UNPKG

4.17 kBJavaScriptView Raw
1//
2
3const ObservedRemoveSet = require('./set');
4const getVerifier = require('./verifier');
5const { InvalidSignatureError } = require('./signed-error');
6
7
8
9
10
11
12
13
14class SignedObservedRemoveSet extends ObservedRemoveSet {
15 constructor(entries , options ) {
16 super([], options);
17 if (!options || !options.key) {
18 throw new Error('Missing required options.key parameter');
19 }
20 this.verify = getVerifier(options.key, options.format);
21 this.insertionSignatureMap = new Map();
22 this.deletionSignatureMap = new Map();
23 if (!entries) {
24 return;
25 }
26 for (const [value, id, signature] of entries) {
27 this.addSigned(value, id, signature);
28 }
29 }
30
31
32
33
34
35 /**
36 * Return an array containing all of the set's insertions and deletions.
37 * @return {Array<Array<any>>}
38 */
39 dump() {
40 const [insertQueue, deleteQueue] = super.dump();
41 const signedInsertQueue = insertQueue.map(([hash, [id, value]]) => {
42 const signature = this.insertionSignatureMap.get(id);
43 if (!signature) {
44 throw new Error(`Missing signature for insertion with id "${id}" and value "${JSON.stringify(value)}"`);
45 }
46 return [signature, id, hash, value];
47 });
48 const signedDeleteQueue = deleteQueue.map(([id, hash]) => {
49 const signature = this.deletionSignatureMap.get(id);
50 if (!signature) {
51 throw new Error(`Missing signature for deletion with id "${id}"`);
52 }
53 return [signature, id, hash];
54 });
55 const queue = [signedInsertQueue, signedDeleteQueue];
56 return queue;
57 }
58
59 flush() {
60 const now = Date.now();
61 for (const [id] of this.deletions) {
62 const timestamp = parseInt(id.slice(0, 9), 36);
63 if (now - timestamp >= this.maxAge) {
64 this.deletions.delete(id);
65 this.deletionSignatureMap.delete(id);
66 }
67 }
68 }
69
70 process(signedQueue , skipFlush = false) {
71 const [signedInsertQueue, signedDeleteQueue] = signedQueue;
72 const insertQueue = signedInsertQueue.map(([signature, id, hash, value]) => {
73 if (!this.verify(signature, value, id)) {
74 throw new InvalidSignatureError(`Signature does not match for value ${JSON.stringify(value)}`);
75 }
76 this.insertionSignatureMap.set(id, signature);
77 return [hash, [id, value]];
78 });
79 const deleteQueue = signedDeleteQueue.map(([signature, id, hash]) => {
80 if (!this.verify(signature, id)) {
81 throw new InvalidSignatureError(`Signature does not match for id ${JSON.stringify(id)}`);
82 }
83 this.deletionSignatureMap.set(id, signature);
84 return [id, hash];
85 });
86 const queue = [insertQueue, deleteQueue];
87 super.process(queue, skipFlush);
88 for (const [signature, id, hash] of signedInsertQueue) { // eslint-disable-line no-unused-vars
89 const pair = this.pairs.get(hash);
90 if (!pair || pair[0] !== id) {
91 this.insertionSignatureMap.delete(id);
92 }
93 }
94 }
95
96 addSigned(value , id , signature ) {
97 const hash = this.hash(value);
98 const message = [signature, id, hash, value];
99 this.process([[message], []], true);
100 this.insertQueue.push(message);
101 this.dequeue();
102 return this;
103 }
104
105 deleteSignedId(id , signature ) {
106 for (const [hash, [pairId]] of this.pairs) {
107 if (pairId === id) {
108 const message = [signature, id, hash];
109 this.process([[], [message]], true);
110 this.deleteQueue.push(message);
111 this.dequeue();
112 return;
113 }
114 }
115 }
116
117 clear() {
118 throw new Error('Unsupported method clear()');
119 }
120
121 add() {
122 throw new Error('Unsupported method add(), use addSigned()');
123 }
124
125 delete() {
126 throw new Error('Unsupported method delete(), use deleteSignedId()');
127 }
128}
129
130module.exports = SignedObservedRemoveSet;