@superhero/eventflow-db 4.0.0 → 4.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/README.md +158 -47
- package/index.js +101 -21
- package/index.test.js +65 -0
- package/package.json +2 -2
- package/sql/certificate/persist.sql +2 -0
- package/sql/certificate/read.sql +5 -0
- package/sql/certificate/revoke.sql +13 -0
- package/sql/certificate/schema.sql +26 -0
package/README.md
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
- Simplified table schema management for the Eventflow components.
|
|
8
8
|
- Supports creating, reading, updating and deleting events and their associations.
|
|
9
9
|
- Supports database interactions for scheduled and published events.
|
|
10
|
+
- Supports database interactions for certificate, hub and log.
|
|
10
11
|
- Integrates with `@superhero/db` for file management of SQL queries, and `mysql2` as the database driver.
|
|
11
12
|
- Error declarations with descriptive error messages and error codes.
|
|
12
13
|
|
|
@@ -110,6 +111,8 @@ await db.updateEventPublishedToSuccess(eventId)
|
|
|
110
111
|
|
|
111
112
|
### Logging
|
|
112
113
|
|
|
114
|
+
#### Persisting a log entry
|
|
115
|
+
|
|
113
116
|
```javascript
|
|
114
117
|
const log =
|
|
115
118
|
{
|
|
@@ -121,6 +124,15 @@ const log =
|
|
|
121
124
|
await db.persistLog(log)
|
|
122
125
|
```
|
|
123
126
|
|
|
127
|
+
#### Archive logs
|
|
128
|
+
|
|
129
|
+
Archives logs by partitioning the log table by date.
|
|
130
|
+
|
|
131
|
+
```javascript
|
|
132
|
+
const date = new Date()
|
|
133
|
+
await db.archiveLog(date)
|
|
134
|
+
```
|
|
135
|
+
|
|
124
136
|
### Managing Hubs
|
|
125
137
|
|
|
126
138
|
#### Persisting a Hub
|
|
@@ -145,10 +157,95 @@ const hubs = await db.readOnlineHubs()
|
|
|
145
157
|
console.log('Online Hubs:', hubs)
|
|
146
158
|
```
|
|
147
159
|
|
|
160
|
+
### Managing Certificate
|
|
161
|
+
|
|
162
|
+
#### Persisting a Certificate
|
|
163
|
+
|
|
164
|
+
```javascript
|
|
165
|
+
const certificate =
|
|
166
|
+
{
|
|
167
|
+
id : 'unique_certificate_id',
|
|
168
|
+
validity : new Date('2025-12-31T23:59:59.000Z'),
|
|
169
|
+
cert : 'certificate_value',
|
|
170
|
+
key : Buffer.from('encryption_key'),
|
|
171
|
+
key_iv : Buffer.from('initialization_vector'),
|
|
172
|
+
key_salt : Buffer.from('key_salt'),
|
|
173
|
+
key_tag : Buffer.from('key_tag'),
|
|
174
|
+
pass : Buffer.from('encrypted_passphrase'),
|
|
175
|
+
pass_iv : Buffer.from('pass_iv'),
|
|
176
|
+
pass_salt : Buffer.from('pass_salt'),
|
|
177
|
+
pass_tag : Buffer.from('pass_tag'),
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const isPersisted = await db.persistCertificate(certificate);
|
|
181
|
+
console.log('Persisted:', isPersisted);
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
#### Reading a Certificate
|
|
185
|
+
|
|
186
|
+
```javascript
|
|
187
|
+
try
|
|
188
|
+
{
|
|
189
|
+
const certificate = await db.readCertificate('unique_certificate_id');
|
|
190
|
+
console.log('Certificate:', certificate);
|
|
191
|
+
}
|
|
192
|
+
catch (error)
|
|
193
|
+
{
|
|
194
|
+
if (error.code === 'E_EVENTFLOW_DB_CERTIFICATE_NOT_FOUND')
|
|
195
|
+
{
|
|
196
|
+
console.error('Certificate not found');
|
|
197
|
+
}
|
|
198
|
+
else
|
|
199
|
+
{
|
|
200
|
+
console.error('Error reading certificate:', error);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
#### Revoking a Certificate
|
|
206
|
+
|
|
207
|
+
```javascript
|
|
208
|
+
const revoked = await db.revokeCertificate('unique_certificate_id');
|
|
209
|
+
console.log('Certificate revoked:', revoked);
|
|
210
|
+
```
|
|
211
|
+
|
|
148
212
|
## Table Schemas
|
|
149
213
|
|
|
150
214
|
Below are the database schemas used in this component:
|
|
151
215
|
|
|
216
|
+
### Certificate Table
|
|
217
|
+
|
|
218
|
+
Only expected to have 1 certificate for each ID active at the same time. Once a certificate is revoked, it will be be persisted with a version number greater than 0, hence partition it as `cold` data; archived.
|
|
219
|
+
|
|
220
|
+
```sql
|
|
221
|
+
CREATE TABLE IF NOT EXISTS certificate
|
|
222
|
+
(
|
|
223
|
+
created DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
|
224
|
+
updated DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
|
225
|
+
version INT UNSIGNED NOT NULL DEFAULT 0,
|
|
226
|
+
id VARCHAR(64) NOT NULL,
|
|
227
|
+
cert TEXT NOT NULL,
|
|
228
|
+
`key` BLOB NOT NULL,
|
|
229
|
+
key_iv VARBINARY(16) NOT NULL,
|
|
230
|
+
key_salt VARBINARY(16) NOT NULL,
|
|
231
|
+
key_tag VARBINARY(16) NOT NULL,
|
|
232
|
+
pass BLOB NOT NULL,
|
|
233
|
+
pass_iv VARBINARY(16) NOT NULL,
|
|
234
|
+
pass_salt VARBINARY(16) NOT NULL,
|
|
235
|
+
pass_tag VARBINARY(16) NOT NULL,
|
|
236
|
+
validity DATETIME NOT NULL,
|
|
237
|
+
revoked DATETIME NULL,
|
|
238
|
+
|
|
239
|
+
PRIMARY KEY (version, id)
|
|
240
|
+
)
|
|
241
|
+
ENGINE=InnoDB
|
|
242
|
+
PARTITION BY RANGE (version)
|
|
243
|
+
(
|
|
244
|
+
PARTITION p_hot VALUES LESS THAN (1),
|
|
245
|
+
PARTITION p_cold VALUES LESS THAN MAXVALUE
|
|
246
|
+
)
|
|
247
|
+
```
|
|
248
|
+
|
|
152
249
|
### Event Table
|
|
153
250
|
|
|
154
251
|
```sql
|
|
@@ -283,6 +380,8 @@ ENGINE=InnoDB
|
|
|
283
380
|
|
|
284
381
|
### Log Table
|
|
285
382
|
|
|
383
|
+
Partition on timestamp to make it possible to archive logs.
|
|
384
|
+
|
|
286
385
|
```sql
|
|
287
386
|
CREATE TABLE IF NOT EXISTS log
|
|
288
387
|
(
|
|
@@ -324,72 +423,84 @@ npm test
|
|
|
324
423
|
▶ @superhero/eventflow-db
|
|
325
424
|
▶ Setup table schemas
|
|
326
425
|
▶ Persist a hub
|
|
327
|
-
✔ Read online hubs (
|
|
426
|
+
✔ Read online hubs (8.808208ms)
|
|
328
427
|
|
|
329
428
|
▶ Persisting an event should generate an ID if not provided
|
|
330
|
-
✔ Read an event by id should return the same data as when persisted the event (
|
|
429
|
+
✔ Read an event by id should return the same data as when persisted the event (9.057985ms)
|
|
331
430
|
|
|
332
431
|
▶ Schedule a persisted event
|
|
333
|
-
✔ Read all scheduled events (5.
|
|
334
|
-
✔ Update scheduled event as executed (
|
|
335
|
-
✔ Update scheduled event as success (
|
|
336
|
-
✔ Update scheduled event as failed (
|
|
337
|
-
✔ Schedule a persisted event (
|
|
432
|
+
✔ Read all scheduled events (5.28951ms)
|
|
433
|
+
✔ Update scheduled event as executed (11.686935ms)
|
|
434
|
+
✔ Update scheduled event as success (10.393756ms)
|
|
435
|
+
✔ Update scheduled event as failed (9.877872ms)
|
|
436
|
+
✔ Schedule a persisted event (50.493271ms)
|
|
338
437
|
|
|
339
438
|
▶ Publish a persisted event
|
|
340
|
-
✔ Update published event to consumed by hub (
|
|
341
|
-
✔ Update published event to consumed by spoke (
|
|
342
|
-
✔ Update published event to success (
|
|
343
|
-
✔ Update published event to failed (
|
|
344
|
-
✔ Update published event to orphan (
|
|
345
|
-
✔ Publish a persisted event (
|
|
439
|
+
✔ Update published event to consumed by hub (8.985592ms)
|
|
440
|
+
✔ Update published event to consumed by spoke (10.847144ms)
|
|
441
|
+
✔ Update published event to success (8.945934ms)
|
|
442
|
+
✔ Update published event to failed (12.743366ms)
|
|
443
|
+
✔ Update published event to orphan (12.484305ms)
|
|
444
|
+
✔ Publish a persisted event (69.042999ms)
|
|
346
445
|
|
|
347
446
|
▶ Persist event cpid association
|
|
348
|
-
✔ Read events by domain and cpid (
|
|
349
|
-
✔ Read associated cpid by event id (
|
|
350
|
-
✔ Delete associated cpid by event id (
|
|
351
|
-
✔ Read deleted associated cpid by event id returns empty (
|
|
352
|
-
✔ Persist event cpid association (
|
|
447
|
+
✔ Read events by domain and cpid (6.375096ms)
|
|
448
|
+
✔ Read associated cpid by event id (6.539711ms)
|
|
449
|
+
✔ Delete associated cpid by event id (35.785772ms)
|
|
450
|
+
✔ Read deleted associated cpid by event id returns empty (3.44164ms)
|
|
451
|
+
✔ Persist event cpid association (63.474382ms)
|
|
353
452
|
|
|
354
453
|
▶ Persist event eid association
|
|
355
|
-
✔ Read events by eid (3.
|
|
356
|
-
✔ Read events by domain and eid (
|
|
357
|
-
✔ Read associated eid by event id (
|
|
358
|
-
✔ Delete associated eid by event id (
|
|
359
|
-
✔ Read deleted associated eid by event id returns empty (
|
|
360
|
-
✔ Persist event eid association (
|
|
454
|
+
✔ Read events by eid (3.186193ms)
|
|
455
|
+
✔ Read events by domain and eid (3.211094ms)
|
|
456
|
+
✔ Read associated eid by event id (5.22712ms)
|
|
457
|
+
✔ Delete associated eid by event id (4.791241ms)
|
|
458
|
+
✔ Read deleted associated eid by event id returns empty (2.82022ms)
|
|
459
|
+
✔ Persist event eid association (25.839658ms)
|
|
361
460
|
|
|
362
461
|
▶ Delete event
|
|
363
|
-
✔ Reading a deleted event rejects (2.
|
|
364
|
-
✔ Delete event (
|
|
462
|
+
✔ Reading a deleted event rejects (2.870914ms)
|
|
463
|
+
✔ Delete event (12.001935ms)
|
|
365
464
|
|
|
366
465
|
▶ By domain and pid
|
|
367
|
-
✔ Read event by domain and pid (
|
|
368
|
-
✔ Delete event by domain and pid (
|
|
369
|
-
✔ Read empty eventlog by domain and pid (2.
|
|
370
|
-
✔ By domain and pid (
|
|
371
|
-
✔ Persisting an event should generate an ID if not provided (
|
|
372
|
-
|
|
373
|
-
✔ Persist log (
|
|
374
|
-
✔ Update hub to quit (
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
✔
|
|
379
|
-
|
|
380
|
-
|
|
466
|
+
✔ Read event by domain and pid (4.653075ms)
|
|
467
|
+
✔ Delete event by domain and pid (6.649683ms)
|
|
468
|
+
✔ Read empty eventlog by domain and pid (2.870288ms)
|
|
469
|
+
✔ By domain and pid (19.564013ms)
|
|
470
|
+
✔ Persisting an event should generate an ID if not provided (257.977724ms)
|
|
471
|
+
|
|
472
|
+
✔ Persist log (8.236839ms)
|
|
473
|
+
✔ Update hub to quit (11.86896ms)
|
|
474
|
+
|
|
475
|
+
▶ Certificate management
|
|
476
|
+
✔ Persist a certificate (9.410534ms)
|
|
477
|
+
✔ Persisting a duplicate certificate should return false (3.669139ms)
|
|
478
|
+
✔ Read a persisted certificate by id (9.817305ms)
|
|
479
|
+
✔ Reading a non-existing certificate should reject with an error (3.705119ms)
|
|
480
|
+
|
|
481
|
+
▶ Revoke a persisted certificate
|
|
482
|
+
✔ Reading a revoked certificate should reject with an error (3.894204ms)
|
|
483
|
+
✔ Revoke a persisted certificate (14.21005ms)
|
|
484
|
+
✔ Certificate management (44.130336ms)
|
|
485
|
+
✔ Persist a hub (339.721847ms)
|
|
486
|
+
|
|
487
|
+
✔ Reading a non existing event should reject with an error (6.280731ms)
|
|
488
|
+
✔ Setup table schemas (431.031157ms)
|
|
489
|
+
✔ @superhero/eventflow-db (436.106715ms)
|
|
490
|
+
|
|
491
|
+
tests 43
|
|
381
492
|
suites 1
|
|
382
|
-
pass
|
|
493
|
+
pass 43
|
|
383
494
|
|
|
384
|
-
|
|
495
|
+
-------------------------------------------------------------------------------------------------------------------------
|
|
385
496
|
file | line % | branch % | funcs % | uncovered lines
|
|
386
|
-
|
|
497
|
+
-------------------------------------------------------------------------------------------------------------------------
|
|
387
498
|
config.js | 100.00 | 100.00 | 100.00 |
|
|
388
|
-
index.js |
|
|
499
|
+
index.js | 69.41 | 56.25 | 97.92 | 43-48 58-62 73-77 88-92 103-107 118-122 133-137 148-153 186-191 203-207…
|
|
389
500
|
index.test.js | 100.00 | 100.00 | 100.00 |
|
|
390
|
-
|
|
391
|
-
all files |
|
|
392
|
-
|
|
501
|
+
-------------------------------------------------------------------------------------------------------------------------
|
|
502
|
+
all files | 79.42 | 70.83 | 98.92 |
|
|
503
|
+
-------------------------------------------------------------------------------------------------------------------------
|
|
393
504
|
```
|
|
394
505
|
|
|
395
506
|
## License
|
package/index.js
CHANGED
|
@@ -33,16 +33,31 @@ export default class DB
|
|
|
33
33
|
await this.gateway.close()
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
async
|
|
36
|
+
async createTableCertificate()
|
|
37
37
|
{
|
|
38
38
|
try
|
|
39
39
|
{
|
|
40
|
-
await this.gateway.query('
|
|
40
|
+
await this.gateway.query('certificate/schema')
|
|
41
41
|
}
|
|
42
42
|
catch(reason)
|
|
43
43
|
{
|
|
44
|
-
const error = new Error('could not create table
|
|
45
|
-
error.code = '
|
|
44
|
+
const error = new Error('could not create table certificate')
|
|
45
|
+
error.code = 'E_EVENTFLOW_DB_CREATE_TABLE_CERTIFICATE'
|
|
46
|
+
error.cause = reason
|
|
47
|
+
throw error
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async createTableEvent()
|
|
52
|
+
{
|
|
53
|
+
try
|
|
54
|
+
{
|
|
55
|
+
await this.gateway.query('event/schema')
|
|
56
|
+
}
|
|
57
|
+
catch(reason)
|
|
58
|
+
{
|
|
59
|
+
const error = new Error('could not create table event')
|
|
60
|
+
error.code = 'E_EVENTFLOW_DB_CREATE_TABLE_EVENT'
|
|
46
61
|
error.cause = reason
|
|
47
62
|
throw error
|
|
48
63
|
}
|
|
@@ -78,68 +93,69 @@ export default class DB
|
|
|
78
93
|
}
|
|
79
94
|
}
|
|
80
95
|
|
|
81
|
-
async
|
|
96
|
+
async createTableEventPublished()
|
|
82
97
|
{
|
|
83
98
|
try
|
|
84
99
|
{
|
|
85
|
-
await this.gateway.query('
|
|
100
|
+
await this.gateway.query('event_published/schema')
|
|
86
101
|
}
|
|
87
102
|
catch(reason)
|
|
88
103
|
{
|
|
89
|
-
const error = new Error('could not create table
|
|
90
|
-
error.code = '
|
|
104
|
+
const error = new Error('could not create table event_published')
|
|
105
|
+
error.code = 'E_EVENTFLOW_DB_CREATE_TABLE_EVENT_PUBLISHED'
|
|
91
106
|
error.cause = reason
|
|
92
107
|
throw error
|
|
93
108
|
}
|
|
94
109
|
}
|
|
95
110
|
|
|
96
|
-
async
|
|
111
|
+
async createTableEventScheduled()
|
|
97
112
|
{
|
|
98
113
|
try
|
|
99
114
|
{
|
|
100
|
-
await this.gateway.query('
|
|
115
|
+
await this.gateway.query('event_scheduled/schema')
|
|
101
116
|
}
|
|
102
117
|
catch(reason)
|
|
103
118
|
{
|
|
104
|
-
const error = new Error('could not create table
|
|
105
|
-
error.code = '
|
|
119
|
+
const error = new Error('could not create table event_schedule')
|
|
120
|
+
error.code = 'E_EVENTFLOW_DB_CREATE_TABLE_EVENT_SCHEDULED'
|
|
106
121
|
error.cause = reason
|
|
107
122
|
throw error
|
|
108
123
|
}
|
|
109
124
|
}
|
|
110
125
|
|
|
111
|
-
async
|
|
126
|
+
async createTableHub()
|
|
112
127
|
{
|
|
113
128
|
try
|
|
114
129
|
{
|
|
115
|
-
await this.gateway.query('
|
|
130
|
+
await this.gateway.query('hub/schema')
|
|
116
131
|
}
|
|
117
132
|
catch(reason)
|
|
118
133
|
{
|
|
119
|
-
const error = new Error('could not create table
|
|
120
|
-
error.code = '
|
|
134
|
+
const error = new Error('could not create table hub')
|
|
135
|
+
error.code = 'E_EVENTFLOW_DB_CREATE_TABLE_HUB'
|
|
121
136
|
error.cause = reason
|
|
122
137
|
throw error
|
|
123
138
|
}
|
|
124
139
|
}
|
|
125
140
|
|
|
126
|
-
async
|
|
141
|
+
async createTableLog()
|
|
127
142
|
{
|
|
128
143
|
try
|
|
129
144
|
{
|
|
130
|
-
await this.gateway.query('
|
|
145
|
+
await this.gateway.query('log/schema')
|
|
131
146
|
}
|
|
132
147
|
catch(reason)
|
|
133
148
|
{
|
|
134
|
-
const error = new Error('could not create table
|
|
135
|
-
error.code = '
|
|
149
|
+
const error = new Error('could not create table log')
|
|
150
|
+
error.code = 'E_EVENTFLOW_DB_CREATE_TABLE_LOG'
|
|
136
151
|
error.cause = reason
|
|
137
152
|
throw error
|
|
138
|
-
}
|
|
153
|
+
}
|
|
139
154
|
}
|
|
140
155
|
|
|
141
156
|
async setupTableSchemas()
|
|
142
157
|
{
|
|
158
|
+
await this.createTableCertificate()
|
|
143
159
|
await this.createTableHub()
|
|
144
160
|
await this.createTableEvent()
|
|
145
161
|
await this.createTableEventCpid()
|
|
@@ -659,4 +675,68 @@ export default class DB
|
|
|
659
675
|
throw error
|
|
660
676
|
}
|
|
661
677
|
}
|
|
678
|
+
|
|
679
|
+
async readCertificate(id)
|
|
680
|
+
{
|
|
681
|
+
let result
|
|
682
|
+
|
|
683
|
+
try
|
|
684
|
+
{
|
|
685
|
+
result = await this.gateway.query('certificate/read', [ id ])
|
|
686
|
+
}
|
|
687
|
+
catch(reason)
|
|
688
|
+
{
|
|
689
|
+
const error = new Error(`could not read certificate by id: ${id}`)
|
|
690
|
+
error.code = 'E_EVENTFLOW_DB_CERTIFICATE_READ'
|
|
691
|
+
error.cause = reason
|
|
692
|
+
throw error
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
if(0 === result.length)
|
|
696
|
+
{
|
|
697
|
+
const error = new Error(`certificate not found by id: ${id}`)
|
|
698
|
+
error.code = 'E_EVENTFLOW_DB_CERTIFICATE_NOT_FOUND'
|
|
699
|
+
throw error
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
return result[0]
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
async persistCertificate(certificate)
|
|
706
|
+
{
|
|
707
|
+
try
|
|
708
|
+
{
|
|
709
|
+
const result = await this.gateway.query('certificate/persist', [ certificate ])
|
|
710
|
+
return result.affectedRows > 0
|
|
711
|
+
}
|
|
712
|
+
catch(reason)
|
|
713
|
+
{
|
|
714
|
+
if('ER_DUP_ENTRY' === reason.code)
|
|
715
|
+
{
|
|
716
|
+
return false
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
const error = new Error(`could not persist certificate`)
|
|
720
|
+
error.code = 'E_EVENTFLOW_DB_CERTIFICATE_PERSIST'
|
|
721
|
+
error.cause = reason
|
|
722
|
+
error.certificate = certificate
|
|
723
|
+
throw error
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
async revokeCertificate(id)
|
|
728
|
+
{
|
|
729
|
+
try
|
|
730
|
+
{
|
|
731
|
+
const result = await this.gateway.query('certificate/revoke', [ id, id ])
|
|
732
|
+
return result.affectedRows > 0
|
|
733
|
+
}
|
|
734
|
+
catch(reason)
|
|
735
|
+
{
|
|
736
|
+
const error = new Error(`could not revoke certificate by id: ${id}`)
|
|
737
|
+
error.code = 'E_EVENTFLOW_DB_CERTIFICATE_REVOKE'
|
|
738
|
+
error.cause = reason
|
|
739
|
+
throw error
|
|
740
|
+
}
|
|
741
|
+
}
|
|
662
742
|
}
|
package/index.test.js
CHANGED
|
@@ -252,6 +252,71 @@ suite('@superhero/eventflow-db', async () =>
|
|
|
252
252
|
const updated = await db.updateHubToQuit(hub.id)
|
|
253
253
|
assert.ok(updated, 'Hub should be updated to quit')
|
|
254
254
|
})
|
|
255
|
+
|
|
256
|
+
await sub.test('Certificate management', async (sub) =>
|
|
257
|
+
{
|
|
258
|
+
const
|
|
259
|
+
id = Date.now().toString(36),
|
|
260
|
+
crt =
|
|
261
|
+
{
|
|
262
|
+
id,
|
|
263
|
+
validity : new Date(new Date().toISOString().substring(0, 19)),
|
|
264
|
+
cert : 'test_certificate_value',
|
|
265
|
+
key : Buffer.from('test_key'),
|
|
266
|
+
key_iv : Buffer.from('test_key_iv'),
|
|
267
|
+
key_salt : Buffer.from('test_key_salt'),
|
|
268
|
+
key_tag : Buffer.from('test_key_tag'),
|
|
269
|
+
pass : Buffer.from('test_pass'),
|
|
270
|
+
pass_iv : Buffer.from('test_pass_iv'),
|
|
271
|
+
pass_salt : Buffer.from('test_pass_salt'),
|
|
272
|
+
pass_tag : Buffer.from('test_pass_tag')
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
await sub.test('Persist a certificate', async () =>
|
|
276
|
+
{
|
|
277
|
+
const persisted = await db.persistCertificate(crt)
|
|
278
|
+
assert.ok(persisted, 'Certificate should be persisted')
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
await sub.test('Persisting a duplicate certificate should return false', async () =>
|
|
282
|
+
{
|
|
283
|
+
const duplicatePersisted = await db.persistCertificate(crt)
|
|
284
|
+
assert.equal(duplicatePersisted, false, 'Duplicate certificate should not be persisted')
|
|
285
|
+
})
|
|
286
|
+
|
|
287
|
+
await sub.test('Read a persisted certificate by id', async () =>
|
|
288
|
+
{
|
|
289
|
+
const readCert = await db.readCertificate(id)
|
|
290
|
+
|
|
291
|
+
for(const key in crt)
|
|
292
|
+
{
|
|
293
|
+
assert.deepEqual(readCert[key], crt[key], 'Read certificate should match the persisted certificate')
|
|
294
|
+
}
|
|
295
|
+
})
|
|
296
|
+
|
|
297
|
+
await sub.test('Reading a non-existing certificate should reject with an error', async () =>
|
|
298
|
+
{
|
|
299
|
+
await assert.rejects(
|
|
300
|
+
db.readCertificate('ROOT', 'non_existing_id'),
|
|
301
|
+
{ code: 'E_EVENTFLOW_DB_CERTIFICATE_NOT_FOUND' },
|
|
302
|
+
'Should throw an error when certificate is not found'
|
|
303
|
+
)
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
await sub.test('Revoke a persisted certificate', async (sub) =>
|
|
307
|
+
{
|
|
308
|
+
const revoked = await db.revokeCertificate(id)
|
|
309
|
+
assert.ok(revoked, 'Certificate should be revoked')
|
|
310
|
+
await sub.test('Reading a revoked certificate should reject with an error', async () =>
|
|
311
|
+
{
|
|
312
|
+
await assert.rejects(
|
|
313
|
+
db.readCertificate(id),
|
|
314
|
+
{ code: 'E_EVENTFLOW_DB_CERTIFICATE_NOT_FOUND' },
|
|
315
|
+
'Revoked certificate should not be readable'
|
|
316
|
+
)
|
|
317
|
+
})
|
|
318
|
+
})
|
|
319
|
+
})
|
|
255
320
|
})
|
|
256
321
|
|
|
257
322
|
await sub.test('Reading a non existing event should reject with an error', async () =>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@superhero/eventflow-db",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.2",
|
|
4
4
|
"description": "Eventflow db is a set of common database logic in the eventflow ecosystem.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"eventflow"
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"@superhero/locator": "4.2.0"
|
|
21
21
|
},
|
|
22
22
|
"scripts": {
|
|
23
|
-
"build": "docker run --rm --name eventflow-mysql -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=eventflow -p 3306:3306 -d mysql:latest",
|
|
23
|
+
"test-build": "docker ps -q -f name=eventflow-mysql | grep -q . && docker stop eventflow-mysql; docker run --rm --name eventflow-mysql -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=eventflow -p 3306:3306 --health-cmd=\"mysqladmin ping -h 127.0.0.1 -uroot -proot --silent || exit 1\" --health-interval=10s --health-timeout=5s --health-retries=5 -d mysql:latest; until [ \"$(docker inspect --format='{{.State.Health.Status}}' eventflow-mysql)\" == \"healthy\" ]; do sleep 1; done; npm test",
|
|
24
24
|
"test": "node --trace-warnings --test --experimental-test-coverage"
|
|
25
25
|
},
|
|
26
26
|
"author": {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
UPDATE certificate AS c
|
|
2
|
+
LEFT JOIN
|
|
3
|
+
(
|
|
4
|
+
SELECT id, COUNT(*) AS new_version
|
|
5
|
+
FROM certificate
|
|
6
|
+
WHERE id = ?
|
|
7
|
+
) sub
|
|
8
|
+
ON c.id = sub.id
|
|
9
|
+
SET c.revoked = UTC_TIMESTAMP(),
|
|
10
|
+
c.version = sub.new_version
|
|
11
|
+
WHERE c.id = ?
|
|
12
|
+
AND c.version = 0
|
|
13
|
+
AND c.revoked IS NULL
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS certificate
|
|
2
|
+
(
|
|
3
|
+
created DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
|
4
|
+
updated DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
|
5
|
+
version INT UNSIGNED NOT NULL DEFAULT 0,
|
|
6
|
+
id VARCHAR(64) NOT NULL,
|
|
7
|
+
cert TEXT NOT NULL,
|
|
8
|
+
`key` BLOB NOT NULL,
|
|
9
|
+
key_iv VARBINARY(16) NOT NULL,
|
|
10
|
+
key_salt VARBINARY(16) NOT NULL,
|
|
11
|
+
key_tag VARBINARY(16) NOT NULL,
|
|
12
|
+
pass BLOB NOT NULL,
|
|
13
|
+
pass_iv VARBINARY(16) NOT NULL,
|
|
14
|
+
pass_salt VARBINARY(16) NOT NULL,
|
|
15
|
+
pass_tag VARBINARY(16) NOT NULL,
|
|
16
|
+
validity DATETIME NOT NULL,
|
|
17
|
+
revoked DATETIME NULL,
|
|
18
|
+
|
|
19
|
+
PRIMARY KEY (version, id)
|
|
20
|
+
)
|
|
21
|
+
ENGINE=InnoDB
|
|
22
|
+
PARTITION BY RANGE (version)
|
|
23
|
+
(
|
|
24
|
+
PARTITION p_hot VALUES LESS THAN (1),
|
|
25
|
+
PARTITION p_cold VALUES LESS THAN MAXVALUE
|
|
26
|
+
)
|