@didcid/gatekeeper 0.1.3 → 0.3.0
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/cjs/{abstract-json-BJMq-iEa.cjs → abstract-json-DNKwEI6F.cjs} +1 -1
- package/dist/cjs/db/json-cache.cjs +1 -1
- package/dist/cjs/db/json-memory.cjs +1 -1
- package/dist/cjs/db/json.cjs +1 -1
- package/dist/cjs/db/mongo.cjs +5 -5
- package/dist/cjs/db/redis.cjs +6 -6
- package/dist/cjs/db/sqlite.cjs +2 -2
- package/dist/cjs/gatekeeper-client.cjs +21 -0
- package/dist/cjs/gatekeeper.cjs +220 -39
- package/dist/cjs/index.cjs +1 -1
- package/dist/cjs/node.cjs +1 -1
- package/dist/esm/db/abstract-json.js +1 -1
- package/dist/esm/db/abstract-json.js.map +1 -1
- package/dist/esm/db/mongo.js +5 -5
- package/dist/esm/db/mongo.js.map +1 -1
- package/dist/esm/db/redis.js +6 -6
- package/dist/esm/db/redis.js.map +1 -1
- package/dist/esm/db/sqlite.js +2 -2
- package/dist/esm/db/sqlite.js.map +1 -1
- package/dist/esm/gatekeeper-client.js +21 -0
- package/dist/esm/gatekeeper-client.js.map +1 -1
- package/dist/esm/gatekeeper.js +104 -39
- package/dist/esm/gatekeeper.js.map +1 -1
- package/dist/esm/search-index.js +118 -0
- package/dist/esm/search-index.js.map +1 -0
- package/dist/types/gatekeeper-client.d.ts +5 -0
- package/dist/types/gatekeeper.d.ts +10 -2
- package/dist/types/search-index.d.ts +12 -0
- package/dist/types/types.d.ts +16 -7
- package/package.json +2 -2
|
@@ -141,7 +141,7 @@ class AbstractJson {
|
|
|
141
141
|
if (!oldQueue) {
|
|
142
142
|
return true;
|
|
143
143
|
}
|
|
144
|
-
db.queue[registry] = oldQueue.filter(item => !batch.some(op => op.
|
|
144
|
+
db.queue[registry] = oldQueue.filter(item => !batch.some(op => op.proof?.proofValue === item.proof?.proofValue));
|
|
145
145
|
this.writeDb(db);
|
|
146
146
|
return true;
|
|
147
147
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var fs = require('fs');
|
|
6
|
-
var abstractJson = require('../abstract-json-
|
|
6
|
+
var abstractJson = require('../abstract-json-DNKwEI6F.cjs');
|
|
7
7
|
require('../errors-DQaog-FG.cjs');
|
|
8
8
|
|
|
9
9
|
class DbJsonCache extends abstractJson.AbstractJson {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var abstractJson = require('../abstract-json-
|
|
5
|
+
var abstractJson = require('../abstract-json-DNKwEI6F.cjs');
|
|
6
6
|
require('../errors-DQaog-FG.cjs');
|
|
7
7
|
|
|
8
8
|
class DbJsonMemory extends abstractJson.AbstractJson {
|
package/dist/cjs/db/json.cjs
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var fs = require('fs');
|
|
6
|
-
var abstractJson = require('../abstract-json-
|
|
6
|
+
var abstractJson = require('../abstract-json-DNKwEI6F.cjs');
|
|
7
7
|
require('../errors-DQaog-FG.cjs');
|
|
8
8
|
|
|
9
9
|
class DbJson extends abstractJson.AbstractJson {
|
package/dist/cjs/db/mongo.cjs
CHANGED
|
@@ -167,15 +167,15 @@ class DbMongo {
|
|
|
167
167
|
throw new Error(MONGO_NOT_STARTED_ERROR);
|
|
168
168
|
}
|
|
169
169
|
try {
|
|
170
|
-
const
|
|
171
|
-
.map(op => op.
|
|
172
|
-
.filter((
|
|
173
|
-
if (
|
|
170
|
+
const proofValues = batch
|
|
171
|
+
.map(op => op.proof?.proofValue)
|
|
172
|
+
.filter((p) => !!p);
|
|
173
|
+
if (proofValues.length === 0) {
|
|
174
174
|
return true;
|
|
175
175
|
}
|
|
176
176
|
await this.db
|
|
177
177
|
.collection('queue')
|
|
178
|
-
.updateOne({ id: registry }, { $pull: { ops: { '
|
|
178
|
+
.updateOne({ id: registry }, { $pull: { ops: { 'proof.proofValue': { $in: proofValues } } } });
|
|
179
179
|
return true;
|
|
180
180
|
}
|
|
181
181
|
catch (error) {
|
package/dist/cjs/db/redis.cjs
CHANGED
|
@@ -165,10 +165,10 @@ class DbRedis {
|
|
|
165
165
|
if (!this.redis) {
|
|
166
166
|
throw new Error(REDIS_NOT_STARTED_ERROR);
|
|
167
167
|
}
|
|
168
|
-
const
|
|
169
|
-
.map(op => op.
|
|
170
|
-
.filter((
|
|
171
|
-
if (
|
|
168
|
+
const proofValues = batch
|
|
169
|
+
.map(op => op.proof?.proofValue)
|
|
170
|
+
.filter((p) => !!p);
|
|
171
|
+
if (proofValues.length === 0) {
|
|
172
172
|
return true;
|
|
173
173
|
}
|
|
174
174
|
const key = this.queueKey(registry);
|
|
@@ -186,7 +186,7 @@ class DbRedis {
|
|
|
186
186
|
local keep = {}
|
|
187
187
|
for i=1,#list do
|
|
188
188
|
local ok, obj = pcall(cjson.decode, list[i])
|
|
189
|
-
if ok and obj and obj.
|
|
189
|
+
if ok and obj and obj.proof and obj.proof.proofValue and want[obj.proof.proofValue] then
|
|
190
190
|
-- drop
|
|
191
191
|
else
|
|
192
192
|
table.insert(keep, list[i])
|
|
@@ -199,7 +199,7 @@ class DbRedis {
|
|
|
199
199
|
return #list - #keep
|
|
200
200
|
`;
|
|
201
201
|
try {
|
|
202
|
-
await this.redis.eval(script, 1, key,
|
|
202
|
+
await this.redis.eval(script, 1, key, proofValues.length.toString(), ...proofValues);
|
|
203
203
|
return true;
|
|
204
204
|
}
|
|
205
205
|
catch (e) {
|
package/dist/cjs/db/sqlite.cjs
CHANGED
|
@@ -259,8 +259,8 @@ class DbSqlite {
|
|
|
259
259
|
}
|
|
260
260
|
return this.runExclusive(async () => this.withTx(async () => {
|
|
261
261
|
const oldQueue = await this.getQueueStrict(registry);
|
|
262
|
-
const
|
|
263
|
-
const newQueue = oldQueue.filter(item => !
|
|
262
|
+
const batchProofValues = new Set(batch.map(b => b.proof?.proofValue).filter((p) => p !== undefined));
|
|
263
|
+
const newQueue = oldQueue.filter(item => !batchProofValues.has(item.proof?.proofValue || ''));
|
|
264
264
|
await this.db.run(`INSERT OR REPLACE INTO queue(id, ops) VALUES(?, ?)`, registry, JSON.stringify(newQueue));
|
|
265
265
|
return true;
|
|
266
266
|
}).catch(err => {
|
|
@@ -364,6 +364,27 @@ class GatekeeperClient {
|
|
|
364
364
|
throwError(error);
|
|
365
365
|
}
|
|
366
366
|
}
|
|
367
|
+
async searchDocs(q) {
|
|
368
|
+
try {
|
|
369
|
+
const response = await this.axios.get(`${this.API}/search`, { params: { q } });
|
|
370
|
+
return response.data;
|
|
371
|
+
}
|
|
372
|
+
catch (error) {
|
|
373
|
+
throwError(error);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
async queryDocs(where) {
|
|
377
|
+
try {
|
|
378
|
+
const response = await this.axios.post(`${this.API}/query`, { where });
|
|
379
|
+
return response.data;
|
|
380
|
+
}
|
|
381
|
+
catch (error) {
|
|
382
|
+
throwError(error);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
async search(query) {
|
|
386
|
+
return this.queryDocs(query.where);
|
|
387
|
+
}
|
|
367
388
|
}
|
|
368
389
|
|
|
369
390
|
exports.default = GatekeeperClient;
|
package/dist/cjs/gatekeeper.cjs
CHANGED
|
@@ -41125,6 +41125,128 @@ async function generateCID(data) {
|
|
|
41125
41125
|
return cid.toString(); // CID v1 default: base32 encoding
|
|
41126
41126
|
}
|
|
41127
41127
|
|
|
41128
|
+
class SearchIndex {
|
|
41129
|
+
docs = new Map();
|
|
41130
|
+
static ARRAY_WILDCARD_END = /\[\*]$/;
|
|
41131
|
+
static ARRAY_WILDCARD_MID = /\[\*]\./;
|
|
41132
|
+
store(did, doc) {
|
|
41133
|
+
// Only index didDocumentData to focus on actual content
|
|
41134
|
+
const data = doc.didDocumentData;
|
|
41135
|
+
if (data && typeof data === 'object') {
|
|
41136
|
+
this.docs.set(did, JSON.parse(JSON.stringify(data)));
|
|
41137
|
+
}
|
|
41138
|
+
else {
|
|
41139
|
+
this.docs.set(did, {});
|
|
41140
|
+
}
|
|
41141
|
+
}
|
|
41142
|
+
delete(did) {
|
|
41143
|
+
this.docs.delete(did);
|
|
41144
|
+
}
|
|
41145
|
+
clear() {
|
|
41146
|
+
this.docs.clear();
|
|
41147
|
+
}
|
|
41148
|
+
get size() {
|
|
41149
|
+
return this.docs.size;
|
|
41150
|
+
}
|
|
41151
|
+
searchDocs(q) {
|
|
41152
|
+
const out = [];
|
|
41153
|
+
for (const [did, doc] of this.docs.entries()) {
|
|
41154
|
+
if (JSON.stringify(doc).includes(q))
|
|
41155
|
+
out.push(did);
|
|
41156
|
+
}
|
|
41157
|
+
return out;
|
|
41158
|
+
}
|
|
41159
|
+
queryDocs(where) {
|
|
41160
|
+
const entry = Object.entries(where)[0];
|
|
41161
|
+
if (!entry) {
|
|
41162
|
+
return [];
|
|
41163
|
+
}
|
|
41164
|
+
const [rawPath, cond] = entry;
|
|
41165
|
+
if (typeof cond !== 'object' || cond === null || !Array.isArray(cond.$in)) {
|
|
41166
|
+
throw new Error('Only {$in:[...]} supported');
|
|
41167
|
+
}
|
|
41168
|
+
const list = cond.$in;
|
|
41169
|
+
const isKeyWildcard = rawPath.endsWith('.*');
|
|
41170
|
+
const isValueWildcard = rawPath.includes('.*.');
|
|
41171
|
+
const isArrayTail = SearchIndex.ARRAY_WILDCARD_END.test(rawPath);
|
|
41172
|
+
const isArrayMid = SearchIndex.ARRAY_WILDCARD_MID.test(rawPath);
|
|
41173
|
+
const result = [];
|
|
41174
|
+
for (const [did, doc] of this.docs.entries()) {
|
|
41175
|
+
let match = false;
|
|
41176
|
+
if (isArrayTail) {
|
|
41177
|
+
const basePath = rawPath.replace(SearchIndex.ARRAY_WILDCARD_END, '');
|
|
41178
|
+
const arr = this.getPath(doc, basePath);
|
|
41179
|
+
if (Array.isArray(arr)) {
|
|
41180
|
+
match = arr.some(v => list.includes(v));
|
|
41181
|
+
}
|
|
41182
|
+
}
|
|
41183
|
+
else if (isArrayMid) {
|
|
41184
|
+
const [prefix, suffix] = rawPath.split('[*].');
|
|
41185
|
+
const arr = this.getPath(doc, prefix);
|
|
41186
|
+
if (Array.isArray(arr)) {
|
|
41187
|
+
match = arr.some(el => list.includes(this.getPath(el, suffix)));
|
|
41188
|
+
}
|
|
41189
|
+
}
|
|
41190
|
+
else if (isKeyWildcard) {
|
|
41191
|
+
const basePath = rawPath.slice(0, -2);
|
|
41192
|
+
const obj = this.getPath(doc, basePath);
|
|
41193
|
+
if (obj && typeof obj === 'object' && !Array.isArray(obj)) {
|
|
41194
|
+
const keys = Object.keys(obj);
|
|
41195
|
+
match = keys.some(k => list.includes(k));
|
|
41196
|
+
}
|
|
41197
|
+
}
|
|
41198
|
+
else if (isValueWildcard) {
|
|
41199
|
+
const [prefix, suffix] = rawPath.split('.*.');
|
|
41200
|
+
const obj = this.getPath(doc, prefix);
|
|
41201
|
+
if (obj && typeof obj === 'object' && !Array.isArray(obj)) {
|
|
41202
|
+
const values = Object.values(obj);
|
|
41203
|
+
match = values.some(v => list.includes(this.getPath(v, suffix)));
|
|
41204
|
+
}
|
|
41205
|
+
}
|
|
41206
|
+
else {
|
|
41207
|
+
const val = this.getPath(doc, rawPath);
|
|
41208
|
+
match = list.includes(val);
|
|
41209
|
+
}
|
|
41210
|
+
if (match) {
|
|
41211
|
+
result.push(did);
|
|
41212
|
+
}
|
|
41213
|
+
}
|
|
41214
|
+
return result;
|
|
41215
|
+
}
|
|
41216
|
+
getPath(root, path) {
|
|
41217
|
+
if (!path || root == null) {
|
|
41218
|
+
return undefined;
|
|
41219
|
+
}
|
|
41220
|
+
const clean = path.startsWith('$.') ? path.slice(2) : path.startsWith('$') ? path.slice(1) : path;
|
|
41221
|
+
if (!clean) {
|
|
41222
|
+
return root;
|
|
41223
|
+
}
|
|
41224
|
+
const parts = clean.split('.');
|
|
41225
|
+
let cur = root;
|
|
41226
|
+
for (const rawPart of parts) {
|
|
41227
|
+
if (cur == null) {
|
|
41228
|
+
return undefined;
|
|
41229
|
+
}
|
|
41230
|
+
const idx = Number.isInteger(+rawPart) ? +rawPart : null;
|
|
41231
|
+
if (idx !== null && Array.isArray(cur)) {
|
|
41232
|
+
cur = cur[idx];
|
|
41233
|
+
continue;
|
|
41234
|
+
}
|
|
41235
|
+
if (typeof cur === 'object') {
|
|
41236
|
+
cur = cur[rawPart];
|
|
41237
|
+
}
|
|
41238
|
+
else {
|
|
41239
|
+
return undefined;
|
|
41240
|
+
}
|
|
41241
|
+
}
|
|
41242
|
+
return cur;
|
|
41243
|
+
}
|
|
41244
|
+
}
|
|
41245
|
+
|
|
41246
|
+
function base64urlToHex(b64) {
|
|
41247
|
+
const bytes = base64url.baseDecode(b64);
|
|
41248
|
+
return Buffer.from(bytes).toString('hex');
|
|
41249
|
+
}
|
|
41128
41250
|
const ValidVersions = [1];
|
|
41129
41251
|
const ValidTypes = ['agent', 'asset'];
|
|
41130
41252
|
// Registries that are considered valid when importing DIDs from the network
|
|
@@ -41134,7 +41256,6 @@ const ValidRegistries = [
|
|
|
41134
41256
|
'BTC:mainnet',
|
|
41135
41257
|
'BTC:testnet4',
|
|
41136
41258
|
'BTC:signet',
|
|
41137
|
-
'FTC:testnet5',
|
|
41138
41259
|
];
|
|
41139
41260
|
var ImportStatus;
|
|
41140
41261
|
(function (ImportStatus) {
|
|
@@ -41156,6 +41277,7 @@ class Gatekeeper {
|
|
|
41156
41277
|
maxQueueSize;
|
|
41157
41278
|
supportedRegistries;
|
|
41158
41279
|
didLocks = new Map();
|
|
41280
|
+
searchIndex;
|
|
41159
41281
|
constructor(options) {
|
|
41160
41282
|
if (!options || !options.db) {
|
|
41161
41283
|
throw new errors.InvalidParameterError('missing options.db');
|
|
@@ -41183,6 +41305,30 @@ class Gatekeeper {
|
|
|
41183
41305
|
throw new errors.InvalidParameterError(`registry=${registry}`);
|
|
41184
41306
|
}
|
|
41185
41307
|
}
|
|
41308
|
+
this.searchIndex = new SearchIndex();
|
|
41309
|
+
}
|
|
41310
|
+
async initSearchIndex() {
|
|
41311
|
+
const dids = await this.getDIDs();
|
|
41312
|
+
for (const did of dids) {
|
|
41313
|
+
try {
|
|
41314
|
+
const doc = await this.resolveDID(did);
|
|
41315
|
+
this.searchIndex.store(did, doc);
|
|
41316
|
+
}
|
|
41317
|
+
catch {
|
|
41318
|
+
// Skip DIDs that can't be resolved
|
|
41319
|
+
}
|
|
41320
|
+
}
|
|
41321
|
+
console.log(`Search index initialized with ${this.searchIndex.size} DIDs`);
|
|
41322
|
+
}
|
|
41323
|
+
async updateSearchIndex(did) {
|
|
41324
|
+
try {
|
|
41325
|
+
const doc = await this.resolveDID(did);
|
|
41326
|
+
this.searchIndex.store(did, doc);
|
|
41327
|
+
}
|
|
41328
|
+
catch {
|
|
41329
|
+
// If DID can't be resolved, remove from index
|
|
41330
|
+
this.searchIndex.delete(did);
|
|
41331
|
+
}
|
|
41186
41332
|
}
|
|
41187
41333
|
async withDidLock(did, fn) {
|
|
41188
41334
|
const prev = this.didLocks.get(did) ?? Promise.resolve();
|
|
@@ -41311,7 +41457,7 @@ class Gatekeeper {
|
|
|
41311
41457
|
if (registry) {
|
|
41312
41458
|
byRegistry[registry] = (byRegistry[registry] || 0) + 1;
|
|
41313
41459
|
}
|
|
41314
|
-
const version = doc.didDocumentMetadata?.
|
|
41460
|
+
const version = doc.didDocumentMetadata?.versionSequence;
|
|
41315
41461
|
if (version != null) {
|
|
41316
41462
|
const versionNum = parseInt(version, 10);
|
|
41317
41463
|
if (!isNaN(versionNum)) {
|
|
@@ -41333,6 +41479,7 @@ class Gatekeeper {
|
|
|
41333
41479
|
async resetDb() {
|
|
41334
41480
|
await this.db.resetDb();
|
|
41335
41481
|
this.verifiedDIDs = {};
|
|
41482
|
+
this.searchIndex.clear();
|
|
41336
41483
|
return true;
|
|
41337
41484
|
}
|
|
41338
41485
|
async generateCID(operation, save = false) {
|
|
@@ -41372,21 +41519,29 @@ class Gatekeeper {
|
|
|
41372
41519
|
const hex64Regex = /^[a-f0-9]{64}$/i;
|
|
41373
41520
|
return hex64Regex.test(hash);
|
|
41374
41521
|
}
|
|
41375
|
-
|
|
41376
|
-
if (!
|
|
41522
|
+
verifyProofFormat(proof) {
|
|
41523
|
+
if (!proof) {
|
|
41377
41524
|
return false;
|
|
41378
41525
|
}
|
|
41379
|
-
if (
|
|
41526
|
+
if (proof.type !== "EcdsaSecp256k1Signature2019") {
|
|
41380
41527
|
return false;
|
|
41381
41528
|
}
|
|
41382
|
-
if (!this.
|
|
41529
|
+
if (!this.verifyDateFormat(proof.created)) {
|
|
41383
41530
|
return false;
|
|
41384
41531
|
}
|
|
41385
|
-
|
|
41386
|
-
if (signature.signer && !this.verifyDIDFormat(signature.signer)) {
|
|
41532
|
+
if (!proof.proofPurpose || !["assertionMethod", "authentication"].includes(proof.proofPurpose)) {
|
|
41387
41533
|
return false;
|
|
41388
41534
|
}
|
|
41389
|
-
|
|
41535
|
+
// Validate verificationMethod format: did:...#key-N or #key-N (relative reference for create ops)
|
|
41536
|
+
if (!proof.verificationMethod || !proof.verificationMethod.includes('#')) {
|
|
41537
|
+
return false;
|
|
41538
|
+
}
|
|
41539
|
+
const [did] = proof.verificationMethod.split('#');
|
|
41540
|
+
// Empty string is valid (relative reference like #key-1), otherwise must be valid DID
|
|
41541
|
+
if (did !== '' && !this.verifyDIDFormat(did)) {
|
|
41542
|
+
return false;
|
|
41543
|
+
}
|
|
41544
|
+
return !!(proof.proofValue && typeof proof.proofValue === 'string');
|
|
41390
41545
|
}
|
|
41391
41546
|
async verifyCreateOperation(operation) {
|
|
41392
41547
|
if (!operation) {
|
|
@@ -41414,8 +41569,12 @@ class Gatekeeper {
|
|
|
41414
41569
|
if (!ValidRegistries.includes(operation.registration.registry)) {
|
|
41415
41570
|
throw new errors.InvalidOperationError(`registration.registry=${operation.registration.registry}`);
|
|
41416
41571
|
}
|
|
41417
|
-
if (!this.
|
|
41418
|
-
throw new errors.InvalidOperationError('
|
|
41572
|
+
if (!this.verifyProofFormat(operation.proof)) {
|
|
41573
|
+
throw new errors.InvalidOperationError('proof');
|
|
41574
|
+
}
|
|
41575
|
+
// For agent create operations, verificationMethod must be relative #key-1 (no DID exists yet)
|
|
41576
|
+
if (operation.registration.type === 'agent' && operation.proof.verificationMethod !== '#key-1') {
|
|
41577
|
+
throw new errors.InvalidOperationError('proof.verificationMethod must be #key-1 for agent create');
|
|
41419
41578
|
}
|
|
41420
41579
|
if (operation.registration.validUntil && !this.verifyDateFormat(operation.registration.validUntil)) {
|
|
41421
41580
|
throw new errors.InvalidOperationError(`registration.validUntil=${operation.registration.validUntil}`);
|
|
@@ -41425,20 +41584,23 @@ class Gatekeeper {
|
|
|
41425
41584
|
throw new errors.InvalidOperationError('publicJwk');
|
|
41426
41585
|
}
|
|
41427
41586
|
const operationCopy = copyJSON(operation);
|
|
41428
|
-
delete operationCopy.
|
|
41587
|
+
delete operationCopy.proof;
|
|
41429
41588
|
const msgHash = this.cipher.hashJSON(operationCopy);
|
|
41430
|
-
|
|
41589
|
+
const signatureHex = base64urlToHex(operation.proof.proofValue);
|
|
41590
|
+
return this.cipher.verifySig(msgHash, signatureHex, operation.publicJwk);
|
|
41431
41591
|
}
|
|
41432
41592
|
if (operation.registration.type === 'asset') {
|
|
41433
|
-
|
|
41593
|
+
// Extract controller DID from verificationMethod
|
|
41594
|
+
const [controllerDid] = operation.proof.verificationMethod.split('#');
|
|
41595
|
+
if (operation.controller !== controllerDid) {
|
|
41434
41596
|
throw new errors.InvalidOperationError('signer is not controller');
|
|
41435
41597
|
}
|
|
41436
|
-
const doc = await this.resolveDID(
|
|
41598
|
+
const doc = await this.resolveDID(controllerDid, { confirm: true, versionTime: operation.proof.created });
|
|
41437
41599
|
if (doc.didDocumentRegistration && doc.didDocumentRegistration.registry === 'local' && operation.registration.registry !== 'local') {
|
|
41438
41600
|
throw new errors.InvalidOperationError(`non-local registry=${operation.registration.registry}`);
|
|
41439
41601
|
}
|
|
41440
41602
|
const operationCopy = copyJSON(operation);
|
|
41441
|
-
delete operationCopy.
|
|
41603
|
+
delete operationCopy.proof;
|
|
41442
41604
|
const msgHash = this.cipher.hashJSON(operationCopy);
|
|
41443
41605
|
if (!doc.didDocument ||
|
|
41444
41606
|
!doc.didDocument.verificationMethod ||
|
|
@@ -41448,7 +41610,8 @@ class Gatekeeper {
|
|
|
41448
41610
|
}
|
|
41449
41611
|
// TBD select the right key here, not just the first one
|
|
41450
41612
|
const publicJwk = doc.didDocument.verificationMethod[0].publicKeyJwk;
|
|
41451
|
-
|
|
41613
|
+
const signatureHex = base64urlToHex(operation.proof.proofValue);
|
|
41614
|
+
return this.cipher.verifySig(msgHash, signatureHex, publicJwk);
|
|
41452
41615
|
}
|
|
41453
41616
|
throw new errors.InvalidOperationError(`registration.type=${operation.registration.type}`);
|
|
41454
41617
|
}
|
|
@@ -41456,8 +41619,8 @@ class Gatekeeper {
|
|
|
41456
41619
|
if (JSON.stringify(operation).length > this.maxOpBytes) {
|
|
41457
41620
|
throw new errors.InvalidOperationError('size');
|
|
41458
41621
|
}
|
|
41459
|
-
if (!this.
|
|
41460
|
-
throw new errors.InvalidOperationError('
|
|
41622
|
+
if (!this.verifyProofFormat(operation.proof)) {
|
|
41623
|
+
throw new errors.InvalidOperationError('proof');
|
|
41461
41624
|
}
|
|
41462
41625
|
if (!doc?.didDocument) {
|
|
41463
41626
|
throw new errors.InvalidOperationError('doc.didDocument');
|
|
@@ -41467,26 +41630,24 @@ class Gatekeeper {
|
|
|
41467
41630
|
}
|
|
41468
41631
|
if (doc.didDocument.controller) {
|
|
41469
41632
|
// This DID is an asset, verify with controller's keys
|
|
41470
|
-
const controllerDoc = await this.resolveDID(doc.didDocument.controller, { confirm: true, versionTime: operation.
|
|
41633
|
+
const controllerDoc = await this.resolveDID(doc.didDocument.controller, { confirm: true, versionTime: operation.proof.created });
|
|
41471
41634
|
return this.verifyUpdateOperation(operation, controllerDoc);
|
|
41472
41635
|
}
|
|
41473
41636
|
if (!doc.didDocument.verificationMethod) {
|
|
41474
41637
|
throw new errors.InvalidOperationError('doc.didDocument.verificationMethod');
|
|
41475
41638
|
}
|
|
41476
|
-
const
|
|
41639
|
+
const proof = operation.proof;
|
|
41477
41640
|
const jsonCopy = copyJSON(operation);
|
|
41478
|
-
delete jsonCopy.
|
|
41641
|
+
delete jsonCopy.proof;
|
|
41479
41642
|
const msgHash = this.cipher.hashJSON(jsonCopy);
|
|
41480
|
-
if (signature.hash && signature.hash !== msgHash) {
|
|
41481
|
-
return false;
|
|
41482
|
-
}
|
|
41483
41643
|
if (doc.didDocument.verificationMethod.length === 0 ||
|
|
41484
41644
|
!doc.didDocument.verificationMethod[0].publicKeyJwk) {
|
|
41485
41645
|
throw new errors.InvalidOperationError('didDocument missing verificationMethod');
|
|
41486
41646
|
}
|
|
41487
|
-
// TBD get the right
|
|
41647
|
+
// TBD get the right key here, not just the first one
|
|
41488
41648
|
const publicJwk = doc.didDocument.verificationMethod[0].publicKeyJwk;
|
|
41489
|
-
|
|
41649
|
+
const signatureHex = base64urlToHex(proof.proofValue);
|
|
41650
|
+
return this.cipher.verifySig(msgHash, signatureHex, publicJwk);
|
|
41490
41651
|
}
|
|
41491
41652
|
async queueOperation(registry, operation) {
|
|
41492
41653
|
// Don't distribute local DIDs
|
|
@@ -41506,7 +41667,7 @@ class Gatekeeper {
|
|
|
41506
41667
|
async createDID(operation) {
|
|
41507
41668
|
const valid = await this.verifyCreateOperation(operation);
|
|
41508
41669
|
if (!valid) {
|
|
41509
|
-
throw new errors.InvalidOperationError('
|
|
41670
|
+
throw new errors.InvalidOperationError('proof');
|
|
41510
41671
|
}
|
|
41511
41672
|
const registry = operation.registration.registry;
|
|
41512
41673
|
// Reject operations with unsupported registries
|
|
@@ -41530,6 +41691,7 @@ class Gatekeeper {
|
|
|
41530
41691
|
did
|
|
41531
41692
|
});
|
|
41532
41693
|
await this.queueOperation(registry, operation);
|
|
41694
|
+
await this.updateSearchIndex(did);
|
|
41533
41695
|
return did;
|
|
41534
41696
|
});
|
|
41535
41697
|
}
|
|
@@ -41566,6 +41728,9 @@ class Gatekeeper {
|
|
|
41566
41728
|
"authentication": [
|
|
41567
41729
|
"#key-1"
|
|
41568
41730
|
],
|
|
41731
|
+
"assertionMethod": [
|
|
41732
|
+
"#key-1"
|
|
41733
|
+
],
|
|
41569
41734
|
},
|
|
41570
41735
|
"didDocumentMetadata": {
|
|
41571
41736
|
"created": anchor.created,
|
|
@@ -41676,14 +41841,14 @@ class Gatekeeper {
|
|
|
41676
41841
|
if (verify) {
|
|
41677
41842
|
const valid = await this.verifyCreateOperation(operation);
|
|
41678
41843
|
if (!valid) {
|
|
41679
|
-
throw new errors.InvalidOperationError('
|
|
41844
|
+
throw new errors.InvalidOperationError('proof');
|
|
41680
41845
|
}
|
|
41681
41846
|
}
|
|
41682
41847
|
doc.didDocumentMetadata = {
|
|
41683
41848
|
created,
|
|
41684
41849
|
canonicalId,
|
|
41685
41850
|
versionId,
|
|
41686
|
-
|
|
41851
|
+
versionSequence: versionNum.toString(),
|
|
41687
41852
|
confirmed,
|
|
41688
41853
|
timestamp,
|
|
41689
41854
|
};
|
|
@@ -41702,7 +41867,7 @@ class Gatekeeper {
|
|
|
41702
41867
|
if (verify) {
|
|
41703
41868
|
const valid = await this.verifyUpdateOperation(operation, doc);
|
|
41704
41869
|
if (!valid) {
|
|
41705
|
-
throw new errors.InvalidOperationError('
|
|
41870
|
+
throw new errors.InvalidOperationError('proof');
|
|
41706
41871
|
}
|
|
41707
41872
|
if (!operation.previd || operation.previd !== doc.didDocumentMetadata?.versionId) {
|
|
41708
41873
|
throw new errors.InvalidOperationError('previd');
|
|
@@ -41726,7 +41891,7 @@ class Gatekeeper {
|
|
|
41726
41891
|
updated,
|
|
41727
41892
|
canonicalId,
|
|
41728
41893
|
versionId,
|
|
41729
|
-
|
|
41894
|
+
versionSequence: versionNum.toString(),
|
|
41730
41895
|
confirmed,
|
|
41731
41896
|
timestamp,
|
|
41732
41897
|
};
|
|
@@ -41742,7 +41907,7 @@ class Gatekeeper {
|
|
|
41742
41907
|
deleted: updated,
|
|
41743
41908
|
canonicalId,
|
|
41744
41909
|
versionId,
|
|
41745
|
-
|
|
41910
|
+
versionSequence: versionNum.toString(),
|
|
41746
41911
|
confirmed,
|
|
41747
41912
|
timestamp,
|
|
41748
41913
|
};
|
|
@@ -41778,13 +41943,14 @@ class Gatekeeper {
|
|
|
41778
41943
|
const opid = await this.generateCID(operation, true);
|
|
41779
41944
|
await this.db.addEvent(operation.did, {
|
|
41780
41945
|
registry: 'local',
|
|
41781
|
-
time: operation.
|
|
41946
|
+
time: operation.proof?.created || '',
|
|
41782
41947
|
ordinal: [0],
|
|
41783
41948
|
operation,
|
|
41784
41949
|
opid,
|
|
41785
41950
|
did: operation.did
|
|
41786
41951
|
});
|
|
41787
41952
|
await this.queueOperation(registry, operation);
|
|
41953
|
+
await this.updateSearchIndex(operation.did);
|
|
41788
41954
|
return true;
|
|
41789
41955
|
});
|
|
41790
41956
|
}
|
|
@@ -41853,6 +42019,7 @@ class Gatekeeper {
|
|
|
41853
42019
|
}
|
|
41854
42020
|
for (const did of dids) {
|
|
41855
42021
|
await this.db.deleteEvents(did);
|
|
42022
|
+
this.searchIndex.delete(did);
|
|
41856
42023
|
}
|
|
41857
42024
|
return true;
|
|
41858
42025
|
}
|
|
@@ -41893,7 +42060,7 @@ class Gatekeeper {
|
|
|
41893
42060
|
if (!event.opid) {
|
|
41894
42061
|
event.opid = await this.generateCID(event.operation, true);
|
|
41895
42062
|
}
|
|
41896
|
-
const opMatch = currentEvents.find(item => item.operation.
|
|
42063
|
+
const opMatch = currentEvents.find(item => item.operation.proof?.proofValue === event.operation.proof?.proofValue);
|
|
41897
42064
|
if (opMatch) {
|
|
41898
42065
|
const index = currentEvents.indexOf(opMatch);
|
|
41899
42066
|
const expectedRegistry = expectedRegistryForIndex(currentEvents, index);
|
|
@@ -41969,6 +42136,9 @@ class Gatekeeper {
|
|
|
41969
42136
|
if (status === ImportStatus.ADDED) {
|
|
41970
42137
|
added += 1;
|
|
41971
42138
|
console.log(`import ${i}/${total}: added event for ${event.did}`);
|
|
42139
|
+
if (event.did) {
|
|
42140
|
+
await this.updateSearchIndex(event.did);
|
|
42141
|
+
}
|
|
41972
42142
|
}
|
|
41973
42143
|
else if (status === ImportStatus.MERGED) {
|
|
41974
42144
|
merged += 1;
|
|
@@ -42029,7 +42199,7 @@ class Gatekeeper {
|
|
|
42029
42199
|
if (JSON.stringify(operation).length > this.maxOpBytes) {
|
|
42030
42200
|
return false;
|
|
42031
42201
|
}
|
|
42032
|
-
if (!this.
|
|
42202
|
+
if (!this.verifyProofFormat(operation.proof)) {
|
|
42033
42203
|
return false;
|
|
42034
42204
|
}
|
|
42035
42205
|
if (operation.type === 'create') {
|
|
@@ -42056,7 +42226,9 @@ class Gatekeeper {
|
|
|
42056
42226
|
}
|
|
42057
42227
|
// eslint-disable-next-line
|
|
42058
42228
|
if (operation.registration.type === 'asset') {
|
|
42059
|
-
|
|
42229
|
+
// Extract controller DID from verificationMethod
|
|
42230
|
+
const [controllerDid] = operation.proof.verificationMethod.split('#');
|
|
42231
|
+
if (operation.controller !== controllerDid) {
|
|
42060
42232
|
return false;
|
|
42061
42233
|
}
|
|
42062
42234
|
}
|
|
@@ -42098,7 +42270,7 @@ class Gatekeeper {
|
|
|
42098
42270
|
const event = batch[i];
|
|
42099
42271
|
const ok = await this.verifyEvent(event);
|
|
42100
42272
|
if (ok) {
|
|
42101
|
-
const eventKey = `${event.registry}/${event.operation.
|
|
42273
|
+
const eventKey = `${event.registry}/${event.operation.proof?.proofValue}`;
|
|
42102
42274
|
if (!this.eventsSeen[eventKey]) {
|
|
42103
42275
|
this.eventsSeen[eventKey] = true;
|
|
42104
42276
|
this.eventsQueue.push(event);
|
|
@@ -42160,7 +42332,7 @@ class Gatekeeper {
|
|
|
42160
42332
|
return false;
|
|
42161
42333
|
});
|
|
42162
42334
|
const events = nonlocalDIDs.flat();
|
|
42163
|
-
return events.sort((a, b) => new Date(a.operation.
|
|
42335
|
+
return events.sort((a, b) => new Date(a.operation.proof?.created ?? 0).getTime() - new Date(b.operation.proof?.created ?? 0).getTime());
|
|
42164
42336
|
}
|
|
42165
42337
|
async getQueue(registry) {
|
|
42166
42338
|
if (!ValidRegistries.includes(registry)) {
|
|
@@ -42207,6 +42379,15 @@ class Gatekeeper {
|
|
|
42207
42379
|
async getJSON(cid) {
|
|
42208
42380
|
return this.ipfs.getJSON(cid);
|
|
42209
42381
|
}
|
|
42382
|
+
async searchDocs(q) {
|
|
42383
|
+
return this.searchIndex.searchDocs(q);
|
|
42384
|
+
}
|
|
42385
|
+
async queryDocs(where) {
|
|
42386
|
+
return this.searchIndex.queryDocs(where);
|
|
42387
|
+
}
|
|
42388
|
+
async search(query) {
|
|
42389
|
+
return this.queryDocs(query.where);
|
|
42390
|
+
}
|
|
42210
42391
|
}
|
|
42211
42392
|
|
|
42212
42393
|
exports.default = Gatekeeper;
|
package/dist/cjs/index.cjs
CHANGED
package/dist/cjs/node.cjs
CHANGED
|
@@ -11,7 +11,7 @@ var db_mongo = require('./db/mongo.cjs');
|
|
|
11
11
|
var db_redis = require('./db/redis.cjs');
|
|
12
12
|
var db_sqlite = require('./db/sqlite.cjs');
|
|
13
13
|
require('axios');
|
|
14
|
-
require('./abstract-json-
|
|
14
|
+
require('./abstract-json-DNKwEI6F.cjs');
|
|
15
15
|
require('./errors-DQaog-FG.cjs');
|
|
16
16
|
require('crypto');
|
|
17
17
|
require('assert');
|
|
@@ -138,7 +138,7 @@ export class AbstractJson {
|
|
|
138
138
|
if (!oldQueue) {
|
|
139
139
|
return true;
|
|
140
140
|
}
|
|
141
|
-
db.queue[registry] = oldQueue.filter(item => !batch.some(op => op.
|
|
141
|
+
db.queue[registry] = oldQueue.filter(item => !batch.some(op => op.proof?.proofValue === item.proof?.proofValue));
|
|
142
142
|
this.writeDb(db);
|
|
143
143
|
return true;
|
|
144
144
|
}
|