gamerpc 9.0.0 → 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/package.json +7 -8
- package/src/authConn.js +533 -349
- package/src/gameConn.js +3 -4
- package/src/index.js +32 -49
- 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 +3 -3
- package/test/utils/secp256k1.js +444 -0
- package/webpack.config.js +2 -2
- package/.babelrc +0 -16
- package/docs/2026.07.15.md +0 -142
- package/test/game/kow.js +0 -43
- package/test/game/mgr.js +0 -80
package/src/authConn.js
CHANGED
|
@@ -1,396 +1,577 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* authConn - 授权式连接器 (V7.1.
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* 核心功能:
|
|
8
|
-
* - setup() 配置网络类型和连接参数
|
|
9
|
-
* - execute() 执行钱包 RPC 命令
|
|
10
|
-
* - login() WS 模式下的 token 认证登录
|
|
11
|
-
* - watch() 监听推送消息
|
|
12
|
-
* - 支持 WS / HTTP GET / HTTP POST 三种通讯模式
|
|
2
|
+
* authConn - 授权式连接器 (V7.1.3)
|
|
3
|
+
*
|
|
4
|
+
* 完整封装了客户端通过授权模式访问远程全节点的方法,仅仅依赖 create-hmac
|
|
5
|
+
* 可以直接用于 node 环境下的服务端程序,来访问远程全节点丰富的API接口
|
|
6
|
+
* 通过合适的打包程序,也可以用于浏览器环境
|
|
13
7
|
*/
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
const {
|
|
17
|
-
|
|
18
|
-
const
|
|
8
|
+
|
|
9
|
+
const assert = require('./utils/assert')
|
|
10
|
+
const {io, signHMAC, Base64, now, CommStatus, createHmac, ReturnCode, CommMode, NotifyType, encrypt, decrypt, stringify} = require('./utils/util');
|
|
11
|
+
let {sha1, hash160, hash256, verifyData, generateKey, signObj, verifyObj, verifyAddress} = require('./utils/verifyData');
|
|
12
|
+
const Secret = require('./utils/secret')
|
|
19
13
|
|
|
20
14
|
/**
|
|
21
|
-
*
|
|
22
|
-
* @param {String} token 令牌固定量
|
|
23
|
-
* @param {String} random 令牌随机量(从服务端获取)
|
|
24
|
-
* @returns {String} HMAC 签名(hex)
|
|
15
|
+
* 终端配置管理
|
|
25
16
|
*/
|
|
26
|
-
function signHMAC(token, random) {
|
|
27
|
-
var hmac = createHmac('sha256', random);
|
|
28
|
-
let sig = hmac.update(token).digest('hex');
|
|
29
|
-
return sig;
|
|
30
|
-
}
|
|
31
17
|
|
|
32
|
-
class AuthConn
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
this.socketEvents = {};
|
|
59
|
-
this.mode = CommMode.post;
|
|
60
|
-
this.socket = null;
|
|
61
|
-
this.$params = {
|
|
62
|
-
random: null,
|
|
63
|
-
randomTime: null,
|
|
64
|
-
};
|
|
18
|
+
class AuthConn
|
|
19
|
+
{
|
|
20
|
+
constructor() {
|
|
21
|
+
this.defaultNetworkType = 'testnet';
|
|
22
|
+
this.AuthConnConfig = {
|
|
23
|
+
'main': {
|
|
24
|
+
type: 'main',
|
|
25
|
+
ip: '127.0.0.1', //远程服务器地址
|
|
26
|
+
port: 2002, //RPC端口
|
|
27
|
+
head: 'http', //远程服务器通讯协议,分为 http 和 https
|
|
28
|
+
id: 'primary', //默认访问的钱包编号
|
|
29
|
+
apiKey: '', //远程服务器基本校验密码
|
|
30
|
+
cid: '', //授权节点编号,用于访问远程钱包时的认证
|
|
31
|
+
token: '', //授权节点令牌固定量,用于访问远程钱包时的认证
|
|
32
|
+
},
|
|
33
|
+
'testnet': {
|
|
34
|
+
type: 'testnet',
|
|
35
|
+
ip: '127.0.0.1', //远程服务器地址
|
|
36
|
+
port: 2102, //RPC端口
|
|
37
|
+
head: 'http', //远程服务器通讯协议,分为 http 和 https
|
|
38
|
+
id: 'primary', //默认访问的钱包编号
|
|
39
|
+
apiKey: '', //远程服务器基本校验密码
|
|
40
|
+
cid: '', //授权节点编号,用于访问远程钱包时的认证
|
|
41
|
+
token: '', //授权节点令牌固定量,用于访问远程钱包时的认证
|
|
42
|
+
},
|
|
65
43
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
44
|
+
|
|
45
|
+
this.socketEvents = {};
|
|
46
|
+
this.mode = CommMode.post;
|
|
47
|
+
this.socket = null;
|
|
48
|
+
this.$params = {
|
|
49
|
+
random: null,
|
|
50
|
+
randomTime: null,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* 设置通讯模式
|
|
56
|
+
* @param {*} mode 通讯模式
|
|
57
|
+
* @param {*} cb 连接建立时的回调
|
|
58
|
+
*/
|
|
59
|
+
setmode(mode, cb) {
|
|
60
|
+
this.mode = mode;
|
|
61
|
+
if(this.mode == CommMode.ws) {
|
|
62
|
+
this.socketEvents['connect'] = async () => {
|
|
63
|
+
await this.login();
|
|
64
|
+
await this.join();
|
|
65
|
+
if(typeof cb == 'function') {
|
|
66
|
+
await cb();
|
|
82
67
|
}
|
|
83
|
-
|
|
68
|
+
};
|
|
84
69
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
async retoken() {
|
|
94
|
-
let params = this.getTerminalConfig();
|
|
95
|
-
let msg = await this.setmode(CommMode.ws).execute('token.random', [params.cid]);
|
|
96
|
-
if (!!params.structured) {
|
|
97
|
-
msg = msg.result;
|
|
98
|
-
}
|
|
99
|
-
const hmac = createHmac('sha256', msg);
|
|
100
|
-
params.calc = hmac.update(params.token).digest('hex');
|
|
101
|
-
return params;
|
|
70
|
+
return this;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async retoken() {
|
|
74
|
+
let params = this.getTerminalConfig();
|
|
75
|
+
let msg = await this.setmode(CommMode.ws).execute('token.random', [params.cid]);
|
|
76
|
+
if(!!params.structured) {
|
|
77
|
+
msg = msg.result;
|
|
102
78
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
79
|
+
const hmac = this.createHmac('sha256', msg);
|
|
80
|
+
params.calc = hmac.update(params.token).digest('hex'); //计算并附加访问令牌
|
|
81
|
+
|
|
82
|
+
return params;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* WS模式下的登录流程
|
|
87
|
+
* @param {*} params
|
|
88
|
+
* @param {*} callback
|
|
89
|
+
*/
|
|
90
|
+
async login() {
|
|
91
|
+
let params = await this.retoken();
|
|
92
|
+
|
|
93
|
+
return await this.execute('wallet.auth', [
|
|
94
|
+
params.apiKey,
|
|
95
|
+
params.type,
|
|
96
|
+
params.id,
|
|
97
|
+
params.cid,
|
|
98
|
+
params.calc,
|
|
99
|
+
]);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Listen for events on wallet id.
|
|
104
|
+
* @returns {Promise}
|
|
105
|
+
*/
|
|
106
|
+
|
|
107
|
+
async join() {
|
|
108
|
+
let conf = this.getTerminalConfig();
|
|
109
|
+
|
|
110
|
+
let params = await this.retoken();
|
|
111
|
+
params = [params.id, params.cid, params.calc];
|
|
112
|
+
let sig = signObj({
|
|
113
|
+
method: 'wallet.join',
|
|
114
|
+
params: params,
|
|
115
|
+
cid: conf.cid,
|
|
116
|
+
wid: conf.id,
|
|
117
|
+
}, hash256(Buffer.from(conf.token)));
|
|
118
|
+
|
|
119
|
+
return new Promise((resolve, reject) => {
|
|
120
|
+
this.socket.emit('request', 'wallet.join', params, sig, (err) => {
|
|
121
|
+
if (!!err) {
|
|
122
|
+
console.log(err);
|
|
123
|
+
reject(new Error(err.message));
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
resolve();
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Unlisten for events on wallet id.
|
|
133
|
+
*/
|
|
134
|
+
async leave() {
|
|
135
|
+
let conf = this.getTerminalConfig();
|
|
136
|
+
|
|
137
|
+
let params = [conf.id];
|
|
138
|
+
let sig = signObj({
|
|
139
|
+
method: 'wallet.leave',
|
|
140
|
+
params: params,
|
|
141
|
+
cid: conf.cid,
|
|
142
|
+
wid: conf.id,
|
|
143
|
+
}, hash256(Buffer.from(conf.token)));
|
|
144
|
+
|
|
145
|
+
return new Promise((resolve, reject) => {
|
|
146
|
+
this.socket.emit('request', 'wallet.leave', params, sig, (err) => {
|
|
147
|
+
if (err) {
|
|
148
|
+
reject(new Error(err.message));
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
resolve();
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* 以 GET 方式,访问开放式API
|
|
158
|
+
* @param {*} url
|
|
159
|
+
*/
|
|
160
|
+
async get(url) {
|
|
161
|
+
const newOptions = { json: true };
|
|
162
|
+
|
|
163
|
+
let conf = this.getTerminalConfig();
|
|
164
|
+
let _head = !!conf.head ? conf.head : 'http';
|
|
165
|
+
url = `${_head}://${conf.ip}:${conf.port}/public/${url}`;
|
|
166
|
+
|
|
167
|
+
newOptions.headers = {
|
|
168
|
+
Accept: 'application/json',
|
|
169
|
+
'Content-Type': 'application/json; charset=utf-8',
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
try {
|
|
173
|
+
let ret = null;
|
|
174
|
+
if(this.fetch) {
|
|
175
|
+
ret = await this.fetch(url, newOptions);
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
ret = await fetch(url, newOptions);
|
|
179
|
+
}
|
|
180
|
+
let json = await ret.json();
|
|
181
|
+
|
|
182
|
+
if(!conf.structured) {
|
|
183
|
+
if(json.error) {
|
|
184
|
+
return json;
|
|
185
|
+
} else {
|
|
186
|
+
return json.result; //脱去外围数据结构
|
|
187
|
+
}
|
|
188
|
+
} else {
|
|
189
|
+
return json; //保留外围数据结构
|
|
190
|
+
}
|
|
117
191
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
* WS 模式下的加入钱包操作
|
|
121
|
-
*/
|
|
122
|
-
async join() {
|
|
123
|
-
let params = this.getTerminalConfig();
|
|
124
|
-
return await this.execute('wallet.join', [params.cid, params.id]);
|
|
192
|
+
catch(e) {
|
|
193
|
+
console.error(e);
|
|
125
194
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async post(url, options) {
|
|
198
|
+
const newOptions = { json: true, method: 'POST', body: JSON.stringify(options) };
|
|
199
|
+
|
|
200
|
+
let conf = this.getTerminalConfig();
|
|
201
|
+
let _head = !!conf.head ? conf.head : 'http';
|
|
202
|
+
url = `${_head}://${conf.ip}:${conf.port}/public/${url}`;
|
|
203
|
+
|
|
204
|
+
newOptions.headers = {
|
|
205
|
+
Accept: 'application/json',
|
|
206
|
+
'Content-Type': 'application/json; charset=utf-8',
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
try {
|
|
210
|
+
let ret = null;
|
|
211
|
+
if(this.fetch) {
|
|
212
|
+
ret = await this.fetch(url, newOptions);
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
ret = await fetch(url, newOptions);
|
|
216
|
+
}
|
|
217
|
+
let json = await ret.json();
|
|
218
|
+
|
|
219
|
+
if(!conf.structured) {
|
|
220
|
+
if(json.error) {
|
|
221
|
+
return json;
|
|
222
|
+
} else {
|
|
223
|
+
return json.result; //脱去外围数据结构
|
|
141
224
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
this.socket.connect();
|
|
149
|
-
}
|
|
150
|
-
}, 1500);
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
return new Promise(resolve => {
|
|
154
|
-
this.socket.on('connect', () => {
|
|
155
|
-
resolve();
|
|
156
|
-
});
|
|
157
|
-
});
|
|
225
|
+
} else {
|
|
226
|
+
return json; //保留外围数据结构
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
catch(e) {
|
|
230
|
+
console.error(e);
|
|
158
231
|
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* 执行RPC调用
|
|
236
|
+
* @param {*} method
|
|
237
|
+
* @param {*} params
|
|
238
|
+
*/
|
|
239
|
+
async execute(method, params) {
|
|
240
|
+
params = params || [];
|
|
241
|
+
|
|
242
|
+
let conf = this.getTerminalConfig();
|
|
243
|
+
switch(this.mode) {
|
|
244
|
+
case CommMode.ws: {
|
|
245
|
+
if(!this.socket) {
|
|
246
|
+
await this.createSocket();
|
|
247
|
+
}
|
|
159
248
|
|
|
160
|
-
|
|
161
|
-
* 执行 RPC 命令(统一入口)
|
|
162
|
-
* @param {String} command 命令名称(如 'balance.all')
|
|
163
|
-
* @param {Array} args 命令参数
|
|
164
|
-
*/
|
|
165
|
-
async execute(command, args) {
|
|
166
|
-
let params = this.getTerminalConfig();
|
|
249
|
+
let key = generateKey(hash256(Buffer.from(conf.token)));
|
|
167
250
|
let obj = {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
id: params.id,
|
|
173
|
-
},
|
|
251
|
+
method: method,
|
|
252
|
+
params: params,
|
|
253
|
+
cid: conf.cid,
|
|
254
|
+
wid: conf.id,
|
|
174
255
|
};
|
|
256
|
+
let sig = signObj(obj, key.private);
|
|
175
257
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
258
|
+
return new Promise((resolve, reject) => {
|
|
259
|
+
this.socket.emit('request', method, params, sig, (err, msg) => {
|
|
260
|
+
if(!!err) {
|
|
261
|
+
reject(err);
|
|
262
|
+
}
|
|
263
|
+
if(!conf.structured) {
|
|
264
|
+
if(!!msg) {
|
|
265
|
+
if(msg.error) {
|
|
266
|
+
resolve(msg);
|
|
267
|
+
} else {
|
|
268
|
+
resolve(msg.result);
|
|
184
269
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
});
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
case CommMode.get:
|
|
192
|
-
return this.getRequest(obj);
|
|
193
|
-
|
|
194
|
-
case CommMode.post:
|
|
195
|
-
return this.postRequest(obj);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
return Promise.reject(new Error('Unknown mode'));
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* 以 GET 方式访问远程 API
|
|
203
|
-
*/
|
|
204
|
-
async get(url) {
|
|
205
|
-
const options = {
|
|
206
|
-
json: true,
|
|
207
|
-
method: 'GET',
|
|
208
|
-
mode: 'cors',
|
|
209
|
-
headers: {
|
|
210
|
-
Accept: 'application/json',
|
|
211
|
-
'Content-Type': 'application/json; charset=utf-8',
|
|
212
|
-
},
|
|
213
|
-
};
|
|
214
|
-
|
|
215
|
-
// 添加 API Key 认证
|
|
216
|
-
let params = this.getTerminalConfig();
|
|
217
|
-
if (params.apiKey) {
|
|
218
|
-
let auth = Buffer.from('x:' + params.apiKey).toString('base64');
|
|
219
|
-
options.headers['Authorization'] = 'Basic ' + auth;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
try {
|
|
223
|
-
if (this.fetch) {
|
|
224
|
-
let ret = await this.fetch(url, options);
|
|
225
|
-
return await ret.json();
|
|
270
|
+
} else {
|
|
271
|
+
resolve(null);
|
|
272
|
+
}
|
|
226
273
|
} else {
|
|
227
|
-
|
|
228
|
-
return await ret.json();
|
|
274
|
+
resolve(msg);
|
|
229
275
|
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
default: {
|
|
281
|
+
await this.queryToken();
|
|
282
|
+
|
|
283
|
+
let opt = this.fillOptions({
|
|
284
|
+
method: 'POST',
|
|
285
|
+
body: {
|
|
286
|
+
method: method,
|
|
287
|
+
params: params,
|
|
288
|
+
},
|
|
289
|
+
});
|
|
235
290
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
body: JSON.stringify(body),
|
|
245
|
-
headers: {
|
|
246
|
-
Accept: 'application/json',
|
|
247
|
-
'Content-Type': 'application/json; charset=utf-8',
|
|
248
|
-
},
|
|
249
|
-
};
|
|
291
|
+
let rt = await this.request(
|
|
292
|
+
opt,
|
|
293
|
+
this.getTerminalConfig(),
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
if(!rt) {
|
|
297
|
+
return { error:-1, };
|
|
298
|
+
}
|
|
250
299
|
|
|
251
|
-
|
|
252
|
-
if (params.apiKey) {
|
|
253
|
-
let auth = Buffer.from('x:' + params.apiKey).toString('base64');
|
|
254
|
-
options.headers['Authorization'] = 'Basic ' + auth;
|
|
300
|
+
if(!!rt.error) {
|
|
255
301
|
}
|
|
256
302
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
} catch (e) {
|
|
266
|
-
console.error(e);
|
|
267
|
-
return null;
|
|
303
|
+
if(!conf.structured) {
|
|
304
|
+
if(rt.error) {
|
|
305
|
+
return rt;
|
|
306
|
+
} else {
|
|
307
|
+
return rt.result;
|
|
308
|
+
}
|
|
309
|
+
} else {
|
|
310
|
+
return rt;
|
|
268
311
|
}
|
|
312
|
+
}
|
|
269
313
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
return this.get(url);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* 计算并返回用于对称加密的密钥
|
|
318
|
+
*/
|
|
319
|
+
getAes() {
|
|
320
|
+
let buf = hash256(Buffer.from(this.getTerminalConfig().token));
|
|
321
|
+
let aeskey = buf.toString('base64').slice(0, 32);
|
|
322
|
+
buf = hash256(buf);
|
|
323
|
+
let aesiv = buf.toString('base64').slice(0, 16);
|
|
324
|
+
|
|
325
|
+
return {aeskey, aesiv};
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
getRandom() {
|
|
329
|
+
let _t = (now() / 120) | 0;
|
|
330
|
+
this.$params.randomTime = this.$params.randomTime || _t;
|
|
331
|
+
if (_t > this.$params.randomTime) {
|
|
332
|
+
//有效期检测
|
|
333
|
+
this.$params.random = null;
|
|
291
334
|
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
335
|
+
|
|
336
|
+
return this.$params.random;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
setRandom(val) {
|
|
340
|
+
this.$params.random = val;
|
|
341
|
+
if (!!val) {
|
|
342
|
+
this.$params.randomTime = (now() / 120) | 0; //设置有效期
|
|
300
343
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
if (this.socket) {
|
|
307
|
-
this.socket.removeAllListeners();
|
|
308
|
-
this.socket.disconnect();
|
|
309
|
-
this.socket = null;
|
|
310
|
-
}
|
|
311
|
-
return this;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
fillOptions(options) {
|
|
347
|
+
if (!options) {
|
|
348
|
+
options = {};
|
|
312
349
|
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
* 监听推送消息
|
|
316
|
-
* @param {Function} cb 回调
|
|
317
|
-
* @param {String} etype 事件类型
|
|
318
|
-
*/
|
|
319
|
-
watch(cb, etype) {
|
|
320
|
-
if (this.socket) {
|
|
321
|
-
this.socket.on(etype, cb);
|
|
322
|
-
} else {
|
|
323
|
-
this.socketEvents[etype] = cb;
|
|
324
|
-
}
|
|
325
|
-
return this;
|
|
350
|
+
if (!options.body) {
|
|
351
|
+
options.body = {};
|
|
326
352
|
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
* 获取终端配置
|
|
330
|
-
* @param {String} networkType 网络类型 'main' / 'testnet'
|
|
331
|
-
*/
|
|
332
|
-
getTerminalConfig(networkType) {
|
|
333
|
-
networkType = networkType || this.defaultNetworkType;
|
|
334
|
-
|
|
335
|
-
if (!this.AuthConnConfig[networkType]) {
|
|
336
|
-
this.AuthConnConfig[networkType] = {};
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
return this.AuthConnConfig[networkType];
|
|
353
|
+
if (!options.headers) {
|
|
354
|
+
options.headers = {};
|
|
340
355
|
}
|
|
341
356
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
357
|
+
let rnd = this.getRandom();
|
|
358
|
+
let _token = this.getTerminalConfig().token;
|
|
359
|
+
if (_token && rnd) {
|
|
360
|
+
options.body.token = signHMAC(_token, rnd);
|
|
361
|
+
}
|
|
362
|
+
options.body.wid = this.getTerminalConfig().id; //附加默认钱包编号
|
|
363
|
+
options.body.cid = this.getTerminalConfig().cid; //附加客户端编号
|
|
364
|
+
|
|
365
|
+
//对上行数据添加签名, 使用原始 token 作为私钥源
|
|
366
|
+
options.body.sig = signObj({
|
|
367
|
+
method: options.body.method,
|
|
368
|
+
params: options.body.params,
|
|
369
|
+
cid: options.body.cid,
|
|
370
|
+
wid: options.body.wid,
|
|
371
|
+
}, hash256(Buffer.from(_token)));
|
|
372
|
+
|
|
373
|
+
options.body = JSON.stringify(options.body);
|
|
374
|
+
|
|
375
|
+
let auth = {
|
|
376
|
+
username: 'gamerpc',
|
|
377
|
+
password: this.getTerminalConfig().apiKey || '',
|
|
378
|
+
};
|
|
379
|
+
var base = new Base64();
|
|
380
|
+
var result = base.encode(`${auth.username}:${auth.password}`);
|
|
381
|
+
options.headers.Authorization = `Basic ${result}`;
|
|
382
|
+
return options;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
async queryToken() {
|
|
386
|
+
let ret = this.getRandom();
|
|
387
|
+
if (!ret) {
|
|
388
|
+
ret = await this.request(
|
|
389
|
+
this.fillOptions({
|
|
390
|
+
method: 'POST',
|
|
391
|
+
body: {
|
|
392
|
+
method: 'token.random',
|
|
393
|
+
params: [this.getTerminalConfig().cid],
|
|
394
|
+
},
|
|
395
|
+
}),
|
|
396
|
+
this.getTerminalConfig()
|
|
397
|
+
);
|
|
398
|
+
if(!ret || !!ret.error) {
|
|
399
|
+
console.error(`HMAC请求错误`);
|
|
400
|
+
} else {
|
|
401
|
+
this.setRandom(ret.result); //获取令牌随机量
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* 创建通讯连接组件
|
|
408
|
+
* @param {*} ip
|
|
409
|
+
* @param {*} port
|
|
410
|
+
*/
|
|
411
|
+
async createSocket(){
|
|
412
|
+
this.close();
|
|
413
|
+
|
|
414
|
+
let uri = ``;
|
|
415
|
+
let conf = this.getTerminalConfig();
|
|
416
|
+
let _head = !!conf.head ? conf.head : 'http';
|
|
417
|
+
uri = `${_head}://${conf.ip}:${conf.port}/`;
|
|
418
|
+
|
|
419
|
+
this.socket = io(uri, {'force new connection': true})
|
|
420
|
+
.on('disconnect', ()=>{//断线重连
|
|
421
|
+
this.socket.needConnect = true;
|
|
422
|
+
setTimeout(()=>{
|
|
423
|
+
if(!!this.socket.needConnect) {
|
|
424
|
+
this.socket.needConnect = false;
|
|
425
|
+
this.socket.connect();
|
|
426
|
+
}
|
|
427
|
+
}, 1500);
|
|
428
|
+
})
|
|
429
|
+
|
|
430
|
+
Object.keys(this.socketEvents).map(key=>{
|
|
431
|
+
this.socket.on(key, this.socketEvents[key]);
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
await (async function(time){return new Promise(resolve =>{setTimeout(resolve, time);});})(2000);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* 关闭长连接
|
|
439
|
+
*/
|
|
440
|
+
close() {
|
|
441
|
+
if(!!this.socket) {
|
|
442
|
+
this.socket.removeAllListeners();
|
|
443
|
+
this.socket.disconnect();
|
|
444
|
+
this.socket = null;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Requests a URL, returning a promise.
|
|
450
|
+
*
|
|
451
|
+
* @param {object} [options] The options we want to pass to "fetch"
|
|
452
|
+
* @return {object} An object containing either "data" or "err"
|
|
453
|
+
*/
|
|
454
|
+
async request(options, conf) {
|
|
455
|
+
const defaultOptions = {
|
|
456
|
+
//credentials: 'include',
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
const newOptions = { ...defaultOptions, ...options };
|
|
460
|
+
newOptions.json = true;
|
|
461
|
+
|
|
462
|
+
let _head = !!conf.head ? conf.head : 'http';
|
|
463
|
+
|
|
464
|
+
newOptions.uri = `${_head}://${conf.ip}:${conf.port}/`;
|
|
465
|
+
|
|
466
|
+
if (
|
|
467
|
+
newOptions.method === 'POST' ||
|
|
468
|
+
newOptions.method === 'PUT' ||
|
|
469
|
+
newOptions.method === 'DELETE'
|
|
470
|
+
) {
|
|
471
|
+
newOptions.headers = {
|
|
472
|
+
Accept: 'application/json',
|
|
473
|
+
'Content-Type': 'application/json; charset=utf-8',
|
|
474
|
+
...newOptions.headers,
|
|
475
|
+
};
|
|
352
476
|
}
|
|
353
477
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
478
|
+
try {
|
|
479
|
+
if(this.fetch) {
|
|
480
|
+
let ret = await this.fetch(newOptions.uri, newOptions);
|
|
481
|
+
return await ret.json();
|
|
482
|
+
}
|
|
483
|
+
else {
|
|
484
|
+
let ret = await fetch(newOptions.uri, newOptions);
|
|
485
|
+
return await ret.json();
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
catch(e) {
|
|
489
|
+
console.error(e);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* 设置服务端推送报文的监控句柄,支持链式调用
|
|
496
|
+
* @param cb 回调
|
|
497
|
+
* @param etype 事件类型
|
|
498
|
+
* @returns {Remote}
|
|
499
|
+
*/
|
|
500
|
+
watch(cb, etype) {
|
|
501
|
+
if(this.socket) {
|
|
502
|
+
this.socket.on(etype, cb);
|
|
503
|
+
} else {
|
|
504
|
+
this.socketEvents[etype] = cb;
|
|
505
|
+
}
|
|
506
|
+
return this;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* 获取终端配置
|
|
511
|
+
* @param {*} networkType
|
|
512
|
+
*/
|
|
513
|
+
getTerminalConfig(networkType) {
|
|
514
|
+
networkType = networkType || this.defaultNetworkType;
|
|
515
|
+
|
|
516
|
+
if(!this.AuthConnConfig[networkType]) {
|
|
517
|
+
this.AuthConnConfig[networkType] = {}; // Fix: was `info.type` in V7.1.2
|
|
376
518
|
}
|
|
377
519
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
520
|
+
return this.AuthConnConfig[networkType];
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* 等待指定时长
|
|
525
|
+
* @param {Number} time 等待时长(毫秒)
|
|
526
|
+
*/
|
|
527
|
+
async wait (time) {
|
|
528
|
+
await (async (time) => {return new Promise(resolve => {setTimeout(resolve, time);});})(time);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* 设置终端配置
|
|
533
|
+
* @param {*} networkType
|
|
534
|
+
* @param {*} info
|
|
535
|
+
*/
|
|
536
|
+
setup(info) {
|
|
537
|
+
if(!!info && info.type) {
|
|
538
|
+
if(!this.AuthConnConfig[info.type]) {
|
|
539
|
+
this.AuthConnConfig[info.type] = {};
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
//设置默认网络类型
|
|
543
|
+
this.defaultNetworkType = info.type;
|
|
544
|
+
|
|
545
|
+
for(let k of Object.keys(info)) {
|
|
546
|
+
//设置默认网络类型的参数 - 逐项设置
|
|
547
|
+
this.AuthConnConfig[info.type][k] = info[k];
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
if(this.mode == CommMode.ws) {
|
|
551
|
+
//断开后自动重连,以便刷新接口参数如目标钱包编号等
|
|
552
|
+
this.close();
|
|
553
|
+
}
|
|
385
554
|
}
|
|
555
|
+
|
|
556
|
+
return this;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/**
|
|
560
|
+
* 为了提供node下的兼容性而添加的属性设定函数
|
|
561
|
+
* @param {*} fn
|
|
562
|
+
*/
|
|
563
|
+
setFetch(fn) {
|
|
564
|
+
this.fetch = fn;
|
|
565
|
+
return this;
|
|
566
|
+
}
|
|
386
567
|
}
|
|
387
568
|
|
|
388
|
-
// 挂载静态工具函数到原型,方便实例使用
|
|
389
569
|
AuthConn.prototype.CommMode = CommMode;
|
|
390
570
|
AuthConn.prototype.createHmac = createHmac;
|
|
391
|
-
AuthConn.prototype.signHMAC = signHMAC;
|
|
392
571
|
AuthConn.prototype.assert = assert;
|
|
393
572
|
AuthConn.prototype.stringify = stringify;
|
|
573
|
+
AuthConn.prototype.encrypt = encrypt;
|
|
574
|
+
AuthConn.prototype.decrypt = decrypt;
|
|
394
575
|
AuthConn.prototype.verifyData = verifyData;
|
|
395
576
|
AuthConn.prototype.generateKey = generateKey;
|
|
396
577
|
AuthConn.prototype.signObj = signObj;
|
|
@@ -404,4 +585,7 @@ AuthConn.prototype.hash256 = hash256;
|
|
|
404
585
|
AuthConn.prototype.hash160 = hash160;
|
|
405
586
|
AuthConn.prototype.sha1 = sha1;
|
|
406
587
|
|
|
588
|
+
/**
|
|
589
|
+
* 访问全节点的远程调用函数
|
|
590
|
+
*/
|
|
407
591
|
module.exports = AuthConn;
|