config

package
v0.53.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 4, 2026 License: AGPL-3.0 Imports: 16 Imported by: 0

Documentation

Overview

Package config reads the configuration of every command from environment variables into one typed Config, validated as a whole at startup so a command stops before doing anything with a value it cannot use (ADR 0002).

The variables, their defaults and an example are in .env.example. A secret, such as the log key, is held as a Secret: it never appears in a log line, an error message or a formatted Config.

Commands write only under Config.DataDir, the data volume, so the rest of the file system can be mounted read-only.

Index

Constants

View Source
const (
	EnvAddr     = "ARNAKOFF_ADDR"
	EnvLogLevel = "ARNAKOFF_LOG_LEVEL"
	EnvLogKey   = "ARNAKOFF_LOG_KEY"
	EnvDataDir  = "ARNAKOFF_DATA_DIR"

	EnvSourceACPR = "ARNAKOFF_SOURCE_ACPR"

	EnvAlertWebhook = "ARNAKOFF_ALERT_WEBHOOK"

	EnvProblemBaseURL = "ARNAKOFF_PROBLEM_BASE_URL"

	EnvBatchMaxItems = "ARNAKOFF_BATCH_MAX_ITEMS"

	EnvDatabaseURL  = "ARNAKOFF_DATABASE_URL"
	EnvDatabaseCA   = "ARNAKOFF_DATABASE_CA"
	EnvAPIKeySecret = "ARNAKOFF_API_KEY_SECRET" //nolint:gosec // G101: the name of a variable, not its value.
	EnvAPIKeyEnv    = "ARNAKOFF_API_KEY_ENV"    //nolint:gosec // G101: the name of a variable, not its value.

	EnvRateLimitKey   = "ARNAKOFF_RATE_LIMIT_KEY"
	EnvRateLimitIP    = "ARNAKOFF_RATE_LIMIT_IP"
	EnvRateLimitAuth  = "ARNAKOFF_RATE_LIMIT_AUTH"
	EnvTrustedProxies = "ARNAKOFF_TRUSTED_PROXIES"
	EnvClientIPHeader = "ARNAKOFF_CLIENT_IP_HEADER"
)

Environment variables read by Load.

View Source
const (
	DefaultAddr     = ":8100"
	DefaultLogLevel = "info"
	DefaultDataDir  = "var"

	// DefaultSourceACPR keeps the ACPR blacklist off: its reuse licence is
	// still to be obtained (docs/sources.md).
	DefaultSourceACPR = "false"

	// DefaultProblemBaseURL is where arnakoff/web documents the problems
	// the API answers, one page per code.
	DefaultProblemBaseURL = "https://arnakoff.com/docs/erreurs/"
)

Defaults applied by Load to an unset variable. ARNAKOFF_LOG_KEY has none.

View Source
const (
	// DefaultBatchMaxItems is the most items POST /v1/check/batch accepts,
	// as the owner set it; the contract's example states it.
	DefaultBatchMaxItems = 50

	// MaxBatchMaxItems is the highest value Load accepts: beyond, one
	// request would weigh like a thousand checks.
	MaxBatchMaxItems = 1000
)

Bounds of ARNAKOFF_BATCH_MAX_ITEMS.

View Source
const (
	EnvDemoOrigin          = "ARNAKOFF_DEMO_ORIGIN"
	EnvTurnstileSecret     = "ARNAKOFF_TURNSTILE_SECRET" //nolint:gosec // G101: the name of a variable, not its value.
	EnvRateLimitDemo       = "ARNAKOFF_RATE_LIMIT_DEMO"
	EnvRateLimitDemoGlobal = "ARNAKOFF_RATE_LIMIT_DEMO_GLOBAL"
)

Environment variables of the demo access, read by Load.

View Source
const (
	// DefaultRateLimitDemo is the number of demo checks of a client
	// address.
	DefaultRateLimitDemo = 10

	// DefaultRateLimitDemoGlobal is the number of demo checks of every
	// client together: a flood from many addresses stays bounded.
	DefaultRateLimitDemoGlobal = 300
)

