satellite/admin: functionality to disable account bot restriction

Added new admin functionality to disable account bot restriction by activating it.
This must be used for accounts with status PendingBotVerification.

Note: PendingBotVerification status is automatically applied for accounts with high captcha score right after activation.

Issue:
https://github.com/storj/storj-private/issues/503

Change-Id: I4c9ee834075a7abaf221ac054a455a8d27debf40
This commit is contained in:
Vitalii 2023-11-29 20:47:15 +02:00 committed by Vitalii Shpital
parent 594b0933f1
commit b776382f18
5 changed files with 90 additions and 0 deletions

View File

@ -29,6 +29,7 @@ Requires setting `Authorization` header for requests.
* [GET /api/users/pending-deletion](#get-apiuserspending-deletion)
* [PATCH /api/users/{user-email}/geofence](#patch-apiusersuser-emailgeofence)
* [DELETE /api/users/{user-email}/geofence](#delete-apiusersuser-emailgeofence)
* [PATCH /api/users/{user-email}/activate-account/disable-bot-restriction](#patch-apiusersuser-emailactivate-accountdisable-bot-restriction)
* [OAuth Client Management](#oauth-client-management)
* [POST /api/oauth/clients](#post-apioauthclients)
* [PUT /api/oauth/clients/{id}](#put-apioauthclientsid)
@ -235,6 +236,10 @@ Example request:
Removes the account level geofence for the user.
#### PATCH /api/users/{user-email}/activate-account/disable-bot-restriction
Disables account bot restriction by activating it. Used only for accounts with PendingBotVerification status.
### OAuth Client Management
Manages oauth clients known to the Satellite.

View File

@ -140,6 +140,7 @@ func NewServer(
fullAccessAPI.HandleFunc("/users/{useremail}", server.updateUser).Methods("PUT")
fullAccessAPI.HandleFunc("/users/{useremail}", server.deleteUser).Methods("DELETE")
fullAccessAPI.HandleFunc("/users/{useremail}/mfa", server.disableUserMFA).Methods("DELETE")
fullAccessAPI.HandleFunc("/users/{useremail}/activate-account/disable-bot-restriction", server.disableBotRestriction).Methods("PATCH")
fullAccessAPI.HandleFunc("/users/{useremail}/useragent", server.updateUsersUserAgent).Methods("PATCH")
fullAccessAPI.HandleFunc("/users/{useremail}/geofence", server.createGeofenceForAccount).Methods("PATCH")
fullAccessAPI.HandleFunc("/users/{useremail}/geofence", server.deleteGeofenceForAccount).Methods("DELETE")

View File

@ -452,6 +452,17 @@ Blank fields will not be updated.`,
}) as Promise<null>;
}
},
{
name: 'activate account/disable bot restriction',
desc: 'disables account bot restriction by activating it. Must be used only for accounts with PendingBotVerification status.',
params: [['email', new InputText('email', true)]],
func: async (email: string): Promise<null> => {
return this.fetch(
'PATCH',
`users/${email}/activate-account/disable-bot-restriction`
) as Promise<null>;
}
},
{
name: 'disable MFA',
desc: "Disable user's mulifactor authentication",

View File

@ -1055,6 +1055,42 @@ func (server *Server) createGeofenceForAccount(w http.ResponseWriter, r *http.Re
server.setGeofenceForUser(w, r, placement)
}
func (server *Server) disableBotRestriction(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
userEmail, ok := vars["useremail"]
if !ok {
sendJSONError(w, "user-email missing", "", http.StatusBadRequest)
return
}
user, err := server.db.Console().Users().GetByEmail(ctx, userEmail)
if errors.Is(err, sql.ErrNoRows) {
sendJSONError(w, fmt.Sprintf("user with email %q does not exist", userEmail),
"", http.StatusNotFound)
return
}
if err != nil {
sendJSONError(w, "failed to get user details",
err.Error(), http.StatusInternalServerError)
return
}
if user.Status != console.PendingBotVerification {
sendJSONError(w, fmt.Sprintf("user with email %q must have PendingBotVerification status to disable bot restriction", userEmail),
"", http.StatusBadRequest)
return
}
activeStatus := console.Active
if err = server.db.Console().Users().Update(ctx, user.ID, console.UpdateUserRequest{Status: &activeStatus}); err != nil {
sendJSONError(w, "unable to set user status to active",
err.Error(), http.StatusInternalServerError)
return
}
}
func (server *Server) deleteGeofenceForAccount(w http.ResponseWriter, r *http.Request) {
server.setGeofenceForUser(w, r, storj.DefaultPlacement)
}

View File

@ -369,6 +369,43 @@ func TestDisableMFA(t *testing.T) {
})
}
func TestDisableBotRestriction(t *testing.T) {
testplanet.Run(t, testplanet.Config{
SatelliteCount: 1,
StorageNodeCount: 0,
UplinkCount: 1,
Reconfigure: testplanet.Reconfigure{
Satellite: func(_ *zap.Logger, _ int, config *satellite.Config) {
config.Admin.Address = "127.0.0.1:0"
},
},
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
address := planet.Satellites[0].Admin.Admin.Listener.Addr()
user, err := planet.Satellites[0].DB.Console().Users().GetByEmail(ctx, planet.Uplinks[0].Projects[0].Owner.Email)
require.NoError(t, err)
// Error on try set active status for a user with non-PendingBotVerification status.
link := fmt.Sprintf("http://"+address.String()+"/api/users/%s/activate-account/disable-bot-restriction", user.Email)
expectedBody := fmt.Sprintf("{\"error\":\"user with email \\\"%s\\\" must have PendingBotVerification status to disable bot restriction\",\"detail\":\"\"}", user.Email)
body := assertReq(ctx, t, link, http.MethodPatch, "", http.StatusBadRequest, expectedBody, planet.Satellites[0].Config.Console.AuthToken)
require.NotZero(t, len(body))
// Set user status to not active.
botStatus := console.PendingBotVerification
err = planet.Satellites[0].DB.Console().Users().Update(ctx, user.ID, console.UpdateUserRequest{Status: &botStatus})
require.NoError(t, err)
// Set user status back to active.
body = assertReq(ctx, t, link, http.MethodPatch, "", http.StatusOK, "", planet.Satellites[0].Config.Console.AuthToken)
require.Len(t, body, 0)
// Ensure status is updated.
updatedUser, err := planet.Satellites[0].DB.Console().Users().Get(ctx, user.ID)
require.NoError(t, err)
require.Equal(t, console.Active, updatedUser.Status)
})
}
func TestBillingFreezeUnfreezeUser(t *testing.T) {
testplanet.Run(t, testplanet.Config{
SatelliteCount: 1,