Skip to content

Commit

Permalink
Merge pull request #49 from choxx/reset-password-generic-apis
Browse files Browse the repository at this point in the history
Password reset APIs (OTP based)
  • Loading branch information
choxx authored Jan 5, 2023
2 parents 0153d1d + 1faa69b commit ee38540
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 272 deletions.
27 changes: 27 additions & 0 deletions src/api/api.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { FusionauthService } from './fusionauth/fusionauth.service';
import { OtpService } from './otp/otp.service';
import { SMSResponse } from './sms/sms.interface';
import { RefreshRequest } from '@fusionauth/typescript-client/build/src/FusionAuthClient';
import { ChangePasswordDTO } from '../user/dto/changePassword.dto';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const CryptoJS = require('crypto-js');

Expand Down Expand Up @@ -266,4 +267,30 @@ export class ApiController {
authHeader,
);
}

@Post('/changePassword/sendOTP')
async changePasswordOTP(
@Headers('authorization') authHeader,
@Headers('x-application-id') applicationId,
@Body() data: any,
): Promise<SignupResponse> {
return await this.apiService.changePasswordOTP(
data.username,
applicationId,
authHeader,
);
}

@Patch('/changePassword/update')
async changePassword(
@Headers('authorization') authHeader,
@Headers('x-application-id') applicationId,
@Body() data: ChangePasswordDTO,
): Promise<SignupResponse> {
return await this.apiService.changePassword(
data,
applicationId,
authHeader,
);
}
}
102 changes: 101 additions & 1 deletion src/api/api.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ import { OtpService } from './otp/otp.service';
import { v4 as uuidv4 } from 'uuid';
import { ConfigResolverService } from './config.resolver.service';
import { RefreshRequest } from '@fusionauth/typescript-client/build/src/FusionAuthClient';
import { FAStatus } from '../user/fusionauth/fusionauth.service';
import { ChangePasswordDTO } from '../user/dto/changePassword.dto';
import { SMSResponseStatus } from '../user/sms/sms.interface';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const CryptoJS = require('crypto-js');
// eslint-disable-next-line @typescript-eslint/no-var-requires
Expand Down Expand Up @@ -214,7 +217,7 @@ export class ApiService {
applicationId: string,
authHeader?: string,
): Promise<any> {
return this.fusionAuthService.upddatePasswordWithLoginId(
return this.fusionAuthService.updatePasswordWithLoginId(
data,
applicationId,
authHeader,
Expand Down Expand Up @@ -408,4 +411,101 @@ export class ApiService {
response.result = userResponse.user;
return response;
}

async changePasswordOTP(
username: string,
applicationId: UUID,
authHeader: null | string,
): Promise<SignupResponse> {
// Get Phone No from username
const {
statusFA,
userId,
user,
}: { statusFA: FAStatus; userId: UUID; user: User } =
await this.fusionAuthService.getUser(username, applicationId, authHeader);
const response: SignupResponse = new SignupResponse().init(uuidv4());
// If phone number is valid => Send OTP
if (statusFA === FAStatus.USER_EXISTS) {
const re = /^[6-9]{1}[0-9]{9}$/;
if (re.test(user.mobilePhone)) {
const result = await this.otpService.sendOTP(user.mobilePhone);
response.result = {
data: result,
responseMsg: `OTP has been sent to ${user.mobilePhone}.`,
};
response.responseCode = ResponseCode.OK;
response.params.status = ResponseStatus.success;
} else {
response.responseCode = ResponseCode.FAILURE;
response.params.err = 'INVALID_PHONE_NUMBER';
response.params.errMsg = 'Invalid Phone number';
response.params.status = ResponseStatus.failure;
}
} else {
response.responseCode = ResponseCode.FAILURE;
response.params.err = 'INVALID_USERNAME';
response.params.errMsg = 'No user with this Username exists';
response.params.status = ResponseStatus.failure;
}
return response;
}

async changePassword(
data: ChangePasswordDTO,
applicationId: UUID,
authHeader: null | string,
): Promise<SignupResponse> {
// Verify OTP
const {
statusFA,
userId,
user,
}: { statusFA: FAStatus; userId: UUID; user: User } =
await this.fusionAuthService.getUser(
data.username,
applicationId,
authHeader,
);
const response: SignupResponse = new SignupResponse().init(uuidv4());
if (statusFA === FAStatus.USER_EXISTS) {
const verifyOTPResult = await this.otpService.verifyOTP({
phone: user.mobilePhone,
otp: data.OTP,
});

if (verifyOTPResult.status === SMSResponseStatus.success) {
const result = await this.fusionAuthService.updatePassword(
userId,
data.password,
applicationId,
authHeader,
);

if (result.statusFA == FAStatus.SUCCESS) {
response.result = {
responseMsg: 'Password updated successfully',
};
response.responseCode = ResponseCode.OK;
response.params.status = ResponseStatus.success;
} else {
response.responseCode = ResponseCode.FAILURE;
response.params.err = 'UNCAUGHT_EXCEPTION';
response.params.errMsg = 'Server Error';
response.params.status = ResponseStatus.failure;
}
} else {
response.responseCode = ResponseCode.FAILURE;
response.params.err = 'INVALID_OTP_USERNAME_PAIR';
response.params.errMsg = 'OTP and Username did not match.';
response.params.status = ResponseStatus.failure;
}
} else {
response.responseCode = ResponseCode.FAILURE;
response.params.err = 'INVALID_USERNAME';
response.params.errMsg = 'No user with this Username exists';
response.params.status = ResponseStatus.failure;
}
return response;
}
}
Loading

0 comments on commit ee38540

Please sign in to comment.