mirror of
https://github.com/SyncrowIOT/backend.git
synced 2025-07-15 18:27:05 +00:00
164 lines
4.8 KiB
TypeScript
164 lines
4.8 KiB
TypeScript
import { PlatformType } from '@app/common/constants/platform-type.enum';
|
|
import { RoleType } from '@app/common/constants/role.type.enum';
|
|
import { UserEntity } from '@app/common/modules/user/entities';
|
|
import {
|
|
BadRequestException,
|
|
Injectable,
|
|
UnauthorizedException,
|
|
} from '@nestjs/common';
|
|
import { ConfigService } from '@nestjs/config';
|
|
import { JwtService } from '@nestjs/jwt';
|
|
import * as argon2 from 'argon2';
|
|
import { OAuth2Client } from 'google-auth-library';
|
|
import { UserSessionEntity } from '../../../../common/src/modules/session/entities';
|
|
import { UserSessionRepository } from '../../../../common/src/modules/session/repositories/session.repository';
|
|
import { UserRepository } from '../../../../common/src/modules/user/repositories';
|
|
import { HelperHashService } from '../../helper/services';
|
|
|
|
@Injectable()
|
|
export class AuthService {
|
|
private client: OAuth2Client;
|
|
constructor(
|
|
private jwtService: JwtService,
|
|
private readonly userRepository: UserRepository,
|
|
private readonly sessionRepository: UserSessionRepository,
|
|
private readonly helperHashService: HelperHashService,
|
|
private readonly configService: ConfigService,
|
|
) {
|
|
this.client = new OAuth2Client(this.configService.get('GOOGLE_CLIENT_ID'));
|
|
}
|
|
|
|
async validateUser(
|
|
email: string,
|
|
pass: string,
|
|
regionUuid?: string,
|
|
platform?: PlatformType,
|
|
): Promise<Omit<UserEntity, 'password'>> {
|
|
const user = await this.userRepository.findOne({
|
|
where: {
|
|
email,
|
|
region: regionUuid ? { uuid: regionUuid } : undefined,
|
|
},
|
|
relations: ['roleType', 'project'],
|
|
});
|
|
if (!user) {
|
|
throw new BadRequestException('Invalid credentials');
|
|
}
|
|
if (
|
|
platform === PlatformType.WEB &&
|
|
[RoleType.SPACE_OWNER, RoleType.SPACE_MEMBER].includes(
|
|
user.roleType.type as RoleType,
|
|
)
|
|
) {
|
|
throw new UnauthorizedException('Access denied for web platform');
|
|
}
|
|
|
|
if (!user.isUserVerified) {
|
|
throw new BadRequestException('User is not verified');
|
|
}
|
|
if (!user.isActive) {
|
|
throw new BadRequestException('User is not active');
|
|
}
|
|
if (!user.hasAcceptedAppAgreement) {
|
|
throw new BadRequestException('User has not accepted app agreement');
|
|
}
|
|
const passwordMatch = await this.helperHashService.bcryptCompare(
|
|
pass,
|
|
user.password,
|
|
);
|
|
if (!passwordMatch) {
|
|
throw new BadRequestException('Invalid credentials');
|
|
}
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
// const { password, ...result } = user;
|
|
delete user.password;
|
|
return user;
|
|
}
|
|
|
|
async createSession(data): Promise<UserSessionEntity> {
|
|
return await this.sessionRepository.save(data);
|
|
}
|
|
|
|
async getTokens(
|
|
payload,
|
|
isRefreshToken = true,
|
|
accessTokenExpiry = '24h',
|
|
refreshTokenExpiry = '30d',
|
|
) {
|
|
const [accessToken, refreshToken] = await Promise.all([
|
|
this.jwtService.signAsync(payload, {
|
|
secret: this.configService.get<string>('JWT_SECRET'),
|
|
expiresIn: accessTokenExpiry,
|
|
}),
|
|
isRefreshToken
|
|
? this.jwtService.signAsync(payload, {
|
|
secret: this.configService.get<string>('JWT_SECRET'),
|
|
expiresIn: refreshTokenExpiry,
|
|
})
|
|
: null,
|
|
]);
|
|
|
|
return {
|
|
accessToken,
|
|
...(isRefreshToken ? { refreshToken } : {}),
|
|
};
|
|
}
|
|
|
|
async login(user: any) {
|
|
const payload = {
|
|
email: user.email,
|
|
userId: user.userId,
|
|
uuid: user.uuid,
|
|
sessionId: user.sessionId,
|
|
role: user?.role,
|
|
googleCode: user.googleCode,
|
|
hasAcceptedWebAgreement: user.hasAcceptedWebAgreement,
|
|
hasAcceptedAppAgreement: user.hasAcceptedAppAgreement,
|
|
project: user?.project,
|
|
bookingPoints: user?.bookingPoints,
|
|
};
|
|
if (payload.googleCode) {
|
|
const profile = await this.getProfile(payload.googleCode);
|
|
user = await this.userRepository.findOne({
|
|
where: { email: profile.email },
|
|
});
|
|
if (!user) {
|
|
return { profile };
|
|
}
|
|
}
|
|
const tokens = await this.getTokens(payload);
|
|
await this.updateRefreshToken(user.uuid, tokens.refreshToken);
|
|
return tokens;
|
|
}
|
|
|
|
async updateRefreshToken(userId: string, refreshToken: string) {
|
|
const hashedRefreshToken = await this.hashData(refreshToken);
|
|
await this.userRepository.update(
|
|
{ uuid: userId },
|
|
{
|
|
refreshToken: hashedRefreshToken,
|
|
},
|
|
);
|
|
}
|
|
|
|
hashData(data: string) {
|
|
return argon2.hash(data);
|
|
}
|
|
|
|
async getProfile(googleCode: string) {
|
|
try {
|
|
const ticket = await this.client.verifyIdToken({
|
|
idToken: googleCode,
|
|
audience: this.configService.get('GOOGLE_CLIENT_ID'),
|
|
});
|
|
const payload = ticket.getPayload();
|
|
return {
|
|
...payload,
|
|
};
|
|
} catch (error) {
|
|
throw new UnauthorizedException('Google login failed');
|
|
}
|
|
}
|
|
}
|