Add API to get account two recovery status

This commit is contained in:
Neeraj Gupta 2024-03-05 09:43:25 +05:30 committed by Neeraj Gupta
parent 13bae268ec
commit 09a7d557d2
5 changed files with 84 additions and 0 deletions

View file

@ -5,6 +5,7 @@ import (
"database/sql" "database/sql"
b64 "encoding/base64" b64 "encoding/base64"
"fmt" "fmt"
"github.com/ente-io/museum/pkg/repo/accountrecovery"
"net/http" "net/http"
"os" "os"
"os/signal" "os/signal"
@ -137,6 +138,7 @@ func main() {
twoFactorRepo := &repo.TwoFactorRepository{DB: db, SecretEncryptionKey: secretEncryptionKeyBytes} twoFactorRepo := &repo.TwoFactorRepository{DB: db, SecretEncryptionKey: secretEncryptionKeyBytes}
userAuthRepo := &repo.UserAuthRepository{DB: db} userAuthRepo := &repo.UserAuthRepository{DB: db}
accountRecoveryRepo := &accountrecovery.Repository{Db: db}
billingRepo := &repo.BillingRepository{DB: db} billingRepo := &repo.BillingRepository{DB: db}
userEntityRepo := &userEntityRepo.Repository{DB: db} userEntityRepo := &userEntityRepo.Repository{DB: db}
locationTagRepository := &locationtagRepo.Repository{DB: db} locationTagRepository := &locationtagRepo.Repository{DB: db}
@ -304,6 +306,7 @@ func main() {
usageRepo, usageRepo,
userAuthRepo, userAuthRepo,
twoFactorRepo, twoFactorRepo,
accountRecoveryRepo,
passkeysRepo, passkeysRepo,
storagBonusRepo, storagBonusRepo,
fileRepo, fileRepo,
@ -429,6 +432,10 @@ func main() {
publicAPI.POST("/users/two-factor/remove", userHandler.RemoveTwoFactor) publicAPI.POST("/users/two-factor/remove", userHandler.RemoveTwoFactor)
publicAPI.POST("/users/two-factor/passkeys/begin", userHandler.BeginPasskeyAuthenticationCeremony) publicAPI.POST("/users/two-factor/passkeys/begin", userHandler.BeginPasskeyAuthenticationCeremony)
publicAPI.POST("/users/two-factor/passkeys/finish", userHandler.FinishPasskeyAuthenticationCeremony) publicAPI.POST("/users/two-factor/passkeys/finish", userHandler.FinishPasskeyAuthenticationCeremony)
privateAPI.GET("/users/two-factor/account-recovery-status", userHandler.GetAccountRecoveryStatus)
privateAPI.POST("/users/two-factor/passkeys/set-reset-challenge", userHandler.ConfigurePassKeyRecovery)
publicAPI.GET("/users/two-factor/passkeys/reset-challenge", userHandler.GetPasskeyResetChallenge)
publicAPI.POST("/users/two-factor/passkeys/reset", userHandler.ResetPasskey)
privateAPI.GET("/users/two-factor/status", userHandler.GetTwoFactorStatus) privateAPI.GET("/users/two-factor/status", userHandler.GetTwoFactorStatus)
privateAPI.POST("/users/two-factor/setup", userHandler.SetupTwoFactor) privateAPI.POST("/users/two-factor/setup", userHandler.SetupTwoFactor)
privateAPI.POST("/users/two-factor/enable", userHandler.EnableTwoFactor) privateAPI.POST("/users/two-factor/enable", userHandler.EnableTwoFactor)

View file

@ -244,6 +244,27 @@ func (h *UserHandler) GetTwoFactorStatus(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"status": status}) c.JSON(http.StatusOK, gin.H{"status": status})
} }
func (h *UserHandler) GetAccountRecoveryStatus(c *gin.Context) {
res, err := h.UserController.GetAccountRecoveryStatus(c)
if err != nil {
handler.Error(c, stacktrace.Propagate(err, ""))
return
}
c.JSON(http.StatusOK, res)
}
func (h *UserHandler) ConfigurePassKeyRecovery(c *gin.Context) {
c.JSON(http.StatusNotImplemented, gin.H{"message": "Not implemented"})
}
func (h *UserHandler) GetPasskeyResetChallenge(c *gin.Context) {
c.JSON(http.StatusNotImplemented, gin.H{"message": "Not implemented"})
}
func (h *UserHandler) ResetPasskey(c *gin.Context) {
c.JSON(http.StatusNotImplemented, gin.H{"message": "Not implemented"})
}
// SetupTwoFactor generates a two factor secret and sends it to user to setup his authenticator app with // SetupTwoFactor generates a two factor secret and sends it to user to setup his authenticator app with
func (h *UserHandler) SetupTwoFactor(c *gin.Context) { func (h *UserHandler) SetupTwoFactor(c *gin.Context) {
userID := auth.GetUserID(c.Request.Header) userID := auth.GetUserID(c.Request.Header)
@ -352,6 +373,16 @@ func (h *UserHandler) FinishPasskeyAuthenticationCeremony(c *gin.Context) {
c.JSON(http.StatusOK, response) c.JSON(http.StatusOK, response)
} }
func (h *UserHandler) IsPasskeyRecoveryEnabled(c *gin.Context) {
userID := auth.GetUserID(c.Request.Header)
response, err := h.UserController.GetKeyAttributeAndToken(c, userID)
if err != nil {
handler.Error(c, stacktrace.Propagate(err, ""))
return
}
c.JSON(http.StatusOK, response)
}
// DisableTwoFactor disables the two factor authentication for a user // DisableTwoFactor disables the two factor authentication for a user
func (h *UserHandler) DisableTwoFactor(c *gin.Context) { func (h *UserHandler) DisableTwoFactor(c *gin.Context) {
userID := auth.GetUserID(c.Request.Header) userID := auth.GetUserID(c.Request.Header)

View file

@ -0,0 +1,13 @@
package user
import (
"github.com/ente-io/museum/ente"
"github.com/ente-io/museum/pkg/utils/auth"
"github.com/gin-gonic/gin"
)
// GetAccountRecoveryStatus returns a user's passkey reset status
func (c *UserController) GetAccountRecoveryStatus(ctx *gin.Context) (*ente.AccountRecoveryStatus, error) {
userID := auth.GetUserID(ctx.Request.Header)
return c.AccountRecoveryRepo.GetAccountRecoveryStatus(userID)
}

View file

@ -3,6 +3,7 @@ package user
import ( import (
"errors" "errors"
"fmt" "fmt"
"github.com/ente-io/museum/pkg/repo/accountrecovery"
"strings" "strings"
cache2 "github.com/ente-io/museum/ente/cache" cache2 "github.com/ente-io/museum/ente/cache"
@ -30,6 +31,7 @@ import (
// UserController exposes request handlers for all user related requests // UserController exposes request handlers for all user related requests
type UserController struct { type UserController struct {
UserRepo *repo.UserRepository UserRepo *repo.UserRepository
AccountRecoveryRepo *accountrecovery.Repository
UsageRepo *repo.UsageRepository UsageRepo *repo.UsageRepository
UserAuthRepo *repo.UserAuthRepository UserAuthRepo *repo.UserAuthRepository
TwoFactorRepo *repo.TwoFactorRepository TwoFactorRepo *repo.TwoFactorRepository
@ -99,6 +101,7 @@ func NewUserController(
usageRepo *repo.UsageRepository, usageRepo *repo.UsageRepository,
userAuthRepo *repo.UserAuthRepository, userAuthRepo *repo.UserAuthRepository,
twoFactorRepo *repo.TwoFactorRepository, twoFactorRepo *repo.TwoFactorRepository,
accountRecoveryRepo *accountrecovery.Repository,
passkeyRepo *passkey.Repository, passkeyRepo *passkey.Repository,
storageBonusRepo *storageBonusRepo.Repository, storageBonusRepo *storageBonusRepo.Repository,
fileRepo *repo.FileRepository, fileRepo *repo.FileRepository,
@ -121,6 +124,7 @@ func NewUserController(
return &UserController{ return &UserController{
UserRepo: userRepo, UserRepo: userRepo,
UsageRepo: usageRepo, UsageRepo: usageRepo,
AccountRecoveryRepo: accountRecoveryRepo,
UserAuthRepo: userAuthRepo, UserAuthRepo: userAuthRepo,
StorageBonusRepo: storageBonusRepo, StorageBonusRepo: storageBonusRepo,
TwoFactorRepo: twoFactorRepo, TwoFactorRepo: twoFactorRepo,

View file

@ -0,0 +1,29 @@
package accountrecovery
import (
"database/sql"
"github.com/ente-io/museum/ente"
)
type Repository struct {
Db *sql.DB
}
// GetAccountRecoveryStatus returns `ente.AccountRecoveryStatus` for a user
func (r *Repository) GetAccountRecoveryStatus(userID int64) (*ente.AccountRecoveryStatus, error) {
var isAdminResetEnabled bool
var resetKey sql.NullString
row := r.Db.QueryRow("SELECT enable_admin_mfa_reset, pass_key_reset_key FROM account_recovery WHERE user_id = $1", userID)
err := row.Scan(&isAdminResetEnabled, &resetKey)
if err != nil {
if err == sql.ErrNoRows {
// by default, admin
return &ente.AccountRecoveryStatus{
AllowAdminReset: true,
IsPassKeyResetEnabled: false,
}, nil
}
return nil, err
}
return &ente.AccountRecoveryStatus{AllowAdminReset: isAdminResetEnabled, IsPassKeyResetEnabled: resetKey.Valid}, nil
}