Skip to content

Commit 650edf0

Browse files
author
yaser2us
committed
introducing context done ;)
1 parent 0ace3ce commit 650edf0

File tree

31 files changed

+1599
-77
lines changed

31 files changed

+1599
-77
lines changed
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// ============================================
2+
// STEP 2: ALTERNATIVE APPROACH WITH REQUEST INJECTION
3+
// ============================================
4+
5+
// enhanced-user-context.pipe.ts (better approach)
6+
7+
import {
8+
Injectable,
9+
PipeTransform,
10+
ArgumentMetadata,
11+
Inject,
12+
Scope
13+
} from '@nestjs/common';
14+
import { REQUEST } from '@nestjs/core';
15+
16+
@Injectable({ scope: Scope.REQUEST })
17+
export class EnhancedUserContextPipe implements PipeTransform {
18+
19+
constructor(
20+
@Inject(REQUEST) private readonly request: any
21+
) { }
22+
23+
transform(query: any, metadata: ArgumentMetadata): any {
24+
console.log('🚰 EnhancedUserContextPipe activated');
25+
console.log('📥 Original query:', query);
26+
27+
try {
28+
console.log('👤 Request user:', this.request.user);
29+
console.log('🔗 Request headers:', this.request.headers);
30+
31+
// Create enhanced query with user context
32+
const enhancedQuery = {
33+
...query,
34+
context: {
35+
// User context from JWT
36+
userContext: this.request.user ? {
37+
id: this.request.user.id,
38+
workspaceId: this.request.user.workspaceId,
39+
roles: this.request.user.roles || [],
40+
email: this.request.user.email,
41+
permissions: this.request.user.permissions || []
42+
} : {
43+
id: 'user-456',
44+
roles: ['manager'],
45+
accessibleIds: ['1', '2', '3', '4', '5', '15', '17', '18', '19', '13', '11', '25', '27'], // Specific records user can access
46+
departmentId: 42
47+
},
48+
49+
// Request metadata
50+
requestId: this.request.headers['x-request-id'] || `req-${Date.now()}`,
51+
timestamp: new Date().toISOString(),
52+
userAgent: this.request.headers['user-agent'],
53+
54+
// Network info
55+
ipAddress: this.request.ip || this.request.connection?.remoteAddress,
56+
origin: this.request.headers['origin'],
57+
58+
// Tenant/workspace context
59+
tenantId: this.request.headers['x-tenant-id'] || this.request.user?.workspaceId,
60+
61+
// API metadata
62+
apiVersion: this.request.headers['api-version'] || '1.0',
63+
endpoint: this.request.route?.path || this.request.url,
64+
method: this.request.method,
65+
66+
// Security context
67+
sessionId: this.request.sessionID,
68+
csrfToken: this.request.headers['x-csrf-token'],
69+
70+
// Feature flags (you could add async loading here)
71+
featureFlags: {
72+
// Default flags - you could make this dynamic
73+
enableAdvancedSearch: this.request.user?.roles?.includes('admin') || false,
74+
enableBetaFeatures: this.request.user?.roles?.includes('beta-tester') || false,
75+
enableAuditLogging: true
76+
}
77+
}
78+
};
79+
80+
console.log('✅ Successfully enhanced query with context');
81+
console.log('🔧 Context keys:', Object.keys(enhancedQuery.context));
82+
83+
return enhancedQuery;
84+
85+
} catch (error) {
86+
console.error('❌ Error in EnhancedUserContextPipe:', error);
87+
// Return original query on error
88+
return query;
89+
}
90+
}
91+
}
Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
// real-db-integration-controller.ts
2+
// Test access control with actual database queries
3+
4+
import { Controller, Get, Query, Inject } from '@nestjs/common';
5+
import { Repository } from 'typeorm';
6+
import { InjectRepository } from '@nestjs/typeorm';
7+
import { simpleAccessControlledGetAll } from '@klerick/json-api-nestjs-typeorm';
8+
9+
// Import your entities
10+
import {
11+
Users,
12+
Addresses,
13+
Comments,
14+
Roles,
15+
BookList,
16+
School,
17+
User,
18+
Workspace,
19+
YasserNasser
20+
} from '@nestjs-json-api/typeorm-database';
21+
22+
@Controller('api/real-test')
23+
export class RealDbIntegrationController {
24+
25+
constructor(
26+
@InjectRepository(School) private usersRepository: Repository<School>
27+
) { }
28+
29+
@Get('users-original')
30+
async getOriginalUsers(@Query() query: any) {
31+
console.log('📊 Testing ORIGINAL database query (no access control)...');
32+
33+
const pageSize = parseInt(query.size) || 10;
34+
const pageNumber = parseInt(query.page) || 1;
35+
const skip = (pageNumber - 1) * pageSize;
36+
37+
// Simple original query
38+
const [data, totalItems] = await this.usersRepository.findAndCount({
39+
take: pageSize,
40+
skip: skip
41+
});
42+
43+
console.log(`📊 Original query: ${data.length} items returned, ${totalItems} total`);
44+
console.log('📊 First user:', data[0]);
45+
46+
return {
47+
meta: {
48+
pageNumber,
49+
totalItems,
50+
pageSize,
51+
},
52+
data,
53+
message: 'Original query - no access control'
54+
};
55+
}
56+
57+
@Get('users-access-controlled')
58+
async getAccessControlledUsers(@Query() query: any) {
59+
console.log('🔐 Testing ACCESS CONTROLLED database query...');
60+
61+
// Mock TypeORM service structure
62+
const mockTypeOrmService = {
63+
repository: this.usersRepository,
64+
typeormUtilsService: {
65+
currentAlias: 'school',
66+
currentPrimaryColumn: 'id'
67+
},
68+
transformDataService: {
69+
transformData: (data: any, query: any) => ({
70+
data,
71+
included: null
72+
})
73+
}
74+
};
75+
76+
// Mock user context
77+
const userContext = {
78+
id: 'test-user-123',
79+
workspaceId: 'test-workspace-123',
80+
roles: ['admin'] // Try changing to ['user'] to see different results
81+
};
82+
83+
// Mock query structure
84+
const mockQuery = {
85+
page: {
86+
size: parseInt(query.size) || 10,
87+
number: parseInt(query.page) || 1
88+
}
89+
};
90+
91+
try {
92+
// Call our access-controlled function
93+
const result = await simpleAccessControlledGetAll(
94+
mockTypeOrmService,
95+
mockQuery,
96+
userContext
97+
);
98+
99+
console.log('🔐 Access controlled result:', result);
100+
101+
return {
102+
...result,
103+
message: 'Access controlled query - only accessible users returned'
104+
};
105+
106+
} catch (error) {
107+
console.error('❌ Error in access controlled query:', error);
108+
return {
109+
error: 'Access controlled query failed',
110+
details: error.message,
111+
data: []
112+
};
113+
}
114+
}
115+
116+
@Get('compare')
117+
async compareResults(@Query() query: any) {
118+
console.log('🔍 COMPARING original vs access-controlled results...');
119+
120+
try {
121+
// Get both results
122+
const original = await this.getOriginalUsers(query);
123+
const accessControlled = await this.getAccessControlledUsers(query);
124+
125+
console.log('📊 COMPARISON RESULTS:');
126+
console.log(`Original: ${original.data?.length || 0} users`);
127+
console.log(`Access Controlled: ${accessControlled.data?.length || 0} users`);
128+
129+
return {
130+
original: {
131+
count: original.data?.length || 0,
132+
totalItems: original.meta?.totalItems || 0,
133+
data: original.data
134+
},
135+
accessControlled: {
136+
count: accessControlled.data?.length || 0,
137+
totalItems: accessControlled.meta?.totalItems || 0,
138+
data: accessControlled.data
139+
},
140+
comparison: {
141+
filtered: (original.data?.length || 0) - (accessControlled.data?.length || 0),
142+
message: 'Access control successfully filtered results'
143+
}
144+
};
145+
146+
} catch (error) {
147+
console.error('❌ Comparison failed:', error);
148+
return {
149+
error: 'Comparison failed',
150+
details: error.message
151+
};
152+
}
153+
}
154+
155+
@Get('test-different-users')
156+
async testDifferentUsers() {
157+
console.log('👥 Testing DIFFERENT USER ROLES...');
158+
159+
const mockTypeOrmService = {
160+
repository: this.usersRepository,
161+
typeormUtilsService: {
162+
currentAlias: 'users',
163+
currentPrimaryColumn: 'id'
164+
},
165+
transformDataService: {
166+
transformData: (data: any, query: any) => ({ data, included: null })
167+
}
168+
};
169+
170+
const mockQuery = { page: { size: 10, number: 1 } };
171+
172+
// Test admin user
173+
const adminContext = {
174+
id: 'admin-user',
175+
workspaceId: 'test-workspace-123',
176+
roles: ['admin']
177+
};
178+
179+
// Test regular user
180+
const userContext = {
181+
id: 'regular-user',
182+
workspaceId: 'test-workspace-123',
183+
roles: ['user']
184+
};
185+
186+
try {
187+
const adminResult = await simpleAccessControlledGetAll(mockTypeOrmService, mockQuery, adminContext);
188+
const userResult = await simpleAccessControlledGetAll(mockTypeOrmService, mockQuery, userContext);
189+
190+
console.log(`👨‍💼 Admin sees: ${adminResult.data?.length || 0} users`);
191+
console.log(`👤 Regular user sees: ${userResult.data?.length || 0} users`);
192+
193+
return {
194+
admin: {
195+
accessibleIds: ['1', '2', '3', '4', '5'], // From our mock function
196+
actualResults: adminResult.data?.length || 0,
197+
data: adminResult.data
198+
},
199+
user: {
200+
accessibleIds: ['1', '2'], // From our mock function
201+
actualResults: userResult.data?.length || 0,
202+
data: userResult.data
203+
},
204+
message: 'Different users see different results based on access control'
205+
};
206+
207+
} catch (error) {
208+
console.error('❌ Multi-user test failed:', error);
209+
return {
210+
error: 'Multi-user test failed',
211+
details: error.message
212+
};
213+
}
214+
}
215+
}
216+
217+
// ===================================
218+
// ADD TO YOUR MODULE
219+
// ===================================
220+
221+
/*
222+
Add this to your resources-type.module.ts:
223+
224+
import { RealDbIntegrationController } from './real-db-integration-controller';
225+
226+
@Module({
227+
imports: [
228+
TypeOrmModule.forFeature([Users]), // Make sure Users entity is available
229+
TypeOrmJsonApiModule.forRoot({
230+
entities: [Users, Documents],
231+
})
232+
],
233+
controllers: [TestController, RealDbIntegrationController], // Add the new controller
234+
})
235+
export class ResourcesTypeModule {}
236+
*/
237+
238+
// ===================================
239+
// TESTING ENDPOINTS
240+
// ===================================
241+
242+
/*
243+
NOW TEST THESE ENDPOINTS:
244+
245+
1. GET /api/real-test/users-original
246+
→ Should return ALL users from database (no filtering)
247+
248+
2. GET /api/real-test/users-access-controlled
249+
→ Should return ONLY users with IDs ['1','2','3','4','5'] (admin) or ['1','2'] (user)
250+
251+
3. GET /api/real-test/compare
252+
→ Shows side-by-side comparison of original vs access-controlled results
253+
254+
4. GET /api/real-test/test-different-users
255+
→ Tests admin vs regular user access patterns
256+
257+
WHAT TO LOOK FOR:
258+
259+
✅ Original query returns all users in database
260+
✅ Access controlled query only returns users with IDs in access list
261+
✅ Admin user gets more results than regular user
262+
✅ SQL IN clause is properly generated and executed
263+
✅ No errors or crashes
264+
265+
If you see SQL like:
266+
SELECT * FROM users WHERE users.id IN ('1','2','3','4','5') LIMIT 10
267+
268+
Then our access control is working perfectly! 🎉
269+
*/

0 commit comments

Comments
 (0)