mirror of
				https://github.com/steveiliop56/tinyauth.git
				synced 2025-10-30 21:55:43 +00:00 
			
		
		
		
	Compare commits
	
		
			11 Commits
		
	
	
		
			feat/analy
			...
			b5eaf05629
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| ![dependabot[bot]](/assets/img/avatar_default.png)  | b5eaf05629 | ||
|   | 085f6257c5 | ||
|   | c307f7eb2e | ||
|   | 5dd8526833 | ||
|   | e8558b89b4 | ||
|   | f8047a6c2e | ||
|   | e114bf0943 | ||
|   | c9867ccb76 | ||
|   | 866933b3d6 | ||
|   | d70cbea546 | ||
|   | 50105e4e9d | 
							
								
								
									
										19
									
								
								.env.example
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								.env.example
									
									
									
									
									
								
							| @@ -4,20 +4,6 @@ APP_URL=http://localhost:3000 | ||||
| USERS=your_user_password_hash | ||||
| USERS_FILE=users_file | ||||
| SECURE_COOKIE=false | ||||
| GITHUB_CLIENT_ID=github_client_id | ||||
| GITHUB_CLIENT_SECRET=github_client_secret | ||||
| GITHUB_CLIENT_SECRET_FILE=github_client_secret_file | ||||
| GOOGLE_CLIENT_ID=google_client_id | ||||
| GOOGLE_CLIENT_SECRET=google_client_secret | ||||
| GOOGLE_CLIENT_SECRET_FILE=google_client_secret_file | ||||
| GENERIC_CLIENT_ID=generic_client_id | ||||
| GENERIC_CLIENT_SECRET=generic_client_secret | ||||
| GENERIC_CLIENT_SECRET_FILE=generic_client_secret_file | ||||
| GENERIC_SCOPES=generic_scopes | ||||
| GENERIC_AUTH_URL=generic_auth_url | ||||
| GENERIC_TOKEN_URL=generic_token_url | ||||
| GENERIC_USER_URL=generic_user_url | ||||
| DISABLE_CONTINUE=false | ||||
| OAUTH_WHITELIST= | ||||
| GENERIC_NAME=My OAuth | ||||
| SESSION_EXPIRY=7200 | ||||
| @@ -30,4 +16,7 @@ OAUTH_AUTO_REDIRECT=none | ||||
| BACKGROUND_IMAGE=some_image_url | ||||
| GENERIC_SKIP_SSL=false | ||||
| RESOURCES_DIR=/data/resources | ||||
| DATABASE_PATH=/data/tinyauth.db | ||||
| DATABASE_PATH=/data/tinyauth.db | ||||
| DISABLE_ANALYTICS=false | ||||
| DISABLE_RESOURCES=false | ||||
| TRUSTED_PROXIES= | ||||
							
								
								
									
										4
									
								
								.github/workflows/nightly.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/nightly.yml
									
									
									
									
										vendored
									
									
								
							| @@ -80,7 +80,7 @@ jobs: | ||||
