@@ -11,6 +11,7 @@ import { HttpsProxyAgent } from 'https-proxy-agent';
1111import { SocksProxyAgent } from 'socks-proxy-agent' ;
1212// @ts -ignore
1313import nodeFetch from 'node-fetch' ;
14+
1415// @ts -ignore
1516import zip from 'lodash.zipobject' ;
1617import stringHash from 'string-hash' ;
@@ -63,6 +64,8 @@ export default class Binance {
6364
6465 APIKEY : string = undefined ;
6566 APISECRET : string = undefined ;
67+ PRIVATEKEY : string = undefined ;
68+ PRIVATEKEYPASSWORD : string = undefined ;
6669 test = false ;
6770
6871 timeOffset : number = 0 ;
@@ -209,6 +212,8 @@ export default class Binance {
209212
210213 if ( this . Options . APIKEY ) this . APIKEY = this . Options . APIKEY ;
211214 if ( this . Options . APISECRET ) this . APISECRET = this . Options . APISECRET ;
215+ if ( this . Options . PRIVATEKEY ) this . PRIVATEKEY = this . Options . PRIVATEKEY ;
216+ if ( this . Options . PRIVATEKEYPASSWORD ) this . PRIVATEKEYPASSWORD = this . Options . PRIVATEKEYPASSWORD ;
212217 if ( this . Options . test ) this . test = true ;
213218 if ( this . Options . headers ) this . headers = this . Options . Headers ;
214219 if ( this . Options . domain ) this . domain = this . Options . domain ;
@@ -535,7 +540,7 @@ export default class Binance {
535540 data . timestamp += this . timeOffset ;
536541 }
537542 query = this . makeQueryString ( data ) ;
538- data . signature = crypto . createHmac ( 'sha256' , this . APISECRET ) . update ( query ) . digest ( 'hex' ) ; // HMAC hash header
543+ data . signature = this . generateSignature ( query ) ;
539544 opt . url = `${ url } ?${ query } &signature=${ data . signature } ` ;
540545 }
541546 ( opt as any ) . qs = data ;
@@ -647,7 +652,9 @@ export default class Binance {
647652
648653 if ( ! data . recvWindow ) data . recvWindow = this . Options . recvWindow ;
649654 const query = method === 'POST' && noDataInSignature ? '' : this . makeQueryString ( data ) ;
650- const signature = crypto . createHmac ( 'sha256' , this . Options . APISECRET ) . update ( query ) . digest ( 'hex' ) ; // set the HMAC hash header
655+
656+ const signature = this . generateSignature ( query ) ;
657+
651658 if ( method === 'POST' ) {
652659 const opt = this . reqObjPOST (
653660 url ,
@@ -670,6 +677,44 @@ export default class Binance {
670677 }
671678 }
672679
680+ generateSignature ( query : string , encode = true ) {
681+ const secret = this . APISECRET || this . PRIVATEKEY ;
682+ let signature = '' ;
683+ if ( secret . includes ( 'PRIVATE KEY' ) ) {
684+ // if less than the below length, then it can't be RSA key
685+ let keyObject : crypto . KeyObject ;
686+ try {
687+ const privateKeyObj : crypto . PrivateKeyInput = { key : secret } ;
688+
689+ if ( this . PRIVATEKEYPASSWORD ) {
690+ privateKeyObj . passphrase = this . PRIVATEKEYPASSWORD ;
691+ }
692+
693+ keyObject = crypto . createPrivateKey ( privateKeyObj ) ;
694+
695+ } catch ( e ) {
696+ throw new Error (
697+ 'Invalid private key. Please provide a valid RSA or ED25519 private key. ' + e . toString ( )
698+ ) ;
699+ }
700+
701+ if ( secret . length > 120 ) {
702+ // RSA key
703+ signature = crypto
704+ . sign ( 'RSA-SHA256' , Buffer . from ( query ) , keyObject )
705+ . toString ( 'base64' ) ;
706+ if ( encode ) signature = encodeURIComponent ( signature ) ;
707+ return signature ;
708+ } else {
709+ // Ed25519 key
710+ signature = crypto . sign ( null , Buffer . from ( query ) , keyObject ) . toString ( 'base64' ) ;
711+ }
712+ } else {
713+ signature = crypto . createHmac ( 'sha256' , this . Options . APISECRET ) . update ( query ) . digest ( 'hex' ) ; // set the HMAC hash header
714+ }
715+ return signature ;
716+ }
717+
673718 // --- ENDPOINTS --- //
674719
675720 /**
0 commit comments