-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Expand file tree
/
Copy pathapikey.strategy.ts
More file actions
76 lines (64 loc) · 2.19 KB
/
apikey.strategy.ts
File metadata and controls
76 lines (64 loc) · 2.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import { Injectable, ServiceUnavailableException } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import {
FeatureFlagsService,
HttpRequestHeaderKeysEnum,
InMemoryLRUCacheService,
InMemoryLRUCacheStore,
} from '@novu/application-generic';
import { ApiAuthSchemeEnum, FeatureFlagsKeysEnum, UserSessionData } from '@novu/shared';
import { createHash } from 'crypto';
import { HeaderAPIKeyStrategy } from 'passport-headerapikey';
import { AuthService } from '../auth.service';
import { addNewRelicTraceAttributes } from './newrelic.util';
@Injectable()
export class ApiKeyStrategy extends PassportStrategy(HeaderAPIKeyStrategy) {
constructor(
private readonly authService: AuthService,
private readonly featureFlagsService: FeatureFlagsService,
private readonly inMemoryLRUCacheService: InMemoryLRUCacheService
) {
super(
{
header: HttpRequestHeaderKeysEnum.AUTHORIZATION,
prefix: `${ApiAuthSchemeEnum.API_KEY} `,
},
false
);
}
async validate(apiKey: string): Promise<UserSessionData | false> {
const user = await this.validateApiKey(apiKey);
if (!user) {
return false;
}
addNewRelicTraceAttributes(user);
return user;
}
private async validateApiKey(apiKey: string): Promise<UserSessionData | null> {
const hashedApiKey = createHash('sha256').update(apiKey).digest('hex');
const user = await this.inMemoryLRUCacheService.get(
InMemoryLRUCacheStore.API_KEY_USER,
hashedApiKey,
() => this.authService.getUserByApiKey(apiKey),
{
environmentId: 'system',
}
);
if (user) {
await this.checkKillSwitch(user);
}
return user;
}
private async checkKillSwitch(user: UserSessionData): Promise<void> {
const isKillSwitchEnabled = await this.featureFlagsService.getFlag({
key: FeatureFlagsKeysEnum.IS_ORG_KILLSWITCH_FLAG_ENABLED,
defaultValue: false,
organization: { _id: user.organizationId },
environment: { _id: user.environmentId },
component: 'api',
});
if (isKillSwitchEnabled) {
throw new ServiceUnavailableException('Service temporarily unavailable for this organization');
}
}
}