@enbox/dwn-sdk-js 0.4.3 → 0.4.5
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/browser.mjs +15 -15
- package/dist/browser.mjs.map +4 -4
- package/dist/esm/generated/precompiled-validators.js +5406 -2200
- package/dist/esm/generated/precompiled-validators.js.map +1 -1
- package/dist/esm/json-schemas/definitions.json +18 -0
- package/dist/esm/src/core/constants.js +3 -3
- package/dist/esm/src/core/constants.js.map +1 -1
- package/dist/esm/src/core/dwn-error.js +29 -1
- package/dist/esm/src/core/dwn-error.js.map +1 -1
- package/dist/esm/src/core/messages-grant-authorization.js +20 -0
- package/dist/esm/src/core/messages-grant-authorization.js.map +1 -1
- package/dist/esm/src/core/protocol-authorization-validation.js +80 -3
- package/dist/esm/src/core/protocol-authorization-validation.js.map +1 -1
- package/dist/esm/src/core/recording-validation-state-reader.js +5 -0
- package/dist/esm/src/core/recording-validation-state-reader.js.map +1 -1
- package/dist/esm/src/core/replication-apply.js +163 -7
- package/dist/esm/src/core/replication-apply.js.map +1 -1
- package/dist/esm/src/core/validation-state-reader.js +20 -0
- package/dist/esm/src/core/validation-state-reader.js.map +1 -1
- package/dist/esm/src/dwn.js +19 -2
- package/dist/esm/src/dwn.js.map +1 -1
- package/dist/esm/src/handlers/messages-query.js +3 -5
- package/dist/esm/src/handlers/messages-query.js.map +1 -1
- package/dist/esm/src/handlers/protocols-configure.js +10 -4
- package/dist/esm/src/handlers/protocols-configure.js.map +1 -1
- package/dist/esm/src/handlers/records-write.js +1 -1
- package/dist/esm/src/handlers/records-write.js.map +1 -1
- package/dist/esm/src/index.js +2 -1
- package/dist/esm/src/index.js.map +1 -1
- package/dist/esm/src/interfaces/protocols-configure.js +23 -10
- package/dist/esm/src/interfaces/protocols-configure.js.map +1 -1
- package/dist/esm/src/interfaces/records-write-signing.js +2 -8
- package/dist/esm/src/interfaces/records-write-signing.js.map +1 -1
- package/dist/esm/src/interfaces/records-write.js +43 -65
- package/dist/esm/src/interfaces/records-write.js.map +1 -1
- package/dist/esm/src/protocols/encryption.js +411 -0
- package/dist/esm/src/protocols/encryption.js.map +1 -0
- package/dist/esm/src/protocols/permission-grant.js +3 -3
- package/dist/esm/src/protocols/permission-grant.js.map +1 -1
- package/dist/esm/src/protocols/permissions.js +1 -0
- package/dist/esm/src/protocols/permissions.js.map +1 -1
- package/dist/esm/src/types/message-types.js.map +1 -1
- package/dist/esm/src/types/permission-types.js.map +1 -1
- package/dist/esm/src/types/protocols-types.js.map +1 -1
- package/dist/esm/src/utils/encryption.js +135 -187
- package/dist/esm/src/utils/encryption.js.map +1 -1
- package/dist/esm/src/utils/hd-key.js +0 -1
- package/dist/esm/src/utils/hd-key.js.map +1 -1
- package/dist/esm/src/utils/permission-scope.js +9 -6
- package/dist/esm/src/utils/permission-scope.js.map +1 -1
- package/dist/esm/src/utils/protocols.js +12 -9
- package/dist/esm/src/utils/protocols.js.map +1 -1
- package/dist/esm/src/utils/records.js +54 -56
- package/dist/esm/src/utils/records.js.map +1 -1
- package/dist/esm/src/utils/replication.js +27 -4
- package/dist/esm/src/utils/replication.js.map +1 -1
- package/dist/esm/tests/core/replication-apply.spec.js +141 -1
- package/dist/esm/tests/core/replication-apply.spec.js.map +1 -1
- package/dist/esm/tests/core/replication-replay-property.spec.js +1 -0
- package/dist/esm/tests/core/replication-replay-property.spec.js.map +1 -1
- package/dist/esm/tests/core/validation-read-closure.spec.js +111 -0
- package/dist/esm/tests/core/validation-read-closure.spec.js.map +1 -1
- package/dist/esm/tests/core/validation-state-reader.spec.js +89 -0
- package/dist/esm/tests/core/validation-state-reader.spec.js.map +1 -1
- package/dist/esm/tests/features/protocol-composition.spec.js +30 -31
- package/dist/esm/tests/features/protocol-composition.spec.js.map +1 -1
- package/dist/esm/tests/fuzz/encryption.fuzz.spec.js +29 -121
- package/dist/esm/tests/fuzz/encryption.fuzz.spec.js.map +1 -1
- package/dist/esm/tests/handlers/messages-query.spec.js +71 -3
- package/dist/esm/tests/handlers/messages-query.spec.js.map +1 -1
- package/dist/esm/tests/handlers/messages-read.spec.js +2 -2
- package/dist/esm/tests/handlers/messages-read.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-read.spec.js +9 -135
- package/dist/esm/tests/handlers/records-read.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-write.spec.js +279 -19
- package/dist/esm/tests/handlers/records-write.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/protocols-configure.spec.js +17 -22
- package/dist/esm/tests/interfaces/protocols-configure.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/records-write.spec.js +170 -150
- package/dist/esm/tests/interfaces/records-write.spec.js.map +1 -1
- package/dist/esm/tests/protocols/encryption.spec.js +914 -0
- package/dist/esm/tests/protocols/encryption.spec.js.map +1 -0
- package/dist/esm/tests/protocols/permission-grant.spec.js +55 -0
- package/dist/esm/tests/protocols/permission-grant.spec.js.map +1 -1
- package/dist/esm/tests/scenarios/end-to-end-tests.spec.js +100 -100
- package/dist/esm/tests/scenarios/end-to-end-tests.spec.js.map +1 -1
- package/dist/esm/tests/store/message-store-level.spec.js +20 -2
- package/dist/esm/tests/store/message-store-level.spec.js.map +1 -1
- package/dist/esm/tests/utils/encryption-callbacks.spec.js +88 -125
- package/dist/esm/tests/utils/encryption-callbacks.spec.js.map +1 -1
- package/dist/esm/tests/utils/encryption.spec.js +125 -255
- package/dist/esm/tests/utils/encryption.spec.js.map +1 -1
- package/dist/esm/tests/utils/permission-scope.spec.js +5 -1
- package/dist/esm/tests/utils/permission-scope.spec.js.map +1 -1
- package/dist/esm/tests/utils/records.spec.js +15 -5
- package/dist/esm/tests/utils/records.spec.js.map +1 -1
- package/dist/esm/tests/utils/test-data-generator.js +7 -44
- package/dist/esm/tests/utils/test-data-generator.js.map +1 -1
- package/dist/esm/tests/validation/json-schemas/encryption/grant-key.spec.js +63 -0
- package/dist/esm/tests/validation/json-schemas/encryption/grant-key.spec.js.map +1 -0
- package/dist/types/generated/precompiled-validators.d.ts +140 -92
- package/dist/types/generated/precompiled-validators.d.ts.map +1 -1
- package/dist/types/src/core/constants.d.ts +2 -2
- package/dist/types/src/core/constants.d.ts.map +1 -1
- package/dist/types/src/core/core-protocol.d.ts +1 -1
- package/dist/types/src/core/core-protocol.d.ts.map +1 -1
- package/dist/types/src/core/dwn-error.d.ts +29 -1
- package/dist/types/src/core/dwn-error.d.ts.map +1 -1
- package/dist/types/src/core/messages-grant-authorization.d.ts +2 -0
- package/dist/types/src/core/messages-grant-authorization.d.ts.map +1 -1
- package/dist/types/src/core/protocol-authorization-validation.d.ts +2 -2
- package/dist/types/src/core/protocol-authorization-validation.d.ts.map +1 -1
- package/dist/types/src/core/recording-validation-state-reader.d.ts +9 -0
- package/dist/types/src/core/recording-validation-state-reader.d.ts.map +1 -1
- package/dist/types/src/core/replication-apply.d.ts +4 -3
- package/dist/types/src/core/replication-apply.d.ts.map +1 -1
- package/dist/types/src/core/validation-state-reader.d.ts +9 -0
- package/dist/types/src/core/validation-state-reader.d.ts.map +1 -1
- package/dist/types/src/dwn.d.ts +1 -0
- package/dist/types/src/dwn.d.ts.map +1 -1
- package/dist/types/src/handlers/messages-query.d.ts.map +1 -1
- package/dist/types/src/handlers/protocols-configure.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +6 -5
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/interfaces/protocols-configure.d.ts +1 -1
- package/dist/types/src/interfaces/protocols-configure.d.ts.map +1 -1
- package/dist/types/src/interfaces/records-write-signing.d.ts +4 -8
- package/dist/types/src/interfaces/records-write-signing.d.ts.map +1 -1
- package/dist/types/src/interfaces/records-write.d.ts +10 -26
- package/dist/types/src/interfaces/records-write.d.ts.map +1 -1
- package/dist/types/src/protocols/encryption.d.ts +43 -0
- package/dist/types/src/protocols/encryption.d.ts.map +1 -0
- package/dist/types/src/protocols/permission-grant.d.ts +3 -6
- package/dist/types/src/protocols/permission-grant.d.ts.map +1 -1
- package/dist/types/src/protocols/permissions.d.ts +2 -1
- package/dist/types/src/protocols/permissions.d.ts.map +1 -1
- package/dist/types/src/types/encryption-types.d.ts +5 -38
- package/dist/types/src/types/encryption-types.d.ts.map +1 -1
- package/dist/types/src/types/message-types.d.ts +0 -13
- package/dist/types/src/types/message-types.d.ts.map +1 -1
- package/dist/types/src/types/permission-types.d.ts +44 -9
- package/dist/types/src/types/permission-types.d.ts.map +1 -1
- package/dist/types/src/types/protocols-types.d.ts +9 -14
- package/dist/types/src/types/protocols-types.d.ts.map +1 -1
- package/dist/types/src/types/records-types.d.ts +3 -3
- package/dist/types/src/types/records-types.d.ts.map +1 -1
- package/dist/types/src/types/validation-state-reader.d.ts +12 -0
- package/dist/types/src/types/validation-state-reader.d.ts.map +1 -1
- package/dist/types/src/utils/encryption.d.ts +54 -145
- package/dist/types/src/utils/encryption.d.ts.map +1 -1
- package/dist/types/src/utils/hd-key.d.ts +1 -1
- package/dist/types/src/utils/hd-key.d.ts.map +1 -1
- package/dist/types/src/utils/permission-scope.d.ts +4 -3
- package/dist/types/src/utils/permission-scope.d.ts.map +1 -1
- package/dist/types/src/utils/protocols.d.ts +3 -5
- package/dist/types/src/utils/protocols.d.ts.map +1 -1
- package/dist/types/src/utils/records.d.ts +5 -13
- package/dist/types/src/utils/records.d.ts.map +1 -1
- package/dist/types/src/utils/replication.d.ts +3 -0
- package/dist/types/src/utils/replication.d.ts.map +1 -1
- package/dist/types/tests/features/protocol-composition.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/messages-query.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/records-read.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/records-write.spec.d.ts.map +1 -1
- package/dist/types/tests/protocols/encryption.spec.d.ts +2 -0
- package/dist/types/tests/protocols/encryption.spec.d.ts.map +1 -0
- package/dist/types/tests/scenarios/end-to-end-tests.spec.d.ts.map +1 -1
- package/dist/types/tests/utils/test-data-generator.d.ts +0 -5
- package/dist/types/tests/utils/test-data-generator.d.ts.map +1 -1
- package/dist/types/tests/validation/json-schemas/encryption/grant-key.spec.d.ts +2 -0
- package/dist/types/tests/validation/json-schemas/encryption/grant-key.spec.d.ts.map +1 -0
- package/package.json +3 -3
- package/src/core/constants.ts +3 -3
- package/src/core/core-protocol.ts +1 -1
- package/src/core/dwn-error.ts +29 -1
- package/src/core/messages-grant-authorization.ts +27 -0
- package/src/core/protocol-authorization-validation.ts +145 -6
- package/src/core/recording-validation-state-reader.ts +13 -0
- package/src/core/replication-apply.ts +222 -8
- package/src/core/validation-state-reader.ts +30 -0
- package/src/dwn.ts +24 -2
- package/src/handlers/messages-query.ts +6 -5
- package/src/handlers/protocols-configure.ts +19 -3
- package/src/handlers/records-write.ts +1 -1
- package/src/index.ts +15 -5
- package/src/interfaces/protocols-configure.ts +39 -12
- package/src/interfaces/records-write-signing.ts +5 -12
- package/src/interfaces/records-write.ts +75 -92
- package/src/protocols/encryption.ts +649 -0
- package/src/protocols/permission-grant.ts +4 -5
- package/src/protocols/permissions.ts +8 -6
- package/src/types/encryption-types.ts +9 -38
- package/src/types/message-types.ts +0 -13
- package/src/types/permission-types.ts +57 -9
- package/src/types/protocols-types.ts +9 -16
- package/src/types/records-types.ts +3 -3
- package/src/types/validation-state-reader.ts +13 -0
- package/src/utils/encryption.ts +213 -283
- package/src/utils/hd-key.ts +1 -1
- package/src/utils/permission-scope.ts +10 -6
- package/src/utils/protocols.ts +16 -15
- package/src/utils/records.ts +86 -71
- package/src/utils/replication.ts +30 -4
- package/dist/esm/tests/vectors/protocol-definitions/chat.json +0 -70
|
@@ -0,0 +1,649 @@
|
|
|
1
|
+
import type { CoreProtocol } from '../core/core-protocol.js';
|
|
2
|
+
import type { Filter } from '../types/query-types.js';
|
|
3
|
+
import type { GenericSignaturePayload } from '../types/message-types.js';
|
|
4
|
+
import type { MessagesFilter } from '../types/messages-types.js';
|
|
5
|
+
import type { PermissionGrant } from './permission-grant.js';
|
|
6
|
+
import type { PermissionScope } from '../types/permission-types.js';
|
|
7
|
+
import type { PublicKeyJwk } from '../types/jose-types.js';
|
|
8
|
+
import type { RecordsWriteMessage } from '../types/records-types.js';
|
|
9
|
+
import type { ValidationStateReader } from '../types/validation-state-reader.js';
|
|
10
|
+
import type { ProtocolActionRule, ProtocolDefinition, ProtocolRuleSet } from '../types/protocols-types.js';
|
|
11
|
+
|
|
12
|
+
import { checkActor } from '../core/protocol-authorization-action.js';
|
|
13
|
+
import { Encoder } from '../utils/encoder.js';
|
|
14
|
+
import { Encryption } from '../utils/encryption.js';
|
|
15
|
+
import { ENCRYPTION_PROTOCOL_URI } from '../core/constants.js';
|
|
16
|
+
import { FilterUtility } from '../utils/filter.js';
|
|
17
|
+
import { Jws } from '../utils/jws.js';
|
|
18
|
+
import { Message } from '../core/message.js';
|
|
19
|
+
import { Records } from '../utils/records.js';
|
|
20
|
+
import { validateJsonSchema } from '../schema-validator.js';
|
|
21
|
+
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
|
|
22
|
+
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
|
|
23
|
+
import { getRuleSetAtPath, isCrossProtocolRef, parseCrossProtocolRef } from '../utils/protocols.js';
|
|
24
|
+
import { ProtocolAction, ProtocolActor } from '../types/protocols-types.js';
|
|
25
|
+
|
|
26
|
+
type AudienceTags = {
|
|
27
|
+
protocol: string;
|
|
28
|
+
contextId: string;
|
|
29
|
+
role: string;
|
|
30
|
+
epoch: number;
|
|
31
|
+
keyId: string;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
type AudienceEpochData = AudienceTags & {
|
|
35
|
+
publicKeyJwk: PublicKeyJwk;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export class EncryptionProtocol implements CoreProtocol {
|
|
39
|
+
public static readonly uri = ENCRYPTION_PROTOCOL_URI;
|
|
40
|
+
public static readonly audienceEpochPath = 'audienceEpoch';
|
|
41
|
+
public static readonly audienceKeyPath = 'audienceKey';
|
|
42
|
+
public static readonly grantKeyPath = 'grantKey';
|
|
43
|
+
|
|
44
|
+
public static readonly definition: ProtocolDefinition = {
|
|
45
|
+
published : true,
|
|
46
|
+
protocol : EncryptionProtocol.uri,
|
|
47
|
+
types : {
|
|
48
|
+
audienceEpoch: {
|
|
49
|
+
dataFormats : ['application/json'],
|
|
50
|
+
schema : 'https://identity.foundation/dwn/json-schemas/encryption/audience-epoch.json',
|
|
51
|
+
},
|
|
52
|
+
audienceKey: {
|
|
53
|
+
dataFormats : ['application/json'],
|
|
54
|
+
schema : 'https://identity.foundation/dwn/json-schemas/encryption/audience-key.json',
|
|
55
|
+
},
|
|
56
|
+
grantKey: {
|
|
57
|
+
dataFormats : ['application/json'],
|
|
58
|
+
schema : 'https://identity.foundation/dwn/json-schemas/encryption/grant-key.json',
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
structure: {
|
|
62
|
+
audienceEpoch: {
|
|
63
|
+
$actions: [
|
|
64
|
+
{ can: ['create', 'read'], who: 'anyone' },
|
|
65
|
+
],
|
|
66
|
+
$immutable : true,
|
|
67
|
+
$tags : {
|
|
68
|
+
$allowUndefinedTags : false,
|
|
69
|
+
$requiredTags : ['protocol', 'contextId', 'role', 'epoch', 'keyId'],
|
|
70
|
+
contextId : { type: 'string' },
|
|
71
|
+
epoch : { minimum: 1, type: 'integer' },
|
|
72
|
+
keyId : { pattern: '^[A-Za-z0-9_-]{43}$', type: 'string' },
|
|
73
|
+
protocol : { type: 'string' },
|
|
74
|
+
role : { type: 'string' },
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
audienceKey: {
|
|
78
|
+
$actions: [
|
|
79
|
+
{ can: ['create'], who: 'anyone' },
|
|
80
|
+
{ can: ['read'], of: 'audienceKey', who: 'recipient' },
|
|
81
|
+
],
|
|
82
|
+
$immutable : true,
|
|
83
|
+
$tags : {
|
|
84
|
+
$allowUndefinedTags : false,
|
|
85
|
+
$requiredTags : ['protocol', 'contextId', 'role', 'epoch', 'keyId'],
|
|
86
|
+
contextId : { type: 'string' },
|
|
87
|
+
epoch : { minimum: 1, type: 'integer' },
|
|
88
|
+
keyId : { pattern: '^[A-Za-z0-9_-]{43}$', type: 'string' },
|
|
89
|
+
protocol : { type: 'string' },
|
|
90
|
+
role : { type: 'string' },
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
grantKey: {
|
|
94
|
+
$actions: [
|
|
95
|
+
{ can: ['create'], who: 'anyone' },
|
|
96
|
+
{ can: ['read'], of: 'grantKey', who: 'recipient' },
|
|
97
|
+
],
|
|
98
|
+
$immutable : true,
|
|
99
|
+
$tags : {
|
|
100
|
+
$allowUndefinedTags : false,
|
|
101
|
+
$requiredTags : ['grantId', 'protocol', 'keyId'],
|
|
102
|
+
grantId : { type: 'string' },
|
|
103
|
+
keyId : { maxLength: 43, minLength: 43, pattern: '^[A-Za-z0-9_-]{43}$', type: 'string' },
|
|
104
|
+
protocol : { type: 'string' },
|
|
105
|
+
protocolPath : { type: 'string' },
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
public get uri(): string {
|
|
112
|
+
return EncryptionProtocol.uri;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
public get definition(): ProtocolDefinition {
|
|
116
|
+
return EncryptionProtocol.definition;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
public async preProcessWrite(
|
|
120
|
+
tenant: string,
|
|
121
|
+
message: RecordsWriteMessage,
|
|
122
|
+
validationStateReader: ValidationStateReader,
|
|
123
|
+
): Promise<void> {
|
|
124
|
+
switch (message.descriptor.protocolPath) {
|
|
125
|
+
case EncryptionProtocol.audienceEpochPath:
|
|
126
|
+
await EncryptionProtocol.preProcessAudienceEpoch(tenant, message, validationStateReader);
|
|
127
|
+
return;
|
|
128
|
+
case EncryptionProtocol.audienceKeyPath:
|
|
129
|
+
await EncryptionProtocol.preProcessAudienceKey(tenant, message, validationStateReader);
|
|
130
|
+
return;
|
|
131
|
+
case EncryptionProtocol.grantKeyPath:
|
|
132
|
+
await EncryptionProtocol.preProcessGrantKey(tenant, message, validationStateReader);
|
|
133
|
+
return;
|
|
134
|
+
default:
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
public async validateRecord(message: RecordsWriteMessage, dataBytes: Uint8Array): Promise<void> {
|
|
140
|
+
switch (message.descriptor.protocolPath) {
|
|
141
|
+
case EncryptionProtocol.audienceEpochPath:
|
|
142
|
+
await EncryptionProtocol.validateAudienceEpoch(message, dataBytes);
|
|
143
|
+
return;
|
|
144
|
+
case EncryptionProtocol.audienceKeyPath:
|
|
145
|
+
case EncryptionProtocol.grantKeyPath:
|
|
146
|
+
EncryptionProtocol.verifyEncryptedDelivery(message);
|
|
147
|
+
return;
|
|
148
|
+
default:
|
|
149
|
+
throw new DwnError(
|
|
150
|
+
DwnErrorCode.EncryptionProtocolValidateSchemaUnexpectedRecord,
|
|
151
|
+
`Unexpected encryption record: ${message.descriptor.protocolPath}`
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
private static async preProcessAudienceEpoch(
|
|
157
|
+
tenant: string,
|
|
158
|
+
message: RecordsWriteMessage,
|
|
159
|
+
validationStateReader: ValidationStateReader,
|
|
160
|
+
): Promise<void> {
|
|
161
|
+
if (message.encryption !== undefined) {
|
|
162
|
+
throw new DwnError(
|
|
163
|
+
DwnErrorCode.EncryptionProtocolValidateAudienceEpochEncrypted,
|
|
164
|
+
'audienceEpoch records must be plaintext.'
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const tags = EncryptionProtocol.getAudienceTags(message, 'audienceEpoch');
|
|
169
|
+
const { ruleSet, protocolDefinition } = await EncryptionProtocol.verifyRoleAudienceDefinition(tenant, tags, message, validationStateReader);
|
|
170
|
+
await EncryptionProtocol.verifyWriterCanCreateRole({
|
|
171
|
+
tenant,
|
|
172
|
+
message,
|
|
173
|
+
tags,
|
|
174
|
+
ruleSet,
|
|
175
|
+
protocolDefinition,
|
|
176
|
+
validationStateReader,
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
private static async preProcessAudienceKey(
|
|
182
|
+
tenant: string,
|
|
183
|
+
message: RecordsWriteMessage,
|
|
184
|
+
validationStateReader: ValidationStateReader,
|
|
185
|
+
): Promise<void> {
|
|
186
|
+
EncryptionProtocol.verifyEncryptedDelivery(message);
|
|
187
|
+
|
|
188
|
+
const recipient = message.descriptor.recipient;
|
|
189
|
+
if (recipient === undefined) {
|
|
190
|
+
throw new DwnError(
|
|
191
|
+
DwnErrorCode.EncryptionProtocolValidateAudienceKeyRecipientMissing,
|
|
192
|
+
'audienceKey records must have a recipient.'
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const tags = EncryptionProtocol.getAudienceTags(message, 'audienceKey');
|
|
197
|
+
const { ruleSet, protocolDefinition } = await EncryptionProtocol.verifyRoleAudienceDefinition(tenant, tags, message, validationStateReader);
|
|
198
|
+
await EncryptionProtocol.verifyWriterCanCreateRole({
|
|
199
|
+
tenant,
|
|
200
|
+
message,
|
|
201
|
+
tags,
|
|
202
|
+
ruleSet,
|
|
203
|
+
protocolDefinition,
|
|
204
|
+
validationStateReader,
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
const matchingEpochs = await validationStateReader.queryAudienceEpochs({
|
|
208
|
+
tenant,
|
|
209
|
+
protocol : tags.protocol,
|
|
210
|
+
contextId : tags.contextId,
|
|
211
|
+
role : tags.role,
|
|
212
|
+
epoch : tags.epoch,
|
|
213
|
+
keyId : tags.keyId,
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
if (matchingEpochs.length === 0) {
|
|
217
|
+
throw new DwnError(
|
|
218
|
+
DwnErrorCode.EncryptionProtocolValidateAudienceEpochMissing,
|
|
219
|
+
'audienceKey references a missing audienceEpoch.'
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const hasRoleRecord = await validationStateReader.hasMatchingRoleRecord({
|
|
224
|
+
tenant,
|
|
225
|
+
protocol : tags.protocol,
|
|
226
|
+
protocolPath : tags.role,
|
|
227
|
+
recipient,
|
|
228
|
+
contextIdPrefix : tags.contextId === '' ? undefined : tags.contextId,
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
if (!hasRoleRecord) {
|
|
232
|
+
throw new DwnError(
|
|
233
|
+
DwnErrorCode.EncryptionProtocolValidateAudienceKeyRoleRecordMissing,
|
|
234
|
+
'audienceKey recipient is not an active holder of the referenced role.'
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
private static async preProcessGrantKey(
|
|
240
|
+
tenant: string,
|
|
241
|
+
message: RecordsWriteMessage,
|
|
242
|
+
validationStateReader: ValidationStateReader,
|
|
243
|
+
): Promise<void> {
|
|
244
|
+
EncryptionProtocol.verifyEncryptedDelivery(message);
|
|
245
|
+
|
|
246
|
+
const grantId = EncryptionProtocol.getRequiredStringTag(message, 'grantId');
|
|
247
|
+
const protocol = EncryptionProtocol.getRequiredStringTag(message, 'protocol');
|
|
248
|
+
const protocolPath = EncryptionProtocol.getOptionalStringTag(message, 'protocolPath');
|
|
249
|
+
EncryptionProtocol.getRequiredStringTag(message, 'keyId');
|
|
250
|
+
|
|
251
|
+
const grant = await validationStateReader.fetchGrant(tenant, grantId);
|
|
252
|
+
await EncryptionProtocol.verifyGrantActive(tenant, message, grant, validationStateReader);
|
|
253
|
+
EncryptionProtocol.verifyGrantKeyAuthor(message, grant);
|
|
254
|
+
EncryptionProtocol.verifyGrantKeyRecipient(message, grant);
|
|
255
|
+
EncryptionProtocol.verifyGrantKeyScope(grant.scope, protocol, protocolPath);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
private static verifyEncryptedDelivery(message: RecordsWriteMessage): void {
|
|
259
|
+
if (message.encryption === undefined) {
|
|
260
|
+
throw new DwnError(
|
|
261
|
+
DwnErrorCode.EncryptionProtocolValidateEncryptedDeliveryMissingEncryption,
|
|
262
|
+
`${message.descriptor.protocolPath} records must be encrypted.`
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
private static async validateAudienceEpoch(message: RecordsWriteMessage, dataBytes: Uint8Array): Promise<void> {
|
|
268
|
+
if (message.encryption !== undefined) {
|
|
269
|
+
throw new DwnError(
|
|
270
|
+
DwnErrorCode.EncryptionProtocolValidateAudienceEpochEncrypted,
|
|
271
|
+
'audienceEpoch records must be plaintext.'
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const dataObject = JSON.parse(Encoder.bytesToString(dataBytes)) as AudienceEpochData;
|
|
276
|
+
validateJsonSchema('AudienceEpoch', dataObject);
|
|
277
|
+
|
|
278
|
+
const tags = EncryptionProtocol.getAudienceTags(message, 'audienceEpoch');
|
|
279
|
+
EncryptionProtocol.verifyAudiencePayloadMatchesTags(dataObject, tags);
|
|
280
|
+
|
|
281
|
+
const keyId = await Encryption.getKeyId(dataObject.publicKeyJwk);
|
|
282
|
+
if (keyId !== dataObject.keyId) {
|
|
283
|
+
throw new DwnError(
|
|
284
|
+
DwnErrorCode.EncryptionProtocolValidateAudienceEpochKeyIdMismatch,
|
|
285
|
+
'audienceEpoch keyId must match publicKeyJwk thumbprint.'
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
private static verifyAudiencePayloadMatchesTags(payload: AudienceTags, tags: AudienceTags): void {
|
|
291
|
+
if (payload.protocol !== tags.protocol ||
|
|
292
|
+
payload.contextId !== tags.contextId ||
|
|
293
|
+
payload.role !== tags.role ||
|
|
294
|
+
payload.epoch !== tags.epoch ||
|
|
295
|
+
payload.keyId !== tags.keyId) {
|
|
296
|
+
throw new DwnError(
|
|
297
|
+
DwnErrorCode.EncryptionProtocolValidateAudienceTagsMismatch,
|
|
298
|
+
'audienceEpoch tags must match payload fields.'
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
private static getRequiredStringTag(message: RecordsWriteMessage, tag: string, recordType = 'grantKey'): string {
|
|
304
|
+
const value = message.descriptor.tags?.[tag];
|
|
305
|
+
if (typeof value !== 'string') {
|
|
306
|
+
const errorCode = recordType === 'grantKey'
|
|
307
|
+
? DwnErrorCode.EncryptionProtocolValidateGrantKeyMissingRequiredTag
|
|
308
|
+
: DwnErrorCode.EncryptionProtocolValidateAudienceMissingRequiredTag;
|
|
309
|
+
throw new DwnError(
|
|
310
|
+
errorCode,
|
|
311
|
+
`${recordType} records must include string tag '${tag}'.`
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return value;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
private static getRequiredIntegerTag(message: RecordsWriteMessage, tag: string, recordType: string): number {
|
|
319
|
+
const value = message.descriptor.tags?.[tag];
|
|
320
|
+
if (!Number.isInteger(value)) {
|
|
321
|
+
throw new DwnError(
|
|
322
|
+
DwnErrorCode.EncryptionProtocolValidateAudienceMissingRequiredTag,
|
|
323
|
+
`${recordType} records must include integer tag '${tag}'.`
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return value as number;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
private static getAudienceTags(message: RecordsWriteMessage, recordType: string): AudienceTags {
|
|
331
|
+
return {
|
|
332
|
+
protocol : EncryptionProtocol.getRequiredStringTag(message, 'protocol', recordType),
|
|
333
|
+
contextId : EncryptionProtocol.getRequiredStringTag(message, 'contextId', recordType),
|
|
334
|
+
role : EncryptionProtocol.getRequiredStringTag(message, 'role', recordType),
|
|
335
|
+
epoch : EncryptionProtocol.getRequiredIntegerTag(message, 'epoch', recordType),
|
|
336
|
+
keyId : EncryptionProtocol.getRequiredStringTag(message, 'keyId', recordType),
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
private static getOptionalStringTag(message: RecordsWriteMessage, tag: string): string | undefined {
|
|
341
|
+
const value = message.descriptor.tags?.[tag];
|
|
342
|
+
if (value === undefined) {
|
|
343
|
+
return undefined;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (typeof value !== 'string') {
|
|
347
|
+
throw new DwnError(
|
|
348
|
+
DwnErrorCode.EncryptionProtocolValidateGrantKeyMissingRequiredTag,
|
|
349
|
+
`grantKey tag '${tag}' must be a string.`
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
return value;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
private static async verifyGrantActive(
|
|
357
|
+
tenant: string,
|
|
358
|
+
message: RecordsWriteMessage,
|
|
359
|
+
grant: PermissionGrant,
|
|
360
|
+
validationStateReader: ValidationStateReader,
|
|
361
|
+
): Promise<void> {
|
|
362
|
+
const timestamp = message.descriptor.messageTimestamp;
|
|
363
|
+
if (timestamp < grant.dateGranted) {
|
|
364
|
+
throw new DwnError(
|
|
365
|
+
DwnErrorCode.GrantAuthorizationGrantNotYetActive,
|
|
366
|
+
'grantKey references a permission grant that is not active yet.'
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
if (timestamp >= grant.dateExpires) {
|
|
371
|
+
throw new DwnError(
|
|
372
|
+
DwnErrorCode.GrantAuthorizationGrantExpired,
|
|
373
|
+
'grantKey references an expired permission grant.'
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const oldestRevocation = await validationStateReader.fetchOldestGrantRevocation(tenant, grant.id);
|
|
378
|
+
if (oldestRevocation !== undefined && oldestRevocation.descriptor.messageTimestamp <= timestamp) {
|
|
379
|
+
throw new DwnError(
|
|
380
|
+
DwnErrorCode.GrantAuthorizationGrantRevoked,
|
|
381
|
+
`grantKey references revoked permission grant ${grant.id}.`
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
private static verifyGrantKeyAuthor(message: RecordsWriteMessage, grant: PermissionGrant): void {
|
|
387
|
+
if (Message.getAuthor(message) === grant.grantor) {
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
throw new DwnError(
|
|
392
|
+
DwnErrorCode.EncryptionProtocolValidateGrantKeyAuthorMismatch,
|
|
393
|
+
`grantKey author must be permission grantor ${grant.grantor}.`
|
|
394
|
+
);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
private static verifyGrantKeyRecipient(message: RecordsWriteMessage, grant: PermissionGrant): void {
|
|
398
|
+
if (message.descriptor.recipient === grant.grantee) {
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
throw new DwnError(
|
|
403
|
+
DwnErrorCode.EncryptionProtocolValidateGrantKeyRecipientMismatch,
|
|
404
|
+
`grantKey recipient must be permission grantee ${grant.grantee}.`
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
private static verifyGrantKeyScope(grantScope: PermissionScope, protocol: string, protocolPath: string | undefined): void {
|
|
409
|
+
if (!EncryptionProtocol.isReadScope(grantScope)) {
|
|
410
|
+
throw new DwnError(
|
|
411
|
+
DwnErrorCode.EncryptionProtocolValidateGrantKeyGrantScopeMismatch,
|
|
412
|
+
'grantKey must reference a read permission grant.'
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
if ('protocol' in grantScope && grantScope.protocol !== undefined && grantScope.protocol !== protocol) {
|
|
417
|
+
throw new DwnError(
|
|
418
|
+
DwnErrorCode.EncryptionProtocolValidateGrantKeyGrantScopeMismatch,
|
|
419
|
+
`grantKey protocol ${protocol} is outside the permission grant scope.`
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
if (!('protocolPath' in grantScope) || grantScope.protocolPath === undefined) {
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
if (protocolPath === undefined || !EncryptionProtocol.isBoundaryAwareSubtree(grantScope.protocolPath, protocolPath)) {
|
|
428
|
+
throw new DwnError(
|
|
429
|
+
DwnErrorCode.EncryptionProtocolValidateGrantKeyGrantScopeMismatch,
|
|
430
|
+
`grantKey protocolPath ${protocolPath ?? '<protocol>'} is outside the permission grant scope.`
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
private static isReadScope(scope: PermissionScope): boolean {
|
|
436
|
+
return (scope.interface === DwnInterfaceName.Records || scope.interface === DwnInterfaceName.Messages) &&
|
|
437
|
+
scope.method === DwnMethodName.Read;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
private static isBoundaryAwareSubtree(scopePath: string, candidatePath: string): boolean {
|
|
441
|
+
return candidatePath === scopePath || candidatePath.startsWith(scopePath + '/');
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
private static async verifyRoleAudienceDefinition(
|
|
445
|
+
tenant: string,
|
|
446
|
+
tags: AudienceTags,
|
|
447
|
+
message: RecordsWriteMessage,
|
|
448
|
+
validationStateReader: ValidationStateReader,
|
|
449
|
+
): Promise<{ protocolDefinition: ProtocolDefinition; ruleSet: ProtocolRuleSet }> {
|
|
450
|
+
EncryptionProtocol.verifyRoleAudienceContext(tags.role, tags.contextId);
|
|
451
|
+
|
|
452
|
+
const protocolDefinition = await validationStateReader.fetchProtocolDefinition(
|
|
453
|
+
tenant,
|
|
454
|
+
tags.protocol,
|
|
455
|
+
message.descriptor.messageTimestamp,
|
|
456
|
+
);
|
|
457
|
+
const ruleSet = getRuleSetAtPath(tags.role, protocolDefinition.structure);
|
|
458
|
+
|
|
459
|
+
if (ruleSet?.$role !== true || ruleSet.$keyAgreement === undefined) {
|
|
460
|
+
throw new DwnError(
|
|
461
|
+
DwnErrorCode.EncryptionProtocolValidateRoleAudienceInvalid,
|
|
462
|
+
`role audience path '${tags.role}' must be a role path with $keyAgreement.`
|
|
463
|
+
);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
return { protocolDefinition, ruleSet };
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
private static verifyRoleAudienceContext(rolePath: string, contextId: string): void {
|
|
470
|
+
const parentDepth = rolePath.split('/').length - 1;
|
|
471
|
+
if ((parentDepth === 0 && contextId !== '') || (parentDepth > 0 && contextId === '')) {
|
|
472
|
+
throw new DwnError(
|
|
473
|
+
DwnErrorCode.EncryptionProtocolValidateRoleAudienceContextInvalid,
|
|
474
|
+
'role audience contextId is inconsistent with role path depth.'
|
|
475
|
+
);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
private static async verifyWriterCanCreateRole(input: {
|
|
480
|
+
tenant: string;
|
|
481
|
+
message: RecordsWriteMessage;
|
|
482
|
+
tags: AudienceTags;
|
|
483
|
+
ruleSet: ProtocolRuleSet;
|
|
484
|
+
protocolDefinition: ProtocolDefinition;
|
|
485
|
+
validationStateReader: ValidationStateReader;
|
|
486
|
+
}): Promise<void> {
|
|
487
|
+
const author = Message.getAuthor(input.message);
|
|
488
|
+
if (author === input.tenant) {
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
if (author === undefined) {
|
|
493
|
+
throw new DwnError(
|
|
494
|
+
DwnErrorCode.EncryptionProtocolValidateAudienceWriterUnauthorized,
|
|
495
|
+
'audience key records must be authored by a DID authorized to create role records.'
|
|
496
|
+
);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
const actionRules = input.ruleSet.$actions ?? [];
|
|
500
|
+
const recordChain = await EncryptionProtocol.constructRoleParentChain(input.tenant, input.tags, input.validationStateReader);
|
|
501
|
+
const signaturePayload = Jws.decodePlainObjectPayload(input.message.authorization.signature) as GenericSignaturePayload;
|
|
502
|
+
|
|
503
|
+
for (const actionRule of actionRules) {
|
|
504
|
+
if (!actionRule.can.includes(ProtocolAction.Create)) {
|
|
505
|
+
continue;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
if (actionRule.who === ProtocolActor.Anyone) {
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
if (await EncryptionProtocol.roleRuleAllowsAuthor(
|
|
513
|
+
input.tenant,
|
|
514
|
+
author,
|
|
515
|
+
actionRule,
|
|
516
|
+
input.tags,
|
|
517
|
+
input.protocolDefinition,
|
|
518
|
+
input.validationStateReader,
|
|
519
|
+
signaturePayload.protocolRole,
|
|
520
|
+
)) {
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
if (await checkActor(author, actionRule, recordChain, input.protocolDefinition)) {
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
throw new DwnError(
|
|
530
|
+
DwnErrorCode.EncryptionProtocolValidateAudienceWriterUnauthorized,
|
|
531
|
+
'audience key records must be authored by a DID authorized to create role records.'
|
|
532
|
+
);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
private static async constructRoleParentChain(
|
|
536
|
+
tenant: string,
|
|
537
|
+
tags: AudienceTags,
|
|
538
|
+
validationStateReader: ValidationStateReader,
|
|
539
|
+
): Promise<RecordsWriteMessage[]> {
|
|
540
|
+
if (tags.contextId === '') {
|
|
541
|
+
return [];
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
const parentRecordId = tags.contextId.split('/').pop();
|
|
545
|
+
if (parentRecordId === undefined || parentRecordId === '') {
|
|
546
|
+
return [];
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
return validationStateReader.constructRecordChain(tenant, parentRecordId);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
private static async roleRuleAllowsAuthor(
|
|
553
|
+
tenant: string,
|
|
554
|
+
author: string,
|
|
555
|
+
actionRule: ProtocolActionRule,
|
|
556
|
+
tags: AudienceTags,
|
|
557
|
+
protocolDefinition: ProtocolDefinition,
|
|
558
|
+
validationStateReader: ValidationStateReader,
|
|
559
|
+
invokedRole: string | undefined,
|
|
560
|
+
): Promise<boolean> {
|
|
561
|
+
if (actionRule.role === undefined || invokedRole !== actionRule.role) {
|
|
562
|
+
return false;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
const roleRef = actionRule.role;
|
|
566
|
+
return EncryptionProtocol.hasInvokedRole(tenant, author, roleRef, tags, protocolDefinition, validationStateReader);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
private static async hasInvokedRole(
|
|
570
|
+
tenant: string,
|
|
571
|
+
author: string,
|
|
572
|
+
roleRef: string,
|
|
573
|
+
tags: AudienceTags,
|
|
574
|
+
protocolDefinition: ProtocolDefinition,
|
|
575
|
+
validationStateReader: ValidationStateReader,
|
|
576
|
+
): Promise<boolean> {
|
|
577
|
+
const resolved = EncryptionProtocol.resolveRoleReference(roleRef, tags.protocol, protocolDefinition);
|
|
578
|
+
if (resolved === undefined) {
|
|
579
|
+
return false;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
const ancestorDepth = resolved.protocolPath.split('/').length - 1;
|
|
583
|
+
let contextIdPrefix: string | undefined;
|
|
584
|
+
if (ancestorDepth > 0) {
|
|
585
|
+
contextIdPrefix = tags.contextId.split('/').slice(0, ancestorDepth).join('/');
|
|
586
|
+
if (contextIdPrefix === '') {
|
|
587
|
+
return false;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
return validationStateReader.hasMatchingRoleRecord({
|
|
592
|
+
tenant,
|
|
593
|
+
protocol : resolved.protocol,
|
|
594
|
+
protocolPath : resolved.protocolPath,
|
|
595
|
+
recipient : author,
|
|
596
|
+
contextIdPrefix,
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
private static resolveRoleReference(
|
|
601
|
+
roleRef: string,
|
|
602
|
+
currentProtocol: string,
|
|
603
|
+
protocolDefinition: ProtocolDefinition,
|
|
604
|
+
): { protocol: string; protocolPath: string } | undefined {
|
|
605
|
+
if (!isCrossProtocolRef(roleRef)) {
|
|
606
|
+
return { protocol: currentProtocol, protocolPath: roleRef };
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
const parsed = parseCrossProtocolRef(roleRef);
|
|
610
|
+
if (parsed === undefined) {
|
|
611
|
+
return undefined;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
const protocol = protocolDefinition.uses?.[parsed.alias];
|
|
615
|
+
if (protocol === undefined) {
|
|
616
|
+
return undefined;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
return { protocol, protocolPath: parsed.protocolPath };
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
public mapErrorToStatusCode(errorCode: string): number | undefined {
|
|
623
|
+
if (errorCode.startsWith('EncryptionProtocolValidate')) {
|
|
624
|
+
return 400;
|
|
625
|
+
}
|
|
626
|
+
return undefined;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
public constructAdditionalMessageFilter(filter: MessagesFilter): Filter | undefined {
|
|
630
|
+
const { protocol, messageTimestamp } = filter;
|
|
631
|
+
if (protocol === undefined) {
|
|
632
|
+
return undefined;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
const taggedFilter = {
|
|
636
|
+
protocol: EncryptionProtocol.uri,
|
|
637
|
+
...Records.convertTagsFilter({ protocol }),
|
|
638
|
+
} as Filter;
|
|
639
|
+
|
|
640
|
+
if (messageTimestamp !== undefined) {
|
|
641
|
+
const messageTimestampFilter = FilterUtility.convertRangeCriterion(messageTimestamp);
|
|
642
|
+
if (messageTimestampFilter) {
|
|
643
|
+
taggedFilter.messageTimestamp = messageTimestampFilter;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
return taggedFilter;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { DataEncodedRecordsWriteMessage } from '../types/records-types.js';
|
|
2
|
-
import type { PermissionConditions, PermissionGrantData, PermissionScope } from '../types/permission-types.js';
|
|
2
|
+
import type { ConnectSessionMetadata, PermissionConditions, PermissionGrantData, PermissionScope } from '../types/permission-types.js';
|
|
3
3
|
|
|
4
4
|
import { Encoder } from '../utils/encoder.js';
|
|
5
5
|
import { Message } from '../core/message.js';
|
|
@@ -62,9 +62,9 @@ export class PermissionGrant {
|
|
|
62
62
|
public readonly conditions?: PermissionConditions;
|
|
63
63
|
|
|
64
64
|
/**
|
|
65
|
-
* Optional
|
|
65
|
+
* Optional metadata describing the connect approval session that created this grant.
|
|
66
66
|
*/
|
|
67
|
-
public readonly
|
|
67
|
+
public readonly connectSession?: ConnectSessionMetadata;
|
|
68
68
|
|
|
69
69
|
/**
|
|
70
70
|
* Parses a `DataEncodedRecordsWriteMessage` into a `PermissionGrant`.
|
|
@@ -137,7 +137,6 @@ export class PermissionGrant {
|
|
|
137
137
|
this.requestId = permissionGrant.requestId;
|
|
138
138
|
this.scope = permissionGrant.scope;
|
|
139
139
|
this.conditions = permissionGrant.conditions;
|
|
140
|
-
this.
|
|
140
|
+
this.connectSession = permissionGrant.connectSession;
|
|
141
141
|
}
|
|
142
142
|
}
|
|
143
|
-
|