@justair/justair-library 6.8.0 → 6.9.0-alpha.d61eca7
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/dist/models/admin.d.ts.map +1 -1
- package/dist/models/measurements.d.ts +6 -6
- package/dist/modules/audit/actions.d.ts +28 -0
- package/dist/modules/audit/actions.d.ts.map +1 -0
- package/dist/modules/audit/auditLog.d.ts +32 -0
- package/dist/modules/audit/auditLog.d.ts.map +1 -0
- package/dist/modules/audit/index.d.ts +4 -0
- package/dist/modules/audit/index.d.ts.map +1 -0
- package/dist/modules/audit/schema.d.ts +321 -0
- package/dist/modules/audit/schema.d.ts.map +1 -0
- package/dist/modules/audit/tests/actions.test.d.ts +2 -0
- package/dist/modules/audit/tests/actions.test.d.ts.map +1 -0
- package/dist/modules/audit/tests/auditLog.test.d.ts +2 -0
- package/dist/modules/audit/tests/auditLog.test.d.ts.map +1 -0
- package/dist/modules/audit/tests/schema.test.d.ts +2 -0
- package/dist/modules/audit/tests/schema.test.d.ts.map +1 -0
- package/dist/modules/auth/cookieConfig.d.ts +42 -0
- package/dist/modules/auth/cookieConfig.d.ts.map +1 -0
- package/dist/modules/auth/extractClaims.d.ts +22 -0
- package/dist/modules/auth/extractClaims.d.ts.map +1 -0
- package/dist/modules/auth/index.d.ts +6 -0
- package/dist/modules/auth/index.d.ts.map +1 -0
- package/dist/modules/auth/oidcVerifier.d.ts +22 -0
- package/dist/modules/auth/oidcVerifier.d.ts.map +1 -0
- package/dist/modules/auth/requestContext.d.ts +25 -0
- package/dist/modules/auth/requestContext.d.ts.map +1 -0
- package/dist/modules/auth/silentRefresh.d.ts +33 -0
- package/dist/modules/auth/silentRefresh.d.ts.map +1 -0
- package/dist/modules/auth/tests/cookieConfig.test.d.ts +2 -0
- package/dist/modules/auth/tests/cookieConfig.test.d.ts.map +1 -0
- package/dist/modules/auth/tests/extractClaims.test.d.ts +2 -0
- package/dist/modules/auth/tests/extractClaims.test.d.ts.map +1 -0
- package/dist/modules/auth/tests/oidcVerifier.test.d.ts +2 -0
- package/dist/modules/auth/tests/oidcVerifier.test.d.ts.map +1 -0
- package/dist/modules/auth/tests/requestContext.test.d.ts +2 -0
- package/dist/modules/auth/tests/requestContext.test.d.ts.map +1 -0
- package/dist/modules/auth/tests/silentRefresh.test.d.ts +2 -0
- package/dist/modules/auth/tests/silentRefresh.test.d.ts.map +1 -0
- package/package.json +14 -3
- package/src/models/admin.js +11 -1
- package/src/modules/audit/actions.js +28 -0
- package/src/modules/audit/auditLog.js +39 -0
- package/src/modules/audit/index.js +8 -0
- package/src/modules/audit/schema.js +44 -0
- package/src/modules/audit/tests/actions.test.js +26 -0
- package/src/modules/audit/tests/auditLog.test.js +47 -0
- package/src/modules/audit/tests/schema.test.js +50 -0
- package/src/modules/auth/cookieConfig.js +40 -0
- package/src/modules/auth/extractClaims.js +26 -0
- package/src/modules/auth/index.js +16 -0
- package/src/modules/auth/oidcVerifier.js +66 -0
- package/src/modules/auth/requestContext.js +20 -0
- package/src/modules/auth/silentRefresh.js +77 -0
- package/src/modules/auth/tests/cookieConfig.test.js +41 -0
- package/src/modules/auth/tests/extractClaims.test.js +36 -0
- package/src/modules/auth/tests/oidcVerifier.test.js +101 -0
- package/src/modules/auth/tests/requestContext.test.js +17 -0
- package/src/modules/auth/tests/silentRefresh.test.js +54 -0
- package/tsconfig.json +4 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../../src/models/admin.js"],"names":[],"mappings":"AAEA,
|
|
1
|
+
{"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../../src/models/admin.js"],"names":[],"mappings":"AAEA,8BAsBG;AAcH,wBAAmD"}
|
|
@@ -6,10 +6,10 @@ export const annotationSchema: mongoose.Schema<any, mongoose.Model<any, any, any
|
|
|
6
6
|
_id: true;
|
|
7
7
|
timestamps: false;
|
|
8
8
|
}, {
|
|
9
|
-
source: "admin" | "processing_engine";
|
|
10
|
-
timestamp: Date;
|
|
11
9
|
comment: string;
|
|
12
10
|
measurementIdentifier: string;
|
|
11
|
+
source: "admin" | "processing_engine";
|
|
12
|
+
timestamp: Date;
|
|
13
13
|
adminId?: {
|
|
14
14
|
prototype?: mongoose.Types.ObjectId;
|
|
15
15
|
cacheHexString?: unknown;
|
|
@@ -20,10 +20,10 @@ export const annotationSchema: mongoose.Schema<any, mongoose.Model<any, any, any
|
|
|
20
20
|
isValid?: {};
|
|
21
21
|
};
|
|
22
22
|
}, mongoose.Document<unknown, {}, mongoose.FlatRecord<{
|
|
23
|
-
source: "admin" | "processing_engine";
|
|
24
|
-
timestamp: Date;
|
|
25
23
|
comment: string;
|
|
26
24
|
measurementIdentifier: string;
|
|
25
|
+
source: "admin" | "processing_engine";
|
|
26
|
+
timestamp: Date;
|
|
27
27
|
adminId?: {
|
|
28
28
|
prototype?: mongoose.Types.ObjectId;
|
|
29
29
|
cacheHexString?: unknown;
|
|
@@ -34,10 +34,10 @@ export const annotationSchema: mongoose.Schema<any, mongoose.Model<any, any, any
|
|
|
34
34
|
isValid?: {};
|
|
35
35
|
};
|
|
36
36
|
}>> & mongoose.FlatRecord<{
|
|
37
|
-
source: "admin" | "processing_engine";
|
|
38
|
-
timestamp: Date;
|
|
39
37
|
comment: string;
|
|
40
38
|
measurementIdentifier: string;
|
|
39
|
+
source: "admin" | "processing_engine";
|
|
40
|
+
timestamp: Date;
|
|
41
41
|
adminId?: {
|
|
42
42
|
prototype?: mongoose.Types.ObjectId;
|
|
43
43
|
cacheHexString?: unknown;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth/compliance audit action enum (auth-contracts #4 — EXACT strings, frozen).
|
|
3
|
+
* Distinct domain from the measurement-lineage `Audit` model in
|
|
4
|
+
* models/measurements.js: this tracks WHO did WHAT to admin/auth state, for the
|
|
5
|
+
* government-compliance audit trail.
|
|
6
|
+
*
|
|
7
|
+
* Emit sites (in the services): login (success/failure), logout, forgot-password
|
|
8
|
+
* (requested/completed), silent refresh, and the admin mutation sites
|
|
9
|
+
* (create/update/delete, role.change when permissionName changes,
|
|
10
|
+
* deactivate/reactivate when isActive toggles).
|
|
11
|
+
*/
|
|
12
|
+
export const AUDIT_ACTIONS: Readonly<{
|
|
13
|
+
LOGIN_SUCCESS: "auth.login.success";
|
|
14
|
+
LOGIN_FAILURE: "auth.login.failure";
|
|
15
|
+
LOGOUT: "auth.logout";
|
|
16
|
+
PASSWORD_RESET_REQUESTED: "auth.password.reset.requested";
|
|
17
|
+
PASSWORD_RESET_COMPLETED: "auth.password.reset.completed";
|
|
18
|
+
TOKEN_REFRESH: "auth.token.refresh";
|
|
19
|
+
ADMIN_CREATE: "admin.create";
|
|
20
|
+
ADMIN_UPDATE: "admin.update";
|
|
21
|
+
ADMIN_DELETE: "admin.delete";
|
|
22
|
+
ADMIN_ROLE_CHANGE: "admin.role.change";
|
|
23
|
+
ADMIN_DEACTIVATE: "admin.deactivate";
|
|
24
|
+
ADMIN_REACTIVATE: "admin.reactivate";
|
|
25
|
+
}>;
|
|
26
|
+
/** Frozen list of all valid action strings — used as the AuditLog schema enum. */
|
|
27
|
+
export const AUDIT_ACTION_VALUES: readonly ("auth.login.success" | "auth.login.failure" | "auth.logout" | "auth.password.reset.requested" | "auth.password.reset.completed" | "auth.token.refresh" | "admin.create" | "admin.update" | "admin.delete" | "admin.role.change" | "admin.deactivate" | "admin.reactivate")[];
|
|
28
|
+
//# sourceMappingURL=actions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../../src/modules/audit/actions.js"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH;;;;;;;;;;;;;GAaG;AAEH,kFAAkF;AAClF,yTAA+E"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single canonical audit write path (auth-contracts #4).
|
|
3
|
+
*
|
|
4
|
+
* writeAudit(entry) ──► AuditLog.create
|
|
5
|
+
* │ ok │ throws (db down, validation)
|
|
6
|
+
* ▼ ▼
|
|
7
|
+
* return true logger.error + return false (NEVER throws)
|
|
8
|
+
*
|
|
9
|
+
* An audit hiccup must not fail the request it is recording (e.g. a login). The
|
|
10
|
+
* caller gets a boolean and decides; the failure is logged at error for compliance
|
|
11
|
+
* follow-up. Inject the consuming service's logger via deps.logger (DI); it falls
|
|
12
|
+
* back to a no-op rather than raw console so it honors the "no console" rule.
|
|
13
|
+
*
|
|
14
|
+
* @param {{action:string, actor?:object, resource?:object, outcome:string,
|
|
15
|
+
* reason?:string, metadata?:object, requestId?:string}} entry
|
|
16
|
+
* @param {{ logger?: { error: Function } }} [deps]
|
|
17
|
+
* @returns {Promise<boolean>} true if persisted, false if the write failed
|
|
18
|
+
*/
|
|
19
|
+
export function writeAudit({ action, actor, resource, outcome, reason, metadata, requestId }?: {
|
|
20
|
+
action: string;
|
|
21
|
+
actor?: object;
|
|
22
|
+
resource?: object;
|
|
23
|
+
outcome: string;
|
|
24
|
+
reason?: string;
|
|
25
|
+
metadata?: object;
|
|
26
|
+
requestId?: string;
|
|
27
|
+
}, { logger }?: {
|
|
28
|
+
logger?: {
|
|
29
|
+
error: Function;
|
|
30
|
+
};
|
|
31
|
+
}): Promise<boolean>;
|
|
32
|
+
//# sourceMappingURL=auditLog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auditLog.d.ts","sourceRoot":"","sources":["../../../src/modules/audit/auditLog.js"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;GAiBG;AACH,+FALW;IAAC,MAAM,EAAC,MAAM,CAAC;IAAC,KAAK,CAAC,EAAC,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAC,MAAM,CAAC;IAAC,OAAO,EAAC,MAAM,CAAC;IAC/D,MAAM,CAAC,EAAC,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAC,MAAM,CAAC;IAAC,SAAS,CAAC,EAAC,MAAM,CAAA;CAAC,eACrD;IAAE,MAAM,CAAC,EAAE;QAAE,KAAK,WAAU;KAAE,CAAA;CAAE,GAC9B,OAAO,CAAC,OAAO,CAAC,CAiB5B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/modules/audit/index.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AuditLog — auth/compliance audit trail (JA-2814, auth-contracts #4).
|
|
3
|
+
* One model definition; both services import it, neither redefines it. This is NOT
|
|
4
|
+
* the measurement-lineage `Audit` model (models/measurements.js) — different domain,
|
|
5
|
+
* different collection.
|
|
6
|
+
*
|
|
7
|
+
* actor (who) ─┐
|
|
8
|
+
* action (what) ├─► AuditLog doc ──► compliance queries (by actor / action / target)
|
|
9
|
+
* resource (tgt) ┘
|
|
10
|
+
*/
|
|
11
|
+
export const auditLogSchema: mongoose.Schema<any, mongoose.Model<any, any, any, any, any, any>, {}, {}, {}, {}, {
|
|
12
|
+
timestamps: true;
|
|
13
|
+
}, {
|
|
14
|
+
createdAt: NativeDate;
|
|
15
|
+
updatedAt: NativeDate;
|
|
16
|
+
} & {
|
|
17
|
+
action: "auth.login.success" | "auth.login.failure" | "auth.logout" | "auth.password.reset.requested" | "auth.password.reset.completed" | "auth.token.refresh" | "admin.create" | "admin.update" | "admin.delete" | "admin.role.change" | "admin.deactivate" | "admin.reactivate";
|
|
18
|
+
outcome: "success" | "failure";
|
|
19
|
+
metadata?: any;
|
|
20
|
+
actor?: {
|
|
21
|
+
adminId?: {
|
|
22
|
+
prototype?: mongoose.Types.ObjectId;
|
|
23
|
+
cacheHexString?: unknown;
|
|
24
|
+
generate?: {};
|
|
25
|
+
createFromTime?: {};
|
|
26
|
+
createFromHexString?: {};
|
|
27
|
+
createFromBase64?: {};
|
|
28
|
+
isValid?: {};
|
|
29
|
+
};
|
|
30
|
+
email?: string;
|
|
31
|
+
orgId?: {
|
|
32
|
+
prototype?: mongoose.Types.ObjectId;
|
|
33
|
+
cacheHexString?: unknown;
|
|
34
|
+
generate?: {};
|
|
35
|
+
createFromTime?: {};
|
|
36
|
+
createFromHexString?: {};
|
|
37
|
+
createFromBase64?: {};
|
|
38
|
+
isValid?: {};
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
resource?: {
|
|
42
|
+
type?: string;
|
|
43
|
+
};
|
|
44
|
+
reason?: string;
|
|
45
|
+
requestId?: string;
|
|
46
|
+
}, mongoose.Document<unknown, {}, mongoose.FlatRecord<{
|
|
47
|
+
createdAt: NativeDate;
|
|
48
|
+
updatedAt: NativeDate;
|
|
49
|
+
} & {
|
|
50
|
+
action: "auth.login.success" | "auth.login.failure" | "auth.logout" | "auth.password.reset.requested" | "auth.password.reset.completed" | "auth.token.refresh" | "admin.create" | "admin.update" | "admin.delete" | "admin.role.change" | "admin.deactivate" | "admin.reactivate";
|
|
51
|
+
outcome: "success" | "failure";
|
|
52
|
+
metadata?: any;
|
|
53
|
+
actor?: {
|
|
54
|
+
adminId?: {
|
|
55
|
+
prototype?: mongoose.Types.ObjectId;
|
|
56
|
+
cacheHexString?: unknown;
|
|
57
|
+
generate?: {};
|
|
58
|
+
createFromTime?: {};
|
|
59
|
+
createFromHexString?: {};
|
|
60
|
+
createFromBase64?: {};
|
|
61
|
+
isValid?: {};
|
|
62
|
+
};
|
|
63
|
+
email?: string;
|
|
64
|
+
orgId?: {
|
|
65
|
+
prototype?: mongoose.Types.ObjectId;
|
|
66
|
+
cacheHexString?: unknown;
|
|
67
|
+
generate?: {};
|
|
68
|
+
createFromTime?: {};
|
|
69
|
+
createFromHexString?: {};
|
|
70
|
+
createFromBase64?: {};
|
|
71
|
+
isValid?: {};
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
resource?: {
|
|
75
|
+
type?: string;
|
|
76
|
+
};
|
|
77
|
+
reason?: string;
|
|
78
|
+
requestId?: string;
|
|
79
|
+
}>> & mongoose.FlatRecord<{
|
|
80
|
+
createdAt: NativeDate;
|
|
81
|
+
updatedAt: NativeDate;
|
|
82
|
+
} & {
|
|
83
|
+
action: "auth.login.success" | "auth.login.failure" | "auth.logout" | "auth.password.reset.requested" | "auth.password.reset.completed" | "auth.token.refresh" | "admin.create" | "admin.update" | "admin.delete" | "admin.role.change" | "admin.deactivate" | "admin.reactivate";
|
|
84
|
+
outcome: "success" | "failure";
|
|
85
|
+
metadata?: any;
|
|
86
|
+
actor?: {
|
|
87
|
+
adminId?: {
|
|
88
|
+
prototype?: mongoose.Types.ObjectId;
|
|
89
|
+
cacheHexString?: unknown;
|
|
90
|
+
generate?: {};
|
|
91
|
+
createFromTime?: {};
|
|
92
|
+
createFromHexString?: {};
|
|
93
|
+
createFromBase64?: {};
|
|
94
|
+
isValid?: {};
|
|
95
|
+
};
|
|
96
|
+
email?: string;
|
|
97
|
+
orgId?: {
|
|
98
|
+
prototype?: mongoose.Types.ObjectId;
|
|
99
|
+
cacheHexString?: unknown;
|
|
100
|
+
generate?: {};
|
|
101
|
+
createFromTime?: {};
|
|
102
|
+
createFromHexString?: {};
|
|
103
|
+
createFromBase64?: {};
|
|
104
|
+
isValid?: {};
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
resource?: {
|
|
108
|
+
type?: string;
|
|
109
|
+
};
|
|
110
|
+
reason?: string;
|
|
111
|
+
requestId?: string;
|
|
112
|
+
}> & {
|
|
113
|
+
_id: mongoose.Types.ObjectId;
|
|
114
|
+
}>;
|
|
115
|
+
export const AuditLog: mongoose.Model<{
|
|
116
|
+
createdAt: NativeDate;
|
|
117
|
+
updatedAt: NativeDate;
|
|
118
|
+
} & {
|
|
119
|
+
action: "auth.login.success" | "auth.login.failure" | "auth.logout" | "auth.password.reset.requested" | "auth.password.reset.completed" | "auth.token.refresh" | "admin.create" | "admin.update" | "admin.delete" | "admin.role.change" | "admin.deactivate" | "admin.reactivate";
|
|
120
|
+
outcome: "success" | "failure";
|
|
121
|
+
metadata?: any;
|
|
122
|
+
actor?: {
|
|
123
|
+
adminId?: {
|
|
124
|
+
prototype?: mongoose.Types.ObjectId;
|
|
125
|
+
cacheHexString?: unknown;
|
|
126
|
+
generate?: {};
|
|
127
|
+
createFromTime?: {};
|
|
128
|
+
createFromHexString?: {};
|
|
129
|
+
createFromBase64?: {};
|
|
130
|
+
isValid?: {};
|
|
131
|
+
};
|
|
132
|
+
email?: string;
|
|
133
|
+
orgId?: {
|
|
134
|
+
prototype?: mongoose.Types.ObjectId;
|
|
135
|
+
cacheHexString?: unknown;
|
|
136
|
+
generate?: {};
|
|
137
|
+
createFromTime?: {};
|
|
138
|
+
createFromHexString?: {};
|
|
139
|
+
createFromBase64?: {};
|
|
140
|
+
isValid?: {};
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
resource?: {
|
|
144
|
+
type?: string;
|
|
145
|
+
};
|
|
146
|
+
reason?: string;
|
|
147
|
+
requestId?: string;
|
|
148
|
+
}, {}, {}, {}, mongoose.Document<unknown, {}, {
|
|
149
|
+
createdAt: NativeDate;
|
|
150
|
+
updatedAt: NativeDate;
|
|
151
|
+
} & {
|
|
152
|
+
action: "auth.login.success" | "auth.login.failure" | "auth.logout" | "auth.password.reset.requested" | "auth.password.reset.completed" | "auth.token.refresh" | "admin.create" | "admin.update" | "admin.delete" | "admin.role.change" | "admin.deactivate" | "admin.reactivate";
|
|
153
|
+
outcome: "success" | "failure";
|
|
154
|
+
metadata?: any;
|
|
155
|
+
actor?: {
|
|
156
|
+
adminId?: {
|
|
157
|
+
prototype?: mongoose.Types.ObjectId;
|
|
158
|
+
cacheHexString?: unknown;
|
|
159
|
+
generate?: {};
|
|
160
|
+
createFromTime?: {};
|
|
161
|
+
createFromHexString?: {};
|
|
162
|
+
createFromBase64?: {};
|
|
163
|
+
isValid?: {};
|
|
164
|
+
};
|
|
165
|
+
email?: string;
|
|
166
|
+
orgId?: {
|
|
167
|
+
prototype?: mongoose.Types.ObjectId;
|
|
168
|
+
cacheHexString?: unknown;
|
|
169
|
+
generate?: {};
|
|
170
|
+
createFromTime?: {};
|
|
171
|
+
createFromHexString?: {};
|
|
172
|
+
createFromBase64?: {};
|
|
173
|
+
isValid?: {};
|
|
174
|
+
};
|
|
175
|
+
};
|
|
176
|
+
resource?: {
|
|
177
|
+
type?: string;
|
|
178
|
+
};
|
|
179
|
+
reason?: string;
|
|
180
|
+
requestId?: string;
|
|
181
|
+
}> & {
|
|
182
|
+
createdAt: NativeDate;
|
|
183
|
+
updatedAt: NativeDate;
|
|
184
|
+
} & {
|
|
185
|
+
action: "auth.login.success" | "auth.login.failure" | "auth.logout" | "auth.password.reset.requested" | "auth.password.reset.completed" | "auth.token.refresh" | "admin.create" | "admin.update" | "admin.delete" | "admin.role.change" | "admin.deactivate" | "admin.reactivate";
|
|
186
|
+
outcome: "success" | "failure";
|
|
187
|
+
metadata?: any;
|
|
188
|
+
actor?: {
|
|
189
|
+
adminId?: {
|
|
190
|
+
prototype?: mongoose.Types.ObjectId;
|
|
191
|
+
cacheHexString?: unknown;
|
|
192
|
+
generate?: {};
|
|
193
|
+
createFromTime?: {};
|
|
194
|
+
createFromHexString?: {};
|
|
195
|
+
createFromBase64?: {};
|
|
196
|
+
isValid?: {};
|
|
197
|
+
};
|
|
198
|
+
email?: string;
|
|
199
|
+
orgId?: {
|
|
200
|
+
prototype?: mongoose.Types.ObjectId;
|
|
201
|
+
cacheHexString?: unknown;
|
|
202
|
+
generate?: {};
|
|
203
|
+
createFromTime?: {};
|
|
204
|
+
createFromHexString?: {};
|
|
205
|
+
createFromBase64?: {};
|
|
206
|
+
isValid?: {};
|
|
207
|
+
};
|
|
208
|
+
};
|
|
209
|
+
resource?: {
|
|
210
|
+
type?: string;
|
|
211
|
+
};
|
|
212
|
+
reason?: string;
|
|
213
|
+
requestId?: string;
|
|
214
|
+
} & {
|
|
215
|
+
_id: mongoose.Types.ObjectId;
|
|
216
|
+
}, mongoose.Schema<any, mongoose.Model<any, any, any, any, any, any>, {}, {}, {}, {}, {
|
|
217
|
+
timestamps: true;
|
|
218
|
+
}, {
|
|
219
|
+
createdAt: NativeDate;
|
|
220
|
+
updatedAt: NativeDate;
|
|
221
|
+
} & {
|
|
222
|
+
action: "auth.login.success" | "auth.login.failure" | "auth.logout" | "auth.password.reset.requested" | "auth.password.reset.completed" | "auth.token.refresh" | "admin.create" | "admin.update" | "admin.delete" | "admin.role.change" | "admin.deactivate" | "admin.reactivate";
|
|
223
|
+
outcome: "success" | "failure";
|
|
224
|
+
metadata?: any;
|
|
225
|
+
actor?: {
|
|
226
|
+
adminId?: {
|
|
227
|
+
prototype?: mongoose.Types.ObjectId;
|
|
228
|
+
cacheHexString?: unknown;
|
|
229
|
+
generate?: {};
|
|
230
|
+
createFromTime?: {};
|
|
231
|
+
createFromHexString?: {};
|
|
232
|
+
createFromBase64?: {};
|
|
233
|
+
isValid?: {};
|
|
234
|
+
};
|
|
235
|
+
email?: string;
|
|
236
|
+
orgId?: {
|
|
237
|
+
prototype?: mongoose.Types.ObjectId;
|
|
238
|
+
cacheHexString?: unknown;
|
|
239
|
+
generate?: {};
|
|
240
|
+
createFromTime?: {};
|
|
241
|
+
createFromHexString?: {};
|
|
242
|
+
createFromBase64?: {};
|
|
243
|
+
isValid?: {};
|
|
244
|
+
};
|
|
245
|
+
};
|
|
246
|
+
resource?: {
|
|
247
|
+
type?: string;
|
|
248
|
+
};
|
|
249
|
+
reason?: string;
|
|
250
|
+
requestId?: string;
|
|
251
|
+
}, mongoose.Document<unknown, {}, mongoose.FlatRecord<{
|
|
252
|
+
createdAt: NativeDate;
|
|
253
|
+
updatedAt: NativeDate;
|
|
254
|
+
} & {
|
|
255
|
+
action: "auth.login.success" | "auth.login.failure" | "auth.logout" | "auth.password.reset.requested" | "auth.password.reset.completed" | "auth.token.refresh" | "admin.create" | "admin.update" | "admin.delete" | "admin.role.change" | "admin.deactivate" | "admin.reactivate";
|
|
256
|
+
outcome: "success" | "failure";
|
|
257
|
+
metadata?: any;
|
|
258
|
+
actor?: {
|
|
259
|
+
adminId?: {
|
|
260
|
+
prototype?: mongoose.Types.ObjectId;
|
|
261
|
+
cacheHexString?: unknown;
|
|
262
|
+
generate?: {};
|
|
263
|
+
createFromTime?: {};
|
|
264
|
+
createFromHexString?: {};
|
|
265
|
+
createFromBase64?: {};
|
|
266
|
+
isValid?: {};
|
|
267
|
+
};
|
|
268
|
+
email?: string;
|
|
269
|
+
orgId?: {
|
|
270
|
+
prototype?: mongoose.Types.ObjectId;
|
|
271
|
+
cacheHexString?: unknown;
|
|
272
|
+
generate?: {};
|
|
273
|
+
createFromTime?: {};
|
|
274
|
+
createFromHexString?: {};
|
|
275
|
+
createFromBase64?: {};
|
|
276
|
+
isValid?: {};
|
|
277
|
+
};
|
|
278
|
+
};
|
|
279
|
+
resource?: {
|
|
280
|
+
type?: string;
|
|
281
|
+
};
|
|
282
|
+
reason?: string;
|
|
283
|
+
requestId?: string;
|
|
284
|
+
}>> & mongoose.FlatRecord<{
|
|
285
|
+
createdAt: NativeDate;
|
|
286
|
+
updatedAt: NativeDate;
|
|
287
|
+
} & {
|
|
288
|
+
action: "auth.login.success" | "auth.login.failure" | "auth.logout" | "auth.password.reset.requested" | "auth.password.reset.completed" | "auth.token.refresh" | "admin.create" | "admin.update" | "admin.delete" | "admin.role.change" | "admin.deactivate" | "admin.reactivate";
|
|
289
|
+
outcome: "success" | "failure";
|
|
290
|
+
metadata?: any;
|
|
291
|
+
actor?: {
|
|
292
|
+
adminId?: {
|
|
293
|
+
prototype?: mongoose.Types.ObjectId;
|
|
294
|
+
cacheHexString?: unknown;
|
|
295
|
+
generate?: {};
|
|
296
|
+
createFromTime?: {};
|
|
297
|
+
createFromHexString?: {};
|
|
298
|
+
createFromBase64?: {};
|
|
299
|
+
isValid?: {};
|
|
300
|
+
};
|
|
301
|
+
email?: string;
|
|
302
|
+
orgId?: {
|
|
303
|
+
prototype?: mongoose.Types.ObjectId;
|
|
304
|
+
cacheHexString?: unknown;
|
|
305
|
+
generate?: {};
|
|
306
|
+
createFromTime?: {};
|
|
307
|
+
createFromHexString?: {};
|
|
308
|
+
createFromBase64?: {};
|
|
309
|
+
isValid?: {};
|
|
310
|
+
};
|
|
311
|
+
};
|
|
312
|
+
resource?: {
|
|
313
|
+
type?: string;
|
|
314
|
+
};
|
|
315
|
+
reason?: string;
|
|
316
|
+
requestId?: string;
|
|
317
|
+
}> & {
|
|
318
|
+
_id: mongoose.Types.ObjectId;
|
|
319
|
+
}>>;
|
|
320
|
+
import mongoose from 'mongoose';
|
|
321
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/modules/audit/schema.js"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqBE;AAOF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAA4D;qBAzCvC,UAAU"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actions.test.d.ts","sourceRoot":"","sources":["../../../../src/modules/audit/tests/actions.test.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auditLog.test.d.ts","sourceRoot":"","sources":["../../../../src/modules/audit/tests/auditLog.test.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.test.d.ts","sourceRoot":"","sources":["../../../../src/modules/audit/tests/schema.test.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical httpOnly cookie options for Keycloak tokens (auth-contracts #3).
|
|
3
|
+
* Lifted from JustAirService/util/cookieConfig.js and extended to the two-TTL model:
|
|
4
|
+
* a short-lived access cookie + a long-lived refresh cookie. Both services import
|
|
5
|
+
* THIS — do not hand-roll cookie options per controller.
|
|
6
|
+
*
|
|
7
|
+
* Exposed as functions (not constants) so NODE_ENV is read at call time, not at
|
|
8
|
+
* import time — a service that configures env after importing still gets the right
|
|
9
|
+
* secure/SameSite flags.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Shared flags. SameSite=Lax: every JustAir admin frontend lives under
|
|
13
|
+
* `*.justair.app`, so frontend → API requests are same-site (same registrable
|
|
14
|
+
* domain) and Lax sends the cookie cross-subdomain while still blocking cross-site
|
|
15
|
+
* POST/fetch (tighter CSRF posture than None). Secure only in prod — dev is
|
|
16
|
+
* http://localhost, and Lax (unlike None) does not require Secure.
|
|
17
|
+
*/
|
|
18
|
+
export function baseCookieOptions(): {
|
|
19
|
+
httpOnly: boolean;
|
|
20
|
+
secure: boolean;
|
|
21
|
+
sameSite: string;
|
|
22
|
+
path: string;
|
|
23
|
+
};
|
|
24
|
+
/** Options for the short-lived access_token cookie. */
|
|
25
|
+
export function accessTokenCookieOptions(): {
|
|
26
|
+
maxAge: number;
|
|
27
|
+
httpOnly: boolean;
|
|
28
|
+
secure: boolean;
|
|
29
|
+
sameSite: string;
|
|
30
|
+
path: string;
|
|
31
|
+
};
|
|
32
|
+
/** Options for the long-lived refresh_token cookie. */
|
|
33
|
+
export function refreshTokenCookieOptions(): {
|
|
34
|
+
maxAge: number;
|
|
35
|
+
httpOnly: boolean;
|
|
36
|
+
secure: boolean;
|
|
37
|
+
sameSite: string;
|
|
38
|
+
path: string;
|
|
39
|
+
};
|
|
40
|
+
export const ACCESS_TOKEN_MAX_AGE_MS: number;
|
|
41
|
+
export const REFRESH_TOKEN_MAX_AGE_MS: number;
|
|
42
|
+
//# sourceMappingURL=cookieConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cookieConfig.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/cookieConfig.js"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;;;GAMG;AACH;;;;;EAQC;AAKD,uDAAuD;AACvD;;;;;;EAEC;AAED,uDAAuD;AACvD;;;;;;EAEC;AAXD,6CAAqD;AACrD,8CAAgE"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalize a verified Keycloak token payload into the canonical AuthContext
|
|
3
|
+
* (auth-contracts #1 — FROZEN shape; consumers read these exact keys, never raw
|
|
4
|
+
* Keycloak claim paths).
|
|
5
|
+
*
|
|
6
|
+
* verified payload ──► { sub, email, roles, orgId }
|
|
7
|
+
*
|
|
8
|
+
* Pure function of the token. Request context (ip/userAgent/source) and persisted
|
|
9
|
+
* Admin state (ssoProvider) are deliberately NOT here — see ./requestContext.js
|
|
10
|
+
* and the Admin model. `roles` is realm roles only; `orgId` is undefined when the
|
|
11
|
+
* user has no org attribute.
|
|
12
|
+
*
|
|
13
|
+
* @param {import('jose').JWTPayload} payload - output of verifyToken()
|
|
14
|
+
* @returns {{ sub: string|undefined, email: string|undefined, roles: string[], orgId: string|undefined }}
|
|
15
|
+
*/
|
|
16
|
+
export function extractClaims(payload: import("jose").JWTPayload): {
|
|
17
|
+
sub: string | undefined;
|
|
18
|
+
email: string | undefined;
|
|
19
|
+
roles: string[];
|
|
20
|
+
orgId: string | undefined;
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=extractClaims.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractClaims.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/extractClaims.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,uCAHW,OAAO,MAAM,EAAE,UAAU,GACvB;IAAE,GAAG,EAAE,MAAM,GAAC,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,GAAC,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,GAAC,SAAS,CAAA;CAAE,CAYxG"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { extractClaims } from "./extractClaims.js";
|
|
2
|
+
export { requestContext } from "./requestContext.js";
|
|
3
|
+
export { verifyToken, isExpiredError } from "./oidcVerifier.js";
|
|
4
|
+
export { silentRefresh, RefreshError } from "./silentRefresh.js";
|
|
5
|
+
export { baseCookieOptions, accessTokenCookieOptions, refreshTokenCookieOptions, ACCESS_TOKEN_MAX_AGE_MS, REFRESH_TOKEN_MAX_AGE_MS } from "./cookieConfig.js";
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/index.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {string} token - raw access-token JWT (from cookie or Authorization header)
|
|
3
|
+
* @param {{ issuer: string, audience: string, jwksUri: string }} config
|
|
4
|
+
* @returns {Promise<import('jose').JWTPayload>} the verified token payload
|
|
5
|
+
* @throws jose errors (carry `.code`); use isExpiredError() to branch on expiry
|
|
6
|
+
*/
|
|
7
|
+
export function verifyToken(token: string, { issuer, audience, jwksUri }?: {
|
|
8
|
+
issuer: string;
|
|
9
|
+
audience: string;
|
|
10
|
+
jwksUri: string;
|
|
11
|
+
}): Promise<import("jose").JWTPayload>;
|
|
12
|
+
/**
|
|
13
|
+
* True when verification failed solely because the token is expired — the one
|
|
14
|
+
* failure consumers recover from via silent refresh. All other failures → 401.
|
|
15
|
+
*
|
|
16
|
+
* @param {unknown} err
|
|
17
|
+
* @returns {boolean}
|
|
18
|
+
*/
|
|
19
|
+
export function isExpiredError(err: unknown): boolean;
|
|
20
|
+
/** Test-only: clear the module-level JWKS cache between cases. */
|
|
21
|
+
export function _resetJwksCache(): void;
|
|
22
|
+
//# sourceMappingURL=oidcVerifier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oidcVerifier.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/oidcVerifier.js"],"names":[],"mappings":"AAiCA;;;;;GAKG;AACH,mCALW,MAAM,kCACN;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACnD,OAAO,CAAC,OAAO,MAAM,EAAE,UAAU,CAAC,CAa9C;AAED;;;;;;GAMG;AACH,oCAHW,OAAO,GACL,OAAO,CAInB;AAED,kEAAkE;AAClE,wCAEC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit request-context extractor (auth-contracts #1/#4 seam).
|
|
3
|
+
*
|
|
4
|
+
* AuthContext (extractClaims) is token-only by design. The request-scoped fields an
|
|
5
|
+
* audit row needs — ip, userAgent, source — live on the Express request, not the
|
|
6
|
+
* token. Both JustAirService and JustAirUserService call this and feed the result
|
|
7
|
+
* into writeAudit({ metadata }) so audit rows carry consistent request context
|
|
8
|
+
* without each service re-deriving the same three lines.
|
|
9
|
+
*
|
|
10
|
+
* @param {{ ip?: string, headers?: Object, socket?: { remoteAddress?: string } }} req - Express request
|
|
11
|
+
* @param {string} source - logical channel, e.g. 'web' | 'light-system'
|
|
12
|
+
* @returns {{ ip: string|undefined, userAgent: string|undefined, source: string }}
|
|
13
|
+
*/
|
|
14
|
+
export function requestContext(req: {
|
|
15
|
+
ip?: string;
|
|
16
|
+
headers?: any;
|
|
17
|
+
socket?: {
|
|
18
|
+
remoteAddress?: string;
|
|
19
|
+
};
|
|
20
|
+
}, source: string): {
|
|
21
|
+
ip: string | undefined;
|
|
22
|
+
userAgent: string | undefined;
|
|
23
|
+
source: string;
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=requestContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"requestContext.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/requestContext.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,oCAJW;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,MAAS;IAAC,MAAM,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,UACtE,MAAM,GACJ;IAAE,EAAE,EAAE,MAAM,GAAC,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,GAAC,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAQjF"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {string} refreshToken
|
|
3
|
+
* @param {{ tokenUrl: string, clientId: string, clientSecret: string }} config
|
|
4
|
+
* @returns {Promise<{accessToken:string, refreshToken:string, expiresIn:number, refreshExpiresIn:number}>}
|
|
5
|
+
* @throws {RefreshError}
|
|
6
|
+
*/
|
|
7
|
+
export function silentRefresh(refreshToken: string, { tokenUrl, clientId, clientSecret }?: {
|
|
8
|
+
tokenUrl: string;
|
|
9
|
+
clientId: string;
|
|
10
|
+
clientSecret: string;
|
|
11
|
+
}): Promise<{
|
|
12
|
+
accessToken: string;
|
|
13
|
+
refreshToken: string;
|
|
14
|
+
expiresIn: number;
|
|
15
|
+
refreshExpiresIn: number;
|
|
16
|
+
}>;
|
|
17
|
+
/**
|
|
18
|
+
* Silent refresh against Keycloak's token endpoint (auth-contracts #3).
|
|
19
|
+
*
|
|
20
|
+
* refreshToken ──► POST {tokenUrl} grant_type=refresh_token
|
|
21
|
+
* │ 200 │ non-200 / network / bad-json
|
|
22
|
+
* ▼ ▼
|
|
23
|
+
* { accessToken, refreshToken, ... } throw RefreshError (caller → 401)
|
|
24
|
+
*
|
|
25
|
+
* Uses Node's global fetch (Node 18+). Every failure throws RefreshError so the
|
|
26
|
+
* middleware maps any refresh miss to a single 401.
|
|
27
|
+
*/
|
|
28
|
+
export class RefreshError extends Error {
|
|
29
|
+
constructor(message: any, { status, cause }?: {});
|
|
30
|
+
status: any;
|
|
31
|
+
cause: any;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=silentRefresh.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"silentRefresh.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/silentRefresh.js"],"names":[],"mappings":"AAqBA;;;;;GAKG;AACH,4CALW,MAAM,yCACN;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAC1D,OAAO,CAAC;IAAC,WAAW,EAAC,MAAM,CAAC;IAAC,YAAY,EAAC,MAAM,CAAC;IAAC,SAAS,EAAC,MAAM,CAAC;IAAC,gBAAgB,EAAC,MAAM,CAAA;CAAC,CAAC,CAoDzG;AA5ED;;;;;;;;;;GAUG;AAEH;IACE,kDAKC;IAFC,YAAoB;IACT,WAAkB;CAEhC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cookieConfig.test.d.ts","sourceRoot":"","sources":["../../../../src/modules/auth/tests/cookieConfig.test.js"],"names":[],"mappings":""}
|