@zintrust/core 0.7.7 → 0.7.9
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/package.json +1 -1
- package/src/auth/LoginFlow.d.ts +7 -1
- package/src/auth/LoginFlow.d.ts.map +1 -1
- package/src/auth/LoginFlow.js +98 -2
- package/src/cli/OptionalCliExtensions.d.ts +1 -0
- package/src/cli/OptionalCliExtensions.d.ts.map +1 -1
- package/src/cli/OptionalCliExtensions.js +24 -2
- package/src/cli/commands/MySqlProxyCommand.d.ts.map +1 -1
- package/src/cli/commands/MySqlProxyCommand.js +1 -1
- package/src/cli/commands/RoutesCommand.d.ts.map +1 -1
- package/src/cli/commands/RoutesCommand.js +39 -2
- package/src/cli/commands/ScheduleStartCommand.d.ts.map +1 -1
- package/src/cli/commands/ScheduleStartCommand.js +14 -9
- package/src/cli/commands/schedule/ScheduleCliSupport.d.ts.map +1 -1
- package/src/cli/commands/schedule/ScheduleCliSupport.js +29 -4
- package/src/config/env.d.ts +2 -0
- package/src/config/env.d.ts.map +1 -1
- package/src/config/env.js +2 -0
- package/src/http/Request.d.ts +1 -0
- package/src/http/Request.d.ts.map +1 -1
- package/src/http/Request.js +3 -0
- package/src/index.d.ts +8 -4
- package/src/index.d.ts.map +1 -1
- package/src/index.js +7 -4
- package/src/middleware/BulletproofAuthMiddleware.d.ts +2 -1
- package/src/middleware/BulletproofAuthMiddleware.d.ts.map +1 -1
- package/src/middleware/BulletproofAuthMiddleware.js +106 -36
- package/src/runtime/useFileLoader.d.ts +5 -0
- package/src/runtime/useFileLoader.d.ts.map +1 -1
- package/src/runtime/useFileLoader.js +58 -37
- package/src/security/BulletproofDeviceStore.d.ts +18 -0
- package/src/security/BulletproofDeviceStore.d.ts.map +1 -0
- package/src/security/BulletproofDeviceStore.js +243 -0
- package/src/security/JwtVerifier.d.ts +75 -0
- package/src/security/JwtVerifier.d.ts.map +1 -0
- package/src/security/JwtVerifier.js +336 -0
- package/src/templates/project/basic/app/Controllers/AuthController.ts.tpl +24 -10
- package/src/templates/project/basic/config/trace.ts.tpl +73 -0
- package/src/templates/project/basic/database/migrations/20260419000000_create_bulletproof_devices_table.ts.tpl +36 -0
|
@@ -29,6 +29,7 @@ type PasswordLoginContext = {
|
|
|
29
29
|
email: string;
|
|
30
30
|
ipAddress: string;
|
|
31
31
|
requestId?: string;
|
|
32
|
+
request: IRequest;
|
|
32
33
|
};
|
|
33
34
|
|
|
34
35
|
const toSubject = (id: unknown): string | undefined => {
|
|
@@ -37,10 +38,6 @@ const toSubject = (id: unknown): string | undefined => {
|
|
|
37
38
|
return undefined;
|
|
38
39
|
};
|
|
39
40
|
|
|
40
|
-
const toDeviceId = (subject: string | undefined): string | undefined => {
|
|
41
|
-
return isUndefinedOrNull(subject) ? undefined : `dev-${subject}`;
|
|
42
|
-
};
|
|
43
|
-
|
|
44
41
|
const getClaimString = (claims: unknown, key: string): string | undefined => {
|
|
45
42
|
if (typeof claims !== 'object' || claims === null) {
|
|
46
43
|
return undefined;
|
|
@@ -55,7 +52,23 @@ const getIssuedToken = (issued: unknown): string => {
|
|
|
55
52
|
return issued;
|
|
56
53
|
}
|
|
57
54
|
|
|
58
|
-
|
|
55
|
+
if (typeof issued === 'object' && issued !== null) {
|
|
56
|
+
const token = (issued as Record<string, unknown>)['token'];
|
|
57
|
+
if (typeof token === 'string' && token.trim() !== '') {
|
|
58
|
+
return token;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
throw ErrorFactory.createSecurityError('LoginFlow issuer returned an invalid access token');
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const getIssuedString = (issued: unknown, key: string): string | undefined => {
|
|
66
|
+
if (typeof issued !== 'object' || issued === null) {
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const value = (issued as Record<string, unknown>)[key];
|
|
71
|
+
return typeof value === 'string' && value.trim() !== '' ? value : undefined;
|
|
59
72
|
};
|
|
60
73
|
|
|
61
74
|
const isLoginFlowUnauthorizedFailure = (error: unknown): boolean => {
|
|
@@ -120,7 +133,6 @@ const passwordLoginProvider = Object.freeze({
|
|
|
120
133
|
|
|
121
134
|
const user = pickPublicUser(identity);
|
|
122
135
|
const subject = toSubject(user.id);
|
|
123
|
-
const deviceId = toDeviceId(subject);
|
|
124
136
|
|
|
125
137
|
return {
|
|
126
138
|
user,
|
|
@@ -128,7 +140,6 @@ const passwordLoginProvider = Object.freeze({
|
|
|
128
140
|
claims: {
|
|
129
141
|
sub: subject,
|
|
130
142
|
email: user.email,
|
|
131
|
-
...(isUndefinedOrNull(deviceId) ? {} : { deviceId }),
|
|
132
143
|
},
|
|
133
144
|
};
|
|
134
145
|
},
|
|
@@ -156,17 +167,19 @@ async function login(req: IRequest, res: IResponse): Promise<void> {
|
|
|
156
167
|
try {
|
|
157
168
|
const result = await LoginFlow.create({
|
|
158
169
|
provider: passwordLoginProvider,
|
|
159
|
-
context: Object.freeze({ email, ipAddress, requestId }),
|
|
170
|
+
context: Object.freeze({ email, ipAddress, requestId, request: req }),
|
|
160
171
|
})
|
|
161
172
|
.identify({ email })
|
|
162
173
|
.verify({ password })
|
|
163
|
-
.issue('
|
|
174
|
+
.issue('bulletproof')
|
|
164
175
|
.audit()
|
|
165
176
|
.run();
|
|
166
177
|
|
|
167
178
|
const user = result.verified.user as { id: unknown; name: string; email: string };
|
|
168
179
|
const subject = getClaimString(result.verified.claims, 'sub');
|
|
169
|
-
const deviceId =
|
|
180
|
+
const deviceId =
|
|
181
|
+
getIssuedString(result.issued, 'deviceId') ?? getClaimString(result.verified.claims, 'deviceId');
|
|
182
|
+
const deviceSecret = getIssuedString(result.issued, 'deviceSecret');
|
|
170
183
|
const token = getIssuedToken(result.issued);
|
|
171
184
|
|
|
172
185
|
Logger.info('AuthController.login: successful login', {
|
|
@@ -181,6 +194,7 @@ async function login(req: IRequest, res: IResponse): Promise<void> {
|
|
|
181
194
|
token,
|
|
182
195
|
token_type: 'Bearer',
|
|
183
196
|
...(isUndefinedOrNull(deviceId) ? {} : { deviceId }),
|
|
197
|
+
...(isUndefinedOrNull(deviceSecret) ? {} : { deviceSecret }),
|
|
184
198
|
user,
|
|
185
199
|
});
|
|
186
200
|
} catch (error) {
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Env } from '@zintrust/core';
|
|
2
|
+
import type { TraceConfigOverrides } from '@zintrust/trace';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* SystemTrace Configuration
|
|
6
|
+
*
|
|
7
|
+
* Keep this file declarative:
|
|
8
|
+
* - Package owns defaults and type validation.
|
|
9
|
+
* - Edit values below to override for this project.
|
|
10
|
+
*
|
|
11
|
+
* Usage: import '@zintrust/trace/register' in your bootstrap.
|
|
12
|
+
* Protect /trace with your own middleware (auth, admin role, etc.).
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export default {
|
|
16
|
+
enabled: Env.getBool('TRACE_ENABLED', false),
|
|
17
|
+
|
|
18
|
+
// Optional: use a separate DB connection for trace tables.
|
|
19
|
+
// Leave undefined to fall back to the app's default connection.
|
|
20
|
+
connection: Env.get('TRACE_DB_CONNECTION', '') || undefined,
|
|
21
|
+
|
|
22
|
+
pruneAfterHours: Env.getInt('TRACE_PRUNE_HOURS', 72),
|
|
23
|
+
|
|
24
|
+
ignoreRoutes: ['/trace', '/health', '/ping', '/metrics', '/api-docs', '/api-docs-json'],
|
|
25
|
+
|
|
26
|
+
ignorePaths: [
|
|
27
|
+
'/telemetry',
|
|
28
|
+
'/favicon.ico',
|
|
29
|
+
'/robots.txt',
|
|
30
|
+
'/sitemap.xml',
|
|
31
|
+
'/workers',
|
|
32
|
+
'/queue-monitor',
|
|
33
|
+
'.js',
|
|
34
|
+
'.css',
|
|
35
|
+
],
|
|
36
|
+
|
|
37
|
+
slowQueryThreshold: Env.getInt('TRACE_SLOW_QUERY_MS', 100),
|
|
38
|
+
|
|
39
|
+
logMinLevel: Env.get('TRACE_LOG_LEVEL', 'warn') as 'debug' | 'info' | 'warn' | 'error' | 'fatal',
|
|
40
|
+
|
|
41
|
+
watchers: {
|
|
42
|
+
// Set a watcher to false to disable it entirely.
|
|
43
|
+
// All watchers are enabled by default when trace is enabled.
|
|
44
|
+
// Include/exclude filters are contains-based and can be applied per watcher.
|
|
45
|
+
// request: {
|
|
46
|
+
// get: { exclude: ['report','workers/events'] },
|
|
47
|
+
// post: { include: ['auth'] },
|
|
48
|
+
// patch: { include: ['profile'] },
|
|
49
|
+
// delete: { exclude: ['internal'] },
|
|
50
|
+
// },
|
|
51
|
+
// log: { exclude: ['healthcheck'] },
|
|
52
|
+
// exception: { include: ['trace'] },
|
|
53
|
+
// clientRequest: {
|
|
54
|
+
// exclude: ['internal-http'],
|
|
55
|
+
// sources: {
|
|
56
|
+
// termii: { enabled: false },
|
|
57
|
+
// sendgrid: { responseBody: false },
|
|
58
|
+
// s3: { requestHeaders: false, responseHeaders: false },
|
|
59
|
+
// },
|
|
60
|
+
// },
|
|
61
|
+
// cache: { include: ['session:'] },
|
|
62
|
+
// dump: false, // DumpWatcher is opt-in — enable explicitly if needed
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
redaction: {
|
|
66
|
+
// Extra keys to mask recursively before trace entries are persisted.
|
|
67
|
+
// You can also provide these via TRACE_REDACT_KEYS as JSON or CSV.
|
|
68
|
+
keys: ['password', 'token', 'secret', 'authorization', 'card', 'cardNumber', 'cvv'],
|
|
69
|
+
headers: ['authorization', 'cookie', 'x-api-key', 'x-auth-token'],
|
|
70
|
+
body: ['password', 'token', 'secret', 'apiKey', 'api_key', 'jwt', 'bearer'],
|
|
71
|
+
query: [],
|
|
72
|
+
},
|
|
73
|
+
} satisfies TraceConfigOverrides;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Migration: CreateBulletproofDevicesTable
|
|
3
|
+
* Creates the core-backed device store used by Bulletproof authentication.
|
|
4
|
+
*/
|
|
5
|
+
import type { Blueprint, IDatabase } from '@zintrust/core';
|
|
6
|
+
import { MigrationSchema } from '@zintrust/core';
|
|
7
|
+
|
|
8
|
+
export interface Migration {
|
|
9
|
+
up(db: IDatabase): Promise<void>;
|
|
10
|
+
down(db: IDatabase): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const migration: Migration = {
|
|
14
|
+
async up(db: IDatabase): Promise<void> {
|
|
15
|
+
const schema = MigrationSchema.create(db);
|
|
16
|
+
|
|
17
|
+
await schema.create('zintrust_bulletproof_devices', (table: Blueprint) => {
|
|
18
|
+
table.id();
|
|
19
|
+
table.string('user_id', 191).nullable();
|
|
20
|
+
table.string('device_id', 191).unique();
|
|
21
|
+
table.text('signing_secret');
|
|
22
|
+
table.text('user_agent').nullable();
|
|
23
|
+
table.timestamp('last_seen_at').notNullable().default('CURRENT_TIMESTAMP');
|
|
24
|
+
table.timestamp('created_at').notNullable().default('CURRENT_TIMESTAMP');
|
|
25
|
+
table.timestamp('updated_at').notNullable().default('CURRENT_TIMESTAMP');
|
|
26
|
+
|
|
27
|
+
table.index(['user_id']);
|
|
28
|
+
table.index(['last_seen_at']);
|
|
29
|
+
});
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
async down(db: IDatabase): Promise<void> {
|
|
33
|
+
const schema = MigrationSchema.create(db);
|
|
34
|
+
await schema.dropIfExists('zintrust_bulletproof_devices');
|
|
35
|
+
},
|
|
36
|
+
};
|