Skip to content

Commit

Permalink
fix: add mfa status endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
Vilsol committed Jan 21, 2025
1 parent 8fa8744 commit 928bc10
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 0 deletions.
45 changes: 45 additions & 0 deletions src/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ import {
CreateBackupTOTPCodesRequest,
CreateBackupTOTPCodesResponse,
ResetTOTPRequest,
MfaStatusRequest,
MfaStatusResponse
} from '@restorecommerce/rc-grpc-clients/dist/generated-server/io/restorecommerce/user.js';
import {
Role,
Expand Down Expand Up @@ -3420,6 +3422,49 @@ export class UserService extends ServiceBase<UserListResponse, UserList> impleme
return this.makeRenderRequestMsg(user, emailSubject, emailBody,
dataBody, {}, user.email);
}

async mfaStatus(request: MfaStatusRequest, context: any): Promise<DeepPartial<MfaStatusResponse>> {
const subject = request.subject;
const users = await super.read(ReadRequest.fromPartial({
filters: [{
filters: [{
field: 'id',
operation: Filter_Operation.eq,
value: subject?.id
}]
}]
}), context);

if (!users || users.total_count === 0) {
this.logger.debug('user does not exist', { identifier: subject.id });
return returnOperationStatus(404, 'user does not exist');
} else if (users.total_count > 1) {
return returnOperationStatus(400, `Invalid identifier provided for mfa status, multiple users found for identifier ${subject.id}`);
}

const user = users.items[0].payload;
let acsResponse: DecisionResponse;
try {
acsResponse = await checkAccessRequest({
...context,
subject,
resources: { id: user.id, meta: user.meta }
}, [{ resource: 'user', id: user.id, property: ['totp_recovery_codes', 'totp_secret'] }], AuthZAction.READ, Operation.isAllowed);
} catch (err: any) {
this.logger.error('Error occurred requesting access-control-srv for mfa status', { code: err.code, message: err.message, stack: err.stack });
return returnOperationStatus(err.code, err.message);
}

if (acsResponse.decision != Response_Decision.PERMIT) {
return { operation_status: acsResponse.operation_status };
}

return Promise.resolve({
has_totp: user.totp_secret !== undefined && user.totp_secret !== '',
has_backup_codes: user.totp_recovery_codes !== undefined && user.totp_recovery_codes.length > 0,
operation_status: returnCodeMessage(200, 'success')
});
}
}

export class RoleService extends ServiceBase<RoleListResponse, RoleList> implements RoleServiceImplementation {
Expand Down
13 changes: 13 additions & 0 deletions test/service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2158,6 +2158,19 @@ describe('testing identity-srv', () => {
const userDBDoc = compareResult.items![0]!.payload!;
exchangeResponse!.payload!.should.deepEqual(userDBDoc);
});

it('should have totp and backup codes setup', async () => {
const setupResult = await (userService.mfaStatus({
identifier: 'test.user2',
subject: { token: 'user-token' }
}));

should.exist(setupResult);
setupResult.operation_status!.code!.should.equal(200);
setupResult.operation_status!.message!.should.equal('success');
setupResult.has_totp.should.equal(true);
setupResult.has_backup_codes.should.equal(true);
});
})
});
});
Expand Down

0 comments on commit 928bc10

Please sign in to comment.