mirror of
https://github.com/unmojang/drasl.git
synced 2025-08-03 02:46:03 -04:00
Initial i18n support
This commit is contained in:
parent
ecd485cc1d
commit
38d533581b
2
Makefile
2
Makefile
@ -23,7 +23,7 @@ install: build
|
||||
install -Dm 755 drasl "$(prefix)/bin/drasl"
|
||||
install -Dm 644 LICENSE "$(prefix)/share/licenses/drasl/LICENSE"
|
||||
mkdir -p "$(prefix)/share/drasl/"
|
||||
cp -R assets view public "$(prefix)/share/drasl/"
|
||||
cp -R assets view public locales "$(prefix)/share/drasl/"
|
||||
|
||||
clean:
|
||||
rm -f drasl
|
||||
|
178
front.go
178
front.go
@ -10,9 +10,11 @@ import (
|
||||
"github.com/google/uuid"
|
||||
"github.com/jxskiss/base62"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/leonelquinteros/gotext"
|
||||
"github.com/samber/mo"
|
||||
"github.com/zitadel/oidc/v3/pkg/client/rp"
|
||||
"github.com/zitadel/oidc/v3/pkg/oidc"
|
||||
"golang.org/x/text/language"
|
||||
"gorm.io/gorm"
|
||||
"html/template"
|
||||
"io"
|
||||
@ -28,6 +30,7 @@ import (
|
||||
Web front end for creating user accounts, changing passwords, skins, player names, etc.
|
||||
*/
|
||||
|
||||
const CONTEXT_KEY_LOCALE = "DraslLocale"
|
||||
const BROWSER_TOKEN_AGE_SEC = 24 * 60 * 60
|
||||
const COOKIE_PREFIX = "__Host-"
|
||||
const BROWSER_TOKEN_COOKIE_NAME = COOKIE_PREFIX + "browserToken"
|
||||
@ -82,6 +85,21 @@ func NewTemplate(app *App) *Template {
|
||||
return t
|
||||
}
|
||||
|
||||
func (app *App) GetLanguageMiddleware() func(echo.HandlerFunc) echo.HandlerFunc {
|
||||
matcher := language.NewMatcher(app.LocaleTags)
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
header := c.Request().Header.Get("Accept-Language")
|
||||
t, _, _ := language.ParseAcceptLanguage(header)
|
||||
// Use only the returned index, not the returned tag: https://github.com/golang/go/issues/24211
|
||||
_, localeTagIndex, _ := matcher.Match(t...)
|
||||
l := app.Locales[app.LocaleTags[localeTagIndex]]
|
||||
c.Set(CONTEXT_KEY_LOCALE, l)
|
||||
return next(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
|
||||
return t.Templates[name].ExecuteTemplate(w, "base", data)
|
||||
}
|
||||
@ -138,15 +156,31 @@ func NewWebError(returnURL string, message string, args ...interface{}) error {
|
||||
}
|
||||
}
|
||||
|
||||
type errorContext struct {
|
||||
type baseContext struct {
|
||||
App *App
|
||||
User *User
|
||||
L *gotext.Locale
|
||||
URL string
|
||||
SuccessMessage string
|
||||
WarningMessage string
|
||||
ErrorMessage string
|
||||
Message string
|
||||
StatusCode int
|
||||
}
|
||||
|
||||
func (app *App) NewBaseContext(c *echo.Context) baseContext {
|
||||
return baseContext{
|
||||
App: app,
|
||||
L: (*c).Get(CONTEXT_KEY_LOCALE).(*gotext.Locale),
|
||||
URL: (*c).Request().URL.RequestURI(),
|
||||
SuccessMessage: app.lastSuccessMessage(c),
|
||||
WarningMessage: app.lastWarningMessage(c),
|
||||
ErrorMessage: app.lastErrorMessage(c),
|
||||
}
|
||||
}
|
||||
|
||||
type errorContext struct {
|
||||
baseContext
|
||||
User *User
|
||||
Message string
|
||||
StatusCode int
|
||||
}
|
||||
|
||||
// Set error message and redirect
|
||||
@ -182,14 +216,10 @@ func (app *App) HandleWebError(err error, c *echo.Context) error {
|
||||
}
|
||||
if Contains(safeMethods, (*c).Request().Method) {
|
||||
return (*c).Render(code, "error", errorContext{
|
||||
App: app,
|
||||
User: nil,
|
||||
URL: (*c).Request().URL.RequestURI(),
|
||||
Message: message,
|
||||
SuccessMessage: app.lastSuccessMessage(c),
|
||||
WarningMessage: app.lastWarningMessage(c),
|
||||
ErrorMessage: app.lastErrorMessage(c),
|
||||
StatusCode: code,
|
||||
baseContext: app.NewBaseContext(c),
|
||||
User: nil,
|
||||
Message: message,
|
||||
StatusCode: code,
|
||||
})
|
||||
} else {
|
||||
returnURL := getReturnURL(app, c)
|
||||
@ -301,13 +331,9 @@ func EncodeOIDCState(state oidcState) (string, error) {
|
||||
// GET /
|
||||
func FrontRoot(app *App) func(c echo.Context) error {
|
||||
type rootContext struct {
|
||||
App *App
|
||||
baseContext
|
||||
User *User
|
||||
URL string
|
||||
Destination string
|
||||
SuccessMessage string
|
||||
WarningMessage string
|
||||
ErrorMessage string
|
||||
WebOIDCProviders []webOIDCProvider
|
||||
}
|
||||
|
||||
@ -348,13 +374,9 @@ func FrontRoot(app *App) func(c echo.Context) error {
|
||||
}
|
||||
|
||||
return c.Render(http.StatusOK, "root", rootContext{
|
||||
App: app,
|
||||
baseContext: app.NewBaseContext(&c),
|
||||
User: user,
|
||||
URL: c.Request().URL.RequestURI(),
|
||||
Destination: destination,
|
||||
SuccessMessage: app.lastSuccessMessage(&c),
|
||||
WarningMessage: app.lastWarningMessage(&c),
|
||||
ErrorMessage: app.lastErrorMessage(&c),
|
||||
WebOIDCProviders: webOIDCProviders,
|
||||
})
|
||||
})
|
||||
@ -408,12 +430,8 @@ type oidcState struct {
|
||||
// GET /registration
|
||||
func FrontRegistration(app *App) func(c echo.Context) error {
|
||||
type registrationContext struct {
|
||||
App *App
|
||||
baseContext
|
||||
User *User
|
||||
URL string
|
||||
SuccessMessage string
|
||||
WarningMessage string
|
||||
ErrorMessage string
|
||||
InviteCode string
|
||||
WebOIDCProviders []webOIDCProvider
|
||||
}
|
||||
@ -454,12 +472,8 @@ func FrontRegistration(app *App) func(c echo.Context) error {
|
||||
}
|
||||
|
||||
return c.Render(http.StatusOK, "registration", registrationContext{
|
||||
App: app,
|
||||
baseContext: app.NewBaseContext(&c),
|
||||
User: user,
|
||||
URL: c.Request().URL.RequestURI(),
|
||||
SuccessMessage: app.lastSuccessMessage(&c),
|
||||
WarningMessage: app.lastWarningMessage(&c),
|
||||
ErrorMessage: app.lastErrorMessage(&c),
|
||||
InviteCode: inviteCode,
|
||||
WebOIDCProviders: webOIDCProviders,
|
||||
})
|
||||
@ -502,12 +516,8 @@ func (app *App) getIDTokenCookie(c *echo.Context) (*OIDCProvider, string, oidc.I
|
||||
|
||||
func FrontCompleteRegistration(app *App) func(c echo.Context) error {
|
||||
type completeRegistrationContext struct {
|
||||
App *App
|
||||
baseContext
|
||||
User *User
|
||||
URL string
|
||||
SuccessMessage string
|
||||
WarningMessage string
|
||||
ErrorMessage string
|
||||
InviteCode string
|
||||
AnyUnmigratedUsers bool
|
||||
AllowChoosingPlayerName bool
|
||||
@ -547,12 +557,8 @@ func FrontCompleteRegistration(app *App) func(c echo.Context) error {
|
||||
}
|
||||
|
||||
return c.Render(http.StatusOK, "complete-registration", completeRegistrationContext{
|
||||
App: app,
|
||||
baseContext: app.NewBaseContext(&c),
|
||||
User: user,
|
||||
URL: c.Request().URL.RequestURI(),
|
||||
SuccessMessage: app.lastSuccessMessage(&c),
|
||||
WarningMessage: app.lastWarningMessage(&c),
|
||||
ErrorMessage: app.lastErrorMessage(&c),
|
||||
InviteCode: inviteCode,
|
||||
PreferredPlayerName: preferredPlayerName,
|
||||
AllowChoosingPlayerName: provider.Config.AllowChoosingPlayerName,
|
||||
@ -775,14 +781,10 @@ func FrontOIDCCallback(app *App) func(c echo.Context) error {
|
||||
// GET /web/admin
|
||||
func FrontAdmin(app *App) func(c echo.Context) error {
|
||||
type adminContext struct {
|
||||
App *App
|
||||
User *User
|
||||
URL string
|
||||
SuccessMessage string
|
||||
WarningMessage string
|
||||
ErrorMessage string
|
||||
Users []User
|
||||
Invites []Invite
|
||||
baseContext
|
||||
User *User
|
||||
Users []User
|
||||
Invites []Invite
|
||||
}
|
||||
|
||||
return withBrowserAdmin(app, func(c echo.Context, user *User) error {
|
||||
@ -799,14 +801,10 @@ func FrontAdmin(app *App) func(c echo.Context) error {
|
||||
}
|
||||
|
||||
return c.Render(http.StatusOK, "admin", adminContext{
|
||||
App: app,
|
||||
User: user,
|
||||
URL: c.Request().URL.RequestURI(),
|
||||
SuccessMessage: app.lastSuccessMessage(&c),
|
||||
WarningMessage: app.lastWarningMessage(&c),
|
||||
ErrorMessage: app.lastErrorMessage(&c),
|
||||
Users: users,
|
||||
Invites: invites,
|
||||
baseContext: app.NewBaseContext(&c),
|
||||
User: user,
|
||||
Users: users,
|
||||
Invites: invites,
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -925,12 +923,8 @@ func FrontNewInvite(app *App) func(c echo.Context) error {
|
||||
// GET /web/user/:uuid
|
||||
func FrontUser(app *App) func(c echo.Context) error {
|
||||
type userContext struct {
|
||||
App *App
|
||||
baseContext
|
||||
User *User
|
||||
URL string
|
||||
SuccessMessage string
|
||||
WarningMessage string
|
||||
ErrorMessage string
|
||||
TargetUser *User
|
||||
TargetUserID string
|
||||
SkinURL *string
|
||||
@ -1014,12 +1008,8 @@ func FrontUser(app *App) func(c echo.Context) error {
|
||||
}
|
||||
|
||||
return c.Render(http.StatusOK, "user", userContext{
|
||||
App: app,
|
||||
baseContext: app.NewBaseContext(&c),
|
||||
User: user,
|
||||
URL: c.Request().URL.RequestURI(),
|
||||
SuccessMessage: app.lastSuccessMessage(&c),
|
||||
WarningMessage: app.lastWarningMessage(&c),
|
||||
ErrorMessage: app.lastErrorMessage(&c),
|
||||
TargetUser: targetUser,
|
||||
AdminView: adminView,
|
||||
LinkedOIDCProviderNames: linkedOIDCProviderNames.ToSlice(),
|
||||
@ -1032,18 +1022,14 @@ func FrontUser(app *App) func(c echo.Context) error {
|
||||
// GET /web/player/:uuid
|
||||
func FrontPlayer(app *App) func(c echo.Context) error {
|
||||
type playerContext struct {
|
||||
App *App
|
||||
User *User
|
||||
URL string
|
||||
SuccessMessage string
|
||||
WarningMessage string
|
||||
ErrorMessage string
|
||||
PlayerUser *User
|
||||
Player *Player
|
||||
PlayerID string
|
||||
SkinURL *string
|
||||
CapeURL *string
|
||||
AdminView bool
|
||||
baseContext
|
||||
User *User
|
||||
PlayerUser *User
|
||||
Player *Player
|
||||
PlayerID string
|
||||
SkinURL *string
|
||||
CapeURL *string
|
||||
AdminView bool
|
||||
}
|
||||
|
||||
return withBrowserAuthentication(app, true, func(c echo.Context, user *User) error {
|
||||
@ -1081,18 +1067,14 @@ func FrontPlayer(app *App) func(c echo.Context) error {
|
||||
}
|
||||
|
||||
return c.Render(http.StatusOK, "player", playerContext{
|
||||
App: app,
|
||||
User: user,
|
||||
URL: c.Request().URL.RequestURI(),
|
||||
SuccessMessage: app.lastSuccessMessage(&c),
|
||||
WarningMessage: app.lastWarningMessage(&c),
|
||||
ErrorMessage: app.lastErrorMessage(&c),
|
||||
PlayerUser: &playerUser,
|
||||
Player: &player,
|
||||
PlayerID: id,
|
||||
SkinURL: skinURL,
|
||||
CapeURL: capeURL,
|
||||
AdminView: adminView,
|
||||
baseContext: app.NewBaseContext(&c),
|
||||
User: user,
|
||||
PlayerUser: &playerUser,
|
||||
Player: &player,
|
||||
PlayerID: id,
|
||||
SkinURL: skinURL,
|
||||
CapeURL: capeURL,
|
||||
AdminView: adminView,
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -1283,12 +1265,8 @@ func FrontRegisterChallenge(app *App) func(c echo.Context) error {
|
||||
|
||||
func frontChallenge(app *App, action string) func(c echo.Context) error {
|
||||
type challengeContext struct {
|
||||
App *App
|
||||
baseContext
|
||||
User *User
|
||||
URL string
|
||||
SuccessMessage string
|
||||
WarningMessage string
|
||||
ErrorMessage string
|
||||
PlayerName string
|
||||
RegistrationProvider string
|
||||
SkinBase64 string
|
||||
@ -1372,12 +1350,8 @@ func frontChallenge(app *App, action string) func(c echo.Context) error {
|
||||
skinBase64 := base64.StdEncoding.EncodeToString(challengeSkinBytes)
|
||||
|
||||
return c.Render(http.StatusOK, "challenge", challengeContext{
|
||||
App: app,
|
||||
baseContext: app.NewBaseContext(&c),
|
||||
User: user,
|
||||
URL: c.Request().URL.RequestURI(),
|
||||
SuccessMessage: app.lastSuccessMessage(&c),
|
||||
WarningMessage: app.lastWarningMessage(&c),
|
||||
ErrorMessage: app.lastErrorMessage(&c),
|
||||
PlayerName: playerName,
|
||||
SkinBase64: skinBase64,
|
||||
SkinFilename: playerName + "-challenge.png",
|
||||
|
5
go.mod
5
go.mod
@ -1,8 +1,8 @@
|
||||
module unmojang.org/drasl
|
||||
|
||||
go 1.23.0
|
||||
go 1.23.5
|
||||
|
||||
toolchain go1.23.2
|
||||
toolchain go1.23.10
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.3.2
|
||||
@ -38,6 +38,7 @@ require (
|
||||
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/labstack/gommon v0.4.2 // indirect
|
||||
github.com/leonelquinteros/gotext v1.7.2 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.18 // indirect
|
||||
|
2
go.sum
2
go.sum
@ -64,6 +64,8 @@ github.com/labstack/echo/v4 v4.11.4 h1:vDZmA+qNeh1pd/cCkEicDMrjtrnMGQ1QFI9gWN1zG
|
||||
github.com/labstack/echo/v4 v4.11.4/go.mod h1:noh7EvLwqDsmh/X/HWKPUl1AjzJrhyptRyEbQJfxen8=
|
||||
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
|
||||
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
|
||||
github.com/leonelquinteros/gotext v1.7.2 h1:bDPndU8nt+/kRo1m4l/1OXiiy2v7Z7dfPQ9+YP7G1Mc=
|
||||
github.com/leonelquinteros/gotext v1.7.2/go.mod h1:9/haCkm5P7Jay1sxKDGJ5WIg4zkz8oZKw4ekNpALob8=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
|
0
locales/en-US/default.po
Normal file
0
locales/en-US/default.po
Normal file
7
locales/es/default.po
Normal file
7
locales/es/default.po
Normal file
@ -0,0 +1,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Language: es\n"
|
||||
|
||||
msgid "Register"
|
||||
msgstr "Registrarse"
|
79
main.go
79
main.go
@ -13,8 +13,10 @@ import (
|
||||
"github.com/dgraph-io/ristretto"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/labstack/echo/v4/middleware"
|
||||
"github.com/leonelquinteros/gotext"
|
||||
"github.com/zitadel/oidc/v3/pkg/client/rp"
|
||||
httphelper "github.com/zitadel/oidc/v3/pkg/http"
|
||||
"golang.org/x/text/language"
|
||||
"golang.org/x/time/rate"
|
||||
"gorm.io/gorm"
|
||||
"image"
|
||||
@ -25,6 +27,7 @@ import (
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
@ -71,6 +74,8 @@ type App struct {
|
||||
OIDCProvidersByName map[string]*OIDCProvider
|
||||
OIDCProvidersByIssuer map[string]*OIDCProvider
|
||||
FallbackAPIServers []FallbackAPIServer
|
||||
Locales map[language.Tag]*gotext.Locale
|
||||
LocaleTags []language.Tag
|
||||
}
|
||||
|
||||
func LogInfo(args ...interface{}) {
|
||||
@ -195,31 +200,36 @@ func (app *App) MakeServer() *echo.Echo {
|
||||
t := NewTemplate(app)
|
||||
e.Renderer = t
|
||||
frontUser := FrontUser(app)
|
||||
e.GET("/", FrontRoot(app))
|
||||
e.GET("/web/admin", FrontAdmin(app))
|
||||
e.GET("/web/complete-registration", FrontCompleteRegistration(app))
|
||||
e.GET("/web/create-player-challenge", FrontCreatePlayerChallenge(app))
|
||||
e.GET("/web/manifest.webmanifest", FrontWebManifest(app))
|
||||
e.GET("/web/oidc-callback/:providerName", FrontOIDCCallback(app))
|
||||
e.GET("/web/player/:uuid", FrontPlayer(app))
|
||||
e.GET("/web/register-challenge", FrontRegisterChallenge(app))
|
||||
e.GET("/web/registration", FrontRegistration(app))
|
||||
e.GET("/web/user", frontUser)
|
||||
e.GET("/web/user/:uuid", frontUser)
|
||||
e.POST("/web/admin/delete-invite", FrontDeleteInvite(app))
|
||||
e.POST("/web/admin/new-invite", FrontNewInvite(app))
|
||||
e.POST("/web/admin/update-users", FrontUpdateUsers(app))
|
||||
e.POST("/web/create-player", FrontCreatePlayer(app))
|
||||
e.POST("/web/delete-player", FrontDeletePlayer(app))
|
||||
e.POST("/web/delete-user", FrontDeleteUser(app))
|
||||
e.POST("/web/login", FrontLogin(app))
|
||||
e.POST("/web/logout", FrontLogout(app))
|
||||
e.POST("/web/oidc-migrate", app.FrontOIDCMigrate())
|
||||
e.POST("/web/oidc-unlink", app.FrontOIDCUnlink())
|
||||
e.POST("/web/register", FrontRegister(app))
|
||||
e.POST("/web/update-player", FrontUpdatePlayer(app))
|
||||
e.POST("/web/update-user", FrontUpdateUser(app))
|
||||
e.Static("/web/public", path.Join(app.Config.DataDirectory, "public"))
|
||||
|
||||
getLanguage := app.GetLanguageMiddleware()
|
||||
|
||||
e.GET("/", FrontRoot(app), getLanguage)
|
||||
g := e.Group("/web")
|
||||
g.Use(getLanguage)
|
||||
g.GET("/admin", FrontAdmin(app))
|
||||
g.GET("/complete-registration", FrontCompleteRegistration(app))
|
||||
g.GET("/create-player-challenge", FrontCreatePlayerChallenge(app))
|
||||
g.GET("/manifest.webmanifest", FrontWebManifest(app))
|
||||
g.GET("/oidc-callback/:providerName", FrontOIDCCallback(app))
|
||||
g.GET("/player/:uuid", FrontPlayer(app))
|
||||
g.GET("/register-challenge", FrontRegisterChallenge(app))
|
||||
g.GET("/registration", FrontRegistration(app))
|
||||
g.GET("/user", frontUser)
|
||||
g.GET("/user/:uuid", frontUser)
|
||||
g.POST("/admin/delete-invite", FrontDeleteInvite(app))
|
||||
g.POST("/admin/new-invite", FrontNewInvite(app))
|
||||
g.POST("/admin/update-users", FrontUpdateUsers(app))
|
||||
g.POST("/create-player", FrontCreatePlayer(app))
|
||||
g.POST("/delete-player", FrontDeletePlayer(app))
|
||||
g.POST("/delete-user", FrontDeleteUser(app))
|
||||
g.POST("/login", FrontLogin(app))
|
||||
g.POST("/logout", FrontLogout(app))
|
||||
g.POST("/oidc-migrate", app.FrontOIDCMigrate())
|
||||
g.POST("/oidc-unlink", app.FrontOIDCUnlink())
|
||||
g.POST("/register", FrontRegister(app))
|
||||
g.POST("/update-player", FrontUpdatePlayer(app))
|
||||
g.POST("/update-user", FrontUpdateUser(app))
|
||||
g.Static("/public", path.Join(app.Config.DataDirectory, "public"))
|
||||
}
|
||||
e.Static("/web/texture/cape", path.Join(app.Config.StateDirectory, "cape"))
|
||||
e.Static("/web/texture/default-cape", path.Join(app.Config.StateDirectory, "default-cape"))
|
||||
@ -425,6 +435,23 @@ func setup(config *Config) *App {
|
||||
log.Fatalf("Couldn't access DataDirectory: %s", err)
|
||||
}
|
||||
|
||||
// Locales
|
||||
locales := map[language.Tag]*gotext.Locale{}
|
||||
localeTags := make([]language.Tag, 0)
|
||||
locales_path := path.Join(config.DataDirectory, "locales")
|
||||
lang_paths, err := filepath.Glob(path.Join(locales_path, "*"))
|
||||
for _, lang_path := range lang_paths {
|
||||
lang := filepath.Base(lang_path)
|
||||
tag, err := language.Parse(lang)
|
||||
if err != nil {
|
||||
log.Fatalf("Unrecognized language tag: %s", lang)
|
||||
}
|
||||
l := gotext.NewLocale(locales_path, lang)
|
||||
l.AddDomain("default")
|
||||
localeTags = append(localeTags, tag)
|
||||
locales[tag] = l
|
||||
}
|
||||
|
||||
// Crypto
|
||||
key := ReadOrCreateKey(config)
|
||||
keyBytes := Unwrap(x509.MarshalPKCS8PrivateKey(key))
|
||||
@ -575,6 +602,8 @@ func setup(config *Config) *App {
|
||||
OIDCProvidersByName: oidcProvidersByName,
|
||||
OIDCProvidersByIssuer: oidcProvidersByIssuer,
|
||||
FallbackAPIServers: fallbackAPIServers,
|
||||
Locales: locales,
|
||||
LocaleTags: localeTags,
|
||||
}
|
||||
|
||||
// Post-setup
|
||||
|
@ -92,7 +92,7 @@ a:visited {
|
||||
}
|
||||
|
||||
.logo {
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
font-family: Arial, sans-serif;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
font-size: 2rem;
|
||||
|
@ -24,7 +24,7 @@
|
||||
<input type="submit" value="Log out" />
|
||||
</form>
|
||||
{{ else }}
|
||||
<a href="{{ .App.FrontEndURL }}/web/registration">Register</a>
|
||||
<a href="{{ .App.FrontEndURL }}/web/registration">{{ .L.Get "Register" }}</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
</nav>
|
||||
|
Loading…
x
Reference in New Issue
Block a user