|       - name: Build | ||||
|         run: | | ||||
|           cp -r frontend/dist internal/assets/dist | ||||
|           go build -ldflags "-s -w -X tinyauth/internal/constants.Version=${{ needs.generate-metadata.outputs.VERSION }} -X tinyauth/internal/constants.CommitHash=${{ needs.generate-metadata.outputs.COMMIT_HASH }} -X tinyauth/internal/constants.BuildTimestamp=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}" -o tinyauth-amd64 | ||||
|           go build -ldflags "-s -w -X tinyauth/internal/config.Version=${{ needs.generate-metadata.outputs.VERSION }} -X tinyauth/internal/config.CommitHash=${{ needs.generate-metadata.outputs.COMMIT_HASH }} -X tinyauth/internal/config.BuildTimestamp=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}" -o tinyauth-amd64 | ||||
|         env: | ||||
|           CGO_ENABLED: 0 | ||||
|  | ||||
| @@ -126,7 +126,7 @@ jobs: | ||||
|       - name: Build | ||||
|         run: | | ||||
|           cp -r frontend/dist internal/assets/dist | ||||
|           go build -ldflags "-s -w -X tinyauth/internal/constants.Version=${{ needs.generate-metadata.outputs.VERSION }} -X tinyauth/internal/constants.CommitHash=${{ needs.generate-metadata.outputs.COMMIT_HASH }} -X tinyauth/internal/constants.BuildTimestamp=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}" -o tinyauth-arm64 | ||||
|           go build -ldflags "-s -w -X tinyauth/internal/config.Version=${{ needs.generate-metadata.outputs.VERSION }} -X tinyauth/internal/config.CommitHash=${{ needs.generate-metadata.outputs.COMMIT_HASH }} -X tinyauth/internal/config.BuildTimestamp=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}" -o tinyauth-arm64 | ||||
|         env: | ||||
|           CGO_ENABLED: 0 | ||||
|  | ||||
|   | ||||
							
								
								
									
										4
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							| @@ -58,7 +58,7 @@ jobs: | ||||
|       - name: Build | ||||
|         run: | | ||||
|           cp -r frontend/dist internal/assets/dist | ||||
|           go build -ldflags "-s -w -X tinyauth/internal/constants.Version=${{ needs.generate-metadata.outputs.VERSION }} -X tinyauth/internal/constants.CommitHash=${{ needs.generate-metadata.outputs.COMMIT_HASH }} -X tinyauth/internal/constants.BuildTimestamp=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}" -o tinyauth-amd64 | ||||
|           go build -ldflags "-s -w -X tinyauth/internal/config.Version=${{ needs.generate-metadata.outputs.VERSION }} -X tinyauth/internal/config.CommitHash=${{ needs.generate-metadata.outputs.COMMIT_HASH }} -X tinyauth/internal/config.BuildTimestamp=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}" -o tinyauth-amd64 | ||||
|         env: | ||||
|           CGO_ENABLED: 0 | ||||
|  | ||||
| @@ -101,7 +101,7 @@ jobs: | ||||
|       - name: Build | ||||
|         run: | | ||||
|           cp -r frontend/dist internal/assets/dist | ||||
|           go build -ldflags "-s -w -X tinyauth/internal/constants.Version=${{ needs.generate-metadata.outputs.VERSION }} -X tinyauth/internal/constants.CommitHash=${{ needs.generate-metadata.outputs.COMMIT_HASH }} -X tinyauth/internal/constants.BuildTimestamp=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}" -o tinyauth-arm64 | ||||
|           go build -ldflags "-s -w -X tinyauth/internal/config.Version=${{ needs.generate-metadata.outputs.VERSION }} -X tinyauth/internal/config.CommitHash=${{ needs.generate-metadata.outputs.COMMIT_HASH }} -X tinyauth/internal/config.BuildTimestamp=${{ needs.generate-metadata.outputs.BUILD_TIMESTAMP }}" -o tinyauth-arm64 | ||||
|         env: | ||||
|           CGO_ENABLED: 0 | ||||
|  | ||||
|   | ||||
| @@ -38,7 +38,7 @@ COPY ./cmd ./cmd | ||||
| COPY ./internal ./internal | ||||
| COPY --from=frontend-builder /frontend/dist ./internal/assets/dist | ||||
|  | ||||
| RUN CGO_ENABLED=0 go build -ldflags "-s -w -X tinyauth/internal/constants.Version=${VERSION} -X tinyauth/internal/constants.CommitHash=${COMMIT_HASH} -X tinyauth/internal/constants.BuildTimestamp=${BUILD_TIMESTAMP}"  | ||||
| RUN CGO_ENABLED=0 go build -ldflags "-s -w -X tinyauth/internal/config.Version=${VERSION} -X tinyauth/internal/config.CommitHash=${COMMIT_HASH} -X tinyauth/internal/config.BuildTimestamp=${BUILD_TIMESTAMP}"  | ||||
|   | ||||
| # Runner | ||||
| FROM alpine:3.22 AS runner | ||||
|   | ||||
| @@ -94,6 +94,8 @@ func init() { | ||||
| 		{"resources-dir", "/data/resources", "Path to a directory containing custom resources (e.g. background image)."}, | ||||
| 		{"database-path", "/data/tinyauth.db", "Path to the Sqlite database file."}, | ||||
| 		{"trusted-proxies", "", "Comma separated list of trusted proxies (IP addresses or CIDRs) for correct client IP detection."}, | ||||
| 		{"disable-analytics", false, "Disable anonymous version collection."}, | ||||
| 		{"disable-resources", false, "Disable the resources server."}, | ||||
| 	} | ||||
|  | ||||
| 	for _, opt := range configOptions { | ||||
|   | ||||
| @@ -70,7 +70,7 @@ var VerifyCmd = &cobra.Command{ | ||||
|  | ||||
| 		err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(iPassword)) | ||||
| 		if err != nil { | ||||
| 			log.Fatal().Msg("Ppassword is incorrect") | ||||
| 			log.Fatal().Msg("Password is incorrect") | ||||
| 		} | ||||
|  | ||||
| 		if user.TotpSecret == "" { | ||||
|   | ||||
| @@ -34,6 +34,10 @@ services: | ||||
|     build: | ||||
|       context: . | ||||
|       dockerfile: Dockerfile.dev | ||||
|       args: | ||||
|         - VERSION=development | ||||
|         - COMMIT_HASH=development | ||||
|         - BUILD_TIMESTAMP=000-00-00T00:00:00Z | ||||
|     env_file: .env | ||||
|     volumes: | ||||
|       - ./internal:/tinyauth/internal | ||||
|   | ||||
							
								
								
									
										25
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								go.mod
									
									
									
									
									
								
							| @@ -6,7 +6,7 @@ toolchain go1.24.3 | ||||
|  | ||||
| require ( | ||||
| 	github.com/cenkalti/backoff/v5 v5.0.3 | ||||
| 	github.com/gin-gonic/gin v1.10.1 | ||||
| 	github.com/gin-gonic/gin v1.11.0 | ||||
| 	github.com/glebarez/sqlite v1.11.0 | ||||
| 	github.com/go-playground/validator/v10 v10.27.0 | ||||
| 	github.com/golang-migrate/migrate/v4 v4.19.0 | ||||
| @@ -34,6 +34,7 @@ require ( | ||||
| 	github.com/glebarez/go-sqlite v1.21.2 // indirect | ||||
| 	github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect | ||||
| 	github.com/go-viper/mapstructure/v2 v2.4.0 // indirect | ||||
| 	github.com/goccy/go-yaml v1.18.0 // indirect | ||||
| 	github.com/google/go-cmp v0.7.0 // indirect | ||||
| 	github.com/hashicorp/errwrap v1.1.0 // indirect | ||||
| 	github.com/hashicorp/go-multierror v1.1.1 // indirect | ||||
| @@ -43,13 +44,18 @@ require ( | ||||
| 	github.com/moby/sys/atomicwriter v0.1.0 // indirect | ||||
| 	github.com/moby/term v0.5.2 // indirect | ||||
| 	github.com/ncruces/go-strftime v0.1.9 // indirect | ||||
| 	github.com/quic-go/qpack v0.5.1 // indirect | ||||
| 	github.com/quic-go/quic-go v0.54.0 // indirect | ||||
| 	github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect | ||||
| 	github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect | ||||
| 	go.opentelemetry.io/auto/sdk v1.1.0 // indirect | ||||
| 	go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0 // indirect | ||||
| 	go.opentelemetry.io/otel/sdk v1.34.0 // indirect | ||||
| 	go.uber.org/mock v0.5.0 // indirect | ||||
| 	go.yaml.in/yaml/v3 v3.0.4 // indirect | ||||
| 	golang.org/x/mod v0.27.0 // indirect | ||||
| 	golang.org/x/term v0.35.0 // indirect | ||||
| 	golang.org/x/tools v0.36.0 // indirect | ||||
| 	modernc.org/libc v1.66.3 // indirect | ||||
| 	modernc.org/mathutil v1.7.1 // indirect | ||||
| 	modernc.org/memory v1.11.0 // indirect | ||||
| @@ -62,8 +68,8 @@ require ( | ||||
| 	github.com/atotto/clipboard v0.1.4 // indirect | ||||
| 	github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect | ||||
| 	github.com/boombuler/barcode v1.0.2 // indirect | ||||
| 	github.com/bytedance/sonic v1.12.7 // indirect | ||||
| 	github.com/bytedance/sonic/loader v0.2.3 // indirect | ||||
| 	github.com/bytedance/sonic v1.14.0 // indirect | ||||
| 	github.com/bytedance/sonic/loader v0.3.0 // indirect | ||||
| 	github.com/catppuccin/go v0.3.0 // indirect | ||||
| 	github.com/charmbracelet/bubbles v0.21.0 // indirect | ||||
| 	github.com/charmbracelet/bubbletea v1.3.4 // indirect | ||||
| @@ -72,7 +78,7 @@ require ( | ||||
| 	github.com/charmbracelet/x/ansi v0.8.0 // indirect | ||||
| 	github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 // indirect | ||||
| 	github.com/charmbracelet/x/term v0.2.1 // indirect | ||||
| 	github.com/cloudwego/base64x v0.1.4 // indirect | ||||
| 	github.com/cloudwego/base64x v0.1.6 // indirect | ||||
| 	github.com/distribution/reference v0.6.0 // indirect | ||||
| 	github.com/docker/docker v28.4.0+incompatible | ||||
| 	github.com/docker/go-connections v0.5.0 // indirect | ||||
| @@ -82,7 +88,7 @@ require ( | ||||
| 	github.com/felixge/httpsnoop v1.0.4 // indirect | ||||
| 	github.com/fsnotify/fsnotify v1.9.0 // indirect | ||||
| 	github.com/gabriel-vasile/mimetype v1.4.8 // indirect | ||||
| 	github.com/gin-contrib/sse v1.0.0 // indirect | ||||
| 	github.com/gin-contrib/sse v1.1.0 // indirect | ||||
| 	github.com/go-ldap/ldap/v3 v3.4.11 | ||||
| 	github.com/go-logr/logr v1.4.3 // indirect | ||||
| 	github.com/go-logr/stdr v1.2.2 // indirect | ||||
| @@ -91,7 +97,7 @@ require ( | ||||
| 	github.com/goccy/go-json v0.10.4 // indirect | ||||
| 	github.com/inconshreveable/mousetrap v1.1.0 // indirect | ||||
| 	github.com/json-iterator/go v1.1.12 // indirect | ||||
| 	github.com/klauspost/cpuid/v2 v2.2.9 // indirect | ||||
| 	github.com/klauspost/cpuid/v2 v2.3.0 // indirect | ||||
| 	github.com/leodido/go-urn v1.4.0 // indirect | ||||
| 	github.com/lucasb-eyer/go-colorful v1.2.0 // indirect | ||||
| 	github.com/mattn/go-colorable v0.1.14 // indirect | ||||
| @@ -118,17 +124,16 @@ require ( | ||||
| 	github.com/spf13/pflag v1.0.10 // indirect | ||||
| 	github.com/subosito/gotenv v1.6.0 // indirect | ||||
| 	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect | ||||
| 	github.com/ugorji/go/codec v1.2.12 // indirect | ||||
| 	github.com/ugorji/go/codec v1.3.0 // indirect | ||||
| 	go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect | ||||
| 	go.opentelemetry.io/otel v1.37.0 // indirect | ||||
| 	go.opentelemetry.io/otel/metric v1.37.0 // indirect | ||||
| 	go.opentelemetry.io/otel/trace v1.37.0 // indirect | ||||
| 	golang.org/x/arch v0.13.0 // indirect | ||||
| 	golang.org/x/arch v0.20.0 // indirect | ||||
| 	golang.org/x/net v0.44.0 // indirect | ||||
| 	golang.org/x/oauth2 v0.31.0 | ||||
| 	golang.org/x/sync v0.17.0 // indirect | ||||
| 	golang.org/x/sys v0.36.0 // indirect | ||||
| 	golang.org/x/text v0.29.0 // indirect | ||||
| 	google.golang.org/protobuf v1.36.3 // indirect | ||||
| 	gopkg.in/yaml.v3 v3.0.1 // indirect | ||||
| 	google.golang.org/protobuf v1.36.9 // indirect | ||||
| ) | ||||
|   | ||||
							
								
								
									
										53
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										53
									
								
								go.sum
									
									
									
									
									
								
							| @@ -17,11 +17,10 @@ github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/ | ||||
| github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= | ||||
| github.com/boombuler/barcode v1.0.2 h1:79yrbttoZrLGkL/oOI8hBrUKucwOL0oOjUgEguGMcJ4= | ||||
| github.com/boombuler/barcode v1.0.2/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= | ||||
| github.com/bytedance/sonic v1.12.7 h1:CQU8pxOy9HToxhndH0Kx/S1qU/CuS9GnKYrGioDcU1Q= | ||||
| github.com/bytedance/sonic v1.12.7/go.mod h1:tnbal4mxOMju17EGfknm2XyYcpyCnIROYOEYuemj13I= | ||||
| github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= | ||||
| github.com/bytedance/sonic/loader v0.2.3 h1:yctD0Q3v2NOGfSWPLPvG2ggA2kV6TS6s4wioyEqssH0= | ||||
| github.com/bytedance/sonic/loader v0.2.3/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= | ||||
| github.com/bytedance/sonic v1.14.0 h1:/OfKt8HFw0kh2rj8N0F6C/qPGRESq0BbaNZgcNXXzQQ= | ||||
| github.com/bytedance/sonic v1.14.0/go.mod h1:WoEbx8WTcFJfzCe0hbmyTGrfjt8PzNEBdxlNUO24NhA= | ||||
| github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZwvZJyqeA= | ||||
| github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= | ||||
| github.com/catppuccin/go v0.3.0 h1:d+0/YicIq+hSTo5oPuRi5kOpqkVA5tAsU6dNhvRu+aY= | ||||
| github.com/catppuccin/go v0.3.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc= | ||||
| github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= | ||||
| @@ -56,9 +55,8 @@ github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8 | ||||
| github.com/charmbracelet/x/termios v0.1.1/go.mod h1:rB7fnv1TgOPOyyKRJ9o+AsTU/vK5WHJ2ivHeut/Pcwo= | ||||
| github.com/charmbracelet/x/xpty v0.1.2 h1:Pqmu4TEJ8KeA9uSkISKMU3f+C1F6OGBn8ABuGlqCbtI= | ||||
| github.com/charmbracelet/x/xpty v0.1.2/go.mod h1:XK2Z0id5rtLWcpeNiMYBccNNBrP2IJnzHI0Lq13Xzq4= | ||||
| github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= | ||||
| github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= | ||||
| github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= | ||||
| github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M= | ||||
| github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU= | ||||
| github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= | ||||
| github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= | ||||
| github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= | ||||
| @@ -92,10 +90,10 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S | ||||
| github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= | ||||
| github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= | ||||
| github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= | ||||
| github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E= | ||||
| github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0= | ||||
| github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ= | ||||
| github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= | ||||
| github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w= | ||||
| github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM= | ||||
| github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk= | ||||
| github.com/gin-gonic/gin v1.11.0/go.mod h1:+iq/FyxlGzII0KHiBGjuNn4UNENUlKbGlNmc+W50Dls= | ||||
| github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo= | ||||
| github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k= | ||||
| github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw= | ||||
| @@ -121,6 +119,8 @@ github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9L | ||||
| github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= | ||||
| github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM= | ||||
| github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= | ||||
| github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= | ||||
| github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= | ||||
| github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= | ||||
| github.com/golang-migrate/migrate/v4 v4.19.0 h1:RcjOnCGz3Or6HQYEJ/EEVLfWnmw9KnoigPSjzhCuaSE= | ||||
| github.com/golang-migrate/migrate/v4 v4.19.0/go.mod h1:9dyEcu+hO+G9hPSw8AIg50yg622pXJsoHItQnDGZkI0= | ||||
| @@ -163,10 +163,8 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= | ||||
| github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= | ||||
| github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= | ||||
| github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= | ||||
| github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= | ||||
| github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= | ||||
| github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= | ||||
| github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= | ||||
| github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= | ||||
| github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= | ||||
| github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= | ||||
| github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= | ||||
| github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= | ||||
| @@ -229,6 +227,10 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb | ||||
| github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||||
| github.com/pquerna/otp v1.5.0 h1:NMMR+WrmaqXU4EzdGJEE1aUUI0AMRzsp96fFFWNPwxs= | ||||
| github.com/pquerna/otp v1.5.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= | ||||
| github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= | ||||
| github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= | ||||
| github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQBg= | ||||
| github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY= | ||||
| github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= | ||||
| github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= | ||||
| github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= | ||||
| @@ -260,14 +262,10 @@ github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjb | ||||
| github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||
| github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= | ||||
| github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= | ||||
| github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= | ||||
| github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | ||||
| github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||||
| github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||||
| github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= | ||||
| github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= | ||||
| github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= | ||||
| github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= | ||||
| github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= | ||||
| github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= | ||||
| github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= | ||||
| @@ -276,8 +274,8 @@ github.com/traefik/paerser v0.2.2 h1:cpzW/ZrQrBh3mdwD/jnp6aXASiUFKOVr6ldP+keJTcQ | ||||
| github.com/traefik/paerser v0.2.2/go.mod h1:7BBDd4FANoVgaTZG+yh26jI6CA2nds7D/4VTEdIsh24= | ||||
| github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= | ||||
| github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= | ||||
| github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= | ||||
| github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= | ||||
| github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA= | ||||
| github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4= | ||||
| github.com/weppos/publicsuffix-go v0.50.0 h1:M178k6l8cnh9T1c1cStkhytVxdk5zPd6gGZf8ySIuVo= | ||||
| github.com/weppos/publicsuffix-go v0.50.0/go.mod h1:VXhClBYMlDrUsome4pOTpe68Ui0p6iQRAbyHQD1yKoU= | ||||
| github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= | ||||
| @@ -300,10 +298,12 @@ go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mx | ||||
| go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= | ||||
| go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= | ||||
| go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= | ||||
| go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= | ||||
| go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= | ||||
| go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= | ||||
| go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= | ||||
| golang.org/x/arch v0.13.0 h1:KCkqVVV1kGg0X87TFysjCJ8MxtZEIU4Ja/yXGeoECdA= | ||||
| golang.org/x/arch v0.13.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= | ||||
| golang.org/x/arch v0.20.0 h1:dx1zTU0MAE98U+TQ8BLl7XsJbgze2WnNKF/8tGp/Q6c= | ||||
| golang.org/x/arch v0.20.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk= | ||||
| golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= | ||||
| golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= | ||||
| golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o= | ||||
| @@ -338,8 +338,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1: | ||||
| google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= | ||||
| google.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A= | ||||
| google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= | ||||
| google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU= | ||||
| google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= | ||||
| google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= | ||||
| google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= | ||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||
| gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= | ||||
| gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= | ||||
| @@ -376,6 +376,5 @@ modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= | ||||
| modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= | ||||
| modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= | ||||
| modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= | ||||
| nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= | ||||
| rsc.io/qr v0.2.0 h1:6vBLea5/NRMVTz8V66gipeLycZMl/+UlFmk8DvqQ6WY= | ||||
| rsc.io/qr v0.2.0/go.mod h1:IF+uZjkb9fqyeF/4tlBoynqmQxUoPfWEKh921coOuXs= | ||||
|   | ||||
| @@ -1,10 +1,14 @@ | ||||
| package bootstrap | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"os" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| 	"tinyauth/internal/config" | ||||
| 	"tinyauth/internal/controller" | ||||
| 	"tinyauth/internal/middleware" | ||||
| @@ -29,40 +33,43 @@ type Service interface { | ||||
| } | ||||
|  | ||||
| type BootstrapApp struct { | ||||
| 	Config config.Config | ||||
| 	config config.Config | ||||
| 	uuid   string | ||||
| } | ||||
|  | ||||
| func NewBootstrapApp(config config.Config) *BootstrapApp { | ||||
| 	return &BootstrapApp{ | ||||
| 		Config: config, | ||||
| 		config: config, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (app *BootstrapApp) Setup() error { | ||||
| 	// Parse users | ||||
| 	users, err := utils.GetUsers(app.Config.Users, app.Config.UsersFile) | ||||
| 	users, err := utils.GetUsers(app.config.Users, app.config.UsersFile) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	// Get OAuth configs | ||||
| 	oauthProviders, err := utils.GetOAuthProvidersConfig(os.Environ(), os.Args, app.Config.AppURL) | ||||
| 	oauthProviders, err := utils.GetOAuthProvidersConfig(os.Environ(), os.Args, app.config.AppURL) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	// Get cookie domain | ||||
| 	cookieDomain, err := utils.GetCookieDomain(app.Config.AppURL) | ||||
| 	cookieDomain, err := utils.GetCookieDomain(app.config.AppURL) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	// Cookie names | ||||
| 	appUrl, _ := url.Parse(app.Config.AppURL) // Already validated | ||||
| 	cookieId := utils.GenerateIdentifier(appUrl.Hostname()) | ||||
| 	appUrl, _ := url.Parse(app.config.AppURL) // Already validated | ||||
| 	uuid := utils.GenerateUUID(appUrl.Hostname()) | ||||
| 	app.uuid = uuid | ||||
| 	cookieId := strings.Split(uuid, "-")[0] | ||||
| 	sessionCookieName := fmt.Sprintf("%s-%s", config.SessionCookieName, cookieId) | ||||
| 	csrfCookieName := fmt.Sprintf("%s-%s", config.CSRFCookieName, cookieId) | ||||
| 	redirectCookieName := fmt.Sprintf("%s-%s", config.RedirectCookieName, cookieId) | ||||
| @@ -70,26 +77,26 @@ func (app *BootstrapApp) Setup() error { | ||||
| 	// Create configs | ||||
| 	authConfig := service.AuthServiceConfig{ | ||||
| 		Users:             users, | ||||
| 		OauthWhitelist:    app.Config.OAuthWhitelist, | ||||
| 		SessionExpiry:     app.Config.SessionExpiry, | ||||
| 		SecureCookie:      app.Config.SecureCookie, | ||||
| 		OauthWhitelist:    app.config.OAuthWhitelist, | ||||
| 		SessionExpiry:     app.config.SessionExpiry, | ||||
| 		SecureCookie:      app.config.SecureCookie, | ||||
| 		CookieDomain:      cookieDomain, | ||||
| 		LoginTimeout:      app.Config.LoginTimeout, | ||||
| 		LoginMaxRetries:   app.Config.LoginMaxRetries, | ||||
| 		LoginTimeout:      app.config.LoginTimeout, | ||||
| 		LoginMaxRetries:   app.config.LoginMaxRetries, | ||||
| 		SessionCookieName: sessionCookieName, | ||||
| 	} | ||||
|  | ||||
| 	// Setup services | ||||
| 	var ldapService *service.LdapService | ||||
|  | ||||
| 	if app.Config.LdapAddress != "" { | ||||
| 	if app.config.LdapAddress != "" { | ||||
| 		ldapConfig := service.LdapServiceConfig{ | ||||
| 			Address:      app.Config.LdapAddress, | ||||
| 			BindDN:       app.Config.LdapBindDN, | ||||
| 			BindPassword: app.Config.LdapBindPassword, | ||||
| 			BaseDN:       app.Config.LdapBaseDN, | ||||
| 			Insecure:     app.Config.LdapInsecure, | ||||
| 			SearchFilter: app.Config.LdapSearchFilter, | ||||
| 			Address:      app.config.LdapAddress, | ||||
| 			BindDN:       app.config.LdapBindDN, | ||||
| 			BindPassword: app.config.LdapBindPassword, | ||||
| 			BaseDN:       app.config.LdapBaseDN, | ||||
| 			Insecure:     app.config.LdapInsecure, | ||||
| 			SearchFilter: app.config.LdapSearchFilter, | ||||
| 		} | ||||
|  | ||||
| 		ldapService = service.NewLdapService(ldapConfig) | ||||
| @@ -104,7 +111,7 @@ func (app *BootstrapApp) Setup() error { | ||||
|  | ||||
| 	// Bootstrap database | ||||
| 	databaseService := service.NewDatabaseService(service.DatabaseServiceConfig{ | ||||
| 		DatabasePath: app.Config.DatabasePath, | ||||
| 		DatabasePath: app.config.DatabasePath, | ||||
| 	}) | ||||
|  | ||||
| 	log.Debug().Str("service", fmt.Sprintf("%T", databaseService)).Msg("Initializing service") | ||||
| @@ -140,10 +147,6 @@ func (app *BootstrapApp) Setup() error { | ||||
| 	} | ||||
|  | ||||
| 	// Configured providers | ||||
| 	babysit := map[string]string{ | ||||
| 		"google": "Google", | ||||
| 		"github": "GitHub", | ||||
| 	} | ||||
| 	configuredProviders := make([]controller.Provider, 0) | ||||
|  | ||||
| 	for id, provider := range oauthProviders { | ||||
| @@ -152,7 +155,7 @@ func (app *BootstrapApp) Setup() error { | ||||
| 		} | ||||
|  | ||||
| 		if provider.Name == "" { | ||||
| 			if name, ok := babysit[id]; ok { | ||||
| 			if name, ok := config.OverrideProviders[id]; ok { | ||||
| 				provider.Name = name | ||||
| 			} else { | ||||
| 				provider.Name = utils.Capitalize(id) | ||||
| @@ -181,16 +184,20 @@ func (app *BootstrapApp) Setup() error { | ||||
| 	} | ||||
|  | ||||
| 	// Create engine | ||||
| 	engine := gin.New() | ||||
|  | ||||
| 	if len(app.Config.TrustedProxies) > 0 { | ||||
| 		engine.SetTrustedProxies(strings.Split(app.Config.TrustedProxies, ",")) | ||||
| 	} | ||||
|  | ||||
| 	if config.Version != "development" { | ||||
| 		gin.SetMode(gin.ReleaseMode) | ||||
| 	} | ||||
|  | ||||
| 	engine := gin.New() | ||||
|  | ||||
| 	if len(app.config.TrustedProxies) > 0 { | ||||
| 		err := engine.SetTrustedProxies(strings.Split(app.config.TrustedProxies, ",")) | ||||
|  | ||||
| 		if err != nil { | ||||
| 			return fmt.Errorf("failed to set trusted proxies: %w", err) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Create middlewares | ||||
| 	var middlewares []Middleware | ||||
|  | ||||
| @@ -219,24 +226,24 @@ func (app *BootstrapApp) Setup() error { | ||||
| 	// Create controllers | ||||
| 	contextController := controller.NewContextController(controller.ContextControllerConfig{ | ||||
| 		Providers:             configuredProviders, | ||||
| 		Title:                 app.Config.Title, | ||||
| 		AppURL:                app.Config.AppURL, | ||||
| 		Title:                 app.config.Title, | ||||
| 		AppURL:                app.config.AppURL, | ||||
| 		CookieDomain:          cookieDomain, | ||||
| 		ForgotPasswordMessage: app.Config.ForgotPasswordMessage, | ||||
| 		BackgroundImage:       app.Config.BackgroundImage, | ||||
| 		OAuthAutoRedirect:     app.Config.OAuthAutoRedirect, | ||||
| 		ForgotPasswordMessage: app.config.ForgotPasswordMessage, | ||||
| 		BackgroundImage:       app.config.BackgroundImage, | ||||
| 		OAuthAutoRedirect:     app.config.OAuthAutoRedirect, | ||||
| 	}, apiRouter) | ||||
|  | ||||
| 	oauthController := controller.NewOAuthController(controller.OAuthControllerConfig{ | ||||
| 		AppURL:             app.Config.AppURL, | ||||
| 		SecureCookie:       app.Config.SecureCookie, | ||||
| 		AppURL:             app.config.AppURL, | ||||
| 		SecureCookie:       app.config.SecureCookie, | ||||
| 		CSRFCookieName:     csrfCookieName, | ||||
| 		RedirectCookieName: redirectCookieName, | ||||
| 		CookieDomain:       cookieDomain, | ||||
| 	}, apiRouter, authService, oauthBrokerService) | ||||
|  | ||||
| 	proxyController := controller.NewProxyController(controller.ProxyControllerConfig{ | ||||
| 		AppURL: app.Config.AppURL, | ||||
| 		AppURL: app.config.AppURL, | ||||
| 	}, apiRouter, dockerService, authService) | ||||
|  | ||||
| 	userController := controller.NewUserController(controller.UserControllerConfig{ | ||||
| @@ -244,7 +251,8 @@ func (app *BootstrapApp) Setup() error { | ||||
| 	}, apiRouter, authService) | ||||
|  | ||||
| 	resourcesController := controller.NewResourcesController(controller.ResourcesControllerConfig{ | ||||
| 		ResourcesDir: app.Config.ResourcesDir, | ||||
| 		ResourcesDir:      app.config.ResourcesDir, | ||||
| 		ResourcesDisabled: app.config.DisableResources, | ||||
| 	}, mainRouter) | ||||
|  | ||||
| 	healthController := controller.NewHealthController(apiRouter) | ||||
| @@ -264,8 +272,14 @@ func (app *BootstrapApp) Setup() error { | ||||
| 		ctrl.SetupRoutes() | ||||
| 	} | ||||
|  | ||||
| 	// If analytics are not disabled, start heartbeat | ||||
| 	if !app.config.DisableAnalytics { | ||||
| 		log.Debug().Msg("Starting heartbeat routine") | ||||
| 		go app.heartbeat() | ||||
| 	} | ||||
|  | ||||
| 	// Start server | ||||
| 	address := fmt.Sprintf("%s:%d", app.Config.Address, app.Config.Port) | ||||
| 	address := fmt.Sprintf("%s:%d", app.config.Address, app.config.Port) | ||||
| 	log.Info().Msgf("Starting server on %s", address) | ||||
| 	if err := engine.Run(address); err != nil { | ||||
| 		log.Fatal().Err(err).Msg("Failed to start server") | ||||
| @@ -273,3 +287,55 @@ func (app *BootstrapApp) Setup() error { | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (app *BootstrapApp) heartbeat() { | ||||
| 	ticker := time.NewTicker(time.Duration(12) * time.Hour) | ||||
| 	defer ticker.Stop() | ||||
|  | ||||
| 	type heartbeat struct { | ||||
| 		UUID    string `json:"uuid"` | ||||
| 		Version string `json:"version"` | ||||
| 	} | ||||
|  | ||||
| 	var body heartbeat | ||||
|  | ||||
| 	body.UUID = app.uuid | ||||
| 	body.Version = config.Version | ||||
|  | ||||
| 	bodyJson, err := json.Marshal(body) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		log.Error().Err(err).Msg("Failed to marshal heartbeat body") | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	client := &http.Client{} | ||||
|  | ||||
| 	heartbeatURL := config.ApiServer + "/v1/instances/heartbeat" | ||||
|  | ||||
| 	for ; true; <-ticker.C { | ||||
| 		log.Debug().Msg("Sending heartbeat") | ||||
|  | ||||
| 		req, err := http.NewRequest(http.MethodPost, heartbeatURL, bytes.NewReader(bodyJson)) | ||||
|  | ||||
| 		if err != nil { | ||||
| 			log.Error().Err(err).Msg("Failed to create heartbeat request") | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		req.Header.Add("Content-Type", "application/json") | ||||
|  | ||||
| 		res, err := client.Do(req) | ||||
|  | ||||
| 		if err != nil { | ||||
| 			log.Error().Err(err).Msg("Failed to send heartbeat") | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		res.Body.Close() | ||||
|  | ||||
| 		if res.StatusCode != 200 && res.StatusCode != 201 { | ||||
| 			log.Debug().Str("status", res.Status).Msg("Heartbeat returned non-200/201 status") | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -3,8 +3,8 @@ package config | ||||
| // Version information, set at build time | ||||
|  | ||||
| var Version = "development" | ||||
| var CommitHash = "n/a" | ||||
| var BuildTimestamp = "n/a" | ||||
| var CommitHash = "development" | ||||
| var BuildTimestamp = "0000-00-00T00:00:00Z" | ||||
|  | ||||
| // Cookie name templates | ||||
|  | ||||
| @@ -39,6 +39,8 @@ type Config struct { | ||||
| 	ResourcesDir          string `mapstructure:"resources-dir"` | ||||
| 	DatabasePath          string `mapstructure:"database-path" validate:"required"` | ||||
| 	TrustedProxies        string `mapstructure:"trusted-proxies"` | ||||
| 	DisableAnalytics      bool   `mapstructure:"disable-analytics"` | ||||
| 	DisableResources      bool   `mapstructure:"disable-resources"` | ||||
| } | ||||
|  | ||||
| // OAuth/OIDC config | ||||
| @@ -63,6 +65,11 @@ type OAuthServiceConfig struct { | ||||
| 	Name               string   `key:"name"` | ||||
| } | ||||
|  | ||||
| var OverrideProviders = map[string]string{ | ||||
| 	"google": "Google", | ||||
| 	"github": "GitHub", | ||||
| } | ||||
|  | ||||
| // User/session related stuff | ||||
|  | ||||
| type User struct { | ||||
| @@ -169,3 +176,7 @@ type AppPath struct { | ||||
| type Providers struct { | ||||
| 	Providers map[string]OAuthServiceConfig | ||||
| } | ||||
|  | ||||
| // API server | ||||
|  | ||||
| var ApiServer = "https://api.tinyauth.app" | ||||
|   | ||||
| @@ -7,7 +7,8 @@ import ( | ||||
| ) | ||||
|  | ||||
| type ResourcesControllerConfig struct { | ||||
| 	ResourcesDir string | ||||
| 	ResourcesDir      string | ||||
| 	ResourcesDisabled bool | ||||
| } | ||||
|  | ||||
| type ResourcesController struct { | ||||
| @@ -38,5 +39,12 @@ func (controller *ResourcesController) resourcesHandler(c *gin.Context) { | ||||
| 		}) | ||||
| 		return | ||||
| 	} | ||||
| 	if controller.config.ResourcesDisabled { | ||||
| 		c.JSON(403, gin.H{ | ||||
| 			"status":  403, | ||||
| 			"message": "Resources are disabled", | ||||
| 		}) | ||||
| 		return | ||||
| 	} | ||||
| 	controller.fileServer.ServeHTTP(c.Writer, c.Request) | ||||
| } | ||||
|   | ||||
| @@ -309,12 +309,14 @@ func (auth *AuthService) IsInOAuthGroup(c *gin.Context, context config.UserConte | ||||
| 		return true | ||||
| 	} | ||||
|  | ||||
| 	if context.Provider != "generic" { | ||||
| 		log.Debug().Msg("Not using generic provider, skipping group check") | ||||
| 		return true | ||||
| 	for id := range config.OverrideProviders { | ||||
| 		if context.Provider == id { | ||||
| 			log.Info().Str("provider", id).Msg("OAuth groups not supported for this provider") | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	for _, userGroup := range strings.Split(context.OAuthGroups, ",") { | ||||
| 	for userGroup := range strings.SplitSeq(context.OAuthGroups, ",") { | ||||
| 		if utils.CheckFilter(requiredGroups, strings.TrimSpace(userGroup)) { | ||||
| 			return true | ||||
| 		} | ||||
|   | ||||
| @@ -50,7 +50,7 @@ func (broker *OAuthBrokerService) Init() error { | ||||
| 			log.Error().Err(err).Msgf("Failed to initialize OAuth service: %T", name) | ||||
| 			return err | ||||
| 		} | ||||
| 		log.Info().Msgf("Initialized OAuth service: %T", name) | ||||
| 		log.Info().Str("service", service.GetName()).Msg("Initialized OAuth service") | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
|   | ||||
| @@ -183,14 +183,13 @@ func GetOAuthProvidersConfig(env []string, args []string, appUrl string) (map[st | ||||
| 		providers[name] = provider | ||||
| 	} | ||||
|  | ||||
| 	// If we have google/github providers and no redirect URL babysit them | ||||
| 	babysitProviders := []string{"google", "github"} | ||||
| 	// If we have google/github providers and no redirect URL then set a default | ||||
|  | ||||
| 	for _, name := range babysitProviders { | ||||
| 		if provider, exists := providers[name]; exists { | ||||
| 	for id := range config.OverrideProviders { | ||||
| 		if provider, exists := providers[id]; exists { | ||||
| 			if provider.RedirectURL == "" { | ||||
| 				provider.RedirectURL = appUrl + "/api/oauth/callback/" + name | ||||
| 				providers[name] = provider | ||||
| 				provider.RedirectURL = appUrl + "/api/oauth/callback/" + id | ||||
| 				providers[id] = provider | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|   | ||||
| @@ -18,10 +18,14 @@ func NormalizeKeys(keys map[string]string, rootName string, sep string) map[stri | ||||
|  | ||||
| 		finalKey = append(finalKey, rootName) | ||||
| 		finalKey = append(finalKey, "providers") | ||||
| 		cebabKey := strings.ToLower(k) | ||||
| 		lowerKey := strings.ToLower(k) | ||||
|  | ||||
| 		if !strings.HasPrefix(lowerKey, "providers"+sep) { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		for _, known := range knownKeys { | ||||
| 			if strings.HasSuffix(cebabKey, strings.ReplaceAll(known, "-", sep)) { | ||||
| 			if strings.HasSuffix(lowerKey, strings.ReplaceAll(known, "-", sep)) { | ||||
| 				suffix = known | ||||
| 				break | ||||
| 			} | ||||
| @@ -31,7 +35,11 @@ func NormalizeKeys(keys map[string]string, rootName string, sep string) map[stri | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		clientNameParts := strings.Split(strings.TrimPrefix(strings.TrimSuffix(cebabKey, sep+strings.ReplaceAll(suffix, "-", sep)), "providers"+sep), sep) | ||||
| 		if strings.TrimSpace(strings.TrimSuffix(strings.TrimPrefix(lowerKey, "providers"+sep), strings.ReplaceAll(suffix, "-", sep))) == "" { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		clientNameParts := strings.Split(strings.TrimPrefix(strings.TrimSuffix(lowerKey, sep+strings.ReplaceAll(suffix, "-", sep)), "providers"+sep), sep) | ||||
|  | ||||
| 		for i, p := range clientNameParts { | ||||
| 			if i == 0 { | ||||
| @@ -46,9 +54,9 @@ func NormalizeKeys(keys map[string]string, rootName string, sep string) map[stri | ||||
|  | ||||
| 		finalKey = append(finalKey, camelClientName) | ||||
|  | ||||
| 		filedParts := strings.Split(suffix, "-") | ||||
| 		fieldParts := strings.Split(suffix, "-") | ||||
|  | ||||
| 		for i, p := range filedParts { | ||||
| 		for i, p := range fieldParts { | ||||
| 			if i == 0 { | ||||
| 				camelField += p | ||||
| 				continue | ||||
|   | ||||
| @@ -14,6 +14,8 @@ func TestNormalizeKeys(t *testing.T) { | ||||
| 		"PROVIDERS_CLIENT1_CLIENT_SECRET":                "my-client-secret", | ||||
| 		"PROVIDERS_MY_AWESOME_CLIENT_CLIENT_ID":          "my-awesome-client-id", | ||||
| 		"PROVIDERS_MY_AWESOME_CLIENT_CLIENT_SECRET_FILE": "/path/to/secret", | ||||
| 		"I_LOOK_LIKE_A_KEY_CLIENT_ID":                    "should-not-appear", | ||||
| 		"PROVIDERS_CLIENT_ID":                            "should-not-appear", | ||||
| 	} | ||||
| 	expected := map[string]string{ | ||||
| 		"tinyauth.providers.client1.clientId":                 "my-client-id", | ||||
| @@ -31,6 +33,9 @@ func TestNormalizeKeys(t *testing.T) { | ||||
| 		"providers-client1-client-secret":                "my-client-secret", | ||||
| 		"providers-my-awesome-client-client-id":          "my-awesome-client-id", | ||||
| 		"providers-my-awesome-client-client-secret-file": "/path/to/secret", | ||||
| 		"providers-should-not-appear-client":             "should-not-appear", | ||||
| 		"i-look-like-a-key-client-id":                    "should-not-appear", | ||||
| 		"providers-client-id":                            "should-not-appear", | ||||
| 	} | ||||
| 	expected = map[string]string{ | ||||
| 		"tinyauth.providers.client1.clientId":                 "my-client-id", | ||||
|   | ||||
| @@ -101,8 +101,7 @@ func CheckFilter(filter string, str string) bool { | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func GenerateIdentifier(str string) string { | ||||
| func GenerateUUID(str string) string { | ||||
| 	uuid := uuid.NewSHA1(uuid.NameSpaceURL, []byte(str)) | ||||
| 	uuidString := uuid.String() | ||||
| 	return strings.Split(uuidString, "-")[0] | ||||
| 	return uuid.String() | ||||
| } | ||||
|   | ||||
| @@ -136,16 +136,13 @@ func TestCheckFilter(t *testing.T) { | ||||
| 	assert.Equal(t, false, utils.CheckFilter("apple, banana, cherry", "grape")) | ||||
| } | ||||
|  | ||||
| func TestGenerateIdentifier(t *testing.T) { | ||||
| func TestGenerateUUID(t *testing.T) { | ||||
| 	// Consistent output for same input | ||||
| 	id1 := utils.GenerateIdentifier("teststring") | ||||
| 	id2 := utils.GenerateIdentifier("teststring") | ||||
| 	id1 := utils.GenerateUUID("teststring") | ||||
| 	id2 := utils.GenerateUUID("teststring") | ||||
| 	assert.Equal(t, id1, id2) | ||||
|  | ||||
| 	// Different output for different input | ||||
| 	id3 := utils.GenerateIdentifier("differentstring") | ||||
| 	id3 := utils.GenerateUUID("differentstring") | ||||
| 	assert.Assert(t, id1 != id3) | ||||
|  | ||||
| 	// Check length (should be 8 characters from first segment of UUID) | ||||
| 	assert.Equal(t, 8, len(id1)) | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user