2022-09-14 14:29:12 +02:00
|
|
|
import crypto from 'crypto';
|
|
|
|
import { Logger } from '../logger';
|
|
|
|
import { IUnleashConfig, IUnleashStores } from '../types';
|
|
|
|
import { IPublicSignupTokenStore } from '../types/stores/public-signup-token-store';
|
|
|
|
import { PublicSignupTokenSchema } from '../openapi/spec/public-signup-token-schema';
|
|
|
|
import { IRoleStore } from '../types/stores/role-store';
|
|
|
|
import { IPublicSignupTokenCreate } from '../types/models/public-signup-token';
|
|
|
|
import { PublicSignupTokenCreateSchema } from '../openapi/spec/public-signup-token-create-schema';
|
2022-09-30 13:01:32 +02:00
|
|
|
import { CreateInvitedUserSchema } from 'lib/openapi/spec/create-invited-user-schema';
|
2022-09-14 14:29:12 +02:00
|
|
|
import { RoleName } from '../types/model';
|
|
|
|
import { IEventStore } from '../types/stores/event-store';
|
|
|
|
import {
|
|
|
|
PublicSignupTokenCreatedEvent,
|
2022-09-30 13:01:32 +02:00
|
|
|
PublicSignupTokenUpdatedEvent,
|
2022-09-14 14:29:12 +02:00
|
|
|
PublicSignupTokenUserAddedEvent,
|
|
|
|
} from '../types/events';
|
2022-09-30 13:01:32 +02:00
|
|
|
import UserService from './user-service';
|
2022-09-14 14:29:12 +02:00
|
|
|
import { IUser } from '../types/user';
|
2022-09-26 12:06:30 +02:00
|
|
|
import { URL } from 'url';
|
2022-11-01 10:38:18 +01:00
|
|
|
import { add } from 'date-fns';
|
2022-09-14 14:29:12 +02:00
|
|
|
|
|
|
|
export class PublicSignupTokenService {
|
|
|
|
private store: IPublicSignupTokenStore;
|
|
|
|
|
|
|
|
private roleStore: IRoleStore;
|
|
|
|
|
|
|
|
private eventStore: IEventStore;
|
|
|
|
|
|
|
|
private userService: UserService;
|
|
|
|
|
|
|
|
private logger: Logger;
|
|
|
|
|
|
|
|
private timer: NodeJS.Timeout;
|
|
|
|
|
2022-09-26 12:06:30 +02:00
|
|
|
private readonly unleashBase: string;
|
|
|
|
|
2022-09-14 14:29:12 +02:00
|
|
|
constructor(
|
|
|
|
{
|
|
|
|
publicSignupTokenStore,
|
|
|
|
roleStore,
|
|
|
|
eventStore,
|
|
|
|
}: Pick<
|
|
|
|
IUnleashStores,
|
|
|
|
'publicSignupTokenStore' | 'roleStore' | 'eventStore'
|
|
|
|
>,
|
2022-09-26 12:06:30 +02:00
|
|
|
config: Pick<IUnleashConfig, 'getLogger' | 'authentication' | 'server'>,
|
2022-09-14 14:29:12 +02:00
|
|
|
userService: UserService,
|
|
|
|
) {
|
|
|
|
this.store = publicSignupTokenStore;
|
|
|
|
this.userService = userService;
|
|
|
|
this.roleStore = roleStore;
|
|
|
|
this.eventStore = eventStore;
|
|
|
|
this.logger = config.getLogger(
|
|
|
|
'/services/public-signup-token-service.ts',
|
|
|
|
);
|
2022-09-26 12:06:30 +02:00
|
|
|
this.unleashBase = config.server.unleashUrl;
|
|
|
|
}
|
|
|
|
|
|
|
|
private getUrl(secret: string): string {
|
|
|
|
return new URL(
|
2022-09-30 13:01:32 +02:00
|
|
|
`${this.unleashBase}/new-user?invite=${secret}`,
|
2022-09-26 12:06:30 +02:00
|
|
|
).toString();
|
2022-09-14 14:29:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public async get(secret: string): Promise<PublicSignupTokenSchema> {
|
|
|
|
return this.store.get(secret);
|
|
|
|
}
|
|
|
|
|
|
|
|
public async getAllTokens(): Promise<PublicSignupTokenSchema[]> {
|
|
|
|
return this.store.getAll();
|
|
|
|
}
|
|
|
|
|
|
|
|
public async getAllActiveTokens(): Promise<PublicSignupTokenSchema[]> {
|
|
|
|
return this.store.getAllActive();
|
|
|
|
}
|
|
|
|
|
|
|
|
public async validate(secret: string): Promise<boolean> {
|
|
|
|
return this.store.isValid(secret);
|
|
|
|
}
|
|
|
|
|
2022-09-30 13:01:32 +02:00
|
|
|
public async update(
|
2022-09-14 14:29:12 +02:00
|
|
|
secret: string,
|
2022-09-30 13:01:32 +02:00
|
|
|
{ expiresAt, enabled }: { expiresAt?: Date; enabled?: boolean },
|
|
|
|
createdBy: string,
|
2022-09-14 14:29:12 +02:00
|
|
|
): Promise<PublicSignupTokenSchema> {
|
2022-09-30 13:01:32 +02:00
|
|
|
const result = await this.store.update(secret, { expiresAt, enabled });
|
|
|
|
await this.eventStore.store(
|
|
|
|
new PublicSignupTokenUpdatedEvent({
|
|
|
|
createdBy,
|
|
|
|
data: { secret, enabled, expiresAt },
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
return result;
|
2022-09-14 14:29:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public async addTokenUser(
|
|
|
|
secret: string,
|
2022-09-30 13:01:32 +02:00
|
|
|
createUser: CreateInvitedUserSchema,
|
2022-09-14 14:29:12 +02:00
|
|
|
): Promise<IUser> {
|
2022-09-26 12:06:30 +02:00
|
|
|
const token = await this.get(secret);
|
2022-09-30 13:01:32 +02:00
|
|
|
const user = await this.userService.createUser({
|
|
|
|
...createUser,
|
|
|
|
rootRole: token.role.id,
|
|
|
|
});
|
2022-09-14 14:29:12 +02:00
|
|
|
await this.store.addTokenUser(secret, user.id);
|
|
|
|
await this.eventStore.store(
|
|
|
|
new PublicSignupTokenUserAddedEvent({
|
2022-09-26 12:06:30 +02:00
|
|
|
createdBy: 'System',
|
2022-09-14 14:29:12 +02:00
|
|
|
data: { secret, userId: user.id },
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
return user;
|
|
|
|
}
|
|
|
|
|
|
|
|
public async createNewPublicSignupToken(
|
|
|
|
tokenCreate: PublicSignupTokenCreateSchema,
|
|
|
|
createdBy: string,
|
|
|
|
): Promise<PublicSignupTokenSchema> {
|
|
|
|
const viewerRole = await this.roleStore.getRoleByName(RoleName.VIEWER);
|
2022-09-26 12:06:30 +02:00
|
|
|
const secret = this.generateSecretKey();
|
|
|
|
const url = this.getUrl(secret);
|
2022-11-01 10:38:18 +01:00
|
|
|
const cappedDate = this.getMinimumDate(
|
|
|
|
new Date(tokenCreate.expiresAt),
|
|
|
|
add(new Date(), { months: 1 }),
|
|
|
|
);
|
2022-09-14 14:29:12 +02:00
|
|
|
const newToken: IPublicSignupTokenCreate = {
|
|
|
|
name: tokenCreate.name,
|
2022-11-01 10:38:18 +01:00
|
|
|
expiresAt: cappedDate,
|
2022-09-26 12:06:30 +02:00
|
|
|
secret: secret,
|
2022-09-14 14:29:12 +02:00
|
|
|
roleId: viewerRole ? viewerRole.id : -1,
|
|
|
|
createdBy: createdBy,
|
2022-09-26 12:06:30 +02:00
|
|
|
url: url,
|
2022-09-14 14:29:12 +02:00
|
|
|
};
|
|
|
|
const token = await this.store.insert(newToken);
|
|
|
|
|
|
|
|
await this.eventStore.store(
|
|
|
|
new PublicSignupTokenCreatedEvent({
|
|
|
|
createdBy: createdBy,
|
2022-09-26 12:06:30 +02:00
|
|
|
data: token,
|
2022-09-14 14:29:12 +02:00
|
|
|
}),
|
|
|
|
);
|
|
|
|
return token;
|
|
|
|
}
|
|
|
|
|
|
|
|
private generateSecretKey(): string {
|
2022-09-26 12:06:30 +02:00
|
|
|
return crypto.randomBytes(16).toString('hex');
|
2022-09-14 14:29:12 +02:00
|
|
|
}
|
|
|
|
|
2022-11-01 10:38:18 +01:00
|
|
|
private getMinimumDate(date1: Date, date2: Date): Date {
|
|
|
|
return date1 < date2 ? date1 : date2;
|
|
|
|
}
|
|
|
|
|
2022-09-14 14:29:12 +02:00
|
|
|
destroy(): void {
|
|
|
|
clearInterval(this.timer);
|
|
|
|
this.timer = null;
|
|
|
|
}
|
|
|
|
}
|