Refactor + bug fixes

This commit is contained in:
Neeraj Gupta 2024-03-07 18:14:04 +05:30 committed by Neeraj Gupta
parent 980ab6c49c
commit 7f66714d96
7 changed files with 27 additions and 31 deletions

View file

@ -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)

View file

@ -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"`
}

View file

@ -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,

View file

@ -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, ""))

View file

@ -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, "")

View file

@ -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, "")

View file

@ -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
}