mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-12-22 17:10:10 +00:00
form: rework email confirmation
realized half the info from the signup form wasnt being stored in the JWT used to create the account after email confirmation, and instead of adding them, the -whole request- from the browser is stored temporarily by the server, indexed by a smaller JWT that only includes the invite code. Someone complained on reddit about me storing the password in the JWT a while back, and although security-wise that isn't an issue (only the server can decrypt the token), it doesn't happen anymore. Happy?
This commit is contained in:
parent
f779f0345e
commit
14c18bd668
15
api-users.go
15
api-users.go
@ -242,12 +242,17 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc
|
|||||||
success = false
|
success = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
inv, _ := app.storage.GetInvitesKey(req.Code)
|
if app.ConfirmationKeys == nil {
|
||||||
if inv.ConfirmationKeys == nil {
|
app.ConfirmationKeys = map[string]map[string]newUserDTO{}
|
||||||
inv.ConfirmationKeys = map[string]newUserDTO{}
|
|
||||||
}
|
}
|
||||||
inv.ConfirmationKeys[key] = req
|
cKeys, ok := app.ConfirmationKeys[req.Code]
|
||||||
app.storage.SetInvitesKey(req.Code, inv)
|
if !ok {
|
||||||
|
cKeys = map[string]newUserDTO{}
|
||||||
|
}
|
||||||
|
cKeys[key] = req
|
||||||
|
app.confirmationKeysLock.Lock()
|
||||||
|
app.ConfirmationKeys[req.Code] = cKeys
|
||||||
|
app.confirmationKeysLock.Unlock()
|
||||||
f = func(gc *gin.Context) {
|
f = func(gc *gin.Context) {
|
||||||
app.debug.Printf("%s: Email confirmation required", req.Code)
|
app.debug.Printf("%s: Email confirmation required", req.Code)
|
||||||
respond(401, "confirmEmail", gc)
|
respond(401, "confirmEmail", gc)
|
||||||
|
45
main.go
45
main.go
@ -17,6 +17,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -90,27 +91,29 @@ type appContext struct {
|
|||||||
adminUsers []User
|
adminUsers []User
|
||||||
invalidTokens []string
|
invalidTokens []string
|
||||||
// Keeping jf name because I can't think of a better one
|
// Keeping jf name because I can't think of a better one
|
||||||
jf *mediabrowser.MediaBrowser
|
jf *mediabrowser.MediaBrowser
|
||||||
authJf *mediabrowser.MediaBrowser
|
authJf *mediabrowser.MediaBrowser
|
||||||
ombi *ombi.Ombi
|
ombi *ombi.Ombi
|
||||||
datePattern string
|
datePattern string
|
||||||
timePattern string
|
timePattern string
|
||||||
storage Storage
|
storage Storage
|
||||||
validator Validator
|
validator Validator
|
||||||
email *Emailer
|
email *Emailer
|
||||||
telegram *TelegramDaemon
|
telegram *TelegramDaemon
|
||||||
discord *DiscordDaemon
|
discord *DiscordDaemon
|
||||||
matrix *MatrixDaemon
|
matrix *MatrixDaemon
|
||||||
info, debug, err *logger.Logger
|
info, debug, err *logger.Logger
|
||||||
host string
|
host string
|
||||||
port int
|
port int
|
||||||
version string
|
version string
|
||||||
URLBase string
|
URLBase string
|
||||||
updater *Updater
|
updater *Updater
|
||||||
newUpdate bool // Whether whatever's in update is new.
|
newUpdate bool // Whether whatever's in update is new.
|
||||||
tag Tag
|
tag Tag
|
||||||
update Update
|
update Update
|
||||||
internalPWRs map[string]InternalPWR
|
internalPWRs map[string]InternalPWR
|
||||||
|
ConfirmationKeys map[string]map[string]newUserDTO // Map of invite code to jwt to request
|
||||||
|
confirmationKeysLock sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateSecret(length int) (string, error) {
|
func generateSecret(length int) (string, error) {
|
||||||
|
11
storage.go
11
storage.go
@ -274,12 +274,11 @@ type Invite struct {
|
|||||||
UserMinutes int `json:"user-minutes,omitempty"`
|
UserMinutes int `json:"user-minutes,omitempty"`
|
||||||
SendTo string `json:"email"`
|
SendTo string `json:"email"`
|
||||||
// Used to be stored as formatted time, now as Unix.
|
// Used to be stored as formatted time, now as Unix.
|
||||||
UsedBy [][]string `json:"used-by"`
|
UsedBy [][]string `json:"used-by"`
|
||||||
Notify map[string]map[string]bool `json:"notify"`
|
Notify map[string]map[string]bool `json:"notify"`
|
||||||
Profile string `json:"profile"`
|
Profile string `json:"profile"`
|
||||||
Label string `json:"label,omitempty"`
|
Label string `json:"label,omitempty"`
|
||||||
ConfirmationKeys map[string]newUserDTO `json:"-"` // map of JWT confirmation keys to their original requests
|
Captchas map[string]*captcha.Data // Map of Captcha IDs to answers
|
||||||
Captchas map[string]*captcha.Data // Map of Captcha IDs to answers
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Lang struct {
|
type Lang struct {
|
||||||
|
27
views.go
27
views.go
@ -512,7 +512,6 @@ func (app *appContext) InviteProxy(gc *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if key := gc.Query("key"); key != "" && app.config.Section("email_confirmation").Key("enabled").MustBool(false) {
|
if key := gc.Query("key"); key != "" && app.config.Section("email_confirmation").Key("enabled").MustBool(false) {
|
||||||
req, ok := inv.ConfirmationKeys[key]
|
|
||||||
fail := func() {
|
fail := func() {
|
||||||
gcHTML(gc, 404, "404.html", gin.H{
|
gcHTML(gc, 404, "404.html", gin.H{
|
||||||
"cssClass": app.cssClass,
|
"cssClass": app.cssClass,
|
||||||
@ -520,6 +519,18 @@ func (app *appContext) InviteProxy(gc *gin.Context) {
|
|||||||
"contactMessage": app.config.Section("ui").Key("contact_message").String(),
|
"contactMessage": app.config.Section("ui").Key("contact_message").String(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
var req newUserDTO
|
||||||
|
if app.ConfirmationKeys == nil {
|
||||||
|
fail()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
invKeys, ok := app.ConfirmationKeys[code]
|
||||||
|
if !ok {
|
||||||
|
fail()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req, ok = invKeys[key]
|
||||||
if !ok {
|
if !ok {
|
||||||
fail()
|
fail()
|
||||||
return
|
return
|
||||||
@ -537,8 +548,11 @@ func (app *appContext) InviteProxy(gc *gin.Context) {
|
|||||||
app.debug.Printf("Invalid key")
|
app.debug.Printf("Invalid key")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, success := app.newUser(req, true)
|
f, success := app.newUser(req, true)
|
||||||
if !success {
|
if !success {
|
||||||
|
app.err.Printf("Failed to create new user")
|
||||||
|
// Not meant for us. Calling this will be a mess, but at least it might give us some information.
|
||||||
|
f(gc)
|
||||||
fail()
|
fail()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -554,11 +568,10 @@ func (app *appContext) InviteProxy(gc *gin.Context) {
|
|||||||
"jfLink": jfLink,
|
"jfLink": jfLink,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
inv, ok := app.storage.GetInvitesKey(code)
|
delete(invKeys, key)
|
||||||
if ok {
|
app.confirmationKeysLock.Lock()
|
||||||
delete(inv.ConfirmationKeys, key)
|
app.ConfirmationKeys[code] = invKeys
|
||||||
app.storage.SetInvitesKey(code, inv)
|
app.confirmationKeysLock.Unlock()
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
email := ""
|
email := ""
|
||||||
|
Loading…
Reference in New Issue
Block a user