Compare commits

..

4 Commits

Author SHA1 Message Date
Stavros
189ad7115a New translations en.json (Serbian (Cyrillic)) (#683) 2026-03-02 20:17:41 +02:00
Stavros
2f2556d480 fix: set correct paths in dockerfiles 2026-03-02 20:15:51 +02:00
Stavros
f1512f45b7 chore: update example env 2026-03-02 19:53:17 +02:00
Stavros
cd410b6cdf refactor: categorize leftover config options (#682)
* refactor: categorize leftover config options

* chore: update config description
2026-03-02 19:49:59 +02:00
15 changed files with 92 additions and 62 deletions

View File

@@ -4,14 +4,23 @@
# The base URL where the app is hosted. # The base URL where the app is hosted.
TINYAUTH_APPURL= TINYAUTH_APPURL=
# database config
# The path to the database, including file name.
TINYAUTH_DATABASE_PATH="./tinyauth.db"
# analytics config
# Enable periodic version information collection.
TINYAUTH_ANALYTICS_ENABLED=true
# resources config
# Enable the resources server.
TINYAUTH_RESOURCES_ENABLED=true
# The directory where resources are stored. # The directory where resources are stored.
TINYAUTH_RESOURCESDIR="./resources" TINYAUTH_RESOURCES_PATH="./resources"
# The path to the database file.
TINYAUTH_DATABASEPATH="./tinyauth.db"
# Disable analytics.
TINYAUTH_DISABLEANALYTICS=false
# Disable resources server.
TINYAUTH_DISABLERESOURCES=false
# server config # server config
@@ -107,9 +116,9 @@ TINYAUTH_OAUTH_PROVIDERS_name_NAME=
# oidc config # oidc config
# Path to the private key file. # Path to the private key file, including file name.
TINYAUTH_OIDC_PRIVATEKEYPATH="./tinyauth_oidc_key" TINYAUTH_OIDC_PRIVATEKEYPATH="./tinyauth_oidc_key"
# Path to the public key file. # Path to the public key file, including file name.
TINYAUTH_OIDC_PUBLICKEYPATH="./tinyauth_oidc_key.pub" TINYAUTH_OIDC_PUBLICKEYPATH="./tinyauth_oidc_key.pub"
# OIDC client ID. # OIDC client ID.
TINYAUTH_OIDC_CLIENTS_name_CLIENTID= TINYAUTH_OIDC_CLIENTS_name_CLIENTID=
@@ -130,8 +139,8 @@ TINYAUTH_UI_TITLE="Tinyauth"
TINYAUTH_UI_FORGOTPASSWORDMESSAGE="You can change your password by changing the configuration." TINYAUTH_UI_FORGOTPASSWORDMESSAGE="You can change your password by changing the configuration."
# Path to the background image. # Path to the background image.
TINYAUTH_UI_BACKGROUNDIMAGE="/background.jpg" TINYAUTH_UI_BACKGROUNDIMAGE="/background.jpg"
# Disable UI warnings. # Enable UI warnings.
TINYAUTH_UI_DISABLEWARNINGS=false TINYAUTH_UI_WARNINGSENABLED=true
# ldap config # ldap config

View File

@@ -57,9 +57,9 @@ EXPOSE 3000
VOLUME ["/data"] VOLUME ["/data"]
ENV TINYAUTH_DATABASEPATH=/data/tinyauth.db ENV TINYAUTH_DATABASE_PATH=/data/tinyauth.db
ENV TINYAUTH_RESOURCESDIR=/data/resources ENV TINYAUTH_RESOURCES_PATH=/data/resources
ENV PATH=$PATH:/tinyauth ENV PATH=$PATH:/tinyauth

View File

@@ -18,8 +18,8 @@ COPY ./air.toml ./
EXPOSE 3000 EXPOSE 3000
ENV TINYAUTH_DATABASEPATH=/data/tinyauth.db ENV TINYAUTH_DATABASE_PATH=/data/tinyauth.db
ENV TINYAUTH_RESOURCESDIR=/data/resources ENV TINYAUTH_RESOURCES_PATH=/data/resources
ENTRYPOINT ["air", "-c", "air.toml"] ENTRYPOINT ["air", "-c", "air.toml"]

View File

@@ -60,9 +60,9 @@ EXPOSE 3000
VOLUME ["/data"] VOLUME ["/data"]
ENV TINYAUTH_DATABASEPATH=/data/tinyauth.db ENV TINYAUTH_DATABASE_PATH=/data/tinyauth.db
ENV TINYAUTH_RESOURCESDIR=/data/resources ENV TINYAUTH_RESOURCES_PATH=/data/resources
ENV PATH=$PATH:/tinyauth ENV PATH=$PATH:/tinyauth

View File

@@ -31,7 +31,7 @@ const BaseLayout = ({ children }: { children: React.ReactNode }) => {
}; };
export const Layout = () => { export const Layout = () => {
const { appUrl, disableUiWarnings } = useAppContext(); const { appUrl, warningsEnabled } = useAppContext();
const [ignoreDomainWarning, setIgnoreDomainWarning] = useState(() => { const [ignoreDomainWarning, setIgnoreDomainWarning] = useState(() => {
return window.sessionStorage.getItem("ignoreDomainWarning") === "true"; return window.sessionStorage.getItem("ignoreDomainWarning") === "true";
}); });
@@ -42,7 +42,7 @@ export const Layout = () => {
setIgnoreDomainWarning(true); setIgnoreDomainWarning(true);
}, [setIgnoreDomainWarning]); }, [setIgnoreDomainWarning]);
if (!ignoreDomainWarning && !disableUiWarnings && appUrl !== currentUrl) { if (!ignoreDomainWarning && warningsEnabled && appUrl !== currentUrl) {
return ( return (
<BaseLayout> <BaseLayout>
<DomainWarning <DomainWarning

View File

@@ -58,8 +58,8 @@
"invalidInput": "Неисправан унос", "invalidInput": "Неисправан унос",
"domainWarningTitle": "Неисправан домен", "domainWarningTitle": "Неисправан домен",
"domainWarningSubtitle": "Ова инстанца је подешена да јој се приступа са <code>{{appUrl}}</code>, али се користи <code>{{currentUrl}}</code>. Ако наставите, можете искусити проблеме са аутентификацијом.", "domainWarningSubtitle": "Ова инстанца је подешена да јој се приступа са <code>{{appUrl}}</code>, али се користи <code>{{currentUrl}}</code>. Ако наставите, можете искусити проблеме са аутентификацијом.",
"domainWarningCurrent": "Current:", "domainWarningCurrent": "Тренутни:",
"domainWarningExpected": "Expected:", "domainWarningExpected": "Очекивани:",
"ignoreTitle": "Игнориши", "ignoreTitle": "Игнориши",
"goToCorrectDomainTitle": "Иди на исправан домен", "goToCorrectDomainTitle": "Иди на исправан домен",
"authorizeTitle": "Ауторизуј", "authorizeTitle": "Ауторизуј",

View File

@@ -14,7 +14,7 @@ import { useCallback, useEffect, useRef, useState } from "react";
import { useRedirectUri } from "@/lib/hooks/redirect-uri"; import { useRedirectUri } from "@/lib/hooks/redirect-uri";
export const ContinuePage = () => { export const ContinuePage = () => {
const { cookieDomain, disableUiWarnings } = useAppContext(); const { cookieDomain, warningsEnabled } = useAppContext();
const { isLoggedIn } = useUserContext(); const { isLoggedIn } = useUserContext();
const { search } = useLocation(); const { search } = useLocation();
const { t } = useTranslation(); const { t } = useTranslation();
@@ -35,10 +35,9 @@ export const ContinuePage = () => {
const urlHref = url?.href; const urlHref = url?.href;
const hasValidRedirect = valid && allowedProto; const hasValidRedirect = valid && allowedProto;
const showUntrustedWarning = const showUntrustedWarning = hasValidRedirect && !trusted && warningsEnabled;
hasValidRedirect && !trusted && !disableUiWarnings;
const showInsecureWarning = const showInsecureWarning =
hasValidRedirect && httpsDowngrade && !disableUiWarnings; hasValidRedirect && httpsDowngrade && warningsEnabled;
const shouldAutoRedirect = const shouldAutoRedirect =
isLoggedIn && isLoggedIn &&
hasValidRedirect && hasValidRedirect &&

View File

@@ -14,7 +14,7 @@ export const appContextSchema = z.object({
forgotPasswordMessage: z.string(), forgotPasswordMessage: z.string(),
backgroundImage: z.string(), backgroundImage: z.string(),
oauthAutoRedirect: z.string(), oauthAutoRedirect: z.string(),
disableUiWarnings: z.boolean(), warningsEnabled: z.boolean(),
}); });
export type AppContextSchema = z.infer<typeof appContextSchema>; export type AppContextSchema = z.infer<typeof appContextSchema>;

View File

@@ -124,7 +124,7 @@ func (app *BootstrapApp) Setup() error {
tlog.App.Trace().Str("redirectCookieName", app.context.redirectCookieName).Msg("Redirect cookie name") tlog.App.Trace().Str("redirectCookieName", app.context.redirectCookieName).Msg("Redirect cookie name")
// Database // Database
db, err := app.SetupDatabase(app.config.DatabasePath) db, err := app.SetupDatabase(app.config.Database.Path)
if err != nil { if err != nil {
return fmt.Errorf("failed to setup database: %w", err) return fmt.Errorf("failed to setup database: %w", err)
@@ -193,7 +193,7 @@ func (app *BootstrapApp) Setup() error {
go app.dbCleanup(queries) go app.dbCleanup(queries)
// If analytics are not disabled, start heartbeat // If analytics are not disabled, start heartbeat
if !app.config.DisableAnalytics { if app.config.Analytics.Enabled {
tlog.App.Debug().Msg("Starting heartbeat routine") tlog.App.Debug().Msg("Starting heartbeat routine")
go app.heartbeat() go app.heartbeat()
} }

View File

@@ -71,7 +71,7 @@ func (app *BootstrapApp) setupRouter() (*gin.Engine, error) {
ForgotPasswordMessage: app.config.UI.ForgotPasswordMessage, ForgotPasswordMessage: app.config.UI.ForgotPasswordMessage,
BackgroundImage: app.config.UI.BackgroundImage, BackgroundImage: app.config.UI.BackgroundImage,
OAuthAutoRedirect: app.config.OAuth.AutoRedirect, OAuthAutoRedirect: app.config.OAuth.AutoRedirect,
DisableUIWarnings: app.config.UI.DisableWarnings, WarningsEnabled: app.config.UI.WarningsEnabled,
}, apiRouter) }, apiRouter)
contextController.SetupRoutes() contextController.SetupRoutes()
@@ -103,8 +103,8 @@ func (app *BootstrapApp) setupRouter() (*gin.Engine, error) {
userController.SetupRoutes() userController.SetupRoutes()
resourcesController := controller.NewResourcesController(controller.ResourcesControllerConfig{ resourcesController := controller.NewResourcesController(controller.ResourcesControllerConfig{
ResourcesDir: app.config.ResourcesDir, Path: app.config.Resources.Path,
ResourcesDisabled: app.config.DisableResources, Enabled: app.config.Resources.Enabled,
}, &engine.RouterGroup) }, &engine.RouterGroup)
resourcesController.SetupRoutes() resourcesController.SetupRoutes()

View File

@@ -3,8 +3,16 @@ package config
// Default configuration // Default configuration
func NewDefaultConfiguration() *Config { func NewDefaultConfiguration() *Config {
return &Config{ return &Config{
ResourcesDir: "./resources", Database: DatabaseConfig{
DatabasePath: "./tinyauth.db", Path: "./tinyauth.db",
},
Analytics: AnalyticsConfig{
Enabled: true,
},
Resources: ResourcesConfig{
Enabled: true,
Path: "./resources",
},
Server: ServerConfig{ Server: ServerConfig{
Port: 3000, Port: 3000,
Address: "0.0.0.0", Address: "0.0.0.0",
@@ -19,6 +27,7 @@ func NewDefaultConfiguration() *Config {
Title: "Tinyauth", Title: "Tinyauth",
ForgotPasswordMessage: "You can change your password by changing the configuration.", ForgotPasswordMessage: "You can change your password by changing the configuration.",
BackgroundImage: "/background.jpg", BackgroundImage: "/background.jpg",
WarningsEnabled: true,
}, },
Ldap: LdapConfig{ Ldap: LdapConfig{
Insecure: false, Insecure: false,
@@ -68,20 +77,32 @@ var RedirectCookieName = "tinyauth-redirect"
// Main app config // Main app config
type Config struct { type Config struct {
AppURL string `description:"The base URL where the app is hosted." yaml:"appUrl"` AppURL string `description:"The base URL where the app is hosted." yaml:"appUrl"`
ResourcesDir string `description:"The directory where resources are stored." yaml:"resourcesDir"` Database DatabaseConfig `description:"Database configuration." yaml:"database"`
DatabasePath string `description:"The path to the database file." yaml:"databasePath"` Analytics AnalyticsConfig `description:"Analytics configuration." yaml:"analytics"`
DisableAnalytics bool `description:"Disable analytics." yaml:"disableAnalytics"` Resources ResourcesConfig `description:"Resources configuration." yaml:"resources"`
DisableResources bool `description:"Disable resources server." yaml:"disableResources"` Server ServerConfig `description:"Server configuration." yaml:"server"`
Server ServerConfig `description:"Server configuration." yaml:"server"` Auth AuthConfig `description:"Authentication configuration." yaml:"auth"`
Auth AuthConfig `description:"Authentication configuration." yaml:"auth"` Apps map[string]App `description:"Application ACLs configuration." yaml:"apps"`
Apps map[string]App `description:"Application ACLs configuration." yaml:"apps"` OAuth OAuthConfig `description:"OAuth configuration." yaml:"oauth"`
OAuth OAuthConfig `description:"OAuth configuration." yaml:"oauth"` OIDC OIDCConfig `description:"OIDC configuration." yaml:"oidc"`
OIDC OIDCConfig `description:"OIDC configuration." yaml:"oidc"` UI UIConfig `description:"UI customization." yaml:"ui"`
UI UIConfig `description:"UI customization." yaml:"ui"` Ldap LdapConfig `description:"LDAP configuration." yaml:"ldap"`
Ldap LdapConfig `description:"LDAP configuration." yaml:"ldap"` Experimental ExperimentalConfig `description:"Experimental features, use with caution." yaml:"experimental"`
Experimental ExperimentalConfig `description:"Experimental features, use with caution." yaml:"experimental"` Log LogConfig `description:"Logging configuration." yaml:"log"`
Log LogConfig `description:"Logging configuration." yaml:"log"` }
type DatabaseConfig struct {
Path string `description:"The path to the database, including file name." yaml:"path"`
}
type AnalyticsConfig struct {
Enabled bool `description:"Enable periodic version information collection." yaml:"enabled"`
}
type ResourcesConfig struct {
Enabled bool `description:"Enable the resources server." yaml:"enabled"`
Path string `description:"The directory where resources are stored." yaml:"path"`
} }
type ServerConfig struct { type ServerConfig struct {
@@ -114,8 +135,8 @@ type OAuthConfig struct {
} }
type OIDCConfig struct { type OIDCConfig struct {
PrivateKeyPath string `description:"Path to the private key file." yaml:"privateKeyPath"` PrivateKeyPath string `description:"Path to the private key file, including file name." yaml:"privateKeyPath"`
PublicKeyPath string `description:"Path to the public key file." yaml:"publicKeyPath"` PublicKeyPath string `description:"Path to the public key file, including file name." yaml:"publicKeyPath"`
Clients map[string]OIDCClientConfig `description:"OIDC clients configuration." yaml:"clients"` Clients map[string]OIDCClientConfig `description:"OIDC clients configuration." yaml:"clients"`
} }
@@ -123,7 +144,7 @@ type UIConfig struct {
Title string `description:"The title of the UI." yaml:"title"` Title string `description:"The title of the UI." yaml:"title"`
ForgotPasswordMessage string `description:"Message displayed on the forgot password page." yaml:"forgotPasswordMessage"` ForgotPasswordMessage string `description:"Message displayed on the forgot password page." yaml:"forgotPasswordMessage"`
BackgroundImage string `description:"Path to the background image." yaml:"backgroundImage"` BackgroundImage string `description:"Path to the background image." yaml:"backgroundImage"`
DisableWarnings bool `description:"Disable UI warnings." yaml:"disableWarnings"` WarningsEnabled bool `description:"Enable UI warnings." yaml:"warningsEnabled"`
} }
type LdapConfig struct { type LdapConfig struct {

View File

@@ -33,7 +33,7 @@ type AppContextResponse struct {
ForgotPasswordMessage string `json:"forgotPasswordMessage"` ForgotPasswordMessage string `json:"forgotPasswordMessage"`
BackgroundImage string `json:"backgroundImage"` BackgroundImage string `json:"backgroundImage"`
OAuthAutoRedirect string `json:"oauthAutoRedirect"` OAuthAutoRedirect string `json:"oauthAutoRedirect"`
DisableUIWarnings bool `json:"disableUiWarnings"` WarningsEnabled bool `json:"warningsEnabled"`
} }
type Provider struct { type Provider struct {
@@ -50,7 +50,7 @@ type ContextControllerConfig struct {
ForgotPasswordMessage string ForgotPasswordMessage string
BackgroundImage string BackgroundImage string
OAuthAutoRedirect string OAuthAutoRedirect string
DisableUIWarnings bool WarningsEnabled bool
} }
type ContextController struct { type ContextController struct {
@@ -59,7 +59,7 @@ type ContextController struct {
} }
func NewContextController(config ContextControllerConfig, router *gin.RouterGroup) *ContextController { func NewContextController(config ContextControllerConfig, router *gin.RouterGroup) *ContextController {
if config.DisableUIWarnings { if !config.WarningsEnabled {
tlog.App.Warn().Msg("UI warnings are disabled. This may expose users to security risks. Proceed with caution.") tlog.App.Warn().Msg("UI warnings are disabled. This may expose users to security risks. Proceed with caution.")
} }
@@ -124,6 +124,6 @@ func (controller *ContextController) appContextHandler(c *gin.Context) {
ForgotPasswordMessage: controller.config.ForgotPasswordMessage, ForgotPasswordMessage: controller.config.ForgotPasswordMessage,
BackgroundImage: controller.config.BackgroundImage, BackgroundImage: controller.config.BackgroundImage,
OAuthAutoRedirect: controller.config.OAuthAutoRedirect, OAuthAutoRedirect: controller.config.OAuthAutoRedirect,
DisableUIWarnings: controller.config.DisableUIWarnings, WarningsEnabled: controller.config.WarningsEnabled,
}) })
} }

View File

@@ -32,7 +32,7 @@ var contextControllerCfg = controller.ContextControllerConfig{
ForgotPasswordMessage: "Contact admin to reset your password.", ForgotPasswordMessage: "Contact admin to reset your password.",
BackgroundImage: "/assets/bg.jpg", BackgroundImage: "/assets/bg.jpg",
OAuthAutoRedirect: "google", OAuthAutoRedirect: "google",
DisableUIWarnings: false, WarningsEnabled: true,
} }
var contextCtrlTestContext = config.UserContext{ var contextCtrlTestContext = config.UserContext{
@@ -82,7 +82,7 @@ func TestAppContextHandler(t *testing.T) {
ForgotPasswordMessage: contextControllerCfg.ForgotPasswordMessage, ForgotPasswordMessage: contextControllerCfg.ForgotPasswordMessage,
BackgroundImage: contextControllerCfg.BackgroundImage, BackgroundImage: contextControllerCfg.BackgroundImage,
OAuthAutoRedirect: contextControllerCfg.OAuthAutoRedirect, OAuthAutoRedirect: contextControllerCfg.OAuthAutoRedirect,
DisableUIWarnings: contextControllerCfg.DisableUIWarnings, WarningsEnabled: contextControllerCfg.WarningsEnabled,
} }
router, recorder := setupContextController(nil) router, recorder := setupContextController(nil)

View File

@@ -7,8 +7,8 @@ import (
) )
type ResourcesControllerConfig struct { type ResourcesControllerConfig struct {
ResourcesDir string Path string
ResourcesDisabled bool Enabled bool
} }
type ResourcesController struct { type ResourcesController struct {
@@ -18,7 +18,7 @@ type ResourcesController struct {
} }
func NewResourcesController(config ResourcesControllerConfig, router *gin.RouterGroup) *ResourcesController { func NewResourcesController(config ResourcesControllerConfig, router *gin.RouterGroup) *ResourcesController {
fileServer := http.StripPrefix("/resources", http.FileServer(http.Dir(config.ResourcesDir))) fileServer := http.StripPrefix("/resources", http.FileServer(http.Dir(config.Path)))
return &ResourcesController{ return &ResourcesController{
config: config, config: config,
@@ -32,14 +32,14 @@ func (controller *ResourcesController) SetupRoutes() {
} }
func (controller *ResourcesController) resourcesHandler(c *gin.Context) { func (controller *ResourcesController) resourcesHandler(c *gin.Context) {
if controller.config.ResourcesDir == "" { if controller.config.Path == "" {
c.JSON(404, gin.H{ c.JSON(404, gin.H{
"status": 404, "status": 404,
"message": "Resources not found", "message": "Resources not found",
}) })
return return
} }
if controller.config.ResourcesDisabled { if !controller.config.Enabled {
c.JSON(403, gin.H{ c.JSON(403, gin.H{
"status": 403, "status": 403,
"message": "Resources are disabled", "message": "Resources are disabled",

View File

@@ -18,7 +18,8 @@ func TestResourcesHandler(t *testing.T) {
group := router.Group("/") group := router.Group("/")
ctrl := controller.NewResourcesController(controller.ResourcesControllerConfig{ ctrl := controller.NewResourcesController(controller.ResourcesControllerConfig{
ResourcesDir: "/tmp/tinyauth", Path: "/tmp/tinyauth",
Enabled: true,
}, group) }, group)
ctrl.SetupRoutes() ctrl.SetupRoutes()