mirror of
				https://github.com/steveiliop56/tinyauth.git
				synced 2025-11-03 23:55:44 +00:00 
			
		
		
		
	Compare commits
	
		
			3 Commits
		
	
	
		
			a9c1bf8865
			...
			v4.0.1-bet
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					2ea921f3ca | ||
| 
						 | 
					473109b36a | ||
| 
						 | 
					f628d1f0b3 | 
@@ -1,5 +1,5 @@
 | 
				
			|||||||
# Site builder
 | 
					# Site builder
 | 
				
			||||||
FROM oven/bun:1.2.23-alpine AS frontend-builder
 | 
					FROM oven/bun:1.3.0-alpine AS frontend-builder
 | 
				
			||||||
 | 
					
 | 
				
			||||||
WORKDIR /frontend
 | 
					WORKDIR /frontend
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
# Site builder
 | 
					# Site builder
 | 
				
			||||||
FROM oven/bun:1.2.23-alpine AS frontend-builder
 | 
					FROM oven/bun:1.3.0-alpine AS frontend-builder
 | 
				
			||||||
 | 
					
 | 
				
			||||||
WORKDIR /frontend
 | 
					WORKDIR /frontend
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,7 @@
 | 
				
			|||||||
        "axios": "^1.12.2",
 | 
					        "axios": "^1.12.2",
 | 
				
			||||||
        "class-variance-authority": "^0.7.1",
 | 
					        "class-variance-authority": "^0.7.1",
 | 
				
			||||||
        "clsx": "^2.1.1",
 | 
					        "clsx": "^2.1.1",
 | 
				
			||||||
        "i18next": "^25.5.3",
 | 
					        "i18next": "^25.6.0",
 | 
				
			||||||
        "i18next-browser-languagedetector": "^8.2.0",
 | 
					        "i18next-browser-languagedetector": "^8.2.0",
 | 
				
			||||||
        "i18next-resources-to-backend": "^1.2.1",
 | 
					        "i18next-resources-to-backend": "^1.2.1",
 | 
				
			||||||
        "input-otp": "^1.4.2",
 | 
					        "input-otp": "^1.4.2",
 | 
				
			||||||
@@ -22,7 +22,7 @@
 | 
				
			|||||||
        "next-themes": "^0.4.6",
 | 
					        "next-themes": "^0.4.6",
 | 
				
			||||||
        "react": "^19.2.0",
 | 
					        "react": "^19.2.0",
 | 
				
			||||||
        "react-dom": "^19.2.0",
 | 
					        "react-dom": "^19.2.0",
 | 
				
			||||||
        "react-hook-form": "^7.64.0",
 | 
					        "react-hook-form": "^7.65.0",
 | 
				
			||||||
        "react-i18next": "^16.0.0",
 | 
					        "react-i18next": "^16.0.0",
 | 
				
			||||||
        "react-markdown": "^10.1.0",
 | 
					        "react-markdown": "^10.1.0",
 | 
				
			||||||
        "react-router": "^7.9.4",
 | 
					        "react-router": "^7.9.4",
 | 
				
			||||||
