2024-12-21 17:15:50 +05:30

98 lines
3.2 KiB
Go

package emergency
import (
"github.com/ente-io/museum/ente"
"github.com/ente-io/museum/pkg/repo/emergency"
"github.com/ente-io/stacktrace"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
log "github.com/sirupsen/logrus"
)
func (c *Controller) GetRecoveryInfo(ctx *gin.Context,
userID int64,
sessionID uuid.UUID,
) (*string, *ente.KeyAttributes, error) {
contact, err := c.checkRecoveryAndGetContact(ctx, userID, sessionID)
if err != nil {
return nil, nil, err
}
recoveryTarget, err := c.UserRepo.Get(contact.UserID)
if err != nil {
return nil, nil, err
}
keyAttr, err := c.UserRepo.GetKeyAttributes(recoveryTarget.ID)
if err != nil {
return nil, nil, err
}
return contact.EncryptedKey, &keyAttr, nil
}
func (c *Controller) InitChangePassword(ctx *gin.Context, userID int64, request ente.RecoverySrpSetupRequest) (*ente.SetupSRPResponse, error) {
sessionID := request.RecoveryID
contact, err := c.checkRecoveryAndGetContact(ctx, userID, sessionID)
if err != nil {
return nil, err
}
resp, err := c.UserCtrl.SetupSRP(ctx, contact.UserID, request.SetUpSRPReq)
if err != nil {
return nil, stacktrace.Propagate(err, "")
}
return resp, nil
}
func (c *Controller) ChangePassword(ctx *gin.Context, userID int64, request ente.RecoveryUpdateSRPAndKeysRequest) (*ente.UpdateSRPSetupResponse, error) {
sessionID := request.RecoveryID
contact, err := c.checkRecoveryAndGetContact(ctx, userID, sessionID)
if err != nil {
return nil, err
}
// disable 2fa
if disableErr := c.UserCtrl.DisableTwoFactor(contact.UserID); disableErr != nil {
return nil, stacktrace.Propagate(disableErr, "failed to disable 2fa")
}
if disableErr := c.PasskeyController.RemovePasskey2FA(contact.UserID); disableErr != nil {
return nil, stacktrace.Propagate(disableErr, "failed to disable passkey")
}
resp, err := c.UserCtrl.UpdateSrpAndKeyAttributes(ctx, contact.UserID, request.UpdateSrp, false)
if err != nil {
return nil, stacktrace.Propagate(err, "")
}
hasUpdate, err := c.Repo.UpdateRecoveryStatusForID(ctx, sessionID, ente.RecoveryStatusRecovered)
if err != nil {
return nil, stacktrace.Propagate(err, "failed to update recovery status")
}
if !hasUpdate {
log.WithField("userID", userID).WithField("req", request).
Warn("no row updated while rejecting recovery")
} else {
go c.sendRecoveryNotification(ctx, contact.UserID, contact.EmergencyContactID, ente.RecoveryStatusRecovered)
}
return resp, nil
}
func (c *Controller) checkRecoveryAndGetContact(ctx *gin.Context,
userID int64,
sessionID uuid.UUID) (*emergency.ContactRow, error) {
recoverRow, err := c.Repo.GetRecoverRowByID(ctx, sessionID)
if err != nil {
return nil, stacktrace.Propagate(err, "")
}
if recoverRow.EmergencyContactID != userID {
return nil, stacktrace.Propagate(ente.ErrPermissionDenied, "only the emergency contact can get recovery info")
}
if err = recoverRow.CanRecover(); err != nil {
return nil, stacktrace.Propagate(ente.NewBadRequestWithMessage(err.Error()), "")
}
contact, err := c.Repo.GetActiveEmergencyContact(ctx, recoverRow.UserID, recoverRow.EmergencyContactID)
if err != nil {
return nil, stacktrace.Propagate(err, "")
}
if contact.EncryptedKey == nil {
return nil, stacktrace.Propagate(ente.ErrNotFound, "no encrypted key found")
}
return contact, nil
}