mirror of
				https://github.com/steveiliop56/tinyauth.git
				synced 2025-10-31 06:05:43 +00:00 
			
		
		
		
	Compare commits
	
		
			21 Commits
		
	
	
		
			v3.2.0-bet
			...
			v3.2.1
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 61dfc91110 | ||
|   | 130e6facb7 | ||
|   | 525f4f3041 | ||
|   | 8a21345706 | ||
|   | 1169c633cc | ||
|   | 2242c9c1e6 | ||
|   | 939919df39 | ||
|   | a579cf37ce | ||
|   | 2647aa07b4 | ||
|   | f68c580e11 | ||
|   | 9b39a2b856 | ||
|   | 6d17ce699a | ||
|   | 20dbb35d44 | ||
|   | 36d9dd7354 | ||
|   | 5129f9bff8 | ||
|   | 496a56676d | ||
|   | 57e25524c7 | ||
|   | 614a9b468a | ||
|   | 94a5359080 | ||
|   | 38c5cd7b32 | ||
|   | c664be5cc5 | 
| @@ -12,9 +12,6 @@ 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 | ||||
| TAILSCALE_CLIENT_ID=tailscale_client_id | ||||
| TAILSCALE_CLIENT_SECRET=tailscale_client_secret | ||||
| TAILSCALE_CLIENT_SECRET_FILE=tailscale__client_secret_file | ||||
| GENERIC_CLIENT_ID=generic_client_id | ||||
| GENERIC_CLIENT_SECRET=generic_client_secret | ||||
| GENERIC_CLIENT_SECRET_FILE=generic_client_secret_file | ||||
|   | ||||
							
								
								
									
										105
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										105
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							| @@ -6,7 +6,85 @@ on: | ||||
|       - "v*" | ||||
|  | ||||
| jobs: | ||||
|   build: | ||||
|   binary-build: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: Checkout | ||||
|         uses: actions/checkout@v4 | ||||
|  | ||||
|       - uses: oven-sh/setup-bun@v2 | ||||
|         with: | ||||
|           bun-version: latest | ||||
|  | ||||
|       - uses: actions/setup-go@v5 | ||||
|         with: | ||||
|           go-version: "^1.23.2" | ||||
|  | ||||
|       - name: Install frontend dependencies | ||||
|         run: | | ||||
|           cd frontend | ||||
|           bun install | ||||
|  | ||||
|       - name: Install backend dependencies | ||||
|         run: | | ||||
|           go mod tidy | ||||
|  | ||||
|       - name: Build frontend | ||||
|         run: | | ||||
|           cd frontend | ||||
|           bun run build | ||||
|  | ||||
|       - name: Build | ||||
|         run: | | ||||
|           cp -r frontend/dist internal/assets/dist | ||||
|           CGO_ENABLED=0 go build -ldflags "-s -w" -o tinyauth-amd64 | ||||
|  | ||||
|       - name: Upload artifact | ||||
|         uses: actions/upload-artifact@v4 | ||||
|         with: | ||||
|           name: tinyauth-amd64 | ||||
|           path: tinyauth-amd64 | ||||
|  | ||||
|   binary-build-arm: | ||||
|     runs-on: ubuntu-24.04-arm | ||||
|     steps: | ||||
|       - name: Checkout | ||||
|         uses: actions/checkout@v4 | ||||
|  | ||||
|       - uses: oven-sh/setup-bun@v2 | ||||
|         with: | ||||
|           bun-version: latest | ||||
|  | ||||
|       - uses: actions/setup-go@v5 | ||||
|         with: | ||||
|           go-version: "^1.23.2" | ||||
|  | ||||
|       - name: Install frontend dependencies | ||||
|         run: | | ||||
|           cd frontend | ||||
|           bun install | ||||
|  | ||||
|       - name: Install backend dependencies | ||||
|         run: | | ||||
|           go mod tidy | ||||
|  | ||||
|       - name: Build frontend | ||||
|         run: | | ||||
|           cd frontend | ||||
|           bun run build | ||||
|  | ||||
|       - name: Build | ||||
|         run: | | ||||
|           cp -r frontend/dist internal/assets/dist | ||||
|           CGO_ENABLED=0 go build -ldflags "-s -w" -o tinyauth-arm64 | ||||
|  | ||||
|       - name: Upload artifact | ||||
|         uses: actions/upload-artifact@v4 | ||||
|         with: | ||||
|           name: tinyauth-arm64 | ||||
|           path: tinyauth-arm64 | ||||
|  | ||||
|   image-build: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: Checkout | ||||
| @@ -51,7 +129,7 @@ jobs: | ||||
|           if-no-files-found: error | ||||
|           retention-days: 1 | ||||
|  | ||||
|   build-arm: | ||||
|   image-build-arm: | ||||
|     runs-on: ubuntu-24.04-arm | ||||
|     steps: | ||||
|       - name: Checkout | ||||
| @@ -96,11 +174,11 @@ jobs: | ||||
|           if-no-files-found: error | ||||
|           retention-days: 1 | ||||
|  | ||||
|   merge: | ||||
|   image-merge: | ||||
|     runs-on: ubuntu-latest | ||||
|     needs: | ||||
|       - build | ||||
|       - build-arm | ||||
|       - image-build | ||||
|       - image-build-arm | ||||
|     steps: | ||||
|       - name: Download digests | ||||
|         uses: actions/download-artifact@v4 | ||||
| @@ -134,3 +212,20 @@ jobs: | ||||
|         run: | | ||||
|           docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ | ||||
|             $(printf 'ghcr.io/${{ github.repository_owner }}/tinyauth@sha256:%s ' *) | ||||
|  | ||||
|   update-release: | ||||
|     runs-on: ubuntu-latest | ||||
|     needs: | ||||
|       - binary-build | ||||
|       - binary-build-arm | ||||
|     steps: | ||||
|       - uses: actions/download-artifact@v4 | ||||
|         with: | ||||
|           pattern: tinyauth-* | ||||
|           path: binaries | ||||
|           merge-multiple: true | ||||
|  | ||||
|       - name: Release | ||||
|         uses: softprops/action-gh-release@v2 | ||||
|         with: | ||||
|           files: binaries/* | ||||
|   | ||||
| @@ -17,6 +17,8 @@ | ||||
|  | ||||
| Tinyauth is a simple authentication middleware that adds simple username/password login or OAuth with Google, Github and any generic OAuth provider to all of your docker apps. It is made for traefik but it can be extended to work with all reverse proxies like caddy and nginx. | ||||
|  | ||||
|  | ||||
|  | ||||
| > [!WARNING] | ||||
| > Tinyauth is in active development and configuration may change often. Please make sure to carefully read the release notes before updating. | ||||
|  | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								assets/screenshot.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/screenshot.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 96 KiB | 
							
								
								
									
										31
									
								
								cmd/root.go
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								cmd/root.go
									
									
									
									
									
								
							| @@ -42,7 +42,6 @@ var rootCmd = &cobra.Command{ | ||||
| 		config.GithubClientSecret = utils.GetSecret(config.GithubClientSecret, config.GithubClientSecretFile) | ||||
| 		config.GoogleClientSecret = utils.GetSecret(config.GoogleClientSecret, config.GoogleClientSecretFile) | ||||
| 		config.GenericClientSecret = utils.GetSecret(config.GenericClientSecret, config.GenericClientSecretFile) | ||||
| 		config.TailscaleClientSecret = utils.GetSecret(config.TailscaleClientSecret, config.TailscaleClientSecretFile) | ||||
|  | ||||
| 		// Validate config | ||||
| 		validator := validator.New() | ||||
| @@ -77,19 +76,17 @@ var rootCmd = &cobra.Command{ | ||||
|  | ||||
| 		// Create OAuth config | ||||
| 		oauthConfig := types.OAuthConfig{ | ||||
| 			GithubClientId:        config.GithubClientId, | ||||
| 			GithubClientSecret:    config.GithubClientSecret, | ||||
| 			GoogleClientId:        config.GoogleClientId, | ||||
| 			GoogleClientSecret:    config.GoogleClientSecret, | ||||
| 			TailscaleClientId:     config.TailscaleClientId, | ||||
| 			TailscaleClientSecret: config.TailscaleClientSecret, | ||||
| 			GenericClientId:       config.GenericClientId, | ||||
| 			GenericClientSecret:   config.GenericClientSecret, | ||||
| 			GenericScopes:         strings.Split(config.GenericScopes, ","), | ||||
| 			GenericAuthURL:        config.GenericAuthURL, | ||||
| 			GenericTokenURL:       config.GenericTokenURL, | ||||
| 			GenericUserURL:        config.GenericUserURL, | ||||
| 			AppURL:                config.AppURL, | ||||
| 			GithubClientId:      config.GithubClientId, | ||||
| 			GithubClientSecret:  config.GithubClientSecret, | ||||
| 			GoogleClientId:      config.GoogleClientId, | ||||
| 			GoogleClientSecret:  config.GoogleClientSecret, | ||||
| 			GenericClientId:     config.GenericClientId, | ||||
| 			GenericClientSecret: config.GenericClientSecret, | ||||
| 			GenericScopes:       strings.Split(config.GenericScopes, ","), | ||||
| 			GenericAuthURL:      config.GenericAuthURL, | ||||
| 			GenericTokenURL:     config.GenericTokenURL, | ||||
| 			GenericUserURL:      config.GenericUserURL, | ||||
| 			AppURL:              config.AppURL, | ||||
| 		} | ||||
|  | ||||
| 		// Create handlers config | ||||
| @@ -189,9 +186,6 @@ func init() { | ||||
| 	rootCmd.Flags().String("google-client-id", "", "Google OAuth client ID.") | ||||
| 	rootCmd.Flags().String("google-client-secret", "", "Google OAuth client secret.") | ||||
| 	rootCmd.Flags().String("google-client-secret-file", "", "Google OAuth client secret file.") | ||||
| 	rootCmd.Flags().String("tailscale-client-id", "", "Tailscale OAuth client ID.") | ||||
| 	rootCmd.Flags().String("tailscale-client-secret", "", "Tailscale OAuth client secret.") | ||||
| 	rootCmd.Flags().String("tailscale-client-secret-file", "", "Tailscale OAuth client secret file.") | ||||
| 	rootCmd.Flags().String("generic-client-id", "", "Generic OAuth client ID.") | ||||
| 	rootCmd.Flags().String("generic-client-secret", "", "Generic OAuth client secret.") | ||||
| 	rootCmd.Flags().String("generic-client-secret-file", "", "Generic OAuth client secret file.") | ||||
| @@ -223,9 +217,6 @@ func init() { | ||||
| 	viper.BindEnv("google-client-id", "GOOGLE_CLIENT_ID") | ||||
| 	viper.BindEnv("google-client-secret", "GOOGLE_CLIENT_SECRET") | ||||
| 	viper.BindEnv("google-client-secret-file", "GOOGLE_CLIENT_SECRET_FILE") | ||||
| 	viper.BindEnv("tailscale-client-id", "TAILSCALE_CLIENT_ID") | ||||
| 	viper.BindEnv("tailscale-client-secret", "TAILSCALE_CLIENT_SECRET") | ||||
| 	viper.BindEnv("tailscale-client-secret-file", "TAILSCALE_CLIENT_SECRET_FILE") | ||||
| 	viper.BindEnv("generic-client-id", "GENERIC_CLIENT_ID") | ||||
| 	viper.BindEnv("generic-client-secret", "GENERIC_CLIENT_SECRET") | ||||
| 	viper.BindEnv("generic-client-secret-file", "GENERIC_CLIENT_SECRET_FILE") | ||||
|   | ||||
| @@ -25,7 +25,7 @@ export const LoginForm = (props: LoginFormProps) => { | ||||
|     <form onSubmit={form.onSubmit(onSubmit)}> | ||||
|       <TextInput | ||||
|         label={t("loginUsername")} | ||||
|         placeholder="user@example.com" | ||||
|         placeholder="username" | ||||
|         required | ||||
|         disabled={isLoading} | ||||
|         key={form.key("username")} | ||||
|   | ||||
| @@ -2,7 +2,6 @@ import { Grid, Button } from "@mantine/core"; | ||||
| import { GithubIcon } from "../../icons/github"; | ||||
| import { GoogleIcon } from "../../icons/google"; | ||||
| import { OAuthIcon } from "../../icons/oauth"; | ||||
| import { TailscaleIcon } from "../../icons/tailscale"; | ||||
|  | ||||
| interface OAuthButtonsProps { | ||||
|   oauthProviders: string[]; | ||||
| @@ -41,19 +40,6 @@ export const OAuthButtons = (props: OAuthButtonsProps) => { | ||||
|           </Button> | ||||
|         </Grid.Col> | ||||
|       )} | ||||
|       {oauthProviders.includes("tailscale") && ( | ||||
|         <Grid.Col span="content"> | ||||
|           <Button | ||||
|             radius="xl" | ||||
|             leftSection={<TailscaleIcon style={{ width: 14, height: 14 }} />} | ||||
|             variant="default" | ||||
|             onClick={() => mutate("tailscale")} | ||||
|             loading={isLoading} | ||||
|           > | ||||
|             Tailscale | ||||
|           </Button> | ||||
|         </Grid.Col> | ||||
|       )} | ||||
|       {oauthProviders.includes("generic") && ( | ||||
|         <Grid.Col span="content"> | ||||
|           <Button | ||||
|   | ||||
| @@ -1,55 +0,0 @@ | ||||
| import type { SVGProps } from "react"; | ||||
|  | ||||
| export function TailscaleIcon(props: SVGProps<SVGSVGElement>) { | ||||
|   return ( | ||||
|     <svg | ||||
|       xmlns="http://www.w3.org/2000/svg" | ||||
|       viewBox="0 0 512 512" | ||||
|       width={24} | ||||
|       height={24} | ||||
|       {...props} | ||||
|     > | ||||
|       <style>{".st0{opacity:0.2;fill:#CCCAC9;}.st1{fill:#FFFFFF;}"}</style> | ||||
|       <g> | ||||
|         <g> | ||||
|           <path | ||||
|             className="st0" | ||||
|             d="M65.6,127.7c35.3,0,63.9-28.6,63.9-63.9S100.9,0,65.6,0S1.8,28.6,1.8,63.9S30.4,127.7,65.6,127.7z" | ||||
|           /> | ||||
|           <path | ||||
|             className="st1" | ||||
|             d="M65.6,318.1c35.3,0,63.9-28.6,63.9-63.9s-28.6-63.9-63.9-63.9S1.8,219,1.8,254.2S30.4,318.1,65.6,318.1z" | ||||
|           /> | ||||
|           <path | ||||
|             className="st0" | ||||
|             d="M65.6,512c35.3,0,63.9-28.6,63.9-63.9s-28.6-63.9-63.9-63.9S1.8,412.9,1.8,448.1S30.4,512,65.6,512z" | ||||
|           /> | ||||
|           <path | ||||
|             className="st1" | ||||
|             d="M257.2,318.1c35.3,0,63.9-28.6,63.9-63.9s-28.6-63.9-63.9-63.9s-63.9,28.6-63.9,63.9S221.9,318.1,257.2,318.1z" | ||||
|           /> | ||||
|           <path | ||||
|             className="st1" | ||||
|             d="M257.2,512c35.3,0,63.9-28.6,63.9-63.9s-28.6-63.9-63.9-63.9s-63.9,28.6-63.9,63.9S221.9,512,257.2,512z" | ||||
|           /> | ||||
|           <path | ||||
|             className="st0" | ||||
|             d="M257.2,127.7c35.3,0,63.9-28.6,63.9-63.9S292.5,0,257.2,0s-63.9,28.6-63.9,63.9S221.9,127.7,257.2,127.7z" | ||||
|           /> | ||||
|           <path | ||||
|             className="st0" | ||||
|             d="M446.4,127.7c35.3,0,63.9-28.6,63.9-63.9S481.6,0,446.4,0c-35.3,0-63.9,28.6-63.9,63.9S411.1,127.7,446.4,127.7z" | ||||
|           /> | ||||
|           <path | ||||
|             className="st1" | ||||
|             d="M446.4,318.1c35.3,0,63.9-28.6,63.9-63.9s-28.6-63.9-63.9-63.9s-63.9,28.6-63.9,63.9S411.1,318.1,446.4,318.1z" | ||||
|           /> | ||||
|           <path | ||||
|             className="st0" | ||||
|             d="M446.4,512c35.3,0,63.9-28.6,63.9-63.9s-28.6-63.9-63.9-63.9s-63.9,28.6-63.9,63.9S411.1,512,446.4,512z" | ||||
|           /> | ||||
|         </g> | ||||
|       </g> | ||||
|     </svg> | ||||
|   ); | ||||
| } | ||||
| @@ -6,6 +6,7 @@ | ||||
|     "loginSubmit": "Login", | ||||
|     "loginFailTitle": "Failed to log in", | ||||
|     "loginFailSubtitle": "Please check your username and password", | ||||
|     "loginFailRateLimit": "You failed to login too many times, please try again later", | ||||
|     "loginSuccessTitle": "Logged in", | ||||
|     "loginSuccessSubtitle": "Welcome back!", | ||||
|     "loginOauthFailTitle": "Internal error", | ||||
| @@ -39,7 +40,7 @@ | ||||
|     "totpSuccessSubtitle": "Redirecting to your app", | ||||
|     "totpTitle": "Enter your TOTP code", | ||||
|     "unauthorizedTitle": "Unauthorized", | ||||
|     "unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.", | ||||
|     "unauthorizedResourceSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to login.", | ||||
|     "unauthorizedButton": "Try again" | ||||
| } | ||||
| @@ -1,45 +1,46 @@ | ||||
| { | ||||
|     "loginTitle": "Welcome back, login with", | ||||
|     "loginDivider": "Or continue with password", | ||||
|     "loginUsername": "Username", | ||||
|     "loginPassword": "Password", | ||||
|     "loginSubmit": "Login", | ||||
|     "loginFailTitle": "Failed to log in", | ||||
|     "loginFailSubtitle": "Please check your username and password", | ||||
|     "loginSuccessTitle": "Logged in", | ||||
|     "loginSuccessSubtitle": "Welcome back!", | ||||
|     "loginOauthFailTitle": "Internal error", | ||||
|     "loginOauthFailSubtitle": "Failed to get OAuth URL", | ||||
|     "loginOauthSuccessTitle": "Redirecting", | ||||
|     "loginOauthSuccessSubtitle": "Redirecting to your OAuth provider", | ||||
|     "continueRedirectingTitle": "Redirecting...", | ||||
|     "continueRedirectingSubtitle": "You should be redirected to the app soon", | ||||
|     "continueInvalidRedirectTitle": "Invalid redirect", | ||||
|     "continueInvalidRedirectSubtitle": "The redirect URL is invalid", | ||||
|     "continueInsecureRedirectTitle": "Insecure redirect", | ||||
|     "continueInsecureRedirectSubtitle": "You are trying to redirect from <Code>https</Code> to <Code>http</Code>, are you sure you want to continue?", | ||||
|     "continueTitle": "Continue", | ||||
|     "continueSubtitle": "Click the button to continue to your app.", | ||||
|     "internalErrorTitle": "Internal Server Error", | ||||
|     "internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.", | ||||
|     "internalErrorButton": "Try again", | ||||
|     "logoutFailTitle": "Failed to log out", | ||||
|     "logoutFailSubtitle": "Please try again", | ||||
|     "logoutSuccessTitle": "Logged out", | ||||
|     "logoutSuccessSubtitle": "You have been logged out", | ||||
|     "logoutTitle": "Logout", | ||||
|     "logoutUsernameSubtitle": "You are currently logged in as <Code>{{username}}</Code>, click the button below to logout.", | ||||
|     "logoutOauthSubtitle": "You are currently logged in as <Code>{{username}}</Code> using the {{provider}} OAuth provider, click the button below to logout.", | ||||
|     "notFoundTitle": "Page not found", | ||||
|     "notFoundSubtitle": "The page you are looking for does not exist.", | ||||
|     "notFoundButton": "Go home", | ||||
|     "totpFailTitle": "Failed to verify code", | ||||
|     "totpFailSubtitle": "Please check your code and try again", | ||||
|     "totpSuccessTitle": "Verified", | ||||
|     "totpSuccessSubtitle": "Redirecting to your app", | ||||
|     "totpTitle": "Enter your TOTP code", | ||||
|     "unauthorizedTitle": "Unauthorized", | ||||
|     "unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.", | ||||
|     "unauthorizedButton": "Try again" | ||||
|     "loginTitle": "مرحبا بعودتك، قم بتسجيل الدخول باستخدام", | ||||
|     "loginDivider": "أو المتابعة بكلمة المرور", | ||||
|     "loginUsername": "اسم المستخدم", | ||||
|     "loginPassword": "كلمة المرور", | ||||
|     "loginSubmit": "تسجيل الدخول", | ||||
|     "loginFailTitle": "فشل تسجيل الدخول", | ||||
|     "loginFailSubtitle": "الرجاء التحقق من اسم المستخدم وكلمة المرور", | ||||
|     "loginFailRateLimit": "فشلت في تسجيل الدخول عدة مرات، الرجاء المحاولة مرة أخرى لاحقا", | ||||
|     "loginSuccessTitle": "تم تسجيل الدخول", | ||||
|     "loginSuccessSubtitle": "مرحبا بعودتك!", | ||||
|     "loginOauthFailTitle": "خطأ داخلي", | ||||
|     "loginOauthFailSubtitle": "فشل في الحصول على رابط OAuth", | ||||
|     "loginOauthSuccessTitle": "إعادة توجيه", | ||||
|     "loginOauthSuccessSubtitle": "إعادة توجيه إلى مزود OAuth الخاص بك", | ||||
|     "continueRedirectingTitle": "إعادة توجيه...", | ||||
|     "continueRedirectingSubtitle": "يجب إعادة توجيهك إلى التطبيق قريبا", | ||||
|     "continueInvalidRedirectTitle": "إعادة توجيه غير صالحة", | ||||
|     "continueInvalidRedirectSubtitle": "رابط إعادة التوجيه غير صالح", | ||||
|     "continueInsecureRedirectTitle": "إعادة توجيه غير آمنة", | ||||
|     "continueInsecureRedirectSubtitle": "أنت تحاول إعادة التوجيه من <Code>https</Code> إلى <Code>http</Code>، هل أنت متأكد أنك تريد المتابعة؟", | ||||
|     "continueTitle": "متابعة", | ||||
|     "continueSubtitle": "انقر الزر للمتابعة إلى التطبيق الخاص بك.", | ||||
|     "internalErrorTitle": "خطأ داخلي في الخادم", | ||||
|     "internalErrorSubtitle": "حدث خطأ على الخادم ولا يمكن حاليا تلبية طلبك.", | ||||
|     "internalErrorButton": "حاول مجددا", | ||||
|     "logoutFailTitle": "فشل تسجيل الخروج", | ||||
|     "logoutFailSubtitle": "يرجى إعادة المحاولة", | ||||
|     "logoutSuccessTitle": "تم تسجيل الخروج", | ||||
|     "logoutSuccessSubtitle": "تم تسجيل خروجك", | ||||
|     "logoutTitle": "تسجيل الخروج", | ||||
|     "logoutUsernameSubtitle": "أنت حاليا مسجل الدخول ك <Code>{{username}}</Code>، انقر الزر أدناه لتسجيل الخروج.", | ||||
|     "logoutOauthSubtitle": "أنت حاليا مسجل الدخول ك <Code>{{username}}</Code> باستخدام مزود OAuth {{provider}} ، انقر الزر أدناه لتسجيل الخروج.", | ||||
|     "notFoundTitle": "الصفحة غير موجودة", | ||||
|     "notFoundSubtitle": "الصفحة التي تبحث عنها غير موجودة.", | ||||
|     "notFoundButton": "انتقل إلى الرئيسية", | ||||
|     "totpFailTitle": "فشل في التحقق من الرمز", | ||||
|     "totpFailSubtitle": "الرجاء التحقق من الرمز الخاص بك وحاول مرة أخرى", | ||||
|     "totpSuccessTitle": "تم التحقق", | ||||
|     "totpSuccessSubtitle": "إعادة توجيه إلى تطبيقك", | ||||
|     "totpTitle": "أدخل رمز TOTP الخاص بك", | ||||
|     "unauthorizedTitle": "غير مرخص", | ||||
|     "unauthorizedResourceSubtitle": "المستخدم الذي يحمل اسم المستخدم <Code>{{username}}</Code> غير مصرح له بالوصول إلى المورد <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "المستخدم الذي يحمل اسم المستخدم <Code>{{username}}</Code> غير مصرح له بتسجيل الدخول.", | ||||
|     "unauthorizedButton": "حاول مجددا" | ||||
| } | ||||
| @@ -6,6 +6,7 @@ | ||||
|     "loginSubmit": "Login", | ||||
|     "loginFailTitle": "Failed to log in", | ||||
|     "loginFailSubtitle": "Please check your username and password", | ||||
|     "loginFailRateLimit": "You failed to login too many times, please try again later", | ||||
|     "loginSuccessTitle": "Logged in", | ||||
|     "loginSuccessSubtitle": "Welcome back!", | ||||
|     "loginOauthFailTitle": "Internal error", | ||||
| @@ -39,7 +40,7 @@ | ||||
|     "totpSuccessSubtitle": "Redirecting to your app", | ||||
|     "totpTitle": "Enter your TOTP code", | ||||
|     "unauthorizedTitle": "Unauthorized", | ||||
|     "unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.", | ||||
|     "unauthorizedResourceSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to login.", | ||||
|     "unauthorizedButton": "Try again" | ||||
| } | ||||
| @@ -6,6 +6,7 @@ | ||||
|     "loginSubmit": "Login", | ||||
|     "loginFailTitle": "Failed to log in", | ||||
|     "loginFailSubtitle": "Please check your username and password", | ||||
|     "loginFailRateLimit": "You failed to login too many times, please try again later", | ||||
|     "loginSuccessTitle": "Logged in", | ||||
|     "loginSuccessSubtitle": "Welcome back!", | ||||
|     "loginOauthFailTitle": "Internal error", | ||||
| @@ -39,7 +40,7 @@ | ||||
|     "totpSuccessSubtitle": "Redirecting to your app", | ||||
|     "totpTitle": "Enter your TOTP code", | ||||
|     "unauthorizedTitle": "Unauthorized", | ||||
|     "unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.", | ||||
|     "unauthorizedResourceSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to login.", | ||||
|     "unauthorizedButton": "Try again" | ||||
| } | ||||
| @@ -6,6 +6,7 @@ | ||||
|     "loginSubmit": "Login", | ||||
|     "loginFailTitle": "Failed to log in", | ||||
|     "loginFailSubtitle": "Please check your username and password", | ||||
|     "loginFailRateLimit": "You failed to login too many times, please try again later", | ||||
|     "loginSuccessTitle": "Logged in", | ||||
|     "loginSuccessSubtitle": "Welcome back!", | ||||
|     "loginOauthFailTitle": "Internal error", | ||||
| @@ -39,7 +40,7 @@ | ||||
|     "totpSuccessSubtitle": "Redirecting to your app", | ||||
|     "totpTitle": "Enter your TOTP code", | ||||
|     "unauthorizedTitle": "Unauthorized", | ||||
|     "unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.", | ||||
|     "unauthorizedResourceSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to login.", | ||||
|     "unauthorizedButton": "Try again" | ||||
| } | ||||
| @@ -1,26 +1,27 @@ | ||||
| { | ||||
|     "loginTitle": "Welcome back, login with", | ||||
|     "loginDivider": "Or continue with password", | ||||
|     "loginUsername": "Username", | ||||
|     "loginPassword": "Password", | ||||
|     "loginSubmit": "Login", | ||||
|     "loginFailTitle": "Failed to log in", | ||||
|     "loginFailSubtitle": "Please check your username and password", | ||||
|     "loginTitle": "Willkommen zurück, logge dich ein mit", | ||||
|     "loginDivider": "Oder mit Passwort fortfahren", | ||||
|     "loginUsername": "Benutzername", | ||||
|     "loginPassword": "Passwort", | ||||
|     "loginSubmit": "Anmelden", | ||||
|     "loginFailTitle": "Login fehlgeschlagen", | ||||
|     "loginFailSubtitle": "Bitte überprüfe deinen Benutzernamen und Passwort", | ||||
|     "loginFailRateLimit": "Sie konnten sich zu oft nicht einloggen, bitte versuchen Sie es später erneut", | ||||
|     "loginSuccessTitle": "Logged in", | ||||
|     "loginSuccessSubtitle": "Welcome back!", | ||||
|     "loginOauthFailTitle": "Internal error", | ||||
|     "loginOauthFailSubtitle": "Failed to get OAuth URL", | ||||
|     "loginSuccessSubtitle": "Willkommen zurück!", | ||||
|     "loginOauthFailTitle": "Interner Fehler", | ||||
|     "loginOauthFailSubtitle": "Fehler beim Abrufen der OAuth-URL", | ||||
|     "loginOauthSuccessTitle": "Redirecting", | ||||
|     "loginOauthSuccessSubtitle": "Redirecting to your OAuth provider", | ||||
|     "continueRedirectingTitle": "Redirecting...", | ||||
|     "continueRedirectingSubtitle": "You should be redirected to the app soon", | ||||
|     "continueInvalidRedirectTitle": "Invalid redirect", | ||||
|     "continueInvalidRedirectSubtitle": "The redirect URL is invalid", | ||||
|     "continueInsecureRedirectTitle": "Insecure redirect", | ||||
|     "continueInvalidRedirectTitle": "Ungültige Weiterleitung", | ||||
|     "continueInvalidRedirectSubtitle": "Die Weiterleitungs-URL ist ungültig", | ||||
|     "continueInsecureRedirectTitle": "Unsichere Weiterleitung", | ||||
|     "continueInsecureRedirectSubtitle": "You are trying to redirect from <Code>https</Code> to <Code>http</Code>, are you sure you want to continue?", | ||||
|     "continueTitle": "Continue", | ||||
|     "continueTitle": "Weiter", | ||||
|     "continueSubtitle": "Click the button to continue to your app.", | ||||
|     "internalErrorTitle": "Internal Server Error", | ||||
|     "internalErrorTitle": "Interner Serverfehler", | ||||
|     "internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.", | ||||
|     "internalErrorButton": "Try again", | ||||
|     "logoutFailTitle": "Failed to log out", | ||||
| @@ -39,7 +40,7 @@ | ||||
|     "totpSuccessSubtitle": "Redirecting to your app", | ||||
|     "totpTitle": "Enter your TOTP code", | ||||
|     "unauthorizedTitle": "Unauthorized", | ||||
|     "unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.", | ||||
|     "unauthorizedResourceSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to login.", | ||||
|     "unauthorizedButton": "Try again" | ||||
| } | ||||
| @@ -6,6 +6,7 @@ | ||||
|     "loginSubmit": "Είσοδος", | ||||
|     "loginFailTitle": "Αποτυχία σύνδεσης", | ||||
|     "loginFailSubtitle": "Παρακαλώ ελέγξτε το όνομα χρήστη και τον κωδικό πρόσβασης", | ||||
|     "loginFailRateLimit": "Αποτύχατε να συνδεθείτε πάρα πολλές φορές, παρακαλώ προσπαθήστε ξανά αργότερα", | ||||
|     "loginSuccessTitle": "Συνδεδεμένος", | ||||
|     "loginSuccessSubtitle": "Καλώς ήρθατε!", | ||||
|     "loginOauthFailTitle": "Εσωτερικό σφάλμα", | ||||
| @@ -39,7 +40,7 @@ | ||||
|     "totpSuccessSubtitle": "Ανακατεύθυνση στην εφαρμογή σας", | ||||
|     "totpTitle": "Εισάγετε τον κωδικό TOTP", | ||||
|     "unauthorizedTitle": "Μη εξουσιοδοτημένο", | ||||
|     "unauthorizedResourceSubtitle": "Ο χρήστης με όνομα χρήστη {{username}} δεν είναι εξουσιοδοτημένος να έχει πρόσβαση στον πόρο <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "Ο χρήστης με όνομα χρήστη {{username}} δεν είναι εξουσιοδοτημένος να συνδεθεί.", | ||||
|     "unauthorizedResourceSubtitle": "Ο χρήστης με όνομα χρήστη <Code>{{username}}</Code> δεν έχει άδεια πρόσβασης στον πόρο <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "Ο χρήστης με όνομα χρήστη <Code>{{username}}</Code> δεν είναι εξουσιοδοτημένος να συνδεθεί.", | ||||
|     "unauthorizedButton": "Προσπαθήστε ξανά" | ||||
| } | ||||
| @@ -40,7 +40,7 @@ | ||||
|     "totpSuccessSubtitle": "Redirecting to your app", | ||||
|     "totpTitle": "Enter your TOTP code", | ||||
|     "unauthorizedTitle": "Unauthorized", | ||||
|     "unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.", | ||||
|     "unauthorizedResourceSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to login.", | ||||
|     "unauthorizedButton": "Try again" | ||||
| } | ||||
| @@ -40,7 +40,7 @@ | ||||
|     "totpSuccessSubtitle": "Redirecting to your app", | ||||
|     "totpTitle": "Enter your TOTP code", | ||||
|     "unauthorizedTitle": "Unauthorized", | ||||
|     "unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.", | ||||
|     "unauthorizedResourceSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to login.", | ||||
|     "unauthorizedButton": "Try again" | ||||
| } | ||||
| @@ -6,6 +6,7 @@ | ||||
|     "loginSubmit": "Login", | ||||
|     "loginFailTitle": "Failed to log in", | ||||
|     "loginFailSubtitle": "Please check your username and password", | ||||
|     "loginFailRateLimit": "You failed to login too many times, please try again later", | ||||
|     "loginSuccessTitle": "Logged in", | ||||
|     "loginSuccessSubtitle": "Welcome back!", | ||||
|     "loginOauthFailTitle": "Internal error", | ||||
| @@ -39,7 +40,7 @@ | ||||
|     "totpSuccessSubtitle": "Redirecting to your app", | ||||
|     "totpTitle": "Enter your TOTP code", | ||||
|     "unauthorizedTitle": "Unauthorized", | ||||
|     "unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.", | ||||
|     "unauthorizedResourceSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to login.", | ||||
|     "unauthorizedButton": "Try again" | ||||
| } | ||||
| @@ -6,6 +6,7 @@ | ||||
|     "loginSubmit": "Login", | ||||
|     "loginFailTitle": "Failed to log in", | ||||
|     "loginFailSubtitle": "Please check your username and password", | ||||
|     "loginFailRateLimit": "You failed to login too many times, please try again later", | ||||
|     "loginSuccessTitle": "Logged in", | ||||
|     "loginSuccessSubtitle": "Welcome back!", | ||||
|     "loginOauthFailTitle": "Internal error", | ||||
| @@ -39,7 +40,7 @@ | ||||
|     "totpSuccessSubtitle": "Redirecting to your app", | ||||
|     "totpTitle": "Enter your TOTP code", | ||||
|     "unauthorizedTitle": "Unauthorized", | ||||
|     "unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.", | ||||
|     "unauthorizedResourceSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to login.", | ||||
|     "unauthorizedButton": "Try again" | ||||
| } | ||||
| @@ -6,6 +6,7 @@ | ||||
|     "loginSubmit": "Se connecter", | ||||
|     "loginFailTitle": "Échec de la connexion", | ||||
|     "loginFailSubtitle": "Veuillez vérifier votre nom d'utilisateur et votre mot de passe", | ||||
|     "loginFailRateLimit": "Vous n'avez pas pu vous connecter trop de fois, veuillez réessayer plus tard", | ||||
|     "loginSuccessTitle": "Connecté", | ||||
|     "loginSuccessSubtitle": "Bienvenue!", | ||||
|     "loginOauthFailTitle": "Erreur interne", | ||||
| @@ -39,7 +40,7 @@ | ||||
|     "totpSuccessSubtitle": "Redirection vers votre application", | ||||
|     "totpTitle": "Saisissez votre code TOTP", | ||||
|     "unauthorizedTitle": "Non autorisé", | ||||
|     "unauthorizedResourceSubtitle": "L'utilisateur avec le nom d'utilisateur {{username}} n'est pas autorisé à accéder à la ressource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "L'utilisateur avec le nom d'utilisateur {{username}} n'est pas autorisé à se connecter.", | ||||
|     "unauthorizedResourceSubtitle": "L'utilisateur avec le nom d'utilisateur <Code>{{username}}</Code> n'est pas autorisé à accéder à la ressource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "L'utilisateur avec le nom d'utilisateur <Code>{{username}}</Code> n'est pas autorisé à se connecter.", | ||||
|     "unauthorizedButton": "Réessayer" | ||||
| } | ||||
| @@ -6,6 +6,7 @@ | ||||
|     "loginSubmit": "Login", | ||||
|     "loginFailTitle": "Failed to log in", | ||||
|     "loginFailSubtitle": "Please check your username and password", | ||||
|     "loginFailRateLimit": "You failed to login too many times, please try again later", | ||||
|     "loginSuccessTitle": "Logged in", | ||||
|     "loginSuccessSubtitle": "Welcome back!", | ||||
|     "loginOauthFailTitle": "Internal error", | ||||
| @@ -39,7 +40,7 @@ | ||||
|     "totpSuccessSubtitle": "Redirecting to your app", | ||||
|     "totpTitle": "Enter your TOTP code", | ||||
|     "unauthorizedTitle": "Unauthorized", | ||||
|     "unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.", | ||||
|     "unauthorizedResourceSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to login.", | ||||
|     "unauthorizedButton": "Try again" | ||||
| } | ||||
| @@ -6,6 +6,7 @@ | ||||
|     "loginSubmit": "Login", | ||||
|     "loginFailTitle": "Failed to log in", | ||||
|     "loginFailSubtitle": "Please check your username and password", | ||||
|     "loginFailRateLimit": "You failed to login too many times, please try again later", | ||||
|     "loginSuccessTitle": "Logged in", | ||||
|     "loginSuccessSubtitle": "Welcome back!", | ||||
|     "loginOauthFailTitle": "Internal error", | ||||
| @@ -39,7 +40,7 @@ | ||||
|     "totpSuccessSubtitle": "Redirecting to your app", | ||||
|     "totpTitle": "Enter your TOTP code", | ||||
|     "unauthorizedTitle": "Unauthorized", | ||||
|     "unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.", | ||||
|     "unauthorizedResourceSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to login.", | ||||
|     "unauthorizedButton": "Try again" | ||||
| } | ||||
| @@ -6,6 +6,7 @@ | ||||
|     "loginSubmit": "Login", | ||||
|     "loginFailTitle": "Failed to log in", | ||||
|     "loginFailSubtitle": "Please check your username and password", | ||||
|     "loginFailRateLimit": "You failed to login too many times, please try again later", | ||||
|     "loginSuccessTitle": "Logged in", | ||||
|     "loginSuccessSubtitle": "Welcome back!", | ||||
|     "loginOauthFailTitle": "Internal error", | ||||
| @@ -39,7 +40,7 @@ | ||||
|     "totpSuccessSubtitle": "Redirecting to your app", | ||||
|     "totpTitle": "Enter your TOTP code", | ||||
|     "unauthorizedTitle": "Unauthorized", | ||||
|     "unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.", | ||||
|     "unauthorizedResourceSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to login.", | ||||
|     "unauthorizedButton": "Try again" | ||||
| } | ||||
| @@ -6,6 +6,7 @@ | ||||
|     "loginSubmit": "Login", | ||||
|     "loginFailTitle": "Failed to log in", | ||||
|     "loginFailSubtitle": "Please check your username and password", | ||||
|     "loginFailRateLimit": "You failed to login too many times, please try again later", | ||||
|     "loginSuccessTitle": "Logged in", | ||||
|     "loginSuccessSubtitle": "Welcome back!", | ||||
|     "loginOauthFailTitle": "Internal error", | ||||
| @@ -39,7 +40,7 @@ | ||||
|     "totpSuccessSubtitle": "Redirecting to your app", | ||||
|     "totpTitle": "Enter your TOTP code", | ||||
|     "unauthorizedTitle": "Unauthorized", | ||||
|     "unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.", | ||||
|     "unauthorizedResourceSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to login.", | ||||
|     "unauthorizedButton": "Try again" | ||||
| } | ||||
| @@ -6,6 +6,7 @@ | ||||
|     "loginSubmit": "Login", | ||||
|     "loginFailTitle": "Failed to log in", | ||||
|     "loginFailSubtitle": "Please check your username and password", | ||||
|     "loginFailRateLimit": "You failed to login too many times, please try again later", | ||||
|     "loginSuccessTitle": "Logged in", | ||||
|     "loginSuccessSubtitle": "Welcome back!", | ||||
|     "loginOauthFailTitle": "Internal error", | ||||
| @@ -39,7 +40,7 @@ | ||||
|     "totpSuccessSubtitle": "Redirecting to your app", | ||||
|     "totpTitle": "Enter your TOTP code", | ||||
|     "unauthorizedTitle": "Unauthorized", | ||||
|     "unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.", | ||||
|     "unauthorizedResourceSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to login.", | ||||
|     "unauthorizedButton": "Try again" | ||||
| } | ||||
| @@ -1,45 +1,46 @@ | ||||
| { | ||||
|     "loginTitle": "Welcome back, login with", | ||||
|     "loginDivider": "Or continue with password", | ||||
|     "loginUsername": "Username", | ||||
|     "loginPassword": "Password", | ||||
|     "loginSubmit": "Login", | ||||
|     "loginFailTitle": "Failed to log in", | ||||
|     "loginFailSubtitle": "Please check your username and password", | ||||
|     "loginSuccessTitle": "Logged in", | ||||
|     "loginSuccessSubtitle": "Welcome back!", | ||||
|     "loginOauthFailTitle": "Internal error", | ||||
|     "loginOauthFailSubtitle": "Failed to get OAuth URL", | ||||
|     "loginOauthSuccessTitle": "Redirecting", | ||||
|     "loginOauthSuccessSubtitle": "Redirecting to your OAuth provider", | ||||
|     "continueRedirectingTitle": "Redirecting...", | ||||
|     "continueRedirectingSubtitle": "You should be redirected to the app soon", | ||||
|     "continueInvalidRedirectTitle": "Invalid redirect", | ||||
|     "continueInvalidRedirectSubtitle": "The redirect URL is invalid", | ||||
|     "continueInsecureRedirectTitle": "Insecure redirect", | ||||
|     "continueInsecureRedirectSubtitle": "You are trying to redirect from <Code>https</Code> to <Code>http</Code>, are you sure you want to continue?", | ||||
|     "continueTitle": "Continue", | ||||
|     "continueSubtitle": "Click the button to continue to your app.", | ||||
|     "internalErrorTitle": "Internal Server Error", | ||||
|     "internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.", | ||||
|     "internalErrorButton": "Try again", | ||||
|     "logoutFailTitle": "Failed to log out", | ||||
|     "logoutFailSubtitle": "Please try again", | ||||
|     "logoutSuccessTitle": "Logged out", | ||||
|     "logoutSuccessSubtitle": "You have been logged out", | ||||
|     "logoutTitle": "Logout", | ||||
|     "logoutUsernameSubtitle": "You are currently logged in as <Code>{{username}}</Code>, click the button below to logout.", | ||||
|     "logoutOauthSubtitle": "You are currently logged in as <Code>{{username}}</Code> using the {{provider}} OAuth provider, click the button below to logout.", | ||||
|     "notFoundTitle": "Page not found", | ||||
|     "notFoundSubtitle": "The page you are looking for does not exist.", | ||||
|     "notFoundButton": "Go home", | ||||
|     "totpFailTitle": "Failed to verify code", | ||||
|     "totpFailSubtitle": "Please check your code and try again", | ||||
|     "totpSuccessTitle": "Verified", | ||||
|     "totpSuccessSubtitle": "Redirecting to your app", | ||||
|     "totpTitle": "Enter your TOTP code", | ||||
|     "unauthorizedTitle": "Unauthorized", | ||||
|     "unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.", | ||||
|     "unauthorizedButton": "Try again" | ||||
|     "loginTitle": "Welkom terug, log in met", | ||||
|     "loginDivider": "Of ga door met wachtwoord", | ||||
|     "loginUsername": "Gebruikersnaam", | ||||
|     "loginPassword": "Wachtwoord", | ||||
|     "loginSubmit": "Log in", | ||||
|     "loginFailTitle": "Mislukt om in te loggen", | ||||
|     "loginFailSubtitle": "Controleer je gebruikersnaam en wachtwoord", | ||||
|     "loginFailRateLimit": "Inloggen te vaak mislukt, probeer het later opnieuw", | ||||
|     "loginSuccessTitle": "Ingelogd", | ||||
|     "loginSuccessSubtitle": "Welkom terug!", | ||||
|     "loginOauthFailTitle": "Interne fout", | ||||
|     "loginOauthFailSubtitle": "Fout bij het ophalen van OAuth URL", | ||||
|     "loginOauthSuccessTitle": "Omleiden", | ||||
|     "loginOauthSuccessSubtitle": "Omleiden naar je OAuth provider", | ||||
|     "continueRedirectingTitle": "Omleiden...", | ||||
|     "continueRedirectingSubtitle": "Je wordt naar de app doorgestuurd", | ||||
|     "continueInvalidRedirectTitle": "Ongeldige omleiding", | ||||
|     "continueInvalidRedirectSubtitle": "De omleidings-URL is ongeldig", | ||||
|     "continueInsecureRedirectTitle": "Onveilige doorverwijzing", | ||||
|     "continueInsecureRedirectSubtitle": "Je probeert door te verwijzen van <Code>https</Code> naar <Code>http</Code>, weet je zeker dat je wilt doorgaan?", | ||||
|     "continueTitle": "Ga verder", | ||||
|     "continueSubtitle": "Klik op de knop om door te gaan naar de app.", | ||||
|     "internalErrorTitle": "Interne server fout", | ||||
|     "internalErrorSubtitle": "Er is een fout opgetreden op de server en het kan momenteel niet voldoen aan je verzoek.", | ||||
|     "internalErrorButton": "Opnieuw proberen", | ||||
|     "logoutFailTitle": "Afmelden mislukt", | ||||
|     "logoutFailSubtitle": "Probeer het opnieuw", | ||||
|     "logoutSuccessTitle": "Afgemeld", | ||||
|     "logoutSuccessSubtitle": "Je bent afgemeld", | ||||
|     "logoutTitle": "Afmelden", | ||||
|     "logoutUsernameSubtitle": "Je bent momenteel ingelogd als <Code>{{username}}</Code>, klik op de knop hieronder om uit te loggen.", | ||||
|     "logoutOauthSubtitle": "Je bent momenteel ingelogd als <Code>{{username}}</Code> met behulp van de {{provider}} OAuth provider, klik op de knop hieronder om uit te loggen.", | ||||
|     "notFoundTitle": "Pagina niet gevonden", | ||||
|     "notFoundSubtitle": "De pagina die je zoekt bestaat niet.", | ||||
|     "notFoundButton": "Naar startpagina", | ||||
|     "totpFailTitle": "Verifiëren van code mislukt", | ||||
|     "totpFailSubtitle": "Controleer je code en probeer het opnieuw", | ||||
|     "totpSuccessTitle": "Geverifiëerd", | ||||
|     "totpSuccessSubtitle": "Omleiden naar je app", | ||||
|     "totpTitle": "Voer je TOTP-code in", | ||||
|     "unauthorizedTitle": "Ongeautoriseerd", | ||||
|     "unauthorizedResourceSubtitle": "De gebruiker met gebruikersnaam <Code>{{username}}</Code> heeft geen toegang tot de bron <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "De gebruiker met gebruikersnaam <Code>{{username}}</Code> is niet gemachtigd om in te loggen.", | ||||
|     "unauthorizedButton": "Opnieuw proberen" | ||||
| } | ||||
| @@ -6,6 +6,7 @@ | ||||
|     "loginSubmit": "Login", | ||||
|     "loginFailTitle": "Failed to log in", | ||||
|     "loginFailSubtitle": "Please check your username and password", | ||||
|     "loginFailRateLimit": "You failed to login too many times, please try again later", | ||||
|     "loginSuccessTitle": "Logged in", | ||||
|     "loginSuccessSubtitle": "Welcome back!", | ||||
|     "loginOauthFailTitle": "Internal error", | ||||
| @@ -39,7 +40,7 @@ | ||||
|     "totpSuccessSubtitle": "Redirecting to your app", | ||||
|     "totpTitle": "Enter your TOTP code", | ||||
|     "unauthorizedTitle": "Unauthorized", | ||||
|     "unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.", | ||||
|     "unauthorizedResourceSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to login.", | ||||
|     "unauthorizedButton": "Try again" | ||||
| } | ||||
| @@ -3,9 +3,10 @@ | ||||
|     "loginDivider": "Lub kontynuuj z hasłem", | ||||
|     "loginUsername": "Nazwa użytkownika", | ||||
|     "loginPassword": "Hasło", | ||||
|     "loginSubmit": "Login", | ||||
|     "loginFailTitle": "Failed to log in", | ||||
|     "loginSubmit": "Zaloguj się", | ||||
|     "loginFailTitle": "Nie udało się zalogować", | ||||
|     "loginFailSubtitle": "Sprawdź swoją nazwę użytkownika i hasło", | ||||
|     "loginFailRateLimit": "Nie udało się zalogować zbyt wiele razy, spróbuj ponownie później", | ||||
|     "loginSuccessTitle": "Zalogowano", | ||||
|     "loginSuccessSubtitle": "Witaj ponownie!", | ||||
|     "loginOauthFailTitle": "Wewnętrzny błąd", | ||||
| @@ -21,9 +22,9 @@ | ||||
|     "continueTitle": "Kontynuuj", | ||||
|     "continueSubtitle": "Kliknij przycisk, aby przejść do aplikacji.", | ||||
|     "internalErrorTitle": "Wewnętrzny błąd serwera", | ||||
|     "internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.", | ||||
|     "internalErrorSubtitle": "Wystąpił błąd na serwerze i obecnie nie można obsłużyć tego żądania.", | ||||
|     "internalErrorButton": "Spróbuj ponownie", | ||||
|     "logoutFailTitle": "Failed to log out", | ||||
|     "logoutFailTitle": "Nie udało się wylogować", | ||||
|     "logoutFailSubtitle": "Spróbuj ponownie", | ||||
|     "logoutSuccessTitle": "Wylogowano", | ||||
|     "logoutSuccessSubtitle": "Zostałeś wylogowany", | ||||
| @@ -39,7 +40,7 @@ | ||||
|     "totpSuccessSubtitle": "Przekierowywanie do aplikacji", | ||||
|     "totpTitle": "Wprowadź kod TOTP", | ||||
|     "unauthorizedTitle": "Nieautoryzowany", | ||||
|     "unauthorizedResourceSubtitle": "Użytkownik o nazwie {{username}} nie jest upoważniony do uzyskania dostępu do zasobu <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "Użytkownik o nazwie {{username}} nie jest upoważniony do logowania.", | ||||
|     "unauthorizedResourceSubtitle": "Użytkownik o nazwie <Code>{{username}}</Code> nie jest upoważniony do uzyskania dostępu do zasobu <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "Użytkownik o nazwie <Code>{{username}}</Code> nie jest upoważniony do logowania.", | ||||
|     "unauthorizedButton": "Spróbuj ponownie" | ||||
| } | ||||
| @@ -6,6 +6,7 @@ | ||||
|     "loginSubmit": "Login", | ||||
|     "loginFailTitle": "Failed to log in", | ||||
|     "loginFailSubtitle": "Please check your username and password", | ||||
|     "loginFailRateLimit": "You failed to login too many times, please try again later", | ||||
|     "loginSuccessTitle": "Logged in", | ||||
|     "loginSuccessSubtitle": "Welcome back!", | ||||
|     "loginOauthFailTitle": "Internal error", | ||||
| @@ -39,7 +40,7 @@ | ||||
|     "totpSuccessSubtitle": "Redirecting to your app", | ||||
|     "totpTitle": "Enter your TOTP code", | ||||
|     "unauthorizedTitle": "Unauthorized", | ||||
|     "unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.", | ||||
|     "unauthorizedResourceSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to login.", | ||||
|     "unauthorizedButton": "Try again" | ||||
| } | ||||
| @@ -6,6 +6,7 @@ | ||||
|     "loginSubmit": "Login", | ||||
|     "loginFailTitle": "Failed to log in", | ||||
|     "loginFailSubtitle": "Please check your username and password", | ||||
|     "loginFailRateLimit": "You failed to login too many times, please try again later", | ||||
|     "loginSuccessTitle": "Logged in", | ||||
|     "loginSuccessSubtitle": "Welcome back!", | ||||
|     "loginOauthFailTitle": "Internal error", | ||||
| @@ -39,7 +40,7 @@ | ||||
|     "totpSuccessSubtitle": "Redirecting to your app", | ||||
|     "totpTitle": "Enter your TOTP code", | ||||
|     "unauthorizedTitle": "Unauthorized", | ||||
|     "unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.", | ||||
|     "unauthorizedResourceSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to login.", | ||||
|     "unauthorizedButton": "Try again" | ||||
| } | ||||
| @@ -6,6 +6,7 @@ | ||||
|     "loginSubmit": "Login", | ||||
|     "loginFailTitle": "Failed to log in", | ||||
|     "loginFailSubtitle": "Please check your username and password", | ||||
|     "loginFailRateLimit": "You failed to login too many times, please try again later", | ||||
|     "loginSuccessTitle": "Logged in", | ||||
|     "loginSuccessSubtitle": "Welcome back!", | ||||
|     "loginOauthFailTitle": "Internal error", | ||||
| @@ -39,7 +40,7 @@ | ||||
|     "totpSuccessSubtitle": "Redirecting to your app", | ||||
|     "totpTitle": "Enter your TOTP code", | ||||
|     "unauthorizedTitle": "Unauthorized", | ||||
|     "unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.", | ||||
|     "unauthorizedResourceSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to login.", | ||||
|     "unauthorizedButton": "Try again" | ||||
| } | ||||
| @@ -6,6 +6,7 @@ | ||||
|     "loginSubmit": "Login", | ||||
|     "loginFailTitle": "Failed to log in", | ||||
|     "loginFailSubtitle": "Please check your username and password", | ||||
|     "loginFailRateLimit": "You failed to login too many times, please try again later", | ||||
|     "loginSuccessTitle": "Logged in", | ||||
|     "loginSuccessSubtitle": "Welcome back!", | ||||
|     "loginOauthFailTitle": "Internal error", | ||||
| @@ -39,7 +40,7 @@ | ||||
|     "totpSuccessSubtitle": "Redirecting to your app", | ||||
|     "totpTitle": "Enter your TOTP code", | ||||
|     "unauthorizedTitle": "Unauthorized", | ||||
|     "unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.", | ||||
|     "unauthorizedResourceSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to login.", | ||||
|     "unauthorizedButton": "Try again" | ||||
| } | ||||
| @@ -6,6 +6,7 @@ | ||||
|     "loginSubmit": "Login", | ||||
|     "loginFailTitle": "Failed to log in", | ||||
|     "loginFailSubtitle": "Please check your username and password", | ||||
|     "loginFailRateLimit": "You failed to login too many times, please try again later", | ||||
|     "loginSuccessTitle": "Logged in", | ||||
|     "loginSuccessSubtitle": "Welcome back!", | ||||
|     "loginOauthFailTitle": "Internal error", | ||||
| @@ -39,7 +40,7 @@ | ||||
|     "totpSuccessSubtitle": "Redirecting to your app", | ||||
|     "totpTitle": "Enter your TOTP code", | ||||
|     "unauthorizedTitle": "Unauthorized", | ||||
|     "unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.", | ||||
|     "unauthorizedResourceSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to login.", | ||||
|     "unauthorizedButton": "Try again" | ||||
| } | ||||
| @@ -6,6 +6,7 @@ | ||||
|     "loginSubmit": "Login", | ||||
|     "loginFailTitle": "Failed to log in", | ||||
|     "loginFailSubtitle": "Please check your username and password", | ||||
|     "loginFailRateLimit": "You failed to login too many times, please try again later", | ||||
|     "loginSuccessTitle": "Logged in", | ||||
|     "loginSuccessSubtitle": "Welcome back!", | ||||
|     "loginOauthFailTitle": "Internal error", | ||||
| @@ -39,7 +40,7 @@ | ||||
|     "totpSuccessSubtitle": "Redirecting to your app", | ||||
|     "totpTitle": "Enter your TOTP code", | ||||
|     "unauthorizedTitle": "Unauthorized", | ||||
|     "unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.", | ||||
|     "unauthorizedResourceSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to login.", | ||||
|     "unauthorizedButton": "Try again" | ||||
| } | ||||
| @@ -6,6 +6,7 @@ | ||||
|     "loginSubmit": "Login", | ||||
|     "loginFailTitle": "Failed to log in", | ||||
|     "loginFailSubtitle": "Please check your username and password", | ||||
|     "loginFailRateLimit": "You failed to login too many times, please try again later", | ||||
|     "loginSuccessTitle": "Logged in", | ||||
|     "loginSuccessSubtitle": "Welcome back!", | ||||
|     "loginOauthFailTitle": "Internal error", | ||||
| @@ -39,7 +40,7 @@ | ||||
|     "totpSuccessSubtitle": "Redirecting to your app", | ||||
|     "totpTitle": "Enter your TOTP code", | ||||
|     "unauthorizedTitle": "Unauthorized", | ||||
|     "unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.", | ||||
|     "unauthorizedResourceSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to login.", | ||||
|     "unauthorizedButton": "Try again" | ||||
| } | ||||
| @@ -6,6 +6,7 @@ | ||||
|     "loginSubmit": "Login", | ||||
|     "loginFailTitle": "Failed to log in", | ||||
|     "loginFailSubtitle": "Please check your username and password", | ||||
|     "loginFailRateLimit": "You failed to login too many times, please try again later", | ||||
|     "loginSuccessTitle": "Logged in", | ||||
|     "loginSuccessSubtitle": "Welcome back!", | ||||
|     "loginOauthFailTitle": "Internal error", | ||||
| @@ -39,7 +40,7 @@ | ||||
|     "totpSuccessSubtitle": "Redirecting to your app", | ||||
|     "totpTitle": "Enter your TOTP code", | ||||
|     "unauthorizedTitle": "Unauthorized", | ||||
|     "unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.", | ||||
|     "unauthorizedResourceSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to login.", | ||||
|     "unauthorizedButton": "Try again" | ||||
| } | ||||
| @@ -6,6 +6,7 @@ | ||||
|     "loginSubmit": "Login", | ||||
|     "loginFailTitle": "Failed to log in", | ||||
|     "loginFailSubtitle": "Please check your username and password", | ||||
|     "loginFailRateLimit": "You failed to login too many times, please try again later", | ||||
|     "loginSuccessTitle": "Logged in", | ||||
|     "loginSuccessSubtitle": "Welcome back!", | ||||
|     "loginOauthFailTitle": "Internal error", | ||||
| @@ -39,7 +40,7 @@ | ||||
|     "totpSuccessSubtitle": "Redirecting to your app", | ||||
|     "totpTitle": "Enter your TOTP code", | ||||
|     "unauthorizedTitle": "Unauthorized", | ||||
|     "unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.", | ||||
|     "unauthorizedResourceSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to login.", | ||||
|     "unauthorizedButton": "Try again" | ||||
| } | ||||
| @@ -6,6 +6,7 @@ | ||||
|     "loginSubmit": "Login", | ||||
|     "loginFailTitle": "Failed to log in", | ||||
|     "loginFailSubtitle": "Please check your username and password", | ||||
|     "loginFailRateLimit": "You failed to login too many times, please try again later", | ||||
|     "loginSuccessTitle": "Logged in", | ||||
|     "loginSuccessSubtitle": "Welcome back!", | ||||
|     "loginOauthFailTitle": "Internal error", | ||||
| @@ -39,7 +40,7 @@ | ||||
|     "totpSuccessSubtitle": "Redirecting to your app", | ||||
|     "totpTitle": "Enter your TOTP code", | ||||
|     "unauthorizedTitle": "Unauthorized", | ||||
|     "unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.", | ||||
|     "unauthorizedResourceSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to login.", | ||||
|     "unauthorizedButton": "Try again" | ||||
| } | ||||
| @@ -6,6 +6,7 @@ | ||||
|     "loginSubmit": "Login", | ||||
|     "loginFailTitle": "Failed to log in", | ||||
|     "loginFailSubtitle": "Please check your username and password", | ||||
|     "loginFailRateLimit": "You failed to login too many times, please try again later", | ||||
|     "loginSuccessTitle": "Logged in", | ||||
|     "loginSuccessSubtitle": "Welcome back!", | ||||
|     "loginOauthFailTitle": "Internal error", | ||||
| @@ -39,7 +40,7 @@ | ||||
|     "totpSuccessSubtitle": "Redirecting to your app", | ||||
|     "totpTitle": "Enter your TOTP code", | ||||
|     "unauthorizedTitle": "Unauthorized", | ||||
|     "unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.", | ||||
|     "unauthorizedResourceSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to access the resource <Code>{{resource}}</Code>.", | ||||
|     "unaothorizedLoginSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to login.", | ||||
|     "unauthorizedButton": "Try again" | ||||
| } | ||||
| @@ -29,7 +29,7 @@ const queryClient = new QueryClient({ | ||||
|  | ||||
| createRoot(document.getElementById("root")!).render( | ||||
|   <StrictMode> | ||||
|     <MantineProvider forceColorScheme="dark"> | ||||
|     <MantineProvider defaultColorScheme="auto"> | ||||
|       <QueryClientProvider client={queryClient}> | ||||
|         <Notifications /> | ||||
|         <AppContextProvider> | ||||
|   | ||||
| @@ -37,6 +37,7 @@ export const UnauthorizedPage = () => { | ||||
|               <Trans | ||||
|                 i18nKey="unauthorizedLoginSubtitle" | ||||
|                 t={t} | ||||
|                 components={{ Code: <Code /> }} | ||||
|                 values={{ username }} | ||||
|               /> | ||||
|             </Text> | ||||
|   | ||||
| @@ -1 +1 @@ | ||||
| v3.2.0 | ||||
| v3.2.1 | ||||
| @@ -298,6 +298,8 @@ func (auth *Auth) ResourceAllowed(c *gin.Context, context types.UserContext) (bo | ||||
| 		if slices.Contains(labels.Users, context.Username) { | ||||
| 			return true, nil | ||||
| 		} | ||||
| 	} else { | ||||
| 		return true, nil | ||||
| 	} | ||||
|  | ||||
| 	// Not allowed | ||||
|   | ||||
| @@ -2,7 +2,6 @@ package handlers | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"math/rand/v2" | ||||
| 	"net/http" | ||||
| 	"strings" | ||||
| 	"tinyauth/internal/auth" | ||||
| @@ -531,32 +530,6 @@ func (h *Handlers) OauthUrlHandler(c *gin.Context) { | ||||
| 		}) | ||||
| 	} | ||||
|  | ||||
| 	// Tailscale does not have an auth url so we create a random code (does not need to be secure) to avoid caching and send it | ||||
| 	if request.Provider == "tailscale" { | ||||
| 		// Build tailscale query | ||||
| 		queries, err := query.Values(types.TailscaleQuery{ | ||||
| 			Code: (1000 + rand.IntN(9000)), | ||||
| 		}) | ||||
|  | ||||
| 		// Handle error | ||||
| 		if err != nil { | ||||
| 			log.Error().Err(err).Msg("Failed to build queries") | ||||
| 			c.JSON(500, gin.H{ | ||||
| 				"status":  500, | ||||
| 				"message": "Internal Server Error", | ||||
| 			}) | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		// Return tailscale URL (immidiately redirects to the callback) | ||||
| 		c.JSON(200, gin.H{ | ||||
| 			"status":  200, | ||||
| 			"message": "OK", | ||||
| 			"url":     fmt.Sprintf("%s/api/oauth/callback/tailscale?%s", h.Config.AppURL, queries.Encode()), | ||||
| 		}) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// Return auth URL | ||||
| 	c.JSON(200, gin.H{ | ||||
| 		"status":  200, | ||||
|   | ||||
| @@ -17,11 +17,10 @@ func NewProviders(config types.OAuthConfig) *Providers { | ||||
| } | ||||
|  | ||||
| type Providers struct { | ||||
| 	Config    types.OAuthConfig | ||||
| 	Github    *oauth.OAuth | ||||
| 	Google    *oauth.OAuth | ||||
| 	Tailscale *oauth.OAuth | ||||
| 	Generic   *oauth.OAuth | ||||
| 	Config  types.OAuthConfig | ||||
| 	Github  *oauth.OAuth | ||||
| 	Google  *oauth.OAuth | ||||
| 	Generic *oauth.OAuth | ||||
| } | ||||
|  | ||||
| func (providers *Providers) Init() { | ||||
| @@ -59,22 +58,6 @@ func (providers *Providers) Init() { | ||||
| 		providers.Google.Init() | ||||
| 	} | ||||
|  | ||||
| 	if providers.Config.TailscaleClientId != "" && providers.Config.TailscaleClientSecret != "" { | ||||
| 		log.Info().Msg("Initializing Tailscale OAuth") | ||||
|  | ||||
| 		// Create a new oauth provider with the tailscale config | ||||
| 		providers.Tailscale = oauth.NewOAuth(oauth2.Config{ | ||||
| 			ClientID:     providers.Config.TailscaleClientId, | ||||
| 			ClientSecret: providers.Config.TailscaleClientSecret, | ||||
| 			RedirectURL:  fmt.Sprintf("%s/api/oauth/callback/tailscale", providers.Config.AppURL), | ||||
| 			Scopes:       TailscaleScopes(), | ||||
| 			Endpoint:     TailscaleEndpoint, | ||||
| 		}) | ||||
|  | ||||
| 		// Initialize the oauth provider | ||||
| 		providers.Tailscale.Init() | ||||
| 	} | ||||
|  | ||||
| 	// If we have a client id and secret for generic oauth, initialize the oauth provider | ||||
| 	if providers.Config.GenericClientId != "" && providers.Config.GenericClientSecret != "" { | ||||
| 		log.Info().Msg("Initializing Generic OAuth") | ||||
| @@ -103,8 +86,6 @@ func (providers *Providers) GetProvider(provider string) *oauth.OAuth { | ||||
| 		return providers.Github | ||||
| 	case "google": | ||||
| 		return providers.Google | ||||
| 	case "tailscale": | ||||
| 		return providers.Tailscale | ||||
| 	case "generic": | ||||
| 		return providers.Generic | ||||
| 	default: | ||||
| @@ -161,30 +142,6 @@ func (providers *Providers) GetUser(provider string) (string, error) { | ||||
|  | ||||
| 		log.Debug().Msg("Got email from google") | ||||
|  | ||||
| 		// Return the email | ||||
| 		return email, nil | ||||
| 	case "tailscale": | ||||
| 		// If the tailscale provider is not configured, return an error | ||||
| 		if providers.Tailscale == nil { | ||||
| 			log.Debug().Msg("Tailscale provider not configured") | ||||
| 			return "", nil | ||||
| 		} | ||||
|  | ||||
| 		// Get the client from the tailscale provider | ||||
| 		client := providers.Tailscale.GetClient() | ||||
|  | ||||
| 		log.Debug().Msg("Got client from tailscale") | ||||
|  | ||||
| 		// Get the email from the tailscale provider | ||||
| 		email, err := GetTailscaleEmail(client) | ||||
|  | ||||
| 		// Check if there was an error | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
|  | ||||
| 		log.Debug().Msg("Got email from tailscale") | ||||
|  | ||||
| 		// Return the email | ||||
| 		return email, nil | ||||
| 	case "generic": | ||||
| @@ -225,9 +182,6 @@ func (provider *Providers) GetConfiguredProviders() []string { | ||||
| 	if provider.Google != nil { | ||||
| 		providers = append(providers, "google") | ||||
| 	} | ||||
| 	if provider.Tailscale != nil { | ||||
| 		providers = append(providers, "tailscale") | ||||
| 	} | ||||
| 	if provider.Generic != nil { | ||||
| 		providers = append(providers, "generic") | ||||
| 	} | ||||
|   | ||||
| @@ -1,68 +0,0 @@ | ||||
| package providers | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
|  | ||||
| 	"github.com/rs/zerolog/log" | ||||
| 	"golang.org/x/oauth2" | ||||
| ) | ||||
|  | ||||
| // The tailscale email is the loginName | ||||
| type TailscaleUser struct { | ||||
| 	LoginName string `json:"loginName"` | ||||
| } | ||||
|  | ||||
| // The response from the tailscale user info endpoint | ||||
| type TailscaleUserInfoResponse struct { | ||||
| 	Users []TailscaleUser `json:"users"` | ||||
| } | ||||
|  | ||||
| // The scopes required for the tailscale provider | ||||
| func TailscaleScopes() []string { | ||||
| 	return []string{"users:read"} | ||||
| } | ||||
|  | ||||
| // The tailscale endpoint | ||||
| var TailscaleEndpoint = oauth2.Endpoint{ | ||||
| 	TokenURL: "https://api.tailscale.com/api/v2/oauth/token", | ||||
| } | ||||
|  | ||||
| func GetTailscaleEmail(client *http.Client) (string, error) { | ||||
| 	// Get the user info from tailscale using the oauth http client | ||||
| 	res, err := client.Get("https://api.tailscale.com/api/v2/tailnet/-/users") | ||||
|  | ||||
| 	// Check if there was an error | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	log.Debug().Msg("Got response from tailscale") | ||||
|  | ||||
| 	// Read the body of the response | ||||
| 	body, err := io.ReadAll(res.Body) | ||||
|  | ||||
| 	// Check if there was an error | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	log.Debug().Msg("Read body from tailscale") | ||||
|  | ||||
| 	// Parse the body into a user struct | ||||
| 	var users TailscaleUserInfoResponse | ||||
|  | ||||
| 	// Unmarshal the body into the user struct | ||||
| 	err = json.Unmarshal(body, &users) | ||||
|  | ||||
| 	// Check if there was an error | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	log.Debug().Msg("Parsed users from tailscale") | ||||
|  | ||||
| 	// Return the email of the first user | ||||
| 	return users.Users[0].LoginName, nil | ||||
| } | ||||
| @@ -22,11 +22,6 @@ type UnauthorizedQuery struct { | ||||
| 	Resource string `url:"resource"` | ||||
| } | ||||
|  | ||||
| // TailscaleQuery is the query parameters for the tailscale endpoint | ||||
| type TailscaleQuery struct { | ||||
| 	Code int `url:"code"` | ||||
| } | ||||
|  | ||||
| // Proxy is the uri parameters for the proxy endpoint | ||||
| type Proxy struct { | ||||
| 	Proxy string `uri:"proxy" binding:"required"` | ||||
|   | ||||
| @@ -2,39 +2,36 @@ package types | ||||
|  | ||||
| // Config is the configuration for the tinyauth server | ||||
| type Config struct { | ||||
| 	Port                      int    `mapstructure:"port" validate:"required"` | ||||
| 	Address                   string `validate:"required,ip4_addr" mapstructure:"address"` | ||||
| 	Secret                    string `validate:"required,len=32" mapstructure:"secret"` | ||||
| 	SecretFile                string `mapstructure:"secret-file"` | ||||
| 	AppURL                    string `validate:"required,url" mapstructure:"app-url"` | ||||
| 	Users                     string `mapstructure:"users"` | ||||
| 	UsersFile                 string `mapstructure:"users-file"` | ||||
| 	CookieSecure              bool   `mapstructure:"cookie-secure"` | ||||
| 	GithubClientId            string `mapstructure:"github-client-id"` | ||||
| 	GithubClientSecret        string `mapstructure:"github-client-secret"` | ||||
| 	GithubClientSecretFile    string `mapstructure:"github-client-secret-file"` | ||||
| 	GoogleClientId            string `mapstructure:"google-client-id"` | ||||
| 	GoogleClientSecret        string `mapstructure:"google-client-secret"` | ||||
| 	GoogleClientSecretFile    string `mapstructure:"google-client-secret-file"` | ||||
| 	TailscaleClientId         string `mapstructure:"tailscale-client-id"` | ||||
| 	TailscaleClientSecret     string `mapstructure:"tailscale-client-secret"` | ||||
| 	TailscaleClientSecretFile string `mapstructure:"tailscale-client-secret-file"` | ||||
| 	GenericClientId           string `mapstructure:"generic-client-id"` | ||||
| 	GenericClientSecret       string `mapstructure:"generic-client-secret"` | ||||
| 	GenericClientSecretFile   string `mapstructure:"generic-client-secret-file"` | ||||
| 	GenericScopes             string `mapstructure:"generic-scopes"` | ||||
| 	GenericAuthURL            string `mapstructure:"generic-auth-url"` | ||||
| 	GenericTokenURL           string `mapstructure:"generic-token-url"` | ||||
| 	GenericUserURL            string `mapstructure:"generic-user-url"` | ||||
| 	GenericName               string `mapstructure:"generic-name"` | ||||
| 	DisableContinue           bool   `mapstructure:"disable-continue"` | ||||
| 	OAuthWhitelist            string `mapstructure:"oauth-whitelist"` | ||||
| 	SessionExpiry             int    `mapstructure:"session-expiry"` | ||||
| 	LogLevel                  int8   `mapstructure:"log-level" validate:"min=-1,max=5"` | ||||
| 	Title                     string `mapstructure:"app-title"` | ||||
| 	EnvFile                   string `mapstructure:"env-file"` | ||||
| 	LoginTimeout              int    `mapstructure:"login-timeout"` | ||||
| 	LoginMaxRetries           int    `mapstructure:"login-max-retries"` | ||||
| 	Port                    int    `mapstructure:"port" validate:"required"` | ||||
| 	Address                 string `validate:"required,ip4_addr" mapstructure:"address"` | ||||
| 	Secret                  string `validate:"required,len=32" mapstructure:"secret"` | ||||
| 	SecretFile              string `mapstructure:"secret-file"` | ||||
| 	AppURL                  string `validate:"required,url" mapstructure:"app-url"` | ||||
| 	Users                   string `mapstructure:"users"` | ||||
| 	UsersFile               string `mapstructure:"users-file"` | ||||
| 	CookieSecure            bool   `mapstructure:"cookie-secure"` | ||||
| 	GithubClientId          string `mapstructure:"github-client-id"` | ||||
| 	GithubClientSecret      string `mapstructure:"github-client-secret"` | ||||
| 	GithubClientSecretFile  string `mapstructure:"github-client-secret-file"` | ||||
| 	GoogleClientId          string `mapstructure:"google-client-id"` | ||||
| 	GoogleClientSecret      string `mapstructure:"google-client-secret"` | ||||
| 	GoogleClientSecretFile  string `mapstructure:"google-client-secret-file"` | ||||
| 	GenericClientId         string `mapstructure:"generic-client-id"` | ||||
| 	GenericClientSecret     string `mapstructure:"generic-client-secret"` | ||||
| 	GenericClientSecretFile string `mapstructure:"generic-client-secret-file"` | ||||
| 	GenericScopes           string `mapstructure:"generic-scopes"` | ||||
| 	GenericAuthURL          string `mapstructure:"generic-auth-url"` | ||||
| 	GenericTokenURL         string `mapstructure:"generic-token-url"` | ||||
| 	GenericUserURL          string `mapstructure:"generic-user-url"` | ||||
| 	GenericName             string `mapstructure:"generic-name"` | ||||
| 	DisableContinue         bool   `mapstructure:"disable-continue"` | ||||
| 	OAuthWhitelist          string `mapstructure:"oauth-whitelist"` | ||||
| 	SessionExpiry           int    `mapstructure:"session-expiry"` | ||||
| 	LogLevel                int8   `mapstructure:"log-level" validate:"min=-1,max=5"` | ||||
| 	Title                   string `mapstructure:"app-title"` | ||||
| 	EnvFile                 string `mapstructure:"env-file"` | ||||
| 	LoginTimeout            int    `mapstructure:"login-timeout"` | ||||
| 	LoginMaxRetries         int    `mapstructure:"login-max-retries"` | ||||
| } | ||||
|  | ||||
| // Server configuration | ||||
| @@ -47,19 +44,17 @@ type HandlersConfig struct { | ||||
|  | ||||
| // OAuthConfig is the configuration for the providers | ||||
| type OAuthConfig struct { | ||||
| 	GithubClientId        string | ||||
| 	GithubClientSecret    string | ||||
| 	GoogleClientId        string | ||||
| 	GoogleClientSecret    string | ||||
| 	TailscaleClientId     string | ||||
| 	TailscaleClientSecret string | ||||
| 	GenericClientId       string | ||||
| 	GenericClientSecret   string | ||||
| 	GenericScopes         []string | ||||
| 	GenericAuthURL        string | ||||
| 	GenericTokenURL       string | ||||
| 	GenericUserURL        string | ||||
| 	AppURL                string | ||||
| 	GithubClientId      string | ||||
| 	GithubClientSecret  string | ||||
| 	GoogleClientId      string | ||||
| 	GoogleClientSecret  string | ||||
| 	GenericClientId     string | ||||
| 	GenericClientSecret string | ||||
| 	GenericScopes       []string | ||||
| 	GenericAuthURL      string | ||||
| 	GenericTokenURL     string | ||||
| 	GenericUserURL      string | ||||
| 	AppURL              string | ||||
| } | ||||
|  | ||||
| // APIConfig is the configuration for the API | ||||
|   | ||||
| @@ -130,7 +130,7 @@ func GetSecret(conf string, file string) string { | ||||
| 	} | ||||
|  | ||||
| 	// Return the contents of the file | ||||
| 	return contents | ||||
| 	return ParseSecretFile(contents) | ||||
| } | ||||
|  | ||||
| // Get the users from the config or file | ||||
| @@ -213,7 +213,7 @@ func GetTinyauthLabels(labels map[string]string) types.TinyauthLabels { | ||||
|  | ||||
| // Check if any of the OAuth providers are configured based on the client id and secret | ||||
| func OAuthConfigured(config types.Config) bool { | ||||
| 	return (config.GithubClientId != "" && config.GithubClientSecret != "") || (config.GoogleClientId != "" && config.GoogleClientSecret != "") || (config.GenericClientId != "" && config.GenericClientSecret != "") || (config.TailscaleClientId != "" && config.TailscaleClientSecret != "") | ||||
| 	return (config.GithubClientId != "" && config.GithubClientSecret != "") || (config.GoogleClientId != "" && config.GoogleClientSecret != "") || (config.GenericClientId != "" && config.GenericClientSecret != "") | ||||
| } | ||||
|  | ||||
| // Filter helper function | ||||
| @@ -241,23 +241,21 @@ func ParseUser(user string) (types.User, error) { | ||||
| 		return types.User{}, errors.New("invalid user format") | ||||
| 	} | ||||
|  | ||||
| 	// Check if the user has a totp secret | ||||
| 	if len(userSplit) == 2 { | ||||
| 		// Check for empty username or password | ||||
| 		if userSplit[1] == "" || userSplit[0] == "" { | ||||
| 	// Check for empty strings | ||||
| 	for _, userPart := range userSplit { | ||||
| 		if strings.TrimSpace(userPart) == "" { | ||||
| 			return types.User{}, errors.New("invalid user format") | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Check if the user has a totp secret | ||||
| 	if len(userSplit) == 2 { | ||||
| 		return types.User{ | ||||
| 			Username: userSplit[0], | ||||
| 			Password: userSplit[1], | ||||
| 		}, nil | ||||
| 	} | ||||
|  | ||||
| 	// Check for empty username, password or totp secret | ||||
| 	if userSplit[2] == "" || userSplit[1] == "" || userSplit[0] == "" { | ||||
| 		return types.User{}, errors.New("invalid user format") | ||||
| 	} | ||||
|  | ||||
| 	// Return the user struct | ||||
| 	return types.User{ | ||||
| 		Username:   userSplit[0], | ||||
| @@ -265,3 +263,23 @@ func ParseUser(user string) (types.User, error) { | ||||
| 		TotpSecret: userSplit[2], | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // Parse secret file | ||||
| func ParseSecretFile(contents string) string { | ||||
| 	// Split to lines | ||||
| 	lines := strings.Split(contents, "\n") | ||||
|  | ||||
| 	// Loop through the lines | ||||
| 	for _, line := range lines { | ||||
| 		// Check if the line is empty | ||||
| 		if strings.TrimSpace(line) == "" { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		// Return the line | ||||
| 		return strings.TrimSpace(line) | ||||
| 	} | ||||
|  | ||||
| 	// Return an empty string | ||||
| 	return "" | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| package utils_test | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"reflect" | ||||
| 	"testing" | ||||
| @@ -123,7 +124,7 @@ func TestGetSecret(t *testing.T) { | ||||
| 	expected := "test" | ||||
|  | ||||
| 	// Create file | ||||
| 	err := os.WriteFile(file, []byte(expected), 0644) | ||||
| 	err := os.WriteFile(file, []byte(fmt.Sprintf("\n\n    \n\n\n  %s   \n\n    \n  ", expected)), 0644) | ||||
|  | ||||
| 	// Check if there was an error | ||||
| 	if err != nil { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user