233 lines
6.7 KiB
TypeScript
233 lines
6.7 KiB
TypeScript
import { Injectable } from '@nestjs/common';
|
|
import { Provider, User } from '@prisma/client';
|
|
import { CreateOrgUserDto } from '@gitroom/nestjs-libraries/dtos/auth/create.org.user.dto';
|
|
import { LoginUserDto } from '@gitroom/nestjs-libraries/dtos/auth/login.user.dto';
|
|
import { UsersService } from '@gitroom/nestjs-libraries/database/prisma/users/users.service';
|
|
import { OrganizationService } from '@gitroom/nestjs-libraries/database/prisma/organizations/organization.service';
|
|
import { AuthService as AuthChecker } from '@gitroom/helpers/auth/auth.service';
|
|
import { ProvidersFactory } from '@gitroom/backend/services/auth/providers/providers.factory';
|
|
import dayjs from 'dayjs';
|
|
import { NewsletterService } from '@gitroom/nestjs-libraries/services/newsletter.service';
|
|
import { NotificationService } from '@gitroom/nestjs-libraries/database/prisma/notifications/notification.service';
|
|
import { ForgotReturnPasswordDto } from '@gitroom/nestjs-libraries/dtos/auth/forgot-return.password.dto';
|
|
import { EmailService } from '@gitroom/nestjs-libraries/services/email.service';
|
|
|
|
@Injectable()
|
|
export class AuthService {
|
|
constructor(
|
|
private _userService: UsersService,
|
|
private _organizationService: OrganizationService,
|
|
private _notificationService: NotificationService,
|
|
private _emailService: EmailService
|
|
) {}
|
|
async routeAuth(
|
|
provider: Provider,
|
|
body: CreateOrgUserDto | LoginUserDto,
|
|
ip: string,
|
|
userAgent: string,
|
|
addToOrg?: boolean | { orgId: string; role: 'USER' | 'ADMIN'; id: string }
|
|
) {
|
|
if (provider === Provider.LOCAL) {
|
|
const user = await this._userService.getUserByEmail(body.email);
|
|
if (body instanceof CreateOrgUserDto) {
|
|
if (user) {
|
|
throw new Error('User already exists');
|
|
}
|
|
|
|
const create = await this._organizationService.createOrgAndUser(
|
|
body,
|
|
ip,
|
|
userAgent
|
|
);
|
|
|
|
const addedOrg =
|
|
addToOrg && typeof addToOrg !== 'boolean'
|
|
? await this._organizationService.addUserToOrg(
|
|
create.users[0].user.id,
|
|
addToOrg.id,
|
|
addToOrg.orgId,
|
|
addToOrg.role
|
|
)
|
|
: false;
|
|
|
|
const obj = { addedOrg, jwt: await this.jwt(create.users[0].user) };
|
|
await this._emailService.sendEmail(
|
|
body.email,
|
|
'Activate your account',
|
|
`Click <a href="${process.env.FRONTEND_URL}/auth/activate/${obj.jwt}">here</a> to activate your account`
|
|
);
|
|
return obj;
|
|
}
|
|
|
|
if (!user || !AuthChecker.comparePassword(body.password, user.password)) {
|
|
throw new Error('Invalid user name or password');
|
|
}
|
|
|
|
if (!user.activated) {
|
|
throw new Error('User is not activated');
|
|
}
|
|
|
|
return { addedOrg: false, jwt: await this.jwt(user) };
|
|
}
|
|
|
|
const user = await this.loginOrRegisterProvider(
|
|
provider,
|
|
body as CreateOrgUserDto,
|
|
ip,
|
|
userAgent
|
|
);
|
|
|
|
const addedOrg =
|
|
addToOrg && typeof addToOrg !== 'boolean'
|
|
? await this._organizationService.addUserToOrg(
|
|
user.id,
|
|
addToOrg.id,
|
|
addToOrg.orgId,
|
|
addToOrg.role
|
|
)
|
|
: false;
|
|
return { addedOrg, jwt: await this.jwt(user) };
|
|
}
|
|
|
|
public getOrgFromCookie(cookie?: string) {
|
|
if (!cookie) {
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
const getOrg: any = AuthChecker.verifyJWT(cookie);
|
|
if (dayjs(getOrg.timeLimit).isBefore(dayjs())) {
|
|
return false;
|
|
}
|
|
|
|
return getOrg as {
|
|
email: string;
|
|
role: 'USER' | 'ADMIN';
|
|
orgId: string;
|
|
id: string;
|
|
};
|
|
} catch (err) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private async loginOrRegisterProvider(
|
|
provider: Provider,
|
|
body: CreateOrgUserDto,
|
|
ip: string,
|
|
userAgent: string
|
|
) {
|
|
const providerInstance = ProvidersFactory.loadProvider(provider);
|
|
const providerUser = await providerInstance.getUser(body.providerToken);
|
|
|
|
if (!providerUser) {
|
|
throw new Error('Invalid provider token');
|
|
}
|
|
|
|
const user = await this._userService.getUserByProvider(
|
|
providerUser.id,
|
|
provider
|
|
);
|
|
if (user) {
|
|
return user;
|
|
}
|
|
|
|
const create = await this._organizationService.createOrgAndUser(
|
|
{
|
|
company: body.company,
|
|
email: providerUser.email,
|
|
password: '',
|
|
provider,
|
|
providerId: providerUser.id,
|
|
},
|
|
ip,
|
|
userAgent
|
|
);
|
|
|
|
await NewsletterService.register(providerUser.email);
|
|
|
|
return create.users[0].user;
|
|
}
|
|
|
|
async forgot(email: string) {
|
|
const user = await this._userService.getUserByEmail(email);
|
|
if (!user || user.providerName !== Provider.LOCAL) {
|
|
return false;
|
|
}
|
|
|
|
const resetValues = AuthChecker.signJWT({
|
|
id: user.id,
|
|
expires: dayjs().add(20, 'minutes').format('YYYY-MM-DD HH:mm:ss'),
|
|
});
|
|
|
|
await this._notificationService.sendEmail(
|
|
user.email,
|
|
'Reset your password',
|
|
`You have requested to reset your passsord. <br />Click <a href="${process.env.FRONTEND_URL}/auth/forgot/${resetValues}">here</a> to reset your password<br />The link will expire in 20 minutes`
|
|
);
|
|
}
|
|
|
|
forgotReturn(body: ForgotReturnPasswordDto) {
|
|
const user = AuthChecker.verifyJWT(body.token) as {
|
|
id: string;
|
|
expires: string;
|
|
};
|
|
if (dayjs(user.expires).isBefore(dayjs())) {
|
|
return false;
|
|
}
|
|
|
|
return this._userService.updatePassword(user.id, body.password);
|
|
}
|
|
|
|
async activate(code: string) {
|
|
const user = AuthChecker.verifyJWT(code) as {
|
|
id: string;
|
|
activated: boolean;
|
|
email: string;
|
|
};
|
|
if (user.id && !user.activated) {
|
|
const getUserAgain = await this._userService.getUserByEmail(user.email);
|
|
if (getUserAgain.activated) {
|
|
return false;
|
|
}
|
|
await this._userService.activateUser(user.id);
|
|
user.activated = true;
|
|
await NewsletterService.register(user.email);
|
|
return this.jwt(user as any);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
oauthLink(provider: string) {
|
|
const providerInstance = ProvidersFactory.loadProvider(
|
|
provider as Provider
|
|
);
|
|
return providerInstance.generateLink();
|
|
}
|
|
|
|
async checkExists(provider: string, code: string) {
|
|
const providerInstance = ProvidersFactory.loadProvider(
|
|
provider as Provider
|
|
);
|
|
const token = await providerInstance.getToken(code);
|
|
const user = await providerInstance.getUser(token);
|
|
if (!user) {
|
|
throw new Error('Invalid user');
|
|
}
|
|
const checkExists = await this._userService.getUserByProvider(
|
|
user.id,
|
|
provider as Provider
|
|
);
|
|
if (checkExists) {
|
|
return { jwt: await this.jwt(checkExists) };
|
|
}
|
|
|
|
return { token };
|
|
}
|
|
|
|
private async jwt(user: User) {
|
|
return AuthChecker.signJWT(user);
|
|
}
|
|
}
|