gamerpc 8.0.8 → 9.0.1
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 +0 -12
- package/auth3.0.md +189 -0
- package/docs/2026.07.25.md +209 -0
- package/index.js +68 -1
- package/package.json +33 -21
- package/src/authConn.js +591 -0
- package/src/gameConn.js +10 -0
- package/src/index.js +106 -645
- package/src/remote.js +637 -0
- package/src/utils/secp256k1.js +79 -101
- package/src/utils/socket.io.min.js +7 -0
- package/src/utils/util.js +157 -85
- package/test/game/auth.js +1 -1
- package/test/game/crm.js +1 -1
- package/test/test.html +47 -29
- package/test/utils/secp256k1.js +444 -0
- package/webpack.config.js +41 -13
- package/.babelrc +0 -16
- package/test/game/kow.js +0 -43
- package/test/game/mgr.js +0 -80
package/src/index.js
CHANGED
|
@@ -1,679 +1,140 @@
|
|
|
1
|
-
//const {encrypt, decrypt, createHmac} = require('./utils/util');
|
|
2
|
-
const {stringify, NotifyType, extendObj, CommStatus, clone, ReturnCodeName, ReturnCode, CommMode, io} = require('./utils/util');
|
|
3
|
-
const EventEmitter = require('events').EventEmitter;
|
|
4
|
-
const Indicator = require('./utils/Indicator');
|
|
5
|
-
// const assert = require('./utils/assert')
|
|
6
|
-
// let {sha1, hash160, hash256, verifyData, generateKey, signObj, verifyObj, verifyAddress} = require('./utils/verifyData');
|
|
7
|
-
// const Secret = require('./utils/secret')
|
|
8
|
-
|
|
9
1
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
2
|
+
* gamerpc V9.0.0 - 游戏云/区块链统一工具包
|
|
3
|
+
*
|
|
4
|
+
* 合并 V7.1.3 (auth3.0 分支) 和 V9.0.0 (V8.0.8 继承)。
|
|
5
|
+
*
|
|
6
|
+
* 提供两大核心连接器:
|
|
7
|
+
* 1. gameConn - 游戏云服务器连接器 (连接 Gamecloud,发起RPC调用,订阅推送)
|
|
8
|
+
* 2. conn/authConn - 区块链全节点连接器 (连接 Gamegold Core 对等网络,钱包操作)
|
|
9
|
+
*
|
|
10
|
+
* 同时提供区块链密码学工具函数和通用工具函数。
|
|
15
11
|
*/
|
|
16
|
-
class Remote {
|
|
17
|
-
constructor(options) {
|
|
18
|
-
this.rpcMode = CommMode.post;
|
|
19
|
-
this.loginMode = Indicator.inst();
|
|
20
|
-
this.configOri = options; //读取并保存初始配置,不会修改
|
|
21
|
-
this.config = clone(this.configOri); //复制一份配置信息,有可能修改
|
|
22
|
-
this.notifyHandles = {};
|
|
23
|
-
this.userInfo = {};
|
|
24
|
-
//事件管理器
|
|
25
|
-
this.events = new EventEmitter();
|
|
26
|
-
//状态管理器
|
|
27
|
-
this.status = Indicator.inst(options.status);
|
|
28
|
-
|
|
29
|
-
//两阶段登录时,用户输入验证码时提交此事件
|
|
30
|
-
this.events.on('authcode', async code => {
|
|
31
|
-
console.log('gameconn: commit authcode', code);
|
|
32
|
-
await this.setSign(code).login();
|
|
33
|
-
})
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* 修改通讯模式
|
|
38
|
-
* @param {*} $mode 通讯模式
|
|
39
|
-
* @param {*} cb 建立连接时的回调
|
|
40
|
-
*/
|
|
41
|
-
setmode($mode) {
|
|
42
|
-
this.rpcMode = $mode;
|
|
43
|
-
return this;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* 创建通讯连接组件
|
|
48
|
-
* @param {*} ip
|
|
49
|
-
* @param {*} port
|
|
50
|
-
*/
|
|
51
|
-
async createSocket() {
|
|
52
|
-
let port = this.config.webserver.port;
|
|
53
|
-
let host = this.config.webserver.host;
|
|
54
|
-
let url = this.config.webserver.url;
|
|
55
|
-
|
|
56
|
-
this.close();
|
|
57
|
-
|
|
58
|
-
if(!url) {
|
|
59
|
-
this.socket = io(`${this.config.UrlHead}://${host}:${port}`, {'force new connection': true});
|
|
60
|
-
} else {
|
|
61
|
-
this.socket = io(`${this.config.UrlHead}://${url}`, {'force new connection': true});
|
|
62
|
-
}
|
|
63
|
-
this.socket.on('notify', ret => {//监听推送消息
|
|
64
|
-
if(this.notifyHandles[ret.type]) {
|
|
65
|
-
this.notifyHandles[ret.type](ret.info);
|
|
66
|
-
}
|
|
67
|
-
else if(!!this.notifyHandles['0']){
|
|
68
|
-
this.notifyHandles['0'](ret.info);
|
|
69
|
-
}
|
|
70
|
-
})
|
|
71
|
-
.on('disconnect', ()=>{//断线重连
|
|
72
|
-
console.log('gameconn: socket disconnected');
|
|
73
|
-
this.events.emit('comm', {status: 'disconnect'});
|
|
74
|
-
this.socket.needConnect = true;
|
|
75
|
-
setTimeout(()=>{
|
|
76
|
-
if(!!this.socket.needConnect) {
|
|
77
|
-
this.socket.needConnect = false;
|
|
78
|
-
this.socket.connect();
|
|
79
|
-
}
|
|
80
|
-
}, 1500);
|
|
81
|
-
}).on('connect', () => { //连接消息
|
|
82
|
-
console.log('gameconn: socket connected');
|
|
83
|
-
this.events.emit('comm', {status: 'connect'});
|
|
84
|
-
}).on('error', () => {
|
|
85
|
-
this.events.emit('comm', {status: 'error'});
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
let self = this;
|
|
89
|
-
let prom = new Promise(resolve => {
|
|
90
|
-
self.events.on('comm', async msg => {
|
|
91
|
-
if(msg.status == 'connect') {
|
|
92
|
-
resolve();
|
|
93
|
-
}
|
|
94
|
-
})
|
|
95
|
-
});
|
|
96
|
-
return prom;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* 获取签名数据集
|
|
101
|
-
*/
|
|
102
|
-
async getSign() {
|
|
103
|
-
console.log('gameconn: getSign');
|
|
104
|
-
//此处根据实际需要,发起了基于HTTP请求的认证访问,和本身创建时指定的通讯模式无关。
|
|
105
|
-
let router = this.userInfo.openid.split('.')[0]; //openid一般由代表验证模式的前缀,加上代表节点类型的后缀组成, 获取签名接口的路由路径默认等于其前缀
|
|
106
|
-
let msg = await this.getRequest({}, router);
|
|
107
|
-
|
|
108
|
-
//客户端从模拟网关取得了签名集
|
|
109
|
-
if(!msg) {
|
|
110
|
-
return false;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
this.userInfo.auth = msg;
|
|
114
|
-
|
|
115
|
-
console.log('gameconn: getSign', msg);
|
|
116
|
-
|
|
117
|
-
return true;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* 设置验证码
|
|
122
|
-
* @param {*} code
|
|
123
|
-
*/
|
|
124
|
-
setSign(code) {
|
|
125
|
-
if(!!this.userInfo) {
|
|
126
|
-
if(this.loginMode.check(CommStatus.reqSign)) {
|
|
127
|
-
this.status.set(CommStatus.signCode);
|
|
128
|
-
this.userInfo.auth = this.userInfo.auth || {};
|
|
129
|
-
this.userInfo.auth.captcha = code;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
return this;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* 登录并获得令牌
|
|
137
|
-
*/
|
|
138
|
-
async getToken() {
|
|
139
|
-
if(!this.userInfo
|
|
140
|
-
|| (this.loginMode.check(CommStatus.reqLb) && !this.status.check(CommStatus.lb))
|
|
141
|
-
|| (this.loginMode.check(CommStatus.reqSign) && !this.status.check(CommStatus.signCode)
|
|
142
|
-
|| this.status.check(CommStatus.logined))
|
|
143
|
-
) {
|
|
144
|
-
//不满足登录的前置条件或已经登录
|
|
145
|
-
return false;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
//将签证发送到服务端进行验证
|
|
149
|
-
console.log('gameconn: getToken');
|
|
150
|
-
let msg = await this.fetching({
|
|
151
|
-
'func': 'login.UserLogin',
|
|
152
|
-
"oemInfo": this.userInfo,
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
if(!!msg) {
|
|
156
|
-
console.log('gameconn: getToken', msg.code);
|
|
157
|
-
if(msg.code == ReturnCode.Success && !!msg.data) {
|
|
158
|
-
if(typeof msg.data == 'object') {
|
|
159
|
-
extendObj(this.userInfo, msg.data);
|
|
160
|
-
}
|
|
161
|
-
this.status.set(CommStatus.logined);
|
|
162
|
-
this.events.emit('logined', {code:0, data:{currentAuthority: this.userInfo.currentAuthority}});
|
|
163
|
-
|
|
164
|
-
return true;
|
|
165
|
-
} else {
|
|
166
|
-
this.events.emit('logined', {code: msg.code});
|
|
167
|
-
}
|
|
168
|
-
} else {
|
|
169
|
-
console.log('gameconn: getToken failed');
|
|
170
|
-
this.events.emit('logined', {code:-1});
|
|
171
|
-
}
|
|
172
|
-
return false;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* 清空先前的缓存状态
|
|
177
|
-
*/
|
|
178
|
-
clearCache() {
|
|
179
|
-
if(this.userInfo) {
|
|
180
|
-
this.userInfo.token = null;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* 执行负载均衡流程
|
|
186
|
-
* @param {*} ui
|
|
187
|
-
*/
|
|
188
|
-
async setLB(force) {
|
|
189
|
-
if(!this.userInfo) {
|
|
190
|
-
//尚未设置有效的用户数据,无法执行
|
|
191
|
-
return false;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
if(!force && this.status.check(CommStatus.lb)) {
|
|
195
|
-
//已经执行过LB操作,且非强制执行模式
|
|
196
|
-
return true;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
this.clearCache();
|
|
200
|
-
this.status.init();
|
|
201
|
-
|
|
202
|
-
console.log('gameconn: lb');
|
|
203
|
-
let msg = await this.locate(this.configOri.webserver.host, this.configOri.webserver.port, this.configOri.webserver.url).getRequest({"func": "lb.getServerInfo", "oemInfo":{"domain": this.userInfo.domain, "openid": this.userInfo.openid}});
|
|
204
|
-
|
|
205
|
-
if(!!msg && msg.code == ReturnCode.Success) {
|
|
206
|
-
console.log('gameconn: lb', msg.data);
|
|
207
|
-
this.status.set(CommStatus.lb);
|
|
208
|
-
this.locate(msg.data.ip, msg.data.port, msg.data.url);
|
|
209
|
-
return true;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
console.log('gameconn: lb failed');
|
|
213
|
-
return false;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* 登录流程
|
|
218
|
-
* @param {Object} options
|
|
219
|
-
* @param {Boolean} options.force 强制登录
|
|
220
|
-
*/
|
|
221
|
-
async login(options) {
|
|
222
|
-
options = options || {};
|
|
223
|
-
if(options.force) {
|
|
224
|
-
this.clearCache();
|
|
225
|
-
this.status.init();
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
if(options.domain) {
|
|
229
|
-
let authmode = options.openid.split('.')[0];
|
|
230
|
-
switch(authmode) {
|
|
231
|
-
case 'bxs': { //新增一种验证模式
|
|
232
|
-
this.setUserInfo({
|
|
233
|
-
domain: options.domain, //认证模式
|
|
234
|
-
openid: options.openid, //用户证书
|
|
235
|
-
openkey: options.openkey, //中间证书,经由Auth服务器转换成 openid 下发给客户端
|
|
236
|
-
auth: options.auth, //验证信息
|
|
237
|
-
}, CommStatus.reqLb);
|
|
238
|
-
|
|
239
|
-
break;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
case 'authwx': {
|
|
243
|
-
this.setUserInfo({
|
|
244
|
-
domain: options.domain, //认证模式
|
|
245
|
-
openkey: options.openkey, //中间证书,经由Auth服务器转换成 openid 下发给客户端
|
|
246
|
-
}, CommStatus.reqLb | CommStatus.reqOpenId);
|
|
247
|
-
|
|
248
|
-
break;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
case 'auth2step': {
|
|
252
|
-
this.setUserInfo({
|
|
253
|
-
domain: options.domain, //验证模式
|
|
254
|
-
openid: options.openid, //用户证书
|
|
255
|
-
openkey: options.openkey, //用户证书
|
|
256
|
-
addrType: options.addrType, //验证方式
|
|
257
|
-
address: options.address, //验证地址
|
|
258
|
-
}, CommStatus.reqLb | CommStatus.reqSign);
|
|
259
|
-
|
|
260
|
-
break;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
case 'authpwd': {
|
|
264
|
-
this.setUserInfo({
|
|
265
|
-
domain: options.domain, //验证模式
|
|
266
|
-
openid: options.openid, //用户证书
|
|
267
|
-
openkey: options.openkey, //用户密码
|
|
268
|
-
}, CommStatus.reqLb);
|
|
269
|
-
|
|
270
|
-
break;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
default: {
|
|
274
|
-
this.setUserInfo({
|
|
275
|
-
domain: options.domain || 'official', //验证模式
|
|
276
|
-
openid: options.openid, //登录名称
|
|
277
|
-
openkey: options.openkey, //登录密码
|
|
278
|
-
});
|
|
279
|
-
break;
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
if(this.status.check(CommStatus.logined)) {
|
|
285
|
-
return false;
|
|
286
|
-
}
|
|
287
12
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
if(!(await this.setLB())) {
|
|
297
|
-
//如果负载均衡失败,抛出异常,外围程序负责重新调用
|
|
298
|
-
throw(new Error('lb error'));
|
|
299
|
-
} else {
|
|
300
|
-
this.status.set(CommStatus.lb);
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
//检测执行两阶段验证
|
|
306
|
-
//两阶段验证模式(例如浏览器直接登录):执行此操作,访问控制器方法 authmode.auth 获取签名对象,并赋值到 userInfo.auth 字段,服务端同时会将关联验证码通过邮件或短信下发
|
|
307
|
-
//第三方授权登录模式(例如微信或QQ登录)跳过此步
|
|
308
|
-
if(this.loginMode.check(CommStatus.reqSign)) {
|
|
309
|
-
if(!this.status.check(CommStatus.sign)) {
|
|
310
|
-
//如果需要两阶段验证且尚未执行,执行如下语句
|
|
311
|
-
if(!(await this.getSign())) {
|
|
312
|
-
//如果负载均衡失败,抛出异常,外围程序负责重新调用
|
|
313
|
-
throw(new Error('get sign error'));
|
|
314
|
-
} else {
|
|
315
|
-
this.status.set(CommStatus.sign);
|
|
316
|
-
return true;
|
|
317
|
-
}
|
|
318
|
-
} else {
|
|
319
|
-
return await this.getToken();
|
|
320
|
-
}
|
|
321
|
-
} else {
|
|
322
|
-
return await this.getToken();
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
/**
|
|
327
|
-
* 设置用户信息
|
|
328
|
-
* 1. 支持局部设定模式
|
|
329
|
-
* 2. 每次设置,状态类缓存会被清除,通讯状态被复原
|
|
330
|
-
* @param {Object} ui {openid}
|
|
331
|
-
* @param {Number} st 登录流程描述符
|
|
332
|
-
*/
|
|
333
|
-
setUserInfo(ui, st) {
|
|
334
|
-
this.userInfo = this.userInfo || {};
|
|
335
|
-
|
|
336
|
-
this.clearCache();
|
|
337
|
-
|
|
338
|
-
//设置登录模式
|
|
339
|
-
if(!!st) {
|
|
340
|
-
this.loginMode.init(st);
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
//合并对象数据
|
|
344
|
-
extendObj(this.userInfo, ui);
|
|
345
|
-
|
|
346
|
-
return this;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
/**
|
|
350
|
-
* 设置服务端推送报文的监控句柄,支持链式调用
|
|
351
|
-
* @param cb 回调
|
|
352
|
-
* @param etype
|
|
353
|
-
* @returns {Remote}
|
|
354
|
-
*/
|
|
355
|
-
watch(cb, etype = '0') {
|
|
356
|
-
this.notifyHandles[etype] = cb;
|
|
357
|
-
return this;
|
|
358
|
-
}
|
|
359
|
-
/**
|
|
360
|
-
* 移除监控句柄
|
|
361
|
-
* @param {*} etype
|
|
362
|
-
*/
|
|
363
|
-
unWatch(etype) {
|
|
364
|
-
if(!!this.notifyHandles[etype]) {
|
|
365
|
-
delete this.notifyHandles[etype];
|
|
366
|
-
}
|
|
367
|
-
return this;
|
|
13
|
+
// V7.1.3: 为数组添加工具方法
|
|
14
|
+
Array.prototype.randObj = function() {
|
|
15
|
+
if (this.length == 0) {
|
|
16
|
+
return null;
|
|
17
|
+
} else if (this.length == 1) {
|
|
18
|
+
return this[0];
|
|
19
|
+
} else {
|
|
20
|
+
return this[(Math.random() * this.length) | 0];
|
|
368
21
|
}
|
|
22
|
+
};
|
|
369
23
|
|
|
370
|
-
|
|
371
|
-
* 判断返回值是否成功
|
|
372
|
-
* @param msg 网络报文
|
|
373
|
-
* @param out 强制打印日志
|
|
374
|
-
* @returns {*}
|
|
375
|
-
*/
|
|
376
|
-
isSuccess(msg, out=false) {
|
|
377
|
-
if(!msg) {
|
|
378
|
-
return false;
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
msg.msg = ReturnCodeName[msg.code];
|
|
382
|
-
|
|
383
|
-
if((msg.code != ReturnCode.Success) || out){
|
|
384
|
-
this.log(msg);
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
return msg.code == ReturnCode.Success;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
/**
|
|
391
|
-
* 直接打印各种对象
|
|
392
|
-
* @param val
|
|
393
|
-
*/
|
|
394
|
-
log(val){
|
|
395
|
-
if(!val){
|
|
396
|
-
console.log('undefined');
|
|
397
|
-
return;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
if(!!val.code){
|
|
401
|
-
val.msg = ReturnCodeName[val.code];
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
switch(typeof val){
|
|
405
|
-
case 'number':
|
|
406
|
-
case 'string':
|
|
407
|
-
case 'boolean':
|
|
408
|
-
console.log(val);
|
|
409
|
-
break;
|
|
410
|
-
case 'function':
|
|
411
|
-
console.log(val());
|
|
412
|
-
break;
|
|
413
|
-
case 'undefined':
|
|
414
|
-
console.log('err: undefined');
|
|
415
|
-
break;
|
|
416
|
-
default:
|
|
417
|
-
console.log(JSON.stringify(val));
|
|
418
|
-
break;
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
get newone(){
|
|
423
|
-
return new Remote(this.configOri).setmode(this.rpcMode);
|
|
424
|
-
}
|
|
24
|
+
const toolkit = exports;
|
|
425
25
|
|
|
426
|
-
|
|
427
|
-
* 获取新的远程对象
|
|
428
|
-
* @returns {Remote}
|
|
429
|
-
*/
|
|
430
|
-
get new(){
|
|
431
|
-
return new Remote(this.configOri).setmode(this.rpcMode);
|
|
432
|
-
}
|
|
26
|
+
// ==================== 核心连接器 ====================
|
|
433
27
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
*/
|
|
438
|
-
async wait (time) {
|
|
439
|
-
await (async (time) => {return new Promise(resolve => {setTimeout(resolve, time);});})(time);
|
|
440
|
-
}
|
|
28
|
+
/** 游戏云连接器 - 用于连接游戏云服务器 */
|
|
29
|
+
toolkit.gameconn = require('./gameConn');
|
|
30
|
+
toolkit.gameConn = toolkit.gameconn; // 别名
|
|
441
31
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
setFetch(fn) {
|
|
447
|
-
this.fetch = fn;
|
|
448
|
-
return this;
|
|
449
|
-
}
|
|
32
|
+
/** 区块链授权式连接器 - 用于连接 Gamegold Core 全节点 */
|
|
33
|
+
const AuthConn = require('./authConn');
|
|
34
|
+
toolkit.conn = AuthConn;
|
|
35
|
+
toolkit.authConn = AuthConn; // 别名
|
|
450
36
|
|
|
451
|
-
|
|
452
|
-
* 向服务端提交请求,默认JSONP模式
|
|
453
|
-
* @param params 命令参数,JSON对象
|
|
454
|
-
* .command 命令名称,格式: obj.func, 可以缩写为 func,此时obj为默认值'index',例如 index.setNewbie 等价于 setNewbie
|
|
455
|
-
* .url 附加url地址
|
|
456
|
-
* @param callback 回调函数
|
|
457
|
-
* @returns {*}
|
|
458
|
-
*/
|
|
459
|
-
async fetching(params) {
|
|
460
|
-
this.parseParams(params);
|
|
37
|
+
// ==================== 区块链密码学工具 ====================
|
|
461
38
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
39
|
+
const verifyData = require('./utils/verifyData');
|
|
40
|
+
const Secret = require('./utils/secret');
|
|
41
|
+
const sha256 = require('./utils/sha256');
|
|
465
42
|
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
this.socket.emit('req', params, msg => {
|
|
473
|
-
resolve(msg);
|
|
474
|
-
});
|
|
475
|
-
});
|
|
43
|
+
// 签名与验证
|
|
44
|
+
toolkit.generateKey = verifyData.generateKey;
|
|
45
|
+
toolkit.signObj = verifyData.signObj;
|
|
46
|
+
toolkit.verifyObj = verifyData.verifyObj;
|
|
47
|
+
toolkit.verifyData = verifyData.verifyData;
|
|
48
|
+
toolkit.verifyAddress = verifyData.verifyAddress;
|
|
476
49
|
|
|
477
|
-
|
|
478
|
-
|
|
50
|
+
// 哈希函数
|
|
51
|
+
toolkit.hash256 = verifyData.hash256;
|
|
52
|
+
toolkit.hash160 = verifyData.hash160;
|
|
53
|
+
toolkit.sha1 = verifyData.sha1;
|
|
54
|
+
toolkit.sha256 = sha256.digest;
|
|
479
55
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
}
|
|
56
|
+
// BIP151 加密流
|
|
57
|
+
toolkit.Secret = Secret;
|
|
483
58
|
|
|
484
|
-
|
|
485
|
-
}
|
|
59
|
+
// ==================== AES 加解密 ====================
|
|
486
60
|
|
|
487
|
-
|
|
488
|
-
* 设定远程服务器地址
|
|
489
|
-
* @param host
|
|
490
|
-
* @param port
|
|
491
|
-
* @returns {Remote}
|
|
492
|
-
*/
|
|
493
|
-
locate(host, port, url) {
|
|
494
|
-
this.config.webserver.host = host;
|
|
495
|
-
this.config.webserver.port = port;
|
|
496
|
-
this.config.webserver.url = url;
|
|
61
|
+
const aes = require('./utils/aes');
|
|
497
62
|
|
|
498
|
-
|
|
499
|
-
|
|
63
|
+
/**
|
|
64
|
+
* AES-CBC 字符串加密(兼容 V7.x API)
|
|
65
|
+
* 编码规则:每字节拆分为高4位和低4位,加97偏移映射到 a-p 字符
|
|
66
|
+
*/
|
|
67
|
+
toolkit.encrypt = function encrypt(key, iv, data) {
|
|
68
|
+
if (!Buffer.isBuffer(key)) key = Buffer.from(key, 'binary');
|
|
69
|
+
if (!Buffer.isBuffer(iv)) iv = Buffer.from(iv, 'binary');
|
|
70
|
+
if (!Buffer.isBuffer(data)) data = Buffer.from(data, 'binary');
|
|
500
71
|
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
*/
|
|
504
|
-
close() {
|
|
505
|
-
if(this.socket){
|
|
506
|
-
this.socket.removeAllListeners();
|
|
507
|
-
this.socket.disconnect();
|
|
508
|
-
this.socket = null;
|
|
509
|
-
}
|
|
72
|
+
var crypted = aes.encipher(data, key, iv);
|
|
73
|
+
crypted = Buffer.from(crypted, 'binary');
|
|
510
74
|
|
|
511
|
-
|
|
75
|
+
let ret = Buffer.alloc(crypted.length * 2);
|
|
76
|
+
for (let i = 0; i < crypted.length; i++) {
|
|
77
|
+
ret[2 * i] = (crypted[i] >> 4) + 97;
|
|
78
|
+
ret[2 * i + 1] = (crypted[i] & 0x0F) + 97;
|
|
512
79
|
}
|
|
80
|
+
return ret.toString('binary');
|
|
81
|
+
};
|
|
513
82
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
83
|
+
/**
|
|
84
|
+
* AES-CBC 字符串解密(兼容 V7.x API)
|
|
85
|
+
*/
|
|
86
|
+
toolkit.decrypt = function decrypt(key, iv, data) {
|
|
87
|
+
if (!Buffer.isBuffer(key)) key = Buffer.from(key, 'binary');
|
|
88
|
+
if (!Buffer.isBuffer(iv)) iv = Buffer.from(iv, 'binary');
|
|
89
|
+
if (!Buffer.isBuffer(data)) data = Buffer.from(data, 'binary');
|
|
519
90
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
this.loginMode.init();
|
|
524
|
-
|
|
525
|
-
return this;
|
|
91
|
+
let ret = Buffer.alloc(data.length / 2);
|
|
92
|
+
for (let i = 0; i < ret.length; i++) {
|
|
93
|
+
ret[i] = ((data[i * 2] - 97) << 4) | (data[i * 2 + 1] - 97);
|
|
526
94
|
}
|
|
527
95
|
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
*/
|
|
532
|
-
parseParams(params) {
|
|
533
|
-
params.func = !!params.func ? params.func : 'index.login';
|
|
534
|
-
//填充自动登录参数
|
|
535
|
-
let arr = params.func.split('.');
|
|
536
|
-
if(arr.length > 1) {
|
|
537
|
-
params.control = arr[0];
|
|
538
|
-
params.func = arr[1];
|
|
539
|
-
} else {
|
|
540
|
-
params.func = arr[0];
|
|
541
|
-
}
|
|
96
|
+
var decoded = aes.decipher(ret, key, iv);
|
|
97
|
+
return decoded.toString('binary');
|
|
98
|
+
};
|
|
542
99
|
|
|
543
|
-
|
|
544
|
-
domain: this.userInfo.domain,
|
|
545
|
-
openid: this.userInfo.openid,
|
|
546
|
-
};
|
|
547
|
-
|
|
548
|
-
if(this.userInfo.openkey) {
|
|
549
|
-
params.oemInfo.openkey = this.userInfo.openkey;
|
|
550
|
-
}
|
|
551
|
-
if(this.userInfo.token) {
|
|
552
|
-
params.oemInfo.token = this.userInfo.token;
|
|
553
|
-
}
|
|
554
|
-
if(this.userInfo.addrType) {
|
|
555
|
-
params.oemInfo.addrType = this.userInfo.addrType;
|
|
556
|
-
}
|
|
557
|
-
if(this.userInfo.address) {
|
|
558
|
-
params.oemInfo.address = this.userInfo.address;
|
|
559
|
-
}
|
|
560
|
-
if(this.userInfo.auth) {
|
|
561
|
-
params.oemInfo.auth = this.userInfo.auth;
|
|
562
|
-
}
|
|
563
|
-
}
|
|
100
|
+
// ==================== HMAC 工具 ====================
|
|
564
101
|
|
|
565
|
-
|
|
566
|
-
* 以 GET 方式访问远程API
|
|
567
|
-
* @param {*} url 远程地址
|
|
568
|
-
*/
|
|
569
|
-
async get(url) {
|
|
570
|
-
const newOptions = { json: true, method: 'GET', mode: 'cors', };
|
|
571
|
-
|
|
572
|
-
newOptions.headers = {
|
|
573
|
-
Accept: 'application/json',
|
|
574
|
-
'Content-Type': 'application/json; charset=utf-8',
|
|
575
|
-
};
|
|
102
|
+
const createHmac = require('create-hmac/browser');
|
|
576
103
|
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
/**
|
|
588
|
-
* 以 POST 方式访问远程API
|
|
589
|
-
* @param {*} url 远程地址
|
|
590
|
-
* @param {*} options body
|
|
591
|
-
*/
|
|
592
|
-
async post(url, options) {
|
|
593
|
-
const newOptions = { json: true, method: 'POST', mode: 'cors', body: JSON.stringify(options) };
|
|
594
|
-
|
|
595
|
-
newOptions.headers = {
|
|
596
|
-
Accept: 'application/json',
|
|
597
|
-
'Content-Type': 'application/json; charset=utf-8',
|
|
598
|
-
};
|
|
104
|
+
/**
|
|
105
|
+
* 利用 HMAC-SHA256 计算访问令牌
|
|
106
|
+
*/
|
|
107
|
+
function signHMAC(token, random) {
|
|
108
|
+
var hmac = createHmac('sha256', random);
|
|
109
|
+
return hmac.update(token).digest('hex');
|
|
110
|
+
}
|
|
599
111
|
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
let ret = await this.fetch(url, newOptions);
|
|
603
|
-
return await ret.json();
|
|
604
|
-
}
|
|
605
|
-
else {
|
|
606
|
-
let ret = await fetch(url, newOptions);
|
|
607
|
-
return await ret.json();
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
catch(e) {
|
|
611
|
-
console.error(e);
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
/**
|
|
616
|
-
* (内部函数)发起基于Http协议的RPC请求
|
|
617
|
-
* @param params
|
|
618
|
-
*/
|
|
619
|
-
async getRequest(params, authControl) {
|
|
620
|
-
this.parseParams(params);
|
|
112
|
+
toolkit.createHmac = createHmac;
|
|
113
|
+
toolkit.signHMAC = signHMAC;
|
|
621
114
|
|
|
622
|
-
|
|
623
|
-
if(!this.config.webserver.url) {
|
|
624
|
-
let port = !!params.port ? params.port : this.config.webserver.port;
|
|
625
|
-
url = !!authControl ? `${this.config.UrlHead}://${this.config.webserver.host}:${port}/${authControl}` : `${this.config.UrlHead}://${this.config.webserver.host}:${port}/index.html`;
|
|
626
|
-
} else {
|
|
627
|
-
url = !!authControl ? `${this.config.UrlHead}://${this.config.webserver.url}/${authControl}` : `${this.config.UrlHead}://${this.config.webserver.url}/index.html`;
|
|
628
|
-
}
|
|
115
|
+
// ==================== 通用工具 ====================
|
|
629
116
|
|
|
630
|
-
|
|
631
|
-
if(ret != '') {
|
|
632
|
-
ret += '&';
|
|
633
|
-
}
|
|
634
|
-
//增加了字段编译,避免特殊字符如汉字对URL拼接造成干扰
|
|
635
|
-
return ret + next + "=" + ((typeof params[next]) == "object" ? encodeURIComponent(JSON.stringify(params[next])) : encodeURIComponent(params[next]));
|
|
636
|
-
}, '');
|
|
117
|
+
const util = require('./utils/util');
|
|
637
118
|
|
|
638
|
-
|
|
639
|
-
|
|
119
|
+
toolkit.assert = require('./utils/assert');
|
|
120
|
+
toolkit.stringify = util.stringify;
|
|
121
|
+
toolkit.extendObj = util.extendObj;
|
|
122
|
+
toolkit.clone = util.clone;
|
|
123
|
+
toolkit.Base64 = util.Base64;
|
|
124
|
+
toolkit.CommMode = util.CommMode;
|
|
125
|
+
toolkit.CommStatus = util.CommStatus;
|
|
126
|
+
toolkit.ReturnCode = util.ReturnCode;
|
|
127
|
+
toolkit.ReturnCodeName = util.ReturnCodeName;
|
|
128
|
+
toolkit.NotifyType = util.NotifyType;
|
|
129
|
+
toolkit.sprintf = util.sprintf;
|
|
130
|
+
toolkit.isHex = util.isHex;
|
|
640
131
|
|
|
641
|
-
|
|
642
|
-
* (内部函数)发起基于Http协议的RPC请求
|
|
643
|
-
* @param params
|
|
644
|
-
*/
|
|
645
|
-
async postRequest(params, authControl) {
|
|
646
|
-
this.parseParams(params);
|
|
132
|
+
// ==================== 全局对象挂载 ====================
|
|
647
133
|
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
let port = !!params.port ? params.port : this.config.webserver.port;
|
|
651
|
-
url = !!authControl ? `${this.config.UrlHead}://${this.config.webserver.host}:${port}/${authControl}` : `${this.config.UrlHead}://${this.config.webserver.host}:${port}/index.html`;
|
|
652
|
-
} else {
|
|
653
|
-
url = !!authControl ? `${this.config.UrlHead}://${this.config.webserver.url}/${authControl}` : `${this.config.UrlHead}://${this.config.webserver.url}/index.html`;
|
|
654
|
-
}
|
|
134
|
+
// V7.1.3: Node.js 环境的 global.toolkit
|
|
135
|
+
global.toolkit = toolkit;
|
|
655
136
|
|
|
656
|
-
|
|
657
|
-
|
|
137
|
+
// V9.0.0: 浏览器 <script> 标签引入时的 window.toolkit
|
|
138
|
+
if (typeof window !== 'undefined') {
|
|
139
|
+
window.toolkit = toolkit;
|
|
658
140
|
}
|
|
659
|
-
|
|
660
|
-
Remote.prototype.CommMode = CommMode;
|
|
661
|
-
// Remote.prototype.createHmac = createHmac;
|
|
662
|
-
// Remote.prototype.assert = assert;
|
|
663
|
-
Remote.prototype.stringify = stringify;
|
|
664
|
-
// Remote.prototype.encrypt = encrypt;
|
|
665
|
-
// Remote.prototype.decrypt = decrypt;
|
|
666
|
-
// Remote.prototype.verifyData = verifyData;
|
|
667
|
-
// Remote.prototype.generateKey = generateKey;
|
|
668
|
-
// Remote.prototype.signObj = signObj;
|
|
669
|
-
// Remote.prototype.verifyObj = verifyObj;
|
|
670
|
-
// Remote.prototype.verifyAddress = verifyAddress;
|
|
671
|
-
Remote.prototype.CommStatus = CommStatus;
|
|
672
|
-
Remote.prototype.ReturnCode = ReturnCode;
|
|
673
|
-
Remote.prototype.NotifyType = NotifyType;
|
|
674
|
-
// Remote.prototype.Secret = Secret;
|
|
675
|
-
// Remote.prototype.hash256 = hash256;
|
|
676
|
-
// Remote.prototype.hash160 = hash160;
|
|
677
|
-
// Remote.prototype.sha1 = sha1;
|
|
678
|
-
|
|
679
|
-
module.exports = Remote;
|