Files
opds-proxy/main.go
Evan Buss e21a648506 feat: "local only" automatic authentication
Often you want to expose your library publicly, which requires
authentication to prevent unknown users from seeing your
content.

In my case, I also expose the library on a local domain using a local DNS server which doesn't have these security issues.

This change adds a `local_only` option to the feed auth
config which will only supply the provided username/password
when the request comes from a private IP address.

Omitting `local_only` or setting to false will keep the current
logic of sending the credentials no matter the origin of the
request.
2024-08-10 21:34:23 +00:00

113 lines
2.7 KiB
Go

package main
import (
"encoding/hex"
"flag"
"fmt"
"log"
"net/http"
"os"
"github.com/gorilla/securecookie"
"github.com/knadh/koanf/parsers/yaml"
"github.com/knadh/koanf/providers/confmap"
"github.com/knadh/koanf/providers/file"
"github.com/knadh/koanf/v2"
)
type ProxyConfig struct {
Port string `koanf:"port"`
Auth AuthConfig `koanf:"auth"`
Feeds []FeedConfig `koanf:"feeds" `
isDevMode bool
}
type AuthConfig struct {
HashKey string `koanf:"hash_key"`
BlockKey string `koanf:"block_key"`
}
type FeedConfig struct {
Name string `koanf:"name"`
Url string `koanf:"url"`
Auth *FeedConfigAuth `koanf:"auth"`
}
type FeedConfigAuth struct {
Username string `koanf:"username"`
Password string `koanf:"password"`
LocalOnly bool `koanf:"local_only"`
}
func main() {
fs := flag.NewFlagSet("", flag.ContinueOnError)
// These aren't mapped to the config file.
configPath := fs.String("config", "config.yml", "config file to load")
generateKeys := fs.Bool("generate-keys", false, "generate cookie signing keys and exit")
isDevMode := fs.Bool("dev", false, "enable development mode")
port := fs.String("port", "8080", "port to listen on")
if err := fs.Parse(os.Args[1:]); err != nil {
log.Fatal(err)
}
if *generateKeys {
displayKeys()
os.Exit(0)
}
var k = koanf.New(".")
// Load config file from disk.
// Feed options must be defined here.
if err := k.Load(file.Provider(*configPath), yaml.Parser()); err != nil && !os.IsNotExist(err) {
log.Fatal(err)
}
// Selectively add command line options to the config. Overriding the config file.
if err := k.Load(confmap.Provider(map[string]interface{}{
"port": *port,
}, "."), nil); err != nil {
log.Fatal(err)
}
config := ProxyConfig{}
k.Unmarshal("", &config)
if len(config.Feeds) == 0 {
log.Fatal("No feeds defined in config")
}
if config.Auth.HashKey == "" || config.Auth.BlockKey == "" {
log.Println("Generating new cookie signing credentials")
hashKey, blockKey := displayKeys()
config.Auth.HashKey = hashKey
config.Auth.BlockKey = blockKey
}
// This should only be set by the command line flag,
// so we don't use koanf to set this.
config.isDevMode = *isDevMode
server, err := NewServer(&config)
if err != nil {
log.Fatal(err)
}
if err = server.Serve(); err != nil && err != http.ErrServerClosed {
log.Fatal(err)
}
}
func displayKeys() (string, string) {
hashKey := hex.EncodeToString(securecookie.GenerateRandomKey(32))
blockKey := hex.EncodeToString(securecookie.GenerateRandomKey(32))
log.Println("Set these values in your config file to persist authentication between server restarts.")
fmt.Println("auth:")
fmt.Printf(" hash_key: %s\n", hashKey)
fmt.Printf(" block_key: %s\n", blockKey)
return hashKey, blockKey
}