oak-backend-base 4.1.8 → 4.1.9
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/lib/Synchronizer.js +40 -3
- package/package.json +1 -1
package/lib/Synchronizer.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
|
+
const crypto_1 = require("crypto");
|
|
4
5
|
const types_1 = require("oak-domain/lib/types");
|
|
5
6
|
const relationPath_1 = require("oak-domain/lib/utils/relationPath");
|
|
6
7
|
const assert_1 = tslib_1.__importDefault(require("assert"));
|
|
@@ -11,6 +12,31 @@ const uuid_1 = require("oak-domain/lib/utils/uuid");
|
|
|
11
12
|
const lodash_2 = require("lodash");
|
|
12
13
|
const OAK_SYNC_HEADER_ENTITY = 'oak-sync-entity';
|
|
13
14
|
const OAK_SYNC_HEADER_ENTITY_ID = 'oak-sync-entity-id';
|
|
15
|
+
const OAK_SYNC_HEADER_TIMESTAMP = 'oak-sync-timestamp';
|
|
16
|
+
const OAK_SYNC_HEADER_NONCE = 'oak-sync-nonce';
|
|
17
|
+
const OAK_SYNC_HEADER_SIGN = 'oak-sync-sign';
|
|
18
|
+
function generateSignStr(body, ts, nonce) {
|
|
19
|
+
return `${body}\n${ts}\n${nonce}`;
|
|
20
|
+
}
|
|
21
|
+
async function sign(privateKey, body) {
|
|
22
|
+
const ts = Date.now();
|
|
23
|
+
const nonce = await (0, uuid_1.generateNewIdAsync)();
|
|
24
|
+
const sign2 = (0, crypto_1.createSign)('SHA256');
|
|
25
|
+
sign2.update(generateSignStr(body, `${ts}`, nonce));
|
|
26
|
+
sign2.end();
|
|
27
|
+
const signature = sign2.sign(privateKey).toString('hex');
|
|
28
|
+
return {
|
|
29
|
+
ts,
|
|
30
|
+
nonce,
|
|
31
|
+
signature,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function verify(publicKey, body, ts, nonce, signature) {
|
|
35
|
+
const verify2 = (0, crypto_1.createVerify)('SHA256');
|
|
36
|
+
verify2.update(generateSignStr(body, ts, nonce));
|
|
37
|
+
verify2.end();
|
|
38
|
+
return verify2.verify(publicKey, signature, 'hex');
|
|
39
|
+
}
|
|
14
40
|
class Synchronizer {
|
|
15
41
|
config;
|
|
16
42
|
schema;
|
|
@@ -31,14 +57,19 @@ class Synchronizer {
|
|
|
31
57
|
const finalApi = (0, path_1.join)(api, selfEncryptInfo.id);
|
|
32
58
|
channel.queue = [];
|
|
33
59
|
try {
|
|
60
|
+
const body = JSON.stringify(opers);
|
|
61
|
+
const { ts, nonce, signature } = await sign(selfEncryptInfo.privateKey, body);
|
|
34
62
|
const res = await fetch(finalApi, {
|
|
35
63
|
method: 'post',
|
|
36
64
|
headers: {
|
|
37
65
|
'Content-Type': 'application/json',
|
|
38
66
|
[OAK_SYNC_HEADER_ENTITY]: entity,
|
|
39
67
|
[OAK_SYNC_HEADER_ENTITY_ID]: entityId,
|
|
68
|
+
[OAK_SYNC_HEADER_TIMESTAMP]: `${ts}`,
|
|
69
|
+
[OAK_SYNC_HEADER_NONCE]: nonce,
|
|
70
|
+
[OAK_SYNC_HEADER_SIGN]: signature,
|
|
40
71
|
},
|
|
41
|
-
body
|
|
72
|
+
body,
|
|
42
73
|
});
|
|
43
74
|
if (res.status !== 200) {
|
|
44
75
|
throw new Error(`sync数据时,访问api「${finalApi}」的结果不是200。「${res.status}」`);
|
|
@@ -462,7 +493,7 @@ class Synchronizer {
|
|
|
462
493
|
fn: async (context, params, headers, req, body) => {
|
|
463
494
|
// body中是传过来的oper数组信息
|
|
464
495
|
const { entity, entityId } = params;
|
|
465
|
-
const { [OAK_SYNC_HEADER_ENTITY]: meEntity, [OAK_SYNC_HEADER_ENTITY_ID]: meEntityId } = headers;
|
|
496
|
+
const { [OAK_SYNC_HEADER_ENTITY]: meEntity, [OAK_SYNC_HEADER_ENTITY_ID]: meEntityId, [OAK_SYNC_HEADER_NONCE]: syncNonce, [OAK_SYNC_HEADER_TIMESTAMP]: syncTs, [OAK_SYNC_HEADER_SIGN]: syncSign } = headers;
|
|
466
497
|
if (process.env.NODE_ENV === 'development') {
|
|
467
498
|
console.log('接收到来自远端的sync数据', entity, JSON.stringify(body));
|
|
468
499
|
}
|
|
@@ -493,7 +524,13 @@ class Synchronizer {
|
|
|
493
524
|
if (cxtInfo) {
|
|
494
525
|
await context.initialize(cxtInfo);
|
|
495
526
|
}
|
|
496
|
-
|
|
527
|
+
const syncTimestamp = parseInt(syncTs, 10);
|
|
528
|
+
if (!(Date.now() - syncTimestamp < 10000)) {
|
|
529
|
+
throw new Error('同步时钟漂移过长');
|
|
530
|
+
}
|
|
531
|
+
if (!verify(publicKey, JSON.stringify(body), syncTs, syncNonce, syncSign)) {
|
|
532
|
+
throw new Error('sync验签失败');
|
|
533
|
+
}
|
|
497
534
|
const opers = body;
|
|
498
535
|
const ids = opers.map(ele => ele.id);
|
|
499
536
|
const existsIds = (await context.select('oper', {
|