Defaults of the demo limits, in requests per minute, as the owner set them (#60).

View Source
const (
	EnvSMTPAddr                   = "ARNAKOFF_SMTP_ADDR"
	EnvSMTPUsername               = "ARNAKOFF_SMTP_USERNAME"
	EnvSMTPPassword               = "ARNAKOFF_SMTP_PASSWORD" //nolint:gosec // G101: the name of a variable, not its value.
	EnvMailFrom                   = "ARNAKOFF_MAIL_FROM"
	EnvLoginLinkURL               = "ARNAKOFF_LOGIN_LINK_URL"
	EnvRateLimitKeyRequest        = "ARNAKOFF_RATE_LIMIT_KEY_REQUEST"
	EnvRateLimitKeyRequestAddress = "ARNAKOFF_RATE_LIMIT_KEY_REQUEST_ADDRESS"
)

Environment variables of the key requests by login link, read by Load.

View Source
const (
	// DefaultMailFrom is the sending mailbox the owner chose
	// (arnakoff/.github#3).
	DefaultMailFrom = "contact@arnakoff.com"

	// DefaultLoginLinkURL is the page of the site a login link opens.
	DefaultLoginLinkURL = "https://arnakoff.com/cle"

	// DefaultRateLimitKeyRequest is the number of key requests and
	// redemptions per minute of a client address.
	DefaultRateLimitKeyRequest = 5

	// DefaultRateLimitKeyRequestAddress is the number of login links an
	// email address may receive per hour.
	DefaultRateLimitKeyRequestAddress = 3
)

Defaults of the key requests.

View Source
const (
	DefaultRateLimitKey = 60
	DefaultRateLimitIP  = 30

	// DefaultRateLimitAuth is the number of refused API keys a minute of
	// a client address, as the owner set it (#197).
	DefaultRateLimitAuth = 30

	// MaxRateLimit is the highest limit Load accepts.
	MaxRateLimit = 10000
)

Defaults of the rate limits, in requests per minute, as the owner set them until the offers of #80.

View Source
const (
	EnvSnapshotBucket          = "ARNAKOFF_SNAPSHOT_BUCKET"
	EnvSnapshotBucketAccessKey = "ARNAKOFF_SNAPSHOT_BUCKET_ACCESS_KEY"
	EnvSnapshotBucketSecretKey = "ARNAKOFF_SNAPSHOT_BUCKET_SECRET_KEY" //nolint:gosec // G101: the name of a variable, not its value.
)

Environment variables of the snapshot bucket, read by Load.

View Source
const DefaultAPIKeyEnv = "live"

DefaultAPIKeyEnv accepts the production keys, "ark_live_…".

View Source
const MinLogKeyBytes = logging.MinKeyBytes

MinLogKeyBytes is the shortest log key Load accepts, once hex-decoded: the minimum of logging.New.

Variables

View Source
var ErrInvalid = errors.New("invalid configuration")

ErrInvalid means a variable holds a value Load cannot use.

Functions

This section is empty.

Types

type Config

type Config struct {
	// Addr is the TCP address the HTTP API listens on, "host:port" with a
	// numeric port; an empty host means every interface.
	Addr string

	// LogLevel is the minimum level written to the log.
	LogLevel slog.Level

	// LogKey is the HMAC key that pseudonymises personal data in the log.
	LogKey Secret

	// DataDir is the only directory the commands write to: the data
	// volume. Every other path may be read-only.
	DataDir string

	// SourceACPR turns the ACPR blacklist on, once its reuse licence is
	// obtained.
	SourceACPR bool

	// AlertWebhook is the HTTPS URL a failed or rejected sync is posted
	// to; nil when unset or empty, and then alerts are only logged. It is a
	// Secret: a webhook URL usually carries its credential.
	AlertWebhook Secret

	// ProblemBaseURL is the HTTPS URL of the documentation of the API's
	// problems, ending with a slash: the type of a problem is its code
	// under it.
	ProblemBaseURL string

	// BatchMaxItems is the most items POST /v1/check/batch accepts, from 1
	// to MaxBatchMaxItems.
	BatchMaxItems int

	// DatabaseURL is the PostgreSQL connection string of the API key store;
	// nil when unset or empty. RequireKeyStore tells whether it is set.
	DatabaseURL Secret

	// DatabaseCA is the certificate authority of the database, in PEM,
	// which replaces the system's to verify it: that of a managed database
	// instance. Empty when unset. It is public: no Secret.
	DatabaseCA string

	// APIKeySecret is the HMAC key the API keys are digested with, kept
	// out of the database; nil when unset or empty.
	APIKeySecret Secret

	// APIKeyEnv is the environment of the API keys accepted: "live" or
	// "test".
	APIKeyEnv string

	// RateLimitKey is the number of requests per minute of an API key,
	// from 1 to MaxRateLimit.
	RateLimitKey int

	// RateLimitIP is the number of requests per minute of a client address
	// on the routes needing no key, from 1 to MaxRateLimit.
	RateLimitIP int

	// RateLimitAuth is the number of refused API keys per minute of a
	// client address on the check routes, from 1 to MaxRateLimit: over it,
	// its keys are no longer looked up.
	RateLimitAuth int

	// TrustedProxies are the proxies whose X-Forwarded-For field tells the
	// client's address: nil when unset, empty when set to "none".
	// RequireTrustedProxies tells whether it is set.
	TrustedProxies []netip.Prefix

	// ClientIPHeader is the field, in canonical form, that the platform in
	// front of the API overwrites with the client's address, such as
	// X-Real-Ip on Scaleway Serverless Containers; empty when unset. It
	// excludes TrustedProxies.
	ClientIPHeader string

	// Demo configures the demo access of the site's checker.
	Demo Demo

	// KeyRequest configures the free API keys requested by login link.
	KeyRequest KeyRequest

	// SnapshotBucket is the bucket the snapshots are stored in instead of
	// SnapshotDir, when it is enabled.
	SnapshotBucket SnapshotBucket
}

Config is the configuration of every command.

func Load

func Load(lookup func(string) (string, bool)) (Config, error)

Load reads the configuration with lookup, such as os.LookupEnv. A variable that is set, even to an empty string, is used as is; an unset one takes its default. It returns every invalid variable at once, each wrapping ErrInvalid; an error never quotes the value of a Secret.

func (Config) RequireDatabase added in v0.39.0

func (c Config) RequireDatabase() error

RequireDatabase returns an error, wrapping ErrInvalid, unless the database of the API key store is set.

func (Config) RequireKeyStore added in v0.39.0

func (c Config) RequireKeyStore() error

RequireKeyStore returns an error, wrapping ErrInvalid, unless the API key store is configured: a database and an API key secret other than the log key, so that a leaked log key does not also let anyone check a key.

func (Config) RequireTrustedProxies added in v0.40.0

func (c Config) RequireTrustedProxies() error

RequireTrustedProxies returns an error, wrapping ErrInvalid, when the API serves live keys without ARNAKOFF_TRUSTED_PROXIES nor ARNAKOFF_CLIENT_IP_HEADER: the operator must say who tells the client's address, or that no proxy does.

func (Config) SnapshotDir

func (c Config) SnapshotDir() string

SnapshotDir is where the validated snapshots of the sources are stored, inside DataDir, unless SnapshotBucket is enabled.

type Demo added in v0.42.0

type Demo struct {
	// Origin is the site's origin, "https://host", the only one CORS
	// allows; empty when the demo is off.
	Origin string

	// TurnstileSecret is the secret key of the site's Turnstile widget;
	// nil when the demo is off.
	TurnstileSecret Secret

	// RateLimit is the number of demo checks per minute of a client
	// address, from 1 to MaxRateLimit.
	RateLimit int

	// RateLimitGlobal is the number of demo checks per minute of every
	// client together, from 1 to MaxRateLimit.
	RateLimitGlobal int
}

Demo configures the demo access of the site's checker: checks without an API key, from the site only, each proven by a Cloudflare Turnstile token.

func (Demo) Enabled added in v0.42.0

func (d Demo) Enabled() bool

Enabled reports whether the demo access is on.

func (Demo) Hostname added in v0.42.0

func (d Demo) Hostname() string

Hostname returns the host of Origin, without a port: the hostname a valid Turnstile token names.

type KeyRequest added in v0.52.0

type KeyRequest struct {
	// SMTPAddr is the "host:port" of the sending server, which speaks TLS
	// at once; empty when the key requests are off.
	SMTPAddr string

	// SMTPUsername and SMTPPassword authenticate with the server.
	SMTPUsername string
	SMTPPassword Secret

	// MailFrom is the sender address, a bare address.
	MailFrom string

	// LinkURL is the HTTPS page of the site a login link opens, the token
	// in its fragment.
	LinkURL string

	// RateLimit is the number of requests per minute of a client address
	// to the key request routes, from 1 to MaxRateLimit.
	RateLimit int

	// RateLimitAddress is the number of login links per hour an email
	// address may receive, from 1 to MaxRateLimit.
	RateLimitAddress int
}

KeyRequest configures the free API keys requested by login link (#59).

func (KeyRequest) Enabled added in v0.52.0

func (k KeyRequest) Enabled() bool

Enabled reports whether the key requests are on.

type Secret

type Secret []byte

Secret is a configuration value that must never reach a log, an error or a response. Every fmt verb, encoding/json and log/slog write it as "[redacted]"; only Bytes gives the value.

func (Secret) Bytes

func (s Secret) Bytes() []byte

Bytes returns a copy of the secret value.

func (Secret) Format

func (s Secret) Format(f fmt.State, _ rune)

Format implements fmt.Formatter: every verb writes "[redacted]".

func (Secret) LogValue

func (s Secret) LogValue() slog.Value

LogValue implements slog.LogValuer.

func (Secret) MarshalText

func (s Secret) MarshalText() ([]byte, error)

MarshalText implements encoding.TextMarshaler, which encoding/json uses.

type SnapshotBucket added in v0.50.0

type SnapshotBucket struct {
	// Name is the bucket: 3 to 63 lower-case letters, digits and dashes,
	// starting and ending with a letter or a digit.
	Name string

	// AccessKey and SecretKey are the credentials of the bucket: the key
	// pair of an IAM application restricted to it. Both are Secrets, kept
	// out of every log.
	AccessKey Secret
	SecretKey Secret
}

SnapshotBucket is the S3 bucket the snapshots are stored in, in production (ADR 0005); off when its name is empty, and then they stay in SnapshotDir.

func (SnapshotBucket) Enabled added in v0.50.0

func (b SnapshotBucket) Enabled() bool

Enabled reports whether the snapshots are stored in the bucket.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL