exguard-endpoint 1.0.1 → 1.0.3
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/README.md +79 -13
- package/dist/index.cjs +97 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -1
- package/dist/index.d.ts +38 -1
- package/dist/index.js +101 -3
- package/dist/index.js.map +1 -1
- package/dist/setup.cjs +204 -0
- package/package.json +11 -5
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# ExGuard Endpoint
|
|
2
2
|
|
|
3
|
-
Simple RBAC permission guard for NestJS.
|
|
3
|
+
Simple RBAC permission guard for NestJS with realtime support.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -8,19 +8,42 @@ Simple RBAC permission guard for NestJS.
|
|
|
8
8
|
npm install exguard-endpoint
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
## Quick Setup
|
|
11
|
+
## Quick Setup (Recommended)
|
|
12
|
+
|
|
13
|
+
Run in your NestJS project root:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx exguard-endpoint setup
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
This creates:
|
|
20
|
+
- `src/exguard/exguard.guard.ts` - The permission guard
|
|
21
|
+
- `src/exguard/exguard.module.ts` - The module
|
|
22
|
+
|
|
23
|
+
Then follow the printed instructions.
|
|
24
|
+
|
|
25
|
+
## Manual Setup
|
|
12
26
|
|
|
13
27
|
### 1. Configure AppModule
|
|
14
28
|
|
|
15
29
|
```typescript
|
|
30
|
+
// src/app.module.ts
|
|
16
31
|
import { Module } from '@nestjs/common';
|
|
17
32
|
import { ExGuardModule } from 'exguard-endpoint';
|
|
18
33
|
|
|
19
34
|
@Module({
|
|
20
35
|
imports: [
|
|
21
36
|
ExGuardModule.forRoot({
|
|
22
|
-
baseUrl: 'https://api.exguard.com',
|
|
37
|
+
baseUrl: process.env.EXGUARD_BASE_URL || 'https://api.exguard.com',
|
|
23
38
|
apiKey: process.env.EXGUARD_API_KEY,
|
|
39
|
+
cache: {
|
|
40
|
+
enabled: true,
|
|
41
|
+
ttl: 300000, // 5 minutes
|
|
42
|
+
},
|
|
43
|
+
realtime: {
|
|
44
|
+
enabled: true,
|
|
45
|
+
url: process.env.EXGUARD_REALTIME_URL,
|
|
46
|
+
},
|
|
24
47
|
}),
|
|
25
48
|
],
|
|
26
49
|
})
|
|
@@ -30,11 +53,12 @@ export class AppModule {}
|
|
|
30
53
|
### 2. Use in Controllers
|
|
31
54
|
|
|
32
55
|
```typescript
|
|
33
|
-
|
|
34
|
-
import {
|
|
56
|
+
// src/items/items.controller.ts
|
|
57
|
+
import { Controller, Get, Post, Patch, Delete, UseGuards } from '@nestjs/common';
|
|
58
|
+
import { ExGuardPermissionGuard, RequirePermissions } from '../exguard/exguard.guard';
|
|
35
59
|
|
|
36
60
|
@Controller('items')
|
|
37
|
-
@UseGuards(ExGuardPermissionGuard)
|
|
61
|
+
@UseGuards(ExGuardPermissionGuard) // Apply to all routes in this controller
|
|
38
62
|
export class ItemsController {
|
|
39
63
|
|
|
40
64
|
// User needs ANY of these permissions
|
|
@@ -42,30 +66,72 @@ export class ItemsController {
|
|
|
42
66
|
@RequirePermissions(['item:read'])
|
|
43
67
|
findAll() { }
|
|
44
68
|
|
|
69
|
+
// Multiple permissions - needs ALL
|
|
45
70
|
@Post()
|
|
46
|
-
@RequirePermissions(['item:create'])
|
|
71
|
+
@RequirePermissions(['item:create', 'item:admin'], true)
|
|
47
72
|
create() { }
|
|
48
73
|
|
|
49
|
-
|
|
74
|
+
@Patch(':id')
|
|
75
|
+
@RequirePermissions(['item:update'])
|
|
76
|
+
update() { }
|
|
77
|
+
|
|
50
78
|
@Delete(':id')
|
|
51
79
|
@RequirePermissions(['item:delete', 'admin'], true)
|
|
52
80
|
delete() { }
|
|
53
81
|
}
|
|
54
82
|
```
|
|
55
83
|
|
|
56
|
-
##
|
|
84
|
+
## Environment Variables
|
|
85
|
+
|
|
86
|
+
Add to your `.env` file:
|
|
87
|
+
|
|
88
|
+
```env
|
|
89
|
+
EXGUARD_BASE_URL=https://api.exguard.com
|
|
90
|
+
EXGUARD_API_KEY=your_api_key_here
|
|
91
|
+
EXGUARD_REALTIME_URL=wss://realtime.exguard.com
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## API Reference
|
|
95
|
+
|
|
96
|
+
### Decorators
|
|
57
97
|
|
|
58
98
|
| Decorator | Description |
|
|
59
99
|
|-----------|-------------|
|
|
60
|
-
| `@RequirePermissions(['
|
|
61
|
-
| `@RequirePermissions(['
|
|
100
|
+
| `@RequirePermissions(['item:read'])` | User needs ANY of the listed permissions |
|
|
101
|
+
| `@RequirePermissions(['item:delete', 'admin'], true)` | User needs ALL listed permissions |
|
|
62
102
|
|
|
63
|
-
|
|
103
|
+
### ExGuardModule.forRoot Options
|
|
64
104
|
|
|
65
|
-
|
|
105
|
+
| Option | Type | Required | Default | Description |
|
|
106
|
+
|--------|------|----------|---------|-------------|
|
|
107
|
+
| baseUrl | string | Yes | - | ExGuard API base URL |
|
|
108
|
+
| apiKey | string | Yes | - | Your API key |
|
|
109
|
+
| cache.enabled | boolean | No | true | Enable caching |
|
|
110
|
+
| cache.ttl | number | No | 300000 | Cache TTL in ms (5 min) |
|
|
111
|
+
| realtime.enabled | boolean | No | false | Enable realtime connection |
|
|
112
|
+
| realtime.url | string | No | - | Realtime WebSocket URL |
|
|
113
|
+
|
|
114
|
+
### Token Extraction
|
|
115
|
+
|
|
116
|
+
The guard automatically extracts token from:
|
|
66
117
|
- `Authorization: Bearer <token>` header
|
|
67
118
|
- `x-access-token` header
|
|
68
119
|
|
|
120
|
+
### Request User
|
|
121
|
+
|
|
122
|
+
After successful authentication, the user object is available at:
|
|
123
|
+
```typescript
|
|
124
|
+
@Request() req: any
|
|
125
|
+
console.log(req.user); // { id, username, email, roles, modules }
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Realtime Features
|
|
129
|
+
|
|
130
|
+
When realtime is enabled:
|
|
131
|
+
- Permission changes are detected in real-time
|
|
132
|
+
- Cache is automatically cleared when permissions update
|
|
133
|
+
- Events: `permission:update`, `user:update`
|
|
134
|
+
|
|
69
135
|
## License
|
|
70
136
|
|
|
71
137
|
MIT
|
package/dist/index.cjs
CHANGED
|
@@ -37,7 +37,8 @@ __export(src_exports, {
|
|
|
37
37
|
RequirePermissions: () => RequirePermissions,
|
|
38
38
|
RequireRoles: () => RequireRoles,
|
|
39
39
|
cache: () => cache,
|
|
40
|
-
createExGuardClient: () => createExGuardClient
|
|
40
|
+
createExGuardClient: () => createExGuardClient,
|
|
41
|
+
realtime: () => realtime
|
|
41
42
|
});
|
|
42
43
|
module.exports = __toCommonJS(src_exports);
|
|
43
44
|
|
|
@@ -63,13 +64,96 @@ var ExGuardCache = class {
|
|
|
63
64
|
ttl: ttl || this.ttl
|
|
64
65
|
});
|
|
65
66
|
}
|
|
67
|
+
delete(key) {
|
|
68
|
+
this.cache.delete(key);
|
|
69
|
+
}
|
|
70
|
+
clear() {
|
|
71
|
+
this.cache.clear();
|
|
72
|
+
}
|
|
73
|
+
clearUser(userId) {
|
|
74
|
+
for (const key of this.cache.keys()) {
|
|
75
|
+
if (key.includes(userId)) {
|
|
76
|
+
this.cache.delete(key);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
66
80
|
};
|
|
67
81
|
var cache = new ExGuardCache();
|
|
82
|
+
var ExGuardRealtime = class {
|
|
83
|
+
constructor() {
|
|
84
|
+
this.socket = null;
|
|
85
|
+
this.connected = false;
|
|
86
|
+
this.url = "";
|
|
87
|
+
this.events = {};
|
|
88
|
+
}
|
|
89
|
+
connect(url, events = {}) {
|
|
90
|
+
this.url = url;
|
|
91
|
+
this.events = events;
|
|
92
|
+
if (!url) {
|
|
93
|
+
console.log("[ExGuard] Realtime URL not provided, skipping connection");
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
const { io } = require("socket.io-client");
|
|
98
|
+
this.socket = io(url, {
|
|
99
|
+
transports: ["websocket"],
|
|
100
|
+
reconnection: true,
|
|
101
|
+
reconnectionAttempts: 5,
|
|
102
|
+
reconnectionDelay: 1e3
|
|
103
|
+
});
|
|
104
|
+
this.socket.on("connect", () => {
|
|
105
|
+
this.connected = true;
|
|
106
|
+
console.log("[ExGuard] Realtime connected");
|
|
107
|
+
this.events.onConnect?.();
|
|
108
|
+
});
|
|
109
|
+
this.socket.on("disconnect", () => {
|
|
110
|
+
this.connected = false;
|
|
111
|
+
console.log("[ExGuard] Realtime disconnected");
|
|
112
|
+
this.events.onDisconnect?.();
|
|
113
|
+
});
|
|
114
|
+
this.socket.on("permission:update", (data) => {
|
|
115
|
+
console.log("[ExGuard] Permission update received:", data);
|
|
116
|
+
cache.clearUser(data.userId);
|
|
117
|
+
this.events.onPermissionUpdate?.(data);
|
|
118
|
+
});
|
|
119
|
+
this.socket.on("user:update", (data) => {
|
|
120
|
+
console.log("[ExGuard] User update received:", data);
|
|
121
|
+
cache.clearUser(data.userId);
|
|
122
|
+
this.events.onUserUpdate?.(data);
|
|
123
|
+
});
|
|
124
|
+
this.socket.on("connect_error", (err) => {
|
|
125
|
+
console.error("[ExGuard] Realtime connection error:", err.message);
|
|
126
|
+
});
|
|
127
|
+
} catch (error) {
|
|
128
|
+
console.error("[ExGuard] Failed to load socket.io-client:", error);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
disconnect() {
|
|
132
|
+
if (this.socket) {
|
|
133
|
+
this.socket.disconnect();
|
|
134
|
+
this.socket = null;
|
|
135
|
+
this.connected = false;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
isConnected() {
|
|
139
|
+
return this.connected;
|
|
140
|
+
}
|
|
141
|
+
emit(event, data) {
|
|
142
|
+
if (this.socket && this.connected) {
|
|
143
|
+
this.socket.emit(event, data);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
var realtime = new ExGuardRealtime();
|
|
68
148
|
var ExGuardClient = class {
|
|
69
149
|
constructor(config) {
|
|
70
150
|
this.baseUrl = config.baseUrl;
|
|
71
151
|
this.apiKey = config.apiKey;
|
|
72
152
|
this.cache = cache;
|
|
153
|
+
this.realtime = realtime;
|
|
154
|
+
if (config.realtime?.enabled && config.realtime?.url) {
|
|
155
|
+
this.realtime.connect(config.realtime.url);
|
|
156
|
+
}
|
|
73
157
|
}
|
|
74
158
|
async authenticate(context) {
|
|
75
159
|
const cacheKey = `auth:${context.token}`;
|
|
@@ -104,6 +188,12 @@ var ExGuardClient = class {
|
|
|
104
188
|
const userPermissions = result.user.modules?.flatMap((m) => m.permissions) || [];
|
|
105
189
|
return userPermissions.includes(permission);
|
|
106
190
|
}
|
|
191
|
+
clearCache() {
|
|
192
|
+
this.cache.clear();
|
|
193
|
+
}
|
|
194
|
+
disconnectRealtime() {
|
|
195
|
+
this.realtime.disconnect();
|
|
196
|
+
}
|
|
107
197
|
};
|
|
108
198
|
function createExGuardClient(config) {
|
|
109
199
|
return new ExGuardClient(config);
|
|
@@ -116,7 +206,8 @@ var ExGuardModule = class {
|
|
|
116
206
|
const client = new ExGuardClient({
|
|
117
207
|
baseUrl: options.baseUrl,
|
|
118
208
|
apiKey: options.apiKey,
|
|
119
|
-
cache: options.cache
|
|
209
|
+
cache: options.cache,
|
|
210
|
+
realtime: options.realtime
|
|
120
211
|
});
|
|
121
212
|
return {
|
|
122
213
|
module: ExGuardModule,
|
|
@@ -151,7 +242,8 @@ var ExGuardPermissionGuard = class {
|
|
|
151
242
|
throw new import_common2.UnauthorizedException("No token provided");
|
|
152
243
|
}
|
|
153
244
|
if (!this.client) {
|
|
154
|
-
|
|
245
|
+
console.warn("[ExGuard] Client not configured. Access denied.");
|
|
246
|
+
return false;
|
|
155
247
|
}
|
|
156
248
|
const authResult = await this.client.authenticate({ token, request });
|
|
157
249
|
if (!authResult.allowed) {
|
|
@@ -233,6 +325,7 @@ function RequireRoles(roles, requireAll = false) {
|
|
|
233
325
|
RequirePermissions,
|
|
234
326
|
RequireRoles,
|
|
235
327
|
cache,
|
|
236
|
-
createExGuardClient
|
|
328
|
+
createExGuardClient,
|
|
329
|
+
realtime
|
|
237
330
|
});
|
|
238
331
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/client.ts","../src/module.ts","../src/guard.ts"],"sourcesContent":["export { ExGuardClient, createExGuardClient, cache } from './client.js';\nexport type { ExGuardConfig, User, ModulePermission, UserAccessResponse, GuardContext, GuardResult } from './client.js';\nexport { ExGuardModule } from './module.js';\nexport type { ExGuardModuleOptions } from './module.js';\nexport { ExGuardPermissionGuard, RequirePermissions, RequireRoles, EXGUARD_PERMISSIONS_KEY, EXGUARD_ROLES_KEY } from './guard.js';\n","export interface ExGuardConfig {\n baseUrl: string;\n apiKey: string;\n cache?: {\n enabled?: boolean;\n ttl?: number;\n };\n}\n\nexport interface User {\n id: string;\n username: string;\n email: string;\n}\n\nexport interface ModulePermission {\n key: string;\n name: string;\n permissions: string[];\n}\n\nexport interface UserAccessResponse {\n user: User;\n roles: string[];\n modules: ModulePermission[];\n}\n\nexport interface GuardContext {\n token: string;\n request?: any;\n}\n\nexport interface GuardResult {\n allowed: boolean;\n user?: UserAccessResponse;\n error?: string;\n}\n\nclass ExGuardCache {\n private cache = new Map<string, { data: any; timestamp: number; ttl: number }>();\n private ttl = 300000;\n\n get(key: string): any {\n const entry = this.cache.get(key);\n if (!entry) return null;\n if (Date.now() - entry.timestamp > entry.ttl) {\n this.cache.delete(key);\n return null;\n }\n return entry.data;\n }\n\n set(key: string, data: any, ttl?: number): void {\n this.cache.set(key, {\n data,\n timestamp: Date.now(),\n ttl: ttl || this.ttl,\n });\n }\n}\n\nconst cache = new ExGuardCache();\n\nexport class ExGuardClient {\n private baseUrl: string;\n private apiKey: string;\n private cache: ExGuardCache;\n\n constructor(config: ExGuardConfig) {\n this.baseUrl = config.baseUrl;\n this.apiKey = config.apiKey;\n this.cache = cache;\n }\n\n async authenticate(context: GuardContext): Promise<GuardResult> {\n const cacheKey = `auth:${context.token}`;\n const cached = this.cache.get(cacheKey);\n if (cached) return cached;\n\n try {\n const response = await fetch(`${this.baseUrl}/api/v1/auth/validate`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({ token: context.token }),\n });\n\n if (!response.ok) {\n return { allowed: false, error: 'Invalid token' };\n }\n\n const data = await response.json();\n const result: GuardResult = {\n allowed: true,\n user: data.user || data.data?.user,\n };\n\n this.cache.set(cacheKey, result);\n return result;\n } catch (error) {\n return { allowed: false, error: 'Authentication failed' };\n }\n }\n\n async hasPermission(token: string, permission: string): Promise<boolean> {\n const result = await this.authenticate({ token });\n if (!result.allowed || !result.user) return false;\n\n const userPermissions = result.user.modules?.flatMap(m => m.permissions) || [];\n return userPermissions.includes(permission);\n }\n}\n\nexport function createExGuardClient(config: ExGuardConfig): ExGuardClient {\n return new ExGuardClient(config);\n}\n\nexport { cache };\n","import { Module, Global, DynamicModule } from '@nestjs/common';\nimport { ExGuardClient } from './client.js';\n\nexport interface ExGuardModuleOptions {\n baseUrl: string;\n apiKey: string;\n cache?: {\n enabled?: boolean;\n ttl?: number;\n };\n}\n\n@Global()\n@Module({})\nexport class ExGuardModule {\n static forRoot(options: ExGuardModuleOptions): DynamicModule {\n const client = new ExGuardClient({\n baseUrl: options.baseUrl,\n apiKey: options.apiKey,\n cache: options.cache,\n });\n\n return {\n module: ExGuardModule,\n providers: [\n {\n provide: 'EXGUARD_CLIENT',\n useValue: client,\n },\n ],\n exports: ['EXGUARD_CLIENT'],\n };\n }\n}\n","import { Injectable, CanActivate, ExecutionContext, UnauthorizedException, ForbiddenException, Inject, Optional } from '@nestjs/common';\nimport { Reflector } from '@nestjs/core';\nimport { ExGuardClient } from './client.js';\n\nexport const EXGUARD_PERMISSIONS_KEY = 'exguard_permissions';\nexport const EXGUARD_ROLES_KEY = 'exguard_roles';\n\n@Injectable()\nexport class ExGuardPermissionGuard implements CanActivate {\n constructor(\n @Optional() @Inject('EXGUARD_CLIENT') private client: ExGuardClient,\n private reflector: Reflector,\n ) {}\n\n async canActivate(context: ExecutionContext): Promise<boolean> {\n const request = context.switchToHttp().getRequest();\n const token = this.extractToken(request);\n\n if (!token) {\n throw new UnauthorizedException('No token provided');\n }\n\n if (!this.client) {\n return true;\n }\n\n const authResult = await this.client.authenticate({ token, request });\n\n if (!authResult.allowed) {\n throw new ForbiddenException(authResult.error || 'Access denied');\n }\n\n if (!authResult.user) {\n throw new ForbiddenException('User not found');\n }\n\n const handler = context.getHandler();\n const permMeta = this.reflector.get<{ permissions: string[]; requireAll?: boolean }>(\n EXGUARD_PERMISSIONS_KEY,\n handler,\n );\n\n if (permMeta) {\n const { permissions, requireAll } = permMeta;\n const userPermissions = authResult.user.modules?.flatMap(m => m.permissions) || [];\n\n if (requireAll) {\n if (!permissions.every(p => userPermissions.includes(p))) {\n throw new ForbiddenException('Insufficient permissions');\n }\n } else {\n if (!permissions.some(p => userPermissions.includes(p))) {\n throw new ForbiddenException('Insufficient permissions');\n }\n }\n }\n\n const roleMeta = this.reflector.get<{ roles: string[]; requireAll?: boolean }>(\n EXGUARD_ROLES_KEY,\n handler,\n );\n\n if (roleMeta) {\n const { roles, requireAll } = roleMeta;\n const userRoles = authResult.user.roles || [];\n\n if (requireAll) {\n if (!roles.every(r => userRoles.includes(r))) {\n throw new ForbiddenException('Insufficient roles');\n }\n } else {\n if (!roles.some(r => userRoles.includes(r))) {\n throw new ForbiddenException('Insufficient roles');\n }\n }\n }\n\n request.user = authResult.user;\n return true;\n }\n\n private extractToken(request: any): string | null {\n const auth = request.headers?.authorization;\n if (auth?.startsWith('Bearer ')) {\n return auth.substring(7);\n }\n return request.headers?.['x-access-token'] || null;\n }\n}\n\nexport function RequirePermissions(permissions: string[], requireAll = false) {\n return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {\n Reflect.defineMetadata(EXGUARD_PERMISSIONS_KEY, { permissions, requireAll }, descriptor.value);\n return descriptor;\n };\n}\n\nexport function RequireRoles(roles: string[], requireAll = false) {\n return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {\n Reflect.defineMetadata(EXGUARD_ROLES_KEY, { roles, requireAll }, descriptor.value);\n return descriptor;\n };\n}\n"],"mappings":"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","names":["import_common"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/client.ts","../src/module.ts","../src/guard.ts"],"sourcesContent":["export { ExGuardClient, createExGuardClient, cache, realtime } from './client.js';\nexport type { ExGuardConfig, User, ModulePermission, UserAccessResponse, GuardContext, GuardResult, RealtimeEvents } from './client.js';\nexport { ExGuardModule } from './module.js';\nexport type { ExGuardModuleOptions } from './module.js';\nexport { ExGuardPermissionGuard, RequirePermissions, RequireRoles, EXGUARD_PERMISSIONS_KEY, EXGUARD_ROLES_KEY } from './guard.js';\n","export interface ExGuardConfig {\n baseUrl: string;\n apiKey: string;\n cache?: {\n enabled?: boolean;\n ttl?: number;\n };\n realtime?: {\n enabled?: boolean;\n url?: string;\n };\n}\n\nexport interface User {\n id: string;\n username: string;\n email: string;\n}\n\nexport interface ModulePermission {\n key: string;\n name: string;\n permissions: string[];\n}\n\nexport interface UserAccessResponse {\n user: User;\n roles: string[];\n modules: ModulePermission[];\n}\n\nexport interface GuardContext {\n token: string;\n request?: any;\n}\n\nexport interface GuardResult {\n allowed: boolean;\n user?: UserAccessResponse;\n error?: string;\n}\n\nexport interface RealtimeEvents {\n onConnect?: () => void;\n onDisconnect?: () => void;\n onPermissionUpdate?: (data: { userId: string; permissions: string[] }) => void;\n onUserUpdate?: (data: { userId: string; user: UserAccessResponse }) => void;\n}\n\nclass ExGuardCache {\n private cache = new Map<string, { data: any; timestamp: number; ttl: number }>();\n private ttl = 300000;\n\n get(key: string): any {\n const entry = this.cache.get(key);\n if (!entry) return null;\n if (Date.now() - entry.timestamp > entry.ttl) {\n this.cache.delete(key);\n return null;\n }\n return entry.data;\n }\n\n set(key: string, data: any, ttl?: number): void {\n this.cache.set(key, {\n data,\n timestamp: Date.now(),\n ttl: ttl || this.ttl,\n });\n }\n\n delete(key: string): void {\n this.cache.delete(key);\n }\n\n clear(): void {\n this.cache.clear();\n }\n\n clearUser(userId: string): void {\n for (const key of this.cache.keys()) {\n if (key.includes(userId)) {\n this.cache.delete(key);\n }\n }\n }\n}\n\nconst cache = new ExGuardCache();\n\nclass ExGuardRealtime {\n private socket: any = null;\n private connected = false;\n private url: string = '';\n private events: RealtimeEvents = {};\n\n connect(url: string, events: RealtimeEvents = {}): void {\n this.url = url;\n this.events = events;\n \n if (!url) {\n console.log('[ExGuard] Realtime URL not provided, skipping connection');\n return;\n }\n\n try {\n const { io } = require('socket.io-client');\n this.socket = io(url, {\n transports: ['websocket'],\n reconnection: true,\n reconnectionAttempts: 5,\n reconnectionDelay: 1000,\n });\n\n this.socket.on('connect', () => {\n this.connected = true;\n console.log('[ExGuard] Realtime connected');\n this.events.onConnect?.();\n });\n\n this.socket.on('disconnect', () => {\n this.connected = false;\n console.log('[ExGuard] Realtime disconnected');\n this.events.onDisconnect?.();\n });\n\n this.socket.on('permission:update', (data: any) => {\n console.log('[ExGuard] Permission update received:', data);\n cache.clearUser(data.userId);\n this.events.onPermissionUpdate?.(data);\n });\n\n this.socket.on('user:update', (data: any) => {\n console.log('[ExGuard] User update received:', data);\n cache.clearUser(data.userId);\n this.events.onUserUpdate?.(data);\n });\n\n this.socket.on('connect_error', (err: any) => {\n console.error('[ExGuard] Realtime connection error:', err.message);\n });\n } catch (error) {\n console.error('[ExGuard] Failed to load socket.io-client:', error);\n }\n }\n\n disconnect(): void {\n if (this.socket) {\n this.socket.disconnect();\n this.socket = null;\n this.connected = false;\n }\n }\n\n isConnected(): boolean {\n return this.connected;\n }\n\n emit(event: string, data: any): void {\n if (this.socket && this.connected) {\n this.socket.emit(event, data);\n }\n }\n}\n\nconst realtime = new ExGuardRealtime();\n\nexport class ExGuardClient {\n private baseUrl: string;\n private apiKey: string;\n private cache: ExGuardCache;\n private realtime: ExGuardRealtime;\n\n constructor(config: ExGuardConfig) {\n this.baseUrl = config.baseUrl;\n this.apiKey = config.apiKey;\n this.cache = cache;\n this.realtime = realtime;\n\n if (config.realtime?.enabled && config.realtime?.url) {\n this.realtime.connect(config.realtime.url);\n }\n }\n\n async authenticate(context: GuardContext): Promise<GuardResult> {\n const cacheKey = `auth:${context.token}`;\n const cached = this.cache.get(cacheKey);\n if (cached) return cached;\n\n try {\n const response = await fetch(`${this.baseUrl}/api/v1/auth/validate`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({ token: context.token }),\n });\n\n if (!response.ok) {\n return { allowed: false, error: 'Invalid token' };\n }\n\n const data = await response.json();\n const result: GuardResult = {\n allowed: true,\n user: data.user || data.data?.user,\n };\n\n this.cache.set(cacheKey, result);\n return result;\n } catch (error) {\n return { allowed: false, error: 'Authentication failed' };\n }\n }\n\n async hasPermission(token: string, permission: string): Promise<boolean> {\n const result = await this.authenticate({ token });\n if (!result.allowed || !result.user) return false;\n\n const userPermissions = result.user.modules?.flatMap(m => m.permissions) || [];\n return userPermissions.includes(permission);\n }\n\n clearCache(): void {\n this.cache.clear();\n }\n\n disconnectRealtime(): void {\n this.realtime.disconnect();\n }\n}\n\nexport function createExGuardClient(config: ExGuardConfig): ExGuardClient {\n return new ExGuardClient(config);\n}\n\nexport { cache, realtime };\n","import { Module, Global, DynamicModule } from '@nestjs/common';\nimport { ExGuardClient } from './client.js';\n\nexport interface ExGuardModuleOptions {\n baseUrl: string;\n apiKey: string;\n cache?: {\n enabled?: boolean;\n ttl?: number;\n };\n realtime?: {\n enabled?: boolean;\n url?: string;\n };\n}\n\n@Global()\n@Module({})\nexport class ExGuardModule {\n static forRoot(options: ExGuardModuleOptions): DynamicModule {\n const client = new ExGuardClient({\n baseUrl: options.baseUrl,\n apiKey: options.apiKey,\n cache: options.cache,\n realtime: options.realtime,\n });\n\n return {\n module: ExGuardModule,\n providers: [\n {\n provide: 'EXGUARD_CLIENT',\n useValue: client,\n },\n ],\n exports: ['EXGUARD_CLIENT'],\n };\n }\n}\n","import { Injectable, CanActivate, ExecutionContext, UnauthorizedException, ForbiddenException, Inject, Optional } from '@nestjs/common';\nimport { Reflector } from '@nestjs/core';\nimport { ExGuardClient } from './client.js';\n\nexport const EXGUARD_PERMISSIONS_KEY = 'exguard_permissions';\nexport const EXGUARD_ROLES_KEY = 'exguard_roles';\n\n@Injectable()\nexport class ExGuardPermissionGuard implements CanActivate {\n constructor(\n @Optional() @Inject('EXGUARD_CLIENT') private client: ExGuardClient,\n private reflector: Reflector,\n ) {}\n\n async canActivate(context: ExecutionContext): Promise<boolean> {\n const request = context.switchToHttp().getRequest();\n const token = this.extractToken(request);\n\n if (!token) {\n throw new UnauthorizedException('No token provided');\n }\n\n if (!this.client) {\n console.warn('[ExGuard] Client not configured. Access denied.');\n return false;\n }\n\n const authResult = await this.client.authenticate({ token, request });\n\n if (!authResult.allowed) {\n throw new ForbiddenException(authResult.error || 'Access denied');\n }\n\n if (!authResult.user) {\n throw new ForbiddenException('User not found');\n }\n\n const handler = context.getHandler();\n const permMeta = this.reflector.get<{ permissions: string[]; requireAll?: boolean }>(\n EXGUARD_PERMISSIONS_KEY,\n handler,\n );\n\n if (permMeta) {\n const { permissions, requireAll } = permMeta;\n const userPermissions = authResult.user.modules?.flatMap(m => m.permissions) || [];\n\n if (requireAll) {\n if (!permissions.every(p => userPermissions.includes(p))) {\n throw new ForbiddenException('Insufficient permissions');\n }\n } else {\n if (!permissions.some(p => userPermissions.includes(p))) {\n throw new ForbiddenException('Insufficient permissions');\n }\n }\n }\n\n const roleMeta = this.reflector.get<{ roles: string[]; requireAll?: boolean }>(\n EXGUARD_ROLES_KEY,\n handler,\n );\n\n if (roleMeta) {\n const { roles, requireAll } = roleMeta;\n const userRoles = authResult.user.roles || [];\n\n if (requireAll) {\n if (!roles.every(r => userRoles.includes(r))) {\n throw new ForbiddenException('Insufficient roles');\n }\n } else {\n if (!roles.some(r => userRoles.includes(r))) {\n throw new ForbiddenException('Insufficient roles');\n }\n }\n }\n\n request.user = authResult.user;\n return true;\n }\n\n private extractToken(request: any): string | null {\n const auth = request.headers?.authorization;\n if (auth?.startsWith('Bearer ')) {\n return auth.substring(7);\n }\n return request.headers?.['x-access-token'] || null;\n }\n}\n\nexport function RequirePermissions(permissions: string[], requireAll = false) {\n return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {\n Reflect.defineMetadata(EXGUARD_PERMISSIONS_KEY, { permissions, requireAll }, descriptor.value);\n return descriptor;\n };\n}\n\nexport function RequireRoles(roles: string[], requireAll = false) {\n return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {\n Reflect.defineMetadata(EXGUARD_ROLES_KEY, { roles, requireAll }, descriptor.value);\n return descriptor;\n };\n}\n"],"mappings":"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","names":["import_common"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -8,6 +8,10 @@ interface ExGuardConfig {
|
|
|
8
8
|
enabled?: boolean;
|
|
9
9
|
ttl?: number;
|
|
10
10
|
};
|
|
11
|
+
realtime?: {
|
|
12
|
+
enabled?: boolean;
|
|
13
|
+
url?: string;
|
|
14
|
+
};
|
|
11
15
|
}
|
|
12
16
|
interface User {
|
|
13
17
|
id: string;
|
|
@@ -33,20 +37,49 @@ interface GuardResult {
|
|
|
33
37
|
user?: UserAccessResponse;
|
|
34
38
|
error?: string;
|
|
35
39
|
}
|
|
40
|
+
interface RealtimeEvents {
|
|
41
|
+
onConnect?: () => void;
|
|
42
|
+
onDisconnect?: () => void;
|
|
43
|
+
onPermissionUpdate?: (data: {
|
|
44
|
+
userId: string;
|
|
45
|
+
permissions: string[];
|
|
46
|
+
}) => void;
|
|
47
|
+
onUserUpdate?: (data: {
|
|
48
|
+
userId: string;
|
|
49
|
+
user: UserAccessResponse;
|
|
50
|
+
}) => void;
|
|
51
|
+
}
|
|
36
52
|
declare class ExGuardCache {
|
|
37
53
|
private cache;
|
|
38
54
|
private ttl;
|
|
39
55
|
get(key: string): any;
|
|
40
56
|
set(key: string, data: any, ttl?: number): void;
|
|
57
|
+
delete(key: string): void;
|
|
58
|
+
clear(): void;
|
|
59
|
+
clearUser(userId: string): void;
|
|
41
60
|
}
|
|
42
61
|
declare const cache: ExGuardCache;
|
|
62
|
+
declare class ExGuardRealtime {
|
|
63
|
+
private socket;
|
|
64
|
+
private connected;
|
|
65
|
+
private url;
|
|
66
|
+
private events;
|
|
67
|
+
connect(url: string, events?: RealtimeEvents): void;
|
|
68
|
+
disconnect(): void;
|
|
69
|
+
isConnected(): boolean;
|
|
70
|
+
emit(event: string, data: any): void;
|
|
71
|
+
}
|
|
72
|
+
declare const realtime: ExGuardRealtime;
|
|
43
73
|
declare class ExGuardClient {
|
|
44
74
|
private baseUrl;
|
|
45
75
|
private apiKey;
|
|
46
76
|
private cache;
|
|
77
|
+
private realtime;
|
|
47
78
|
constructor(config: ExGuardConfig);
|
|
48
79
|
authenticate(context: GuardContext): Promise<GuardResult>;
|
|
49
80
|
hasPermission(token: string, permission: string): Promise<boolean>;
|
|
81
|
+
clearCache(): void;
|
|
82
|
+
disconnectRealtime(): void;
|
|
50
83
|
}
|
|
51
84
|
declare function createExGuardClient(config: ExGuardConfig): ExGuardClient;
|
|
52
85
|
|
|
@@ -57,6 +90,10 @@ interface ExGuardModuleOptions {
|
|
|
57
90
|
enabled?: boolean;
|
|
58
91
|
ttl?: number;
|
|
59
92
|
};
|
|
93
|
+
realtime?: {
|
|
94
|
+
enabled?: boolean;
|
|
95
|
+
url?: string;
|
|
96
|
+
};
|
|
60
97
|
}
|
|
61
98
|
declare class ExGuardModule {
|
|
62
99
|
static forRoot(options: ExGuardModuleOptions): DynamicModule;
|
|
@@ -74,4 +111,4 @@ declare class ExGuardPermissionGuard implements CanActivate {
|
|
|
74
111
|
declare function RequirePermissions(permissions: string[], requireAll?: boolean): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
|
|
75
112
|
declare function RequireRoles(roles: string[], requireAll?: boolean): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
|
|
76
113
|
|
|
77
|
-
export { EXGUARD_PERMISSIONS_KEY, EXGUARD_ROLES_KEY, ExGuardClient, type ExGuardConfig, ExGuardModule, type ExGuardModuleOptions, ExGuardPermissionGuard, type GuardContext, type GuardResult, type ModulePermission, RequirePermissions, RequireRoles, type User, type UserAccessResponse, cache, createExGuardClient };
|
|
114
|
+
export { EXGUARD_PERMISSIONS_KEY, EXGUARD_ROLES_KEY, ExGuardClient, type ExGuardConfig, ExGuardModule, type ExGuardModuleOptions, ExGuardPermissionGuard, type GuardContext, type GuardResult, type ModulePermission, type RealtimeEvents, RequirePermissions, RequireRoles, type User, type UserAccessResponse, cache, createExGuardClient, realtime };
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,10 @@ interface ExGuardConfig {
|
|
|
8
8
|
enabled?: boolean;
|
|
9
9
|
ttl?: number;
|
|
10
10
|
};
|
|
11
|
+
realtime?: {
|
|
12
|
+
enabled?: boolean;
|
|
13
|
+
url?: string;
|
|
14
|
+
};
|
|
11
15
|
}
|
|
12
16
|
interface User {
|
|
13
17
|
id: string;
|
|
@@ -33,20 +37,49 @@ interface GuardResult {
|
|
|
33
37
|
user?: UserAccessResponse;
|
|
34
38
|
error?: string;
|
|
35
39
|
}
|
|
40
|
+
interface RealtimeEvents {
|
|
41
|
+
onConnect?: () => void;
|
|
42
|
+
onDisconnect?: () => void;
|
|
43
|
+
onPermissionUpdate?: (data: {
|
|
44
|
+
userId: string;
|
|
45
|
+
permissions: string[];
|
|
46
|
+
}) => void;
|
|
47
|
+
onUserUpdate?: (data: {
|
|
48
|
+
userId: string;
|
|
49
|
+
user: UserAccessResponse;
|
|
50
|
+
}) => void;
|
|
51
|
+
}
|
|
36
52
|
declare class ExGuardCache {
|
|
37
53
|
private cache;
|
|
38
54
|
private ttl;
|
|
39
55
|
get(key: string): any;
|
|
40
56
|
set(key: string, data: any, ttl?: number): void;
|
|
57
|
+
delete(key: string): void;
|
|
58
|
+
clear(): void;
|
|
59
|
+
clearUser(userId: string): void;
|
|
41
60
|
}
|
|
42
61
|
declare const cache: ExGuardCache;
|
|
62
|
+
declare class ExGuardRealtime {
|
|
63
|
+
private socket;
|
|
64
|
+
private connected;
|
|
65
|
+
private url;
|
|
66
|
+
private events;
|
|
67
|
+
connect(url: string, events?: RealtimeEvents): void;
|
|
68
|
+
disconnect(): void;
|
|
69
|
+
isConnected(): boolean;
|
|
70
|
+
emit(event: string, data: any): void;
|
|
71
|
+
}
|
|
72
|
+
declare const realtime: ExGuardRealtime;
|
|
43
73
|
declare class ExGuardClient {
|
|
44
74
|
private baseUrl;
|
|
45
75
|
private apiKey;
|
|
46
76
|
private cache;
|
|
77
|
+
private realtime;
|
|
47
78
|
constructor(config: ExGuardConfig);
|
|
48
79
|
authenticate(context: GuardContext): Promise<GuardResult>;
|
|
49
80
|
hasPermission(token: string, permission: string): Promise<boolean>;
|
|
81
|
+
clearCache(): void;
|
|
82
|
+
disconnectRealtime(): void;
|
|
50
83
|
}
|
|
51
84
|
declare function createExGuardClient(config: ExGuardConfig): ExGuardClient;
|
|
52
85
|
|
|
@@ -57,6 +90,10 @@ interface ExGuardModuleOptions {
|
|
|
57
90
|
enabled?: boolean;
|
|
58
91
|
ttl?: number;
|
|
59
92
|
};
|
|
93
|
+
realtime?: {
|
|
94
|
+
enabled?: boolean;
|
|
95
|
+
url?: string;
|
|
96
|
+
};
|
|
60
97
|
}
|
|
61
98
|
declare class ExGuardModule {
|
|
62
99
|
static forRoot(options: ExGuardModuleOptions): DynamicModule;
|
|
@@ -74,4 +111,4 @@ declare class ExGuardPermissionGuard implements CanActivate {
|
|
|
74
111
|
declare function RequirePermissions(permissions: string[], requireAll?: boolean): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
|
|
75
112
|
declare function RequireRoles(roles: string[], requireAll?: boolean): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
|
|
76
113
|
|
|
77
|
-
export { EXGUARD_PERMISSIONS_KEY, EXGUARD_ROLES_KEY, ExGuardClient, type ExGuardConfig, ExGuardModule, type ExGuardModuleOptions, ExGuardPermissionGuard, type GuardContext, type GuardResult, type ModulePermission, RequirePermissions, RequireRoles, type User, type UserAccessResponse, cache, createExGuardClient };
|
|
114
|
+
export { EXGUARD_PERMISSIONS_KEY, EXGUARD_ROLES_KEY, ExGuardClient, type ExGuardConfig, ExGuardModule, type ExGuardModuleOptions, ExGuardPermissionGuard, type GuardContext, type GuardResult, type ModulePermission, type RealtimeEvents, RequirePermissions, RequireRoles, type User, type UserAccessResponse, cache, createExGuardClient, realtime };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
4
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
5
|
+
}) : x)(function(x) {
|
|
6
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
7
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
8
|
+
});
|
|
3
9
|
var __decorateClass = (decorators, target, key, kind) => {
|
|
4
10
|
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
5
11
|
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
@@ -32,13 +38,96 @@ var ExGuardCache = class {
|
|
|
32
38
|
ttl: ttl || this.ttl
|
|
33
39
|
});
|
|
34
40
|
}
|
|
41
|
+
delete(key) {
|
|
42
|
+
this.cache.delete(key);
|
|
43
|
+
}
|
|
44
|
+
clear() {
|
|
45
|
+
this.cache.clear();
|
|
46
|
+
}
|
|
47
|
+
clearUser(userId) {
|
|
48
|
+
for (const key of this.cache.keys()) {
|
|
49
|
+
if (key.includes(userId)) {
|
|
50
|
+
this.cache.delete(key);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
35
54
|
};
|
|
36
55
|
var cache = new ExGuardCache();
|
|
56
|
+
var ExGuardRealtime = class {
|
|
57
|
+
constructor() {
|
|
58
|
+
this.socket = null;
|
|
59
|
+
this.connected = false;
|
|
60
|
+
this.url = "";
|
|
61
|
+
this.events = {};
|
|
62
|
+
}
|
|
63
|
+
connect(url, events = {}) {
|
|
64
|
+
this.url = url;
|
|
65
|
+
this.events = events;
|
|
66
|
+
if (!url) {
|
|
67
|
+
console.log("[ExGuard] Realtime URL not provided, skipping connection");
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
const { io } = __require("socket.io-client");
|
|
72
|
+
this.socket = io(url, {
|
|
73
|
+
transports: ["websocket"],
|
|
74
|
+
reconnection: true,
|
|
75
|
+
reconnectionAttempts: 5,
|
|
76
|
+
reconnectionDelay: 1e3
|
|
77
|
+
});
|
|
78
|
+
this.socket.on("connect", () => {
|
|
79
|
+
this.connected = true;
|
|
80
|
+
console.log("[ExGuard] Realtime connected");
|
|
81
|
+
this.events.onConnect?.();
|
|
82
|
+
});
|
|
83
|
+
this.socket.on("disconnect", () => {
|
|
84
|
+
this.connected = false;
|
|
85
|
+
console.log("[ExGuard] Realtime disconnected");
|
|
86
|
+
this.events.onDisconnect?.();
|
|
87
|
+
});
|
|
88
|
+
this.socket.on("permission:update", (data) => {
|
|
89
|
+
console.log("[ExGuard] Permission update received:", data);
|
|
90
|
+
cache.clearUser(data.userId);
|
|
91
|
+
this.events.onPermissionUpdate?.(data);
|
|
92
|
+
});
|
|
93
|
+
this.socket.on("user:update", (data) => {
|
|
94
|
+
console.log("[ExGuard] User update received:", data);
|
|
95
|
+
cache.clearUser(data.userId);
|
|
96
|
+
this.events.onUserUpdate?.(data);
|
|
97
|
+
});
|
|
98
|
+
this.socket.on("connect_error", (err) => {
|
|
99
|
+
console.error("[ExGuard] Realtime connection error:", err.message);
|
|
100
|
+
});
|
|
101
|
+
} catch (error) {
|
|
102
|
+
console.error("[ExGuard] Failed to load socket.io-client:", error);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
disconnect() {
|
|
106
|
+
if (this.socket) {
|
|
107
|
+
this.socket.disconnect();
|
|
108
|
+
this.socket = null;
|
|
109
|
+
this.connected = false;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
isConnected() {
|
|
113
|
+
return this.connected;
|
|
114
|
+
}
|
|
115
|
+
emit(event, data) {
|
|
116
|
+
if (this.socket && this.connected) {
|
|
117
|
+
this.socket.emit(event, data);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
var realtime = new ExGuardRealtime();
|
|
37
122
|
var ExGuardClient = class {
|
|
38
123
|
constructor(config) {
|
|
39
124
|
this.baseUrl = config.baseUrl;
|
|
40
125
|
this.apiKey = config.apiKey;
|
|
41
126
|
this.cache = cache;
|
|
127
|
+
this.realtime = realtime;
|
|
128
|
+
if (config.realtime?.enabled && config.realtime?.url) {
|
|
129
|
+
this.realtime.connect(config.realtime.url);
|
|
130
|
+
}
|
|
42
131
|
}
|
|
43
132
|
async authenticate(context) {
|
|
44
133
|
const cacheKey = `auth:${context.token}`;
|
|
@@ -73,6 +162,12 @@ var ExGuardClient = class {
|
|
|
73
162
|
const userPermissions = result.user.modules?.flatMap((m) => m.permissions) || [];
|
|
74
163
|
return userPermissions.includes(permission);
|
|
75
164
|
}
|
|
165
|
+
clearCache() {
|
|
166
|
+
this.cache.clear();
|
|
167
|
+
}
|
|
168
|
+
disconnectRealtime() {
|
|
169
|
+
this.realtime.disconnect();
|
|
170
|
+
}
|
|
76
171
|
};
|
|
77
172
|
function createExGuardClient(config) {
|
|
78
173
|
return new ExGuardClient(config);
|
|
@@ -85,7 +180,8 @@ var ExGuardModule = class {
|
|
|
85
180
|
const client = new ExGuardClient({
|
|
86
181
|
baseUrl: options.baseUrl,
|
|
87
182
|
apiKey: options.apiKey,
|
|
88
|
-
cache: options.cache
|
|
183
|
+
cache: options.cache,
|
|
184
|
+
realtime: options.realtime
|
|
89
185
|
});
|
|
90
186
|
return {
|
|
91
187
|
module: ExGuardModule,
|
|
@@ -120,7 +216,8 @@ var ExGuardPermissionGuard = class {
|
|
|
120
216
|
throw new UnauthorizedException("No token provided");
|
|
121
217
|
}
|
|
122
218
|
if (!this.client) {
|
|
123
|
-
|
|
219
|
+
console.warn("[ExGuard] Client not configured. Access denied.");
|
|
220
|
+
return false;
|
|
124
221
|
}
|
|
125
222
|
const authResult = await this.client.authenticate({ token, request });
|
|
126
223
|
if (!authResult.allowed) {
|
|
@@ -201,6 +298,7 @@ export {
|
|
|
201
298
|
RequirePermissions,
|
|
202
299
|
RequireRoles,
|
|
203
300
|
cache,
|
|
204
|
-
createExGuardClient
|
|
301
|
+
createExGuardClient,
|
|
302
|
+
realtime
|
|
205
303
|
};
|
|
206
304
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts","../src/module.ts","../src/guard.ts"],"sourcesContent":["export interface ExGuardConfig {\n baseUrl: string;\n apiKey: string;\n cache?: {\n enabled?: boolean;\n ttl?: number;\n };\n}\n\nexport interface User {\n id: string;\n username: string;\n email: string;\n}\n\nexport interface ModulePermission {\n key: string;\n name: string;\n permissions: string[];\n}\n\nexport interface UserAccessResponse {\n user: User;\n roles: string[];\n modules: ModulePermission[];\n}\n\nexport interface GuardContext {\n token: string;\n request?: any;\n}\n\nexport interface GuardResult {\n allowed: boolean;\n user?: UserAccessResponse;\n error?: string;\n}\n\nclass ExGuardCache {\n private cache = new Map<string, { data: any; timestamp: number; ttl: number }>();\n private ttl = 300000;\n\n get(key: string): any {\n const entry = this.cache.get(key);\n if (!entry) return null;\n if (Date.now() - entry.timestamp > entry.ttl) {\n this.cache.delete(key);\n return null;\n }\n return entry.data;\n }\n\n set(key: string, data: any, ttl?: number): void {\n this.cache.set(key, {\n data,\n timestamp: Date.now(),\n ttl: ttl || this.ttl,\n });\n }\n}\n\nconst cache = new ExGuardCache();\n\nexport class ExGuardClient {\n private baseUrl: string;\n private apiKey: string;\n private cache: ExGuardCache;\n\n constructor(config: ExGuardConfig) {\n this.baseUrl = config.baseUrl;\n this.apiKey = config.apiKey;\n this.cache = cache;\n }\n\n async authenticate(context: GuardContext): Promise<GuardResult> {\n const cacheKey = `auth:${context.token}`;\n const cached = this.cache.get(cacheKey);\n if (cached) return cached;\n\n try {\n const response = await fetch(`${this.baseUrl}/api/v1/auth/validate`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({ token: context.token }),\n });\n\n if (!response.ok) {\n return { allowed: false, error: 'Invalid token' };\n }\n\n const data = await response.json();\n const result: GuardResult = {\n allowed: true,\n user: data.user || data.data?.user,\n };\n\n this.cache.set(cacheKey, result);\n return result;\n } catch (error) {\n return { allowed: false, error: 'Authentication failed' };\n }\n }\n\n async hasPermission(token: string, permission: string): Promise<boolean> {\n const result = await this.authenticate({ token });\n if (!result.allowed || !result.user) return false;\n\n const userPermissions = result.user.modules?.flatMap(m => m.permissions) || [];\n return userPermissions.includes(permission);\n }\n}\n\nexport function createExGuardClient(config: ExGuardConfig): ExGuardClient {\n return new ExGuardClient(config);\n}\n\nexport { cache };\n","import { Module, Global, DynamicModule } from '@nestjs/common';\nimport { ExGuardClient } from './client.js';\n\nexport interface ExGuardModuleOptions {\n baseUrl: string;\n apiKey: string;\n cache?: {\n enabled?: boolean;\n ttl?: number;\n };\n}\n\n@Global()\n@Module({})\nexport class ExGuardModule {\n static forRoot(options: ExGuardModuleOptions): DynamicModule {\n const client = new ExGuardClient({\n baseUrl: options.baseUrl,\n apiKey: options.apiKey,\n cache: options.cache,\n });\n\n return {\n module: ExGuardModule,\n providers: [\n {\n provide: 'EXGUARD_CLIENT',\n useValue: client,\n },\n ],\n exports: ['EXGUARD_CLIENT'],\n };\n }\n}\n","import { Injectable, CanActivate, ExecutionContext, UnauthorizedException, ForbiddenException, Inject, Optional } from '@nestjs/common';\nimport { Reflector } from '@nestjs/core';\nimport { ExGuardClient } from './client.js';\n\nexport const EXGUARD_PERMISSIONS_KEY = 'exguard_permissions';\nexport const EXGUARD_ROLES_KEY = 'exguard_roles';\n\n@Injectable()\nexport class ExGuardPermissionGuard implements CanActivate {\n constructor(\n @Optional() @Inject('EXGUARD_CLIENT') private client: ExGuardClient,\n private reflector: Reflector,\n ) {}\n\n async canActivate(context: ExecutionContext): Promise<boolean> {\n const request = context.switchToHttp().getRequest();\n const token = this.extractToken(request);\n\n if (!token) {\n throw new UnauthorizedException('No token provided');\n }\n\n if (!this.client) {\n return true;\n }\n\n const authResult = await this.client.authenticate({ token, request });\n\n if (!authResult.allowed) {\n throw new ForbiddenException(authResult.error || 'Access denied');\n }\n\n if (!authResult.user) {\n throw new ForbiddenException('User not found');\n }\n\n const handler = context.getHandler();\n const permMeta = this.reflector.get<{ permissions: string[]; requireAll?: boolean }>(\n EXGUARD_PERMISSIONS_KEY,\n handler,\n );\n\n if (permMeta) {\n const { permissions, requireAll } = permMeta;\n const userPermissions = authResult.user.modules?.flatMap(m => m.permissions) || [];\n\n if (requireAll) {\n if (!permissions.every(p => userPermissions.includes(p))) {\n throw new ForbiddenException('Insufficient permissions');\n }\n } else {\n if (!permissions.some(p => userPermissions.includes(p))) {\n throw new ForbiddenException('Insufficient permissions');\n }\n }\n }\n\n const roleMeta = this.reflector.get<{ roles: string[]; requireAll?: boolean }>(\n EXGUARD_ROLES_KEY,\n handler,\n );\n\n if (roleMeta) {\n const { roles, requireAll } = roleMeta;\n const userRoles = authResult.user.roles || [];\n\n if (requireAll) {\n if (!roles.every(r => userRoles.includes(r))) {\n throw new ForbiddenException('Insufficient roles');\n }\n } else {\n if (!roles.some(r => userRoles.includes(r))) {\n throw new ForbiddenException('Insufficient roles');\n }\n }\n }\n\n request.user = authResult.user;\n return true;\n }\n\n private extractToken(request: any): string | null {\n const auth = request.headers?.authorization;\n if (auth?.startsWith('Bearer ')) {\n return auth.substring(7);\n }\n return request.headers?.['x-access-token'] || null;\n }\n}\n\nexport function RequirePermissions(permissions: string[], requireAll = false) {\n return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {\n Reflect.defineMetadata(EXGUARD_PERMISSIONS_KEY, { permissions, requireAll }, descriptor.value);\n return descriptor;\n };\n}\n\nexport function RequireRoles(roles: string[], requireAll = false) {\n return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {\n Reflect.defineMetadata(EXGUARD_ROLES_KEY, { roles, requireAll }, descriptor.value);\n return descriptor;\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/client.ts","../src/module.ts","../src/guard.ts"],"sourcesContent":["export interface ExGuardConfig {\n baseUrl: string;\n apiKey: string;\n cache?: {\n enabled?: boolean;\n ttl?: number;\n };\n realtime?: {\n enabled?: boolean;\n url?: string;\n };\n}\n\nexport interface User {\n id: string;\n username: string;\n email: string;\n}\n\nexport interface ModulePermission {\n key: string;\n name: string;\n permissions: string[];\n}\n\nexport interface UserAccessResponse {\n user: User;\n roles: string[];\n modules: ModulePermission[];\n}\n\nexport interface GuardContext {\n token: string;\n request?: any;\n}\n\nexport interface GuardResult {\n allowed: boolean;\n user?: UserAccessResponse;\n error?: string;\n}\n\nexport interface RealtimeEvents {\n onConnect?: () => void;\n onDisconnect?: () => void;\n onPermissionUpdate?: (data: { userId: string; permissions: string[] }) => void;\n onUserUpdate?: (data: { userId: string; user: UserAccessResponse }) => void;\n}\n\nclass ExGuardCache {\n private cache = new Map<string, { data: any; timestamp: number; ttl: number }>();\n private ttl = 300000;\n\n get(key: string): any {\n const entry = this.cache.get(key);\n if (!entry) return null;\n if (Date.now() - entry.timestamp > entry.ttl) {\n this.cache.delete(key);\n return null;\n }\n return entry.data;\n }\n\n set(key: string, data: any, ttl?: number): void {\n this.cache.set(key, {\n data,\n timestamp: Date.now(),\n ttl: ttl || this.ttl,\n });\n }\n\n delete(key: string): void {\n this.cache.delete(key);\n }\n\n clear(): void {\n this.cache.clear();\n }\n\n clearUser(userId: string): void {\n for (const key of this.cache.keys()) {\n if (key.includes(userId)) {\n this.cache.delete(key);\n }\n }\n }\n}\n\nconst cache = new ExGuardCache();\n\nclass ExGuardRealtime {\n private socket: any = null;\n private connected = false;\n private url: string = '';\n private events: RealtimeEvents = {};\n\n connect(url: string, events: RealtimeEvents = {}): void {\n this.url = url;\n this.events = events;\n \n if (!url) {\n console.log('[ExGuard] Realtime URL not provided, skipping connection');\n return;\n }\n\n try {\n const { io } = require('socket.io-client');\n this.socket = io(url, {\n transports: ['websocket'],\n reconnection: true,\n reconnectionAttempts: 5,\n reconnectionDelay: 1000,\n });\n\n this.socket.on('connect', () => {\n this.connected = true;\n console.log('[ExGuard] Realtime connected');\n this.events.onConnect?.();\n });\n\n this.socket.on('disconnect', () => {\n this.connected = false;\n console.log('[ExGuard] Realtime disconnected');\n this.events.onDisconnect?.();\n });\n\n this.socket.on('permission:update', (data: any) => {\n console.log('[ExGuard] Permission update received:', data);\n cache.clearUser(data.userId);\n this.events.onPermissionUpdate?.(data);\n });\n\n this.socket.on('user:update', (data: any) => {\n console.log('[ExGuard] User update received:', data);\n cache.clearUser(data.userId);\n this.events.onUserUpdate?.(data);\n });\n\n this.socket.on('connect_error', (err: any) => {\n console.error('[ExGuard] Realtime connection error:', err.message);\n });\n } catch (error) {\n console.error('[ExGuard] Failed to load socket.io-client:', error);\n }\n }\n\n disconnect(): void {\n if (this.socket) {\n this.socket.disconnect();\n this.socket = null;\n this.connected = false;\n }\n }\n\n isConnected(): boolean {\n return this.connected;\n }\n\n emit(event: string, data: any): void {\n if (this.socket && this.connected) {\n this.socket.emit(event, data);\n }\n }\n}\n\nconst realtime = new ExGuardRealtime();\n\nexport class ExGuardClient {\n private baseUrl: string;\n private apiKey: string;\n private cache: ExGuardCache;\n private realtime: ExGuardRealtime;\n\n constructor(config: ExGuardConfig) {\n this.baseUrl = config.baseUrl;\n this.apiKey = config.apiKey;\n this.cache = cache;\n this.realtime = realtime;\n\n if (config.realtime?.enabled && config.realtime?.url) {\n this.realtime.connect(config.realtime.url);\n }\n }\n\n async authenticate(context: GuardContext): Promise<GuardResult> {\n const cacheKey = `auth:${context.token}`;\n const cached = this.cache.get(cacheKey);\n if (cached) return cached;\n\n try {\n const response = await fetch(`${this.baseUrl}/api/v1/auth/validate`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({ token: context.token }),\n });\n\n if (!response.ok) {\n return { allowed: false, error: 'Invalid token' };\n }\n\n const data = await response.json();\n const result: GuardResult = {\n allowed: true,\n user: data.user || data.data?.user,\n };\n\n this.cache.set(cacheKey, result);\n return result;\n } catch (error) {\n return { allowed: false, error: 'Authentication failed' };\n }\n }\n\n async hasPermission(token: string, permission: string): Promise<boolean> {\n const result = await this.authenticate({ token });\n if (!result.allowed || !result.user) return false;\n\n const userPermissions = result.user.modules?.flatMap(m => m.permissions) || [];\n return userPermissions.includes(permission);\n }\n\n clearCache(): void {\n this.cache.clear();\n }\n\n disconnectRealtime(): void {\n this.realtime.disconnect();\n }\n}\n\nexport function createExGuardClient(config: ExGuardConfig): ExGuardClient {\n return new ExGuardClient(config);\n}\n\nexport { cache, realtime };\n","import { Module, Global, DynamicModule } from '@nestjs/common';\nimport { ExGuardClient } from './client.js';\n\nexport interface ExGuardModuleOptions {\n baseUrl: string;\n apiKey: string;\n cache?: {\n enabled?: boolean;\n ttl?: number;\n };\n realtime?: {\n enabled?: boolean;\n url?: string;\n };\n}\n\n@Global()\n@Module({})\nexport class ExGuardModule {\n static forRoot(options: ExGuardModuleOptions): DynamicModule {\n const client = new ExGuardClient({\n baseUrl: options.baseUrl,\n apiKey: options.apiKey,\n cache: options.cache,\n realtime: options.realtime,\n });\n\n return {\n module: ExGuardModule,\n providers: [\n {\n provide: 'EXGUARD_CLIENT',\n useValue: client,\n },\n ],\n exports: ['EXGUARD_CLIENT'],\n };\n }\n}\n","import { Injectable, CanActivate, ExecutionContext, UnauthorizedException, ForbiddenException, Inject, Optional } from '@nestjs/common';\nimport { Reflector } from '@nestjs/core';\nimport { ExGuardClient } from './client.js';\n\nexport const EXGUARD_PERMISSIONS_KEY = 'exguard_permissions';\nexport const EXGUARD_ROLES_KEY = 'exguard_roles';\n\n@Injectable()\nexport class ExGuardPermissionGuard implements CanActivate {\n constructor(\n @Optional() @Inject('EXGUARD_CLIENT') private client: ExGuardClient,\n private reflector: Reflector,\n ) {}\n\n async canActivate(context: ExecutionContext): Promise<boolean> {\n const request = context.switchToHttp().getRequest();\n const token = this.extractToken(request);\n\n if (!token) {\n throw new UnauthorizedException('No token provided');\n }\n\n if (!this.client) {\n console.warn('[ExGuard] Client not configured. Access denied.');\n return false;\n }\n\n const authResult = await this.client.authenticate({ token, request });\n\n if (!authResult.allowed) {\n throw new ForbiddenException(authResult.error || 'Access denied');\n }\n\n if (!authResult.user) {\n throw new ForbiddenException('User not found');\n }\n\n const handler = context.getHandler();\n const permMeta = this.reflector.get<{ permissions: string[]; requireAll?: boolean }>(\n EXGUARD_PERMISSIONS_KEY,\n handler,\n );\n\n if (permMeta) {\n const { permissions, requireAll } = permMeta;\n const userPermissions = authResult.user.modules?.flatMap(m => m.permissions) || [];\n\n if (requireAll) {\n if (!permissions.every(p => userPermissions.includes(p))) {\n throw new ForbiddenException('Insufficient permissions');\n }\n } else {\n if (!permissions.some(p => userPermissions.includes(p))) {\n throw new ForbiddenException('Insufficient permissions');\n }\n }\n }\n\n const roleMeta = this.reflector.get<{ roles: string[]; requireAll?: boolean }>(\n EXGUARD_ROLES_KEY,\n handler,\n );\n\n if (roleMeta) {\n const { roles, requireAll } = roleMeta;\n const userRoles = authResult.user.roles || [];\n\n if (requireAll) {\n if (!roles.every(r => userRoles.includes(r))) {\n throw new ForbiddenException('Insufficient roles');\n }\n } else {\n if (!roles.some(r => userRoles.includes(r))) {\n throw new ForbiddenException('Insufficient roles');\n }\n }\n }\n\n request.user = authResult.user;\n return true;\n }\n\n private extractToken(request: any): string | null {\n const auth = request.headers?.authorization;\n if (auth?.startsWith('Bearer ')) {\n return auth.substring(7);\n }\n return request.headers?.['x-access-token'] || null;\n }\n}\n\nexport function RequirePermissions(permissions: string[], requireAll = false) {\n return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {\n Reflect.defineMetadata(EXGUARD_PERMISSIONS_KEY, { permissions, requireAll }, descriptor.value);\n return descriptor;\n };\n}\n\nexport function RequireRoles(roles: string[], requireAll = false) {\n return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {\n Reflect.defineMetadata(EXGUARD_ROLES_KEY, { roles, requireAll }, descriptor.value);\n return descriptor;\n };\n}\n"],"mappings":"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","names":[]}
|
package/dist/setup.cjs
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
const GUARD_CONTENT = `import { Injectable, CanActivate, ExecutionContext, UnauthorizedException, ForbiddenException, Inject, Optional } from '@nestjs/common';
|
|
5
|
+
import { Reflector } from '@nestjs/core';
|
|
6
|
+
import { ExGuardClient } from 'exguard-endpoint';
|
|
7
|
+
|
|
8
|
+
export const EXGUARD_PERMISSIONS_KEY = 'exguard_permissions';
|
|
9
|
+
export const EXGUARD_ROLES_KEY = 'exguard_roles';
|
|
10
|
+
|
|
11
|
+
@Injectable()
|
|
12
|
+
export class ExGuardPermissionGuard implements CanActivate {
|
|
13
|
+
constructor(
|
|
14
|
+
@Optional() @Inject('EXGUARD_CLIENT') private client: ExGuardClient,
|
|
15
|
+
private reflector: Reflector,
|
|
16
|
+
) {}
|
|
17
|
+
|
|
18
|
+
async canActivate(context: ExecutionContext): Promise<boolean> {
|
|
19
|
+
const request = context.switchToHttp().getRequest();
|
|
20
|
+
const token = this.extractToken(request);
|
|
21
|
+
|
|
22
|
+
if (!token) {
|
|
23
|
+
throw new UnauthorizedException('No token provided');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!this.client) {
|
|
27
|
+
console.warn('[ExGuard] Client not configured. Access denied.');
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const authResult = await this.client.authenticate({ token, request });
|
|
32
|
+
|
|
33
|
+
if (!authResult.allowed) {
|
|
34
|
+
throw new ForbiddenException(authResult.error || 'Access denied');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (!authResult.user) {
|
|
38
|
+
throw new ForbiddenException('User not found');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const handler = context.getHandler();
|
|
42
|
+
const permMeta = this.reflector.get(EXGUARD_PERMISSIONS_KEY, handler);
|
|
43
|
+
|
|
44
|
+
if (permMeta) {
|
|
45
|
+
const { permissions, requireAll } = permMeta;
|
|
46
|
+
const userPermissions = authResult.user.modules ? authResult.user.modules.flatMap(m => m.permissions) : [];
|
|
47
|
+
|
|
48
|
+
if (requireAll) {
|
|
49
|
+
if (!permissions.every(p => userPermissions.includes(p))) {
|
|
50
|
+
throw new ForbiddenException('Insufficient permissions');
|
|
51
|
+
}
|
|
52
|
+
} else {
|
|
53
|
+
if (!permissions.some(p => userPermissions.includes(p))) {
|
|
54
|
+
throw new ForbiddenException('Insufficient permissions');
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const roleMeta = this.reflector.get(EXGUARD_ROLES_KEY, handler);
|
|
60
|
+
|
|
61
|
+
if (roleMeta) {
|
|
62
|
+
const { roles, requireAll } = roleMeta;
|
|
63
|
+
const userRoles = authResult.user.roles || [];
|
|
64
|
+
|
|
65
|
+
if (requireAll) {
|
|
66
|
+
if (!roles.every(r => userRoles.includes(r))) {
|
|
67
|
+
throw new ForbiddenException('Insufficient roles');
|
|
68
|
+
}
|
|
69
|
+
} else {
|
|
70
|
+
if (!roles.some(r => userRoles.includes(r))) {
|
|
71
|
+
throw new ForbiddenException('Insufficient roles');
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
request.user = authResult.user;
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private extractToken(request) {
|
|
81
|
+
const auth = request.headers ? request.headers.authorization : null;
|
|
82
|
+
if (auth && auth.startsWith('Bearer ')) {
|
|
83
|
+
return auth.substring(7);
|
|
84
|
+
}
|
|
85
|
+
return request.headers ? request.headers['x-access-token'] : null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function RequirePermissions(permissions, requireAll = false) {
|
|
90
|
+
return function (target, propertyKey, descriptor) {
|
|
91
|
+
Reflect.defineMetadata(EXGUARD_PERMISSIONS_KEY, { permissions, requireAll }, descriptor.value);
|
|
92
|
+
return descriptor;
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function RequireRoles(roles, requireAll = false) {
|
|
97
|
+
return function (target, propertyKey, descriptor) {
|
|
98
|
+
Reflect.defineMetadata(EXGUARD_ROLES_KEY, { roles, requireAll }, descriptor.value);
|
|
99
|
+
return descriptor;
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
`;
|
|
103
|
+
|
|
104
|
+
const MODULE_CONTENT = `import { Module, Global, DynamicModule } from '@nestjs/common';
|
|
105
|
+
import { ExGuardModule } from 'exguard-endpoint';
|
|
106
|
+
|
|
107
|
+
@Global()
|
|
108
|
+
@Module({})
|
|
109
|
+
export class ExGuardModuleSetup {
|
|
110
|
+
static forRoot(options) {
|
|
111
|
+
return ExGuardModule.forRoot(options);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
`;
|
|
115
|
+
|
|
116
|
+
function ensureDir(dirPath) {
|
|
117
|
+
if (!fs.existsSync(dirPath)) {
|
|
118
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function writeFile(filePath, content) {
|
|
123
|
+
const dir = path.dirname(filePath);
|
|
124
|
+
ensureDir(dir);
|
|
125
|
+
fs.writeFileSync(filePath, content);
|
|
126
|
+
console.log('Created: ' + filePath);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function setup() {
|
|
130
|
+
const srcDir = path.join(process.cwd(), 'src');
|
|
131
|
+
const exguardDir = path.join(srcDir, 'exguard');
|
|
132
|
+
|
|
133
|
+
if (!fs.existsSync(srcDir)) {
|
|
134
|
+
console.error('Error: Run this command in your NestJS project root');
|
|
135
|
+
process.exit(1);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
ensureDir(exguardDir);
|
|
139
|
+
|
|
140
|
+
writeFile(path.join(exguardDir, 'exguard.guard.ts'), GUARD_CONTENT);
|
|
141
|
+
writeFile(path.join(exguardDir, 'exguard.module.ts'), MODULE_CONTENT);
|
|
142
|
+
|
|
143
|
+
console.log('');
|
|
144
|
+
console.log('===========================================');
|
|
145
|
+
console.log('✅ ExGuard Setup Complete!');
|
|
146
|
+
console.log('===========================================');
|
|
147
|
+
console.log('');
|
|
148
|
+
console.log('Next steps:');
|
|
149
|
+
console.log('');
|
|
150
|
+
console.log('1. Add to app.module.ts:');
|
|
151
|
+
console.log('');
|
|
152
|
+
console.log(' import { ExGuardModule } from "./exguard/exguard.module";');
|
|
153
|
+
console.log('');
|
|
154
|
+
console.log(' @Module({');
|
|
155
|
+
console.log(' imports: [');
|
|
156
|
+
console.log(' ExGuardModule.forRoot({');
|
|
157
|
+
console.log(' baseUrl: process.env.EXGUARD_BASE_URL,');
|
|
158
|
+
console.log(' apiKey: process.env.EXGUARD_API_KEY,');
|
|
159
|
+
console.log(' realtime: {');
|
|
160
|
+
console.log(' enabled: true,');
|
|
161
|
+
console.log(' url: process.env.EXGUARD_REALTIME_URL,');
|
|
162
|
+
console.log(' },');
|
|
163
|
+
console.log(' }),');
|
|
164
|
+
console.log(' ],');
|
|
165
|
+
console.log(' })');
|
|
166
|
+
console.log(' export class AppModule {}');
|
|
167
|
+
console.log('');
|
|
168
|
+
console.log('2. Add environment variables:');
|
|
169
|
+
console.log('');
|
|
170
|
+
console.log(' EXGUARD_BASE_URL=https://api.exguard.com');
|
|
171
|
+
console.log(' EXGUARD_API_KEY=your_api_key');
|
|
172
|
+
console.log(' EXGUARD_REALTIME_URL=wss://realtime.exguard.com');
|
|
173
|
+
console.log('');
|
|
174
|
+
console.log('3. Use in controllers:');
|
|
175
|
+
console.log('');
|
|
176
|
+
console.log(' import { ExGuardPermissionGuard, RequirePermissions } from "./exguard/exguard.guard";');
|
|
177
|
+
console.log('');
|
|
178
|
+
console.log(' @Controller("items")');
|
|
179
|
+
console.log(' @UseGuards(ExGuardPermissionGuard)');
|
|
180
|
+
console.log(' export class ItemsController {');
|
|
181
|
+
console.log(' @Get() @RequirePermissions(["item:read"]) findAll() {}');
|
|
182
|
+
console.log(' @Post() @RequirePermissions(["item:create"]) create() {}');
|
|
183
|
+
console.log(' }');
|
|
184
|
+
console.log('');
|
|
185
|
+
console.log('===========================================');
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const args = process.argv.slice(2);
|
|
189
|
+
|
|
190
|
+
if (args[0] === 'setup') {
|
|
191
|
+
setup();
|
|
192
|
+
} else {
|
|
193
|
+
console.log('===========================================');
|
|
194
|
+
console.log('ExGuard Endpoint - NestJS RBAC Guard');
|
|
195
|
+
console.log('===========================================');
|
|
196
|
+
console.log('');
|
|
197
|
+
console.log('To setup in your NestJS project:');
|
|
198
|
+
console.log(' npx exguard-endpoint setup');
|
|
199
|
+
console.log('');
|
|
200
|
+
console.log('Or add manually:');
|
|
201
|
+
console.log(' 1. Import ExGuardModule in app.module.ts');
|
|
202
|
+
console.log(' 2. Use ExGuardPermissionGuard in controllers');
|
|
203
|
+
console.log('');
|
|
204
|
+
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "exguard-endpoint",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
8
8
|
"type": "module",
|
|
9
|
-
"description": "Simple RBAC permission guard for NestJS",
|
|
9
|
+
"description": "Simple RBAC permission guard for NestJS with realtime support",
|
|
10
10
|
"main": "./dist/index.cjs",
|
|
11
11
|
"module": "./dist/index.js",
|
|
12
12
|
"types": "./dist/index.d.ts",
|
|
@@ -17,25 +17,31 @@
|
|
|
17
17
|
"require": "./dist/index.cjs"
|
|
18
18
|
}
|
|
19
19
|
},
|
|
20
|
+
"bin": {
|
|
21
|
+
"exguard-endpoint": "./dist/setup.cjs"
|
|
22
|
+
},
|
|
20
23
|
"files": [
|
|
21
24
|
"dist"
|
|
22
25
|
],
|
|
23
26
|
"scripts": {
|
|
24
27
|
"build": "tsup",
|
|
25
28
|
"clean": "node -e \"fs.rmSync('dist', { recursive: true, force: true })\"",
|
|
26
|
-
"prebuild": "npm run clean"
|
|
29
|
+
"prebuild": "npm run clean",
|
|
30
|
+
"setup": "node dist/setup.cjs"
|
|
27
31
|
},
|
|
28
32
|
"keywords": [
|
|
29
33
|
"exguard",
|
|
30
34
|
"rbac",
|
|
31
35
|
"nestjs",
|
|
32
36
|
"permissions",
|
|
33
|
-
"guards"
|
|
37
|
+
"guards",
|
|
38
|
+
"realtime"
|
|
34
39
|
],
|
|
35
40
|
"author": "EmpowerX",
|
|
36
41
|
"license": "MIT",
|
|
37
42
|
"dependencies": {
|
|
38
|
-
"axios": "^1.0.0"
|
|
43
|
+
"axios": "^1.0.0",
|
|
44
|
+
"socket.io-client": "^4.8.3"
|
|
39
45
|
},
|
|
40
46
|
"devDependencies": {
|
|
41
47
|
"@nestjs/common": "^10.0.0",
|