@futdevpro/nts-dynamo 1.15.232 → 1.15.240
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/build/_enums/email-submission-outcome.enum.d.ts +8 -0
- package/build/_enums/email-submission-outcome.enum.d.ts.map +1 -0
- package/build/_enums/email-submission-outcome.enum.js +12 -0
- package/build/_enums/email-submission-outcome.enum.js.map +1 -0
- package/build/_models/interfaces/email-submission-receipt.interface.d.ts +19 -0
- package/build/_models/interfaces/email-submission-receipt.interface.d.ts.map +1 -0
- package/build/_models/interfaces/email-submission-receipt.interface.js +3 -0
- package/build/_models/interfaces/email-submission-receipt.interface.js.map +1 -0
- package/build/_modules/account-security/_models/account-challenge-transaction-settings.interface.d.ts +21 -0
- package/build/_modules/account-security/_models/account-challenge-transaction-settings.interface.d.ts.map +1 -0
- package/build/_modules/account-security/_models/account-challenge-transaction-settings.interface.js +3 -0
- package/build/_modules/account-security/_models/account-challenge-transaction-settings.interface.js.map +1 -0
- package/build/_modules/account-security/_models/account-session-transaction-settings.interface.d.ts +12 -0
- package/build/_modules/account-security/_models/account-session-transaction-settings.interface.d.ts.map +1 -0
- package/build/_modules/account-security/_models/account-session-transaction-settings.interface.js +3 -0
- package/build/_modules/account-security/_models/account-session-transaction-settings.interface.js.map +1 -0
- package/build/_modules/account-security/account-challenge-transaction.mongo-adapter.d.ts +44 -0
- package/build/_modules/account-security/account-challenge-transaction.mongo-adapter.d.ts.map +1 -0
- package/build/_modules/account-security/account-challenge-transaction.mongo-adapter.js +174 -0
- package/build/_modules/account-security/account-challenge-transaction.mongo-adapter.js.map +1 -0
- package/build/_modules/account-security/account-session-transaction.mongo-store.d.ts +24 -0
- package/build/_modules/account-security/account-session-transaction.mongo-store.d.ts.map +1 -0
- package/build/_modules/account-security/account-session-transaction.mongo-store.js +96 -0
- package/build/_modules/account-security/account-session-transaction.mongo-store.js.map +1 -0
- package/build/_modules/account-security/account-session.control-service.d.ts +12 -0
- package/build/_modules/account-security/account-session.control-service.d.ts.map +1 -1
- package/build/_modules/account-security/account-session.control-service.js +28 -3
- package/build/_modules/account-security/account-session.control-service.js.map +1 -1
- package/build/_modules/account-security/index.d.ts +4 -0
- package/build/_modules/account-security/index.d.ts.map +1 -1
- package/build/_modules/account-security/index.js +5 -1
- package/build/_modules/account-security/index.js.map +1 -1
- package/build/_modules/privacy-lifecycle/_models/privacy-rights-custody.interface.d.ts +86 -0
- package/build/_modules/privacy-lifecycle/_models/privacy-rights-custody.interface.d.ts.map +1 -0
- package/build/_modules/privacy-lifecycle/_models/privacy-rights-custody.interface.js +3 -0
- package/build/_modules/privacy-lifecycle/_models/privacy-rights-custody.interface.js.map +1 -0
- package/build/_modules/privacy-lifecycle/index.d.ts +2 -0
- package/build/_modules/privacy-lifecycle/index.d.ts.map +1 -1
- package/build/_modules/privacy-lifecycle/index.js +3 -1
- package/build/_modules/privacy-lifecycle/index.js.map +1 -1
- package/build/_modules/privacy-lifecycle/privacy-rights-custody.mongo-store.d.ts +51 -0
- package/build/_modules/privacy-lifecycle/privacy-rights-custody.mongo-store.d.ts.map +1 -0
- package/build/_modules/privacy-lifecycle/privacy-rights-custody.mongo-store.js +384 -0
- package/build/_modules/privacy-lifecycle/privacy-rights-custody.mongo-store.js.map +1 -0
- package/build/_services/core/email.service.d.ts +9 -0
- package/build/_services/core/email.service.d.ts.map +1 -1
- package/build/_services/core/email.service.js +90 -25
- package/build/_services/core/email.service.js.map +1 -1
- package/build/index.d.ts +2 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +2 -0
- package/build/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DyNTS_PrivacyRightsCustody_MongoStore = void 0;
|
|
4
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
|
+
const node_util_1 = require("node:util");
|
|
6
|
+
const mongoose_1 = require("mongoose");
|
|
7
|
+
const account_challenge_purpose_type_enum_1 = require("../account-security/_enums/account-challenge-purpose.type-enum");
|
|
8
|
+
const privacy_request_state_type_enum_1 = require("./_enums/privacy-request-state.type-enum");
|
|
9
|
+
const privacy_request_type_enum_1 = require("./_enums/privacy-request.type-enum");
|
|
10
|
+
const privacy_rights_input_control_service_1 = require("./privacy-rights-input.control-service");
|
|
11
|
+
/**
|
|
12
|
+
* Atomic confidential rights-input custody. Call ensureReady during bootstrap, then use the SAME strong
|
|
13
|
+
* transaction for request/subject locking, challenge consumption and encrypted creation. No nested transaction.
|
|
14
|
+
* Injected callbacks are trusted composition, not browser authority. Never catch a failure and commit anyway.
|
|
15
|
+
*/
|
|
16
|
+
class DyNTS_PrivacyRightsCustody_MongoStore {
|
|
17
|
+
settings;
|
|
18
|
+
schemas;
|
|
19
|
+
ownedErrors = new WeakSet();
|
|
20
|
+
isReady = false;
|
|
21
|
+
/** Captures explicit lifetime, policy history and purpose-separated encryption without reading secrets. */
|
|
22
|
+
constructor(settings) {
|
|
23
|
+
try {
|
|
24
|
+
if (!settings?.connection || typeof settings.connection.startSession !== 'function'
|
|
25
|
+
|| !this.positive(settings.maxOperationTimeMs, 2_147_483_647)
|
|
26
|
+
|| !this.positive(settings.retentionMs, 2_592_000_000)
|
|
27
|
+
|| !Array.isArray(settings.policies) || !this.positive(settings.policies.length, 64)
|
|
28
|
+
|| typeof settings.cipher?.seal !== 'function' || typeof settings.cipher?.open !== 'function'
|
|
29
|
+
|| typeof settings.lockRequest !== 'function' || typeof settings.consumeChallenge !== 'function'
|
|
30
|
+
|| typeof settings.acceptRequest !== 'function'
|
|
31
|
+
|| (settings.verifyRequestIdentity !== undefined && typeof settings.verifyRequestIdentity !== 'function')) {
|
|
32
|
+
throw new Error();
|
|
33
|
+
}
|
|
34
|
+
const schemas = new Map();
|
|
35
|
+
for (const policy of settings.policies) {
|
|
36
|
+
if (schemas.has(policy.policyVersion)) {
|
|
37
|
+
throw new Error();
|
|
38
|
+
}
|
|
39
|
+
schemas.set(policy.policyVersion, new privacy_rights_input_control_service_1.DyNTS_PrivacyRightsInput_ControlService(policy));
|
|
40
|
+
}
|
|
41
|
+
if (!schemas.has(settings.currentPolicyVersion)) {
|
|
42
|
+
throw new Error();
|
|
43
|
+
}
|
|
44
|
+
this.settings = Object.freeze({ ...settings });
|
|
45
|
+
this.schemas = schemas;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
throw this.error('SETTINGS_INVALID');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/** Creates a strict collection and unique challenge binding outside all business transactions. */
|
|
52
|
+
async ensureReady() {
|
|
53
|
+
if (this.isReady) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
try {
|
|
58
|
+
await this.settings.connection.db.createCollection('dynts_privacy_rights_inputs', {
|
|
59
|
+
validator: this.validator(), validationLevel: 'strict', validationAction: 'error',
|
|
60
|
+
maxTimeMS: this.settings.maxOperationTimeMs,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
if (!(error instanceof mongoose_1.mongo.MongoServerError) || error.code !== 48) {
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const information = await this.settings.connection.db.listCollections({ name: 'dynts_privacy_rights_inputs' }, { nameOnly: false, maxTimeMS: this.settings.maxOperationTimeMs }).next();
|
|
69
|
+
if (!(0, node_util_1.isDeepStrictEqual)(information?.options?.validator, this.validator())
|
|
70
|
+
|| information?.options?.validationLevel !== 'strict' || information?.options?.validationAction !== 'error') {
|
|
71
|
+
throw this.error('SCHEMA_MIGRATION_REQUIRED');
|
|
72
|
+
}
|
|
73
|
+
await this.collection().createIndex({ challengeId: 1 }, {
|
|
74
|
+
unique: true, name: 'uq_dynts_rights_challenge', maxTimeMS: this.settings.maxOperationTimeMs,
|
|
75
|
+
});
|
|
76
|
+
this.isReady = true;
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
if (error instanceof Error && this.ownedErrors.has(error)) {
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
throw this.error('NOT_READY');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/** Commits with the caller's transaction; replay requires the same credential and identical normalized input. */
|
|
86
|
+
async intake(set, session) {
|
|
87
|
+
return this.execute(session, async () => {
|
|
88
|
+
const authority = this.authority(set?.authority);
|
|
89
|
+
if (typeof set.token !== 'string' || !/^[A-Za-z0-9_-]{43,512}$/u.test(set.token)) {
|
|
90
|
+
throw this.error('CHALLENGE_INVALID');
|
|
91
|
+
}
|
|
92
|
+
const request = await this.lockRequest(authority, session);
|
|
93
|
+
const existing = await this.collection().findOne({ _id: this.key(authority) }, this.options(session));
|
|
94
|
+
const now = await this.databaseTime();
|
|
95
|
+
const credentialHash = (0, node_crypto_1.createHash)('sha256').update(set.token).digest('hex');
|
|
96
|
+
if (Date.parse(request.deadlineAt) <= now.getTime()) {
|
|
97
|
+
throw this.error('REQUEST_EXPIRED');
|
|
98
|
+
}
|
|
99
|
+
if (existing) {
|
|
100
|
+
this.assertRecord(existing, authority, now);
|
|
101
|
+
if (existing.credentialHash !== credentialHash || existing.requestType !== request.type) {
|
|
102
|
+
throw this.error('REPLAY_CONFLICT');
|
|
103
|
+
}
|
|
104
|
+
const parsed = this.parse(set.input, existing);
|
|
105
|
+
const original = this.open(existing);
|
|
106
|
+
if (JSON.stringify(parsed) !== JSON.stringify(original)) {
|
|
107
|
+
throw this.error('REPLAY_CONFLICT');
|
|
108
|
+
}
|
|
109
|
+
return this.receipt(existing, false);
|
|
110
|
+
}
|
|
111
|
+
const needsIdentityVerification = request.state === privacy_request_state_type_enum_1.DyNTS_PrivacyRequestState_Type.received;
|
|
112
|
+
if ((needsIdentityVerification
|
|
113
|
+
? !this.settings.verifyRequestIdentity || !!request.identityVerifiedAt
|
|
114
|
+
: request.state !== privacy_request_state_type_enum_1.DyNTS_PrivacyRequestState_Type.identityVerified || !request.identityVerifiedAt)
|
|
115
|
+
|| !!request.executionStartedAt || request.revision > Number.MAX_SAFE_INTEGER
|
|
116
|
+
- (needsIdentityVerification ? 2 : 1)) {
|
|
117
|
+
throw this.error('REQUEST_STATE_INVALID');
|
|
118
|
+
}
|
|
119
|
+
const policyVersion = typeof set.input === 'object' && set.input !== null
|
|
120
|
+
? Object.getOwnPropertyDescriptor(set.input, 'policyVersion')?.value : undefined;
|
|
121
|
+
if (typeof policyVersion !== 'string' || policyVersion !== this.settings.currentPolicyVersion) {
|
|
122
|
+
throw this.error('INPUT_INVALID');
|
|
123
|
+
}
|
|
124
|
+
const inputContext = {
|
|
125
|
+
contractVersion: 'dynts-privacy-rights-custody/1', ...authority, inputId: (0, node_crypto_1.randomUUID)(),
|
|
126
|
+
requestType: request.type, requestRevision: request.revision, policyVersion: policyVersion,
|
|
127
|
+
challengeId: '', createdAt: now.toISOString(),
|
|
128
|
+
expiresAt: new Date(Math.min(now.getTime() + this.settings.retentionMs, Date.parse(request.deadlineAt))).toISOString(),
|
|
129
|
+
};
|
|
130
|
+
const parsed = this.parse(set.input, inputContext);
|
|
131
|
+
const purpose = this.purpose(request.type);
|
|
132
|
+
const consumed = await this.settings.consumeChallenge({
|
|
133
|
+
token: set.token, subjectId: authority.subjectId, purpose: purpose, session: session, now: now,
|
|
134
|
+
});
|
|
135
|
+
if (!consumed || !this.code(consumed.challengeId) || consumed.subjectId !== authority.subjectId
|
|
136
|
+
|| consumed.purpose !== purpose) {
|
|
137
|
+
throw this.error('CHALLENGE_INVALID');
|
|
138
|
+
}
|
|
139
|
+
const verified = needsIdentityVerification
|
|
140
|
+
? await this.verifyIdentity(request, {
|
|
141
|
+
authority: authority, expectedRevision: request.revision, challengeId: consumed.challengeId,
|
|
142
|
+
verifiedAt: now.toISOString(), session: session,
|
|
143
|
+
})
|
|
144
|
+
: request;
|
|
145
|
+
const context = Object.freeze({
|
|
146
|
+
...inputContext, challengeId: consumed.challengeId,
|
|
147
|
+
});
|
|
148
|
+
const plaintext = JSON.stringify(parsed);
|
|
149
|
+
const sealed = this.settings.cipher.seal(plaintext, context);
|
|
150
|
+
if (!sealed || !this.code(sealed.keyId) || typeof sealed.ciphertext !== 'string'
|
|
151
|
+
|| !sealed.ciphertext || sealed.ciphertext.length > 131_072 || sealed.ciphertext === plaintext) {
|
|
152
|
+
throw this.error('ENCRYPTION_FAILED');
|
|
153
|
+
}
|
|
154
|
+
const record = {
|
|
155
|
+
...context, _id: this.key(authority), credentialHash: credentialHash,
|
|
156
|
+
keyId: sealed.keyId, ciphertext: sealed.ciphertext,
|
|
157
|
+
};
|
|
158
|
+
// Authenticate the actual encryption result before durable storage. Never persist a plaintext checksum.
|
|
159
|
+
if (JSON.stringify(this.open(record)) !== plaintext) {
|
|
160
|
+
throw this.error('ENCRYPTION_FAILED');
|
|
161
|
+
}
|
|
162
|
+
await this.collection().insertOne(record, this.options(session));
|
|
163
|
+
const accepted = await this.settings.acceptRequest({
|
|
164
|
+
authority: authority, expectedRevision: verified.revision, acceptedAt: context.createdAt, session: session,
|
|
165
|
+
});
|
|
166
|
+
if (accepted?.requestId !== authority.requestId || accepted.subjectId !== authority.subjectId
|
|
167
|
+
|| accepted.organizationId !== authority.organizationId || accepted.type !== request.type
|
|
168
|
+
|| accepted.idempotencyHash !== verified.idempotencyHash || accepted.createdAt !== verified.createdAt
|
|
169
|
+
|| accepted.deadlineAt !== verified.deadlineAt
|
|
170
|
+
|| accepted.revision !== verified.revision + 1 || accepted.state !== privacy_request_state_type_enum_1.DyNTS_PrivacyRequestState_Type.scoped
|
|
171
|
+
|| accepted.scopedAt !== context.createdAt || accepted.identityVerifiedAt !== verified.identityVerifiedAt
|
|
172
|
+
|| !!accepted.executionStartedAt || !!accepted.cancelledAt) {
|
|
173
|
+
throw this.error('ACCEPTANCE_CONFLICT');
|
|
174
|
+
}
|
|
175
|
+
return this.receipt(record, true);
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
/** Execution-only callback; no plaintext read/list/download method or arbitrary callback return value. */
|
|
179
|
+
async withExecutionInput(set, session) {
|
|
180
|
+
await this.execute(session, async () => {
|
|
181
|
+
const authority = this.authority(set?.authority);
|
|
182
|
+
const request = await this.lockRequest(authority, session);
|
|
183
|
+
if (request.state !== privacy_request_state_type_enum_1.DyNTS_PrivacyRequestState_Type.executing || typeof set.task !== 'function') {
|
|
184
|
+
throw this.error('EXECUTION_DENIED');
|
|
185
|
+
}
|
|
186
|
+
const record = await this.collection().findOne({ _id: this.key(authority) }, this.options(session));
|
|
187
|
+
const now = await this.databaseTime();
|
|
188
|
+
this.assertRecord(record, authority, now);
|
|
189
|
+
if (record.requestType !== request.type || Date.parse(request.deadlineAt) <= now.getTime()) {
|
|
190
|
+
throw this.error('EXECUTION_DENIED');
|
|
191
|
+
}
|
|
192
|
+
await set.task(this.open(record), session);
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
/** Erases ciphertext and grant-binding data only after expiry or terminal lifecycle, then proves no residue. */
|
|
196
|
+
async eraseInput(authorityValue, session) {
|
|
197
|
+
return this.execute(session, async () => {
|
|
198
|
+
const authority = this.authority(authorityValue);
|
|
199
|
+
// Cleanup must also support cancelled/rejected requests, unlike intake and execution admission.
|
|
200
|
+
const request = await this.settings.lockRequest(authority, session);
|
|
201
|
+
if (request?.requestId !== authority.requestId || request.subjectId !== authority.subjectId
|
|
202
|
+
|| request.organizationId !== authority.organizationId) {
|
|
203
|
+
throw this.error('AUTHORITY_INVALID');
|
|
204
|
+
}
|
|
205
|
+
const record = await this.collection().findOne({ _id: this.key(authority) }, this.options(session));
|
|
206
|
+
if (!record) {
|
|
207
|
+
return 0;
|
|
208
|
+
}
|
|
209
|
+
const terminal = [privacy_request_state_type_enum_1.DyNTS_PrivacyRequestState_Type.completed, privacy_request_state_type_enum_1.DyNTS_PrivacyRequestState_Type.cancelled,
|
|
210
|
+
privacy_request_state_type_enum_1.DyNTS_PrivacyRequestState_Type.rejectedWithReason, privacy_request_state_type_enum_1.DyNTS_PrivacyRequestState_Type.failedTerminal]
|
|
211
|
+
.includes(request.state);
|
|
212
|
+
const now = await this.databaseTime();
|
|
213
|
+
if (!terminal && !(Date.parse(record.expiresAt) <= now.getTime())) {
|
|
214
|
+
throw this.error('ERASURE_NOT_ELIGIBLE');
|
|
215
|
+
}
|
|
216
|
+
const removed = await this.collection().deleteOne({
|
|
217
|
+
_id: record._id, inputId: record.inputId,
|
|
218
|
+
}, this.options(session));
|
|
219
|
+
if (removed.deletedCount !== 1 || await this.collection().findOne({ _id: record._id }, this.options(session))) {
|
|
220
|
+
throw this.error('ERASURE_NOT_VERIFIED');
|
|
221
|
+
}
|
|
222
|
+
return 1;
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
/** Binds the one freshly consumed grant to received -> identityVerified without changing the approved preview. */
|
|
226
|
+
async verifyIdentity(request, set) {
|
|
227
|
+
const verified = await this.settings.verifyRequestIdentity(set);
|
|
228
|
+
const authority = set.authority;
|
|
229
|
+
if (verified?.requestId !== authority.requestId || verified.subjectId !== authority.subjectId
|
|
230
|
+
|| verified.organizationId !== authority.organizationId || verified.type !== request.type
|
|
231
|
+
|| verified.idempotencyHash !== request.idempotencyHash || verified.createdAt !== request.createdAt
|
|
232
|
+
|| verified.deadlineAt !== request.deadlineAt || verified.revision !== request.revision + 1
|
|
233
|
+
|| verified.state !== privacy_request_state_type_enum_1.DyNTS_PrivacyRequestState_Type.identityVerified
|
|
234
|
+
|| verified.identityVerifiedAt !== set.verifiedAt
|
|
235
|
+
|| !!verified.scopedAt || !!verified.plannedAt || !!verified.executionStartedAt || !!verified.verifyingStartedAt
|
|
236
|
+
|| !!verified.completedAt || !!verified.cancelledAt) {
|
|
237
|
+
throw this.error('IDENTITY_VERIFICATION_CONFLICT');
|
|
238
|
+
}
|
|
239
|
+
return verified;
|
|
240
|
+
}
|
|
241
|
+
async lockRequest(authority, session) {
|
|
242
|
+
const request = await this.settings.lockRequest(authority, session);
|
|
243
|
+
if (request?.requestId !== authority.requestId || request.subjectId !== authority.subjectId
|
|
244
|
+
|| request.organizationId !== authority.organizationId || !Number.isSafeInteger(request.revision)
|
|
245
|
+
|| request.revision < 0 || !Number.isFinite(Date.parse(request.deadlineAt))) {
|
|
246
|
+
throw this.error('AUTHORITY_INVALID');
|
|
247
|
+
}
|
|
248
|
+
this.purpose(request.type);
|
|
249
|
+
if (request.cancelledAt || request.state === privacy_request_state_type_enum_1.DyNTS_PrivacyRequestState_Type.cancelled
|
|
250
|
+
|| request.state === privacy_request_state_type_enum_1.DyNTS_PrivacyRequestState_Type.failedTerminal
|
|
251
|
+
|| request.state === privacy_request_state_type_enum_1.DyNTS_PrivacyRequestState_Type.rejectedWithReason) {
|
|
252
|
+
throw this.error('REQUEST_STATE_INVALID');
|
|
253
|
+
}
|
|
254
|
+
return request;
|
|
255
|
+
}
|
|
256
|
+
parse(value, context) {
|
|
257
|
+
const schema = this.schemas.get(context.policyVersion);
|
|
258
|
+
if (!schema) {
|
|
259
|
+
throw this.error('POLICY_UNAVAILABLE');
|
|
260
|
+
}
|
|
261
|
+
const type = Object.values(privacy_request_type_enum_1.DyNTS_PrivacyRequest_Type)
|
|
262
|
+
.find((entry) => entry === context.requestType);
|
|
263
|
+
return schema.parse(value, { requestId: context.requestId, type: type, revision: context.requestRevision });
|
|
264
|
+
}
|
|
265
|
+
open(record) {
|
|
266
|
+
const plaintext = this.settings.cipher.open({ keyId: record.keyId, ciphertext: record.ciphertext }, this.context(record));
|
|
267
|
+
if (typeof plaintext !== 'string' || Buffer.byteLength(plaintext, 'utf8') > 65_536) {
|
|
268
|
+
throw this.error('CIPHERTEXT_INVALID');
|
|
269
|
+
}
|
|
270
|
+
return this.parse(JSON.parse(plaintext), record);
|
|
271
|
+
}
|
|
272
|
+
context(record) {
|
|
273
|
+
return Object.freeze({
|
|
274
|
+
contractVersion: record.contractVersion, inputId: record.inputId, requestId: record.requestId,
|
|
275
|
+
subjectId: record.subjectId, organizationId: record.organizationId, requestType: record.requestType,
|
|
276
|
+
requestRevision: record.requestRevision, policyVersion: record.policyVersion, challengeId: record.challengeId,
|
|
277
|
+
createdAt: record.createdAt, expiresAt: record.expiresAt,
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
assertRecord(record, authority, now) {
|
|
281
|
+
if (record?._id !== this.key(authority) || record.requestId !== authority.requestId
|
|
282
|
+
|| record.subjectId !== authority.subjectId || record.organizationId !== authority.organizationId
|
|
283
|
+
|| record.contractVersion !== 'dynts-privacy-rights-custody/1' || !this.code(record.inputId)
|
|
284
|
+
|| !Number.isFinite(Date.parse(record.expiresAt)) || Date.parse(record.expiresAt) <= now.getTime()) {
|
|
285
|
+
throw this.error('INPUT_UNAVAILABLE');
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
authority(value) {
|
|
289
|
+
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
290
|
+
const requestId = descriptors.requestId?.value;
|
|
291
|
+
const subjectId = descriptors.subjectId?.value;
|
|
292
|
+
const organizationId = descriptors.organizationId?.value;
|
|
293
|
+
if (Reflect.ownKeys(value).length !== 3 || !this.code(requestId)
|
|
294
|
+
|| !this.code(subjectId) || !this.code(organizationId)) {
|
|
295
|
+
throw this.error('AUTHORITY_INVALID');
|
|
296
|
+
}
|
|
297
|
+
return Object.freeze({ requestId: requestId, subjectId: subjectId, organizationId: organizationId });
|
|
298
|
+
}
|
|
299
|
+
async databaseTime() {
|
|
300
|
+
// hello is not legal inside a transaction. This bounded same-server clock read carries no session or payload.
|
|
301
|
+
const result = await this.settings.connection.db.command({ hello: 1, maxTimeMS: this.settings.maxOperationTimeMs }, { timeoutMS: this.settings.maxOperationTimeMs });
|
|
302
|
+
const now = result.localTime;
|
|
303
|
+
if (!(now instanceof Date) || !Number.isFinite(now.getTime())) {
|
|
304
|
+
throw this.error('CLOCK_UNAVAILABLE');
|
|
305
|
+
}
|
|
306
|
+
return now;
|
|
307
|
+
}
|
|
308
|
+
async execute(session, task) {
|
|
309
|
+
const concern = session?.transaction?.options?.readConcern;
|
|
310
|
+
if (!this.isReady || !session?.inTransaction() || session.transaction.options.writeConcern?.w !== 'majority'
|
|
311
|
+
|| (typeof concern === 'string' ? concern : concern?.level) !== 'snapshot') {
|
|
312
|
+
throw this.error('OWNING_TRANSACTION_REQUIRED');
|
|
313
|
+
}
|
|
314
|
+
try {
|
|
315
|
+
// The native driver validates session ownership before dispatch. Empty _id is excluded by our strict schema;
|
|
316
|
+
// this indexed, content-free read verifies the real connection/session pair BEFORE any trusted callback.
|
|
317
|
+
await this.collection().findOne({ _id: '' }, this.options(session));
|
|
318
|
+
return await task();
|
|
319
|
+
}
|
|
320
|
+
catch (error) {
|
|
321
|
+
// Preserve only the driver's retry label, never the message, command or input in its error.
|
|
322
|
+
if (error instanceof mongoose_1.mongo.MongoError && error.hasErrorLabel('TransientTransactionError')) {
|
|
323
|
+
const retryable = new mongoose_1.mongo.MongoError('DyNTS|PRIVACY_RIGHTS_CUSTODY|TRANSACTION_FAILED');
|
|
324
|
+
retryable.addErrorLabel('TransientTransactionError');
|
|
325
|
+
throw retryable;
|
|
326
|
+
}
|
|
327
|
+
if (error instanceof Error && this.ownedErrors.has(error)) {
|
|
328
|
+
throw error;
|
|
329
|
+
}
|
|
330
|
+
throw this.error('INTAKE_OR_EXECUTION_FAILED');
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
purpose(type) {
|
|
334
|
+
switch (type) {
|
|
335
|
+
case privacy_request_type_enum_1.DyNTS_PrivacyRequest_Type.rectification: return account_challenge_purpose_type_enum_1.DyNTS_AccountChallengePurpose_Type.privacyRectification;
|
|
336
|
+
case privacy_request_type_enum_1.DyNTS_PrivacyRequest_Type.restriction: return account_challenge_purpose_type_enum_1.DyNTS_AccountChallengePurpose_Type.privacyRestriction;
|
|
337
|
+
case privacy_request_type_enum_1.DyNTS_PrivacyRequest_Type.objection: return account_challenge_purpose_type_enum_1.DyNTS_AccountChallengePurpose_Type.privacyObjection;
|
|
338
|
+
default: throw this.error('REQUEST_TYPE_INVALID');
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
receipt(record, created) {
|
|
342
|
+
return Object.freeze({ contractVersion: 'dynts-privacy-rights-receipt/1', inputId: record.inputId,
|
|
343
|
+
requestId: record.requestId, created: created, expiresAt: record.expiresAt });
|
|
344
|
+
}
|
|
345
|
+
key(authority) {
|
|
346
|
+
return (0, node_crypto_1.createHash)('sha256').update(JSON.stringify([
|
|
347
|
+
'dynts-privacy-rights-custody/1', authority.requestId, authority.subjectId, authority.organizationId,
|
|
348
|
+
])).digest('hex');
|
|
349
|
+
}
|
|
350
|
+
positive(value, maximum) {
|
|
351
|
+
return Number.isSafeInteger(value) && Number(value) > 0 && Number(value) <= maximum;
|
|
352
|
+
}
|
|
353
|
+
code(value) {
|
|
354
|
+
return typeof value === 'string' && /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/u.test(value);
|
|
355
|
+
}
|
|
356
|
+
options(session) {
|
|
357
|
+
return { session: session, maxTimeMS: this.settings.maxOperationTimeMs };
|
|
358
|
+
}
|
|
359
|
+
collection() {
|
|
360
|
+
return this.settings.connection.db.collection('dynts_privacy_rights_inputs');
|
|
361
|
+
}
|
|
362
|
+
error(code) {
|
|
363
|
+
const error = new Error(`DyNTS|PRIVACY_RIGHTS_CUSTODY|${code}`);
|
|
364
|
+
this.ownedErrors.add(error);
|
|
365
|
+
return error;
|
|
366
|
+
}
|
|
367
|
+
validator() {
|
|
368
|
+
const code = { bsonType: 'string', pattern: '^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$' };
|
|
369
|
+
const properties = {
|
|
370
|
+
_id: { bsonType: 'string', pattern: '^[a-f0-9]{64}$' },
|
|
371
|
+
contractVersion: { enum: ['dynts-privacy-rights-custody/1'] },
|
|
372
|
+
inputId: code, requestId: code, subjectId: code, organizationId: code, policyVersion: code, challengeId: code,
|
|
373
|
+
requestType: { enum: ['rectification', 'restriction', 'objection'] },
|
|
374
|
+
requestRevision: { bsonType: ['int', 'long', 'double'], minimum: 0, maximum: Number.MAX_SAFE_INTEGER },
|
|
375
|
+
createdAt: { bsonType: 'string', maxLength: 24 }, expiresAt: { bsonType: 'string', maxLength: 24 },
|
|
376
|
+
credentialHash: { bsonType: 'string', pattern: '^[a-f0-9]{64}$' },
|
|
377
|
+
keyId: code, ciphertext: { bsonType: 'string', minLength: 1, maxLength: 131_072 },
|
|
378
|
+
};
|
|
379
|
+
return { $jsonSchema: { bsonType: 'object', additionalProperties: false,
|
|
380
|
+
required: Object.keys(properties), properties: properties } };
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
exports.DyNTS_PrivacyRightsCustody_MongoStore = DyNTS_PrivacyRightsCustody_MongoStore;
|
|
384
|
+
//# sourceMappingURL=privacy-rights-custody.mongo-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"privacy-rights-custody.mongo-store.js","sourceRoot":"","sources":["../../../src/_modules/privacy-lifecycle/privacy-rights-custody.mongo-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Attachment } from 'nodemailer/lib/mailer';
|
|
2
2
|
import { DyFM_AnyError, DyFM_Error_Settings } from '@futdevpro/fsm-dynamo';
|
|
3
|
+
import { DyNTS_EmailSubmissionReceipt_Interface } from '../../_models/interfaces/email-submission-receipt.interface';
|
|
3
4
|
export interface DyNTS_EmailService_Settings {
|
|
4
5
|
host: string;
|
|
5
6
|
port: number;
|
|
@@ -52,6 +53,14 @@ export declare class DyNTS_EmailService {
|
|
|
52
53
|
* @param set
|
|
53
54
|
*/
|
|
54
55
|
sendEmail<T>(set: DyNTS_SendEmail_Settings<T>, issuer: string): Promise<void>;
|
|
56
|
+
/** Submits once through the existing renderer/transport and returns only validated submission evidence. */
|
|
57
|
+
sendEmailWithReceipt<T>(set: DyNTS_SendEmail_Settings<T>, issuer: string): Promise<DyNTS_EmailSubmissionReceipt_Interface>;
|
|
58
|
+
/** Never retains raw transport errors, recipients, template data or attachment contents. */
|
|
59
|
+
private submissionFailure;
|
|
60
|
+
/** Projects only data properties of the SMTP result; malformed or accessor-backed evidence is unknown. */
|
|
61
|
+
private submissionReceipt;
|
|
62
|
+
/** SMTP recipient arrays are validated but their addresses never enter the receipt. */
|
|
63
|
+
private recipientList;
|
|
55
64
|
private compileTemplateComponent;
|
|
56
65
|
private compileHTMLMainFrame;
|
|
57
66
|
/** trims all rows and remove everything between /*...*\/ */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"email.service.d.ts","sourceRoot":"","sources":["../../../src/_services/core/email.service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"email.service.d.ts","sourceRoot":"","sources":["../../../src/_services/core/email.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,9 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.DyNTS_EmailService = exports.DyNTS_EmailTemplateComponent = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const FileSystem = tslib_1.__importStar(require("fs"));
|
|
6
|
+
const node_crypto_1 = require("node:crypto");
|
|
6
7
|
const NodeMailer = tslib_1.__importStar(require("nodemailer"));
|
|
7
8
|
const fsm_dynamo_1 = require("@futdevpro/fsm-dynamo");
|
|
8
9
|
const global_settings_const_1 = require("../../_collections/global-settings.const");
|
|
10
|
+
const email_submission_outcome_enum_1 = require("../../_enums/email-submission-outcome.enum");
|
|
9
11
|
const dynts_test_email_sink_service_1 = require("../../_modules/test-email-sink/_services/dynts-test-email-sink.service");
|
|
10
12
|
class DyNTS_EmailTemplateComponent {
|
|
11
13
|
name;
|
|
@@ -74,6 +76,13 @@ class DyNTS_EmailService /* extends DyNTS_SingletonService */ {
|
|
|
74
76
|
* @param set
|
|
75
77
|
*/
|
|
76
78
|
async sendEmail(set, issuer) {
|
|
79
|
+
const receipt = await this.sendEmailWithReceipt(set, issuer);
|
|
80
|
+
if (receipt.outcome !== email_submission_outcome_enum_1.DyNTS_EmailSubmissionOutcome_Enum.accepted) {
|
|
81
|
+
throw this.submissionFailure(issuer, receipt.outcome === email_submission_outcome_enum_1.DyNTS_EmailSubmissionOutcome_Enum.rejected);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/** Submits once through the existing renderer/transport and returns only validated submission evidence. */
|
|
85
|
+
async sendEmailWithReceipt(set, issuer) {
|
|
77
86
|
try {
|
|
78
87
|
let content;
|
|
79
88
|
if (set.content) {
|
|
@@ -108,7 +117,11 @@ class DyNTS_EmailService /* extends DyNTS_SingletonService */ {
|
|
|
108
117
|
html: content,
|
|
109
118
|
issuer: issuer,
|
|
110
119
|
});
|
|
111
|
-
return
|
|
120
|
+
return {
|
|
121
|
+
contractVersion: 'dynts-email-submission-receipt/1', channel: 'test-sink',
|
|
122
|
+
outcome: email_submission_outcome_enum_1.DyNTS_EmailSubmissionOutcome_Enum.accepted,
|
|
123
|
+
submissionReference: '', acceptedCount: 0, rejectedCount: 0, pendingCount: 0,
|
|
124
|
+
};
|
|
112
125
|
}
|
|
113
126
|
const mailOptions = {
|
|
114
127
|
from: this.senderNEmail,
|
|
@@ -117,35 +130,87 @@ class DyNTS_EmailService /* extends DyNTS_SingletonService */ {
|
|
|
117
130
|
html: content,
|
|
118
131
|
attachments: set.attachments,
|
|
119
132
|
};
|
|
120
|
-
await
|
|
121
|
-
|
|
122
|
-
if (error) {
|
|
123
|
-
reject(error);
|
|
124
|
-
}
|
|
125
|
-
else {
|
|
126
|
-
resolve();
|
|
127
|
-
}
|
|
128
|
-
});
|
|
129
|
-
});
|
|
133
|
+
const info = await this.nmTransporter.sendMail(mailOptions);
|
|
134
|
+
return this.submissionReceipt(info);
|
|
130
135
|
}
|
|
131
136
|
catch (error) {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
userMessage: `Can't send mail to ${set.to}!`,
|
|
138
|
-
message: `sendEmail failed to ${set.to}`,
|
|
139
|
-
});
|
|
137
|
+
let allRejected = false;
|
|
138
|
+
try {
|
|
139
|
+
const message = error instanceof Error
|
|
140
|
+
? Object.getOwnPropertyDescriptor(error, 'message')?.value : undefined;
|
|
141
|
+
allRejected = typeof message === 'string' && message.includes('all recipients were rejected');
|
|
140
142
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
143
|
+
catch {
|
|
144
|
+
// A hostile error accessor is not trusted diagnostic evidence.
|
|
145
|
+
}
|
|
146
|
+
throw this.submissionFailure(issuer, allRejected);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/** Never retains raw transport errors, recipients, template data or attachment contents. */
|
|
150
|
+
submissionFailure(issuer, allRejected) {
|
|
151
|
+
return new fsm_dynamo_1.DyFM_Error({
|
|
152
|
+
status: 500,
|
|
153
|
+
errorCode: `${global_settings_const_1.DyNTS_global_settings.systemShortCodeName}|DyNTS-ES0-${allRejected ? 'SE4' : 'SE0'}`,
|
|
154
|
+
message: allRejected ? 'Email recipients were rejected.' : 'Email submission was not confirmed.',
|
|
155
|
+
userMessage: 'The email could not be confirmed as sent. Please contact support before retrying.',
|
|
156
|
+
addECToUserMsg: false,
|
|
157
|
+
issuer: issuer,
|
|
158
|
+
issuerService: this.serviceName,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
/** Projects only data properties of the SMTP result; malformed or accessor-backed evidence is unknown. */
|
|
162
|
+
submissionReceipt(value) {
|
|
163
|
+
const result = {
|
|
164
|
+
contractVersion: 'dynts-email-submission-receipt/1', channel: 'smtp',
|
|
165
|
+
outcome: email_submission_outcome_enum_1.DyNTS_EmailSubmissionOutcome_Enum.indeterminate,
|
|
166
|
+
submissionReference: '', acceptedCount: 0, rejectedCount: 0, pendingCount: 0,
|
|
167
|
+
};
|
|
168
|
+
try {
|
|
169
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
170
|
+
return result;
|
|
171
|
+
}
|
|
172
|
+
const fields = Object.getOwnPropertyDescriptors(value);
|
|
173
|
+
const accepted = fields.accepted?.value;
|
|
174
|
+
const rejected = fields.rejected?.value;
|
|
175
|
+
const pending = fields.pending ? fields.pending.value : [];
|
|
176
|
+
const messageId = fields.messageId?.value;
|
|
177
|
+
if (!this.recipientList(accepted) || !this.recipientList(rejected) || !this.recipientList(pending)) {
|
|
178
|
+
return result;
|
|
179
|
+
}
|
|
180
|
+
result.acceptedCount = accepted.length;
|
|
181
|
+
result.rejectedCount = rejected.length;
|
|
182
|
+
result.pendingCount = pending.length;
|
|
183
|
+
if (accepted.length === 0) {
|
|
184
|
+
result.outcome = rejected.length > 0 && pending.length === 0
|
|
185
|
+
? email_submission_outcome_enum_1.DyNTS_EmailSubmissionOutcome_Enum.rejected : email_submission_outcome_enum_1.DyNTS_EmailSubmissionOutcome_Enum.indeterminate;
|
|
186
|
+
}
|
|
187
|
+
else if (typeof messageId === 'string' && messageId.length > 0 && messageId.length <= 4096) {
|
|
188
|
+
result.outcome = rejected.length === 0 && pending.length === 0
|
|
189
|
+
? email_submission_outcome_enum_1.DyNTS_EmailSubmissionOutcome_Enum.accepted : email_submission_outcome_enum_1.DyNTS_EmailSubmissionOutcome_Enum.partial;
|
|
190
|
+
result.submissionReference = `sha256:${(0, node_crypto_1.createHash)('sha256').update(messageId).digest('hex')}`;
|
|
191
|
+
}
|
|
192
|
+
return result;
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
return {
|
|
196
|
+
contractVersion: 'dynts-email-submission-receipt/1', channel: 'smtp',
|
|
197
|
+
outcome: email_submission_outcome_enum_1.DyNTS_EmailSubmissionOutcome_Enum.indeterminate,
|
|
198
|
+
submissionReference: '', acceptedCount: 0, rejectedCount: 0, pendingCount: 0,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/** SMTP recipient arrays are validated but their addresses never enter the receipt. */
|
|
203
|
+
recipientList(value) {
|
|
204
|
+
if (!Array.isArray(value)) {
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
for (let index = 0; index < value.length; index++) {
|
|
208
|
+
const entry = Object.getOwnPropertyDescriptor(value, index)?.value;
|
|
209
|
+
if (typeof entry !== 'string' || entry.length === 0) {
|
|
210
|
+
return false;
|
|
147
211
|
}
|
|
148
212
|
}
|
|
213
|
+
return true;
|
|
149
214
|
}
|
|
150
215
|
async compileTemplateComponent(componentName, componentProperties, issuer) {
|
|
151
216
|
try {
|