mirror of
https://github.com/lightninglabs/aperture.git
synced 2026-01-02 08:54:24 +01:00
111 lines
3.6 KiB
Go
111 lines
3.6 KiB
Go
package proxy
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"strings"
|
|
|
|
"github.com/lightninglabs/kirin/auth"
|
|
"github.com/lightninglabs/kirin/freebie"
|
|
)
|
|
|
|
var (
|
|
filePrefix = "!file"
|
|
filePrefixHex = filePrefix + "+hex"
|
|
filePrefixBase64 = filePrefix + "+base64"
|
|
)
|
|
|
|
// Service generically specifies configuration data for backend services to the
|
|
// Kirin proxy.
|
|
type Service struct {
|
|
// TLSCertPath is the optional path to the service's TLS certificate.
|
|
TLSCertPath string `long:"tlscertpath" description:"Path to the service's TLS certificate"`
|
|
|
|
// Address is the service's IP address and port.
|
|
Address string `long:"address" description:"service instance rpc address"`
|
|
|
|
// Protocol is the protocol that should be used to connect to the
|
|
// service. Currently supported is http and https.
|
|
Protocol string `long:"protocol" description:"service instance protocol"`
|
|
|
|
// Auth is the authentication level required for this service to be
|
|
// accessed. Valid values are "on" for full authentication, "freebie X"
|
|
// for X free requests per IP address before authentication is required
|
|
// or "off" for no authentication.
|
|
Auth auth.Level `long:"auth" description:"required authentication"`
|
|
|
|
// HostRegexp is a regular expression that is tested against the 'Host'
|
|
// HTTP header field to find out if this service should be used.
|
|
HostRegexp string `long:"hostregexp" description:"Regular expression to match the host against"`
|
|
|
|
// PathRegexp is a regular expression that is tested against the path
|
|
// of the URL of a request to find out if this service should be used.
|
|
PathRegexp string `long:"pathregexp" description:"Regular expression to match the path of the URL against"`
|
|
|
|
// Headers is a map of strings that defines header name and values that
|
|
// should always be passed to the backend service, overwriting any
|
|
// headers with the same name that might have been set by the client
|
|
// request.
|
|
// If the value of a header field starts with the prefix "!file+hex:",
|
|
// the rest of the value is treated as a path to a file and the content
|
|
// of that file is sent to the backend with each call (hex encoded).
|
|
// If the value starts with the prefix "!file+base64:", the content of
|
|
// the file is sent encoded as base64.
|
|
Headers map[string]string `long:"headers" description:"Header fields to always pass to the service"`
|
|
|
|
freebieDb freebie.DB
|
|
}
|
|
|
|
// prepareServices prepares the backend service configurations to be used by the
|
|
// proxy.
|
|
func prepareServices(services []*Service) error {
|
|
for _, service := range services {
|
|
// Each freebie enabled service gets its own store.
|
|
if service.Auth.IsFreebie() {
|
|
service.freebieDb = freebie.NewMemIpMaskStore(
|
|
service.Auth.FreebieCount(),
|
|
)
|
|
}
|
|
|
|
// Replace placeholders/directives in the header fields with the
|
|
// actual desired values.
|
|
for key, value := range service.Headers {
|
|
if !strings.HasPrefix(value, filePrefix) {
|
|
continue
|
|
}
|
|
|
|
parts := strings.Split(value, ":")
|
|
if len(parts) != 2 {
|
|
return fmt.Errorf("invalid header config, " +
|
|
"must be '!file+hex:path'")
|
|
}
|
|
prefix, fileName := parts[0], parts[1]
|
|
bytes, err := ioutil.ReadFile(fileName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// There are two supported formats to encode the file
|
|
// content in: hex and base64.
|
|
switch {
|
|
case prefix == filePrefixHex:
|
|
newValue := hex.EncodeToString(bytes)
|
|
service.Headers[key] = newValue
|
|
|
|
case prefix == filePrefixBase64:
|
|
newValue := base64.StdEncoding.EncodeToString(
|
|
bytes,
|
|
)
|
|
service.Headers[key] = newValue
|
|
|
|
default:
|
|
return fmt.Errorf("unsupported file prefix "+
|
|
"format %s", value)
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|