gamerpc 7.1.1 → 7.1.3
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/auth3.0.md +189 -0
- package/package.json +13 -15
- package/src/utils/secp256k1.js +79 -101
- package/src/utils/socket.io.min.js +7 -7
- package/test/game/auth.js +1 -1
- package/test/game/crm.js +1 -1
- package/test/utils/secp256k1.js +444 -0
- package/webpack.config.js +16 -9
- package/.babelrc +0 -16
- package/test/game/mgr.js +0 -80
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* secp256k1 加密单元测试
|
|
3
|
+
* 使用已知测试向量,验证 @noble/secp256k1 封装层与 elliptic 的等价性
|
|
4
|
+
*
|
|
5
|
+
* 测试向量来源:
|
|
6
|
+
* - RFC 6979 (Deterministic ECDSA)
|
|
7
|
+
* - Bitcoin BIP32 test vectors
|
|
8
|
+
* - secp256k1 标准测试向量
|
|
9
|
+
*/
|
|
10
|
+
const assert = require('assert');
|
|
11
|
+
const secp = require('../../src/utils/secp256k1');
|
|
12
|
+
|
|
13
|
+
// ============================================================
|
|
14
|
+
// Helper
|
|
15
|
+
// ============================================================
|
|
16
|
+
const hex = (buf) => Buffer.isBuffer(buf) ? buf.toString('hex') : buf;
|
|
17
|
+
|
|
18
|
+
describe('secp256k1 封装层单元测试', function () {
|
|
19
|
+
|
|
20
|
+
// ==========================================================
|
|
21
|
+
// 1. 密钥生成
|
|
22
|
+
// ==========================================================
|
|
23
|
+
describe('密钥生成', function () {
|
|
24
|
+
it('generatePrivateKey: 生成 32 字节私钥', function () {
|
|
25
|
+
const priv = secp.generatePrivateKey();
|
|
26
|
+
assert(Buffer.isBuffer(priv));
|
|
27
|
+
assert.strictEqual(priv.length, 32);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('generatePrivateKey: 连续两次生成的私钥不同', function () {
|
|
31
|
+
const a = secp.generatePrivateKey();
|
|
32
|
+
const b = secp.generatePrivateKey();
|
|
33
|
+
assert(!a.equals(b));
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('privateKeyVerify: 有效私钥返回 true', function () {
|
|
37
|
+
const priv = secp.generatePrivateKey();
|
|
38
|
+
assert.strictEqual(secp.privateKeyVerify(priv), true);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('privateKeyVerify: 全零私钥返回 false', function () {
|
|
42
|
+
assert.strictEqual(secp.privateKeyVerify(Buffer.alloc(32, 0)), false);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('privateKeyVerify: 超范围私钥返回 false', function () {
|
|
46
|
+
// n = FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
|
|
47
|
+
const n = Buffer.from('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141', 'hex');
|
|
48
|
+
assert.strictEqual(secp.privateKeyVerify(n), false);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('privateKeyVerify: 长度不是 32 返回 false', function () {
|
|
52
|
+
assert.strictEqual(secp.privateKeyVerify(Buffer.alloc(31, 1)), false);
|
|
53
|
+
assert.strictEqual(secp.privateKeyVerify(Buffer.alloc(33, 1)), false);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// ==========================================================
|
|
58
|
+
// 2. 公钥创建与验证
|
|
59
|
+
// ==========================================================
|
|
60
|
+
describe('公钥操作', function () {
|
|
61
|
+
// 已知测试向量:私钥 1 → 压缩公钥
|
|
62
|
+
// priv=1 → pub=0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798
|
|
63
|
+
const PRIV_ONE = Buffer.from('0000000000000000000000000000000000000000000000000000000000000001', 'hex');
|
|
64
|
+
const PUB_ONE_COMPRESSED = '0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798'.toLowerCase();
|
|
65
|
+
const PUB_ONE_UNCOMPRESSED = '0479BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8'.toLowerCase();
|
|
66
|
+
|
|
67
|
+
it('publicKeyCreate: 已知私钥生成压缩公钥', function () {
|
|
68
|
+
const pub = secp.publicKeyCreate(PRIV_ONE, true);
|
|
69
|
+
assert.strictEqual(hex(pub), PUB_ONE_COMPRESSED);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('publicKeyCreate: 已知私钥生成非压缩公钥', function () {
|
|
73
|
+
const pub = secp.publicKeyCreate(PRIV_ONE, false);
|
|
74
|
+
assert.strictEqual(hex(pub), PUB_ONE_UNCOMPRESSED);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('publicKeyCreate: 默认生成压缩公钥', function () {
|
|
78
|
+
const pub = secp.publicKeyCreate(PRIV_ONE);
|
|
79
|
+
assert.strictEqual(pub.length, 33);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('publicKeyConvert: 压缩→非压缩', function () {
|
|
83
|
+
const compressed = secp.publicKeyCreate(PRIV_ONE, true);
|
|
84
|
+
const uncompressed = secp.publicKeyConvert(compressed, false);
|
|
85
|
+
assert.strictEqual(hex(uncompressed), PUB_ONE_UNCOMPRESSED);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('publicKeyConvert: 非压缩→压缩', function () {
|
|
89
|
+
const uncompressed = secp.publicKeyCreate(PRIV_ONE, false);
|
|
90
|
+
const compressed = secp.publicKeyConvert(uncompressed, true);
|
|
91
|
+
assert.strictEqual(hex(compressed), PUB_ONE_COMPRESSED);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('publicKeyVerify: 有效公钥返回 true', function () {
|
|
95
|
+
assert.strictEqual(secp.publicKeyVerify(Buffer.from(PUB_ONE_COMPRESSED, 'hex')), true);
|
|
96
|
+
assert.strictEqual(secp.publicKeyVerify(Buffer.from(PUB_ONE_UNCOMPRESSED, 'hex')), true);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('publicKeyVerify: 无效公钥返回 false', function () {
|
|
100
|
+
assert.strictEqual(secp.publicKeyVerify(Buffer.alloc(33, 0)), false);
|
|
101
|
+
assert.strictEqual(secp.publicKeyVerify(Buffer.alloc(0)), false);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('generateKey → publicKeyCreate: 生成密钥对一致性', function () {
|
|
105
|
+
for (let i = 0; i < 10; i++) {
|
|
106
|
+
const priv = secp.generatePrivateKey();
|
|
107
|
+
const pubC = secp.publicKeyCreate(priv, true);
|
|
108
|
+
const pubU = secp.publicKeyCreate(priv, false);
|
|
109
|
+
// 验证压缩/非压缩表示同一公钥
|
|
110
|
+
const converted = secp.publicKeyConvert(pubC, false);
|
|
111
|
+
assert.strictEqual(hex(converted), hex(pubU));
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// ==========================================================
|
|
117
|
+
// 3. 签名与验证 (RFC 6979 确定性签名)
|
|
118
|
+
// ==========================================================
|
|
119
|
+
describe('签名与验证', function () {
|
|
120
|
+
// RFC 6979 Appendix A.2.5 测试向量
|
|
121
|
+
// SHA-256("sample")
|
|
122
|
+
const RFC6979_PRIV = Buffer.from('C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721', 'hex');
|
|
123
|
+
const RFC6979_MSG = Buffer.from('AF2BDBE1AA9B6EC1E2ADE1D694F41FC71A831D0268E9891562113D8A62ADD1BF', 'hex');
|
|
124
|
+
// 这个私钥对 "sample" 签名应该能验证
|
|
125
|
+
const SAMPLE_HASH = Buffer.from('AF2BDBE1AA9B6EC1E2ADE1D694F41FC71A831D0268E9891562113D8A62ADD1BF', 'hex');
|
|
126
|
+
|
|
127
|
+
it('sign: 生成 DER 签名', function () {
|
|
128
|
+
const sig = secp.sign(SAMPLE_HASH, RFC6979_PRIV);
|
|
129
|
+
assert(Buffer.isBuffer(sig));
|
|
130
|
+
// DER 签名长度大约 70-73 字节
|
|
131
|
+
assert(sig.length >= 68 && sig.length <= 73, `unexpected sig length: ${sig.length}`);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('sign → verify: 签名后可成功验证 (同一密钥)', function () {
|
|
135
|
+
const priv = secp.generatePrivateKey();
|
|
136
|
+
const pub = secp.publicKeyCreate(priv, true);
|
|
137
|
+
const msg = secp.generatePrivateKey(); // 32 random bytes
|
|
138
|
+
|
|
139
|
+
const sig = secp.sign(msg, priv);
|
|
140
|
+
const result = secp.verify(msg, sig, pub);
|
|
141
|
+
assert.strictEqual(result, true);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('verify: 错误公钥无法验证', function () {
|
|
145
|
+
const privA = secp.generatePrivateKey();
|
|
146
|
+
const privB = secp.generatePrivateKey();
|
|
147
|
+
const pubB = secp.publicKeyCreate(privB, true);
|
|
148
|
+
const msg = secp.generatePrivateKey();
|
|
149
|
+
|
|
150
|
+
const sig = secp.sign(msg, privA);
|
|
151
|
+
const result = secp.verify(msg, sig, pubB);
|
|
152
|
+
assert.strictEqual(result, false);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('verify: 篡改消息无法验证', function () {
|
|
156
|
+
const priv = secp.generatePrivateKey();
|
|
157
|
+
const pub = secp.publicKeyCreate(priv, true);
|
|
158
|
+
const msg = secp.generatePrivateKey();
|
|
159
|
+
|
|
160
|
+
const sig = secp.sign(msg, priv);
|
|
161
|
+
const tampered = Buffer.from(msg);
|
|
162
|
+
tampered[0] ^= 1;
|
|
163
|
+
const result = secp.verify(tampered, sig, pub);
|
|
164
|
+
assert.strictEqual(result, false);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('verify: 空签名返回 false', function () {
|
|
168
|
+
const priv = secp.generatePrivateKey();
|
|
169
|
+
const pub = secp.publicKeyCreate(priv, true);
|
|
170
|
+
const msg = secp.generatePrivateKey();
|
|
171
|
+
assert.strictEqual(secp.verify(msg, Buffer.alloc(0), pub), false);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it('verify: 空公钥返回 false', function () {
|
|
175
|
+
const priv = secp.generatePrivateKey();
|
|
176
|
+
const msg = secp.generatePrivateKey();
|
|
177
|
+
const sig = secp.sign(msg, priv);
|
|
178
|
+
assert.strictEqual(secp.verify(msg, sig, Buffer.alloc(0)), false);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it('确定性: 同一消息和私钥产生相同签名', function () {
|
|
182
|
+
const priv = secp.generatePrivateKey();
|
|
183
|
+
const msg = secp.generatePrivateKey();
|
|
184
|
+
const sig1 = secp.sign(msg, priv);
|
|
185
|
+
const sig2 = secp.sign(msg, priv);
|
|
186
|
+
assert(hex(sig1) === hex(sig2), 'deterministic signatures must be identical');
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('不同消息产生不同签名', function () {
|
|
190
|
+
const priv = secp.generatePrivateKey();
|
|
191
|
+
const msg1 = secp.generatePrivateKey();
|
|
192
|
+
const msg2 = secp.generatePrivateKey();
|
|
193
|
+
// 确保消息不同
|
|
194
|
+
while (msg1.equals(msg2)) {
|
|
195
|
+
msg2.fill(0);
|
|
196
|
+
msg2[0] = msg1[0] ^ 0xFF;
|
|
197
|
+
}
|
|
198
|
+
const sig1 = secp.sign(msg1, priv);
|
|
199
|
+
const sig2 = secp.sign(msg2, priv);
|
|
200
|
+
assert(!sig1.equals(sig2));
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
// ==========================================================
|
|
205
|
+
// 4. DER 格式转换
|
|
206
|
+
// ==========================================================
|
|
207
|
+
describe('DER 格式转换', function () {
|
|
208
|
+
it('toDER → fromDER: 往返转换', function () {
|
|
209
|
+
const priv = secp.generatePrivateKey();
|
|
210
|
+
const msg = secp.generatePrivateKey();
|
|
211
|
+
const der = secp.sign(msg, priv);
|
|
212
|
+
|
|
213
|
+
const compact = secp.fromDER(der);
|
|
214
|
+
assert.strictEqual(compact.length, 64);
|
|
215
|
+
|
|
216
|
+
const der2 = secp.toDER(compact);
|
|
217
|
+
// 重新解析验证
|
|
218
|
+
const compact2 = secp.fromDER(der2);
|
|
219
|
+
assert.strictEqual(hex(compact), hex(compact2));
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('toDER → verify: 往返后可验证', function () {
|
|
223
|
+
const priv = secp.generatePrivateKey();
|
|
224
|
+
const pub = secp.publicKeyCreate(priv, true);
|
|
225
|
+
const msg = secp.generatePrivateKey();
|
|
226
|
+
const der = secp.sign(msg, priv);
|
|
227
|
+
|
|
228
|
+
const compact = secp.fromDER(der);
|
|
229
|
+
const der2 = secp.toDER(compact);
|
|
230
|
+
|
|
231
|
+
assert.strictEqual(secp.verify(msg, der2, pub), true);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it('fromDER: 无效输入不崩溃', function () {
|
|
235
|
+
// 无效 DER 应该抛出或返回异常值
|
|
236
|
+
try {
|
|
237
|
+
secp.fromDER(Buffer.alloc(10, 0xFF));
|
|
238
|
+
// 如果没抛异常也是可以接受的,只要不崩溃
|
|
239
|
+
} catch (e) {
|
|
240
|
+
// 预期可能抛异常
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
it('toDER → isLowS: 低S值验证', function () {
|
|
245
|
+
const priv = secp.generatePrivateKey();
|
|
246
|
+
const msg = secp.generatePrivateKey();
|
|
247
|
+
const der = secp.sign(msg, priv);
|
|
248
|
+
assert.strictEqual(secp.isLowS(der), true, 'normal signature should have low S');
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it('isLowS: 无效输入返回 false', function () {
|
|
252
|
+
assert.strictEqual(secp.isLowS(Buffer.alloc(0)), false);
|
|
253
|
+
assert.strictEqual(secp.isLowS(Buffer.alloc(10, 0xFF)), false);
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
// ==========================================================
|
|
258
|
+
// 5. ECDH 密钥交换
|
|
259
|
+
// ==========================================================
|
|
260
|
+
describe('ECDH 密钥交换', function () {
|
|
261
|
+
it('ecdh: 双方计算得到相同的共享密钥', function () {
|
|
262
|
+
const privA = secp.generatePrivateKey();
|
|
263
|
+
const privB = secp.generatePrivateKey();
|
|
264
|
+
const pubA = secp.publicKeyCreate(privA, true);
|
|
265
|
+
const pubB = secp.publicKeyCreate(privB, true);
|
|
266
|
+
|
|
267
|
+
const sharedA = secp.ecdh(pubB, privA); // A用B的公钥+自己的私钥
|
|
268
|
+
const sharedB = secp.ecdh(pubA, privB); // B用A的公钥+自己的私钥
|
|
269
|
+
|
|
270
|
+
assert.strictEqual(hex(sharedA), hex(sharedB));
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it('ecdh: 返回 32 字节', function () {
|
|
274
|
+
const privA = secp.generatePrivateKey();
|
|
275
|
+
const privB = secp.generatePrivateKey();
|
|
276
|
+
const pubB = secp.publicKeyCreate(privB, true);
|
|
277
|
+
|
|
278
|
+
const shared = secp.ecdh(pubB, privA);
|
|
279
|
+
assert.strictEqual(shared.length, 32);
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
it('ecdh: 不同密钥对产生不同共享密钥', function () {
|
|
283
|
+
const p1 = secp.generatePrivateKey();
|
|
284
|
+
const p2 = secp.generatePrivateKey();
|
|
285
|
+
const p3 = secp.generatePrivateKey();
|
|
286
|
+
const pub2 = secp.publicKeyCreate(p2, true);
|
|
287
|
+
const pub3 = secp.publicKeyCreate(p3, true);
|
|
288
|
+
|
|
289
|
+
const s12 = secp.ecdh(pub2, p1);
|
|
290
|
+
const s13 = secp.ecdh(pub3, p1);
|
|
291
|
+
assert(!s12.equals(s13));
|
|
292
|
+
});
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
// ==========================================================
|
|
296
|
+
// 6. 公钥恢复
|
|
297
|
+
// ==========================================================
|
|
298
|
+
describe('公钥恢复', function () {
|
|
299
|
+
it('recover: 可从签名恢复原公钥', function () {
|
|
300
|
+
const priv = secp.generatePrivateKey();
|
|
301
|
+
const pub = secp.publicKeyCreate(priv, true);
|
|
302
|
+
const msg = secp.generatePrivateKey();
|
|
303
|
+
const sig = secp.sign(msg, priv);
|
|
304
|
+
|
|
305
|
+
// 尝试 4 种 recovery id
|
|
306
|
+
let recovered = null;
|
|
307
|
+
for (let j = 0; j < 4; j++) {
|
|
308
|
+
const rec = secp.recover(msg, sig, j, true);
|
|
309
|
+
if (rec && hex(rec) === hex(pub)) {
|
|
310
|
+
recovered = rec;
|
|
311
|
+
break;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
assert(recovered !== null, 'should recover the original public key');
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
it('recover: 无效签名返回 null', function () {
|
|
318
|
+
const msg = secp.generatePrivateKey();
|
|
319
|
+
const invalidSig = Buffer.alloc(70, 0xFF);
|
|
320
|
+
const result = secp.recover(msg, invalidSig, 0, true);
|
|
321
|
+
assert.strictEqual(result, null);
|
|
322
|
+
});
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
// ==========================================================
|
|
326
|
+
// 7. Tweak 操作
|
|
327
|
+
// ==========================================================
|
|
328
|
+
describe('Tweak 操作', function () {
|
|
329
|
+
it('privateKeyTweakAdd: (key + tweak) % n', function () {
|
|
330
|
+
const priv = secp.generatePrivateKey();
|
|
331
|
+
const tweak = Buffer.from('0000000000000000000000000000000000000000000000000000000000000001', 'hex');
|
|
332
|
+
const tweaked = secp.privateKeyTweakAdd(priv, tweak);
|
|
333
|
+
assert.strictEqual(tweaked.length, 32);
|
|
334
|
+
assert(secp.privateKeyVerify(tweaked));
|
|
335
|
+
// 加1后应该与原私钥不同(除非原私钥恰好是n-1)
|
|
336
|
+
if (hex(priv) !== 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140') {
|
|
337
|
+
assert(!tweaked.equals(priv));
|
|
338
|
+
}
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
it('publicKeyTweakAdd: G * tweak + pubkey', function () {
|
|
342
|
+
const priv = secp.generatePrivateKey();
|
|
343
|
+
const pub = secp.publicKeyCreate(priv, true);
|
|
344
|
+
const tweak = Buffer.from('0000000000000000000000000000000000000000000000000000000000000001', 'hex');
|
|
345
|
+
|
|
346
|
+
const tweakedPub = secp.publicKeyTweakAdd(pub, tweak, true);
|
|
347
|
+
assert.strictEqual(tweakedPub.length, 33);
|
|
348
|
+
assert(secp.publicKeyVerify(tweakedPub));
|
|
349
|
+
|
|
350
|
+
// 验证:手动加1后私钥的公钥应等于原公钥加G
|
|
351
|
+
const tweakedPriv = secp.privateKeyTweakAdd(priv, tweak);
|
|
352
|
+
const expectedPub = secp.publicKeyCreate(tweakedPriv, true);
|
|
353
|
+
assert.strictEqual(hex(tweakedPub), hex(expectedPub),
|
|
354
|
+
'publicKeyTweakAdd result should match privateKeyTweakAdd + publicKeyCreate');
|
|
355
|
+
});
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
// ==========================================================
|
|
359
|
+
// 8. binding 常量
|
|
360
|
+
// ==========================================================
|
|
361
|
+
describe('常量', function () {
|
|
362
|
+
it('binding: 始终为 false (非native)', function () {
|
|
363
|
+
assert.strictEqual(secp.binding, false);
|
|
364
|
+
});
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
// ==========================================================
|
|
368
|
+
// 9. verifyData + secret 集成测试
|
|
369
|
+
// ==========================================================
|
|
370
|
+
describe('上层集成: verifyData & Secret', function () {
|
|
371
|
+
const verifyData = require('../../src/utils/verifyData');
|
|
372
|
+
const Secret = require('../../src/utils/secret');
|
|
373
|
+
|
|
374
|
+
it('generateKey → signObj → verifyObj: 完整流程', function () {
|
|
375
|
+
const keys = verifyData.generateKey();
|
|
376
|
+
assert.strictEqual(typeof keys.private, 'string');
|
|
377
|
+
assert.strictEqual(typeof keys.public, 'string');
|
|
378
|
+
assert.strictEqual(keys.private.length, 64); // hex of 32 bytes
|
|
379
|
+
assert.strictEqual(keys.public.length, 66); // hex of 33 bytes (compressed)
|
|
380
|
+
|
|
381
|
+
const obj = { action: 'transfer', amount: 100, to: 'abc' };
|
|
382
|
+
const sig = verifyData.signObj(obj, keys.private);
|
|
383
|
+
assert.strictEqual(typeof sig, 'string');
|
|
384
|
+
|
|
385
|
+
const ok = verifyData.verifyObj(obj, sig, keys.public);
|
|
386
|
+
assert.strictEqual(ok, true);
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
it('generateKey: 用已知私钥生成公钥', function () {
|
|
390
|
+
const privHex = '0000000000000000000000000000000000000000000000000000000000000001';
|
|
391
|
+
const keys = verifyData.generateKey(privHex);
|
|
392
|
+
assert.strictEqual(keys.private, privHex);
|
|
393
|
+
// 压缩公钥,33字节 hex = 66 chars
|
|
394
|
+
assert.strictEqual(keys.public.length, 66);
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
it('verifyObj: 错误签名应失败', function () {
|
|
398
|
+
const keysA = verifyData.generateKey();
|
|
399
|
+
const keysB = verifyData.generateKey();
|
|
400
|
+
const obj = { msg: 'test' };
|
|
401
|
+
const sig = verifyData.signObj(obj, keysA.private);
|
|
402
|
+
// 用B的公钥验证A的签名 → 应该失败
|
|
403
|
+
const ok = verifyData.verifyObj(obj, sig, keysB.public);
|
|
404
|
+
assert.strictEqual(ok, false);
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
it('verifyObj: 篡改消息应失败', function () {
|
|
408
|
+
const keys = verifyData.generateKey();
|
|
409
|
+
const obj = { msg: 'test' };
|
|
410
|
+
const sig = verifyData.signObj(obj, keys.private);
|
|
411
|
+
const tampered = { msg: 'hacked' };
|
|
412
|
+
const ok = verifyData.verifyObj(tampered, sig, keys.public);
|
|
413
|
+
assert.strictEqual(ok, false);
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
it('Secret: 创建、握手、获取公钥', function () {
|
|
417
|
+
const secret = new Secret();
|
|
418
|
+
const pub = secret.input.getPublicKey();
|
|
419
|
+
assert(Buffer.isBuffer(pub));
|
|
420
|
+
assert.strictEqual(pub.length, 33);
|
|
421
|
+
|
|
422
|
+
const priv = secret.input.privateKey;
|
|
423
|
+
assert(Buffer.isBuffer(priv));
|
|
424
|
+
assert.strictEqual(priv.length, 32);
|
|
425
|
+
assert(secp.privateKeyVerify(priv));
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
it('Secret: 双方握手后共享密钥一致', function () {
|
|
429
|
+
const alice = new Secret();
|
|
430
|
+
const bob = new Secret();
|
|
431
|
+
|
|
432
|
+
const alicePub = alice.input.getPublicKey();
|
|
433
|
+
const bobPub = bob.input.getPublicKey();
|
|
434
|
+
|
|
435
|
+
alice.input.init(bobPub);
|
|
436
|
+
bob.output.init(alicePub);
|
|
437
|
+
|
|
438
|
+
// 双方应完成 ECDH
|
|
439
|
+
assert.strictEqual(alice.input.sid.length, 32);
|
|
440
|
+
assert.strictEqual(bob.output.sid.length, 32);
|
|
441
|
+
});
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
});
|
package/webpack.config.js
CHANGED
|
@@ -5,15 +5,22 @@ module.exports = {
|
|
|
5
5
|
entry: './src/index.js',
|
|
6
6
|
output: {
|
|
7
7
|
path: path.resolve(__dirname, 'lib'),
|
|
8
|
-
filename: `gamerpc${config.version}.js
|
|
8
|
+
filename: `gamerpc${config.version}.js`,
|
|
9
|
+
library: {
|
|
10
|
+
name: 'toolkit',
|
|
11
|
+
type: 'umd',
|
|
12
|
+
},
|
|
13
|
+
globalObject: 'this',
|
|
9
14
|
},
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
target: 'web',
|
|
16
|
+
mode: 'production',
|
|
17
|
+
resolve: {
|
|
18
|
+
fallback: {
|
|
19
|
+
"assert": require.resolve("assert/"),
|
|
20
|
+
"buffer": require.resolve("buffer/"),
|
|
21
|
+
"crypto": require.resolve("crypto-browserify"),
|
|
22
|
+
"stream": require.resolve("stream-browserify"),
|
|
23
|
+
"util": require.resolve("util/"),
|
|
16
24
|
}
|
|
17
|
-
]
|
|
18
25
|
}
|
|
19
|
-
}
|
|
26
|
+
};
|
package/.babelrc
DELETED
package/test/game/mgr.js
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 联机单元测试:远程管理
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
const assert = require('assert')
|
|
6
|
-
|
|
7
|
-
//引入游戏云连接器,创建连接器对象
|
|
8
|
-
const {gameconn} = require('../../src/')
|
|
9
|
-
const remote = new gameconn({
|
|
10
|
-
"UrlHead": "http", //协议选择: http/https
|
|
11
|
-
"webserver": {
|
|
12
|
-
//注意:如果需要负载均衡,这里一般指定负载均衡服务器地址,否则直接填写业务主机地址
|
|
13
|
-
"host": "127.0.0.1", //远程主机地址
|
|
14
|
-
"authPort": 9601, //签证主机端口
|
|
15
|
-
"port": 9901 //远程主机端口
|
|
16
|
-
},
|
|
17
|
-
}).setFetch(require('node-fetch')); //设置node环境下兼容的fetch函数
|
|
18
|
-
|
|
19
|
-
//切换为长连模式
|
|
20
|
-
//remote.setmode(remote.CommMode.ws);
|
|
21
|
-
|
|
22
|
-
//这里需要填充管理员登录信息
|
|
23
|
-
let admin = {
|
|
24
|
-
openid: '',
|
|
25
|
-
openkey: '',
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
describe('远程管理', () => {
|
|
29
|
-
it.skip('执行索引服远程指令 remote.printInfo', async () => {
|
|
30
|
-
await remote.init(/*初始化连接器,只保留原始配置信息*/).login({
|
|
31
|
-
domain: 'CoreOfIndex',
|
|
32
|
-
openid: admin.openid,
|
|
33
|
-
openkey: admin.openkey,
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
let msg = await remote.fetching({func: "remote.printInfo"});
|
|
37
|
-
console.log(msg);
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it.skip('透过索引服执行业务服远程指令 remote.command printInfo', async () => {
|
|
41
|
-
await remote.init(/*初始化连接器,只保留原始配置信息*/).login({
|
|
42
|
-
domain: 'CoreOfIndex',
|
|
43
|
-
openid: admin.openid,
|
|
44
|
-
openkey: admin.openkey,
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
let msg = await remote.fetching({func: "remote.command", data: ['printInfo', 'CoreOfChickIOS', '1']});
|
|
48
|
-
console.log(msg);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('模拟用户注册并登录', async () => {
|
|
52
|
-
//执行登录操作,通过配置对象传入用户信息,并指定签证方式为两阶段认证
|
|
53
|
-
let auth = {
|
|
54
|
-
cpId: 'c376af60-cab5-11ed-90e8-25399b14218a',
|
|
55
|
-
addr: '10000000',
|
|
56
|
-
name: 'bookman',
|
|
57
|
-
bonus: '',
|
|
58
|
-
time: Date.now(),
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
//需要正确填充 auth.sign, 此处采用模拟命令填充, 注意命令 testSign 只在测试模式下开启
|
|
62
|
-
await remote.init().login({
|
|
63
|
-
domain: 'CoreOfIndex',
|
|
64
|
-
openid: admin.openid,
|
|
65
|
-
openkey: admin.openkey,
|
|
66
|
-
});
|
|
67
|
-
let msg = await remote.fetching({func: "remote.command", data: ['testSign', 'CoreOfChickIOS', '1', auth]});
|
|
68
|
-
auth.sign = msg['CoreOfChickIOS.1'].sign;
|
|
69
|
-
|
|
70
|
-
let ret = await remote.init().login({
|
|
71
|
-
domain: 'CoreOfChickIOS', //登录域
|
|
72
|
-
openid: `bxs.${auth.addr}`, //用户登录标识,含验证方式
|
|
73
|
-
auth,
|
|
74
|
-
});
|
|
75
|
-
if(!!ret) {
|
|
76
|
-
ret = await remote.fetching({func: "test.echo"});
|
|
77
|
-
assert(ret.code == 0);
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
});
|