mirror of
https://github.com/steveiliop56/tinyauth.git
synced 2026-02-22 17:02:01 +00:00
Compare commits
2 Commits
feat/optim
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4c4e34d5c | ||
|
|
3f3072254e |
81
.env.example
81
.env.example
@@ -2,220 +2,171 @@
|
|||||||
|
|
||||||
# The base URL where the app is hosted.
|
# The base URL where the app is hosted.
|
||||||
TINYAUTH_APPURL=
|
TINYAUTH_APPURL=
|
||||||
|
|
||||||
# The directory where resources are stored.
|
# The directory where resources are stored.
|
||||||
TINYAUTH_RESOURCESDIR="./resources"
|
TINYAUTH_RESOURCESDIR="./resources"
|
||||||
|
|
||||||
# The path to the database file.
|
# The path to the database file.
|
||||||
TINYAUTH_DATABASEPATH="./tinyauth.db"
|
TINYAUTH_DATABASEPATH="./tinyauth.db"
|
||||||
|
|
||||||
# Disable analytics.
|
# Disable analytics.
|
||||||
TINYAUTH_DISABLEANALYTICS=false
|
TINYAUTH_DISABLEANALYTICS=false
|
||||||
|
|
||||||
# Disable resources server.
|
# Disable resources server.
|
||||||
TINYAUTH_DISABLERESOURCES=false
|
TINYAUTH_DISABLERESOURCES=false
|
||||||
|
|
||||||
|
# server config
|
||||||
|
|
||||||
# The port on which the server listens.
|
# The port on which the server listens.
|
||||||
TINYAUTH_SERVER_PORT=3000
|
TINYAUTH_SERVER_PORT=3000
|
||||||
|
|
||||||
# The address on which the server listens.
|
# The address on which the server listens.
|
||||||
TINYAUTH_SERVER_ADDRESS="0.0.0.0"
|
TINYAUTH_SERVER_ADDRESS="0.0.0.0"
|
||||||
|
|
||||||
# The path to the Unix socket.
|
# The path to the Unix socket.
|
||||||
TINYAUTH_SERVER_SOCKETPATH=
|
TINYAUTH_SERVER_SOCKETPATH=
|
||||||
|
|
||||||
|
# auth config
|
||||||
|
|
||||||
# List of allowed IPs or CIDR ranges.
|
# List of allowed IPs or CIDR ranges.
|
||||||
TINYAUTH_AUTH_IP_ALLOW=
|
TINYAUTH_AUTH_IP_ALLOW=
|
||||||
|
|
||||||
# List of blocked IPs or CIDR ranges.
|
# List of blocked IPs or CIDR ranges.
|
||||||
TINYAUTH_AUTH_IP_BLOCK=
|
TINYAUTH_AUTH_IP_BLOCK=
|
||||||
|
|
||||||
# Comma-separated list of users (username:hashed_password).
|
# Comma-separated list of users (username:hashed_password).
|
||||||
TINYAUTH_AUTH_USERS=
|
TINYAUTH_AUTH_USERS=
|
||||||
|
|
||||||
# Path to the users file.
|
# Path to the users file.
|
||||||
TINYAUTH_AUTH_USERSFILE=
|
TINYAUTH_AUTH_USERSFILE=
|
||||||
|
|
||||||
# Enable secure cookies.
|
# Enable secure cookies.
|
||||||
TINYAUTH_AUTH_SECURECOOKIE=false
|
TINYAUTH_AUTH_SECURECOOKIE=false
|
||||||
|
|
||||||
# Session expiry time in seconds.
|
# Session expiry time in seconds.
|
||||||
TINYAUTH_AUTH_SESSIONEXPIRY=86400
|
TINYAUTH_AUTH_SESSIONEXPIRY=86400
|
||||||
|
|
||||||
# Maximum session lifetime in seconds.
|
# Maximum session lifetime in seconds.
|
||||||
TINYAUTH_AUTH_SESSIONMAXLIFETIME=0
|
TINYAUTH_AUTH_SESSIONMAXLIFETIME=0
|
||||||
|
|
||||||
# Login timeout in seconds.
|
# Login timeout in seconds.
|
||||||
TINYAUTH_AUTH_LOGINTIMEOUT=300
|
TINYAUTH_AUTH_LOGINTIMEOUT=300
|
||||||
|
|
||||||
# Maximum login retries.
|
# Maximum login retries.
|
||||||
TINYAUTH_AUTH_LOGINMAXRETRIES=3
|
TINYAUTH_AUTH_LOGINMAXRETRIES=3
|
||||||
|
|
||||||
# Comma-separated list of trusted proxy addresses.
|
# Comma-separated list of trusted proxy addresses.
|
||||||
TINYAUTH_AUTH_TRUSTEDPROXIES=
|
TINYAUTH_AUTH_TRUSTEDPROXIES=
|
||||||
|
|
||||||
|
# apps config
|
||||||
|
|
||||||
# The domain of the app.
|
# The domain of the app.
|
||||||
TINYAUTH_APPS_name_CONFIG_DOMAIN=
|
TINYAUTH_APPS_name_CONFIG_DOMAIN=
|
||||||
|
|
||||||
# Comma-separated list of allowed users.
|
# Comma-separated list of allowed users.
|
||||||
TINYAUTH_APPS_name_USERS_ALLOW=
|
TINYAUTH_APPS_name_USERS_ALLOW=
|
||||||
|
|
||||||
# Comma-separated list of blocked users.
|
# Comma-separated list of blocked users.
|
||||||
TINYAUTH_APPS_name_USERS_BLOCK=
|
TINYAUTH_APPS_name_USERS_BLOCK=
|
||||||
|
|
||||||
# Comma-separated list of allowed OAuth groups.
|
# Comma-separated list of allowed OAuth groups.
|
||||||
TINYAUTH_APPS_name_OAUTH_WHITELIST=
|
TINYAUTH_APPS_name_OAUTH_WHITELIST=
|
||||||
|
|
||||||
# Comma-separated list of required OAuth groups.
|
# Comma-separated list of required OAuth groups.
|
||||||
TINYAUTH_APPS_name_OAUTH_GROUPS=
|
TINYAUTH_APPS_name_OAUTH_GROUPS=
|
||||||
|
|
||||||
# List of allowed IPs or CIDR ranges.
|
# List of allowed IPs or CIDR ranges.
|
||||||
TINYAUTH_APPS_name_IP_ALLOW=
|
TINYAUTH_APPS_name_IP_ALLOW=
|
||||||
|
|
||||||
# List of blocked IPs or CIDR ranges.
|
# List of blocked IPs or CIDR ranges.
|
||||||
TINYAUTH_APPS_name_IP_BLOCK=
|
TINYAUTH_APPS_name_IP_BLOCK=
|
||||||
|
|
||||||
# List of IPs or CIDR ranges that bypass authentication.
|
# List of IPs or CIDR ranges that bypass authentication.
|
||||||
TINYAUTH_APPS_name_IP_BYPASS=
|
TINYAUTH_APPS_name_IP_BYPASS=
|
||||||
|
|
||||||
# Custom headers to add to the response.
|
# Custom headers to add to the response.
|
||||||
TINYAUTH_APPS_name_RESPONSE_HEADERS=
|
TINYAUTH_APPS_name_RESPONSE_HEADERS=
|
||||||
|
|
||||||
# Basic auth username.
|
# Basic auth username.
|
||||||
TINYAUTH_APPS_name_RESPONSE_BASICAUTH_USERNAME=
|
TINYAUTH_APPS_name_RESPONSE_BASICAUTH_USERNAME=
|
||||||
|
|
||||||
# Basic auth password.
|
# Basic auth password.
|
||||||
TINYAUTH_APPS_name_RESPONSE_BASICAUTH_PASSWORD=
|
TINYAUTH_APPS_name_RESPONSE_BASICAUTH_PASSWORD=
|
||||||
|
|
||||||
# Path to the file containing the basic auth password.
|
# Path to the file containing the basic auth password.
|
||||||
TINYAUTH_APPS_name_RESPONSE_BASICAUTH_PASSWORDFILE=
|
TINYAUTH_APPS_name_RESPONSE_BASICAUTH_PASSWORDFILE=
|
||||||
|
|
||||||
# Comma-separated list of allowed paths.
|
# Comma-separated list of allowed paths.
|
||||||
TINYAUTH_APPS_name_PATH_ALLOW=
|
TINYAUTH_APPS_name_PATH_ALLOW=
|
||||||
|
|
||||||
# Comma-separated list of blocked paths.
|
# Comma-separated list of blocked paths.
|
||||||
TINYAUTH_APPS_name_PATH_BLOCK=
|
TINYAUTH_APPS_name_PATH_BLOCK=
|
||||||
|
|
||||||
# Comma-separated list of required LDAP groups.
|
# Comma-separated list of required LDAP groups.
|
||||||
TINYAUTH_APPS_name_LDAP_GROUPS=
|
TINYAUTH_APPS_name_LDAP_GROUPS=
|
||||||
|
|
||||||
|
# oauth config
|
||||||
|
|
||||||
# Comma-separated list of allowed OAuth domains.
|
# Comma-separated list of allowed OAuth domains.
|
||||||
TINYAUTH_OAUTH_WHITELIST=
|
TINYAUTH_OAUTH_WHITELIST=
|
||||||
|
|
||||||
# The OAuth provider to use for automatic redirection.
|
# The OAuth provider to use for automatic redirection.
|
||||||
TINYAUTH_OAUTH_AUTOREDIRECT=
|
TINYAUTH_OAUTH_AUTOREDIRECT=
|
||||||
|
|
||||||
# OAuth client ID.
|
# OAuth client ID.
|
||||||
TINYAUTH_OAUTH_PROVIDERS_name_CLIENTID=
|
TINYAUTH_OAUTH_PROVIDERS_name_CLIENTID=
|
||||||
|
|
||||||
# OAuth client secret.
|
# OAuth client secret.
|
||||||
TINYAUTH_OAUTH_PROVIDERS_name_CLIENTSECRET=
|
TINYAUTH_OAUTH_PROVIDERS_name_CLIENTSECRET=
|
||||||
|
|
||||||
# Path to the file containing the OAuth client secret.
|
# Path to the file containing the OAuth client secret.
|
||||||
TINYAUTH_OAUTH_PROVIDERS_name_CLIENTSECRETFILE=
|
TINYAUTH_OAUTH_PROVIDERS_name_CLIENTSECRETFILE=
|
||||||
|
|
||||||
# OAuth scopes.
|
# OAuth scopes.
|
||||||
TINYAUTH_OAUTH_PROVIDERS_name_SCOPES=
|
TINYAUTH_OAUTH_PROVIDERS_name_SCOPES=
|
||||||
|
|
||||||
# OAuth redirect URL.
|
# OAuth redirect URL.
|
||||||
TINYAUTH_OAUTH_PROVIDERS_name_REDIRECTURL=
|
TINYAUTH_OAUTH_PROVIDERS_name_REDIRECTURL=
|
||||||
|
|
||||||
# OAuth authorization URL.
|
# OAuth authorization URL.
|
||||||
TINYAUTH_OAUTH_PROVIDERS_name_AUTHURL=
|
TINYAUTH_OAUTH_PROVIDERS_name_AUTHURL=
|
||||||
|
|
||||||
# OAuth token URL.
|
# OAuth token URL.
|
||||||
TINYAUTH_OAUTH_PROVIDERS_name_TOKENURL=
|
TINYAUTH_OAUTH_PROVIDERS_name_TOKENURL=
|
||||||
|
|
||||||
# OAuth userinfo URL.
|
# OAuth userinfo URL.
|
||||||
TINYAUTH_OAUTH_PROVIDERS_name_USERINFOURL=
|
TINYAUTH_OAUTH_PROVIDERS_name_USERINFOURL=
|
||||||
|
|
||||||
# Allow insecure OAuth connections.
|
# Allow insecure OAuth connections.
|
||||||
TINYAUTH_OAUTH_PROVIDERS_name_INSECURE=false
|
TINYAUTH_OAUTH_PROVIDERS_name_INSECURE=false
|
||||||
|
|
||||||
# Provider name in UI.
|
# Provider name in UI.
|
||||||
TINYAUTH_OAUTH_PROVIDERS_name_NAME=
|
TINYAUTH_OAUTH_PROVIDERS_name_NAME=
|
||||||
|
|
||||||
|
# oidc config
|
||||||
|
|
||||||
# Path to the private key file.
|
# Path to the private key file.
|
||||||
TINYAUTH_OIDC_PRIVATEKEYPATH="./tinyauth_oidc_key"
|
TINYAUTH_OIDC_PRIVATEKEYPATH="./tinyauth_oidc_key"
|
||||||
|
|
||||||
# Path to the public key file.
|
# Path to the public key file.
|
||||||
TINYAUTH_OIDC_PUBLICKEYPATH="./tinyauth_oidc_key.pub"
|
TINYAUTH_OIDC_PUBLICKEYPATH="./tinyauth_oidc_key.pub"
|
||||||
|
|
||||||
# OIDC client ID.
|
# OIDC client ID.
|
||||||
TINYAUTH_OIDC_CLIENTS_name_CLIENTID=
|
TINYAUTH_OIDC_CLIENTS_name_CLIENTID=
|
||||||
|
|
||||||
# OIDC client secret.
|
# OIDC client secret.
|
||||||
TINYAUTH_OIDC_CLIENTS_name_CLIENTSECRET=
|
TINYAUTH_OIDC_CLIENTS_name_CLIENTSECRET=
|
||||||
|
|
||||||
# Path to the file containing the OIDC client secret.
|
# Path to the file containing the OIDC client secret.
|
||||||
TINYAUTH_OIDC_CLIENTS_name_CLIENTSECRETFILE=
|
TINYAUTH_OIDC_CLIENTS_name_CLIENTSECRETFILE=
|
||||||
|
|
||||||
# List of trusted redirect URIs.
|
# List of trusted redirect URIs.
|
||||||
TINYAUTH_OIDC_CLIENTS_name_TRUSTEDREDIRECTURIS=
|
TINYAUTH_OIDC_CLIENTS_name_TRUSTEDREDIRECTURIS=
|
||||||
|
|
||||||
# Client name in UI.
|
# Client name in UI.
|
||||||
TINYAUTH_OIDC_CLIENTS_name_NAME=
|
TINYAUTH_OIDC_CLIENTS_name_NAME=
|
||||||
|
|
||||||
|
# ui config
|
||||||
|
|
||||||
# The title of the UI.
|
# The title of the UI.
|
||||||
TINYAUTH_UI_TITLE="Tinyauth"
|
TINYAUTH_UI_TITLE="Tinyauth"
|
||||||
|
|
||||||
# Message displayed on the forgot password page.
|
# Message displayed on the forgot password page.
|
||||||
TINYAUTH_UI_FORGOTPASSWORDMESSAGE="You can change your password by changing the configuration."
|
TINYAUTH_UI_FORGOTPASSWORDMESSAGE="You can change your password by changing the configuration."
|
||||||
|
|
||||||
# Path to the background image.
|
# Path to the background image.
|
||||||
TINYAUTH_UI_BACKGROUNDIMAGE="/background.jpg"
|
TINYAUTH_UI_BACKGROUNDIMAGE="/background.jpg"
|
||||||
|
|
||||||
# Disable UI warnings.
|
# Disable UI warnings.
|
||||||
TINYAUTH_UI_DISABLEWARNINGS=false
|
TINYAUTH_UI_DISABLEWARNINGS=false
|
||||||
|
|
||||||
|
# ldap config
|
||||||
|
|
||||||
# LDAP server address.
|
# LDAP server address.
|
||||||
TINYAUTH_LDAP_ADDRESS=
|
TINYAUTH_LDAP_ADDRESS=
|
||||||
|
|
||||||
# Bind DN for LDAP authentication.
|
# Bind DN for LDAP authentication.
|
||||||
TINYAUTH_LDAP_BINDDN=
|
TINYAUTH_LDAP_BINDDN=
|
||||||
|
|
||||||
# Bind password for LDAP authentication.
|
# Bind password for LDAP authentication.
|
||||||
TINYAUTH_LDAP_BINDPASSWORD=
|
TINYAUTH_LDAP_BINDPASSWORD=
|
||||||
|
|
||||||
# Base DN for LDAP searches.
|
# Base DN for LDAP searches.
|
||||||
TINYAUTH_LDAP_BASEDN=
|
TINYAUTH_LDAP_BASEDN=
|
||||||
|
|
||||||
# Allow insecure LDAP connections.
|
# Allow insecure LDAP connections.
|
||||||
TINYAUTH_LDAP_INSECURE=false
|
TINYAUTH_LDAP_INSECURE=false
|
||||||
|
|
||||||
# LDAP search filter.
|
# LDAP search filter.
|
||||||
TINYAUTH_LDAP_SEARCHFILTER="(uid=%s)"
|
TINYAUTH_LDAP_SEARCHFILTER="(uid=%s)"
|
||||||
|
|
||||||
# Certificate for mTLS authentication.
|
# Certificate for mTLS authentication.
|
||||||
TINYAUTH_LDAP_AUTHCERT=
|
TINYAUTH_LDAP_AUTHCERT=
|
||||||
|
|
||||||
# Certificate key for mTLS authentication.
|
# Certificate key for mTLS authentication.
|
||||||
TINYAUTH_LDAP_AUTHKEY=
|
TINYAUTH_LDAP_AUTHKEY=
|
||||||
|
|
||||||
# Cache duration for LDAP group membership in seconds.
|
# Cache duration for LDAP group membership in seconds.
|
||||||
TINYAUTH_LDAP_GROUPCACHETTL=900
|
TINYAUTH_LDAP_GROUPCACHETTL=900
|
||||||
|
|
||||||
|
# log config
|
||||||
|
|
||||||
# Log level (trace, debug, info, warn, error).
|
# Log level (trace, debug, info, warn, error).
|
||||||
TINYAUTH_LOG_LEVEL="info"
|
TINYAUTH_LOG_LEVEL="info"
|
||||||
|
|
||||||
# Enable JSON formatted logs.
|
# Enable JSON formatted logs.
|
||||||
TINYAUTH_LOG_JSON=false
|
TINYAUTH_LOG_JSON=false
|
||||||
|
|
||||||
# Enable this log stream.
|
# Enable this log stream.
|
||||||
TINYAUTH_LOG_STREAMS_HTTP_ENABLED=true
|
TINYAUTH_LOG_STREAMS_HTTP_ENABLED=true
|
||||||
|
|
||||||
# Log level for this stream. Use global if empty.
|
# Log level for this stream. Use global if empty.
|
||||||
TINYAUTH_LOG_STREAMS_HTTP_LEVEL=
|
TINYAUTH_LOG_STREAMS_HTTP_LEVEL=
|
||||||
|
|
||||||
# Enable this log stream.
|
# Enable this log stream.
|
||||||
TINYAUTH_LOG_STREAMS_APP_ENABLED=true
|
TINYAUTH_LOG_STREAMS_APP_ENABLED=true
|
||||||
|
|
||||||
# Log level for this stream. Use global if empty.
|
# Log level for this stream. Use global if empty.
|
||||||
TINYAUTH_LOG_STREAMS_APP_LEVEL=
|
TINYAUTH_LOG_STREAMS_APP_LEVEL=
|
||||||
|
|
||||||
# Enable this log stream.
|
# Enable this log stream.
|
||||||
TINYAUTH_LOG_STREAMS_AUDIT_ENABLED=false
|
TINYAUTH_LOG_STREAMS_AUDIT_ENABLED=false
|
||||||
|
|
||||||
# Log level for this stream. Use global if empty.
|
# Log level for this stream. Use global if empty.
|
||||||
TINYAUTH_LOG_STREAMS_AUDIT_LEVEL=
|
TINYAUTH_LOG_STREAMS_AUDIT_LEVEL=
|
||||||
|
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -42,3 +42,6 @@ __debug_*
|
|||||||
|
|
||||||
# traefik data
|
# traefik data
|
||||||
/traefik
|
/traefik
|
||||||
|
|
||||||
|
# generated markdown (for docs)
|
||||||
|
/config.gen.md
|
||||||
|
|||||||
@@ -1,102 +0,0 @@
|
|||||||
# Tinyauth Example Configuration
|
|
||||||
|
|
||||||
# The base URL where Tinyauth is accessible
|
|
||||||
appUrl: "https://auth.example.com"
|
|
||||||
# Directory for static resources
|
|
||||||
resourcesDir: "./resources"
|
|
||||||
# Path to SQLite database file
|
|
||||||
databasePath: "./tinyauth.db"
|
|
||||||
# Disable usage analytics
|
|
||||||
disableAnalytics: false
|
|
||||||
# Disable static resource serving
|
|
||||||
disableResources: false
|
|
||||||
# Disable UI warning messages
|
|
||||||
disableUIWarnings: false
|
|
||||||
|
|
||||||
# Logging Configuration
|
|
||||||
log:
|
|
||||||
# Log level: trace, debug, info, warn, error
|
|
||||||
level: "info"
|
|
||||||
json: false
|
|
||||||
streams:
|
|
||||||
app:
|
|
||||||
enabled: true
|
|
||||||
level: "warn"
|
|
||||||
http:
|
|
||||||
enabled: true
|
|
||||||
level: "debug"
|
|
||||||
audit:
|
|
||||||
enabled: false
|
|
||||||
level: "info"
|
|
||||||
|
|
||||||
# Server Configuration
|
|
||||||
server:
|
|
||||||
# Port to listen on
|
|
||||||
port: 3000
|
|
||||||
# Interface to bind to (0.0.0.0 for all interfaces)
|
|
||||||
address: "0.0.0.0"
|
|
||||||
# Unix socket path (optional, overrides port/address if set)
|
|
||||||
socketPath: ""
|
|
||||||
# Comma-separated list of trusted proxy IPs/CIDRs
|
|
||||||
trustedProxies: ""
|
|
||||||
|
|
||||||
# Authentication Configuration
|
|
||||||
auth:
|
|
||||||
# Format: username:bcrypt_hash (use bcrypt to generate hash)
|
|
||||||
users: "admin:$2a$10$example_bcrypt_hash_here"
|
|
||||||
# Path to external users file (optional)
|
|
||||||
usersFile: ""
|
|
||||||
# Enable secure cookies (requires HTTPS)
|
|
||||||
secureCookie: false
|
|
||||||
# Session expiry in seconds (3600 = 1 hour)
|
|
||||||
sessionExpiry: 3600
|
|
||||||
# Session maximum lifetime in seconds (0 = unlimited)
|
|
||||||
sessionMaxLifetime: 0
|
|
||||||
# Login timeout in seconds (300 = 5 minutes)
|
|
||||||
loginTimeout: 300
|
|
||||||
# Maximum login retries before lockout
|
|
||||||
loginMaxRetries: 3
|
|
||||||
|
|
||||||
# OAuth Configuration
|
|
||||||
oauth:
|
|
||||||
# Regex pattern for allowed email addresses (e.g., /@example\.com$/)
|
|
||||||
whitelist: ""
|
|
||||||
# Provider ID to auto-redirect to (skips login page)
|
|
||||||
autoRedirect: ""
|
|
||||||
# OAuth Provider Configuration (replace myprovider with your provider name)
|
|
||||||
providers:
|
|
||||||
myprovider:
|
|
||||||
clientId: "your_client_id_here"
|
|
||||||
clientSecret: "your_client_secret_here"
|
|
||||||
authUrl: "https://provider.example.com/oauth/authorize"
|
|
||||||
tokenUrl: "https://provider.example.com/oauth/token"
|
|
||||||
userInfoUrl: "https://provider.example.com/oauth/userinfo"
|
|
||||||
redirectUrl: "https://auth.example.com/api/oauth/callback/myprovider"
|
|
||||||
scopes: "openid email profile"
|
|
||||||
name: "My OAuth Provider"
|
|
||||||
# Allow insecure connections (self-signed certificates)
|
|
||||||
insecure: false
|
|
||||||
|
|
||||||
# UI Customization
|
|
||||||
ui:
|
|
||||||
# Custom title for login page
|
|
||||||
title: "Tinyauth"
|
|
||||||
# Message shown on forgot password page
|
|
||||||
forgotPasswordMessage: "Contact your administrator to reset your password"
|
|
||||||
# Background image URL for login page
|
|
||||||
backgroundImage: ""
|
|
||||||
|
|
||||||
# LDAP Configuration (optional)
|
|
||||||
ldap:
|
|
||||||
# LDAP server address
|
|
||||||
address: "ldap://ldap.example.com:389"
|
|
||||||
# DN for binding to LDAP server
|
|
||||||
bindDn: "cn=readonly,dc=example,dc=com"
|
|
||||||
# Password for bind DN
|
|
||||||
bindPassword: "your_bind_password"
|
|
||||||
# Base DN for user searches
|
|
||||||
baseDn: "dc=example,dc=com"
|
|
||||||
# Search filter (%s will be replaced with username)
|
|
||||||
searchFilter: "(&(uid=%s)(memberOf=cn=users,ou=groups,dc=example,dc=com))"
|
|
||||||
# Allow insecure LDAP connections
|
|
||||||
insecure: false
|
|
||||||
29
gen/gen.go
29
gen/gen.go
@@ -2,10 +2,37 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
slog.Info("generating example env file")
|
slog.Info("generating example env file")
|
||||||
|
|
||||||
generateExampleEnv()
|
generateExampleEnv()
|
||||||
|
slog.Info("generating config reference markdown file")
|
||||||
|
generateMarkdown()
|
||||||
|
}
|
||||||
|
|
||||||
|
func walkAndBuild[T any](parent reflect.Type, parentValue reflect.Value,
|
||||||
|
parentPath string, entries *[]T,
|
||||||
|
buildEntry func(child reflect.StructField, childValue reflect.Value, parentPath string, entries *[]T),
|
||||||
|
buildMap func(child reflect.StructField, parentPath string, entries *[]T),
|
||||||
|
buildChildPath func(parentPath string, childName string) string,
|
||||||
|
) {
|
||||||
|
for i := 0; i < parent.NumField(); i++ {
|
||||||
|
field := parent.Field(i)
|
||||||
|
fieldType := field.Type
|
||||||
|
fieldValue := parentValue.Field(i)
|
||||||
|
|
||||||
|
switch fieldType.Kind() {
|
||||||
|
case reflect.Struct:
|
||||||
|
childPath := buildChildPath(parentPath, field.Name)
|
||||||
|
walkAndBuild[T](fieldType, fieldValue, childPath, entries, buildEntry, buildMap, buildChildPath)
|
||||||
|
case reflect.Map:
|
||||||
|
buildMap(field, parentPath, entries)
|
||||||
|
case reflect.Bool, reflect.String, reflect.Slice, reflect.Int:
|
||||||
|
buildEntry(field, fieldValue, parentPath, entries)
|
||||||
|
default:
|
||||||
|
slog.Info("unknown type", "type", fieldType.Kind())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
100
gen/gen_env.go
100
gen/gen_env.go
@@ -2,7 +2,9 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
@@ -11,7 +13,7 @@ import (
|
|||||||
"github.com/steveiliop56/tinyauth/internal/config"
|
"github.com/steveiliop56/tinyauth/internal/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Path struct {
|
type EnvEntry struct {
|
||||||
Name string
|
Name string
|
||||||
Description string
|
Description string
|
||||||
Value any
|
Value any
|
||||||
@@ -19,17 +21,17 @@ type Path struct {
|
|||||||
|
|
||||||
func generateExampleEnv() {
|
func generateExampleEnv() {
|
||||||
cfg := config.NewDefaultConfiguration()
|
cfg := config.NewDefaultConfiguration()
|
||||||
paths := make([]Path, 0)
|
entries := make([]EnvEntry, 0)
|
||||||
|
|
||||||
root := reflect.TypeOf(cfg).Elem()
|
root := reflect.TypeOf(cfg).Elem()
|
||||||
rootValue := reflect.ValueOf(cfg).Elem()
|
rootValue := reflect.ValueOf(cfg).Elem()
|
||||||
rootPath := "TINYAUTH_"
|
rootPath := "TINYAUTH_"
|
||||||
|
|
||||||
buildPaths(root, rootValue, rootPath, &paths)
|
walkAndBuild(root, rootValue, rootPath, &entries, buildEnvEntry, buildEnvMapEntry, buildEnvChildPath)
|
||||||
compiled := compileEnv(paths)
|
compiled := compileEnv(entries)
|
||||||
|
|
||||||
err := os.Remove(".env.example")
|
err := os.Remove(".env.example")
|
||||||
if err != nil {
|
if err != nil && !errors.Is(err, fs.ErrNotExist) {
|
||||||
slog.Error("failed to remove example env file", "error", err)
|
slog.Error("failed to remove example env file", "error", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
@@ -41,96 +43,88 @@ func generateExampleEnv() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildPaths(parent reflect.Type, parentValue reflect.Value, parentPath string, paths *[]Path) {
|
func buildEnvEntry(child reflect.StructField, childValue reflect.Value, parentPath string, entries *[]EnvEntry) {
|
||||||
for i := 0; i < parent.NumField(); i++ {
|
desc := child.Tag.Get("description")
|
||||||
field := parent.Field(i)
|
tag := child.Tag.Get("yaml")
|
||||||
fieldType := field.Type
|
|
||||||
fieldValue := parentValue.Field(i)
|
|
||||||
switch fieldType.Kind() {
|
|
||||||
case reflect.Struct:
|
|
||||||
childPath := parentPath + strings.ToUpper(field.Name) + "_"
|
|
||||||
buildPaths(fieldType, fieldValue, childPath, paths)
|
|
||||||
case reflect.Map:
|
|
||||||
buildMapPaths(field, parentPath, paths)
|
|
||||||
case reflect.Bool, reflect.String, reflect.Slice, reflect.Int:
|
|
||||||
buildPath(field, fieldValue, parentPath, paths)
|
|
||||||
default:
|
|
||||||
slog.Info("unknown type", "type", fieldType.Kind())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func buildPath(field reflect.StructField, fieldValue reflect.Value, parent string, paths *[]Path) {
|
if tag == "-" {
|
||||||
desc := field.Tag.Get("description")
|
|
||||||
yamlTag := field.Tag.Get("yaml")
|
|
||||||
|
|
||||||
// probably internal logic, should be skipped
|
|
||||||
if yamlTag == "-" {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultValue := fieldValue.Interface()
|
value := childValue.Interface()
|
||||||
|
|
||||||
path := Path{
|
entry := EnvEntry{
|
||||||
Name: parent + strings.ToUpper(field.Name),
|
Name: parentPath + strings.ToUpper(child.Name),
|
||||||
Description: desc,
|
Description: desc,
|
||||||
}
|
}
|
||||||
|
|
||||||
switch fieldValue.Kind() {
|
switch childValue.Kind() {
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
sl, ok := defaultValue.([]string)
|
sl, ok := value.([]string)
|
||||||
if !ok {
|
if !ok {
|
||||||
slog.Error("invalid default value", "value", defaultValue)
|
slog.Error("invalid default value", "value", value)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
path.Value = strings.Join(sl, ",")
|
entry.Value = strings.Join(sl, ",")
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
st, ok := defaultValue.(string)
|
st, ok := value.(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
slog.Error("invalid default value", "value", defaultValue)
|
slog.Error("invalid default value", "value", value)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// good idea to escape strings probably
|
|
||||||
if st != "" {
|
if st != "" {
|
||||||
path.Value = fmt.Sprintf(`"%s"`, st)
|
entry.Value = fmt.Sprintf(`"%s"`, st)
|
||||||
} else {
|
} else {
|
||||||
path.Value = ""
|
entry.Value = ""
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
path.Value = defaultValue
|
entry.Value = value
|
||||||
}
|
}
|
||||||
*paths = append(*paths, path)
|
*entries = append(*entries, entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildMapPaths(field reflect.StructField, parentPath string, paths *[]Path) {
|
func buildEnvMapEntry(child reflect.StructField, parentPath string, entries *[]EnvEntry) {
|
||||||
fieldType := field.Type
|
fieldType := child.Type
|
||||||
|
|
||||||
if fieldType.Key().Kind() != reflect.String {
|
if fieldType.Key().Kind() != reflect.String {
|
||||||
slog.Info("unsupported map key type", "type", fieldType.Key().Kind())
|
slog.Info("unsupported map key type", "type", fieldType.Key().Kind())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
mapPath := parentPath + strings.ToUpper(field.Name) + "_name_"
|
mapPath := parentPath + strings.ToUpper(child.Name) + "_name_"
|
||||||
valueType := fieldType.Elem()
|
valueType := fieldType.Elem()
|
||||||
|
|
||||||
if valueType.Kind() == reflect.Struct {
|
if valueType.Kind() == reflect.Struct {
|
||||||
zeroValue := reflect.New(valueType).Elem()
|
zeroValue := reflect.New(valueType).Elem()
|
||||||
buildPaths(valueType, zeroValue, mapPath, paths)
|
walkAndBuild(valueType, zeroValue, mapPath, entries, buildEnvEntry, buildEnvMapEntry, buildEnvChildPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func compileEnv(paths []Path) []byte {
|
func buildEnvChildPath(parent string, child string) string {
|
||||||
|
return parent + strings.ToUpper(child) + "_"
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileEnv(entries []EnvEntry) []byte {
|
||||||
buffer := bytes.Buffer{}
|
buffer := bytes.Buffer{}
|
||||||
buffer.WriteString("# Tinyauth example configuration\n\n")
|
buffer.WriteString("# Tinyauth example configuration\n\n")
|
||||||
|
|
||||||
for _, path := range paths {
|
previousSection := ""
|
||||||
|
|
||||||
|
for _, entry := range entries {
|
||||||
|
if strings.Count(entry.Name, "_") > 1 {
|
||||||
|
section := strings.Split(strings.TrimPrefix(entry.Name, "TINYAUTH_"), "_")[0]
|
||||||
|
if section != previousSection {
|
||||||
|
buffer.WriteString("\n# " + strings.ToLower(section) + " config\n\n")
|
||||||
|
previousSection = section
|
||||||
|
}
|
||||||
|
}
|
||||||
buffer.WriteString("# ")
|
buffer.WriteString("# ")
|
||||||
buffer.WriteString(path.Description)
|
buffer.WriteString(entry.Description)
|
||||||
buffer.WriteString("\n")
|
buffer.WriteString("\n")
|
||||||
buffer.WriteString(path.Name)
|
buffer.WriteString(entry.Name)
|
||||||
buffer.WriteString("=")
|
buffer.WriteString("=")
|
||||||
fmt.Fprintf(&buffer, "%v", path.Value)
|
fmt.Fprintf(&buffer, "%v", entry.Value)
|
||||||
buffer.WriteString("\n\n")
|
buffer.WriteString("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
return buffer.Bytes()
|
return buffer.Bytes()
|
||||||
|
|||||||
127
gen/gen_md.go
Normal file
127
gen/gen_md.go
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
|
"log/slog"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/steveiliop56/tinyauth/internal/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MarkdownEntry struct {
|
||||||
|
Env string
|
||||||
|
Flag string
|
||||||
|
Description string
|
||||||
|
Default any
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateMarkdown() {
|
||||||
|
cfg := config.NewDefaultConfiguration()
|
||||||
|
entries := make([]MarkdownEntry, 0)
|
||||||
|
|
||||||
|
root := reflect.TypeOf(cfg).Elem()
|
||||||
|
rootValue := reflect.ValueOf(cfg).Elem()
|
||||||
|
rootPath := "tinyauth."
|
||||||
|
|
||||||
|
walkAndBuild(root, rootValue, rootPath, &entries, buildMdEntry, buildMdMapEntry, buildMdChildPath)
|
||||||
|
compiled := compileMd(entries)
|
||||||
|
|
||||||
|
err := os.Remove("config.gen.md")
|
||||||
|
if err != nil && !errors.Is(err, fs.ErrNotExist) {
|
||||||
|
slog.Error("failed to remove example env file", "error", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.WriteFile("config.gen.md", compiled, 0644)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("failed to write example env file", "error", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildMdEntry(child reflect.StructField, childValue reflect.Value, parentPath string, entries *[]MarkdownEntry) {
|
||||||
|
desc := child.Tag.Get("description")
|
||||||
|
tag := child.Tag.Get("yaml")
|
||||||
|
|
||||||
|
if tag == "-" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
value := childValue.Interface()
|
||||||
|
|
||||||
|
entry := MarkdownEntry{
|
||||||
|
Env: strings.ToUpper(strings.ReplaceAll(parentPath, ".", "_")) + strings.ToUpper(child.Name),
|
||||||
|
Flag: fmt.Sprintf("--%s%s", strings.TrimPrefix(parentPath, "tinyauth."), tag),
|
||||||
|
Description: desc,
|
||||||
|
}
|
||||||
|
|
||||||
|
switch childValue.Kind() {
|
||||||
|
case reflect.Slice:
|
||||||
|
sl, ok := value.([]string)
|
||||||
|
if !ok {
|
||||||
|
slog.Error("invalid default value", "value", value)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
entry.Default = fmt.Sprintf("`%s`", strings.Join(sl, ","))
|
||||||
|
default:
|
||||||
|
entry.Default = fmt.Sprintf("`%v`", value)
|
||||||
|
}
|
||||||
|
*entries = append(*entries, entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildMdMapEntry(child reflect.StructField, parentPath string, entries *[]MarkdownEntry) {
|
||||||
|
fieldType := child.Type
|
||||||
|
|
||||||
|
if fieldType.Key().Kind() != reflect.String {
|
||||||
|
slog.Info("unsupported map key type", "type", fieldType.Key().Kind())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tag := child.Tag.Get("yaml")
|
||||||
|
|
||||||
|
if tag == "-" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mapPath := parentPath + tag + ".[name]."
|
||||||
|
valueType := fieldType.Elem()
|
||||||
|
|
||||||
|
if valueType.Kind() == reflect.Struct {
|
||||||
|
zeroValue := reflect.New(valueType).Elem()
|
||||||
|
walkAndBuild(valueType, zeroValue, mapPath, entries, buildMdEntry, buildMdMapEntry, buildMdChildPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildMdChildPath(parent string, child string) string {
|
||||||
|
return parent + strings.ToLower(child) + "."
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileMd(entries []MarkdownEntry) []byte {
|
||||||
|
buffer := bytes.Buffer{}
|
||||||
|
|
||||||
|
buffer.WriteString("# Tinyauth configuration reference\n\n")
|
||||||
|
buffer.WriteString("| Environment | Flag | Description | Default |\n")
|
||||||
|
buffer.WriteString("| - | - | - | - |\n")
|
||||||
|
|
||||||
|
previousSection := ""
|
||||||
|
|
||||||
|
for _, entry := range entries {
|
||||||
|
if strings.Count(entry.Env, "_") > 1 {
|
||||||
|
section := strings.Split(strings.TrimPrefix(entry.Env, "TINYAUTH_"), "_")[0]
|
||||||
|
if section != previousSection {
|
||||||
|
buffer.WriteString("\n## " + strings.ToLower(section) + "\n\n")
|
||||||
|
buffer.WriteString("| Environment | Flag | Description | Default |\n")
|
||||||
|
buffer.WriteString("| - | - | - | - |\n")
|
||||||
|
previousSection = section
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Fprintf(&buffer, "| `%s` | `%s` | %s | %s |\n", entry.Env, entry.Flag, entry.Description, entry.Default)
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer.Bytes()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user