Copy passkey auth fix from Mk plugin repo
This commit is contained in:
parent
90667d96c7
commit
1dbdec1905
4 changed files with 250 additions and 1 deletions
233
server/middlewareFixPasskeyPerms.go
Normal file
233
server/middlewareFixPasskeyPerms.go
Normal file
|
@ -0,0 +1,233 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog/hlog"
|
||||
"gitlab.com/mstarongitlab/goutils/other"
|
||||
|
||||
"gitlab.com/mstarongitlab/linstrom/storage"
|
||||
)
|
||||
|
||||
func forceCorrectPasskeyAuthFlowMiddleware(
|
||||
handler http.Handler,
|
||||
) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
log := hlog.FromRequest(r)
|
||||
// Don't fuck with the request if not intended for starting to register or login
|
||||
if strings.HasSuffix(r.URL.Path, "loginFinish") {
|
||||
log.Debug().Msg("Request to finish login method, doing nothing")
|
||||
handler.ServeHTTP(w, r)
|
||||
return
|
||||
} else if strings.HasSuffix(r.URL.Path, "registerFinish") {
|
||||
handler.ServeHTTP(w, r)
|
||||
// Force unset session cookie here
|
||||
w.Header().Del("Set-Cookie")
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: "sid",
|
||||
Value: "",
|
||||
Path: "",
|
||||
MaxAge: 0,
|
||||
Expires: time.UnixMilli(0),
|
||||
})
|
||||
return
|
||||
} else if strings.HasSuffix(r.URL.Path, "loginBegin") {
|
||||
fuckWithLoginRequest(w, r, handler)
|
||||
} else if strings.HasSuffix(r.URL.Path, "registerBegin") {
|
||||
fuckWithRegisterRequest(w, r, handler)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func fuckWithRegisterRequest(
|
||||
w http.ResponseWriter,
|
||||
r *http.Request,
|
||||
nextHandler http.Handler,
|
||||
) {
|
||||
log := hlog.FromRequest(r)
|
||||
log.Debug().Msg("Messing with register start request")
|
||||
store := StorageFromRequest(w, r)
|
||||
if store == nil {
|
||||
return
|
||||
}
|
||||
cookie, cookieErr := r.Cookie("sid")
|
||||
var username struct {
|
||||
Username string `json:"username"`
|
||||
}
|
||||
body, _ := io.ReadAll(r.Body)
|
||||
log.Debug().Bytes("body", body).Msg("Body of auth begin request")
|
||||
err := json.Unmarshal(body, &username)
|
||||
if err != nil {
|
||||
other.HttpErr(w, HttpErrIdBadRequest, "Not a username json object", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if cookieErr == nil {
|
||||
// Already authenticated, overwrite username to logged in account's name
|
||||
// Get session from cookie
|
||||
log.Debug().Msg("Session token exists, force overwriting username of register request")
|
||||
session, ok := store.GetSession(cookie.Value)
|
||||
if !ok {
|
||||
log.Error().Str("session-id", cookie.Value).Msg("Passkey session missing")
|
||||
other.HttpErr(
|
||||
w,
|
||||
HttpErrIdDbFailure,
|
||||
"Passkey session missing",
|
||||
http.StatusInternalServerError,
|
||||
)
|
||||
return
|
||||
}
|
||||
acc, err := store.FindAccountByPasskeyId(session.UserID)
|
||||
// Assume account must exist if a session for it exists
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to get account from passkey id from session")
|
||||
other.HttpErr(
|
||||
w,
|
||||
HttpErrIdDbFailure,
|
||||
"Failed to get authenticated account",
|
||||
http.StatusInternalServerError,
|
||||
)
|
||||
return
|
||||
}
|
||||
// Replace whatever username may be given with username of logged in account
|
||||
newBody := strings.ReplaceAll(string(body), username.Username, acc.Username)
|
||||
// Assign to request
|
||||
r.Body = io.NopCloser(strings.NewReader(newBody))
|
||||
r.ContentLength = int64(len(newBody))
|
||||
// And pass on
|
||||
nextHandler.ServeHTTP(w, r)
|
||||
} else {
|
||||
// Not authenticated, ensure that no existing name is registered with
|
||||
_, err = store.FindLocalAccountByUsername(username.Username)
|
||||
switch err {
|
||||
case nil:
|
||||
// No error while getting account means account exists, refuse access
|
||||
log.Info().
|
||||
Str("username", username.Username).
|
||||
Msg("Account with same name already exists, preventing login")
|
||||
other.HttpErr(
|
||||
w,
|
||||
HttpErrIdAlreadyExists,
|
||||
"Account with that name already exists",
|
||||
http.StatusBadRequest,
|
||||
)
|
||||
case storage.ErrEntryNotFound:
|
||||
// Didn't find account with that name, give access
|
||||
log.Debug().
|
||||
Str("username", username.Username).
|
||||
Msg("No account with this username exists yet, passing through")
|
||||
// Copy original body since previous reader hit EOF
|
||||
r.Body = io.NopCloser(strings.NewReader(string(body)))
|
||||
r.ContentLength = int64(len(body))
|
||||
nextHandler.ServeHTTP(w, r)
|
||||
default:
|
||||
// Some other error, log it and return appropriate message
|
||||
log.Error().
|
||||
Err(err).
|
||||
Str("username", username.Username).
|
||||
Msg("Failed to check if account with username already exists")
|
||||
other.HttpErr(
|
||||
w,
|
||||
HttpErrIdDbFailure,
|
||||
"Failed to check if account with that name already exists",
|
||||
http.StatusInternalServerError,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func fuckWithLoginRequest(
|
||||
w http.ResponseWriter,
|
||||
r *http.Request,
|
||||
nextHandler http.Handler,
|
||||
) {
|
||||
log := hlog.FromRequest(r)
|
||||
log.Debug().Msg("Messing with login start request")
|
||||
store := StorageFromRequest(w, r)
|
||||
if store == nil {
|
||||
return
|
||||
}
|
||||
cookie, cookieErr := r.Cookie("sid")
|
||||
var username struct {
|
||||
Username string `json:"username"`
|
||||
}
|
||||
// Force ignore cookie for now
|
||||
_ = cookieErr
|
||||
var err error = errors.New("placeholder")
|
||||
if err == nil {
|
||||
// Someone is logged in, overwrite username with logged in account's one
|
||||
body, _ := io.ReadAll(r.Body)
|
||||
log.Debug().Bytes("body", body).Msg("Body of auth begin request")
|
||||
err := json.Unmarshal(body, &username)
|
||||
if err != nil {
|
||||
other.HttpErr(
|
||||
w,
|
||||
HttpErrIdBadRequest,
|
||||
"Not a username json object",
|
||||
http.StatusBadRequest,
|
||||
)
|
||||
return
|
||||
}
|
||||
session, ok := store.GetSession(cookie.Value)
|
||||
if !ok {
|
||||
log.Error().Str("session-id", cookie.Value).Msg("Passkey session missing")
|
||||
other.HttpErr(
|
||||
w,
|
||||
HttpErrIdDbFailure,
|
||||
"Passkey session missing",
|
||||
http.StatusInternalServerError,
|
||||
)
|
||||
return
|
||||
}
|
||||
acc, err := store.FindAccountByPasskeyId(session.UserID)
|
||||
// Assume account must exist if a session for it exists
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to get account from passkey id from session")
|
||||
other.HttpErr(
|
||||
w,
|
||||
HttpErrIdDbFailure,
|
||||
"Failed to get authenticated account",
|
||||
http.StatusInternalServerError,
|
||||
)
|
||||
return
|
||||
}
|
||||
// Replace whatever username may be given with username of logged in account
|
||||
newBody := strings.ReplaceAll(string(body), username.Username, acc.Username)
|
||||
// Assign to request
|
||||
r.Body = io.NopCloser(strings.NewReader(newBody))
|
||||
r.ContentLength = int64(len(newBody))
|
||||
// And pass on
|
||||
nextHandler.ServeHTTP(w, r)
|
||||
} else {
|
||||
// No one logged in, check if user exists to prevent creating a bugged account
|
||||
body, _ := io.ReadAll(r.Body)
|
||||
log.Debug().Bytes("body", body).Msg("Body of auth begin request")
|
||||
err := json.Unmarshal(body, &username)
|
||||
if err != nil {
|
||||
other.HttpErr(w, HttpErrIdBadRequest, "Not a username json object", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
_, err = store.FindLocalAccountByUsername(username.Username)
|
||||
switch err {
|
||||
case nil:
|
||||
// All good, account exists, keep going
|
||||
// Do nothing in this branch
|
||||
case storage.ErrEntryNotFound:
|
||||
// Account doesn't exist, catch it
|
||||
other.HttpErr(w, HttpErrIdNotFound, "Username not found", http.StatusNotFound)
|
||||
return
|
||||
default:
|
||||
// catch db failures
|
||||
log.Error().Err(err).Str("username", username.Username).Msg("Db failure while getting account")
|
||||
other.HttpErr(w, HttpErrIdDbFailure, "Failed to check for account in db", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
// Restore body as new reader of the same content
|
||||
r.Body = io.NopCloser(strings.NewReader(string(body)))
|
||||
nextHandler.ServeHTTP(w, r)
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue