@peerbit/identity-access-controller 1.0.2
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/LICENSE +22 -0
- package/README.md +11 -0
- package/lib/esm/access.d.ts +20 -0
- package/lib/esm/access.js +74 -0
- package/lib/esm/access.js.map +1 -0
- package/lib/esm/acl-db.d.ts +23 -0
- package/lib/esm/acl-db.js +150 -0
- package/lib/esm/acl-db.js.map +1 -0
- package/lib/esm/condition.d.ts +20 -0
- package/lib/esm/condition.js +113 -0
- package/lib/esm/condition.js.map +1 -0
- package/lib/esm/index.d.ts +3 -0
- package/lib/esm/index.js +4 -0
- package/lib/esm/index.js.map +1 -0
- package/lib/esm/package.json +3 -0
- package/package.json +43 -0
- package/src/access.ts +61 -0
- package/src/acl-db.ts +178 -0
- package/src/condition.ts +96 -0
- package/src/index.ts +3 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021 dao.xyz
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# "Chain agnostic" Access Controller
|
|
2
|
+
## 🚧 Experimental state 🚧
|
|
3
|
+
|
|
4
|
+
An access controller that supports different layers of controll and fallbacks.
|
|
5
|
+
|
|
6
|
+
- A store containing ACL information, for example what public key can read and write
|
|
7
|
+
- A distributed relation store that lets you use linked devices to get access
|
|
8
|
+
- A fallback trusted network access controller that lets you have access if you are trusted by the root trust identity
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
As of know, go through the test for documentation
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { AccessCondition } from "./condition";
|
|
2
|
+
export declare enum AccessType {
|
|
3
|
+
Any = 0,
|
|
4
|
+
Read = 1,
|
|
5
|
+
Write = 2
|
|
6
|
+
}
|
|
7
|
+
export declare class AccessData {
|
|
8
|
+
}
|
|
9
|
+
export declare class Access extends AccessData {
|
|
10
|
+
id: string;
|
|
11
|
+
accessTypes: AccessType[];
|
|
12
|
+
accessCondition: AccessCondition<any>;
|
|
13
|
+
constructor(options?: {
|
|
14
|
+
accessTypes: AccessType[];
|
|
15
|
+
accessCondition: AccessCondition<any>;
|
|
16
|
+
});
|
|
17
|
+
calculateId(): string;
|
|
18
|
+
initialize(): Access;
|
|
19
|
+
assertId(): void;
|
|
20
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
var Access_1;
|
|
11
|
+
import { field, option, variant, vec } from "@dao-xyz/borsh";
|
|
12
|
+
import { serialize } from "@dao-xyz/borsh";
|
|
13
|
+
import { AccessCondition } from "./condition";
|
|
14
|
+
import { toBase64 } from "@peerbit/crypto";
|
|
15
|
+
export var AccessType;
|
|
16
|
+
(function (AccessType) {
|
|
17
|
+
AccessType[AccessType["Any"] = 0] = "Any";
|
|
18
|
+
AccessType[AccessType["Read"] = 1] = "Read";
|
|
19
|
+
AccessType[AccessType["Write"] = 2] = "Write";
|
|
20
|
+
})(AccessType || (AccessType = {}));
|
|
21
|
+
export let AccessData = class AccessData {
|
|
22
|
+
};
|
|
23
|
+
AccessData = __decorate([
|
|
24
|
+
variant(0)
|
|
25
|
+
], AccessData);
|
|
26
|
+
export let Access = Access_1 = class Access extends AccessData {
|
|
27
|
+
id;
|
|
28
|
+
accessTypes;
|
|
29
|
+
accessCondition;
|
|
30
|
+
constructor(options) {
|
|
31
|
+
super();
|
|
32
|
+
if (options) {
|
|
33
|
+
this.accessTypes = options.accessTypes;
|
|
34
|
+
this.accessCondition = options.accessCondition;
|
|
35
|
+
this.initialize();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
calculateId() {
|
|
39
|
+
if (!this.accessTypes || !this.accessCondition) {
|
|
40
|
+
throw new Error("Not initialized");
|
|
41
|
+
}
|
|
42
|
+
const a = new Access_1();
|
|
43
|
+
a.accessCondition = this.accessCondition;
|
|
44
|
+
a.accessTypes = this.accessTypes;
|
|
45
|
+
return toBase64(serialize(a));
|
|
46
|
+
}
|
|
47
|
+
initialize() {
|
|
48
|
+
this.id = this.calculateId();
|
|
49
|
+
return this;
|
|
50
|
+
}
|
|
51
|
+
assertId() {
|
|
52
|
+
const calculatedId = this.calculateId();
|
|
53
|
+
if (this.id !== calculatedId) {
|
|
54
|
+
throw new Error(`Invalid id, got ${this.id} but expected ${calculatedId}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
__decorate([
|
|
59
|
+
field({ type: option("string") }),
|
|
60
|
+
__metadata("design:type", String)
|
|
61
|
+
], Access.prototype, "id", void 0);
|
|
62
|
+
__decorate([
|
|
63
|
+
field({ type: vec("u8") }),
|
|
64
|
+
__metadata("design:type", Array)
|
|
65
|
+
], Access.prototype, "accessTypes", void 0);
|
|
66
|
+
__decorate([
|
|
67
|
+
field({ type: AccessCondition }),
|
|
68
|
+
__metadata("design:type", AccessCondition)
|
|
69
|
+
], Access.prototype, "accessCondition", void 0);
|
|
70
|
+
Access = Access_1 = __decorate([
|
|
71
|
+
variant(0),
|
|
72
|
+
__metadata("design:paramtypes", [Object])
|
|
73
|
+
], Access);
|
|
74
|
+
//# sourceMappingURL=access.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"access.js","sourceRoot":"","sources":["../../src/access.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE3C,MAAM,CAAN,IAAY,UAIX;AAJD,WAAY,UAAU;IACrB,yCAAO,CAAA;IACP,2CAAQ,CAAA;IACR,6CAAS,CAAA;AACV,CAAC,EAJW,UAAU,KAAV,UAAU,QAIrB;AAGM,WAAM,UAAU,GAAhB,MAAM,UAAU;CAAG,CAAA;AAAb,UAAU;IADtB,OAAO,CAAC,CAAC,CAAC;GACE,UAAU,CAAG;AAGnB,WAAM,MAAM,cAAZ,MAAM,MAAO,SAAQ,UAAU;IAErC,EAAE,CAAS;IAGX,WAAW,CAAe;IAG1B,eAAe,CAAuB;IAEtC,YAAY,OAGX;QACA,KAAK,EAAE,CAAC;QACR,IAAI,OAAO,EAAE;YACZ,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;YACvC,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC;YAC/C,IAAI,CAAC,UAAU,EAAE,CAAC;SAClB;IACF,CAAC;IAED,WAAW;QACV,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE;YAC/C,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;SACnC;QACD,MAAM,CAAC,GAAG,IAAI,QAAM,EAAE,CAAC;QACvB,CAAC,CAAC,eAAe,GAAG,IAAI,CAAC,eAAe,CAAC;QACzC,CAAC,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;QACjC,OAAO,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/B,CAAC;IAED,UAAU;QACT,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC;IACb,CAAC;IAED,QAAQ;QACP,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACxC,IAAI,IAAI,CAAC,EAAE,KAAK,YAAY,EAAE;YAC7B,MAAM,IAAI,KAAK,CACd,mBAAmB,IAAI,CAAC,EAAE,iBAAiB,YAAY,EAAE,CACzD,CAAC;SACF;IACF,CAAC;CACD,CAAA;AA3CA;IADC,KAAK,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;;kCACvB;AAGX;IADC,KAAK,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;;2CACD;AAG1B;IADC,KAAK,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC;8BAChB,eAAe;+CAAM;AAR1B,MAAM;IADlB,OAAO,CAAC,CAAC,CAAC;;GACE,MAAM,CA6ClB"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Documents } from "@peerbit/document";
|
|
2
|
+
import { TrustedNetwork, IdentityGraph } from "@peerbit/trusted-network";
|
|
3
|
+
import { Access } from "./access";
|
|
4
|
+
import { Entry } from "@peerbit/log";
|
|
5
|
+
import { PublicSignKey } from "@peerbit/crypto";
|
|
6
|
+
import { Program } from "@peerbit/program";
|
|
7
|
+
import { PeerId } from "@libp2p/interface-peer-id";
|
|
8
|
+
import { SubscriptionType } from "@peerbit/shared-log";
|
|
9
|
+
export declare class IdentityAccessController extends Program {
|
|
10
|
+
access: Documents<Access>;
|
|
11
|
+
identityGraphController: IdentityGraph;
|
|
12
|
+
trustedNetwork: TrustedNetwork;
|
|
13
|
+
constructor(opts: {
|
|
14
|
+
id?: Uint8Array;
|
|
15
|
+
rootTrust: PublicSignKey | PeerId;
|
|
16
|
+
trustedNetwork?: TrustedNetwork;
|
|
17
|
+
});
|
|
18
|
+
canRead(s: PublicSignKey | undefined): Promise<boolean>;
|
|
19
|
+
canAppend(entry: Entry<any>): Promise<boolean>;
|
|
20
|
+
open(properties?: {
|
|
21
|
+
role?: SubscriptionType;
|
|
22
|
+
}): Promise<void>;
|
|
23
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
import { field, variant } from "@dao-xyz/borsh";
|
|
11
|
+
import { Documents, DocumentIndex } from "@peerbit/document";
|
|
12
|
+
import { getPathGenerator, TrustedNetwork, getFromByTo, IdentityGraph, createIdentityGraphStore, } from "@peerbit/trusted-network";
|
|
13
|
+
import { Access, AccessType } from "./access";
|
|
14
|
+
import { sha256Sync } from "@peerbit/crypto";
|
|
15
|
+
import { Program } from "@peerbit/program";
|
|
16
|
+
import { RPC } from "@peerbit/rpc";
|
|
17
|
+
import { concat } from "uint8arrays";
|
|
18
|
+
export let IdentityAccessController = class IdentityAccessController extends Program {
|
|
19
|
+
access;
|
|
20
|
+
identityGraphController;
|
|
21
|
+
trustedNetwork;
|
|
22
|
+
constructor(opts) {
|
|
23
|
+
super();
|
|
24
|
+
if (!opts.trustedNetwork && !opts.rootTrust) {
|
|
25
|
+
throw new Error("Expecting either TrustedNetwork or rootTrust");
|
|
26
|
+
}
|
|
27
|
+
this.access = new Documents({
|
|
28
|
+
id: opts.id && sha256Sync(concat([opts.id, new Uint8Array([0])])),
|
|
29
|
+
index: new DocumentIndex({
|
|
30
|
+
query: new RPC(),
|
|
31
|
+
}),
|
|
32
|
+
});
|
|
33
|
+
this.trustedNetwork = opts.trustedNetwork
|
|
34
|
+
? opts.trustedNetwork
|
|
35
|
+
: new TrustedNetwork({
|
|
36
|
+
id: opts.id && sha256Sync(concat([opts.id, new Uint8Array([1])])),
|
|
37
|
+
rootTrust: opts.rootTrust,
|
|
38
|
+
});
|
|
39
|
+
this.identityGraphController = new IdentityGraph({
|
|
40
|
+
relationGraph: createIdentityGraphStore(opts.id && sha256Sync(concat([opts.id, new Uint8Array([2])]))),
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
// allow anyone write to the ACL db, but assume entry is invalid until a verifier verifies
|
|
44
|
+
// can append will be anyone who has peformed some proof of work
|
|
45
|
+
// or
|
|
46
|
+
// custom can append
|
|
47
|
+
async canRead(s) {
|
|
48
|
+
// TODO, improve, caching etc
|
|
49
|
+
if (!s) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
// Check whether it is trusted by trust web
|
|
53
|
+
if (await this.trustedNetwork.isTrusted(s)) {
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
// Else check whether its trusted by this access controller
|
|
57
|
+
const canReadCheck = async (key) => {
|
|
58
|
+
for (const value of this.access.index.index.values()) {
|
|
59
|
+
const access = value.value;
|
|
60
|
+
if (access instanceof Access) {
|
|
61
|
+
if (access.accessTypes.find((x) => x === AccessType.Any || x === AccessType.Read) !== undefined) {
|
|
62
|
+
// check condition
|
|
63
|
+
if (await access.accessCondition.allowed(key)) {
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
if (await canReadCheck(s)) {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
for await (const trustedByKey of getPathGenerator(s, this.identityGraphController.relationGraph, getFromByTo)) {
|
|
75
|
+
if (await canReadCheck(trustedByKey.from)) {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
async canAppend(entry) {
|
|
82
|
+
// TODO, improve, caching etc
|
|
83
|
+
// Check whether it is trusted by trust web
|
|
84
|
+
const canAppendByKey = async (key) => {
|
|
85
|
+
if (await this.trustedNetwork.isTrusted(key)) {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
// Else check whether its trusted by this access controller
|
|
89
|
+
const canWriteCheck = async (key) => {
|
|
90
|
+
for (const value of this.access.index.index.values()) {
|
|
91
|
+
const access = value.value;
|
|
92
|
+
if (access instanceof Access) {
|
|
93
|
+
if (access.accessTypes.find((x) => x === AccessType.Any || x === AccessType.Write) !== undefined) {
|
|
94
|
+
// check condition
|
|
95
|
+
if (await access.accessCondition.allowed(key)) {
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
if (await canWriteCheck(key)) {
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
for await (const trustedByKey of getPathGenerator(key, this.identityGraphController.relationGraph, getFromByTo)) {
|
|
107
|
+
if (await canWriteCheck(trustedByKey.from)) {
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return false;
|
|
112
|
+
};
|
|
113
|
+
for (const key of await entry.getPublicKeys()) {
|
|
114
|
+
if (await canAppendByKey(key)) {
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
async open(properties) {
|
|
121
|
+
await this.identityGraphController.open({
|
|
122
|
+
role: properties?.role,
|
|
123
|
+
canRead: this.canRead.bind(this),
|
|
124
|
+
});
|
|
125
|
+
await this.access.open({
|
|
126
|
+
role: properties?.role,
|
|
127
|
+
type: Access,
|
|
128
|
+
canAppend: this.canAppend.bind(this),
|
|
129
|
+
canRead: this.canRead.bind(this),
|
|
130
|
+
});
|
|
131
|
+
await this.trustedNetwork.open(properties);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
__decorate([
|
|
135
|
+
field({ type: Documents }),
|
|
136
|
+
__metadata("design:type", Documents)
|
|
137
|
+
], IdentityAccessController.prototype, "access", void 0);
|
|
138
|
+
__decorate([
|
|
139
|
+
field({ type: IdentityGraph }),
|
|
140
|
+
__metadata("design:type", IdentityGraph)
|
|
141
|
+
], IdentityAccessController.prototype, "identityGraphController", void 0);
|
|
142
|
+
__decorate([
|
|
143
|
+
field({ type: TrustedNetwork }),
|
|
144
|
+
__metadata("design:type", TrustedNetwork)
|
|
145
|
+
], IdentityAccessController.prototype, "trustedNetwork", void 0);
|
|
146
|
+
IdentityAccessController = __decorate([
|
|
147
|
+
variant("identity_acl"),
|
|
148
|
+
__metadata("design:paramtypes", [Object])
|
|
149
|
+
], IdentityAccessController);
|
|
150
|
+
//# sourceMappingURL=acl-db.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acl-db.js","sourceRoot":"","sources":["../../src/acl-db.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { PublicSignKey } from "@peerbit/crypto";
|
|
2
|
+
import { PeerId } from "@libp2p/interface-peer-id";
|
|
3
|
+
export declare class Network {
|
|
4
|
+
type: string;
|
|
5
|
+
rpc: string;
|
|
6
|
+
}
|
|
7
|
+
export declare class AccessCondition<T> {
|
|
8
|
+
allowed(_key: PublicSignKey): Promise<boolean>;
|
|
9
|
+
}
|
|
10
|
+
export declare class AnyAccessCondition<T> extends AccessCondition<T> {
|
|
11
|
+
constructor();
|
|
12
|
+
allowed(_key: PublicSignKey): Promise<boolean>;
|
|
13
|
+
}
|
|
14
|
+
export declare class PublicKeyAccessCondition<T> extends AccessCondition<T> {
|
|
15
|
+
key: PublicSignKey;
|
|
16
|
+
constructor(options: {
|
|
17
|
+
key: PublicSignKey | PeerId;
|
|
18
|
+
});
|
|
19
|
+
allowed(identity: PublicSignKey): Promise<boolean>;
|
|
20
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
import { field, variant } from "@dao-xyz/borsh";
|
|
11
|
+
import { PublicSignKey, getPublicKeyFromPeerId } from "@peerbit/crypto";
|
|
12
|
+
const coercePublicKey = (publicKey) => {
|
|
13
|
+
return publicKey instanceof PublicSignKey
|
|
14
|
+
? publicKey
|
|
15
|
+
: getPublicKeyFromPeerId(publicKey);
|
|
16
|
+
};
|
|
17
|
+
export let Network = class Network {
|
|
18
|
+
type;
|
|
19
|
+
rpc;
|
|
20
|
+
};
|
|
21
|
+
__decorate([
|
|
22
|
+
field({ type: "string" }),
|
|
23
|
+
__metadata("design:type", String)
|
|
24
|
+
], Network.prototype, "type", void 0);
|
|
25
|
+
__decorate([
|
|
26
|
+
field({ type: "string" }),
|
|
27
|
+
__metadata("design:type", String)
|
|
28
|
+
], Network.prototype, "rpc", void 0);
|
|
29
|
+
Network = __decorate([
|
|
30
|
+
variant(0)
|
|
31
|
+
], Network);
|
|
32
|
+
export class AccessCondition {
|
|
33
|
+
async allowed(_key) {
|
|
34
|
+
throw new Error("Not implemented");
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export let AnyAccessCondition = class AnyAccessCondition extends AccessCondition {
|
|
38
|
+
constructor() {
|
|
39
|
+
super();
|
|
40
|
+
}
|
|
41
|
+
async allowed(_key) {
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
AnyAccessCondition = __decorate([
|
|
46
|
+
variant([0, 0]),
|
|
47
|
+
__metadata("design:paramtypes", [])
|
|
48
|
+
], AnyAccessCondition);
|
|
49
|
+
export let PublicKeyAccessCondition = class PublicKeyAccessCondition extends AccessCondition {
|
|
50
|
+
key;
|
|
51
|
+
constructor(options) {
|
|
52
|
+
super();
|
|
53
|
+
this.key = coercePublicKey(options.key);
|
|
54
|
+
}
|
|
55
|
+
async allowed(identity) {
|
|
56
|
+
return this.key.equals(identity);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
__decorate([
|
|
60
|
+
field({ type: PublicSignKey }),
|
|
61
|
+
__metadata("design:type", PublicSignKey)
|
|
62
|
+
], PublicKeyAccessCondition.prototype, "key", void 0);
|
|
63
|
+
PublicKeyAccessCondition = __decorate([
|
|
64
|
+
variant([0, 1]),
|
|
65
|
+
__metadata("design:paramtypes", [Object])
|
|
66
|
+
], PublicKeyAccessCondition);
|
|
67
|
+
/* Not yet :)
|
|
68
|
+
|
|
69
|
+
@variant([0, 2])
|
|
70
|
+
export class TokenAccessCondition extends AccessCondition {
|
|
71
|
+
|
|
72
|
+
@field({ type: Network })
|
|
73
|
+
network: Network
|
|
74
|
+
|
|
75
|
+
@field({ type: 'string' })
|
|
76
|
+
token: string
|
|
77
|
+
|
|
78
|
+
@field({ type: 'u64' })
|
|
79
|
+
amount: bigint
|
|
80
|
+
|
|
81
|
+
constructor() {
|
|
82
|
+
super();
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@variant(0)
|
|
88
|
+
export class NFTPropertyCondition {
|
|
89
|
+
@field({ type: 'string' })
|
|
90
|
+
field: string
|
|
91
|
+
|
|
92
|
+
@field({ type: 'string' })
|
|
93
|
+
value: string;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
@variant([0, 3]) // distinguish between ERC-721, ERC-1155, Solana Metaplex?
|
|
97
|
+
export class NFTAccessCondition extends AccessCondition {
|
|
98
|
+
|
|
99
|
+
@field({ type: Network })
|
|
100
|
+
network: Network
|
|
101
|
+
|
|
102
|
+
@field({ type: 'string' })
|
|
103
|
+
id: string
|
|
104
|
+
|
|
105
|
+
@field({ type: option(vec(NFTPropertyCondition)) })
|
|
106
|
+
properties: NFTPropertyCondition
|
|
107
|
+
|
|
108
|
+
constructor() {
|
|
109
|
+
super();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
*/
|
|
113
|
+
//# sourceMappingURL=condition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"condition.js","sourceRoot":"","sources":["../../src/condition.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAGxE,MAAM,eAAe,GAAG,CAAC,SAAiC,EAAE,EAAE;IAC7D,OAAO,SAAS,YAAY,aAAa;QACxC,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,sBAAsB,CAAC,SAAS,CAAC,CAAC;AACtC,CAAC,CAAC;AAGK,WAAM,OAAO,GAAb,MAAM,OAAO;IAEnB,IAAI,CAAS;IAGb,GAAG,CAAS;CACZ,CAAA;AAJA;IADC,KAAK,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;;qCACb;AAGb;IADC,KAAK,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;;oCACd;AALA,OAAO;IADnB,OAAO,CAAC,CAAC,CAAC;GACE,OAAO,CAMnB;AAED,MAAM,OAAO,eAAe;IAC3B,KAAK,CAAC,OAAO,CAAC,IAAmB;QAChC,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACpC,CAAC;CACD;AAGM,WAAM,kBAAkB,GAAxB,MAAM,kBAAsB,SAAQ,eAAkB;IAC5D;QACC,KAAK,EAAE,CAAC;IACT,CAAC;IACD,KAAK,CAAC,OAAO,CAAC,IAAmB;QAChC,OAAO,IAAI,CAAC;IACb,CAAC;CACD,CAAA;AAPY,kBAAkB;IAD9B,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;;GACH,kBAAkB,CAO9B;AAGM,WAAM,wBAAwB,GAA9B,MAAM,wBAA4B,SAAQ,eAAkB;IAElE,GAAG,CAAgB;IAEnB,YAAY,OAAwC;QACnD,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,GAAG,GAAG,eAAe,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,QAAuB;QACpC,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAClC,CAAC;CACD,CAAA;AAVA;IADC,KAAK,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;8BAC1B,aAAa;qDAAC;AAFP,wBAAwB;IADpC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;;GACH,wBAAwB,CAYpC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG"}
|
package/lib/esm/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@peerbit/identity-access-controller",
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "Access controller that operates on a DB",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"module": "lib/esm/index.js",
|
|
8
|
+
"types": "lib/esm/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
"import": "./lib/esm/index.js",
|
|
11
|
+
"require": "./lib/cjs/index.js"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"lib",
|
|
15
|
+
"src",
|
|
16
|
+
"!src/**/__tests__",
|
|
17
|
+
"!lib/**/__tests__",
|
|
18
|
+
"LICENSE"
|
|
19
|
+
],
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"clean": "shx rm -rf lib/*",
|
|
25
|
+
"build": "yarn clean && tsc -p tsconfig.json",
|
|
26
|
+
"postbuild": "echo '{\"type\":\"module\"} ' | node ../../../../node_modules/.bin/json > lib/esm/package.json",
|
|
27
|
+
"test": "node ../../../../node_modules/.bin/jest test -c ../../../../jest.config.ts --runInBand --forceExit",
|
|
28
|
+
"test:unit": "node ../../../../node_modules/.bin/jest test -c ../../../../jest.config.unit.ts --runInBand --forceExit",
|
|
29
|
+
"test:integration": "node ../node_modules/.bin/jest test -c ../../../../jest.config.integration.ts --runInBand --forceExit"
|
|
30
|
+
},
|
|
31
|
+
"author": "dao.xyz",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@dao-xyz/borsh": "^5.1.5",
|
|
35
|
+
"@peerbit/document": "1.0.2",
|
|
36
|
+
"@peerbit/trusted-network": "1.0.2"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@peerbit/test-utils": "^1.0.2",
|
|
40
|
+
"@peerbit/time": "^1.0.0"
|
|
41
|
+
},
|
|
42
|
+
"gitHead": "595db9f1efebf604393eddfff5f678f5d8f16142"
|
|
43
|
+
}
|
package/src/access.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { field, option, variant, vec } from "@dao-xyz/borsh";
|
|
2
|
+
import { serialize } from "@dao-xyz/borsh";
|
|
3
|
+
import { AccessCondition } from "./condition";
|
|
4
|
+
import { toBase64 } from "@peerbit/crypto";
|
|
5
|
+
|
|
6
|
+
export enum AccessType {
|
|
7
|
+
Any = 0,
|
|
8
|
+
Read = 1,
|
|
9
|
+
Write = 2,
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
@variant(0)
|
|
13
|
+
export class AccessData {}
|
|
14
|
+
|
|
15
|
+
@variant(0)
|
|
16
|
+
export class Access extends AccessData {
|
|
17
|
+
@field({ type: option("string") })
|
|
18
|
+
id: string;
|
|
19
|
+
|
|
20
|
+
@field({ type: vec("u8") })
|
|
21
|
+
accessTypes: AccessType[];
|
|
22
|
+
|
|
23
|
+
@field({ type: AccessCondition })
|
|
24
|
+
accessCondition: AccessCondition<any>;
|
|
25
|
+
|
|
26
|
+
constructor(options?: {
|
|
27
|
+
accessTypes: AccessType[];
|
|
28
|
+
accessCondition: AccessCondition<any>;
|
|
29
|
+
}) {
|
|
30
|
+
super();
|
|
31
|
+
if (options) {
|
|
32
|
+
this.accessTypes = options.accessTypes;
|
|
33
|
+
this.accessCondition = options.accessCondition;
|
|
34
|
+
this.initialize();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
calculateId(): string {
|
|
39
|
+
if (!this.accessTypes || !this.accessCondition) {
|
|
40
|
+
throw new Error("Not initialized");
|
|
41
|
+
}
|
|
42
|
+
const a = new Access();
|
|
43
|
+
a.accessCondition = this.accessCondition;
|
|
44
|
+
a.accessTypes = this.accessTypes;
|
|
45
|
+
return toBase64(serialize(a));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
initialize(): Access {
|
|
49
|
+
this.id = this.calculateId();
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
assertId() {
|
|
54
|
+
const calculatedId = this.calculateId();
|
|
55
|
+
if (this.id !== calculatedId) {
|
|
56
|
+
throw new Error(
|
|
57
|
+
`Invalid id, got ${this.id} but expected ${calculatedId}`
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
package/src/acl-db.ts
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { field, variant } from "@dao-xyz/borsh";
|
|
2
|
+
import { Documents, DocumentIndex } from "@peerbit/document";
|
|
3
|
+
import {
|
|
4
|
+
getPathGenerator,
|
|
5
|
+
TrustedNetwork,
|
|
6
|
+
getFromByTo,
|
|
7
|
+
IdentityGraph,
|
|
8
|
+
createIdentityGraphStore,
|
|
9
|
+
} from "@peerbit/trusted-network";
|
|
10
|
+
import { Access, AccessType } from "./access";
|
|
11
|
+
import { Entry } from "@peerbit/log";
|
|
12
|
+
import { PublicSignKey, sha256Sync } from "@peerbit/crypto";
|
|
13
|
+
import { Program } from "@peerbit/program";
|
|
14
|
+
import { RPC } from "@peerbit/rpc";
|
|
15
|
+
import { PeerId } from "@libp2p/interface-peer-id";
|
|
16
|
+
import { concat } from "uint8arrays";
|
|
17
|
+
import { SubscriptionType } from "@peerbit/shared-log";
|
|
18
|
+
|
|
19
|
+
@variant("identity_acl")
|
|
20
|
+
export class IdentityAccessController extends Program {
|
|
21
|
+
@field({ type: Documents })
|
|
22
|
+
access: Documents<Access>;
|
|
23
|
+
|
|
24
|
+
@field({ type: IdentityGraph })
|
|
25
|
+
identityGraphController: IdentityGraph;
|
|
26
|
+
|
|
27
|
+
@field({ type: TrustedNetwork })
|
|
28
|
+
trustedNetwork: TrustedNetwork;
|
|
29
|
+
|
|
30
|
+
constructor(opts: {
|
|
31
|
+
id?: Uint8Array;
|
|
32
|
+
rootTrust: PublicSignKey | PeerId;
|
|
33
|
+
trustedNetwork?: TrustedNetwork;
|
|
34
|
+
}) {
|
|
35
|
+
super();
|
|
36
|
+
if (!opts.trustedNetwork && !opts.rootTrust) {
|
|
37
|
+
throw new Error("Expecting either TrustedNetwork or rootTrust");
|
|
38
|
+
}
|
|
39
|
+
this.access = new Documents({
|
|
40
|
+
id: opts.id && sha256Sync(concat([opts.id, new Uint8Array([0])])),
|
|
41
|
+
index: new DocumentIndex({
|
|
42
|
+
query: new RPC(),
|
|
43
|
+
}),
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
this.trustedNetwork = opts.trustedNetwork
|
|
47
|
+
? opts.trustedNetwork
|
|
48
|
+
: new TrustedNetwork({
|
|
49
|
+
id: opts.id && sha256Sync(concat([opts.id, new Uint8Array([1])])),
|
|
50
|
+
rootTrust: opts.rootTrust,
|
|
51
|
+
});
|
|
52
|
+
this.identityGraphController = new IdentityGraph({
|
|
53
|
+
relationGraph: createIdentityGraphStore(
|
|
54
|
+
opts.id && sha256Sync(concat([opts.id, new Uint8Array([2])]))
|
|
55
|
+
),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// allow anyone write to the ACL db, but assume entry is invalid until a verifier verifies
|
|
60
|
+
// can append will be anyone who has peformed some proof of work
|
|
61
|
+
|
|
62
|
+
// or
|
|
63
|
+
|
|
64
|
+
// custom can append
|
|
65
|
+
|
|
66
|
+
async canRead(s: PublicSignKey | undefined): Promise<boolean> {
|
|
67
|
+
// TODO, improve, caching etc
|
|
68
|
+
|
|
69
|
+
if (!s) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Check whether it is trusted by trust web
|
|
74
|
+
if (await this.trustedNetwork.isTrusted(s)) {
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Else check whether its trusted by this access controller
|
|
79
|
+
const canReadCheck = async (key: PublicSignKey) => {
|
|
80
|
+
for (const value of this.access.index.index.values()) {
|
|
81
|
+
const access = value.value;
|
|
82
|
+
if (access instanceof Access) {
|
|
83
|
+
if (
|
|
84
|
+
access.accessTypes.find(
|
|
85
|
+
(x) => x === AccessType.Any || x === AccessType.Read
|
|
86
|
+
) !== undefined
|
|
87
|
+
) {
|
|
88
|
+
// check condition
|
|
89
|
+
if (await access.accessCondition.allowed(key)) {
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
if (await canReadCheck(s)) {
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
for await (const trustedByKey of getPathGenerator(
|
|
102
|
+
s,
|
|
103
|
+
this.identityGraphController.relationGraph,
|
|
104
|
+
getFromByTo
|
|
105
|
+
)) {
|
|
106
|
+
if (await canReadCheck(trustedByKey.from)) {
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async canAppend(entry: Entry<any>): Promise<boolean> {
|
|
115
|
+
// TODO, improve, caching etc
|
|
116
|
+
|
|
117
|
+
// Check whether it is trusted by trust web
|
|
118
|
+
const canAppendByKey = async (key: PublicSignKey): Promise<boolean> => {
|
|
119
|
+
if (await this.trustedNetwork.isTrusted(key)) {
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
// Else check whether its trusted by this access controller
|
|
123
|
+
const canWriteCheck = async (key: PublicSignKey) => {
|
|
124
|
+
for (const value of this.access.index.index.values()) {
|
|
125
|
+
const access = value.value;
|
|
126
|
+
if (access instanceof Access) {
|
|
127
|
+
if (
|
|
128
|
+
access.accessTypes.find(
|
|
129
|
+
(x) => x === AccessType.Any || x === AccessType.Write
|
|
130
|
+
) !== undefined
|
|
131
|
+
) {
|
|
132
|
+
// check condition
|
|
133
|
+
if (await access.accessCondition.allowed(key)) {
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
if (await canWriteCheck(key)) {
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
for await (const trustedByKey of getPathGenerator(
|
|
145
|
+
key,
|
|
146
|
+
this.identityGraphController.relationGraph,
|
|
147
|
+
getFromByTo
|
|
148
|
+
)) {
|
|
149
|
+
if (await canWriteCheck(trustedByKey.from)) {
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return false;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
for (const key of await entry.getPublicKeys()) {
|
|
158
|
+
if (await canAppendByKey(key)) {
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async open(properties?: { role?: SubscriptionType }) {
|
|
166
|
+
await this.identityGraphController.open({
|
|
167
|
+
role: properties?.role,
|
|
168
|
+
canRead: this.canRead.bind(this),
|
|
169
|
+
});
|
|
170
|
+
await this.access.open({
|
|
171
|
+
role: properties?.role,
|
|
172
|
+
type: Access,
|
|
173
|
+
canAppend: this.canAppend.bind(this),
|
|
174
|
+
canRead: this.canRead.bind(this),
|
|
175
|
+
});
|
|
176
|
+
await this.trustedNetwork.open(properties);
|
|
177
|
+
}
|
|
178
|
+
}
|
package/src/condition.ts
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { field, variant } from "@dao-xyz/borsh";
|
|
2
|
+
import { PublicSignKey, getPublicKeyFromPeerId } from "@peerbit/crypto";
|
|
3
|
+
import { PeerId } from "@libp2p/interface-peer-id";
|
|
4
|
+
|
|
5
|
+
const coercePublicKey = (publicKey: PublicSignKey | PeerId) => {
|
|
6
|
+
return publicKey instanceof PublicSignKey
|
|
7
|
+
? publicKey
|
|
8
|
+
: getPublicKeyFromPeerId(publicKey);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
@variant(0)
|
|
12
|
+
export class Network {
|
|
13
|
+
@field({ type: "string" })
|
|
14
|
+
type: string;
|
|
15
|
+
|
|
16
|
+
@field({ type: "string" })
|
|
17
|
+
rpc: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class AccessCondition<T> {
|
|
21
|
+
async allowed(_key: PublicSignKey): Promise<boolean> {
|
|
22
|
+
throw new Error("Not implemented");
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@variant([0, 0])
|
|
27
|
+
export class AnyAccessCondition<T> extends AccessCondition<T> {
|
|
28
|
+
constructor() {
|
|
29
|
+
super();
|
|
30
|
+
}
|
|
31
|
+
async allowed(_key: PublicSignKey): Promise<boolean> {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@variant([0, 1])
|
|
37
|
+
export class PublicKeyAccessCondition<T> extends AccessCondition<T> {
|
|
38
|
+
@field({ type: PublicSignKey })
|
|
39
|
+
key: PublicSignKey;
|
|
40
|
+
|
|
41
|
+
constructor(options: { key: PublicSignKey | PeerId }) {
|
|
42
|
+
super();
|
|
43
|
+
this.key = coercePublicKey(options.key);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async allowed(identity: PublicSignKey): Promise<boolean> {
|
|
47
|
+
return this.key.equals(identity);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/* Not yet :)
|
|
52
|
+
|
|
53
|
+
@variant([0, 2])
|
|
54
|
+
export class TokenAccessCondition extends AccessCondition {
|
|
55
|
+
|
|
56
|
+
@field({ type: Network })
|
|
57
|
+
network: Network
|
|
58
|
+
|
|
59
|
+
@field({ type: 'string' })
|
|
60
|
+
token: string
|
|
61
|
+
|
|
62
|
+
@field({ type: 'u64' })
|
|
63
|
+
amount: bigint
|
|
64
|
+
|
|
65
|
+
constructor() {
|
|
66
|
+
super();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@variant(0)
|
|
72
|
+
export class NFTPropertyCondition {
|
|
73
|
+
@field({ type: 'string' })
|
|
74
|
+
field: string
|
|
75
|
+
|
|
76
|
+
@field({ type: 'string' })
|
|
77
|
+
value: string;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@variant([0, 3]) // distinguish between ERC-721, ERC-1155, Solana Metaplex?
|
|
81
|
+
export class NFTAccessCondition extends AccessCondition {
|
|
82
|
+
|
|
83
|
+
@field({ type: Network })
|
|
84
|
+
network: Network
|
|
85
|
+
|
|
86
|
+
@field({ type: 'string' })
|
|
87
|
+
id: string
|
|
88
|
+
|
|
89
|
+
@field({ type: option(vec(NFTPropertyCondition)) })
|
|
90
|
+
properties: NFTPropertyCondition
|
|
91
|
+
|
|
92
|
+
constructor() {
|
|
93
|
+
super();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
*/
|
package/src/index.ts
ADDED