Documentation ¶
Overview ¶
Package config provides various parameters(configuration optionals) that can be used to configure ong.
Index ¶
- Constants
- func DefaultSessionAntiReplayFunc(r http.Request) string
- type ClientIPstrategy
- type Opts
- func AcmeOpts(domain string, secretKey string, strategy ClientIPstrategy, ...) Opts
- func CertOpts(domain string, secretKey string, strategy ClientIPstrategy, ...) Opts
- func DevOpts(logger *slog.Logger, secretKey string) Opts
- func LetsEncryptOpts(domain string, secretKey string, strategy ClientIPstrategy, ...) Opts
- func New(domain string, port uint16, logger *slog.Logger, secretKey string, ...) Opts
- func WithOpts(domain string, httpsPort uint16, secretKey string, strategy ClientIPstrategy, ...) Opts
Examples ¶
Constants ¶
const ( // DefaultLoadShedSamplingPeriod is the duration over which we calculate response latencies by default. DefaultLoadShedSamplingPeriod = 12 * time.Minute // DefaultLoadShedMinSampleSize is the minimum number of past requests that have to be available, in the last `loadShedSamplingPeriod` for us to make a decision, by default. // If there were fewer requests(than `loadShedMinSampleSize`) in the `loadShedSamplingPeriod`, then we do decide to let things continue without load shedding. DefaultLoadShedMinSampleSize = 50 // DefaultLoadShedBreachLatency is the latency at which point we start dropping requests, by default. // // The value chosen here is because; // The wikipedia [monitoring] dashboards are public. // In there we can see that the p95 [response] times for http GET requests is ~700ms, & the p95 response times for http POST requests is ~900ms. // Thus, we'll use a `loadShedBreachLatency` of ~700ms. We hope we can do better than wikipedia(chuckle emoji.) // // [monitoring]: https://grafana.wikimedia.org/?orgId=1 // [response]: https://grafana.wikimedia.org/d/RIA1lzDZk/application-servers-red?orgId=1 DefaultLoadShedBreachLatency = 700 * time.Millisecond // DefaultLoadShedPercentile is percentile used to check for load breach, by default. DefaultLoadShedPercentile = 75 )
loadshed middleware.
const ( // DirectIpStrategy derives the client IP from [http.Request.RemoteAddr]. // It should be used if the server accepts direct connections, rather than through a proxy. DirectIpStrategy = clientip.DirectIpStrategy // LeftIpStrategy derives the client IP from the leftmost valid & non-private IP address in the `X-Fowarded-For` or `Forwarded` header. LeftIpStrategy = clientip.LeftIpStrategy // RightIpStrategy derives the client IP from the rightmost valid & non-private IP address in the `X-Fowarded-For` or `Forwarded` header. RightIpStrategy = clientip.RightIpStrategy // ProxyStrategy derives the client IP from the [PROXY protocol v1]. // This should be used when your application is behind a TCP proxy that uses the v1 PROXY protocol. // // [PROXY protocol v1]: https://www.haproxy.org/download/2.8/doc/proxy-protocol.txt ProxyStrategy = clientip.ProxyStrategy )
clientip middleware.
const ( // DefaultMaxBodyBytes is the value used as the limit for incoming request bodies, if a custom value was not provided. // // [Nginx] uses a default value of 1MB, [Apache] uses default of 1GB whereas [Haproxy] does not have such a limit. // // The max size for http [forms] in Go is 10MB. The max size of the entire bible in text form is ~5MB. // Thus here, we are going to use the 2 times the default size for forms. // Note that; from the [code] and [docs], it looks like; if you set the maxBodyBytes, this also becomes the maxFormSize. // // [Nginx]: http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size // [Apache]: https://httpd.apache.org/docs/2.4/mod/core.html#limitrequestbody // [Haproxy]: https://discourse.haproxy.org/t/how-can-you-configure-the-nginx-client-max-body-size-equivalent-in-haproxy/1690/2 // [forms]: https://github.com/golang/go/blob/go1.20.3/src/net/http/request.go#L1233-L1235 // [code]: https://github.com/golang/go/blob/go1.20.3/src/net/http/request.go#L1233-L1235 // [code]: https://pkg.go.dev/net/http#Request.ParseForm DefaultMaxBodyBytes = uint64(2 * 10 * 1024 * 1024) // 20MB // DefaultServerLogLevel is the log level of the logger that will be passed into [http.Server.ErrorLog], if no custom value is provided. DefaultServerLogLevel = slog.LevelInfo // DefaultDrainDuration is used to determine the shutdown duration if a custom one is not provided. DefaultDrainDuration = 13 * time.Second // LetsEncryptProductionUrl is the URL of [letsencrypt's] certificate authority directory endpoint for production. LetsEncryptProductionUrl = "https://acme-v02.api.letsencrypt.org/directory" // LetsEncryptStagingUrl is the URL of [letsencrypt's] certificate authority directory endpoint for staging. LetsEncryptStagingUrl = "https://acme-staging-v02.api.letsencrypt.org/directory" )
const ( // DefaultCorsCacheDuration is the length in time that preflight responses will be cached by default. // 2hrs is chosen since that is the maximum for chromium based browsers. // Firefox had a maximum of 24hrs as at the time of writing. DefaultCorsCacheDuration = 2 * time.Hour )
cors middleware.
const ( // DefaultCsrfCookieDuration is the duration that csrf cookie will be valid for by default. // // At the time of writing; gorilla/csrf uses 12hrs, django uses 1yr & gofiber/fiber uses 1hr. DefaultCsrfCookieDuration = 12 * time.Hour )
csrf
const ( // DefaultRateLimit is the maximum requests allowed (from one IP address) per second, by default. // // The figure chosen here is because; // [github] uses a rate limit of 1 reqs/sec (5_000 reqs/hr). // [twitter] uses 1 reqs/sec (900 reqs/15mins). // [stripe] uses 100 reqs/sec. // // [github]: https://docs.github.com/en/developers/apps/building-github-apps/rate-limits-for-github-apps // [twitter]: https://developer.twitter.com/en/docs/twitter-api/rate-limits // [stripe]: https://stripe.com/docs/rate-limits DefaultRateLimit = 100.00 )
ratelimit middleware.
const ( // DefaultSessionCookieDuration is the duration that session cookie will be valid for by default. // [django] uses a value of 2 weeks by default. // // [django]: https://docs.djangoproject.com/en/4.1/ref/settings/#session-cookie-age DefaultSessionCookieDuration = 14 * time.Hour )
session middleware.
Variables ¶
This section is empty.
Functions ¶
func DefaultSessionAntiReplayFunc ¶ added in v0.1.2
DefaultSessionAntiReplayFunc is the function used, by default, to try and mitigate against replay attacks. It is a no-op.
Types ¶
type ClientIPstrategy ¶
type ClientIPstrategy = clientip.ClientIPstrategy
ClientIPstrategy is a middleware option that describes the strategy to use when fetching the client's IP address.
Warning: This should be used with caution. Clients CAN easily spoof IP addresses. Fetching the "real" client is done in a best-effort basis and can be grossly inaccurate & precarious. You should especially heed this warning if you intend to use the IP addresses for security related activities. Proceed at your own risk.
func SingleIpStrategy ¶ added in v0.0.82
func SingleIpStrategy(headerName string) ClientIPstrategy
SingleIpStrategy derives the client IP from http header headerName.
headerName MUST NOT be either `X-Forwarded-For` or `Forwarded`. It can be something like `CF-Connecting-IP`, `Fastly-Client-IP`, `Fly-Client-IP`, etc; depending on your usecase.
type Opts ¶
type Opts struct {
// contains filtered or unexported fields
}
Opts are the various parameters(optionals) that can be used to configure ong.
Use either New, WithOpts, DevOpts, CertOpts, AcmeOpts or LetsEncryptOpts to get a valid Opts.
func AcmeOpts ¶
func AcmeOpts( domain string, secretKey string, strategy ClientIPstrategy, logger *slog.Logger, acmeEmail string, tlsHosts []string, acmeDirectoryUrl string, ) Opts
AcmeOpts returns a new Opts that procures certificates from an ACME certificate authority. It panics on error. Also see LetsEncryptOpts
See New for extra documentation.
func CertOpts ¶
func CertOpts( domain string, secretKey string, strategy ClientIPstrategy, logger *slog.Logger, certFile string, keyFile string, tlsHosts []string, ) Opts
CertOpts returns a new Opts that has sensible defaults given certFile & keyFile. It panics on error.
See New for extra documentation.
func DevOpts ¶
DevOpts returns a new Opts that has sensible defaults, especially for dev environments. It also automatically creates & configures the developer TLS certificates/key. It panics on error.
See New for extra documentation.
func LetsEncryptOpts ¶
func LetsEncryptOpts( domain string, secretKey string, strategy ClientIPstrategy, logger *slog.Logger, acmeEmail string, tlsHosts []string, ) Opts
LetsEncryptOpts returns a new Opts that procures certificates from letsencrypt. It panics on error. Also see AcmeOpts
See New for extra documentation.
func New ¶
func New( domain string, port uint16, logger *slog.Logger, secretKey string, strategy ClientIPstrategy, logFunc func(w http.ResponseWriter, r http.Request, statusCode int, fields []any), rateLimit float64, loadShedSamplingPeriod time.Duration, loadShedMinSampleSize int, loadShedBreachLatency time.Duration, loadShedPercentile float64, allowedOrigins []string, allowedMethods []string, allowedHeaders []string, allowCredentials bool, corsCacheDuration time.Duration, csrfTokenDuration time.Duration, sessionCookieDuration time.Duration, sessionAntiReplayFunc func(r http.Request) string, maxBodyBytes uint64, serverLogLevel slog.Level, readHeaderTimeout time.Duration, readTimeout time.Duration, writeTimeout time.Duration, idleTimeout time.Duration, drainTimeout time.Duration, certFile string, keyFile string, acmeEmail string, tlsHosts []string, acmeDirectoryUrl string, clientCertificatePool *x509.CertPool, ) Opts
New returns a new Opts. It panics on error.
domain is the domain name of your website. It can be an exact domain, subdomain or wildcard. port is the TLS port where the server will listen on. Http requests will also redirected to that port.
logger is an slog.Logger that will be used for logging. It is used in the server, it's use in middlewares is only if [logFunc] is nil.
secretKey is used for securing signed data. It should be unique & kept secret. If it becomes compromised, generate a new one and restart your application using the new one.
strategy is the algorithm to use when fetching the client's IP address; see ClientIPstrategy. It is important to choose your strategy carefully, see the warning in ClientIPstrategy.
logFunc is a function that dictates what/how middleware is going to log. It is also used to log any recovered panics in the middleware. This function is not used in the server. If it is nil, a suitable default(that utilizes [logger]) is used. To disable logging, use a function that does nothing.
rateLimit is the maximum requests allowed (from one IP address) per second. If it is les than 1.0, DefaultRateLimit is used instead.
loadShedSamplingPeriod is the duration over which we calculate response latencies for purposes of determining whether to loadshed. If it is less than 1second, DefaultLoadShedSamplingPeriod is used instead. loadShedMinSampleSize is the minimum number of past requests that have to be available, in the last [loadShedSamplingPeriod] for us to make a decision, by default. If there were fewer requests(than [loadShedMinSampleSize]) in the [loadShedSamplingPeriod], then we do decide to let things continue without load shedding. If it is less than 1, DefaultLoadShedMinSampleSize is used instead. loadShedBreachLatency is the latency at which point we start dropping(loadshedding) requests. If it is less than 1nanosecond, DefaultLoadShedBreachLatency is used instead. loadShedPercentile is percentile used to check for load breach, by default. If it is less than 0, DefaultLoadShedPercentile is used instead.
allowedOrigins, allowedMethods, allowedHeaders, allowCredentials & corsCacheDuration are used by the CORS middleware. If allowedOrigins is nil, [domain] and its www variant are used. Use []string{"*"} to allow all. If allowedMethods is nil, "GET", "POST", "HEAD" are allowed. Use []string{"*"} to allow all. If allowedHeaders is nil, "Origin", "Accept", "Content-Type", "X-Requested-With" are allowed. Use []string{"*"} to allow all. allowCredentials indicates whether the request can include user credentials like cookies, HTTP authentication or client side SSL certificates. corsCacheDuration is the duration that preflight responses will be cached. If it is less than 1second, DefaultCorsCacheDuration is used instead, 0 second is an exception and is used as is.
csrfTokenDuration is the duration that csrf cookie will be valid for. If it is less than 1second, DefaultCsrfCookieDuration is used instead.
sessionCookieDuration is the duration that session cookie will be valid. If it is less than 1second, DefaultSessionCookieDuration is used instead. sessionAntiReplayFunc is the function used to return a token that will be used to try and mitigate against replay attacks. This mitigation not foolproof. If it is nil, DefaultSessionAntiReplayFunc is used instead.
maxBodyBytes is the maximum size in bytes for incoming request bodies. If this is zero, a reasonable default is used.
serverLogLevel is the log level of the logger that will be passed into http.Server.ErrorLog
readHeaderTimeout is the amount of time a server will be allowed to read request headers. readTimeout is the maximum duration a server will use for reading the entire request, including the body. writeTimeout is the maximum duration before a server times out writes of the response. idleTimeout is the maximum amount of time to wait for the next request when keep-alives are enabled. drainTimeout is the duration to wait for after receiving a shutdown signal and actually starting to shutdown the server. This is important especially in applications running in places like kubernetes.
certFile is a path to a tls certificate. keyFile is a path to a tls key.
acmeEmail is the e-address that will be used if/when procuring certificates from an ACME certificate authority, eg letsencrypt. tlsHosts is the list of hosts for which we are allowed to fetch TLS certificates for. Wildcards are also accepted. If tlsHosts is nil, [domain] is used instead. acmeDirectoryUrl is the URL of the ACME certificate authority's directory endpoint.
If certFile is a non-empty string, this will enable tls using certificates found on disk. If acmeEmail is a non-empty string, this will enable tls using certificates procured from an ACME certificate authority.
clientCertificatePool is an x509.CertPool, that will be used to verify client certificates. Use this option if you would like to perform mutual TLS authentication. The given pool will be used as is, without modification.
Example ¶
package main import ( "context" "fmt" "log/slog" "net/http" "os" "time" "github.com/komuw/ong/config" "github.com/komuw/ong/log" "github.com/komuw/ong/middleware" ) func loginHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { _, _ = fmt.Fprint(w, "welcome to your favorite website.") } } func main() { l := log.New(context.Background(), os.Stdout, 100) opts := config.New( // The domain where our application will be available on. "example.com", // The https port that our application will be listening on. 443, // Logger. l, // The security key to use for securing signed data. "super-h@rd-Pas1word", // In this case, the actual client IP address is fetched from the given http header. config.SingleIpStrategy("CF-Connecting-IP"), // function to use for logging in middlewares func(_ http.ResponseWriter, r http.Request, statusCode int, fields []any) { if statusCode >= http.StatusInternalServerError { // Only log 500's reqL := log.WithID(r.Context(), l) fields = append(fields, "statusCode", statusCode) reqL.Info("request-and-response", fields...) } }, // If a particular IP address sends more than 13 requests per second, throttle requests from that IP. 13.0, // Sample response latencies over a 5 minute window to determine if to loadshed. 5*time.Minute, // If the number of responses in the last 5minutes is less than 10, do not make a loadshed determination. 10, // If the 83rd percentile response latencies, over the last 5minutes is more than 200ms, then start loadshedding. 200*time.Millisecond, // We check for loadshed breach at the 83 percentile 83, // Allow access from these origins for CORs. []string{"http://example.net", "https://example.org"}, // Allow only GET and POST for CORs. []string{"GET", "POST"}, // Allow all http headers for CORs. []string{"*"}, // Do not allow requests to include user credentials like cookies, HTTP authentication or client side SSL certificates false, // Cache CORs preflight requests for 1day. 24*time.Hour, // Expire csrf cookie after 3days. 3*24*time.Hour, // Expire session cookie after 6hours. 6*time.Hour, // Use a given header to try and mitigate against replay-attacks. func(r http.Request) string { return r.Header.Get("Anti-Replay") }, // // The maximum size in bytes for incoming request bodies. 2*1024*1024, // Log level of the logger that will be passed into [http.Server.ErrorLog] slog.LevelError, // Read header, Read, Write, Idle timeouts respectively. 1*time.Second, 2*time.Second, 4*time.Second, 4*time.Minute, // The duration to wait for after receiving a shutdown signal and actually starting to shutdown the server. 17*time.Second, // Tls certificate and key. This are set to empty string since we wont be using them. "", "", // Email address to use when procuring TLS certificates from an ACME authority. "my-acme@example.com", // The hosts that we will allow to fetch certificates for. []string{"api.example.com", "example.com"}, // The ACME certificate authority to use. "https://acme-staging-v02.api.letsencrypt.org/directory", // [x509.CertPool], that will be used to verify client certificates nil, ) handler := middleware.Get(loginHandler(), opts) _ = handler // use handler }
Output:
func WithOpts ¶
func WithOpts( domain string, httpsPort uint16, secretKey string, strategy ClientIPstrategy, logger *slog.Logger, ) Opts
WithOpts returns a new Opts that has sensible defaults. It panics on error.
See New for extra documentation.