@@ -34,7 +34,7 @@
 | 
				
			|||||||
      "devDependencies": {
 | 
					      "devDependencies": {
 | 
				
			||||||
        "@eslint/js": "^9.37.0",
 | 
					        "@eslint/js": "^9.37.0",
 | 
				
			||||||
        "@tanstack/eslint-plugin-query": "^5.91.0",
 | 
					        "@tanstack/eslint-plugin-query": "^5.91.0",
 | 
				
			||||||
        "@types/node": "^24.7.1",
 | 
					        "@types/node": "^24.7.2",
 | 
				
			||||||
        "@types/react": "^19.2.2",
 | 
					        "@types/react": "^19.2.2",
 | 
				
			||||||
        "@types/react-dom": "^19.2.1",
 | 
					        "@types/react-dom": "^19.2.1",
 | 
				
			||||||
        "@vitejs/plugin-react": "^5.0.4",
 | 
					        "@vitejs/plugin-react": "^5.0.4",
 | 
				
			||||||
@@ -355,7 +355,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    "@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
 | 
					    "@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "@types/node": ["@types/node@24.7.1", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-CmyhGZanP88uuC5GpWU9q+fI61j2SkhO3UGMUdfYRE6Bcy0ccyzn1Rqj9YAB/ZY4kOXmNf0ocah5GtphmLMP6Q=="],
 | 
					    "@types/node": ["@types/node@24.7.2", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-/NbVmcGTP+lj5oa4yiYxxeBjRivKQ5Ns1eSZeB99ExsEQ6rX5XYU1Zy/gGxY/ilqtD4Etx9mKyrPxZRetiahhA=="],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="],
 | 
					    "@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -583,7 +583,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    "html-url-attributes": ["html-url-attributes@3.0.1", "", {}, "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ=="],
 | 
					    "html-url-attributes": ["html-url-attributes@3.0.1", "", {}, "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ=="],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "i18next": ["i18next@25.5.3", "", { "dependencies": { "@babel/runtime": "^7.27.6" }, "peerDependencies": { "typescript": "^5" }, "optionalPeers": ["typescript"] }, "sha512-joFqorDeQ6YpIXni944upwnuHBf5IoPMuqAchGVeQLdWC2JOjxgM9V8UGLhNIIH/Q8QleRxIi0BSRQehSrDLcg=="],
 | 
					    "i18next": ["i18next@25.6.0", "", { "dependencies": { "@babel/runtime": "^7.27.6" }, "peerDependencies": { "typescript": "^5" }, "optionalPeers": ["typescript"] }, "sha512-tTn8fLrwBYtnclpL5aPXK/tAYBLWVvoHM1zdfXoRNLcI+RvtMsoZRV98ePlaW3khHYKuNh/Q65W/+NVFUeIwVw=="],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "i18next-browser-languagedetector": ["i18next-browser-languagedetector@8.2.0", "", { "dependencies": { "@babel/runtime": "^7.23.2" } }, "sha512-P+3zEKLnOF0qmiesW383vsLdtQVyKtCNA9cjSoKCppTKPQVfKd2W8hbVo5ZhNJKDqeM7BOcvNoKJOjpHh4Js9g=="],
 | 
					    "i18next-browser-languagedetector": ["i18next-browser-languagedetector@8.2.0", "", { "dependencies": { "@babel/runtime": "^7.23.2" } }, "sha512-P+3zEKLnOF0qmiesW383vsLdtQVyKtCNA9cjSoKCppTKPQVfKd2W8hbVo5ZhNJKDqeM7BOcvNoKJOjpHh4Js9g=="],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -791,7 +791,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    "react-dom": ["react-dom@19.2.0", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.0" } }, "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ=="],
 | 
					    "react-dom": ["react-dom@19.2.0", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.0" } }, "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ=="],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "react-hook-form": ["react-hook-form@7.64.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17 || ^18 || ^19" } }, "sha512-fnN+vvTiMLnRqKNTVhDysdrUay0kUUAymQnFIznmgDvapjveUWOOPqMNzPg+A+0yf9DuE2h6xzBjN1s+Qx8wcg=="],
 | 
					    "react-hook-form": ["react-hook-form@7.65.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17 || ^18 || ^19" } }, "sha512-xtOzDz063WcXvGWaHgLNrNzlsdFgtUWcb32E6WFaGTd7kPZG3EeDusjdZfUsPwKCKVXy1ZlntifaHZ4l8pAsmw=="],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "react-i18next": ["react-i18next@16.0.0", "", { "dependencies": { "@babel/runtime": "^7.27.6", "html-parse-stringify": "^3.0.1" }, "peerDependencies": { "i18next": ">= 25.5.2", "react": ">= 16.8.0", "typescript": "^5" }, "optionalPeers": ["typescript"] }, "sha512-JQ+dFfLnFSKJQt7W01lJHWRC0SX7eDPobI+MSTJ3/gP39xH2g33AuTE7iddAfXYHamJdAeMGM0VFboPaD3G68Q=="],
 | 
					    "react-i18next": ["react-i18next@16.0.0", "", { "dependencies": { "@babel/runtime": "^7.27.6", "html-parse-stringify": "^3.0.1" }, "peerDependencies": { "i18next": ">= 25.5.2", "react": ">= 16.8.0", "typescript": "^5" }, "optionalPeers": ["typescript"] }, "sha512-JQ+dFfLnFSKJQt7W01lJHWRC0SX7eDPobI+MSTJ3/gP39xH2g33AuTE7iddAfXYHamJdAeMGM0VFboPaD3G68Q=="],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,7 +20,7 @@
 | 
				
			|||||||
    "axios": "^1.12.2",
 | 
					    "axios": "^1.12.2",
 | 
				
			||||||
    "class-variance-authority": "^0.7.1",
 | 
					    "class-variance-authority": "^0.7.1",
 | 
				
			||||||
    "clsx": "^2.1.1",
 | 
					    "clsx": "^2.1.1",
 | 
				
			||||||
    "i18next": "^25.5.3",
 | 
					    "i18next": "^25.6.0",
 | 
				
			||||||
    "i18next-browser-languagedetector": "^8.2.0",
 | 
					    "i18next-browser-languagedetector": "^8.2.0",
 | 
				
			||||||
    "i18next-resources-to-backend": "^1.2.1",
 | 
					    "i18next-resources-to-backend": "^1.2.1",
 | 
				
			||||||
    "input-otp": "^1.4.2",
 | 
					    "input-otp": "^1.4.2",
 | 
				
			||||||
@@ -28,7 +28,7 @@
 | 
				
			|||||||
    "next-themes": "^0.4.6",
 | 
					    "next-themes": "^0.4.6",
 | 
				
			||||||
    "react": "^19.2.0",
 | 
					    "react": "^19.2.0",
 | 
				
			||||||
    "react-dom": "^19.2.0",
 | 
					    "react-dom": "^19.2.0",
 | 
				
			||||||
    "react-hook-form": "^7.64.0",
 | 
					    "react-hook-form": "^7.65.0",
 | 
				
			||||||
    "react-i18next": "^16.0.0",
 | 
					    "react-i18next": "^16.0.0",
 | 
				
			||||||
    "react-markdown": "^10.1.0",
 | 
					    "react-markdown": "^10.1.0",
 | 
				
			||||||
    "react-router": "^7.9.4",
 | 
					    "react-router": "^7.9.4",
 | 
				
			||||||
@@ -40,7 +40,7 @@
 | 
				
			|||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
    "@eslint/js": "^9.37.0",
 | 
					    "@eslint/js": "^9.37.0",
 | 
				
			||||||
    "@tanstack/eslint-plugin-query": "^5.91.0",
 | 
					    "@tanstack/eslint-plugin-query": "^5.91.0",
 | 
				
			||||||
    "@types/node": "^24.7.1",
 | 
					    "@types/node": "^24.7.2",
 | 
				
			||||||
    "@types/react": "^19.2.2",
 | 
					    "@types/react": "^19.2.2",
 | 
				
			||||||
    "@types/react-dom": "^19.2.1",
 | 
					    "@types/react-dom": "^19.2.1",
 | 
				
			||||||
    "@vitejs/plugin-react": "^5.0.4",
 | 
					    "@vitejs/plugin-react": "^5.0.4",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -100,17 +100,17 @@ func IsRedirectSafe(redirectURL string, domain string) bool {
 | 
				
			|||||||
		return false
 | 
							return false
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cookieDomain, err := GetCookieDomain(redirectURL)
 | 
						host := parsedURL.Hostname()
 | 
				
			||||||
 | 
						if host == domain {
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cookieDomain, err := GetCookieDomain(redirectURL)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return false
 | 
							return false
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if cookieDomain != domain {
 | 
						return cookieDomain == domain
 | 
				
			||||||
		return false
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return true
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func GetLogLevel(level string) zerolog.Level {
 | 
					func GetLogLevel(level string) zerolog.Level {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -164,7 +164,7 @@ func TestIsRedirectSafe(t *testing.T) {
 | 
				
			|||||||
	// Case with no subdomain
 | 
						// Case with no subdomain
 | 
				
			||||||
	redirectURL := "http://example.com/welcome"
 | 
						redirectURL := "http://example.com/welcome"
 | 
				
			||||||
	result := utils.IsRedirectSafe(redirectURL, domain)
 | 
						result := utils.IsRedirectSafe(redirectURL, domain)
 | 
				
			||||||
	assert.Equal(t, false, result)
 | 
						assert.Equal(t, true, result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Case with different domain
 | 
						// Case with different domain
 | 
				
			||||||
	redirectURL = "http://malicious.com/phishing"
 | 
						redirectURL = "http://malicious.com/phishing"
 | 
				
			||||||
@@ -202,6 +202,41 @@ func TestIsRedirectSafe(t *testing.T) {
 | 
				
			|||||||
	assert.Equal(t, false, result)
 | 
						assert.Equal(t, false, result)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestIsRedirectSafeMultiLevel(t *testing.T) {
 | 
				
			||||||
 | 
						// Setup
 | 
				
			||||||
 | 
						cookieDomain := "tinyauth.example.com"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Case with 3rd level domain
 | 
				
			||||||
 | 
						redirectURL := "http://tinyauth.example.com/welcome"
 | 
				
			||||||
 | 
						result := utils.IsRedirectSafe(redirectURL, cookieDomain)
 | 
				
			||||||
 | 
						assert.Equal(t, true, result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Case with root domain
 | 
				
			||||||
 | 
						redirectURL = "http://example.com/unsafe"
 | 
				
			||||||
 | 
						result = utils.IsRedirectSafe(redirectURL, cookieDomain)
 | 
				
			||||||
 | 
						assert.Equal(t, false, result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Case with 4th level domain
 | 
				
			||||||
 | 
						redirectURL = "http://auth.tinyauth.example.com/post-login"
 | 
				
			||||||
 | 
						result = utils.IsRedirectSafe(redirectURL, cookieDomain)
 | 
				
			||||||
 | 
						assert.Equal(t, true, result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Case with 5th level domain (should be unsafe)
 | 
				
			||||||
 | 
						redirectURL = "http://x.auth.tinyauth.example.com/deep"
 | 
				
			||||||
 | 
						result = utils.IsRedirectSafe(redirectURL, cookieDomain)
 | 
				
			||||||
 | 
						assert.Equal(t, false, result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Case with different subdomain
 | 
				
			||||||
 | 
						redirectURL = "http://auth.tinyauth.example.net/attack"
 | 
				
			||||||
 | 
						result = utils.IsRedirectSafe(redirectURL, cookieDomain)
 | 
				
			||||||
 | 
						assert.Equal(t, false, result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Case with malformed URL
 | 
				
			||||||
 | 
						redirectURL = "http://[::1]:namedport"
 | 
				
			||||||
 | 
						result = utils.IsRedirectSafe(redirectURL, cookieDomain)
 | 
				
			||||||
 | 
						assert.Equal(t, false, result)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestGetOAuthProvidersConfig(t *testing.T) {
 | 
					func TestGetOAuthProvidersConfig(t *testing.T) {
 | 
				
			||||||
	env := []string{"PROVIDERS_CLIENT1_CLIENT_ID=client1-id", "PROVIDERS_CLIENT1_CLIENT_SECRET=client1-secret"}
 | 
						env := []string{"PROVIDERS_CLIENT1_CLIENT_ID=client1-id", "PROVIDERS_CLIENT1_CLIENT_SECRET=client1-secret"}
 | 
				
			||||||
	args := []string{"/tinyauth/tinyauth", "--providers-client2-client-id=client2-id", "--providers-client2-client-secret=client2-secret"}
 | 
						args := []string{"/tinyauth/tinyauth", "--providers-client2-client-id=client2-id", "--providers-client2-client-secret=client2-secret"}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user