@bitpay-labs/bitcore-wallet-service 11.8.0 → 11.8.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/package.json +6 -6
- package/src/bws.ts +2 -0
- package/src/externalservices/ramp.ts +0 -1
- package/src/lib/common/utils.ts +6 -0
- package/src/lib/expressapp.ts +63 -2378
- package/src/lib/logger.ts +5 -74
- package/src/lib/model/txproposal.ts +14 -10
- package/src/lib/routes/advertisements.ts +151 -0
- package/src/lib/routes/blockchain.ts +152 -0
- package/src/lib/routes/context.ts +149 -0
- package/src/lib/routes/maintenance.ts +111 -0
- package/src/lib/routes/moralis.ts +89 -0
- package/src/lib/routes/notifications.ts +135 -0
- package/src/lib/routes/services.ts +528 -0
- package/src/lib/routes/setup.ts +86 -0
- package/src/lib/routes/transactions.ts +196 -0
- package/src/lib/routes/walletdata.ts +167 -0
- package/src/lib/routes/wallets.ts +289 -0
- package/src/lib/server.ts +29 -4
- package/src/lib/storage.ts +3 -0
- package/test/integration/externalservices/ramp.test.ts +0 -4
- package/ts_build/package.json +5 -5
- package/ts_build/src/bws.js +3 -0
- package/ts_build/src/bws.js.map +1 -1
- package/ts_build/src/externalservices/ramp.d.ts.map +1 -1
- package/ts_build/src/externalservices/ramp.js +0 -2
- package/ts_build/src/externalservices/ramp.js.map +1 -1
- package/ts_build/src/lib/common/index.d.ts +1 -0
- package/ts_build/src/lib/common/index.d.ts.map +1 -1
- package/ts_build/src/lib/common/utils.d.ts +1 -0
- package/ts_build/src/lib/common/utils.d.ts.map +1 -1
- package/ts_build/src/lib/common/utils.js +6 -0
- package/ts_build/src/lib/common/utils.js.map +1 -1
- package/ts_build/src/lib/expressapp.d.ts.map +1 -1
- package/ts_build/src/lib/expressapp.js +64 -2224
- package/ts_build/src/lib/expressapp.js.map +1 -1
- package/ts_build/src/lib/logger.d.ts +5 -5
- package/ts_build/src/lib/logger.d.ts.map +1 -1
- package/ts_build/src/lib/logger.js +6 -91
- package/ts_build/src/lib/logger.js.map +1 -1
- package/ts_build/src/lib/model/txproposal.d.ts +1 -4
- package/ts_build/src/lib/model/txproposal.d.ts.map +1 -1
- package/ts_build/src/lib/model/txproposal.js +13 -9
- package/ts_build/src/lib/model/txproposal.js.map +1 -1
- package/ts_build/src/lib/routes/advertisements.d.ts +11 -0
- package/ts_build/src/lib/routes/advertisements.d.ts.map +1 -0
- package/ts_build/src/lib/routes/advertisements.js +119 -0
- package/ts_build/src/lib/routes/advertisements.js.map +1 -0
- package/ts_build/src/lib/routes/blockchain.d.ts +13 -0
- package/ts_build/src/lib/routes/blockchain.d.ts.map +1 -0
- package/ts_build/src/lib/routes/blockchain.js +159 -0
- package/ts_build/src/lib/routes/blockchain.js.map +1 -0
- package/ts_build/src/lib/routes/context.d.ts +12 -0
- package/ts_build/src/lib/routes/context.d.ts.map +1 -0
- package/ts_build/src/lib/routes/context.js +115 -0
- package/ts_build/src/lib/routes/context.js.map +1 -0
- package/ts_build/src/lib/routes/maintenance.d.ts +10 -0
- package/ts_build/src/lib/routes/maintenance.d.ts.map +1 -0
- package/ts_build/src/lib/routes/maintenance.js +131 -0
- package/ts_build/src/lib/routes/maintenance.js.map +1 -0
- package/ts_build/src/lib/routes/moralis.d.ts +9 -0
- package/ts_build/src/lib/routes/moralis.d.ts.map +1 -0
- package/ts_build/src/lib/routes/moralis.js +78 -0
- package/ts_build/src/lib/routes/moralis.js.map +1 -0
- package/ts_build/src/lib/routes/notifications.d.ts +10 -0
- package/ts_build/src/lib/routes/notifications.d.ts.map +1 -0
- package/ts_build/src/lib/routes/notifications.js +120 -0
- package/ts_build/src/lib/routes/notifications.js.map +1 -0
- package/ts_build/src/lib/routes/services.d.ts +11 -0
- package/ts_build/src/lib/routes/services.d.ts.map +1 -0
- package/ts_build/src/lib/routes/services.js +430 -0
- package/ts_build/src/lib/routes/services.js.map +1 -0
- package/ts_build/src/lib/routes/setup.d.ts +4 -0
- package/ts_build/src/lib/routes/setup.d.ts.map +1 -0
- package/ts_build/src/lib/routes/setup.js +79 -0
- package/ts_build/src/lib/routes/setup.js.map +1 -0
- package/ts_build/src/lib/routes/transactions.d.ts +9 -0
- package/ts_build/src/lib/routes/transactions.d.ts.map +1 -0
- package/ts_build/src/lib/routes/transactions.js +188 -0
- package/ts_build/src/lib/routes/transactions.js.map +1 -0
- package/ts_build/src/lib/routes/walletdata.d.ts +10 -0
- package/ts_build/src/lib/routes/walletdata.d.ts.map +1 -0
- package/ts_build/src/lib/routes/walletdata.js +186 -0
- package/ts_build/src/lib/routes/walletdata.js.map +1 -0
- package/ts_build/src/lib/routes/wallets.d.ts +13 -0
- package/ts_build/src/lib/routes/wallets.d.ts.map +1 -0
- package/ts_build/src/lib/routes/wallets.js +292 -0
- package/ts_build/src/lib/routes/wallets.js.map +1 -0
- package/ts_build/src/lib/server.d.ts +5 -3
- package/ts_build/src/lib/server.d.ts.map +1 -1
- package/ts_build/src/lib/server.js +19 -1
- package/ts_build/src/lib/server.js.map +1 -1
- package/ts_build/src/lib/storage.d.ts.map +1 -1
- package/ts_build/src/lib/storage.js +3 -0
- package/ts_build/src/lib/storage.js.map +1 -1
- package/ts_build/test/integration/externalservices/ramp.test.js +0 -4
- package/ts_build/test/integration/externalservices/ramp.test.js.map +1 -1
package/src/lib/logger.ts
CHANGED
|
@@ -1,77 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
import * as winston from 'winston';
|
|
1
|
+
import { createLogger, formatTimestamp, timestamp } from '@bitpay-labs/bitcore-logging';
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
const logLevel = process.env.BWS_LOG_LEVEL || 'debug';
|
|
6
|
-
|
|
7
|
-
export const transports: winston.transport[] = [
|
|
8
|
-
new winston.transports.Console({
|
|
9
|
-
level: logLevel,
|
|
10
|
-
format: winston.format.combine(
|
|
11
|
-
winston.format.colorize(),
|
|
12
|
-
winston.format.prettyPrint(),
|
|
13
|
-
winston.format.splat(),
|
|
14
|
-
winston.format.simple(),
|
|
15
|
-
winston.format.printf(function(info) {
|
|
16
|
-
// fallback in case the above formatters don't work.
|
|
17
|
-
// eg: logger.log({ some: 'object' })
|
|
18
|
-
if (typeof info.message === 'object') {
|
|
19
|
-
info.message = JSON.stringify(info.message, null, 4);
|
|
20
|
-
}
|
|
21
|
-
return `${info.level} :: ${new Date().toISOString()} :: ${info.message}`;
|
|
22
|
-
})
|
|
23
|
-
),
|
|
24
|
-
})
|
|
25
|
-
];
|
|
26
|
-
|
|
27
|
-
if (process.env.BWS_LOG_HTTP_HOST) {
|
|
28
|
-
transports.push(new winston.transports.Http({
|
|
29
|
-
level: process.env.BWS_LOG_HTTP_LEVEL || logLevel,
|
|
30
|
-
host: process.env.BWS_LOG_HTTP_HOST,
|
|
31
|
-
port: parseInt(process.env.BWS_LOG_HTTP_PORT) || undefined,
|
|
32
|
-
path: process.env.BWS_LOG_HTTP_PATH || ('bws.' + path.parse(process.argv[1]).name),
|
|
33
|
-
headers: {
|
|
34
|
-
'Content-Type': 'application/json'
|
|
35
|
-
},
|
|
36
|
-
format: winston.format.combine(
|
|
37
|
-
winston.format.splat(),
|
|
38
|
-
winston.format.simple(),
|
|
39
|
-
winston.format.printf(info => {
|
|
40
|
-
// fallback in case the above formatters don't work.
|
|
41
|
-
// eg: logger.log({ some: 'object' })
|
|
42
|
-
if (typeof info.message === 'object') {
|
|
43
|
-
info.message = JSON.stringify(info.message, null, 4);
|
|
44
|
-
}
|
|
45
|
-
return JSON.stringify({
|
|
46
|
-
tag: process.env.BWS_LOG_HTTP_TAG || ('bws.' + path.parse(process.argv[1]).name),
|
|
47
|
-
...info
|
|
48
|
-
});
|
|
49
|
-
}),
|
|
50
|
-
)
|
|
51
|
-
}));
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export const logger = winston.createLogger({ transports });
|
|
55
|
-
|
|
56
|
-
export const formatTimestamp = (date: Date): string =>
|
|
57
|
-
`${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date
|
|
58
|
-
.getDate()
|
|
59
|
-
.toString()
|
|
60
|
-
.padStart(2, '0')} ${date
|
|
61
|
-
.getHours()
|
|
62
|
-
.toString()
|
|
63
|
-
.padStart(2, '0')}:${date
|
|
64
|
-
.getMinutes()
|
|
65
|
-
.toString()
|
|
66
|
-
.padStart(2, '0')}:${date
|
|
67
|
-
.getSeconds()
|
|
68
|
-
.toString()
|
|
69
|
-
.padStart(2, '0')}.${date
|
|
70
|
-
.getMilliseconds()
|
|
71
|
-
.toString()
|
|
72
|
-
// .padEnd(3, '0')} ${timezone}`;
|
|
73
|
-
.padEnd(3, '0')}`;
|
|
74
|
-
|
|
75
|
-
export const timestamp = () => formatTimestamp(new Date());
|
|
3
|
+
type BwsLogger = ReturnType<typeof createLogger>;
|
|
76
4
|
|
|
5
|
+
export const logger: BwsLogger = createLogger({ prefix: 'BWS', defaultLevel: 'debug' });
|
|
6
|
+
export const transports: BwsLogger['transports'] = logger.transports;
|
|
7
|
+
export { formatTimestamp, timestamp };
|
|
77
8
|
export default logger;
|
|
@@ -424,16 +424,20 @@ export class TxProposal implements ITxProposal {
|
|
|
424
424
|
}
|
|
425
425
|
|
|
426
426
|
getCurrentSignatures() {
|
|
427
|
-
const acceptedActions =
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
427
|
+
const acceptedActions = this.actions.filter(a => a.type == 'accept');
|
|
428
|
+
|
|
429
|
+
const uniqueXpubs = new Set();
|
|
430
|
+
const signatures = [];
|
|
431
|
+
for (const a of acceptedActions) {
|
|
432
|
+
// TSS will have multiple accept actions with the same xpub/signature (different copayerIds)
|
|
433
|
+
if (uniqueXpubs.has(a.xpub)) continue;
|
|
434
|
+
uniqueXpubs.add(a.xpub);
|
|
435
|
+
signatures.push({
|
|
436
|
+
signatures: a.signatures,
|
|
437
|
+
xpub: a.xpub
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
return signatures;
|
|
437
441
|
}
|
|
438
442
|
|
|
439
443
|
getRawTx() {
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import type * as Types from '../../types/expressapp';
|
|
3
|
+
|
|
4
|
+
interface RouteContext {
|
|
5
|
+
getServer: Types.GetServerFn;
|
|
6
|
+
getServerWithAuth: Types.GetServerWithAuthFn;
|
|
7
|
+
setPublicCache: (res: express.Response, seconds: number) => void;
|
|
8
|
+
returnError: Types.ReturnErrorFn;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function registerAdvertisementRoutes(router: express.Router, context: RouteContext) {
|
|
12
|
+
const { getServer, getServerWithAuth, setPublicCache, returnError } = context;
|
|
13
|
+
const ONE_MINUTE = 60;
|
|
14
|
+
|
|
15
|
+
router.post('/v1/advertisements/', (req, res) => {
|
|
16
|
+
getServerWithAuth(
|
|
17
|
+
req,
|
|
18
|
+
res,
|
|
19
|
+
{
|
|
20
|
+
onlyMarketingStaff: true
|
|
21
|
+
},
|
|
22
|
+
server => {
|
|
23
|
+
server.createAdvert(req.body, (err, advert) => {
|
|
24
|
+
if (err) {
|
|
25
|
+
return returnError(err, res, req);
|
|
26
|
+
}
|
|
27
|
+
if (advert) res.json(advert);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
router.get('/v1/advertisements/', (req, res) => {
|
|
34
|
+
const testing = req.query.testing;
|
|
35
|
+
|
|
36
|
+
let server;
|
|
37
|
+
try {
|
|
38
|
+
server = getServer(req, res);
|
|
39
|
+
} catch (ex) {
|
|
40
|
+
return returnError(ex, res, req);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (testing) {
|
|
44
|
+
server.getTestingAdverts(req.body, (err, ads) => {
|
|
45
|
+
if (err) return returnError(err, res, req);
|
|
46
|
+
res.json(ads);
|
|
47
|
+
});
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
setPublicCache(res, 5 * ONE_MINUTE);
|
|
52
|
+
server.getAdverts(req.body, (err, ads) => {
|
|
53
|
+
if (err) return returnError(err, res, req);
|
|
54
|
+
res.json(ads);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
router.get('/v1/advertisements/:adId/', (req, res) => {
|
|
59
|
+
let server;
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
server = getServer(req, res);
|
|
63
|
+
} catch (ex) {
|
|
64
|
+
return returnError(ex, res, req);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const opts = { adId: req.params['adId'] };
|
|
68
|
+
|
|
69
|
+
if (req.params['adId']) {
|
|
70
|
+
server.getAdvert(opts, (err, ad) => {
|
|
71
|
+
if (err) return returnError(err, res, req);
|
|
72
|
+
res.json(ad);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
router.get('/v1/advertisements/country/:country', (req, res) => {
|
|
78
|
+
const opts = { country: req.params['country'] };
|
|
79
|
+
|
|
80
|
+
let server;
|
|
81
|
+
try {
|
|
82
|
+
server = getServer(req, res);
|
|
83
|
+
} catch (ex) {
|
|
84
|
+
return returnError(ex, res, req);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
server.getAdvertsByCountry(opts, (err, ads) => {
|
|
88
|
+
if (err) return returnError(err, res, req);
|
|
89
|
+
res.json(ads);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
router.post('/v1/advertisements/:adId/activate', (req, res) => {
|
|
94
|
+
const opts = { adId: req.params['adId'] };
|
|
95
|
+
|
|
96
|
+
getServerWithAuth(
|
|
97
|
+
req,
|
|
98
|
+
res,
|
|
99
|
+
{
|
|
100
|
+
onlyMarketingStaff: true
|
|
101
|
+
},
|
|
102
|
+
server => {
|
|
103
|
+
if (req.params['adId']) {
|
|
104
|
+
server.activateAdvert(opts, err => {
|
|
105
|
+
if (err) return returnError(err, res, req);
|
|
106
|
+
res.json({ advertisementId: opts.adId, message: 'advert activated' });
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
router.post('/v1/advertisements/:adId/deactivate', (req, res) => {
|
|
114
|
+
const opts = { adId: req.params['adId'] };
|
|
115
|
+
|
|
116
|
+
getServerWithAuth(
|
|
117
|
+
req,
|
|
118
|
+
res,
|
|
119
|
+
{
|
|
120
|
+
onlyMarketingStaff: true
|
|
121
|
+
},
|
|
122
|
+
server => {
|
|
123
|
+
if (req.params['adId']) {
|
|
124
|
+
server.deactivateAdvert(opts, err => {
|
|
125
|
+
if (err) return returnError(err, res, req);
|
|
126
|
+
res.json({ advertisementId: opts.adId, message: 'advert deactivated' });
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
router.delete('/v1/advertisements/:adId/', (req, res) => {
|
|
134
|
+
getServerWithAuth(
|
|
135
|
+
req,
|
|
136
|
+
res,
|
|
137
|
+
{
|
|
138
|
+
onlyMarketingStaff: true
|
|
139
|
+
},
|
|
140
|
+
server => {
|
|
141
|
+
req.body.adId = req.params['adId'];
|
|
142
|
+
server.removeAdvert(req.body, (err, removedAd) => {
|
|
143
|
+
if (err) return returnError(err, res, req);
|
|
144
|
+
if (removedAd) {
|
|
145
|
+
res.json(removedAd);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
);
|
|
150
|
+
});
|
|
151
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import * as _ from 'lodash';
|
|
3
|
+
import type * as Types from '../../types/expressapp';
|
|
4
|
+
import type { WalletService } from '../server';
|
|
5
|
+
|
|
6
|
+
interface RouteContext {
|
|
7
|
+
estimateFeeLimiter: express.Handler;
|
|
8
|
+
getServer: Types.GetServerFn;
|
|
9
|
+
getServerWithAuth: Types.GetServerWithAuthFn;
|
|
10
|
+
logDeprecated: Types.LogDeprecatedFn;
|
|
11
|
+
setPublicCache: (res: express.Response, seconds: number) => void;
|
|
12
|
+
returnError: Types.ReturnErrorFn;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
type RouteHandler = (server: WalletService) => Promise<any> | any;
|
|
16
|
+
|
|
17
|
+
const ONE_MINUTE = 60;
|
|
18
|
+
|
|
19
|
+
function callbackResult<T>(fn: (cb: (err?: any, data?: T) => void) => void): Promise<T> {
|
|
20
|
+
return new Promise((resolve, reject) => {
|
|
21
|
+
fn((err, data) => {
|
|
22
|
+
if (err) return reject(err);
|
|
23
|
+
return resolve(data as T);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function getServerOrReturnError(req, res, context: RouteContext): WalletService | null {
|
|
29
|
+
try {
|
|
30
|
+
return context.getServer(req, res);
|
|
31
|
+
} catch (err) {
|
|
32
|
+
context.returnError(err, res, req);
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function respondWithPublicServer(req, res, context: RouteContext, handler: RouteHandler) {
|
|
38
|
+
const server = getServerOrReturnError(req, res, context);
|
|
39
|
+
if (!server) return;
|
|
40
|
+
|
|
41
|
+
Promise.resolve()
|
|
42
|
+
.then(() => handler(server))
|
|
43
|
+
.then(response => {
|
|
44
|
+
res.json(response);
|
|
45
|
+
})
|
|
46
|
+
.catch(err => {
|
|
47
|
+
context.returnError(err ?? 'unknown', res, req);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function respondWithAuthServer(req, res, context: RouteContext, handler: RouteHandler) {
|
|
52
|
+
context.getServerWithAuth(req, res, server => {
|
|
53
|
+
Promise.resolve()
|
|
54
|
+
.then(() => handler(server))
|
|
55
|
+
.then(response => {
|
|
56
|
+
res.json(response);
|
|
57
|
+
})
|
|
58
|
+
.catch(err => {
|
|
59
|
+
context.returnError(err ?? 'unknown', res, req);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function registerBlockchainRoutes(router: express.Router, context: RouteContext) {
|
|
65
|
+
const { estimateFeeLimiter, logDeprecated, setPublicCache } = context;
|
|
66
|
+
|
|
67
|
+
router.get('/v1/feelevels/', estimateFeeLimiter, (req, res) => {
|
|
68
|
+
setPublicCache(res, 1 * ONE_MINUTE);
|
|
69
|
+
logDeprecated(req);
|
|
70
|
+
|
|
71
|
+
respondWithPublicServer(req, res, context, server =>
|
|
72
|
+
callbackResult(resolve => {
|
|
73
|
+
const opts: { network?: string } = {};
|
|
74
|
+
if (req.query.network) opts.network = req.query.network as string;
|
|
75
|
+
server.getFeeLevels(opts, resolve);
|
|
76
|
+
}).then((feeLevels: any[]) => {
|
|
77
|
+
_.each(feeLevels, feeLevel => {
|
|
78
|
+
feeLevel.feePerKB = feeLevel.feePerKb;
|
|
79
|
+
delete feeLevel.feePerKb;
|
|
80
|
+
});
|
|
81
|
+
return feeLevels;
|
|
82
|
+
})
|
|
83
|
+
);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
router.get('/v2/feelevels/', (req, res) => {
|
|
87
|
+
setPublicCache(res, 1 * ONE_MINUTE);
|
|
88
|
+
|
|
89
|
+
respondWithPublicServer(req, res, context, server =>
|
|
90
|
+
callbackResult(resolve => {
|
|
91
|
+
const opts: { coin?: string; network?: string; chain?: string } = {};
|
|
92
|
+
if (req.query.coin) opts.coin = req.query.coin as string;
|
|
93
|
+
if (req.query.chain || req.query.coin) opts.chain = (req.query.chain || req.query.coin) as string;
|
|
94
|
+
if (req.query.network) opts.network = req.query.network as string;
|
|
95
|
+
server.getFeeLevels(opts, resolve);
|
|
96
|
+
})
|
|
97
|
+
);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
router.post('/v3/estimateGas/', (req, res) => {
|
|
101
|
+
respondWithAuthServer(req, res, context, server => {
|
|
102
|
+
return server.estimateGas(req.body);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
router.post('/v1/ethmultisig/', (req, res) => {
|
|
107
|
+
respondWithAuthServer(req, res, context, server => {
|
|
108
|
+
return server.getMultisigContractInstantiationInfo(req.body);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
router.post('/v1/ethmultisig/info', (req, res) => {
|
|
113
|
+
respondWithAuthServer(req, res, context, server => {
|
|
114
|
+
return server.getMultisigContractInfo(req.body);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
router.post('/v1/multisig/', (req, res) => {
|
|
119
|
+
respondWithAuthServer(req, res, context, server => {
|
|
120
|
+
return server.getMultisigContractInstantiationInfo(req.body);
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
router.post('/v1/multisig/info', (req, res) => {
|
|
125
|
+
respondWithAuthServer(req, res, context, server => {
|
|
126
|
+
return server.getMultisigContractInfo(req.body);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
router.post('/v1/token/info', (req, res) => {
|
|
131
|
+
respondWithAuthServer(req, res, context, server => {
|
|
132
|
+
return server.getTokenContractInfo(req.body);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
router.post('/v1/token/allowance', (req, res) => {
|
|
137
|
+
respondWithPublicServer(req, res, context, server => {
|
|
138
|
+
return server.getTokenAllowance(req.body);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
router.get('/v1/nonce/:address', (req, res) => {
|
|
143
|
+
respondWithAuthServer(req, res, context, server => {
|
|
144
|
+
return server.getNonce({
|
|
145
|
+
coin: req.query.coin || 'eth',
|
|
146
|
+
chain: req.query.chain,
|
|
147
|
+
network: req.query.network || 'livenet',
|
|
148
|
+
address: req.params['address']
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import * as Types from '../../types/expressapp';
|
|
3
|
+
import { Errors } from '../errors/errordefinitions';
|
|
4
|
+
import { logger } from '../logger';
|
|
5
|
+
import { WalletService } from '../server';
|
|
6
|
+
|
|
7
|
+
interface RouteHelpers {
|
|
8
|
+
getServer: Types.GetServerFn;
|
|
9
|
+
getServerWithAuth: Types.GetServerWithAuthFn;
|
|
10
|
+
getServerWithMultiAuth: Types.GetServerWithMultiAuthFn;
|
|
11
|
+
logDeprecated: Types.LogDeprecatedFn;
|
|
12
|
+
setPublicCache: (res: express.Response, seconds: number) => void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function createRouteHelpers(returnError: Types.ReturnErrorFn): RouteHelpers {
|
|
16
|
+
const logDeprecated: Types.LogDeprecatedFn = req => {
|
|
17
|
+
logger.warn('DEPRECATED', req.method, req.url, '(' + req.header('x-client-version') + ')');
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const getCredentials: Types.GetCredentialsFn = req => {
|
|
21
|
+
const identity = req.header('x-identity');
|
|
22
|
+
if (!identity) return;
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
copayerId: identity,
|
|
26
|
+
signature: req.header('x-signature'),
|
|
27
|
+
session: req.header('x-session')
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const getServer: Types.GetServerFn = (req, _res) => {
|
|
32
|
+
const opts = {
|
|
33
|
+
clientVersion: req.header('x-client-version'),
|
|
34
|
+
userAgent: req.header('user-agent')
|
|
35
|
+
};
|
|
36
|
+
return WalletService.getInstance(opts);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const getServerWithAuth: Types.GetServerWithAuthFn = async (req, res, opts, cb) => {
|
|
40
|
+
if (typeof opts === 'function') {
|
|
41
|
+
cb = opts;
|
|
42
|
+
opts = {};
|
|
43
|
+
}
|
|
44
|
+
opts = (opts || {}) as Types.ServerOpts;
|
|
45
|
+
|
|
46
|
+
const credentials = getCredentials(req);
|
|
47
|
+
if (!credentials) {
|
|
48
|
+
return returnError(Errors.NOT_AUTHORIZED, res, req);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const reqUrl = req.redirectedUrl || req.url;
|
|
52
|
+
const auth = {
|
|
53
|
+
copayerId: credentials.copayerId,
|
|
54
|
+
message: req.method.toLowerCase() + '|' + reqUrl + '|' + JSON.stringify(req.body),
|
|
55
|
+
signature: credentials.signature,
|
|
56
|
+
clientVersion: req.header('x-client-version'),
|
|
57
|
+
userAgent: req.header('user-agent'),
|
|
58
|
+
walletId: req.header('x-wallet-id'),
|
|
59
|
+
session: undefined
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
if (opts.allowSession) {
|
|
63
|
+
auth.session = credentials.session;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
const server: WalletService = await new Promise((resolve, reject) => {
|
|
68
|
+
WalletService.getInstanceWithAuth(auth, (err, server) => {
|
|
69
|
+
if (err) {
|
|
70
|
+
return reject(err);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (opts.onlySupportStaff && !server.copayerIsSupportStaff) {
|
|
74
|
+
return reject(Errors.NOT_AUTHORIZED);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (server.copayerIsSupportStaff) {
|
|
78
|
+
req.isSupportStaff = true;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (opts.onlyMarketingStaff && !server.copayerIsMarketingStaff) {
|
|
82
|
+
return reject(Errors.NOT_AUTHORIZED);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
req.walletId = server.walletId;
|
|
86
|
+
req.copayerId = server.copayerId;
|
|
87
|
+
|
|
88
|
+
return resolve(server);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
if (cb) {
|
|
93
|
+
return cb(server);
|
|
94
|
+
}
|
|
95
|
+
return server;
|
|
96
|
+
} catch (err) {
|
|
97
|
+
if (opts.silentFailure) {
|
|
98
|
+
if (cb) {
|
|
99
|
+
return cb(null, err);
|
|
100
|
+
}
|
|
101
|
+
throw err;
|
|
102
|
+
}
|
|
103
|
+
return returnError(err, res, req);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const getServerWithMultiAuth: Types.GetServerWithMultiAuthFn = (req, res, opts = {}) => {
|
|
108
|
+
const identitiesHeader = req.headers['x-identities'];
|
|
109
|
+
const identitiesHeaderValue = Array.isArray(identitiesHeader) ? identitiesHeader.join(',') : identitiesHeader;
|
|
110
|
+
const identities = identitiesHeaderValue ? identitiesHeaderValue.split(',') : false;
|
|
111
|
+
const signature = req.headers['x-signature'];
|
|
112
|
+
if (!identities || !signature) {
|
|
113
|
+
throw Errors.NOT_AUTHORIZED;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (!Array.isArray(identities)) {
|
|
117
|
+
throw Errors.NOT_AUTHORIZED;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return identities.map(
|
|
121
|
+
id =>
|
|
122
|
+
new Promise((resolve, reject) =>
|
|
123
|
+
getServerWithAuth(
|
|
124
|
+
Object.assign(req, {
|
|
125
|
+
headers: {
|
|
126
|
+
...req.headers,
|
|
127
|
+
'x-identity': id
|
|
128
|
+
}
|
|
129
|
+
}),
|
|
130
|
+
res,
|
|
131
|
+
opts,
|
|
132
|
+
(server, err) => (err ? reject(err) : resolve(server))
|
|
133
|
+
)
|
|
134
|
+
)
|
|
135
|
+
);
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const setPublicCache = (res: express.Response, seconds: number) => {
|
|
139
|
+
res.setHeader('Cache-Control', `public, max-age=${seconds}, stale-if-error=${10 * seconds}`);
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
getServer,
|
|
144
|
+
getServerWithAuth,
|
|
145
|
+
getServerWithMultiAuth,
|
|
146
|
+
logDeprecated,
|
|
147
|
+
setPublicCache
|
|
148
|
+
};
|
|
149
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import * as _ from 'lodash';
|
|
3
|
+
import { WalletService } from '../server';
|
|
4
|
+
import { Stats } from '../stats';
|
|
5
|
+
import type * as Types from '../../types/expressapp';
|
|
6
|
+
|
|
7
|
+
interface RouteContext {
|
|
8
|
+
getServerWithAuth: Types.GetServerWithAuthFn;
|
|
9
|
+
setPublicCache: (res: express.Response, seconds: number) => void;
|
|
10
|
+
returnError: Types.ReturnErrorFn;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const ONE_MINUTE = 60;
|
|
14
|
+
|
|
15
|
+
export function registerMaintenanceRoutes(router: express.Router, context: RouteContext) {
|
|
16
|
+
const { getServerWithAuth, setPublicCache, returnError } = context;
|
|
17
|
+
|
|
18
|
+
router.post('/v1/addresses/scan/', (req, res) => {
|
|
19
|
+
getServerWithAuth(req, res, server => {
|
|
20
|
+
req.body = req.body || {};
|
|
21
|
+
req.body.startIdx = server.copayerIsSupportStaff ? Number(req.body.startIdx) : null;
|
|
22
|
+
server.startScan(req.body, (err, started) => {
|
|
23
|
+
if (err) return returnError(err, res, req);
|
|
24
|
+
res.json(started);
|
|
25
|
+
res.end();
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
router.get('/v1/stats/', (req, res) => {
|
|
31
|
+
setPublicCache(res, 1 * ONE_MINUTE);
|
|
32
|
+
const opts: {
|
|
33
|
+
network?: string;
|
|
34
|
+
coin?: string;
|
|
35
|
+
from?: string;
|
|
36
|
+
to?: string;
|
|
37
|
+
} = {};
|
|
38
|
+
|
|
39
|
+
if (req.query.network) opts.network = req.query.network as string;
|
|
40
|
+
if (req.query.coin) opts.coin = req.query.coin as string;
|
|
41
|
+
if (req.query.from) opts.from = req.query.from as string;
|
|
42
|
+
if (req.query.to) opts.to = req.query.to as string;
|
|
43
|
+
|
|
44
|
+
const stats = new Stats(opts);
|
|
45
|
+
stats.run((err, data) => {
|
|
46
|
+
if (err) return returnError(err, res, req);
|
|
47
|
+
res.json(data);
|
|
48
|
+
res.end();
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
router.get('/v1/version/', (req, res) => {
|
|
53
|
+
setPublicCache(res, 1 * ONE_MINUTE);
|
|
54
|
+
res.json({
|
|
55
|
+
serviceVersion: WalletService.getServiceVersion()
|
|
56
|
+
});
|
|
57
|
+
res.end();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
router.get('/v1/txnotes/:txid', (req, res) => {
|
|
61
|
+
getServerWithAuth(req, res, server => {
|
|
62
|
+
server.getTxNote(
|
|
63
|
+
{
|
|
64
|
+
txid: req.params['txid']
|
|
65
|
+
},
|
|
66
|
+
(err, note) => {
|
|
67
|
+
if (err) return returnError(err, res, req);
|
|
68
|
+
res.json(note);
|
|
69
|
+
}
|
|
70
|
+
);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
router.put('/v1/txnotes/:txid/', (req, res) => {
|
|
75
|
+
req.body.txid = req.params['txid'];
|
|
76
|
+
getServerWithAuth(req, res, server => {
|
|
77
|
+
server.editTxNote(req.body, (err, note) => {
|
|
78
|
+
if (err) return returnError(err, res, req);
|
|
79
|
+
res.json(note);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
router.get('/v1/txnotes/', (req, res) => {
|
|
85
|
+
getServerWithAuth(req, res, server => {
|
|
86
|
+
const opts: { minTs?: number } = {};
|
|
87
|
+
if (req.query.minTs && _.isNumber(+req.query.minTs)) {
|
|
88
|
+
opts.minTs = +req.query.minTs;
|
|
89
|
+
}
|
|
90
|
+
server.getTxNotes(opts, (err, notes) => {
|
|
91
|
+
if (err) return returnError(err, res, req);
|
|
92
|
+
res.json(notes);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
router.post('/v1/clearcache/', (req, res) => {
|
|
98
|
+
getServerWithAuth(req, res, server => {
|
|
99
|
+
server
|
|
100
|
+
.clearWalletCache(req.query)
|
|
101
|
+
.then(val => {
|
|
102
|
+
if (val) {
|
|
103
|
+
res.sendStatus(200);
|
|
104
|
+
} else {
|
|
105
|
+
res.sendStatus(500);
|
|
106
|
+
}
|
|
107
|
+
})
|
|
108
|
+
.catch(err => returnError(err, res, req));
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
}
|