2022-09-16 09:54:27 +02:00
|
|
|
import { IUnleashConfig, IUnleashStores } from '../types';
|
|
|
|
import { Logger } from '../logger';
|
|
|
|
import { IPatStore } from '../types/stores/pat-store';
|
2023-01-23 14:11:16 +01:00
|
|
|
import { PAT_CREATED, PAT_DELETED } from '../types/events';
|
2022-09-16 09:54:27 +02:00
|
|
|
import { IPat } from '../types/models/pat';
|
|
|
|
import crypto from 'crypto';
|
|
|
|
import User from '../types/user';
|
2022-10-14 14:28:29 +02:00
|
|
|
import BadDataError from '../error/bad-data-error';
|
|
|
|
import NameExistsError from '../error/name-exists-error';
|
2022-11-02 09:11:35 +01:00
|
|
|
import { OperationDeniedError } from '../error/operation-denied-error';
|
|
|
|
import { PAT_LIMIT } from '../util/constants';
|
2023-09-27 15:23:05 +02:00
|
|
|
import EventService from './event-service';
|
2022-09-16 09:54:27 +02:00
|
|
|
|
|
|
|
export default class PatService {
|
|
|
|
private config: IUnleashConfig;
|
|
|
|
|
|
|
|
private logger: Logger;
|
|
|
|
|
|
|
|
private patStore: IPatStore;
|
|
|
|
|
2023-09-27 15:23:05 +02:00
|
|
|
private eventService: EventService;
|
2022-09-16 09:54:27 +02:00
|
|
|
|
|
|
|
constructor(
|
2023-09-27 15:23:05 +02:00
|
|
|
{ patStore }: Pick<IUnleashStores, 'patStore'>,
|
2022-09-16 09:54:27 +02:00
|
|
|
config: IUnleashConfig,
|
2023-09-27 15:23:05 +02:00
|
|
|
eventService: EventService,
|
2022-09-16 09:54:27 +02:00
|
|
|
) {
|
|
|
|
this.config = config;
|
|
|
|
this.logger = config.getLogger('services/pat-service.ts');
|
|
|
|
this.patStore = patStore;
|
2023-09-27 15:23:05 +02:00
|
|
|
this.eventService = eventService;
|
2022-09-16 09:54:27 +02:00
|
|
|
}
|
|
|
|
|
2023-01-23 14:11:16 +01:00
|
|
|
async createPat(pat: IPat, forUserId: number, editor: User): Promise<IPat> {
|
2023-01-02 11:49:57 +01:00
|
|
|
await this.validatePat(pat, forUserId);
|
2022-09-16 09:54:27 +02:00
|
|
|
pat.secret = this.generateSecretKey();
|
2023-01-02 11:49:57 +01:00
|
|
|
pat.userId = forUserId;
|
2022-09-16 09:54:27 +02:00
|
|
|
const newPat = await this.patStore.create(pat);
|
|
|
|
|
2022-10-10 12:35:12 +02:00
|
|
|
pat.secret = '***';
|
2023-09-27 15:23:05 +02:00
|
|
|
await this.eventService.storeEvent({
|
2022-09-16 09:54:27 +02:00
|
|
|
type: PAT_CREATED,
|
2023-01-23 14:11:16 +01:00
|
|
|
createdBy: editor.email || editor.username,
|
2022-09-16 09:54:27 +02:00
|
|
|
data: pat,
|
|
|
|
});
|
|
|
|
|
|
|
|
return newPat;
|
|
|
|
}
|
|
|
|
|
2023-01-02 11:49:57 +01:00
|
|
|
async getAll(userId: number): Promise<IPat[]> {
|
|
|
|
return this.patStore.getAllByUser(userId);
|
2022-09-16 09:54:27 +02:00
|
|
|
}
|
|
|
|
|
2023-01-23 14:11:16 +01:00
|
|
|
async deletePat(
|
|
|
|
id: number,
|
|
|
|
forUserId: number,
|
|
|
|
editor: User,
|
|
|
|
): Promise<void> {
|
|
|
|
const pat = await this.patStore.get(id);
|
|
|
|
|
|
|
|
pat.secret = '***';
|
2023-09-27 15:23:05 +02:00
|
|
|
await this.eventService.storeEvent({
|
2023-01-23 14:11:16 +01:00
|
|
|
type: PAT_DELETED,
|
|
|
|
createdBy: editor.email || editor.username,
|
|
|
|
data: pat,
|
|
|
|
});
|
|
|
|
|
|
|
|
return this.patStore.deleteForUser(id, forUserId);
|
2022-09-16 09:54:27 +02:00
|
|
|
}
|
|
|
|
|
2022-10-14 14:28:29 +02:00
|
|
|
async validatePat(
|
|
|
|
{ description, expiresAt }: IPat,
|
|
|
|
userId: number,
|
|
|
|
): Promise<void> {
|
|
|
|
if (!description) {
|
|
|
|
throw new BadDataError('PAT description cannot be empty');
|
|
|
|
}
|
|
|
|
|
|
|
|
if (new Date(expiresAt) < new Date()) {
|
|
|
|
throw new BadDataError('The expiry date should be in future.');
|
|
|
|
}
|
|
|
|
|
2022-11-02 09:11:35 +01:00
|
|
|
if ((await this.patStore.countByUser(userId)) >= PAT_LIMIT) {
|
|
|
|
throw new OperationDeniedError(
|
|
|
|
`Too many PATs (${PAT_LIMIT}) already exist for this user.`,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-10-14 14:28:29 +02:00
|
|
|
if (
|
|
|
|
await this.patStore.existsWithDescriptionByUser(description, userId)
|
|
|
|
) {
|
|
|
|
throw new NameExistsError('PAT description already exists');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-16 09:54:27 +02:00
|
|
|
private generateSecretKey() {
|
|
|
|
const randomStr = crypto.randomBytes(28).toString('hex');
|
|
|
|
return `user:${randomStr}`;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = PatService;
|