@boarteam/boar-pack-users-backend 8.0.0 → 8.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audit-logs/audit-logs.controller.js +2 -0
- package/dist/audit-logs/audit-logs.controller.js.map +1 -1
- package/dist/audit-logs/entities/audit-log.entity.js +4 -0
- package/dist/audit-logs/entities/audit-log.entity.js.map +1 -1
- package/dist/auth/auth-manage.controller.js +2 -0
- package/dist/auth/auth-manage.controller.js.map +1 -1
- package/dist/auth/auth.controller.js +4 -0
- package/dist/auth/auth.controller.js.map +1 -1
- package/dist/auth/google/google-auth.controller.js +3 -0
- package/dist/auth/google/google-auth.controller.js.map +1 -1
- package/dist/auth/local-auth/local-auth.controller.js +2 -0
- package/dist/auth/local-auth/local-auth.controller.js.map +1 -1
- package/dist/auth/local-auth/local-auth.dto.js +7 -0
- package/dist/auth/local-auth/local-auth.dto.js.map +1 -1
- package/dist/auth/microsoft/ms-auth.controller.js +3 -0
- package/dist/auth/microsoft/ms-auth.controller.js.map +1 -1
- package/dist/auth/yandex/yandex-auth.controller.js +3 -0
- package/dist/auth/yandex/yandex-auth.controller.js.map +1 -1
- package/dist/event-logs/dto/event-log-create.dto.js +4 -0
- package/dist/event-logs/dto/event-log-create.dto.js.map +1 -1
- package/dist/event-logs/dto/event-log-timeline-query.dto.js +4 -0
- package/dist/event-logs/dto/event-log-timeline-query.dto.js.map +1 -1
- package/dist/event-logs/dto/event-log-timeline.dto.js +4 -0
- package/dist/event-logs/dto/event-log-timeline.dto.js.map +1 -1
- package/dist/event-logs/dto/event-log-update.dto.js +4 -0
- package/dist/event-logs/dto/event-log-update.dto.js.map +1 -1
- package/dist/event-logs/entities/event-log.entity.js +4 -0
- package/dist/event-logs/entities/event-log.entity.js.map +1 -1
- package/dist/event-logs/event-logs.controller.js +3 -0
- package/dist/event-logs/event-logs.controller.js.map +1 -1
- package/dist/event-logs/event-logs.logger.d.ts +2 -2
- package/dist/event-logs/event-logs.logger.js +2 -2
- package/dist/event-logs/event-logs.logger.js.map +1 -1
- package/dist/revoked-tokens/entities/revoked-token.entity.js +4 -0
- package/dist/revoked-tokens/entities/revoked-token.entity.js.map +1 -1
- package/dist/settings/dto/event-settings.dto.js +4 -0
- package/dist/settings/dto/event-settings.dto.js.map +1 -1
- package/dist/settings/entities/setting.entity.js +4 -0
- package/dist/settings/entities/setting.entity.js.map +1 -1
- package/dist/settings/settings.controller.js +3 -0
- package/dist/settings/settings.controller.js.map +1 -1
- package/dist/telegraf/dto/telegram-settings-update.dto.js +4 -0
- package/dist/telegraf/dto/telegram-settings-update.dto.js.map +1 -1
- package/dist/telegraf/dto/telegram-settings.dto.js +4 -0
- package/dist/telegraf/dto/telegram-settings.dto.js.map +1 -1
- package/dist/telegraf/telegraf.controller.js +4 -0
- package/dist/telegraf/telegraf.controller.js.map +1 -1
- package/dist/tokens/dto/token-create.dto.js +4 -0
- package/dist/tokens/dto/token-create.dto.js.map +1 -1
- package/dist/tokens/dto/token-update.dto.js +4 -0
- package/dist/tokens/dto/token-update.dto.js.map +1 -1
- package/dist/tokens/dto/token-with-value.dto.js +4 -0
- package/dist/tokens/dto/token-with-value.dto.js.map +1 -1
- package/dist/tokens/entities/token.entity.js +4 -0
- package/dist/tokens/entities/token.entity.js.map +1 -1
- package/dist/tokens/my-tokens.controller.js +2 -0
- package/dist/tokens/my-tokens.controller.js.map +1 -1
- package/dist/tokens/tokens.controller.js +1 -0
- package/dist/tokens/tokens.controller.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/users/dto/permission.dto.js +4 -0
- package/dist/users/dto/permission.dto.js.map +1 -1
- package/dist/users/dto/user-create.dto.js +4 -0
- package/dist/users/dto/user-create.dto.js.map +1 -1
- package/dist/users/dto/user-update.dto.js +4 -0
- package/dist/users/dto/user-update.dto.js.map +1 -1
- package/dist/users/entities/user.entity.js +4 -0
- package/dist/users/entities/user.entity.js.map +1 -1
- package/dist/users/me.controller.js +2 -0
- package/dist/users/me.controller.js.map +1 -1
- package/dist/users/users.controller.js +1 -0
- package/dist/users/users.controller.js.map +1 -1
- package/dist/ws-auth/ws-auth.guard.js +2 -2
- package/dist/ws-auth/ws-auth.guard.js.map +1 -1
- package/package.json +5 -5
- package/src/audit-logs/audit-log-base-service.ts +0 -169
- package/src/audit-logs/audit-logs.controller.ts +0 -74
- package/src/audit-logs/audit-logs.module.ts +0 -49
- package/src/audit-logs/audit-logs.permissions.ts +0 -4
- package/src/audit-logs/audit-logs.service.ts +0 -14
- package/src/audit-logs/audit-logs.types.ts +0 -9
- package/src/audit-logs/entities/audit-log.entity.ts +0 -46
- package/src/audit-logs/policies/view-audit-logs.policy.ts +0 -8
- package/src/auth/auth-manage.controller.ts +0 -35
- package/src/auth/auth-strategies.constants.ts +0 -7
- package/src/auth/auth.config.ts +0 -20
- package/src/auth/auth.constants.ts +0 -2
- package/src/auth/auth.controller.ts +0 -54
- package/src/auth/auth.exception-filter.ts +0 -15
- package/src/auth/auth.module.ts +0 -118
- package/src/auth/auth.service.ts +0 -122
- package/src/auth/google/google-auth.config.ts +0 -26
- package/src/auth/google/google-auth.controller.ts +0 -39
- package/src/auth/google/google-auth.guard.ts +0 -6
- package/src/auth/google/google-auth.strategy.ts +0 -59
- package/src/auth/index.ts +0 -15
- package/src/auth/local-auth/local-auth.controller.ts +0 -37
- package/src/auth/local-auth/local-auth.dto.ts +0 -17
- package/src/auth/local-auth/local-auth.guard.ts +0 -6
- package/src/auth/local-auth/local-auth.strategy.ts +0 -21
- package/src/auth/microsoft/ms-auth.config.ts +0 -29
- package/src/auth/microsoft/ms-auth.controller.ts +0 -40
- package/src/auth/microsoft/ms-auth.guard.ts +0 -8
- package/src/auth/microsoft/ms-auth.strategy.ts +0 -63
- package/src/auth/yandex/yandex-auth.config.ts +0 -26
- package/src/auth/yandex/yandex-auth.controller.ts +0 -39
- package/src/auth/yandex/yandex-auth.guard.ts +0 -6
- package/src/auth/yandex/yandex-auth.strategy.ts +0 -59
- package/src/bcrypt/bcrypt.config.ts +0 -27
- package/src/bcrypt/bcrypt.module.ts +0 -19
- package/src/bcrypt/bcrypt.service.ts +0 -24
- package/src/bcrypt/index.ts +0 -3
- package/src/casl/action.enum.ts +0 -7
- package/src/casl/casl-ability.factory.ts +0 -130
- package/src/casl/casl.module.ts +0 -31
- package/src/casl/fields-permission.interceptor.ts +0 -58
- package/src/casl/index.ts +0 -5
- package/src/casl/policies/manage-all.policy.ts +0 -9
- package/src/casl/policies.guard.ts +0 -80
- package/src/event-logs/dto/event-log-create.dto.ts +0 -47
- package/src/event-logs/dto/event-log-timeline-query.dto.ts +0 -13
- package/src/event-logs/dto/event-log-timeline.dto.ts +0 -9
- package/src/event-logs/dto/event-log-update.dto.ts +0 -47
- package/src/event-logs/entities/event-log.entity.ts +0 -140
- package/src/event-logs/event-logs.constants.ts +0 -2
- package/src/event-logs/event-logs.controller.ts +0 -80
- package/src/event-logs/event-logs.interceptor.ts +0 -75
- package/src/event-logs/event-logs.logger.ts +0 -48
- package/src/event-logs/event-logs.middleware.ts +0 -58
- package/src/event-logs/event-logs.module.ts +0 -131
- package/src/event-logs/event-logs.permissions.ts +0 -4
- package/src/event-logs/event-logs.service.ts +0 -236
- package/src/event-logs/event-logs.types.ts +0 -4
- package/src/event-logs/index.ts +0 -10
- package/src/event-logs/policies/manage-event-logs.policy.ts +0 -8
- package/src/event-logs/policies/view-event-logs.policy.ts +0 -8
- package/src/generateTypes.ts +0 -94
- package/src/index.ts +0 -10
- package/src/jwt-auth/index.ts +0 -5
- package/src/jwt-auth/jwt-auth.config.ts +0 -27
- package/src/jwt-auth/jwt-auth.guard.ts +0 -26
- package/src/jwt-auth/jwt-auth.module.ts +0 -64
- package/src/jwt-auth/jwt-auth.refresh.guard.ts +0 -7
- package/src/jwt-auth/jwt-auth.refresh.srtategy.ts +0 -85
- package/src/jwt-auth/jwt-auth.service.ts +0 -59
- package/src/jwt-auth/jwt-auth.srtategy.ts +0 -83
- package/src/revoked-tokens/entities/revoked-token.entity.ts +0 -50
- package/src/revoked-tokens/index.ts +0 -3
- package/src/revoked-tokens/revoked-tokens.module.ts +0 -29
- package/src/revoked-tokens/revoked-tokens.service.ts +0 -88
- package/src/settings/dto/event-settings.dto.ts +0 -3
- package/src/settings/entities/setting.entity.ts +0 -19
- package/src/settings/index.ts +0 -5
- package/src/settings/policies/manage-settings.policy.ts +0 -8
- package/src/settings/settings.constants.ts +0 -9
- package/src/settings/settings.controller.ts +0 -32
- package/src/settings/settings.module.ts +0 -46
- package/src/settings/settings.permissions.ts +0 -3
- package/src/settings/settings.service.ts +0 -51
- package/src/telegraf/dto/telegram-settings-update.dto.ts +0 -13
- package/src/telegraf/dto/telegram-settings.dto.ts +0 -5
- package/src/telegraf/index.ts +0 -3
- package/src/telegraf/telegraf.constants.ts +0 -5
- package/src/telegraf/telegraf.controller.ts +0 -40
- package/src/telegraf/telegraf.module.ts +0 -28
- package/src/telegraf/telegraf.service.ts +0 -110
- package/src/tokens/dto/token-create.dto.ts +0 -7
- package/src/tokens/dto/token-update.dto.ts +0 -7
- package/src/tokens/dto/token-with-value.dto.ts +0 -8
- package/src/tokens/entities/token.entity.ts +0 -26
- package/src/tokens/index.ts +0 -2
- package/src/tokens/my-tokens.controller.ts +0 -82
- package/src/tokens/policies/manage-my-tokens.policy.ts +0 -9
- package/src/tokens/policies/manage-tokens.policy.ts +0 -8
- package/src/tokens/policies/view-tokens.policy.ts +0 -8
- package/src/tokens/tokens-auth.guard.ts +0 -7
- package/src/tokens/tokens-auth.strategy.ts +0 -48
- package/src/tokens/tokens.constants.ts +0 -1
- package/src/tokens/tokens.controller.ts +0 -45
- package/src/tokens/tokens.module.ts +0 -86
- package/src/tokens/tokens.permissions.ts +0 -5
- package/src/tokens/tokens.service.ts +0 -14
- package/src/users/dto/permission.dto.ts +0 -5
- package/src/users/dto/user-create.dto.ts +0 -37
- package/src/users/dto/user-update.dto.ts +0 -37
- package/src/users/entities/permissions.ts +0 -23
- package/src/users/entities/user.entity.ts +0 -67
- package/src/users/hash-password.interceptor.ts +0 -22
- package/src/users/index.ts +0 -13
- package/src/users/me.controller.ts +0 -63
- package/src/users/policies/manage-users.policy.ts +0 -10
- package/src/users/policies/view-users.policy.ts +0 -10
- package/src/users/users-editing.guard.ts +0 -85
- package/src/users/users.config.ts +0 -27
- package/src/users/users.constants.ts +0 -1
- package/src/users/users.controller.ts +0 -85
- package/src/users/users.module.ts +0 -81
- package/src/users/users.service.ts +0 -23
- package/src/ws-auth/index.ts +0 -3
- package/src/ws-auth/ws-auth.constants.ts +0 -2
- package/src/ws-auth/ws-auth.d2 +0 -14
- package/src/ws-auth/ws-auth.gateway.ts +0 -25
- package/src/ws-auth/ws-auth.guard.ts +0 -28
- package/src/ws-auth/ws-auth.module.ts +0 -36
- package/src/ws-auth/ws-auth.service.ts +0 -108
|
@@ -1,236 +0,0 @@
|
|
|
1
|
-
import { Injectable, Logger } from '@nestjs/common';
|
|
2
|
-
import { TypeOrmCrudService } from '@dataui/crud-typeorm';
|
|
3
|
-
import { EventLog, LogLevel, LogType, UserRole } from './entities/event-log.entity';
|
|
4
|
-
import { DataSource, Repository } from 'typeorm';
|
|
5
|
-
import { Request } from 'express';
|
|
6
|
-
import { Roles } from "../users";
|
|
7
|
-
import { EventLogTimelineDto } from "./dto/event-log-timeline.dto";
|
|
8
|
-
import { Cron, CronExpression } from "@nestjs/schedule";
|
|
9
|
-
import moment from "moment";
|
|
10
|
-
import 'moment-timezone';
|
|
11
|
-
import { TSkipEventsLogOptions } from "./event-logs.interceptor";
|
|
12
|
-
|
|
13
|
-
type TInterval = 'second' | 'minute' | 'hour' | 'day' | 'week';
|
|
14
|
-
|
|
15
|
-
@Injectable()
|
|
16
|
-
export class EventLogsService extends TypeOrmCrudService<EventLog> {
|
|
17
|
-
private static requestHandled = Symbol('requestHandled');
|
|
18
|
-
private logsStore: Partial<EventLog>[] = [];
|
|
19
|
-
|
|
20
|
-
private readonly logger = new Logger(EventLogsService.name);
|
|
21
|
-
|
|
22
|
-
private static readonly rolesMap = {
|
|
23
|
-
[Roles.USER]: UserRole.USER,
|
|
24
|
-
[Roles.ADMIN]: UserRole.ADMIN,
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
constructor(
|
|
28
|
-
readonly repo: Repository<EventLog>,
|
|
29
|
-
private readonly dataSource: DataSource,
|
|
30
|
-
) {
|
|
31
|
-
super(repo);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
@Cron(CronExpression.EVERY_10_SECONDS)
|
|
35
|
-
private async saveAccumulatedLogs(): Promise<void> {
|
|
36
|
-
if (this.logsStore.length > 0) {
|
|
37
|
-
const logs = [...this.logsStore];
|
|
38
|
-
this.logger.verbose('Reset event logs store variable');
|
|
39
|
-
this.logsStore = [];
|
|
40
|
-
|
|
41
|
-
await this.repo.save(logs).catch(e => {
|
|
42
|
-
// DO NOT USE LOGGER HERE - it will cause infinite loop
|
|
43
|
-
console.error('Error while saving logs');
|
|
44
|
-
console.error(e);
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
@Cron(CronExpression.EVERY_WEEK)
|
|
50
|
-
private async deleteOldEventLogs() {
|
|
51
|
-
const threeMonthsAgo = new Date();
|
|
52
|
-
threeMonthsAgo.setMonth(threeMonthsAgo.getMonth() - 2);
|
|
53
|
-
|
|
54
|
-
const result = await this.repo
|
|
55
|
-
.createQueryBuilder()
|
|
56
|
-
.delete()
|
|
57
|
-
.from(EventLog)
|
|
58
|
-
.where('created_at <= :threeMonthsAgo', { threeMonthsAgo })
|
|
59
|
-
.execute();
|
|
60
|
-
|
|
61
|
-
this.logger.debug(`Removed ${result.affected} expired records from event_logs table.`);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
audit(eventLog: Partial<EventLog>, request?: Request, skipOptions?: TSkipEventsLogOptions): void {
|
|
65
|
-
// @ts-ignore
|
|
66
|
-
if (request?.[EventLogsService.requestHandled]) {
|
|
67
|
-
this.logger.debug('Request already handled');
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const logPartial: Partial<EventLog> = {};
|
|
72
|
-
if (request) {
|
|
73
|
-
const { user } = request;
|
|
74
|
-
const userRole = user?.role ? EventLogsService.rolesMap[user.role] : UserRole.GUEST;
|
|
75
|
-
|
|
76
|
-
const payload = request.body ? { ...request.body } : null;
|
|
77
|
-
if (skipOptions && typeof skipOptions === 'object' && Array.isArray(skipOptions.body) && payload) {
|
|
78
|
-
for (const field of skipOptions.body) {
|
|
79
|
-
if (field in payload) {
|
|
80
|
-
// @ts-ignore
|
|
81
|
-
payload[field] = '*****';
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
logPartial.userId = user?.id || null;
|
|
87
|
-
logPartial.userName = user?.name || null;
|
|
88
|
-
logPartial.userRole = userRole || UserRole.GUEST;
|
|
89
|
-
logPartial.payload = payload;
|
|
90
|
-
logPartial.method = request.method || null;
|
|
91
|
-
logPartial.url = request.url || null;
|
|
92
|
-
logPartial.entityId = request.params.id || null;
|
|
93
|
-
logPartial.ipAddress = request.ip || null;
|
|
94
|
-
logPartial.userAgent = request.headers['user-agent'] || null;
|
|
95
|
-
|
|
96
|
-
// @ts-ignore
|
|
97
|
-
request[EventLogsService.requestHandled] = true;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
this.logsStore.push({
|
|
101
|
-
...logPartial,
|
|
102
|
-
...eventLog,
|
|
103
|
-
logType: LogType.AUDIT,
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
public requestAlreadyHandled(request: Request): boolean {
|
|
108
|
-
// @ts-ignore
|
|
109
|
-
return request?.[EventLogsService.requestHandled];
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// TODO: Remove async in the next major version (breaking change)
|
|
113
|
-
async operationalLog(eventLog: Partial<EventLog>): Promise<void> {
|
|
114
|
-
this.logsStore.push({
|
|
115
|
-
logLevel: LogLevel.INFO,
|
|
116
|
-
userRole: UserRole.SYSTEM,
|
|
117
|
-
...eventLog,
|
|
118
|
-
logType: LogType.OPERATIONAL,
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
public applicationLog(eventLog: Partial<EventLog>): void {
|
|
123
|
-
this.logsStore.push({
|
|
124
|
-
logLevel: LogLevel.INFO,
|
|
125
|
-
userRole: UserRole.SYSTEM,
|
|
126
|
-
...eventLog,
|
|
127
|
-
logType: LogType.APPLICATION,
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
async getTimeline(startTime?: Date, endTime?: Date, timezone: string = 'UTC'): Promise<EventLogTimelineDto[]> {
|
|
132
|
-
if (!startTime) {
|
|
133
|
-
startTime = await this.getOldestLogDate();
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
if (!endTime) {
|
|
137
|
-
endTime = new Date();
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
let startMoment = moment(startTime);
|
|
141
|
-
let endMoment = moment(endTime);
|
|
142
|
-
|
|
143
|
-
const interval = this.determineInterval(startMoment, endMoment);
|
|
144
|
-
const formatTimeFunction = this.getFormatTimeFunction(interval, timezone);
|
|
145
|
-
|
|
146
|
-
const startTimeIntervalBegin = startMoment.clone().tz(timezone).startOf(interval as moment.unitOfTime.StartOf);
|
|
147
|
-
const endTimeIntervalBegin = endMoment.clone().tz(timezone).startOf(interval as moment.unitOfTime.StartOf);
|
|
148
|
-
|
|
149
|
-
return this.dataSource.query(`
|
|
150
|
-
with
|
|
151
|
-
time_series as (select generate_series($1, $2, '1 ${interval}'::interval) as time),
|
|
152
|
-
log_levels as (select unnest(enum_range(null::"${this.dataSource.driver.schema}".event_logs_log_level_enum)) as loglevel)
|
|
153
|
-
select
|
|
154
|
-
${formatTimeFunction} as time,
|
|
155
|
-
ll.loglevel as "logLevel",
|
|
156
|
-
coalesce(count(el.*)::int, 0) as records,
|
|
157
|
-
ts.time as "startTime",
|
|
158
|
-
ts.time + interval '1 ${interval}' as "endTime"
|
|
159
|
-
from time_series ts
|
|
160
|
-
cross join log_levels ll
|
|
161
|
-
left join "${this.dataSource.driver.schema}".event_logs el on date_trunc('${interval}', el.created_at, $5) = ts.time
|
|
162
|
-
and el.log_level = ll.loglevel
|
|
163
|
-
and el.created_at between $3 and $4
|
|
164
|
-
group by ts.time,
|
|
165
|
-
ll.loglevel
|
|
166
|
-
order by ts.time,
|
|
167
|
-
ll.loglevel;
|
|
168
|
-
`, [
|
|
169
|
-
startTimeIntervalBegin.toDate(),
|
|
170
|
-
endTimeIntervalBegin.toDate(),
|
|
171
|
-
startMoment.toDate(),
|
|
172
|
-
endMoment.toDate(),
|
|
173
|
-
timezone
|
|
174
|
-
]);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
async getServiceNames(): Promise<string[]> {
|
|
178
|
-
const result = await this.repo
|
|
179
|
-
.createQueryBuilder('event_logs')
|
|
180
|
-
.select('event_logs.service')
|
|
181
|
-
.distinctOn(['service'])
|
|
182
|
-
.getMany();
|
|
183
|
-
return result.map((data) => data.service);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
private async getOldestLogDate(): Promise<Date> {
|
|
187
|
-
const oldestLog = await this.repo.createQueryBuilder('event_log')
|
|
188
|
-
.select('MIN(event_log.createdAt)', 'min')
|
|
189
|
-
.getRawOne();
|
|
190
|
-
return new Date(oldestLog.min);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
private determineInterval(startTime: moment.Moment, endTime: moment.Moment): TInterval {
|
|
194
|
-
const duration = moment.duration(endTime.diff(startTime));
|
|
195
|
-
|
|
196
|
-
const totalSeconds = duration.asSeconds();
|
|
197
|
-
const totalMinutes = duration.asMinutes();
|
|
198
|
-
const totalHours = duration.asHours();
|
|
199
|
-
const totalDays = duration.asDays();
|
|
200
|
-
const totalWeeks = duration.asWeeks();
|
|
201
|
-
|
|
202
|
-
// Aim for approximately 50-100 bars
|
|
203
|
-
const targetBars = 75;
|
|
204
|
-
|
|
205
|
-
if (totalSeconds <= targetBars) {
|
|
206
|
-
return 'second';
|
|
207
|
-
} else if (totalMinutes <= targetBars) {
|
|
208
|
-
return 'minute';
|
|
209
|
-
} else if (totalHours <= targetBars) {
|
|
210
|
-
return 'hour';
|
|
211
|
-
} else if (totalDays <= targetBars) {
|
|
212
|
-
return 'day';
|
|
213
|
-
} else if (totalWeeks <= targetBars) {
|
|
214
|
-
return 'week';
|
|
215
|
-
} else {
|
|
216
|
-
return 'week'; // fallback to week for very large ranges
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
private getFormatTimeFunction(interval: TInterval, timezone: string): string {
|
|
221
|
-
switch (interval) {
|
|
222
|
-
case 'second':
|
|
223
|
-
return `to_char(ts.time at time zone '${timezone}', 'HH24:MI:SS')`;
|
|
224
|
-
case 'minute':
|
|
225
|
-
return `to_char(ts.time at time zone '${timezone}', 'HH24:MI')`;
|
|
226
|
-
case 'hour':
|
|
227
|
-
return `to_char(ts.time at time zone '${timezone}', 'HH24:MI')`;
|
|
228
|
-
case 'day':
|
|
229
|
-
return `to_char(ts.time at time zone '${timezone}', 'YYYY-MM-DD')`;
|
|
230
|
-
case 'week':
|
|
231
|
-
return `to_char(date_trunc('week', ts.time at time zone '${timezone}'), 'YYYY-MM-DD')`;
|
|
232
|
-
default:
|
|
233
|
-
return `to_char(date_trunc('week', ts.time at time zone '${timezone}'), 'YYYY-MM-DD')`;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}
|
package/src/event-logs/index.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export * from './event-logs.permissions';
|
|
2
|
-
export * from './entities/event-log.entity';
|
|
3
|
-
export * from './dto/event-log-create.dto';
|
|
4
|
-
export * from './dto/event-log-update.dto';
|
|
5
|
-
export * from './policies/manage-event-logs.policy';
|
|
6
|
-
export * from './policies/view-event-logs.policy';
|
|
7
|
-
export * from './event-logs.controller';
|
|
8
|
-
export * from './event-logs.module';
|
|
9
|
-
export * from './event-logs.service';
|
|
10
|
-
export * from './event-logs.interceptor';
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { EventLog } from "../entities/event-log.entity";
|
|
2
|
-
import { Action, AppAbility, IPolicyHandler } from "../../casl";
|
|
3
|
-
|
|
4
|
-
export class ManageEventLogsPolicy implements IPolicyHandler {
|
|
5
|
-
handle(ability: AppAbility) {
|
|
6
|
-
return ability.can(Action.Manage, EventLog);
|
|
7
|
-
}
|
|
8
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { EventLog } from "../entities/event-log.entity";
|
|
2
|
-
import { Action, AppAbility, IPolicyHandler } from "../../casl";
|
|
3
|
-
|
|
4
|
-
export class ViewEventLogsPolicy implements IPolicyHandler {
|
|
5
|
-
handle(ability: AppAbility) {
|
|
6
|
-
return ability.can(Action.Read, EventLog);
|
|
7
|
-
}
|
|
8
|
-
}
|
package/src/generateTypes.ts
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import { NestFactory } from '@nestjs/core';
|
|
2
|
-
import { DocumentBuilder, SwaggerDocumentOptions, SwaggerModule, } from '@nestjs/swagger';
|
|
3
|
-
import { Module } from "@nestjs/common";
|
|
4
|
-
import { TypeOrmModule } from "@nestjs/typeorm";
|
|
5
|
-
import { resolve } from "path";
|
|
6
|
-
import { ConfigModule } from "@nestjs/config";
|
|
7
|
-
// @ts-ignore-next-line - Ignore the error because the package on project level
|
|
8
|
-
import { generate } from "openapi-typescript-codegen";
|
|
9
|
-
import { EventLogsModule } from './event-logs'
|
|
10
|
-
import { UsersModule } from "./users";
|
|
11
|
-
import { TokensModule } from "./tokens";
|
|
12
|
-
import { SettingsModule } from "./settings";
|
|
13
|
-
import { TelegrafModule } from "./telegraf";
|
|
14
|
-
import { AuthModule } from "./auth";
|
|
15
|
-
|
|
16
|
-
@Module({
|
|
17
|
-
imports: [
|
|
18
|
-
ConfigModule.forRoot({
|
|
19
|
-
envFilePath: resolve(__dirname, '../../.env'),
|
|
20
|
-
}),
|
|
21
|
-
TypeOrmModule.forRoot({
|
|
22
|
-
name: 'boar_pack_db',
|
|
23
|
-
type: 'postgres',
|
|
24
|
-
host: 'localhost',
|
|
25
|
-
port: 5951,
|
|
26
|
-
username: 'app',
|
|
27
|
-
password: 'password',
|
|
28
|
-
database: 'boar_pack',
|
|
29
|
-
entities: [
|
|
30
|
-
resolve(__dirname, './*/entities/*.entity.{ts,js}'),
|
|
31
|
-
],
|
|
32
|
-
}),
|
|
33
|
-
AuthModule.forRoot({
|
|
34
|
-
googleAuth: false,
|
|
35
|
-
msAuth: false,
|
|
36
|
-
localAuth: false,
|
|
37
|
-
withControllers: true,
|
|
38
|
-
dataSourceName: 'boar_pack_db',
|
|
39
|
-
}),
|
|
40
|
-
UsersModule.register({
|
|
41
|
-
withControllers: true,
|
|
42
|
-
dataSourceName: 'boar_pack_db',
|
|
43
|
-
}),
|
|
44
|
-
EventLogsModule.forRoot({
|
|
45
|
-
dataSourceName: 'boar_pack_db'
|
|
46
|
-
}),
|
|
47
|
-
TokensModule.forRoot({
|
|
48
|
-
dataSourceName: 'boar_pack_db',
|
|
49
|
-
}),
|
|
50
|
-
SettingsModule.register({
|
|
51
|
-
withControllers: true,
|
|
52
|
-
dataSourceName: 'boar_pack_db',
|
|
53
|
-
}),
|
|
54
|
-
TelegrafModule.register({
|
|
55
|
-
withControllers: true,
|
|
56
|
-
dataSourceName: 'boar_pack_db',
|
|
57
|
-
}),
|
|
58
|
-
],
|
|
59
|
-
})
|
|
60
|
-
class Swagger {
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
async function bootstrap() {
|
|
64
|
-
try {
|
|
65
|
-
const app = await NestFactory.create(Swagger);
|
|
66
|
-
|
|
67
|
-
const options: SwaggerDocumentOptions = {
|
|
68
|
-
operationIdFactory: (controllerKey: string, methodKey: string) => methodKey,
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
const swaggerConfig = new DocumentBuilder()
|
|
72
|
-
.setTitle('API')
|
|
73
|
-
.setVersion('1.0')
|
|
74
|
-
.build();
|
|
75
|
-
|
|
76
|
-
const document = SwaggerModule.createDocument(app, swaggerConfig, options);
|
|
77
|
-
|
|
78
|
-
SwaggerModule.setup('docs', app, document);
|
|
79
|
-
await app.listen(3335);
|
|
80
|
-
await generate({
|
|
81
|
-
input: 'http://localhost:3335/docs-json',
|
|
82
|
-
output: resolve(__dirname, '../../../users-frontend/src/tools/api-client/generated'),
|
|
83
|
-
httpClient: 'node',
|
|
84
|
-
clientName: 'ApiClient',
|
|
85
|
-
useOptions: true,
|
|
86
|
-
});
|
|
87
|
-
await app.close();
|
|
88
|
-
} catch (e) {
|
|
89
|
-
console.error('Error, while application initialization');
|
|
90
|
-
console.error(e);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
bootstrap();
|
package/src/index.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export * from './auth';
|
|
2
|
-
export * from './casl';
|
|
3
|
-
export * from './jwt-auth';
|
|
4
|
-
export * from './users';
|
|
5
|
-
export * from './bcrypt';
|
|
6
|
-
export * from './tokens';
|
|
7
|
-
export * from './ws-auth';
|
|
8
|
-
export * from './event-logs';
|
|
9
|
-
export * from './settings';
|
|
10
|
-
export * from './telegraf';
|
package/src/jwt-auth/index.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { Injectable } from '@nestjs/common';
|
|
2
|
-
import { ConfigService } from '@nestjs/config';
|
|
3
|
-
import { StringValue } from "ms";
|
|
4
|
-
|
|
5
|
-
export type TJWTAuthConfig = {
|
|
6
|
-
jwtSecret: string;
|
|
7
|
-
accessTokenExpiration: StringValue;
|
|
8
|
-
refreshTokenExpiration: StringValue;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
@Injectable()
|
|
12
|
-
export class JWTAuthConfigService {
|
|
13
|
-
constructor(private configService: ConfigService) {
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
get config(): TJWTAuthConfig {
|
|
17
|
-
const jwtSecret = this.configService.getOrThrow<string>('JWT_SECRET');
|
|
18
|
-
const accessTokenExpiration = this.configService.get<StringValue>('ACCESS_TOKEN_EXPIRATION', '1h');
|
|
19
|
-
const refreshTokenExpiration = this.configService.get<StringValue>('REFRESH_TOKEN_EXPIRATION', '7d');
|
|
20
|
-
|
|
21
|
-
return {
|
|
22
|
-
jwtSecret,
|
|
23
|
-
accessTokenExpiration,
|
|
24
|
-
refreshTokenExpiration,
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { ExecutionContext, Injectable, SetMetadata } from '@nestjs/common';
|
|
2
|
-
import { AuthGuard } from '@nestjs/passport';
|
|
3
|
-
import { Reflector } from '@nestjs/core';
|
|
4
|
-
import { JWT_AUTH } from '../auth/auth-strategies.constants';
|
|
5
|
-
|
|
6
|
-
export const SKIP_JWT_GUARD = 'skipJWTGuard';
|
|
7
|
-
export const SkipJWTGuard = () =>
|
|
8
|
-
SetMetadata<string, boolean>(SKIP_JWT_GUARD, true);
|
|
9
|
-
|
|
10
|
-
@Injectable()
|
|
11
|
-
export class JwtAuthGuard extends AuthGuard(JWT_AUTH) {
|
|
12
|
-
constructor(private reflector: Reflector) {
|
|
13
|
-
super();
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
canActivate(context: ExecutionContext) {
|
|
17
|
-
const skipGuard = this.reflector.getAllAndOverride<boolean>(
|
|
18
|
-
SKIP_JWT_GUARD,
|
|
19
|
-
[context.getHandler(), context.getClass()],
|
|
20
|
-
);
|
|
21
|
-
if (skipGuard) {
|
|
22
|
-
return true;
|
|
23
|
-
}
|
|
24
|
-
return super.canActivate(context);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { Module } from '@nestjs/common';
|
|
2
|
-
import { UsersModule } from '../users/users.module';
|
|
3
|
-
import { ConfigModule } from '@nestjs/config';
|
|
4
|
-
import { JwtModule } from '@nestjs/jwt';
|
|
5
|
-
import { JwtAuthStrategy } from './jwt-auth.srtategy';
|
|
6
|
-
import { JwtAuthGuard } from './jwt-auth.guard';
|
|
7
|
-
import { APP_GUARD } from '@nestjs/core';
|
|
8
|
-
import { JWTAuthConfigService } from "./jwt-auth.config";
|
|
9
|
-
import { PassportModule } from "@nestjs/passport";
|
|
10
|
-
import { JWTAuthService } from "./jwt-auth.service";
|
|
11
|
-
import { RevokedTokensModule } from '../revoked-tokens';
|
|
12
|
-
import { JwtAuthRefreshStrategy } from "./jwt-auth.refresh.srtategy";
|
|
13
|
-
|
|
14
|
-
@Module({})
|
|
15
|
-
export class JwtAuthModule {
|
|
16
|
-
static register(config: {
|
|
17
|
-
dataSourceName?: string;
|
|
18
|
-
}) {
|
|
19
|
-
return {
|
|
20
|
-
module: JwtAuthModule,
|
|
21
|
-
imports: [
|
|
22
|
-
ConfigModule,
|
|
23
|
-
UsersModule.register({
|
|
24
|
-
withControllers: false,
|
|
25
|
-
dataSourceName: config.dataSourceName,
|
|
26
|
-
}),
|
|
27
|
-
PassportModule,
|
|
28
|
-
JwtModule.registerAsync({
|
|
29
|
-
imports: [JwtAuthModule.forConfig()],
|
|
30
|
-
inject: [JWTAuthConfigService],
|
|
31
|
-
useFactory: async (jwtAuthConfigService: JWTAuthConfigService) => ({
|
|
32
|
-
secret: jwtAuthConfigService.config.jwtSecret,
|
|
33
|
-
}),
|
|
34
|
-
}),
|
|
35
|
-
RevokedTokensModule.register({
|
|
36
|
-
dataSourceName: config.dataSourceName,
|
|
37
|
-
}),
|
|
38
|
-
],
|
|
39
|
-
providers: [
|
|
40
|
-
JWTAuthConfigService,
|
|
41
|
-
JwtAuthStrategy,
|
|
42
|
-
JwtAuthRefreshStrategy,
|
|
43
|
-
JWTAuthService,
|
|
44
|
-
{
|
|
45
|
-
provide: APP_GUARD,
|
|
46
|
-
useClass: JwtAuthGuard,
|
|
47
|
-
},
|
|
48
|
-
],
|
|
49
|
-
exports: [
|
|
50
|
-
JWTAuthConfigService,
|
|
51
|
-
JWTAuthService,
|
|
52
|
-
],
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
private static forConfig() {
|
|
57
|
-
return {
|
|
58
|
-
module: JwtAuthModule,
|
|
59
|
-
imports: [ConfigModule],
|
|
60
|
-
providers: [JWTAuthConfigService],
|
|
61
|
-
exports: [JWTAuthConfigService],
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
}
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import { ExtractJwt, Strategy } from 'passport-jwt';
|
|
2
|
-
import { PassportStrategy } from '@nestjs/passport';
|
|
3
|
-
import { Injectable, Logger, UnauthorizedException } from '@nestjs/common';
|
|
4
|
-
import { JWTAuthConfigService } from './jwt-auth.config';
|
|
5
|
-
import { Request } from 'express';
|
|
6
|
-
import { JWT_AUTH_REFRESH } from '../auth/auth-strategies.constants';
|
|
7
|
-
import { refreshTokenName } from "../auth/auth.constants";
|
|
8
|
-
import { UsersService } from '../users';
|
|
9
|
-
import { RevokedTokensService, TOKEN_TYPE } from '../revoked-tokens';
|
|
10
|
-
import { TJWTRefreshPayload } from "./jwt-auth.srtategy";
|
|
11
|
-
import ms from "ms";
|
|
12
|
-
|
|
13
|
-
@Injectable()
|
|
14
|
-
export class JwtAuthRefreshStrategy extends PassportStrategy(Strategy, JWT_AUTH_REFRESH) {
|
|
15
|
-
private readonly logger = new Logger(JwtAuthRefreshStrategy.name);
|
|
16
|
-
|
|
17
|
-
constructor(
|
|
18
|
-
private usersService: UsersService,
|
|
19
|
-
private jwtAuthConfigService: JWTAuthConfigService,
|
|
20
|
-
private revokedTokensService: RevokedTokensService,
|
|
21
|
-
) {
|
|
22
|
-
super({
|
|
23
|
-
jwtFromRequest: ExtractJwt.fromExtractors([
|
|
24
|
-
ExtractJwt.fromAuthHeaderAsBearerToken(),
|
|
25
|
-
(req: Request) => {
|
|
26
|
-
const cookies = req.headers.cookie?.split('; ');
|
|
27
|
-
if (!cookies) {
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const cookie = cookies.find(c => c.startsWith(`${refreshTokenName}=`));
|
|
32
|
-
if (!cookie) {
|
|
33
|
-
return null;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return cookie.split('=')[1];
|
|
37
|
-
},
|
|
38
|
-
]),
|
|
39
|
-
ignoreExpiration: false,
|
|
40
|
-
secretOrKey: jwtAuthConfigService.config.jwtSecret,
|
|
41
|
-
passReqToCallback: false,
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
async validate(payload: TJWTRefreshPayload) {
|
|
46
|
-
this.logger.debug(`Validating refresh token for user with id: ${payload.sub}`);
|
|
47
|
-
|
|
48
|
-
// Check if a token has been revoked
|
|
49
|
-
if (!payload.jti) {
|
|
50
|
-
this.logger.error('Refresh token payload does not contain JTI');
|
|
51
|
-
throw new UnauthorizedException('Invalid token payload');
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const isRevoked = await this.revokedTokensService.isTokenRevoked(payload.jti, payload.sid);
|
|
55
|
-
if (isRevoked) {
|
|
56
|
-
this.logger.debug(`Refresh token with JTI ${payload.jti} has already been revoked`);
|
|
57
|
-
throw new UnauthorizedException('Token has been revoked');
|
|
58
|
-
} else {
|
|
59
|
-
// Refresh token is valid, we revoke it to prevent reuse
|
|
60
|
-
this.logger.debug(`Revoking refresh token with JTI ${payload.jti}`);
|
|
61
|
-
await this.revokedTokensService.revokeRefreshToken({
|
|
62
|
-
jti: payload.jti,
|
|
63
|
-
expiresAt: new Date(
|
|
64
|
-
payload.exp
|
|
65
|
-
? payload.exp * 1000
|
|
66
|
-
: Date.now() + ms(this.jwtAuthConfigService.config.refreshTokenExpiration)
|
|
67
|
-
),
|
|
68
|
-
sid: payload.sid || null,
|
|
69
|
-
tokenType: TOKEN_TYPE.REFRESH,
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const userId = payload.sub;
|
|
74
|
-
const user = await this.usersService.findOne({
|
|
75
|
-
select: ['id', 'email', 'role', 'permissions'],
|
|
76
|
-
where: { id: userId },
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
if (!user) {
|
|
80
|
-
throw new UnauthorizedException();
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return user;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { Injectable } from "@nestjs/common";
|
|
2
|
-
import { JwtService } from "@nestjs/jwt";
|
|
3
|
-
import { TJWTPayload, TJWTRefreshPayload } from "./jwt-auth.srtategy";
|
|
4
|
-
import { RevokedToken, RevokedTokensService, TOKEN_TYPE, TRevokedToken } from '../revoked-tokens';
|
|
5
|
-
import { v4 as uuidv4 } from 'uuid';
|
|
6
|
-
import { JWTAuthConfigService, TJWTAuthConfig } from "./jwt-auth.config";
|
|
7
|
-
import { JwtSignOptions } from "@nestjs/jwt/dist/interfaces";
|
|
8
|
-
import ms from 'ms';
|
|
9
|
-
|
|
10
|
-
@Injectable()
|
|
11
|
-
export class JWTAuthService {
|
|
12
|
-
private readonly config: TJWTAuthConfig;
|
|
13
|
-
|
|
14
|
-
constructor(
|
|
15
|
-
private readonly jwtService: JwtService,
|
|
16
|
-
private revokedTokensService: RevokedTokensService,
|
|
17
|
-
private readonly jwtAuthConfig: JWTAuthConfigService,
|
|
18
|
-
) {
|
|
19
|
-
this.config = this.jwtAuthConfig.config;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
public generateJwtId(): string {
|
|
23
|
-
return uuidv4();
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
public sign<PayloadType extends TJWTPayload | TJWTRefreshPayload>(
|
|
27
|
-
payload: PayloadType,
|
|
28
|
-
tokenType: TOKEN_TYPE,
|
|
29
|
-
) {
|
|
30
|
-
const expiresIn = tokenType === TOKEN_TYPE.ACCESS
|
|
31
|
-
? this.config.accessTokenExpiration
|
|
32
|
-
: this.config.refreshTokenExpiration;
|
|
33
|
-
const options: JwtSignOptions = {
|
|
34
|
-
expiresIn,
|
|
35
|
-
jwtid: this.generateJwtId(),
|
|
36
|
-
}
|
|
37
|
-
return {
|
|
38
|
-
token: this.jwtService.sign(payload, options),
|
|
39
|
-
payload: {
|
|
40
|
-
...payload,
|
|
41
|
-
exp: Math.floor((ms(expiresIn) + Date.now()) / 1000),
|
|
42
|
-
jti: options.jwtid,
|
|
43
|
-
sid: payload.sid,
|
|
44
|
-
} as PayloadType,
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
public decode<T = TJWTPayload>(token: string): T {
|
|
49
|
-
return this.jwtService.decode(token) as T;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Revoke a JWT token by its JTI
|
|
54
|
-
* @param token The token to revoke
|
|
55
|
-
*/
|
|
56
|
-
public async revokeToken(token: TRevokedToken) {
|
|
57
|
-
return this.revokedTokensService.revokeToken(token, this.config.refreshTokenExpiration);
|
|
58
|
-
}
|
|
59
|
-
}
|