Compare commits

..
Author SHA1 Message Date
Stavros 39541e9a26 New translations en.json (Catalan)
[ci skip]
2026-09-06 04:52:11 +03:00
Stavros 9d03b1e907 New translations en.json (Catalan)
[ci skip]
2026-09-06 03:50:48 +03:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
b61fc6b54e chore(deps): bump the minor-patch group across 1 directory with 3 updates (#1116)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-03 12:15:04 +03:00
StavrosandGitHub bbcc8cafa6 feat: add backoff to docker connection for proxies (#1114) 2026-09-03 12:14:30 +03:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Stavros
b63a6917fe chore(deps): bump softprops/action-gh-release from 3.0.2 to 3.0.3 (#1111)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Stavros <steveiliop56@gmail.com>
2026-09-01 16:08:10 +03:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
59116f7344 chore(deps): bump the minor-patch group in /frontend with 3 updates (#1112)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-01 16:07:18 +03:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
97eb1efb0e chore(deps): bump node from 26.7-alpine3.23 to 26.8-alpine3.23 (#1106)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-01 16:06:58 +03:00
Stavros 1112d84667 fix: use retries in e2e tests and increase timeouts 2026-09-01 16:04:04 +03:00
StavrosandGitHub b01f49cc44 refactor: use optimized image for background (#1110) 2026-09-01 00:18:35 +03:00
16 changed files with 211 additions and 155 deletions
+1 -1
View File
@@ -204,7 +204,7 @@ TINYAUTH_UI_TITLE="Tinyauth"
# Message displayed on the forgot password page.
TINYAUTH_UI_FORGOTPASSWORDMESSAGE="You can change your password by changing the configuration."
# Path to the background image.
TINYAUTH_UI_BACKGROUNDIMAGE="/background.jpg"
TINYAUTH_UI_BACKGROUNDIMAGE="/background.webp"
# Enable UI warnings.
TINYAUTH_UI_WARNINGSENABLED=true
+2 -2
View File
@@ -23,7 +23,7 @@ jobs:
REPO: ${{ github.event.repository.name }}
- name: Create release
uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3
uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3.0.3
with:
prerelease: true
tag_name: nightly
@@ -476,7 +476,7 @@ jobs:
merge-multiple: true
- name: Release
uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3
uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3.0.3
with:
files: binaries/*
tag_name: nightly
+1 -1
View File
@@ -449,6 +449,6 @@ jobs:
merge-multiple: true
- name: Release
uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3
uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3.0.3
with:
files: binaries/*
+1 -1
View File
@@ -1,5 +1,5 @@
# Site builder
FROM node:26.7-alpine3.23 AS frontend-builder
FROM node:26.8-alpine3.23 AS frontend-builder
WORKDIR /frontend
+1 -1
View File
@@ -1,5 +1,5 @@
# Site builder
FROM node:26.7-alpine3.23 AS frontend-builder
FROM node:26.8-alpine3.23 AS frontend-builder
WORKDIR /frontend
+1 -1
View File
@@ -87,4 +87,4 @@ A huge thank you to [selfh.st](https://selfh.st) for their generous donation to
- **Freepik** for providing the police hat and badge.
- **Renee French** for the original gopher logo.
- **Syrhu** for providing the background image of the app.
- [Siru Zhou](https://unsplash.com/@syrhu) for providing the background image of the app.
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

+5 -1
View File
@@ -4,9 +4,13 @@ export default defineConfig({
testDir: './specs',
fullyParallel: true,
forbidOnly: false,
retries: 0,
retries: 3,
workers: 4,
reporter: 'html',
timeout: 60_000,
expect: {
timeout: 10_000,
},
use: {
trace: 'on-first-retry',
video: 'on',
+4 -4
View File
@@ -26,19 +26,19 @@
"i18next": "^26.4.0",
"i18next-browser-languagedetector": "^8.2.1",
"i18next-resources-to-backend": "^1.2.3",
"lucide-react": "^1.35.0",
"lucide-react": "^1.38.0",
"next-themes": "^0.4.6",
"radix-ui": "^1.6.7",
"react": "^19.2.8",
"react-dom": "^19.2.8",
"react-hook-form": "^7.86.0",
"react-hook-form": "^7.87.0",
"react-i18next": "^17.0.12",
"react-markdown": "^10.1.0",
"react-router": "^8.3.0",
"react-router": "^8.3.1",
"sonner": "^2.0.8",
"tailwind-merge": "^3.5.0",
"tailwindcss": "^4.3.3",
"zod": "^4.3.6"
"zod": "^4.5.4"
},
"devDependencies": {
"@eslint/js": "^10.0.1",
+28 -28
View File
@@ -10,7 +10,7 @@ importers:
dependencies:
'@hookform/resolvers':
specifier: ^5.9.1
version: 5.9.1(react-hook-form@7.86.0(react@19.2.8))(zod@4.4.3)
version: 5.9.1(react-hook-form@7.87.0(react@19.2.8))(zod@4.5.4)
'@radix-ui/react-dropdown-menu':
specifier: ^2.1.24
version: 2.1.24(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
@@ -51,8 +51,8 @@ importers:
specifier: ^1.2.3
version: 1.2.3
lucide-react:
specifier: ^1.35.0
version: 1.35.0(react@19.2.8)
specifier: ^1.38.0
version: 1.38.0(react@19.2.8)
next-themes:
specifier: ^0.4.6
version: 0.4.6(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
@@ -66,8 +66,8 @@ importers:
specifier: ^19.2.8
version: 19.2.8(react@19.2.8)
react-hook-form:
specifier: ^7.86.0
version: 7.86.0(react@19.2.8)
specifier: ^7.87.0
version: 7.87.0(react@19.2.8)
react-i18next:
specifier: ^17.0.12
version: 17.0.12(i18next@26.4.0(typescript@6.0.3))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(typescript@6.0.3)
@@ -75,8 +75,8 @@ importers:
specifier: ^10.1.0
version: 10.1.0(@types/react@19.2.18)(react@19.2.8)
react-router:
specifier: ^8.3.0
version: 8.3.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
specifier: ^8.3.1
version: 8.3.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
sonner:
specifier: ^2.0.8
version: 2.0.8(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
@@ -87,8 +87,8 @@ importers:
specifier: ^4.3.3
version: 4.3.3
zod:
specifier: ^4.3.6
version: 4.4.3
specifier: ^4.5.4
version: 4.5.4
devDependencies:
'@eslint/js':
specifier: ^10.0.1
@@ -2053,8 +2053,8 @@ packages:
lru-cache@5.1.1:
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
lucide-react@1.35.0:
resolution: {integrity: sha512-yXCCWxGFYT6bLIPYC4SY6fPQPRs/d797rRIue+J9XP2Td6vQvD53gaQRBCnIVT1kTQRHtAtxlfOQNWAuIF8ELg==}
lucide-react@1.38.0:
resolution: {integrity: sha512-xZCyBd/wiVUDactoCc+42TjL0aB7EBOXsuX+tjz+W/sGzw2KhHpL1NOH3FIaVUcpimvUBpIYfz34Ofj9S5JEzQ==}
peerDependencies:
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
@@ -2263,8 +2263,8 @@ packages:
peerDependencies:
react: ^19.2.8
react-hook-form@7.86.0:
resolution: {integrity: sha512-4kbWJrh5jPZt1+YqVcXcGKffGcXV/XVbozknLh0Yjh0KhpoAkus21TAQhzRYqNwFkkObmnSvRlZZ3GT+ehoIrA==}
react-hook-form@7.87.0:
resolution: {integrity: sha512-zhFzWvLxNHH+8839OnZcUxgMZw88ah2jZWDWvKWgF3Tpbnd0vKL+dlcuU3nZVWESZQjd81EW8K+wU+cYfYAc0w==}
engines: {node: '>=18.0.0'}
peerDependencies:
react: ^16.8.0 || ^17 || ^18 || ^19
@@ -2311,8 +2311,8 @@ packages:
'@types/react':
optional: true
react-router@8.3.0:
resolution: {integrity: sha512-qyPMvW83jGIct3yiieisxdk9M745anqhpIMKN5m1t6yBMfgVPpt77aHOqs5fUlEJRMCGffg9BaQLH9oPVOL7xQ==}
react-router@8.3.1:
resolution: {integrity: sha512-TEOpiO2g0TJHEOJeRVv4amUFun9v1npCKszvcquNvzETUtJ8udV86ah5eFoHT7g26bsBvT6EiIhqulR8eDF++A==}
engines: {node: '>=22.22.0'}
peerDependencies:
react: '>=19.2.7'
@@ -2619,8 +2619,8 @@ packages:
peerDependencies:
zod: ^3.25.0 || ^4.0.0
zod@4.4.3:
resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==}
zod@4.5.4:
resolution: {integrity: sha512-sC95tT5iHHH9gtpj6A81kh+NEaRAUFN+qlUPDUbRfOMvNf5QCBqsb3WgvnpVtK5Y+4UfA6KqufotuTvMGiTlsA==}
zwitch@2.0.4:
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
@@ -2782,12 +2782,12 @@ snapshots:
'@floating-ui/utils@0.2.12': {}
'@hookform/resolvers@5.9.1(react-hook-form@7.86.0(react@19.2.8))(zod@4.4.3)':
'@hookform/resolvers@5.9.1(react-hook-form@7.87.0(react@19.2.8))(zod@4.5.4)':
dependencies:
'@standard-schema/utils': 0.3.0
react-hook-form: 7.86.0(react@19.2.8)
react-hook-form: 7.87.0(react@19.2.8)
optionalDependencies:
zod: 4.4.3
zod: 4.5.4
'@humanfs/core@0.19.2':
dependencies:
@@ -4023,8 +4023,8 @@ snapshots:
'@babel/parser': 7.29.3
eslint: 10.9.1(jiti@2.7.0)
hermes-parser: 0.25.1
zod: 4.4.3
zod-validation-error: 4.0.2(zod@4.4.3)
zod: 4.5.4
zod-validation-error: 4.0.2(zod@4.5.4)
transitivePeerDependencies:
- supports-color
@@ -4414,7 +4414,7 @@ snapshots:
dependencies:
yallist: 3.1.1
lucide-react@1.35.0(react@19.2.8):
lucide-react@1.38.0(react@19.2.8):
dependencies:
react: 19.2.8
@@ -4799,7 +4799,7 @@ snapshots:
react: 19.2.8
scheduler: 0.27.0
react-hook-form@7.86.0(react@19.2.8):
react-hook-form@7.87.0(react@19.2.8):
dependencies:
react: 19.2.8
@@ -4851,7 +4851,7 @@ snapshots:
optionalDependencies:
'@types/react': 19.2.18
react-router@8.3.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8):
react-router@8.3.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8):
dependencies:
cookie-es: 3.1.1
react: 19.2.8
@@ -5130,10 +5130,10 @@ snapshots:
yocto-queue@0.1.0: {}
zod-validation-error@4.0.2(zod@4.4.3):
zod-validation-error@4.0.2(zod@4.5.4):
dependencies:
zod: 4.4.3
zod: 4.5.4
zod@4.4.3: {}
zod@4.5.4: {}
zwitch@2.0.4: {}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 530 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 KiB

+98 -98
View File
@@ -1,104 +1,104 @@
{
"loginTitle": "Welcome back, login with",
"loginTitleSimple": "Welcome back, please login",
"loginDivider": "Or",
"loginUsername": "Username",
"loginPassword": "Password",
"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": "An error occurred",
"loginOauthFailSubtitle": "Failed to get OAuth URL",
"loginOauthSuccessTitle": "Redirecting",
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
"loginOauthAutoRedirectTitle": "OAuth Auto Redirect",
"loginOauthAutoRedirectSubtitle": "You will be automatically redirected to your OAuth provider to authenticate.",
"loginOauthAutoRedirectButton": "Redirect now",
"continueTitle": "Continue",
"continueRedirectingTitle": "Redirecting...",
"continueRedirectingSubtitle": "You should be redirected to the app soon",
"continueRedirectManually": "Redirect me manually",
"continueInsecureRedirectTitle": "Insecure redirect",
"continueInsecureRedirectSubtitle": "You are trying to redirect from <code>https</code> to <code>http</code> which is not secure. Are you sure you want to continue?",
"continueUntrustedRedirectTitle": "Untrusted redirect",
"continueUntrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{cookieDomain}}</code>). Are you sure you want to continue?",
"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",
"totpSubtitle": "Please enter the code from your authenticator app.",
"unauthorizedTitle": "Unauthorized",
"unauthorizedResourceSubtitle": "The user with username <code>{{username}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
"unauthorizedLoginSubtitle": "The user with username <code>{{username}}</code> is not authorized to login.",
"unauthorizedGroupsSubtitle": "The user with username <code>{{username}}</code> is not in the groups required by the resource <code>{{resource}}</code>.",
"unauthorizedIpSubtitle": "Your IP address <code>{{ip}}</code> is not authorized to access the resource <code>{{resource}}</code>.",
"unauthorizedButton": "Try again",
"cancelTitle": "Cancel",
"forgotPasswordTitle": "Forgot your password?",
"failedToFetchProvidersTitle": "Failed to load authentication providers. Please check your configuration.",
"errorTitle": "An error occurred",
"errorSubtitleInfo": "The following error occurred while processing your request:",
"loginTitle": "Benvingut de nou, inicieu la sessió amb",
"loginTitleSimple": "Benvingut de nou, si us plau, inicieu sessió",
"loginDivider": "O",
"loginUsername": "Nom dusuari",
"loginPassword": "Contrasenya",
"loginSubmit": "Iniciar sessió",
"loginFailTitle": "No s'ha pogut iniciar sessió",
"loginFailSubtitle": "Si us plau, comproveu el vostre nom d'usuari i contrasenya",
"loginFailRateLimit": "Heu fallat en iniciar sessió massa vegades. Si us plau, proveu-ho més tard",
"loginSuccessTitle": "Heu iniciat sessió",
"loginSuccessSubtitle": "Benvingut de nou!",
"loginOauthFailTitle": "S'ha produït un error",
"loginOauthFailSubtitle": "Errada en obtenir l'URL OAuth",
"loginOauthSuccessTitle": "Redirigint",
"loginOauthSuccessSubtitle": "Redirigint al vostre proveïdor OAuth",
"loginOauthAutoRedirectTitle": "Autoredirecció OAuth",
"loginOauthAutoRedirectSubtitle": "Sereu automàticament redirigits al vostre proveïdor OAuth per a autenticar-vos.",
"loginOauthAutoRedirectButton": "Redirigeix ara",
"continueTitle": "Continuar",
"continueRedirectingTitle": "S'està redirigint...",
"continueRedirectingSubtitle": "Hauríeu de ser redirigits aviat a l'app",
"continueRedirectManually": "Redirigiu-me manualment",
"continueInsecureRedirectTitle": "Redirecció no segura",
"continueInsecureRedirectSubtitle": "Esteu intentant redirigir des de <code>https</code>a<code>http</code> que no és segur. Esteu segurs de voler continuar?",
"continueUntrustedRedirectTitle": "Redirecció no confiable",
"continueUntrustedRedirectSubtitle": "Esteu intentant redirigir a un domini que no coincideix amb el vostre domini (<code>{{cookieDomain}}</code>). Esteu segurs de voler continuar?",
"logoutFailTitle": "Errada en tancar la sessió",
"logoutFailSubtitle": "Si us plau, torneu-ho a provar",
"logoutSuccessTitle": "Sessió tancada",
"logoutSuccessSubtitle": "S'ha tancat la sessió",
"logoutTitle": "Tanca la sessió",
"logoutUsernameSubtitle": "Heu iniciat sessió com a <code>{{username}}</code>. Cliqueu el botó de sota per a tancar la sessió.",
"logoutOauthSubtitle": "Heu iniciat la sessió actualment com a <code>{{username}}</code> fent servir {{provider}} com a proveïdor OAuth. Cliqueu el botó de sota per a tancar la sessió.",
"notFoundTitle": "Pàgina no trobada",
"notFoundSubtitle": "La pàgina que cerques no existeix.",
"notFoundButton": "Torna a l'inici",
"totpFailTitle": "Errada en verificar el codi",
"totpFailSubtitle": "Si us plau, comprova el codi i torna-ho a provar",
"totpSuccessTitle": "Verificat",
"totpSuccessSubtitle": "Redirigint a la teva app",
"totpTitle": "Introdueixi el codi TOTP",
"totpSubtitle": "Si us plau, introdueix el codi de la teva aplicació d'autenticació.",
"unauthorizedTitle": "No autoritzat",
"unauthorizedResourceSubtitle": "L'usuari amb el nom <code>{{username}}</code> no està autoritzat a accedir al recurs <code>{{resource}}</code>.",
"unauthorizedLoginSubtitle": "L'usuari amb el nom <code>{{username}}</code> no està autoritzat a iniciar la sessió.",
"unauthorizedGroupsSubtitle": "L'usuari amb el nom <code>{{username}}</code> no està als grups requerits per al recurs <code>{{resource}}</code>.",
"unauthorizedIpSubtitle": "La vostra adreça IP <code>{{ip}}</code> no està autoritzada a accedir al recurs <code>{{resource}}</code>.",
"unauthorizedButton": "Tornar-ho a provar",
"cancelTitle": "Cancel·lar",
"forgotPasswordTitle": "Heu oblidat la vostra contrasenya?",
"failedToFetchProvidersTitle": "Errada en carregar els proveïdors d'autenticació. Si us plau, verifiqueu la vostra configuració.",
"errorTitle": "S'ha produït un error",
"errorSubtitleInfo": "Ha ocorregut l'error següent mentre es processava la vostra petició:",
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
"forgotPasswordMessage": "You can reset your password by changing the `USERS` environment variable.",
"fieldRequired": "This field is required",
"invalidInput": "Invalid input",
"domainWarningTitle": "Invalid Domain",
"domainWarningSubtitle": "You are accessing this instance from an incorrect domain. If you proceed, you may encounter issues with authentication.",
"domainWarningCurrent": "Current:",
"domainWarningExpected": "Expected:",
"ignoreTitle": "Ignore",
"goToCorrectDomainTitle": "Go to correct domain",
"authorizeTitle": "Authorize",
"authorizeCardTitle": "Continue to {{app}}?",
"authorizeSubtitle": "Would you like to continue to this app? Please carefully review the permissions requested by the app.",
"authorizeSubtitleOAuth": "Would you like to continue to this app?",
"authorizeLoadingTitle": "Loading...",
"authorizeLoadingSubtitle": "Please wait while we load the client information.",
"authorizeSuccessTitle": "Authorized",
"authorizeSuccessSubtitle": "You will be redirected to the app in a few seconds.",
"authorizeErrorClientInfo": "An error occurred while loading the client information. Please try again later.",
"authorizeErrorInvalidParams": "The request is missing required parameters or has invalid parameters. Please check the URL and try again.",
"forgotPasswordMessage": "Podeu reiniciar la vostra contrasenya canviant la variable d'entorn `USERS`.",
"fieldRequired": "Aquest camp és obligatori",
"invalidInput": "Entrada no vàlida",
"domainWarningTitle": "Domini invàlid",
"domainWarningSubtitle": "Esteu visitant aquesta instància des d'un domini incorrecte. Si procediu, podríeu trobar-os amb problemes d'autenticació.",
"domainWarningCurrent": "Actual:",
"domainWarningExpected": "Esperat:",
"ignoreTitle": "Ignorar",
"goToCorrectDomainTitle": "Anar al domini correcte",
"authorizeTitle": "Autoritzar",
"authorizeCardTitle": "Continuar a {{app}}?",
"authorizeSubtitle": "Voldríeu continuar a aquesta app? Si us plau, reviseu amb cura els permisos sol·licitats per a l'app.",
"authorizeSubtitleOAuth": "Voldríeu continuar a aquesta app?",
"authorizeLoadingTitle": "S'està carregant...",
"authorizeLoadingSubtitle": "Si us plau, espereu mentre carreguem la informació del client.",
"authorizeSuccessTitle": "Autoritzat",
"authorizeSuccessSubtitle": "Sereu redirigits a l'app en pocs segons.",
"authorizeErrorClientInfo": "Ha ocorregut un error mentre es carregava la informació del client. Si us plau, proveu-ho més tard.",
"authorizeErrorInvalidParams": "La petició manca dels paràmetres requerits o té paràmetres invàlids. Si us plau, comproveu l'URL i torneu-ho a provar.",
"openidScopeName": "OpenID Connect",
"openidScopeDescription": "Allows the app to access your OpenID Connect information.",
"emailScopeName": "Email",
"emailScopeDescription": "Allows the app to access your email address.",
"profileScopeName": "Profile",
"profileScopeDescription": "Allows the app to access your profile information.",
"groupsScopeName": "Groups",
"groupsScopeDescription": "Allows the app to access your group information.",
"backToLoginButton": "Back to login",
"phoneScopeName": "Phone",
"phoneScopeDescription": "Allows the app to access your phone number.",
"addressScopeName": "Address",
"addressScopeDescription": "Allows the app to access your address.",
"loginTailscaleTitle": "Continue with Tailscale",
"loginTailscaleDescription": "You appear to be accessing Tinyauth from an authorized Tailscale device. Would you like to continue with your Tailscale connection?",
"loginTailscaleDeviceName": "Device name:",
"loginTailscaleOtherMethod": "Login with another method",
"loginTailscaleSuccess": "Successfully authenticated with Tailscale.",
"loginTailscaleFail": "Failed to authenticate with Tailscale. Please try again or use another login method.",
"logoutTailscaleSubtitle": "You are currently logged in with Tailscale on your device <code>{{deviceName}}</code>. Click the button below to logout.",
"quickActionsLanguage": "Language",
"quickActionsTheme": "Theme",
"quickActionsThemeLight": "Light",
"quickActionsThemeDark": "Dark",
"quickActionsThemeSystem": "System",
"quickActionsLogout": "Logout",
"quickActionsTitle": "Quick Actions",
"openidScopeDescription": "Permet a l'app l'accés a la vostra informació OpenID Connect.",
"emailScopeName": "Correu electrònic",
"emailScopeDescription": "Permet a l'app l'accés a la vostra adreça de correu electrònic.",
"profileScopeName": "Perfil",
"profileScopeDescription": "Permet a l'app l'accés a la vostra informació de perfil.",
"groupsScopeName": "Grups",
"groupsScopeDescription": "Permet a l'app l'accés la vostra informació de grup.",
"backToLoginButton": "Tornar a l'inici de sessió",
"phoneScopeName": "Telèfon",
"phoneScopeDescription": "Permet a l'app l'accés al vostre número de telèfon.",
"addressScopeName": "Adreça",
"addressScopeDescription": "Permet a l'app l'accés a la vostra adreça.",
"loginTailscaleTitle": "Continuar amb Tailscale",
"loginTailscaleDescription": "Sembla que esteu accedint a Tinyauth des d'un dispositiu Tailscale autoritzat. Voldríeu continuar amb la vostra connexió Tailscale?",
"loginTailscaleDeviceName": "Nom del dispositiu:",
"loginTailscaleOtherMethod": "Iniciar la sessió amb un altre mètode",
"loginTailscaleSuccess": "Autenticat correctament amb Tailscale.",
"loginTailscaleFail": "Errada en autentificar amb Tailscale. Si us plau, intenteu-ho una altra vegada o feu servir un altre mètode d'autenticació.",
"logoutTailscaleSubtitle": "Heu iniciat sessió actualment amb Tailscale en el vostre dispositiu <code>{{deviceName}}</code>. Cliqueu el botó de sota per a tancar la sessió.",
"quickActionsLanguage": "Idioma",
"quickActionsTheme": "Tema",
"quickActionsThemeLight": "Clar",
"quickActionsThemeDark": "Fosc",
"quickActionsThemeSystem": "Sistema",
"quickActionsLogout": "Sortir de la sessió",
"quickActionsTitle": "Accions ràpides",
"quickActionsProviderLocal": "Local",
"quickActionsProviderLDAP": "LDAP",
"quickActionsProviderOAuth": "{{provider}} OAuth"
+1 -1
View File
@@ -53,7 +53,7 @@ func NewDefaultConfiguration(runtimeEnv RuntimeEnv) *Config {
UI: UIConfig{
Title: "Tinyauth",
ForgotPasswordMessage: "You can change your password by changing the configuration.",
BackgroundImage: "/background.jpg",
BackgroundImage: "/background.webp",
WarningsEnabled: true,
},
LDAP: LDAPConfig{
+67 -15
View File
@@ -2,8 +2,12 @@ package service
import (
"context"
"errors"
"fmt"
"os"
"time"
"github.com/cenkalti/backoff/v5"
"github.com/steveiliop56/ding"
"github.com/tinyauthapp/tinyauth/internal/model"
"github.com/tinyauthapp/tinyauth/internal/utils/decoders"
@@ -14,6 +18,10 @@ import (
"github.com/docker/docker/client"
)
var (
ErrPingFailed = fmt.Errorf("failed to ping docker")
)
type DockerService struct {
log *logger.Logger
client *client.Client
@@ -31,26 +39,54 @@ type DockerServiceInput struct {
}
func NewDockerService(i DockerServiceInput) (*DockerService, error) {
client, err := client.NewClientWithOpts(client.FromEnv)
if err != nil {
return nil, err
}
client.NegotiateAPIVersion(i.Ctx)
_, err = client.Ping(i.Ctx)
if err != nil {
i.Log.App.Debug().Err(err).Msg("Docker not connected")
return nil, nil
}
service := &DockerService{
log: i.Log,
client: client,
context: i.Ctx,
}
service.log.App.Debug().Msg("Attempting to connect to Docker")
if os.Getenv("DOCKER_HOST") == "" {
cli, err := service.connect()
if err != nil {
if errors.Is(err, ErrPingFailed) {
service.log.App.Debug().Msg("Docker not connected")
return nil, nil
}
return nil, fmt.Errorf("failed to connect to docker: %w", err)
}
service.client = cli
} else {
exp := backoff.NewExponentialBackOff()
exp.InitialInterval = 3 * time.Second
exp.RandomizationFactor = 0.1
exp.Multiplier = 1.5
exp.Reset()
operation := func() (*client.Client, error) {
if service.client != nil {
service.client.Close()
}
cli, err := service.connect()
if err != nil {
return nil, err
}
return cli, nil
}
cli, err := backoff.Retry(service.context, operation, backoff.WithBackOff(exp), backoff.WithMaxTries(3))
if err != nil {
if errors.Is(err, ErrPingFailed) {
service.log.App.Debug().Msg("Docker not connected after retrying")
return nil, nil
}
return nil, fmt.Errorf("failed to connect to docker after retrying: %w", err)
}
service.client = cli
}
service.isConnected = true
service.log.App.Debug().Msg("Docker connected successfully")
@@ -59,6 +95,22 @@ func NewDockerService(i DockerServiceInput) (*DockerService, error) {
return service, nil
}
func (docker *DockerService) connect() (*client.Client, error) {
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
return nil, err
}
_, err = cli.Ping(docker.context)
if err != nil {
return nil, ErrPingFailed
}
return cli, nil
}
func (docker *DockerService) getContainers() ([]container.Summary, error) {
return docker.client.ContainerList(docker.context, container.ListOptions{})
}
+1 -1
View File
@@ -18,7 +18,7 @@ func CreateTestConfigs(t *testing.T) (model.Config, model.RuntimeConfig) {
UI: model.UIConfig{
Title: "Tinyauth Test",
ForgotPasswordMessage: "foo",
BackgroundImage: "/background.jpg",
BackgroundImage: "/background.webp",
WarningsEnabled: true,
},
OAuth: model.OAuthConfig{