forked from Yara724/api
144 lines
4.2 KiB
TypeScript
144 lines
4.2 KiB
TypeScript
import {
|
|
BadRequestException,
|
|
HttpException,
|
|
HttpStatus,
|
|
Injectable,
|
|
Logger,
|
|
NotAcceptableException,
|
|
NotFoundException,
|
|
} from "@nestjs/common";
|
|
import { JwtService } from "@nestjs/jwt";
|
|
import { Types } from "mongoose";
|
|
import { LoginDtoRs } from "src/auth/dto/user/login.dto";
|
|
import { UserDbService } from "src/users/entities/db-service/user.db.service";
|
|
import { HashService } from "src/utils/hash/hash.service";
|
|
import { OtpService } from "src/utils/otp/otp.service";
|
|
import { SmsManagerService } from "src/utils/sms-manager/sms-manager.service";
|
|
import { describeSmsError } from "src/utils/sms-manager/sms-provider.exception";
|
|
|
|
// TODO FIX REGISTER TO USER.SERVICE AND AUTH IN THIS MODULE
|
|
@Injectable()
|
|
export class UserAuthService {
|
|
private readonly logger = new Logger(UserAuthService.name);
|
|
|
|
constructor(
|
|
private readonly jwtService: JwtService,
|
|
private readonly userDbService: UserDbService,
|
|
private readonly hashService: HashService,
|
|
private readonly otpCreator: OtpService,
|
|
private readonly smsManagerService: SmsManagerService,
|
|
) {}
|
|
|
|
async validateUser(username: string, pass: string): Promise<any> {
|
|
const user = await this.userDbService.findOne({ username });
|
|
if (!user) throw new NotFoundException("user not found");
|
|
|
|
const now = new Date().getTime();
|
|
if (user.otp == null) throw new NotAcceptableException("please get otp");
|
|
if (user.otpExpire < now) {
|
|
throw new NotAcceptableException("expire otp");
|
|
}
|
|
if (await this.hashService.compare(pass, user.otp)) {
|
|
return user;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
async login(user: any) {
|
|
const payload = {
|
|
username: user.username,
|
|
sub: user.id,
|
|
role: "user",
|
|
};
|
|
const accToken = this.jwtService.sign(payload, {
|
|
secret: `${process.env.SECRET}`,
|
|
});
|
|
await this.userDbService.findOneAndUpdate(
|
|
{ username: user.username },
|
|
{
|
|
tokens: { token: accToken },
|
|
otp: null,
|
|
},
|
|
);
|
|
return {
|
|
userId: user._id,
|
|
access_token: accToken,
|
|
};
|
|
}
|
|
|
|
async sendOtpRequest(mobile: string): Promise<LoginDtoRs> {
|
|
const userExist = await this.userDbService.findOne({
|
|
mobile,
|
|
});
|
|
const otp = this.otpCreator.create();
|
|
const hashOtp = await this.hashService.hash(otp);
|
|
const rawExpireMinutes = Number(process.env.EXP_OTP_TIME ?? "2");
|
|
const expireMinutes =
|
|
Number.isFinite(rawExpireMinutes) && rawExpireMinutes > 0
|
|
? rawExpireMinutes
|
|
: 2;
|
|
const otpExpire = Date.now() + expireMinutes * 60 * 1000;
|
|
if (!userExist) {
|
|
await this.smsSender(otp, mobile);
|
|
/// create otp request
|
|
const newUser = await this.userDbService.createUser({
|
|
mobile,
|
|
username: mobile,
|
|
otp: hashOtp,
|
|
tokens: {
|
|
token: "",
|
|
rfToken: "",
|
|
},
|
|
fullName: "",
|
|
nationalCode: "",
|
|
lastLogin: new Date(),
|
|
clientKey: new Types.ObjectId(),
|
|
birthDay: "",
|
|
city: "",
|
|
address: "",
|
|
state: "",
|
|
otpExpire,
|
|
});
|
|
return new LoginDtoRs(newUser);
|
|
}
|
|
if (userExist) {
|
|
if (userExist.otpExpire > new Date(new Date().getTime()).getTime()) throw new BadRequestException("Wait for expiry time to finish");
|
|
await this.smsSender(otp, mobile);
|
|
const updateTokens = await this.userDbService.findOneAndUpdate(
|
|
{
|
|
username: userExist.username,
|
|
},
|
|
{
|
|
otp: hashOtp,
|
|
otpExpire,
|
|
},
|
|
);
|
|
if (updateTokens) return new LoginDtoRs(userExist);
|
|
}
|
|
}
|
|
|
|
private async smsSender(otp: string, mobile: string) {
|
|
try {
|
|
await this.smsManagerService.verifyLookUp({
|
|
token: otp,
|
|
template: process.env.AUTH_SMS_TEMPLATE,
|
|
receptor: mobile,
|
|
});
|
|
this.logger.log(
|
|
`Auth OTP SMS accepted by provider phone=${mobile} otp=${otp}`,
|
|
);
|
|
} catch (err) {
|
|
this.logger.error(
|
|
`Auth OTP SMS failed phone=${mobile} otp=${otp} ${describeSmsError(err)}`,
|
|
);
|
|
if (err instanceof HttpException) {
|
|
throw err;
|
|
}
|
|
throw new HttpException(
|
|
"auth sms send failed",
|
|
HttpStatus.BAD_GATEWAY,
|
|
);
|
|
}
|
|
}
|
|
}
|