Time synchronization with server

- wrapper for /v2/public/time rest endpoint
- synchronize time before trying to authenticate a request in order
  to avoid invalid authentication because prevented replay attacks.

Resolves #1
This commit is contained in:
Stefan Aebischer
2019-09-16 14:17:48 +02:00
parent ed28d14171
commit b6d2803a49
4 changed files with 47 additions and 6 deletions

View File

@@ -3,7 +3,7 @@ const assert = require('assert');
const request = require('request');
const {signMessage} = require('./utility.js');
const {signMessage, getServerTimeOffset} = require('./utility.js');
const baseUrls = {
livenet: 'https://api.bybit.com',
@@ -14,9 +14,13 @@ module.exports = class Request {
constructor(key, secret, livenet=false) {
this.baseUrl = baseUrls[livenet === true ? 'livenet' : 'testnet'];
this._timeOffset = null;
if(key) assert(secret, 'Secret is required for private enpoints');
this._syncTime();
setInterval(this._syncTime.bind(this), 3600000);
this.key = key;
this.secret = secret;
}
@@ -34,12 +38,22 @@ module.exports = class Request {
return result;
}
async getTimeOffset() {
const start = Date.now();
const result = await this.get('/v2/public/time');
const end = Date.now();
return Math.ceil((result.time_now * 1000) - start + ((end - start) / 2));
}
async _call(method, endpoint, params) {
const publicEndpoint = endpoint.startsWith('/v2/public');
if(!publicEndpoint) {
if(!this.key || !this.secret) throw new Error('Private endpoints require api and private keys set');
if(this._timeOffset === null) await this._syncTime();
params = this._signRequest(params);
}
@@ -73,7 +87,7 @@ module.exports = class Request {
const params = {
...data,
api_key: this.key,
timestamp: Date.now()
timestamp: Date.now() + this._timeOffset
};
if(this.key && this.secret) {
@@ -89,4 +103,8 @@ module.exports = class Request {
.map(key => `${key}=${params[key]}`)
.join('&');
}
async _syncTime() {
this._timeOffset = await this.getTimeOffset();
}
}