@bcts/xid 1.0.0-alpha.10

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/src/key.ts ADDED
@@ -0,0 +1,431 @@
1
+ /**
2
+ * XID Key
3
+ *
4
+ * Represents a key in an XID document, containing public keys, optional private keys,
5
+ * nickname, endpoints, and permissions.
6
+ *
7
+ * Ported from bc-xid-rust/src/key.rs
8
+ */
9
+
10
+ import { Envelope, PrivateKeyBase, PublicKeyBase, type EnvelopeEncodable } from "@bcts/envelope";
11
+ import { ENDPOINT, NICKNAME, PRIVATE_KEY, SALT, type KnownValue } from "@bcts/known-values";
12
+ import type { EnvelopeEncodableValue } from "@bcts/envelope";
13
+
14
+ // Helper to convert KnownValue to EnvelopeEncodableValue
15
+ const kv = (v: KnownValue): EnvelopeEncodableValue => v as unknown as EnvelopeEncodableValue;
16
+ import { Salt, Reference } from "@bcts/components";
17
+ import { Permissions, type HasPermissions } from "./permissions";
18
+ import { type Privilege } from "./privilege";
19
+ import { type HasNickname } from "./name";
20
+ import { XIDError } from "./error";
21
+
22
+ /**
23
+ * Options for handling private keys in envelopes.
24
+ */
25
+ export enum XIDPrivateKeyOptions {
26
+ /** Omit the private key from the envelope (default). */
27
+ Omit = "Omit",
28
+ /** Include the private key in plaintext (with salt for decorrelation). */
29
+ Include = "Include",
30
+ /** Include the private key assertion but elide it (maintains digest tree). */
31
+ Elide = "Elide",
32
+ /** Include the private key encrypted with a password. */
33
+ Encrypt = "Encrypt",
34
+ }
35
+
36
+ /**
37
+ * Configuration for encrypting private keys.
38
+ */
39
+ export interface XIDPrivateKeyEncryptConfig {
40
+ type: XIDPrivateKeyOptions.Encrypt;
41
+ password: Uint8Array;
42
+ }
43
+
44
+ /**
45
+ * Union type for all private key options.
46
+ */
47
+ export type XIDPrivateKeyOptionsValue =
48
+ | XIDPrivateKeyOptions.Omit
49
+ | XIDPrivateKeyOptions.Include
50
+ | XIDPrivateKeyOptions.Elide
51
+ | XIDPrivateKeyEncryptConfig;
52
+
53
+ /**
54
+ * Private key data that can be either decrypted or encrypted.
55
+ */
56
+ export type PrivateKeyData =
57
+ | { type: "decrypted"; privateKeyBase: PrivateKeyBase }
58
+ | { type: "encrypted"; envelope: Envelope };
59
+
60
+ /**
61
+ * Represents a key in an XID document.
62
+ */
63
+ export class Key implements HasNickname, HasPermissions, EnvelopeEncodable {
64
+ private readonly _publicKeyBase: PublicKeyBase;
65
+ private readonly _privateKeys: { data: PrivateKeyData; salt: Salt } | undefined;
66
+ private _nickname: string;
67
+ private readonly _endpoints: Set<string>;
68
+ private readonly _permissions: Permissions;
69
+
70
+ private constructor(
71
+ publicKeyBase: PublicKeyBase,
72
+ privateKeys?: { data: PrivateKeyData; salt: Salt },
73
+ nickname = "",
74
+ endpoints = new Set<string>(),
75
+ permissions = Permissions.new(),
76
+ ) {
77
+ this._publicKeyBase = publicKeyBase;
78
+ this._privateKeys = privateKeys;
79
+ this._nickname = nickname;
80
+ this._endpoints = endpoints;
81
+ this._permissions = permissions;
82
+ }
83
+
84
+ /**
85
+ * Create a new Key with only public keys.
86
+ */
87
+ static new(publicKeyBase: PublicKeyBase): Key {
88
+ return new Key(publicKeyBase);
89
+ }
90
+
91
+ /**
92
+ * Create a new Key with public keys and allow-all permissions.
93
+ */
94
+ static newAllowAll(publicKeyBase: PublicKeyBase): Key {
95
+ return new Key(publicKeyBase, undefined, "", new Set(), Permissions.newAllowAll());
96
+ }
97
+
98
+ /**
99
+ * Create a new Key with private key base.
100
+ */
101
+ static newWithPrivateKeyBase(privateKeyBase: PrivateKeyBase): Key {
102
+ const salt = Salt.random(32);
103
+ return new Key(
104
+ privateKeyBase.publicKeys(),
105
+ { data: { type: "decrypted", privateKeyBase }, salt },
106
+ "",
107
+ new Set(),
108
+ Permissions.newAllowAll(),
109
+ );
110
+ }
111
+
112
+ /**
113
+ * Get the public key base.
114
+ */
115
+ publicKeyBase(): PublicKeyBase {
116
+ return this._publicKeyBase;
117
+ }
118
+
119
+ /**
120
+ * Get the private key base, if available and decrypted.
121
+ */
122
+ privateKeyBase(): PrivateKeyBase | undefined {
123
+ if (this._privateKeys === undefined) return undefined;
124
+ if (this._privateKeys.data.type === "decrypted") {
125
+ return this._privateKeys.data.privateKeyBase;
126
+ }
127
+ return undefined;
128
+ }
129
+
130
+ /**
131
+ * Check if this key has decrypted private keys.
132
+ */
133
+ hasPrivateKeys(): boolean {
134
+ return this._privateKeys?.data.type === "decrypted";
135
+ }
136
+
137
+ /**
138
+ * Check if this key has encrypted private keys.
139
+ */
140
+ hasEncryptedPrivateKeys(): boolean {
141
+ return this._privateKeys?.data.type === "encrypted";
142
+ }
143
+
144
+ /**
145
+ * Get the salt used for private key decorrelation.
146
+ */
147
+ privateKeySalt(): Salt | undefined {
148
+ return this._privateKeys?.salt;
149
+ }
150
+
151
+ /**
152
+ * Get the reference for this key (based on public key).
153
+ */
154
+ reference(): Reference {
155
+ return Reference.hash(this._publicKeyBase.data());
156
+ }
157
+
158
+ /**
159
+ * Get the endpoints set.
160
+ */
161
+ endpoints(): Set<string> {
162
+ return this._endpoints;
163
+ }
164
+
165
+ /**
166
+ * Get the endpoints set for mutation.
167
+ */
168
+ endpointsMut(): Set<string> {
169
+ return this._endpoints;
170
+ }
171
+
172
+ /**
173
+ * Add an endpoint.
174
+ */
175
+ addEndpoint(endpoint: string): void {
176
+ this._endpoints.add(endpoint);
177
+ }
178
+
179
+ /**
180
+ * Add a permission.
181
+ */
182
+ addPermission(privilege: Privilege): void {
183
+ this._permissions.addAllow(privilege);
184
+ }
185
+
186
+ // HasNickname implementation
187
+ nickname(): string {
188
+ return this._nickname;
189
+ }
190
+
191
+ setNickname(name: string): void {
192
+ this._nickname = name;
193
+ }
194
+
195
+ // HasPermissions implementation
196
+ permissions(): Permissions {
197
+ return this._permissions;
198
+ }
199
+
200
+ permissionsMut(): Permissions {
201
+ return this._permissions;
202
+ }
203
+
204
+ /**
205
+ * Convert to envelope with specified options.
206
+ */
207
+ intoEnvelopeOpt(
208
+ privateKeyOptions: XIDPrivateKeyOptionsValue = XIDPrivateKeyOptions.Omit,
209
+ ): Envelope {
210
+ let envelope = Envelope.new(this._publicKeyBase.data());
211
+
212
+ // Handle private keys
213
+ if (this._privateKeys !== undefined) {
214
+ const { data, salt } = this._privateKeys;
215
+
216
+ if (data.type === "encrypted") {
217
+ // Always preserve encrypted keys
218
+ envelope = envelope.addAssertion(kv(PRIVATE_KEY), data.envelope);
219
+ envelope = envelope.addAssertion(kv(SALT), salt.toData());
220
+ } else if (data.type === "decrypted") {
221
+ // Handle decrypted keys based on options
222
+ const option =
223
+ typeof privateKeyOptions === "object" ? privateKeyOptions.type : privateKeyOptions;
224
+
225
+ switch (option) {
226
+ case XIDPrivateKeyOptions.Include: {
227
+ envelope = envelope.addAssertion(kv(PRIVATE_KEY), data.privateKeyBase.data());
228
+ envelope = envelope.addAssertion(kv(SALT), salt.toData());
229
+ break;
230
+ }
231
+ case XIDPrivateKeyOptions.Elide: {
232
+ const baseAssertion = Envelope.newAssertion(
233
+ kv(PRIVATE_KEY),
234
+ data.privateKeyBase.data(),
235
+ );
236
+ const elidedAssertion = (baseAssertion as unknown as { elide(): Envelope }).elide();
237
+ envelope = envelope.addAssertionEnvelope(elidedAssertion);
238
+ envelope = envelope.addAssertion(kv(SALT), salt.toData());
239
+ break;
240
+ }
241
+ case XIDPrivateKeyOptions.Encrypt: {
242
+ if (typeof privateKeyOptions === "object") {
243
+ const privateKeysEnvelope = Envelope.new(data.privateKeyBase.data());
244
+ const encrypted = (
245
+ privateKeysEnvelope as unknown as { encryptSubject(p: Uint8Array): Envelope }
246
+ ).encryptSubject(privateKeyOptions.password);
247
+ envelope = envelope.addAssertion(kv(PRIVATE_KEY), encrypted);
248
+ envelope = envelope.addAssertion(kv(SALT), salt.toData());
249
+ }
250
+ break;
251
+ }
252
+ case XIDPrivateKeyOptions.Omit:
253
+ default:
254
+ // Do nothing - omit private keys
255
+ break;
256
+ }
257
+ }
258
+ }
259
+
260
+ // Add nickname if not empty
261
+ if (this._nickname !== "") {
262
+ envelope = envelope.addAssertion(kv(NICKNAME), this._nickname);
263
+ }
264
+
265
+ // Add endpoints
266
+ for (const endpoint of this._endpoints) {
267
+ envelope = envelope.addAssertion(kv(ENDPOINT), endpoint);
268
+ }
269
+
270
+ // Add permissions
271
+ envelope = this._permissions.addToEnvelope(envelope);
272
+
273
+ return envelope;
274
+ }
275
+
276
+ // EnvelopeEncodable implementation
277
+ intoEnvelope(): Envelope {
278
+ return this.intoEnvelopeOpt(XIDPrivateKeyOptions.Omit);
279
+ }
280
+
281
+ /**
282
+ * Try to extract a Key from an envelope, optionally with password for decryption.
283
+ */
284
+ static tryFromEnvelope(envelope: Envelope, password?: Uint8Array): Key {
285
+ type EnvelopeExt = Envelope & {
286
+ asByteString(): Uint8Array | undefined;
287
+ subject(): Envelope;
288
+ assertionsWithPredicate(p: unknown): Envelope[];
289
+ decryptSubject(p: Uint8Array): Envelope;
290
+ };
291
+ const env = envelope as EnvelopeExt;
292
+
293
+ // Extract public key base from subject
294
+ // The envelope may be a node (with assertions) or a leaf
295
+ const envCase = env.case();
296
+ const subject = envCase.type === "node" ? env.subject() : env;
297
+ const publicKeyData = (subject as EnvelopeExt).asByteString();
298
+ if (publicKeyData === undefined) {
299
+ throw XIDError.component(new Error("Could not extract public key from envelope"));
300
+ }
301
+ const publicKeyBase = new PublicKeyBase(publicKeyData);
302
+
303
+ // Extract optional private key
304
+ let privateKeys: { data: PrivateKeyData; salt: Salt } | undefined;
305
+
306
+ // Extract salt from top level (if present)
307
+ let salt: Salt = Salt.random(32);
308
+ const saltAssertions = env.assertionsWithPredicate(SALT);
309
+ if (saltAssertions.length > 0) {
310
+ const saltAssertion = saltAssertions[0];
311
+ const saltCase = saltAssertion.case();
312
+ if (saltCase.type === "assertion") {
313
+ const saltObj = saltCase.assertion.object() as EnvelopeExt;
314
+ const saltData = saltObj.asByteString();
315
+ if (saltData !== undefined) {
316
+ salt = Salt.from(saltData);
317
+ }
318
+ }
319
+ }
320
+
321
+ const privateKeyAssertions = env.assertionsWithPredicate(PRIVATE_KEY);
322
+ if (privateKeyAssertions.length > 0) {
323
+ const privateKeyAssertion = privateKeyAssertions[0] as EnvelopeExt;
324
+ const assertionCase = privateKeyAssertion.case();
325
+
326
+ if (assertionCase.type === "assertion") {
327
+ const privateKeyObject = assertionCase.assertion.object() as EnvelopeExt;
328
+
329
+ // Check if encrypted
330
+ const objCase = privateKeyObject.case();
331
+ if (objCase.type === "encrypted") {
332
+ if (password !== undefined) {
333
+ try {
334
+ const decrypted = privateKeyObject.decryptSubject(password) as EnvelopeExt;
335
+ const decryptedData = decrypted.asByteString();
336
+ if (decryptedData !== undefined) {
337
+ const privateKeyBase = PrivateKeyBase.fromBytes(decryptedData, publicKeyData);
338
+ privateKeys = {
339
+ data: { type: "decrypted", privateKeyBase },
340
+ salt,
341
+ };
342
+ }
343
+ } catch {
344
+ // Wrong password - store as encrypted
345
+ privateKeys = {
346
+ data: { type: "encrypted", envelope: privateKeyObject },
347
+ salt,
348
+ };
349
+ }
350
+ } else {
351
+ // No password - store as encrypted
352
+ privateKeys = {
353
+ data: { type: "encrypted", envelope: privateKeyObject },
354
+ salt,
355
+ };
356
+ }
357
+ } else {
358
+ // Plain text private key
359
+ const privateKeyData = privateKeyObject.asByteString();
360
+ if (privateKeyData !== undefined) {
361
+ const privateKeyBase = PrivateKeyBase.fromBytes(privateKeyData, publicKeyData);
362
+ privateKeys = {
363
+ data: { type: "decrypted", privateKeyBase },
364
+ salt,
365
+ };
366
+ }
367
+ }
368
+ }
369
+ }
370
+
371
+ // Extract nickname
372
+ let nickname = "";
373
+ try {
374
+ const nicknameObj = (
375
+ env as unknown as { objectForPredicate(p: unknown): EnvelopeExt }
376
+ ).objectForPredicate(NICKNAME);
377
+ nickname =
378
+ nicknameObj.asByteString() !== undefined
379
+ ? ""
380
+ : ((nicknameObj as unknown as { asText(): string | undefined }).asText() ?? "");
381
+ } catch {
382
+ // No nickname
383
+ }
384
+
385
+ // Extract endpoints
386
+ const endpoints = new Set<string>();
387
+ const endpointObjects = (
388
+ env as unknown as { objectsForPredicate(p: unknown): EnvelopeExt[] }
389
+ ).objectsForPredicate(ENDPOINT);
390
+ for (const obj of endpointObjects) {
391
+ const text = (obj as unknown as { asText(): string | undefined }).asText();
392
+ if (text !== undefined) {
393
+ endpoints.add(text);
394
+ }
395
+ }
396
+
397
+ // Extract permissions
398
+ const permissions = Permissions.tryFromEnvelope(envelope);
399
+
400
+ return new Key(publicKeyBase, privateKeys, nickname, endpoints, permissions);
401
+ }
402
+
403
+ /**
404
+ * Check equality with another Key.
405
+ */
406
+ equals(other: Key): boolean {
407
+ return this._publicKeyBase.hex() === other._publicKeyBase.hex();
408
+ }
409
+
410
+ /**
411
+ * Get a hash key for use in Sets/Maps.
412
+ */
413
+ hashKey(): string {
414
+ return this._publicKeyBase.hex();
415
+ }
416
+
417
+ /**
418
+ * Clone this Key.
419
+ */
420
+ clone(): Key {
421
+ return new Key(
422
+ this._publicKeyBase,
423
+ this._privateKeys !== undefined
424
+ ? { data: this._privateKeys.data, salt: this._privateKeys.salt }
425
+ : undefined,
426
+ this._nickname,
427
+ new Set(this._endpoints),
428
+ this._permissions.clone(),
429
+ );
430
+ }
431
+ }
package/src/name.ts ADDED
@@ -0,0 +1,42 @@
1
+ /**
2
+ * XID Name (Nickname) Interface
3
+ *
4
+ * Provides the HasNickname interface for objects that can have a nickname.
5
+ *
6
+ * Ported from bc-xid-rust/src/name.rs
7
+ */
8
+
9
+ import { XIDError } from "./error";
10
+
11
+ /**
12
+ * Interface for types that have a nickname.
13
+ */
14
+ export interface HasNickname {
15
+ /**
16
+ * Get the nickname for this object.
17
+ */
18
+ nickname(): string;
19
+
20
+ /**
21
+ * Set the nickname for this object.
22
+ */
23
+ setNickname(name: string): void;
24
+ }
25
+
26
+ /**
27
+ * Helper methods for HasNickname implementers.
28
+ */
29
+ export const HasNicknameMixin = {
30
+ /**
31
+ * Add a nickname, throwing if one already exists or is empty.
32
+ */
33
+ addNickname(obj: HasNickname, name: string): void {
34
+ if (obj.nickname() !== "") {
35
+ throw XIDError.duplicate("nickname");
36
+ }
37
+ if (name === "") {
38
+ throw XIDError.emptyValue("nickname");
39
+ }
40
+ obj.setNickname(name);
41
+ },
42
+ };
@@ -0,0 +1,229 @@
1
+ /**
2
+ * XID Permissions
3
+ *
4
+ * Permissions management for XID documents, including allow and deny sets
5
+ * of privileges.
6
+ *
7
+ * Ported from bc-xid-rust/src/permissions.rs
8
+ */
9
+
10
+ import { ALLOW, DENY } from "@bcts/known-values";
11
+ import { Envelope } from "@bcts/envelope";
12
+ import { Privilege, privilegeFromEnvelope, privilegeToKnownValue } from "./privilege";
13
+
14
+ /**
15
+ * Interface for types that have permissions.
16
+ */
17
+ export interface HasPermissions {
18
+ /**
19
+ * Get the permissions for this object.
20
+ */
21
+ permissions(): Permissions;
22
+
23
+ /**
24
+ * Get a mutable reference to the permissions.
25
+ */
26
+ permissionsMut(): Permissions;
27
+ }
28
+
29
+ /**
30
+ * Helper methods for HasPermissions implementers.
31
+ */
32
+ export const HasPermissionsMixin = {
33
+ /**
34
+ * Get the set of allowed privileges.
35
+ */
36
+ allow(obj: HasPermissions): Set<Privilege> {
37
+ return obj.permissions().allow;
38
+ },
39
+
40
+ /**
41
+ * Get the set of denied privileges.
42
+ */
43
+ deny(obj: HasPermissions): Set<Privilege> {
44
+ return obj.permissions().deny;
45
+ },
46
+
47
+ /**
48
+ * Add an allowed privilege.
49
+ */
50
+ addAllow(obj: HasPermissions, privilege: Privilege): void {
51
+ obj.permissionsMut().allow.add(privilege);
52
+ },
53
+
54
+ /**
55
+ * Add a denied privilege.
56
+ */
57
+ addDeny(obj: HasPermissions, privilege: Privilege): void {
58
+ obj.permissionsMut().deny.add(privilege);
59
+ },
60
+
61
+ /**
62
+ * Remove an allowed privilege.
63
+ */
64
+ removeAllow(obj: HasPermissions, privilege: Privilege): void {
65
+ obj.permissionsMut().allow.delete(privilege);
66
+ },
67
+
68
+ /**
69
+ * Remove a denied privilege.
70
+ */
71
+ removeDeny(obj: HasPermissions, privilege: Privilege): void {
72
+ obj.permissionsMut().deny.delete(privilege);
73
+ },
74
+
75
+ /**
76
+ * Clear all permissions.
77
+ */
78
+ clearAllPermissions(obj: HasPermissions): void {
79
+ obj.permissionsMut().allow.clear();
80
+ obj.permissionsMut().deny.clear();
81
+ },
82
+ };
83
+
84
+ /**
85
+ * Represents the permissions granted to a key or delegate.
86
+ */
87
+ export class Permissions implements HasPermissions {
88
+ public allow: Set<Privilege>;
89
+ public deny: Set<Privilege>;
90
+
91
+ constructor(allow?: Set<Privilege>, deny?: Set<Privilege>) {
92
+ this.allow = allow ?? new Set();
93
+ this.deny = deny ?? new Set();
94
+ }
95
+
96
+ /**
97
+ * Create a new empty Permissions object.
98
+ */
99
+ static new(): Permissions {
100
+ return new Permissions();
101
+ }
102
+
103
+ /**
104
+ * Create a new Permissions object that allows all privileges.
105
+ */
106
+ static newAllowAll(): Permissions {
107
+ const allow = new Set<Privilege>();
108
+ allow.add(Privilege.All);
109
+ return new Permissions(allow);
110
+ }
111
+
112
+ /**
113
+ * Add permissions assertions to an envelope.
114
+ */
115
+ addToEnvelope(envelope: Envelope): Envelope {
116
+ let result = envelope;
117
+
118
+ // Add allow assertions
119
+ for (const privilege of this.allow) {
120
+ result = result.addAssertion(
121
+ Envelope.newWithKnownValue(ALLOW.value()),
122
+ Envelope.newWithKnownValue(privilegeToKnownValue(privilege).value()),
123
+ );
124
+ }
125
+
126
+ // Add deny assertions
127
+ for (const privilege of this.deny) {
128
+ result = result.addAssertion(
129
+ Envelope.newWithKnownValue(DENY.value()),
130
+ Envelope.newWithKnownValue(privilegeToKnownValue(privilege).value()),
131
+ );
132
+ }
133
+
134
+ return result;
135
+ }
136
+
137
+ /**
138
+ * Try to extract Permissions from an envelope.
139
+ */
140
+ static tryFromEnvelope(envelope: Envelope): Permissions {
141
+ const allow = new Set<Privilege>();
142
+ const deny = new Set<Privilege>();
143
+
144
+ // Extract allow assertions
145
+ const allowObjects = (
146
+ envelope as unknown as { objectsForPredicate(p: unknown): Envelope[] }
147
+ ).objectsForPredicate(ALLOW);
148
+ for (const obj of allowObjects) {
149
+ const privilege = privilegeFromEnvelope(obj);
150
+ allow.add(privilege);
151
+ }
152
+
153
+ // Extract deny assertions
154
+ const denyObjects = (
155
+ envelope as unknown as { objectsForPredicate(p: unknown): Envelope[] }
156
+ ).objectsForPredicate(DENY);
157
+ for (const obj of denyObjects) {
158
+ const privilege = privilegeFromEnvelope(obj);
159
+ deny.add(privilege);
160
+ }
161
+
162
+ return new Permissions(allow, deny);
163
+ }
164
+
165
+ /**
166
+ * Add an allowed privilege.
167
+ */
168
+ addAllow(privilege: Privilege): void {
169
+ this.allow.add(privilege);
170
+ }
171
+
172
+ /**
173
+ * Add a denied privilege.
174
+ */
175
+ addDeny(privilege: Privilege): void {
176
+ this.deny.add(privilege);
177
+ }
178
+
179
+ /**
180
+ * Check if a specific privilege is allowed.
181
+ */
182
+ isAllowed(privilege: Privilege): boolean {
183
+ // Deny takes precedence
184
+ if (this.deny.has(privilege) || this.deny.has(Privilege.All)) {
185
+ return false;
186
+ }
187
+ // Check if specifically allowed or all is allowed
188
+ return this.allow.has(privilege) || this.allow.has(Privilege.All);
189
+ }
190
+
191
+ /**
192
+ * Check if a specific privilege is denied.
193
+ */
194
+ isDenied(privilege: Privilege): boolean {
195
+ return this.deny.has(privilege) || this.deny.has(Privilege.All);
196
+ }
197
+
198
+ // HasPermissions implementation
199
+ permissions(): Permissions {
200
+ return this;
201
+ }
202
+
203
+ permissionsMut(): Permissions {
204
+ return this;
205
+ }
206
+
207
+ /**
208
+ * Check equality with another Permissions object.
209
+ */
210
+ equals(other: Permissions): boolean {
211
+ if (this.allow.size !== other.allow.size || this.deny.size !== other.deny.size) {
212
+ return false;
213
+ }
214
+ for (const p of this.allow) {
215
+ if (!other.allow.has(p)) return false;
216
+ }
217
+ for (const p of this.deny) {
218
+ if (!other.deny.has(p)) return false;
219
+ }
220
+ return true;
221
+ }
222
+
223
+ /**
224
+ * Clone this Permissions object.
225
+ */
226
+ clone(): Permissions {
227
+ return new Permissions(new Set(this.allow), new Set(this.deny));
228
+ }
229
+ }