diff --git a/cli/cmd/admin.go b/cli/cmd/admin.go index 8a2d7f006b..f56fea06eb 100644 --- a/cli/cmd/admin.go +++ b/cli/cmd/admin.go @@ -58,6 +58,27 @@ var _disable2faCmd = &cobra.Command{ }, } +var _disablePasskeyCmd = &cobra.Command{ + Use: "disable-passkey", + Short: "Disable passkey for a user", + RunE: func(cmd *cobra.Command, args []string) error { + recoverWithLog() + var flags = &model.AdminActionForUser{} + cmd.Flags().VisitAll(func(f *pflag.Flag) { + if f.Name == "admin-user" { + flags.AdminEmail = f.Value.String() + } + if f.Name == "user" { + flags.UserEmail = f.Value.String() + } + }) + if flags.UserEmail == "" { + return fmt.Errorf("user email is required") + } + return ctrl.DisablePasskeys(context.Background(), *flags) + }, +} + var _deleteUser = &cobra.Command{ Use: "delete-user", Short: "Delete a user", @@ -130,11 +151,13 @@ func init() { _listUsers.Flags().StringP("admin-user", "a", "", "The email of the admin user. ") _disable2faCmd.Flags().StringP("admin-user", "a", "", "The email of the admin user. ") _disable2faCmd.Flags().StringP("user", "u", "", "The email of the user to disable 2FA for. (required)") + _disablePasskeyCmd.Flags().StringP("admin-user", "a", "", "The email of the admin user. ") + _disablePasskeyCmd.Flags().StringP("user", "u", "", "The email of the user to disable passkey for. (required)") _deleteUser.Flags().StringP("admin-user", "a", "", "The email of the admin user. ") _deleteUser.Flags().StringP("user", "u", "", "The email of the user to delete. (required)") _updateFreeUserStorage.Flags().StringP("admin-user", "a", "", "The email of the admin user.") _updateFreeUserStorage.Flags().StringP("user", "u", "", "The email of the user to update subscription for. (required)") // add a flag with no value --no-limit _updateFreeUserStorage.Flags().String("no-limit", "True", "When true, sets 100TB as storage limit, and expiry to current date + 100 years") - _adminCmd.AddCommand(_userDetailsCmd, _disable2faCmd, _updateFreeUserStorage, _listUsers, _deleteUser) + _adminCmd.AddCommand(_userDetailsCmd, _disable2faCmd, _disablePasskeyCmd, _updateFreeUserStorage, _listUsers, _deleteUser) } diff --git a/cli/internal/api/admin.go b/cli/internal/api/admin.go index 9e0bcb90a7..3511876cd1 100644 --- a/cli/internal/api/admin.go +++ b/cli/internal/api/admin.go @@ -88,6 +88,29 @@ func (c *Client) Disable2Fa(ctx context.Context, userID int64) error { return nil } +func (c *Client) DisablePassKeyMFA(ctx context.Context, userID int64) error { + var res interface{} + + payload := map[string]interface{}{ + "userID": userID, + } + r, err := c.restClient.R(). + SetContext(ctx). + SetResult(&res). + SetBody(payload). + Post("/admin/user/disable-passkeys") + if err != nil { + return err + } + if r.IsError() { + return &ApiError{ + StatusCode: r.StatusCode(), + Message: r.String(), + } + } + return nil +} + func (c *Client) UpdateFreePlanSub(ctx context.Context, userDetails *models.UserDetails, storageInBytes int64, expiryTimeInMicro int64) error { var res interface{} if userDetails.Subscription.ProductID != "free" { diff --git a/cli/pkg/admin_actions.go b/cli/pkg/admin_actions.go index 0105cdc199..44af3c27a9 100644 --- a/cli/pkg/admin_actions.go +++ b/cli/pkg/admin_actions.go @@ -82,6 +82,27 @@ func (c *ClICtrl) Disable2FA(ctx context.Context, params model.AdminActionForUse return nil } +func (c *ClICtrl) DisablePasskeys(ctx context.Context, params model.AdminActionForUser) error { + accountCtx, err := c.buildAdminContext(ctx, params.AdminEmail) + if err != nil { + return err + } + userDetails, err := c.Client.GetUserIdFromEmail(accountCtx, params.UserEmail) + if err != nil { + return err + } + err = c.Client.DisablePassKeyMFA(accountCtx, userDetails.User.ID) + if err != nil { + if apiErr, ok := err.(*api.ApiError); ok && apiErr.StatusCode == 400 && strings.Contains(apiErr.Message, "Token is too old") { + fmt.Printf("Error: Old admin token, please re-authenticate using `ente account add` \n") + return nil + } + return err + } + fmt.Println("Successfully disabled passkey for user") + return nil +} + func (c *ClICtrl) UpdateFreeStorage(ctx context.Context, params model.AdminActionForUser, noLimit bool) error { accountCtx, err := c.buildAdminContext(ctx, params.AdminEmail) if err != nil {