[server] Added APIs for ops (#2864)

## Description

## Tests
This commit is contained in:
Neeraj Gupta
2024-08-24 15:40:14 +05:30
committed by GitHub
5 changed files with 102 additions and 3 deletions

View File

@@ -643,6 +643,8 @@ func main() {
adminAPI.POST("/user/disable-2fa", adminHandler.DisableTwoFactor)
adminAPI.POST("/user/update-referral", adminHandler.UpdateReferral)
adminAPI.POST("/user/disable-passkeys", adminHandler.RemovePasskeys)
adminAPI.POST("/user/update-email-mfa", adminHandler.UpdateEmailMFA)
adminAPI.POST("/user/add-ott", adminHandler.AddOtt)
adminAPI.POST("/user/close-family", adminHandler.CloseFamily)
adminAPI.PUT("/user/change-email", adminHandler.ChangeEmail)
adminAPI.DELETE("/user/delete", adminHandler.DeleteUser)

View File

@@ -3,6 +3,7 @@ package ente
import (
"errors"
"fmt"
"time"
)
// GetEmailsFromHashesRequest represents a request to convert hashes
@@ -23,8 +24,29 @@ type UpdateReferralCodeRequest struct {
Code string `json:"code" binding:"required"`
}
type AdminOttReq struct {
Email string `json:"email" binding:"required"`
Code string `json:"code" binding:"required"`
App App `json:"app" binding:"required"`
ExpiryTime int64 `json:"expiryTime" binding:"required"`
}
func (a AdminOttReq) Validate() error {
if !a.App.IsValid() {
return errors.New("invalid app")
}
if a.ExpiryTime < time.Now().UnixMicro() {
return errors.New("expiry time should be in future")
}
if len(a.Code) < 6 {
return errors.New("invalid code length, should be at least 6 digit")
}
return nil
}
type AdminOpsForUserRequest struct {
UserID int64 `json:"userID" binding:"required"`
UserID int64 `json:"userID" binding:"required"`
EmailMFA *bool `json:"emailMFA"`
}
// ReQueueItemRequest puts an item back into the queue for processing.

View File

@@ -281,6 +281,67 @@ func (h *AdminHandler) RemovePasskeys(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{})
}
func (h *AdminHandler) UpdateEmailMFA(c *gin.Context) {
var request ente.AdminOpsForUserRequest
if err := c.ShouldBindJSON(&request); err != nil {
handler.Error(c, stacktrace.Propagate(ente.ErrBadRequest, "Bad request"))
return
}
if request.EmailMFA == nil {
handler.Error(c, stacktrace.Propagate(ente.NewBadRequestWithMessage("emailMFA is required"), ""))
return
}
go h.DiscordController.NotifyAdminAction(
fmt.Sprintf("Admin (%d) updating email mfa (%v) for account %d", auth.GetUserID(c.Request.Header), request.EmailMFA, request.UserID))
logger := logrus.WithFields(logrus.Fields{
"user_id": request.UserID,
"admin_id": auth.GetUserID(c.Request.Header),
"req_id": requestid.Get(c),
"req_ctx": "disable_email_mfa",
})
logger.Info("Initiate remove passkeys")
err := h.UserController.UpdateEmailMFA(c, request.UserID, *request.EmailMFA)
if err != nil {
logger.WithError(err).Error("Failed to update email mfa")
handler.Error(c, stacktrace.Propagate(err, ""))
return
}
logger.Info("Email MFA successfully updated")
c.JSON(http.StatusOK, gin.H{})
}
func (h *AdminHandler) AddOtt(c *gin.Context) {
var request ente.AdminOttReq
if err := c.ShouldBindJSON(&request); err != nil {
handler.Error(c, stacktrace.Propagate(ente.ErrBadRequest, "Bad request"))
return
}
if err := request.Validate(); err != nil {
handler.Error(c, stacktrace.Propagate(ente.NewBadRequestWithMessage(err.Error()), "Bad request"))
return
}
go h.DiscordController.NotifyAdminAction(
fmt.Sprintf("Admin (%d) adding custom ott", auth.GetUserID(c.Request.Header)))
logger := logrus.WithFields(logrus.Fields{
"user_id": request.Email,
"code": request.Code,
"admin_id": auth.GetUserID(c.Request.Header),
"req_id": requestid.Get(c),
"req_ctx": "custom_ott",
})
err := h.UserController.AddAdminOtt(request)
if err != nil {
logger.WithError(err).Error("Failed to add ott")
handler.Error(c, stacktrace.Propagate(err, ""))
return
}
logger.Info("Success added ott")
c.JSON(http.StatusOK, gin.H{})
}
func (h *AdminHandler) UpdateFeatureFlag(c *gin.Context) {
var request ente.AdminUpdateKeyValueRequest
if err := c.ShouldBindJSON(&request); err != nil {

View File

@@ -134,6 +134,20 @@ func (c *UserController) SendEmailOTT(context *gin.Context, email string, purpos
return nil
}
func (c *UserController) AddAdminOtt(req ente.AdminOttReq) error {
emailHash, err := crypto.GetHash(req.Email, c.HashingKey)
if err != nil {
log.WithError(err).Error("Failed to get hash")
return nil
}
err = c.UserAuthRepo.AddOTT(emailHash, req.App, req.Code, req.ExpiryTime)
if err != nil {
log.WithError(err).Error("Failed to add ott")
return stacktrace.Propagate(err, "")
}
return nil
}
// verifyEmailOtt should be deprecated in favor of verifyEmailOttWithSession once clients are updated.
func (c *UserController) verifyEmailOtt(context *gin.Context, email string, ott string) error {
ott = strings.TrimSpace(ott)

View File

@@ -98,8 +98,8 @@ func sendViaSMTP(toEmails []string, fromName string, fromEmail string, subject s
err := smtp.SendMail(smtpServer+":"+smtpPort, auth, fromEmail, []string{toEmail}, []byte(emailMessage))
if err != nil {
errMsg := err.Error()
for _, knownError := range knownInvalidEmailErrors {
if strings.Contains(errMsg, knownError) {
for i := range knownInvalidEmailErrors {
if strings.Contains(errMsg, knownInvalidEmailErrors[i]) {
return stacktrace.Propagate(ente.NewBadRequestWithMessage(fmt.Sprintf("Invalid email %s", toEmail)), errMsg)
}
}