mirror of
				https://github.com/steveiliop56/tinyauth.git
				synced 2025-10-31 06:05:43 +00:00 
			
		
		
		
	Compare commits
	
		
			3 Commits
		
	
	
		
			ddc5596f13
			...
			e996a7015e
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| ![dependabot[bot]](/assets/img/avatar_default.png)  | e996a7015e | ||
|   | 2d78e6b598 | ||
|   | e03eaf4f08 | 
| @@ -10,7 +10,7 @@ | ||||
|         "@radix-ui/react-separator": "^1.1.7", | ||||
|         "@radix-ui/react-slot": "^1.2.3", | ||||
|         "@tailwindcss/vite": "^4.1.13", | ||||
|         "@tanstack/react-query": "^5.87.1", | ||||
|         "@tanstack/react-query": "^5.87.4", | ||||
|         "axios": "^1.11.0", | ||||
|         "class-variance-authority": "^0.7.1", | ||||
|         "clsx": "^2.1.1", | ||||
| @@ -29,7 +29,7 @@ | ||||
|         "sonner": "^2.0.7", | ||||
|         "tailwind-merge": "^3.3.1", | ||||
|         "tailwindcss": "^4.1.13", | ||||
|         "zod": "^4.1.5", | ||||
|         "zod": "^4.1.7", | ||||
|       }, | ||||
|       "devDependencies": { | ||||
|         "@eslint/js": "^9.35.0", | ||||
| @@ -331,9 +331,9 @@ | ||||
|  | ||||
|     "@tanstack/eslint-plugin-query": ["@tanstack/eslint-plugin-query@5.86.0", "", { "dependencies": { "@typescript-eslint/utils": "^8.37.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0" } }, "sha512-tmXdnx/fF3yY5G5jpzrJQbASY3PNzsKF0gq9IsZVqz3LJ4sExgdUFGQ305nao0wTMBOclyrSC13v/VQ3yOXu/Q=="], | ||||
|  | ||||
|     "@tanstack/query-core": ["@tanstack/query-core@5.87.1", "", {}, "sha512-HOFHVvhOCprrWvtccSzc7+RNqpnLlZ5R6lTmngb8aq7b4rc2/jDT0w+vLdQ4lD9bNtQ+/A4GsFXy030Gk4ollA=="], | ||||
|     "@tanstack/query-core": ["@tanstack/query-core@5.87.4", "", {}, "sha512-uNsg6zMxraEPDVO2Bn+F3/ctHi+Zsk+MMpcN8h6P7ozqD088F6mFY5TfGM7zuyIrL7HKpDyu6QHfLWiDxh3cuw=="], | ||||
|  | ||||
|     "@tanstack/react-query": ["@tanstack/react-query@5.87.1", "", { "dependencies": { "@tanstack/query-core": "5.87.1" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-YKauf8jfMowgAqcxj96AHs+Ux3m3bWT1oSVKamaRPXSnW2HqSznnTCEkAVqctF1e/W9R/mPcyzzINIgpOH94qg=="], | ||||
|     "@tanstack/react-query": ["@tanstack/react-query@5.87.4", "", { "dependencies": { "@tanstack/query-core": "5.87.4" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-T5GT/1ZaNsUXf5I3RhcYuT17I4CPlbZgyLxc/ZGv7ciS6esytlbjb3DgUFO6c8JWYMDpdjSWInyGZUErgzqhcA=="], | ||||
|  | ||||
|     "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], | ||||
|  | ||||
| @@ -911,7 +911,7 @@ | ||||
|  | ||||
|     "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], | ||||
|  | ||||
|     "zod": ["zod@4.1.5", "", {}, "sha512-rcUUZqlLJgBC33IT3PNMgsCq6TzLQEG/Ei/KTCU0PedSWRMAXoOUN+4t/0H+Q8bdnLPdqUYnvboJT0bn/229qg=="], | ||||
|     "zod": ["zod@4.1.7", "", {}, "sha512-6qi6UYyzAl7W9uV29KvcSFXqK4QCYNYUz2YASPNBWpJE1RY6R1nArmmFPgGY/CBYWzpeMw3EOER+DR9a05O4IA=="], | ||||
|  | ||||
|     "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="], | ||||
|  | ||||
|   | ||||
| @@ -16,7 +16,7 @@ | ||||
|     "@radix-ui/react-separator": "^1.1.7", | ||||
|     "@radix-ui/react-slot": "^1.2.3", | ||||
|     "@tailwindcss/vite": "^4.1.13", | ||||
|     "@tanstack/react-query": "^5.87.1", | ||||
|     "@tanstack/react-query": "^5.87.4", | ||||
|     "axios": "^1.11.0", | ||||
|     "class-variance-authority": "^0.7.1", | ||||
|     "clsx": "^2.1.1", | ||||
| @@ -35,7 +35,7 @@ | ||||
|     "sonner": "^2.0.7", | ||||
|     "tailwind-merge": "^3.3.1", | ||||
|     "tailwindcss": "^4.1.13", | ||||
|     "zod": "^4.1.5" | ||||
|     "zod": "^4.1.7" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@eslint/js": "^9.35.0", | ||||
|   | ||||
| @@ -21,7 +21,7 @@ | ||||
|     "continueInsecureRedirectTitle": "Insecure redirect", | ||||
|     "continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?", | ||||
|     "continueUntrustedRedirectTitle": "Untrusted redirect", | ||||
|     "continueUntrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{rootDomain}}</code>). Are you sure you want to continue?", | ||||
|     "continueUntrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{cookieDomain}}</code>). Are you sure you want to continue?", | ||||
|     "logoutFailTitle": "Failed to log out", | ||||
|     "logoutFailSubtitle": "Please try again", | ||||
|     "logoutSuccessTitle": "Logged out", | ||||
|   | ||||
| @@ -21,7 +21,7 @@ | ||||
|     "continueInsecureRedirectTitle": "Insecure redirect", | ||||
|     "continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?", | ||||
|     "continueUntrustedRedirectTitle": "Untrusted redirect", | ||||
|     "continueUntrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{rootDomain}}</code>). Are you sure you want to continue?", | ||||
|     "continueUntrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{cookieDomain}}</code>). Are you sure you want to continue?", | ||||
|     "logoutFailTitle": "Failed to log out", | ||||
|     "logoutFailSubtitle": "Please try again", | ||||
|     "logoutSuccessTitle": "Logged out", | ||||
|   | ||||
| @@ -14,7 +14,7 @@ import { Navigate, useLocation, useNavigate } from "react-router"; | ||||
| import { useEffect, useState } from "react"; | ||||
|  | ||||
| export const ContinuePage = () => { | ||||
|   const { rootDomain } = useAppContext(); | ||||
|   const { cookieDomain } = useAppContext(); | ||||
|   const { isLoggedIn } = useUserContext(); | ||||
|   const { search } = useLocation(); | ||||
|   const { t } = useTranslation(); | ||||
| @@ -33,8 +33,8 @@ export const ContinuePage = () => { | ||||
|     : null; | ||||
|   const isTrustedRedirectUri = | ||||
|     redirectUriObj !== null | ||||
|       ? redirectUriObj.hostname === rootDomain || | ||||
|         redirectUriObj.hostname.endsWith(`.${rootDomain}`) | ||||
|       ? redirectUriObj.hostname === cookieDomain || | ||||
|         redirectUriObj.hostname.endsWith(`.${cookieDomain}`) | ||||
|       : false; | ||||
|   const isAllowedRedirectProto = | ||||
|     redirectUriObj !== null | ||||
| @@ -105,7 +105,7 @@ export const ContinuePage = () => { | ||||
|               components={{ | ||||
|                 code: <code />, | ||||
|               }} | ||||
|               values={{ rootDomain }} | ||||
|               values={{ cookieDomain }} | ||||
|             /> | ||||
|           </CardDescription> | ||||
|         </CardHeader> | ||||
|   | ||||
| @@ -5,7 +5,7 @@ export const appContextSchema = z.object({ | ||||
|   title: z.string(), | ||||
|   genericName: z.string(), | ||||
|   appUrl: z.string(), | ||||
|   rootDomain: z.string(), | ||||
|   cookieDomain: z.string(), | ||||
|   forgotPasswordMessage: z.string(), | ||||
|   oauthAutoRedirect: z.enum(["none", "github", "google", "generic"]), | ||||
|   backgroundImage: z.string(), | ||||
|   | ||||
							
								
								
									
										17
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								go.mod
									
									
									
									
									
								
							| @@ -1,6 +1,8 @@ | ||||
| module tinyauth | ||||
|  | ||||
| go 1.23.2 | ||||
| go 1.24.0 | ||||
|  | ||||
| toolchain go1.24.3 | ||||
|  | ||||
| require ( | ||||
| 	github.com/cenkalti/backoff/v5 v5.0.3 | ||||
| @@ -15,7 +17,8 @@ require ( | ||||
| 	github.com/spf13/cobra v1.9.1 | ||||
| 	github.com/spf13/viper v1.20.1 | ||||
| 	github.com/traefik/paerser v0.2.2 | ||||
| 	golang.org/x/crypto v0.41.0 | ||||
| 	github.com/weppos/publicsuffix-go v0.50.0 | ||||
| 	golang.org/x/crypto v0.42.0 | ||||
| 	golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b | ||||
| 	gorm.io/gorm v1.30.1 | ||||
| 	gotest.tools/v3 v3.5.2 | ||||
| @@ -45,7 +48,7 @@ require ( | ||||
| 	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 | ||||
| 	golang.org/x/term v0.34.0 // indirect | ||||
| 	golang.org/x/term v0.35.0 // indirect | ||||
| 	modernc.org/libc v1.66.3 // indirect | ||||
| 	modernc.org/mathutil v1.7.1 // indirect | ||||
| 	modernc.org/memory v1.11.0 // indirect | ||||
| @@ -123,11 +126,11 @@ require ( | ||||
| 	go.uber.org/atomic v1.9.0 // indirect | ||||
| 	go.uber.org/multierr v1.9.0 // indirect | ||||
| 	golang.org/x/arch v0.13.0 // indirect | ||||
| 	golang.org/x/net v0.42.0 // indirect | ||||
| 	golang.org/x/net v0.44.0 // indirect | ||||
| 	golang.org/x/oauth2 v0.30.0 | ||||
| 	golang.org/x/sync v0.16.0 // indirect | ||||
| 	golang.org/x/sys v0.35.0 // indirect | ||||
| 	golang.org/x/text v0.28.0 // indirect | ||||
| 	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 | ||||
| ) | ||||
|   | ||||
							
								
								
									
										34
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								go.sum
									
									
									
									
									
								
							| @@ -280,6 +280,8 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS | ||||
| 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/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= | ||||
| github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= | ||||
| github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | ||||
| @@ -311,27 +313,27 @@ golang.org/x/arch v0.13.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= | ||||
| golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||||
| golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | ||||
| golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | ||||
| golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= | ||||
| golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= | ||||
| 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= | ||||
| golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= | ||||
| golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= | ||||
| golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= | ||||
| golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= | ||||
| golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= | ||||
| golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ= | ||||
| golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc= | ||||
| golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||||
| golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||||
| golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||||
| golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= | ||||
| golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= | ||||
| golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= | ||||
| golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I= | ||||
| golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= | ||||
| golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= | ||||
| golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= | ||||
| golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= | ||||
| golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= | ||||
| golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= | ||||
| golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= | ||||
| golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| @@ -339,22 +341,22 @@ golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBc | ||||
| golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= | ||||
| golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= | ||||
| golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= | ||||
| golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= | ||||
| golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= | ||||
| golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= | ||||
| golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= | ||||
| golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= | ||||
| golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||||
| golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||||
| golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= | ||||
| golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= | ||||
| golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= | ||||
| golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= | ||||
| golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= | ||||
| golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= | ||||
| golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||||
| golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | ||||
| golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= | ||||
| golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= | ||||
| golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= | ||||
| golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= | ||||
| golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg= | ||||
| golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s= | ||||
| golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||
| golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||
| golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||
|   | ||||
| @@ -45,8 +45,8 @@ func (app *BootstrapApp) Setup() error { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	// Get root domain | ||||
| 	rootDomain, err := utils.GetRootDomain(app.Config.AppURL) | ||||
| 	// Get cookie domain | ||||
| 	cookieDomain, err := utils.GetCookieDomain(app.Config.AppURL) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| @@ -65,7 +65,7 @@ func (app *BootstrapApp) Setup() error { | ||||
| 		OauthWhitelist:    app.Config.OAuthWhitelist, | ||||
| 		SessionExpiry:     app.Config.SessionExpiry, | ||||
| 		SecureCookie:      app.Config.SecureCookie, | ||||
| 		RootDomain:        rootDomain, | ||||
| 		CookieDomain:      cookieDomain, | ||||
| 		LoginTimeout:      app.Config.LoginTimeout, | ||||
| 		LoginMaxRetries:   app.Config.LoginMaxRetries, | ||||
| 		SessionCookieName: sessionCookieName, | ||||
| @@ -156,7 +156,7 @@ func (app *BootstrapApp) Setup() error { | ||||
| 	var middlewares []Middleware | ||||
|  | ||||
| 	contextMiddleware := middleware.NewContextMiddleware(middleware.ContextMiddlewareConfig{ | ||||
| 		RootDomain: rootDomain, | ||||
| 		CookieDomain: cookieDomain, | ||||
| 	}, authService, oauthBrokerService) | ||||
|  | ||||
| 	uiMiddleware := middleware.NewUIMiddleware() | ||||
| @@ -183,7 +183,7 @@ func (app *BootstrapApp) Setup() error { | ||||
| 		Title:                 app.Config.Title, | ||||
| 		GenericName:           app.Config.GenericName, | ||||
| 		AppURL:                app.Config.AppURL, | ||||
| 		RootDomain:            rootDomain, | ||||
| 		CookieDomain:          cookieDomain, | ||||
| 		ForgotPasswordMessage: app.Config.ForgotPasswordMessage, | ||||
| 		BackgroundImage:       app.Config.BackgroundImage, | ||||
| 		OAuthAutoRedirect:     app.Config.OAuthAutoRedirect, | ||||
| @@ -194,7 +194,7 @@ func (app *BootstrapApp) Setup() error { | ||||
| 		SecureCookie:       app.Config.SecureCookie, | ||||
| 		CSRFCookieName:     csrfCookieName, | ||||
| 		RedirectCookieName: redirectCookieName, | ||||
| 		RootDomain:         rootDomain, | ||||
| 		CookieDomain:       cookieDomain, | ||||
| 	}, apiRouter, authService, oauthBrokerService) | ||||
|  | ||||
| 	proxyController := controller.NewProxyController(controller.ProxyControllerConfig{ | ||||
| @@ -202,7 +202,7 @@ func (app *BootstrapApp) Setup() error { | ||||
| 	}, apiRouter, dockerService, authService) | ||||
|  | ||||
| 	userController := controller.NewUserController(controller.UserControllerConfig{ | ||||
| 		RootDomain: rootDomain, | ||||
| 		CookieDomain: cookieDomain, | ||||
| 	}, apiRouter, authService) | ||||
|  | ||||
| 	resourcesController := controller.NewResourcesController(controller.ResourcesControllerConfig{ | ||||
|   | ||||
| @@ -28,7 +28,7 @@ type AppContextResponse struct { | ||||
| 	Title                 string   `json:"title"` | ||||
| 	GenericName           string   `json:"genericName"` | ||||
| 	AppURL                string   `json:"appUrl"` | ||||
| 	RootDomain            string   `json:"rootDomain"` | ||||
| 	CookieDomain          string   `json:"cookieDomain"` | ||||
| 	ForgotPasswordMessage string   `json:"forgotPasswordMessage"` | ||||
| 	BackgroundImage       string   `json:"backgroundImage"` | ||||
| 	OAuthAutoRedirect     string   `json:"oauthAutoRedirect"` | ||||
| @@ -39,7 +39,7 @@ type ContextControllerConfig struct { | ||||
| 	Title                 string | ||||
| 	GenericName           string | ||||
| 	AppURL                string | ||||
| 	RootDomain            string | ||||
| 	CookieDomain          string | ||||
| 	ForgotPasswordMessage string | ||||
| 	BackgroundImage       string | ||||
| 	OAuthAutoRedirect     string | ||||
| @@ -100,7 +100,7 @@ func (controller *ContextController) appContextHandler(c *gin.Context) { | ||||
| 		Title:                 controller.config.Title, | ||||
| 		GenericName:           controller.config.GenericName, | ||||
| 		AppURL:                fmt.Sprintf("%s://%s", appUrl.Scheme, appUrl.Host), | ||||
| 		RootDomain:            controller.config.RootDomain, | ||||
| 		CookieDomain:          controller.config.CookieDomain, | ||||
| 		ForgotPasswordMessage: controller.config.ForgotPasswordMessage, | ||||
| 		BackgroundImage:       controller.config.BackgroundImage, | ||||
| 		OAuthAutoRedirect:     controller.config.OAuthAutoRedirect, | ||||
|   | ||||
| @@ -16,7 +16,7 @@ var controllerCfg = controller.ContextControllerConfig{ | ||||
| 	Title:                 "Test App", | ||||
| 	GenericName:           "Generic", | ||||
| 	AppURL:                "http://localhost:8080", | ||||
| 	RootDomain:            "localhost", | ||||
| 	CookieDomain:          "localhost", | ||||
| 	ForgotPasswordMessage: "Contact admin to reset your password.", | ||||
| 	BackgroundImage:       "/assets/bg.jpg", | ||||
| 	OAuthAutoRedirect:     "google", | ||||
| @@ -62,7 +62,7 @@ func TestAppContextHandler(t *testing.T) { | ||||
| 		Title:                 controllerCfg.Title, | ||||
| 		GenericName:           controllerCfg.GenericName, | ||||
| 		AppURL:                controllerCfg.AppURL, | ||||
| 		RootDomain:            controllerCfg.RootDomain, | ||||
| 		CookieDomain:          controllerCfg.CookieDomain, | ||||
| 		ForgotPasswordMessage: controllerCfg.ForgotPasswordMessage, | ||||
| 		BackgroundImage:       controllerCfg.BackgroundImage, | ||||
| 		OAuthAutoRedirect:     controllerCfg.OAuthAutoRedirect, | ||||
|   | ||||
| @@ -23,7 +23,7 @@ type OAuthControllerConfig struct { | ||||
| 	RedirectCookieName string | ||||
| 	SecureCookie       bool | ||||
| 	AppURL             string | ||||
| 	RootDomain         string | ||||
| 	CookieDomain       string | ||||
| } | ||||
|  | ||||
| type OAuthController struct { | ||||
| @@ -74,13 +74,13 @@ func (controller *OAuthController) oauthURLHandler(c *gin.Context) { | ||||
|  | ||||
| 	state := service.GenerateState() | ||||
| 	authURL := service.GetAuthURL(state) | ||||
| 	c.SetCookie(controller.config.CSRFCookieName, state, int(time.Hour.Seconds()), "/", fmt.Sprintf(".%s", controller.config.RootDomain), controller.config.SecureCookie, true) | ||||
| 	c.SetCookie(controller.config.CSRFCookieName, state, int(time.Hour.Seconds()), "/", fmt.Sprintf(".%s", controller.config.CookieDomain), controller.config.SecureCookie, true) | ||||
|  | ||||
| 	redirectURI := c.Query("redirect_uri") | ||||
|  | ||||
| 	if redirectURI != "" && utils.IsRedirectSafe(redirectURI, controller.config.RootDomain) { | ||||
| 	if redirectURI != "" && utils.IsRedirectSafe(redirectURI, controller.config.CookieDomain) { | ||||
| 		log.Debug().Msg("Setting redirect URI cookie") | ||||
| 		c.SetCookie(controller.config.RedirectCookieName, redirectURI, int(time.Hour.Seconds()), "/", fmt.Sprintf(".%s", controller.config.RootDomain), controller.config.SecureCookie, true) | ||||
| 		c.SetCookie(controller.config.RedirectCookieName, redirectURI, int(time.Hour.Seconds()), "/", fmt.Sprintf(".%s", controller.config.CookieDomain), controller.config.SecureCookie, true) | ||||
| 	} | ||||
|  | ||||
| 	c.JSON(200, gin.H{ | ||||
| @@ -108,12 +108,12 @@ func (controller *OAuthController) oauthCallbackHandler(c *gin.Context) { | ||||
|  | ||||
| 	if err != nil || state != csrfCookie { | ||||
| 		log.Warn().Err(err).Msg("CSRF token mismatch or cookie missing") | ||||
| 		c.SetCookie(controller.config.CSRFCookieName, "", -1, "/", fmt.Sprintf(".%s", controller.config.RootDomain), controller.config.SecureCookie, true) | ||||
| 		c.SetCookie(controller.config.CSRFCookieName, "", -1, "/", fmt.Sprintf(".%s", controller.config.CookieDomain), controller.config.SecureCookie, true) | ||||
| 		c.Redirect(http.StatusTemporaryRedirect, fmt.Sprintf("%s/error", controller.config.AppURL)) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	c.SetCookie(controller.config.CSRFCookieName, "", -1, "/", fmt.Sprintf(".%s", controller.config.RootDomain), controller.config.SecureCookie, true) | ||||
| 	c.SetCookie(controller.config.CSRFCookieName, "", -1, "/", fmt.Sprintf(".%s", controller.config.CookieDomain), controller.config.SecureCookie, true) | ||||
|  | ||||
| 	code := c.Query("code") | ||||
| 	service, exists := controller.broker.GetService(req.Provider) | ||||
| @@ -196,7 +196,7 @@ func (controller *OAuthController) oauthCallbackHandler(c *gin.Context) { | ||||
|  | ||||
| 	redirectURI, err := c.Cookie(controller.config.RedirectCookieName) | ||||
|  | ||||
| 	if err != nil || !utils.IsRedirectSafe(redirectURI, controller.config.RootDomain) { | ||||
| 	if err != nil || !utils.IsRedirectSafe(redirectURI, controller.config.CookieDomain) { | ||||
| 		log.Debug().Msg("No redirect URI cookie found, redirecting to app root") | ||||
| 		c.Redirect(http.StatusTemporaryRedirect, controller.config.AppURL) | ||||
| 		return | ||||
| @@ -212,6 +212,6 @@ func (controller *OAuthController) oauthCallbackHandler(c *gin.Context) { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	c.SetCookie(controller.config.RedirectCookieName, "", -1, "/", fmt.Sprintf(".%s", controller.config.RootDomain), controller.config.SecureCookie, true) | ||||
| 	c.SetCookie(controller.config.RedirectCookieName, "", -1, "/", fmt.Sprintf(".%s", controller.config.CookieDomain), controller.config.SecureCookie, true) | ||||
| 	c.Redirect(http.StatusTemporaryRedirect, fmt.Sprintf("%s/continue?%s", controller.config.AppURL, queries.Encode())) | ||||
| } | ||||
|   | ||||
| @@ -50,7 +50,7 @@ func setupProxyController(t *testing.T, middlewares *[]gin.HandlerFunc) (*gin.En | ||||
| 		OauthWhitelist:    "", | ||||
| 		SessionExpiry:     3600, | ||||
| 		SecureCookie:      false, | ||||
| 		RootDomain:        "localhost", | ||||
| 		CookieDomain:      "localhost", | ||||
| 		LoginTimeout:      300, | ||||
| 		LoginMaxRetries:   3, | ||||
| 		SessionCookieName: "tinyauth-session", | ||||
|   | ||||
| @@ -24,6 +24,7 @@ func TestResourcesHandler(t *testing.T) { | ||||
| 	// Create test data | ||||
| 	err := os.Mkdir("/tmp/tinyauth", 0755) | ||||
| 	assert.NilError(t, err) | ||||
| 	defer os.RemoveAll("/tmp/tinyauth") | ||||
|  | ||||
| 	file, err := os.Create("/tmp/tinyauth/test.txt") | ||||
| 	assert.NilError(t, err) | ||||
|   | ||||
| @@ -22,7 +22,7 @@ type TotpRequest struct { | ||||
| } | ||||
|  | ||||
| type UserControllerConfig struct { | ||||
| 	RootDomain string | ||||
| 	CookieDomain string | ||||
| } | ||||
|  | ||||
| type UserController struct { | ||||
| @@ -115,7 +115,7 @@ func (controller *UserController) loginHandler(c *gin.Context) { | ||||
| 			err := controller.auth.CreateSessionCookie(c, &config.SessionCookie{ | ||||
| 				Username:    user.Username, | ||||
| 				Name:        utils.Capitalize(req.Username), | ||||
| 				Email:       fmt.Sprintf("%s@%s", strings.ToLower(req.Username), controller.config.RootDomain), | ||||
| 				Email:       fmt.Sprintf("%s@%s", strings.ToLower(req.Username), controller.config.CookieDomain), | ||||
| 				Provider:    "username", | ||||
| 				TotpPending: true, | ||||
| 			}) | ||||
| @@ -141,7 +141,7 @@ func (controller *UserController) loginHandler(c *gin.Context) { | ||||
| 	err = controller.auth.CreateSessionCookie(c, &config.SessionCookie{ | ||||
| 		Username: req.Username, | ||||
| 		Name:     utils.Capitalize(req.Username), | ||||
| 		Email:    fmt.Sprintf("%s@%s", strings.ToLower(req.Username), controller.config.RootDomain), | ||||
| 		Email:    fmt.Sprintf("%s@%s", strings.ToLower(req.Username), controller.config.CookieDomain), | ||||
| 		Provider: "username", | ||||
| 	}) | ||||
|  | ||||
| @@ -246,7 +246,7 @@ func (controller *UserController) totpHandler(c *gin.Context) { | ||||
| 	err = controller.auth.CreateSessionCookie(c, &config.SessionCookie{ | ||||
| 		Username: user.Username, | ||||
| 		Name:     utils.Capitalize(user.Username), | ||||
| 		Email:    fmt.Sprintf("%s@%s", strings.ToLower(user.Username), controller.config.RootDomain), | ||||
| 		Email:    fmt.Sprintf("%s@%s", strings.ToLower(user.Username), controller.config.CookieDomain), | ||||
| 		Provider: "username", | ||||
| 	}) | ||||
|  | ||||
|   | ||||
| @@ -58,7 +58,7 @@ func setupUserController(t *testing.T, middlewares *[]gin.HandlerFunc) (*gin.Eng | ||||
| 		OauthWhitelist:    "", | ||||
| 		SessionExpiry:     3600, | ||||
| 		SecureCookie:      false, | ||||
| 		RootDomain:        "localhost", | ||||
| 		CookieDomain:      "localhost", | ||||
| 		LoginTimeout:      300, | ||||
| 		LoginMaxRetries:   3, | ||||
| 		SessionCookieName: "tinyauth-session", | ||||
| @@ -66,7 +66,7 @@ func setupUserController(t *testing.T, middlewares *[]gin.HandlerFunc) (*gin.Eng | ||||
|  | ||||
| 	// Controller | ||||
| 	ctrl := controller.NewUserController(controller.UserControllerConfig{ | ||||
| 		RootDomain: "localhost", | ||||
| 		CookieDomain: "localhost", | ||||
| 	}, group, authService) | ||||
| 	ctrl.SetupRoutes() | ||||
|  | ||||
|   | ||||
| @@ -12,7 +12,7 @@ import ( | ||||
| ) | ||||
|  | ||||
| type ContextMiddlewareConfig struct { | ||||
| 	RootDomain string | ||||
| 	CookieDomain string | ||||
| } | ||||
|  | ||||
| type ContextMiddleware struct { | ||||
| @@ -134,7 +134,7 @@ func (m *ContextMiddleware) Middleware() gin.HandlerFunc { | ||||
| 			c.Set("context", &config.UserContext{ | ||||
| 				Username:    user.Username, | ||||
| 				Name:        utils.Capitalize(user.Username), | ||||
| 				Email:       fmt.Sprintf("%s@%s", strings.ToLower(user.Username), m.config.RootDomain), | ||||
| 				Email:       fmt.Sprintf("%s@%s", strings.ToLower(user.Username), m.config.CookieDomain), | ||||
| 				Provider:    "basic", | ||||
| 				IsLoggedIn:  true, | ||||
| 				TotpEnabled: user.TotpSecret != "", | ||||
| @@ -146,7 +146,7 @@ func (m *ContextMiddleware) Middleware() gin.HandlerFunc { | ||||
| 			c.Set("context", &config.UserContext{ | ||||
| 				Username:   basic.Username, | ||||
| 				Name:       utils.Capitalize(basic.Username), | ||||
| 				Email:      fmt.Sprintf("%s@%s", strings.ToLower(basic.Username), m.config.RootDomain), | ||||
| 				Email:      fmt.Sprintf("%s@%s", strings.ToLower(basic.Username), m.config.CookieDomain), | ||||
| 				Provider:   "basic", | ||||
| 				IsLoggedIn: true, | ||||
| 			}) | ||||
|   | ||||
| @@ -28,7 +28,7 @@ type AuthServiceConfig struct { | ||||
| 	OauthWhitelist    string | ||||
| 	SessionExpiry     int | ||||
| 	SecureCookie      bool | ||||
| 	RootDomain        string | ||||
| 	CookieDomain      string | ||||
| 	LoginTimeout      int | ||||
| 	LoginMaxRetries   int | ||||
| 	SessionCookieName string | ||||
| @@ -218,7 +218,7 @@ func (auth *AuthService) CreateSessionCookie(c *gin.Context, data *config.Sessio | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	c.SetCookie(auth.config.SessionCookieName, session.UUID, expiry, "/", fmt.Sprintf(".%s", auth.config.RootDomain), auth.config.SecureCookie, true) | ||||
| 	c.SetCookie(auth.config.SessionCookieName, session.UUID, expiry, "/", fmt.Sprintf(".%s", auth.config.CookieDomain), auth.config.SecureCookie, true) | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
| @@ -236,7 +236,7 @@ func (auth *AuthService) DeleteSessionCookie(c *gin.Context) error { | ||||
| 		return res.Error | ||||
| 	} | ||||
|  | ||||
| 	c.SetCookie(auth.config.SessionCookieName, "", -1, "/", fmt.Sprintf(".%s", auth.config.RootDomain), auth.config.SecureCookie, true) | ||||
| 	c.SetCookie(auth.config.SessionCookieName, "", -1, "/", fmt.Sprintf(".%s", auth.config.CookieDomain), auth.config.SecureCookie, true) | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|   | ||||
| @@ -8,30 +8,38 @@ import ( | ||||
| 	"tinyauth/internal/config" | ||||
|  | ||||
| 	"github.com/gin-gonic/gin" | ||||
|  | ||||
| 	"github.com/rs/zerolog" | ||||
| 	"github.com/weppos/publicsuffix-go/publicsuffix" | ||||
| ) | ||||
|  | ||||
| // Get root domain parses a hostname and returns the upper domain (e.g. sub1.sub2.domain.com -> sub2.domain.com) | ||||
| func GetRootDomain(u string) (string, error) { | ||||
| 	appUrl, err := url.Parse(u) | ||||
| // Get cookie domain parses a hostname and returns the upper domain (e.g. sub1.sub2.domain.com -> sub2.domain.com) | ||||
| func GetCookieDomain(u string) (string, error) { | ||||
| 	parsed, err := url.Parse(u) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	host := appUrl.Hostname() | ||||
| 	host := parsed.Hostname() | ||||
|  | ||||
| 	if netIP := net.ParseIP(host); netIP != nil { | ||||
| 		return "", errors.New("IP addresses are not allowed") | ||||
| 		return "", errors.New("IP addresses not allowed") | ||||
| 	} | ||||
|  | ||||
| 	urlParts := strings.Split(host, ".") | ||||
| 	parts := strings.Split(host, ".") | ||||
|  | ||||
| 	if len(urlParts) < 3 { | ||||
| 		return "", errors.New("invalid domain, must be at least second level domain") | ||||
| 	if len(parts) < 3 { | ||||
| 		return "", errors.New("invalid app url, must be at least second level domain") | ||||
| 	} | ||||
|  | ||||
| 	return strings.Join(urlParts[1:], "."), nil | ||||
| 	domain := strings.Join(parts[1:], ".") | ||||
|  | ||||
| 	_, err = publicsuffix.DomainFromListWithOptions(publicsuffix.DefaultList, domain, nil) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return "", errors.New("domain in public suffix list, cannot set cookies") | ||||
| 	} | ||||
|  | ||||
| 	return domain, nil | ||||
| } | ||||
|  | ||||
| func ParseFileToLine(content string) string { | ||||
| @@ -89,13 +97,13 @@ func IsRedirectSafe(redirectURL string, domain string) bool { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	upper, err := GetRootDomain(redirectURL) | ||||
| 	cookieDomain, err := GetCookieDomain(redirectURL) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	if upper != domain { | ||||
| 	if cookieDomain != domain { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -11,53 +11,58 @@ import ( | ||||
|  | ||||
| func TestGetRootDomain(t *testing.T) { | ||||
| 	// Normal case | ||||
| 	domain := "http://sub.example.com" | ||||
| 	expected := "example.com" | ||||
| 	result, err := utils.GetRootDomain(domain) | ||||
| 	domain := "http://sub.tinyauth.app" | ||||
| 	expected := "tinyauth.app" | ||||
| 	result, err := utils.GetCookieDomain(domain) | ||||
| 	assert.NilError(t, err) | ||||
| 	assert.Equal(t, expected, result) | ||||
|  | ||||
| 	// Domain with multiple subdomains | ||||
| 	domain = "http://b.c.example.com" | ||||
| 	expected = "c.example.com" | ||||
| 	result, err = utils.GetRootDomain(domain) | ||||
| 	domain = "http://b.c.tinyauth.app" | ||||
| 	expected = "c.tinyauth.app" | ||||
| 	result, err = utils.GetCookieDomain(domain) | ||||
| 	assert.NilError(t, err) | ||||
| 	assert.Equal(t, expected, result) | ||||
|  | ||||
| 	// Domain with no subdomain | ||||
| 	domain = "http://example.com" | ||||
| 	expected = "example.com" | ||||
| 	_, err = utils.GetRootDomain(domain) | ||||
| 	assert.Error(t, err, "invalid domain, must be at least second level domain") | ||||
| 	domain = "http://tinyauth.app" | ||||
| 	expected = "tinyauth.app" | ||||
| 	_, err = utils.GetCookieDomain(domain) | ||||
| 	assert.Error(t, err, "invalid app url, must be at least second level domain") | ||||
|  | ||||
| 	// Invalid domain (only TLD) | ||||
| 	domain = "com" | ||||
| 	_, err = utils.GetRootDomain(domain) | ||||
| 	assert.ErrorContains(t, err, "invalid domain") | ||||
| 	_, err = utils.GetCookieDomain(domain) | ||||
| 	assert.ErrorContains(t, err, "invalid app url, must be at least second level domain") | ||||
|  | ||||
| 	// IP address | ||||
| 	domain = "http://10.10.10.10" | ||||
| 	_, err = utils.GetRootDomain(domain) | ||||
| 	assert.ErrorContains(t, err, "IP addresses are not allowed") | ||||
| 	_, err = utils.GetCookieDomain(domain) | ||||
| 	assert.ErrorContains(t, err, "IP addresses not allowed") | ||||
|  | ||||
| 	// Invalid URL | ||||
| 	domain = "http://[::1]:namedport" | ||||
| 	_, err = utils.GetRootDomain(domain) | ||||
| 	_, err = utils.GetCookieDomain(domain) | ||||
| 	assert.ErrorContains(t, err, "parse \"http://[::1]:namedport\": invalid port \":namedport\" after host") | ||||
|  | ||||
| 	// URL with scheme and path | ||||
| 	domain = "https://sub.example.com/path" | ||||
| 	expected = "example.com" | ||||
| 	result, err = utils.GetRootDomain(domain) | ||||
| 	domain = "https://sub.tinyauth.app/path" | ||||
| 	expected = "tinyauth.app" | ||||
| 	result, err = utils.GetCookieDomain(domain) | ||||
| 	assert.NilError(t, err) | ||||
| 	assert.Equal(t, expected, result) | ||||
|  | ||||
| 	// URL with port | ||||
| 	domain = "http://sub.example.com:8080" | ||||
| 	expected = "example.com" | ||||
| 	result, err = utils.GetRootDomain(domain) | ||||
| 	domain = "http://sub.tinyauth.app:8080" | ||||
| 	expected = "tinyauth.app" | ||||
| 	result, err = utils.GetCookieDomain(domain) | ||||
| 	assert.NilError(t, err) | ||||
| 	assert.Equal(t, expected, result) | ||||
|  | ||||
| 	// Domain managed by ICANN | ||||
| 	domain = "http://example.co.uk" | ||||
| 	_, err = utils.GetCookieDomain(domain) | ||||
| 	assert.Error(t, err, "domain in public suffix list, cannot set cookies") | ||||
| } | ||||
|  | ||||
| func TestParseFileToLine(t *testing.T) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user