-
Notifications
You must be signed in to change notification settings - Fork 211
Expand file tree
/
Copy pathability.guard.ts
More file actions
93 lines (79 loc) · 2.65 KB
/
ability.guard.ts
File metadata and controls
93 lines (79 loc) · 2.65 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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
/*
* Copyright © 2025 Hexastack. All rights reserved.
*
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
*/
import { Url } from 'url';
import {
CanActivate,
ExecutionContext,
Injectable,
NotFoundException,
UnauthorizedException,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Request } from 'express';
import { AuthorizationService } from '@/authorization/authorization.service';
import { TRole } from '../schemas/role.schema';
import { User } from '../schemas/user.schema';
import { TModel } from '../types/model.type';
@Injectable()
export class Ability implements CanActivate {
constructor(
private reflector: Reflector,
private readonly authorizationService: AuthorizationService,
) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const roles = this.reflector.get<TRole[]>('roles', context.getHandler());
if (roles?.includes('public')) {
return true;
}
const { user, method, _parsedUrl, session } = context
.switchToHttp()
.getRequest<Request & { user: User; _parsedUrl: Url }>();
if (!user) {
throw new UnauthorizedException();
}
if (!session?.cookie || session.cookie.expires < new Date()) {
throw new UnauthorizedException('Session expired');
}
if (user?.roles?.length) {
if (
_parsedUrl.pathname &&
[
// Allow access to all routes available for authenticated users
'/auth/logout',
'/logout',
'/auth/me',
'/channel',
'/i18n',
// Allow to update own profile
`/user/edit/${user.id}`,
// Allow access to own avatar
`/user/${user.id}/profile_pic`,
].includes(_parsedUrl.pathname)
) {
return true;
}
const modelFromPathname = _parsedUrl?.pathname
?.split('/')[1]
.toLowerCase() as TModel | undefined;
if (!modelFromPathname) {
return false;
}
try {
const hasAbility = await this.authorizationService.canAccess(
method,
user.id,
modelFromPathname,
);
return hasAbility;
} catch (e) {
throw new NotFoundException('Failed to load permissions');
}
}
return false;
}
}