UNPKG

consequunturatque

Version:

A JavaScript / Python / PHP cryptocurrency trading library with support for 130+ exchanges

159 lines (136 loc) 5.79 kB
'use strict' /* ------------------------------------------------------------------------ */ const CryptoJS = require ('../../static_dependencies/crypto-js/crypto-js') const { capitalize } = require ('./string') const { stringToBase64, urlencodeBase64 } = require ('./encode') const NodeRSA = require ('./../../static_dependencies/node-rsa/NodeRSA') const { binaryToBase58, byteArrayToWordArray } = require ('./encode') const elliptic = require ('./../../static_dependencies/elliptic/lib/elliptic') const EC = elliptic.ec const EDDSA = elliptic.eddsa const { ArgumentsRequired } = require ('./../errors') const BN = require ('../../static_dependencies/BN/bn.js') /* ------------------------------------------------------------------------ */ const hash = (request, hash = 'md5', digest = 'hex') => { const options = {} if (hash === 'keccak') { hash = 'SHA3' options['outputLength'] = 256 } const result = CryptoJS[hash.toUpperCase ()] (request, options) return (digest === 'binary') ? result : result.toString (CryptoJS.enc[capitalize (digest)]) } /* ............................................. */ const hmac = (request, secret, hash = 'sha256', digest = 'hex') => { const result = CryptoJS['Hmac' + hash.toUpperCase ()] (request, secret) if (digest) { const encoding = (digest === 'binary') ? 'Latin1' : capitalize (digest) return result.toString (CryptoJS.enc[capitalize (encoding)]) } return result } /* ............................................. */ function rsa (request, secret, alg = 'RS256') { const algos = { 'RS256': 'pkcs1-sha256', 'RS512': 'pkcs1-sha512', } if (!(alg in algos)) { throw new ExchangeError (alg + ' is not a supported rsa signing algorithm.') } const algorithm = algos[alg] let key = new NodeRSA (secret, { 'environment': 'browser', 'signingScheme': algorithm, }) return key.sign (request, 'base64', 'binary') } /** * @return {string} */ function jwt (request, secret, alg = 'HS256') { const algos = { 'HS256': 'sha256', 'HS384': 'sha384', 'HS512': 'sha512', }; const encodedHeader = urlencodeBase64 (stringToBase64 (JSON.stringify ({ 'alg': alg, 'typ': 'JWT' }))) const encodedData = urlencodeBase64 (stringToBase64 (JSON.stringify (request))) const token = [ encodedHeader, encodedData ].join ('.') const algoType = alg.slice (0, 2); const algorithm = algos[alg] let signature = undefined if (algoType === 'HS') { signature = urlencodeBase64 (hmac (token, secret, algorithm, 'base64')) } else if (algoType === 'RS') { signature = urlencodeBase64 (rsa (token, secret, alg)) } return [ token, signature ].join ('.') } function ecdsa (request, secret, algorithm = 'p256', hashFunction = undefined, fixedLength = false) { let digest = request if (hashFunction !== undefined) { digest = hash (request, hashFunction, 'hex') } const curve = new EC (algorithm) let signature = curve.sign (digest, secret, 'hex', { 'canonical': true }) let counter = new BN ('0') const minimum_size = new BN ('1').shln (8 * 31).sub (new BN ('1')) while (fixedLength && (signature.r.gt (curve.nh) || signature.r.lte (minimum_size) || signature.s.lte (minimum_size))) { signature = curve.sign (digest, secret, 'hex', { 'canonical': true, 'extraEntropy': counter.toArray ('le', 32)}) counter = counter.add (new BN ('1')) } return { 'r': signature.r.toString (16).padStart (64, '0'), 's': signature.s.toString (16).padStart (64, '0'), 'v': signature.recoveryParam, } } function eddsa (request, secret, algorithm = 'ed25519') { // used for waves.exchange (that's why the output is base58) const curve = new EDDSA (algorithm) const signature = curve.signModified (request, secret) return binaryToBase58 (byteArrayToWordArray (signature.toBytes ())) } /* ------------------------------------------------------------------------ */ const totp = (secret) => { const dec2hex = s => ((s < 15.5 ? '0' : '') + Math.round (s).toString (16)) , hex2dec = s => parseInt (s, 16) , leftpad = (s, p) => (p + s).slice (-p.length) // both s and p are short strings const base32tohex = (base32) => { let base32chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567' let bits = '' let hex = '' for (let i = 0; i < base32.length; i++) { let val = base32chars.indexOf (base32.charAt (i).toUpperCase ()) bits += leftpad (val.toString (2), '00000') } for (let i = 0; i + 4 <= bits.length; i += 4) { let chunk = bits.substr (i, 4) hex = hex + parseInt (chunk, 2).toString (16) } return hex } const getOTP = (secret) => { secret = secret.replace (' ', '') // support 2fa-secrets with spaces like "4TDV WOGO" → "4TDVWOGO" let epoch = Math.round (new Date ().getTime () / 1000.0) let time = leftpad (dec2hex (Math.floor (epoch / 30)), '0000000000000000') let hmacRes = hmac (CryptoJS.enc.Hex.parse (time), CryptoJS.enc.Hex.parse (base32tohex (secret)), 'sha1', 'hex') let offset = hex2dec (hmacRes.substring (hmacRes.length - 1)) let otp = (hex2dec (hmacRes.substr (offset * 2, 8)) & hex2dec ('7fffffff')) + '' otp = (otp).substr (otp.length - 6, 6) return otp } return getOTP (secret) } /* ------------------------------------------------------------------------ */ module.exports = { hash, hmac, jwt, totp, rsa, ecdsa, eddsa, } /* ------------------------------------------------------------------------ */