Refactor + bug fixes
This commit is contained in:
parent
980ab6c49c
commit
7f66714d96
7 changed files with 27 additions and 31 deletions
|
@ -434,7 +434,7 @@ func main() {
|
|||
publicAPI.POST("/users/two-factor/passkeys/begin", userHandler.BeginPasskeyAuthenticationCeremony)
|
||||
publicAPI.POST("/users/two-factor/passkeys/finish", userHandler.FinishPasskeyAuthenticationCeremony)
|
||||
privateAPI.GET("/users/two-factor/recovery-status", userHandler.GetTwoFactorRecoveryStatus)
|
||||
privateAPI.POST("/users/two-factor/passkeys/set-skip-challenge", userHandler.ConfigurePassKeySkipChallenge)
|
||||
privateAPI.POST("/users/two-factor/passkeys/configure-reset", userHandler.ConfigurePassKeySkipChallenge)
|
||||
privateAPI.GET("/users/two-factor/status", userHandler.GetTwoFactorStatus)
|
||||
privateAPI.POST("/users/two-factor/setup", userHandler.SetupTwoFactor)
|
||||
privateAPI.POST("/users/two-factor/enable", userHandler.EnableTwoFactor)
|
||||
|
|
|
@ -13,8 +13,8 @@ type Passkey struct {
|
|||
|
||||
var MaxPasskeys = 10
|
||||
|
||||
type ConfigurePassKeyRecoveryRequest struct {
|
||||
SkipSecret string `json:"resetSecret" binding:"required"`
|
||||
type SetPassKeyRecoveryRequest struct {
|
||||
Secret uuid.UUID `json:"secret" binding:"required"`
|
||||
// The UserSecretCipher has SkipSecret encrypted with the user's recoveryKey
|
||||
// If the user sends the correct UserSecretCipher, we can be sure that the user has the recoveryKey,
|
||||
// and we can allow the user to recover their MFA.
|
||||
|
@ -25,11 +25,6 @@ type ConfigurePassKeyRecoveryRequest struct {
|
|||
type TwoFactorRecoveryStatus struct {
|
||||
// AllowAdminReset is a boolean that determines if the admin can reset the user's MFA.
|
||||
// If true, in the event that the user loses their MFA device, the admin can reset the user's MFA.
|
||||
AllowAdminReset bool `json:"allowAdminReset" binding:"required"`
|
||||
IsPassKeySkipEnabled bool `json:"isPassKeyResetEnabled" binding:"required"`
|
||||
}
|
||||
|
||||
type SkipPassKeyRequest struct {
|
||||
SessionID string `json:"sessionID" binding:"required"`
|
||||
SkipSecret string `json:"resetSecret" binding:"required"`
|
||||
AllowAdminReset bool `json:"allowAdminReset" binding:"required"`
|
||||
IsPassKeyRecoveryEnabled bool `json:"isPassKeyRecoveryEnabled" binding:"required"`
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
CREATE TABLE IF NOT EXISTS two_factor_recovery (
|
||||
user_id bigint NOT NULL,
|
||||
user_id bigint NOT NULL PRIMARY KEY,
|
||||
-- if false, the support team team will not be able to reset the MFA for the user
|
||||
enable_admin_mfa_reset boolean NOT NULL DEFAULT true,
|
||||
server_passkey_secret_data bytea,
|
||||
|
|
|
@ -256,7 +256,7 @@ func (h *UserHandler) GetTwoFactorRecoveryStatus(c *gin.Context) {
|
|||
// ConfigurePassKeySkipChallenge configures the passkey skip challenge for a user. In case the user does not
|
||||
// have access to passkey, the user can bypass the passkey by providing the recovery key
|
||||
func (h *UserHandler) ConfigurePassKeySkipChallenge(c *gin.Context) {
|
||||
var request ente.ConfigurePassKeyRecoveryRequest
|
||||
var request ente.SetPassKeyRecoveryRequest
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
handler.Error(c, stacktrace.Propagate(err, ""))
|
||||
return
|
||||
|
@ -402,10 +402,10 @@ func (h *UserHandler) DisableTwoFactor(c *gin.Context) {
|
|||
// recoveryKeyEncryptedTwoFactorSecret for the user to decrypt it and make twoFactor removal api call
|
||||
func (h *UserHandler) RecoverTwoFactor(c *gin.Context) {
|
||||
sessionID := c.Query("sessionID")
|
||||
twoFactorType := c.Query("type")
|
||||
twoFactorType := c.Query("twoFactorType")
|
||||
var response *ente.TwoFactorRecoveryResponse
|
||||
var err error
|
||||
if twoFactorType == "passkey" {
|
||||
if twoFactorType == "passKey" {
|
||||
response, err = h.UserController.GetPasskeyRecoveryResponse(c, sessionID)
|
||||
} else {
|
||||
response, err = h.UserController.RecoverTwoFactor(sessionID)
|
||||
|
@ -427,10 +427,10 @@ func (h *UserHandler) RemoveTwoFactor(c *gin.Context) {
|
|||
}
|
||||
var response *ente.TwoFactorAuthorizationResponse
|
||||
var err error
|
||||
if request.TwoFactorType == "passkey" {
|
||||
response, err = h.UserController.SkipPassKey(c, &request)
|
||||
if request.TwoFactorType == "passKey" {
|
||||
response, err = h.UserController.SkipPasskeyVerification(c, &request)
|
||||
} else {
|
||||
response, err = h.UserController.RemoveTwoFactor(c, request.SessionID, request.Secret)
|
||||
response, err = h.UserController.RemoveTOTPTwoFactor(c, request.SessionID, request.Secret)
|
||||
}
|
||||
if err != nil {
|
||||
handler.Error(c, stacktrace.Propagate(err, ""))
|
||||
|
|
|
@ -13,9 +13,9 @@ func (c *UserController) GetTwoFactorRecoveryStatus(ctx *gin.Context) (*ente.Two
|
|||
return c.TwoFactorRecoveryRepo.GetStatus(userID)
|
||||
}
|
||||
|
||||
func (c *UserController) ConfigurePassKeySkip(ctx *gin.Context, req *ente.ConfigurePassKeyRecoveryRequest) error {
|
||||
func (c *UserController) ConfigurePassKeySkip(ctx *gin.Context, req *ente.SetPassKeyRecoveryRequest) error {
|
||||
userID := auth.GetUserID(ctx.Request.Header)
|
||||
return c.TwoFactorRecoveryRepo.ConfigurePassKeySkipChallenge(ctx, userID, req)
|
||||
return c.TwoFactorRecoveryRepo.SetPassKeyRecovery(ctx, userID, req)
|
||||
}
|
||||
|
||||
func (c *UserController) GetPasskeyRecoveryResponse(ctx *gin.Context, passKeySessionID string) (*ente.TwoFactorRecoveryResponse, error) {
|
||||
|
@ -27,7 +27,7 @@ func (c *UserController) GetPasskeyRecoveryResponse(ctx *gin.Context, passKeySes
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !recoveryStatus.IsPassKeySkipEnabled {
|
||||
if !recoveryStatus.IsPassKeyRecoveryEnabled {
|
||||
return nil, ente.NewBadRequestWithMessage("Passkey reset is not configured")
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ func (c *UserController) GetPasskeyRecoveryResponse(ctx *gin.Context, passKeySes
|
|||
return result, nil
|
||||
}
|
||||
|
||||
func (c *UserController) SkipPassKey(context *gin.Context, req *ente.TwoFactorRemovalRequest) (*ente.TwoFactorAuthorizationResponse, error) {
|
||||
func (c *UserController) SkipPasskeyVerification(context *gin.Context, req *ente.TwoFactorRemovalRequest) (*ente.TwoFactorAuthorizationResponse, error) {
|
||||
userID, err := c.PasskeyRepo.GetUserIDWithPasskeyTwoFactorSession(req.SessionID)
|
||||
if err != nil {
|
||||
return nil, stacktrace.Propagate(err, "")
|
||||
|
|
|
@ -143,9 +143,9 @@ func (c *UserController) RecoverTwoFactor(sessionID string) (*ente.TwoFactorReco
|
|||
return &response, nil
|
||||
}
|
||||
|
||||
// RemoveTwoFactor handles two factor deactivation request if user lost his device
|
||||
// RemoveTOTPTwoFactor handles two factor deactivation request if user lost his device
|
||||
// by authenticating him using his twoFactorsessionToken and twoFactor secret
|
||||
func (c *UserController) RemoveTwoFactor(context *gin.Context, sessionID string, secret string) (*ente.TwoFactorAuthorizationResponse, error) {
|
||||
func (c *UserController) RemoveTOTPTwoFactor(context *gin.Context, sessionID string, secret string) (*ente.TwoFactorAuthorizationResponse, error) {
|
||||
userID, err := c.TwoFactorRepo.GetUserIDWithTwoFactorSession(sessionID)
|
||||
if err != nil {
|
||||
return nil, stacktrace.Propagate(err, "")
|
||||
|
|
|
@ -25,24 +25,25 @@ func (r *Repository) GetStatus(userID int64) (*ente.TwoFactorRecoveryStatus, err
|
|||
if err == sql.ErrNoRows {
|
||||
// by default, admin
|
||||
return &ente.TwoFactorRecoveryStatus{
|
||||
AllowAdminReset: true,
|
||||
IsPassKeySkipEnabled: false,
|
||||
AllowAdminReset: true,
|
||||
IsPassKeyRecoveryEnabled: false,
|
||||
}, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &ente.TwoFactorRecoveryStatus{AllowAdminReset: isAdminResetEnabled, IsPassKeySkipEnabled: resetKey.Valid}, nil
|
||||
return &ente.TwoFactorRecoveryStatus{AllowAdminReset: isAdminResetEnabled, IsPassKeyRecoveryEnabled: resetKey.Valid}, nil
|
||||
}
|
||||
|
||||
func (r *Repository) ConfigurePassKeySkipChallenge(ctx context.Context, userID int64, req *ente.ConfigurePassKeyRecoveryRequest) error {
|
||||
serveEncPassKey, encRrr := crypto.Encrypt(req.SkipSecret, r.SecretEncryptionKey)
|
||||
func (r *Repository) SetPassKeyRecovery(ctx context.Context, userID int64, req *ente.SetPassKeyRecoveryRequest) error {
|
||||
serveEncPassKey, encRrr := crypto.Encrypt(req.Secret.String(), r.SecretEncryptionKey)
|
||||
if encRrr != nil {
|
||||
return stacktrace.Propagate(encRrr, "failed to encrypt passkey secret")
|
||||
}
|
||||
_, err := r.Db.ExecContext(ctx, `INSERT INTO two_factor_recovery
|
||||
(user_id, server_passkey_secret_data, server_passkey_secret_nonce, user_passkey_secret_data, user_passkey_secret_nonce))
|
||||
VALUES ($1, $2,$3,$4,$5) ON CONFLICT (user_id)
|
||||
DO UPDATE SET server_passkey_secret_data = $2, server_passkey_secret_nonce = $3, user_passkey_secret_data=$4,user_passkey_secret_nonce=$5`,
|
||||
(user_id, server_passkey_secret_data, server_passkey_secret_nonce, user_passkey_secret_data, user_passkey_secret_nonce)
|
||||
VALUES ($1, $2, $3, $4, $5) ON CONFLICT (user_id)
|
||||
DO UPDATE SET server_passkey_secret_data = $2, server_passkey_secret_nonce = $3, user_passkey_secret_data = $4, user_passkey_secret_nonce = $5
|
||||
WHERE two_factor_recovery.user_passkey_secret_data IS NULL AND two_factor_recovery.server_passkey_secret_data IS NULL`,
|
||||
userID, serveEncPassKey.Cipher, serveEncPassKey.Nonce, req.UserSecretCipher, req.UserSecretNonce)
|
||||
return err
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue