diff --git a/Makefile b/Makefile index 5eda95d..53d646f 100644 --- a/Makefile +++ b/Makefile @@ -196,7 +196,7 @@ STATIC_TARGET = $(STATIC_SRC:static/%=$(DATA)/web/%) COPY_SRC = images/banner.svg jfa-go.service LICENSE $(LANG_SRC) $(STATIC_SRC) COPY_TARGET = $(DATA)/jfa-go.service # $(DATA)/LICENSE $(LANG_TARGET) $(STATIC_TARGET) $(DATA)/web/css/$(CSSVERSION)bundle.css -$(COPY_TARGET): $(INLINE_TARGET) $(STATIC_SRC) +$(COPY_TARGET): $(INLINE_TARGET) $(STATIC_SRC) $(LANG_SRC) $(info copying crash page) cp $(DATA)/crash.html $(DATA)/html/ $(info copying static data) diff --git a/lang/common/en-us.json b/lang/common/en-us.json index 57e4046..34955a7 100644 --- a/lang/common/en-us.json +++ b/lang/common/en-us.json @@ -48,7 +48,8 @@ "errorConnection": "Couldn't connect to jfa-go.", "errorUnknown": "Unknown error.", "error401Unauthorized": "Unauthorized. Try refreshing the page.", - "errorSaveSettings": "Couldn't save settings." + "errorSaveSettings": "Couldn't save settings.", + "errorSpecialSymbols": "Field cannot contain special symbols." }, "quantityStrings": { "year": { @@ -64,4 +65,4 @@ "plural": "{n} Days" } } -} \ No newline at end of file +} diff --git a/logger/logger.go b/logger/logger.go index a48cbf8..354d554 100644 --- a/logger/logger.go +++ b/logger/logger.go @@ -52,6 +52,14 @@ func lshortfile() string { return Lshortfile(3) } +func LshortfileTree() string { + out := "" + for i := 6; i >= 0; i-- { + out += strconv.Itoa(i) + ":" + Lshortfile(i) + " " + } + return out +} + func NewLogger(out io.Writer, prefix string, flag int, color c.Attribute) (l *Logger) { l = &Logger{} // Use reimplemented Lshortfile since wrapping the log functions messes them up @@ -96,6 +104,13 @@ func (l *Logger) PrintfCustomLevel(level int, format string, v ...interface{}) { l.logger.Print(out) } +func (l *Logger) PrintfNoFile(format string, v ...interface{}) { + if l.empty { + return + } + l.logger.Print(l.printer.Sprintf(format, v...)) +} + func (l *Logger) Print(v ...interface{}) { if l.empty { return diff --git a/logmessages/logmessages.go b/logmessages/logmessages.go index 4f47590..6dae416 100644 --- a/logmessages/logmessages.go +++ b/logmessages/logmessages.go @@ -175,6 +175,7 @@ const ( AccountLinked = "account already linked and require_unique enabled" AccountUnverified = "unverified" FailedSetDiscordMemberRole = "Failed to apply/remove " + Discord + " member role: %v" + InvalidChar = "Invalid character '%c'" FailedSetEmailAddress = "Failed to set email address for %s user \"%s\": %v" diff --git a/models.go b/models.go index ee951c0..1fea2b5 100644 --- a/models.go +++ b/models.go @@ -5,8 +5,9 @@ import ( ) type stringResponse struct { - Response string `json:"response" example:"message"` - Error string `json:"error" example:"errorDescription"` + Response string `json:"response" example:"message"` + ErrorText string `json:"error" example:"No special symbols allowed."` + ErrorCode string `json:"error_code" example:"errorSpecialSymbols"` } type boolResponse struct { diff --git a/ts/form.ts b/ts/form.ts index 28bcd71..3f16896 100644 --- a/ts/form.ts +++ b/ts/form.ts @@ -176,13 +176,32 @@ const rePasswordField = document.getElementById("create-reenter-password") as HT let captcha = new Captcha(window.code, window.captcha, window.reCAPTCHA, false); +const clearSubmitButton = () => { + submitInput.setCustomValidity(""); + submitSpan.title = ""; +}; + +const invalidMessage = (el: HTMLInputElement, msg: string) => { + el.setCustomValidity(msg); + submitInput.setCustomValidity(msg); + submitSpan.title = msg; +}; + function _baseValidator(oncomplete: (valid: boolean) => void, captchaValid: boolean): void { + clearSubmitButton(); if (window.emailRequired) { if (!emailField.value.includes("@")) { oncomplete(false); return; } } + usernameField.setCustomValidity(""); + // Jellyfin doesn't like having "+" in the username field + if (usernameField.value.includes("+")) { + invalidMessage(usernameField, window.messages["errorSpecialSymbols"]); + oncomplete(false); + return; + } if (window.discordEnabled && window.discordRequired && !discordVerified) { oncomplete(false); return; diff --git a/ts/modules/accounts.ts b/ts/modules/accounts.ts index ee4455f..812e476 100644 --- a/ts/modules/accounts.ts +++ b/ts/modules/accounts.ts @@ -1138,7 +1138,12 @@ export class accountsList { console.log("User created, but welcome email failed"); } } else { - window.notifications.customError("addUser", window.lang.var("notifications", "errorUserCreated", `"${send['username']}"`)); + let msg = window.lang.var("notifications", "errorUserCreated", `"${send['username']}"`); + if ("error" in req.response) { + let realError = window.lang.notif(req.response["error"]); + if (realError) msg = realError; + } + window.notifications.customError("addUser", msg); } if (req.response["error"] as String) { console.log(req.response["error"]); diff --git a/users.go b/users.go index 1e4e205..f4345a7 100644 --- a/users.go +++ b/users.go @@ -1,10 +1,13 @@ package main import ( + "fmt" + "strings" "sync" "time" "github.com/gin-gonic/gin" + "github.com/hrfee/jfa-go/logger" lm "github.com/hrfee/jfa-go/logmessages" "github.com/hrfee/mediabrowser" "github.com/lithammer/shortuuid/v3" @@ -53,9 +56,11 @@ type NewUserData struct { func (app *appContext) NewUserPostVerification(p NewUserParams) (out NewUserData, pendingTasks *sync.WaitGroup) { pendingTasks = &sync.WaitGroup{} // Some helper functions which will behave as our app.info/error/debug + // And make sure we capture the correct caller location. deferLogInfo := func(s string, args ...any) { + loc := logger.Lshortfile(2) out.Log = func() { - app.info.Printf(s, args) + app.info.PrintfNoFile(loc+" "+s, args...) } } /* deferLogDebug := func(s string, args ...any) { @@ -64,11 +69,19 @@ func (app *appContext) NewUserPostVerification(p NewUserParams) (out NewUserData } } */ deferLogError := func(s string, args ...any) { + loc := logger.Lshortfile(2) out.Log = func() { - app.err.Printf(s, args) + app.err.PrintfNoFile(loc+" "+s, args...) } } + if strings.ContainsRune(p.Req.Username, '+') { + deferLogError(lm.FailedCreateUser, lm.Jellyfin, p.Req.Username, fmt.Sprintf(lm.InvalidChar, '+')) + out.Status = 400 + out.Message = "errorSpecialSymbols" + return + } + existingUser, _ := app.jf.UserByName(p.Req.Username, false) if existingUser.Name != "" { out.Message = lm.UserExists diff --git a/views.go b/views.go index 16027a1..6928bba 100644 --- a/views.go +++ b/views.go @@ -677,7 +677,7 @@ func (app *appContext) NewUserFromConfirmationKey(invite Invite, key string, lan nu.Log() } if !nu.Created { - respond(nu.Status, nu.Message, gc) + // respond(nu.Status, nu.Message, gc) fail() return }