n0mad01 / node.bittrex.api

No longer maintained
MIT License
183 stars 187 forks source link

How to WS SubscribeToUserDeltas? #38

Closed kroitor closed 7 years ago

kroitor commented 7 years ago

Hi! From what I see here: https://www.bittrex.com/signalr/hubs and here: https://github.com/n0mad01/node.bittrex.api/issues/23 Bittrex SignalR has SubscribeToUserDeltas, but I can't see any code able to subscribing to user deltas and do the auth over ws in node.bittrex.api package...

 var setConnectedWs = function(markets) {
    wsclient.serviceHandlers.connected = function(connection) {
      markets.forEach(function(market) {
        wsclient.call('CoreHub', 'SubscribeToExchangeDeltas', market).done(function(err, result) {
          if (err) {
            return console.error(err);
          }

          if (result === true) {
            ((opts.verbose) ? console.log('Subscribed to ' + market) : '');
          }
        });
      });
      ((opts.verbose) ? console.log('Websocket connected') : '');
    };
  };

It only subscribes to exchange deltas upon connecting. Do you have plans/know how to implement the authenticated part of their SignalR API? This is not documented anywhere.

ghost commented 7 years ago

To Authenticate over the websocket you will have to login from the browser and then grab the .AspNet.ApplicationCookie from the page code and pass it as a cookie in the websocket headers. I tested it and it worked by updating the balance and the open orders.

Easier said than done if you plan to automate the process by doing it programmatically. I have been working on this all day and I am stuck at the 2FA bit. I can't get the Google Authenticator API to generate the right Pin :(

kroitor commented 7 years ago

@Squeaky-bed thanks for your comment! Can you please share a snippet of code or a gist showing how you would put a cookie there manually (add to ws headers by means of the underlying signalr-client)?

jsonoldusername commented 7 years ago

@kroitor I tried doing this by stealing the cookie from a page in chrome (stopping all page JS from executing on page load), but my requests kept getting flagged as XSS, despite trying to make sure all the headers matched from chrome to my manual Websockets request. Basically you need to attach these cookies in the header of the websockets connection request. I'm currently seeing if looped, static API calls can suffice for what I need currently. Otherwise I will explore attaching my code as a Chrome plugin that can access/query the DOM and the Knockout.js data, and place trades that way.

(value is omitted) screen shot 2017-08-20 at 10 07 13 pm

@Squeaky-bed I'd be curious to see learn specifically what issues you had with the 2FA bit, my understanding is that you can't get a TOTP code for another app unless you have that app's (Bittrex in this case) private Google 2FA key, but I might be confused https://github.com/google/google-authenticator/issues/234. But how did you snag the cookie from a browser and place it into your headers? My requests keep getting flagged as XSS...

kroitor commented 7 years ago

@jsonhuntrods , thx for your comment! Can you please share a snippet of code that would set the cookie in headers with the underlying signalr-client used in node.bittrex.api ?

jsonoldusername commented 7 years ago

@kroitor I wasn't able to actually get it to work, but basically right after Signalr client initialization here https://github.com/n0mad01/node.bittrex.api/blob/master/node.bittrex.api.js#L161, I set a bunch of headers like this

wsclient.headers['Accept-Language'] = 'en-US,en;q=0.8,la;q=0.6';
wsclient.headers['Cache-Control'] = 'no-cache';
wsclient.headers['Connection'] = 'Upgrade';
wsclient.headers['DNT'] = '1';
wsclient.headers['Host'] = 'socket.bittrex.com';
wsclient.headers['Origin'] = 'https://bittrex.com';
wsclient.headers['Pragma'] = 'no-cache';
wsclient.headers['Sec-WebSocket-Extensions'] = 'permessage-deflate; client_max_window_bits';
wsclient.headers['Sec-WebSocket-Version'] = '13';
wsclient.headers['User-Agent'] = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36';
wsclient.headers['Upgrade'] = 'websocket';
wsclient.headers['Cookie'] = '__cfduid=cookie1; .AspNet.ApplicationCookie=cookie2';

Those headers basically matched what I was using in google chrome. What I did initially was use a request logger to see what the requests going from my Node.js server looked like, it was something like this:

var globalLog = require('global-request-logger');
globalLog.initialize();

That shows everything the node-bittrex-api is sending to Bittrex. Then I compared it to what was being sent in my network tab of chrome locally, specifically the Signalr negotiate call that must be made prior to the websockets connection, and then I looked at the connection itself.

screen shot 2017-08-21 at 7 14 30 pm screen shot 2017-08-21 at 7 14 46 pm

So I make sure all the request headers line up and look the same. But a new cookie is generated on every page load, and might be allowed to initiate a single Websockets connection. So I put a debugging point somewhere in the page's Javascript that would stop the initial connection from happening, grabbed the cookies from the page, put them in the headers, and then tried subscribing from my Node.js instant. I still didn't have any luck. If I didn't include the cookie, it just subscribed me to the exchange summary feed (probably default for when someone isn't authorized), but when I included the cookie I got an error response that said I wasn't authorized and the response had XSS attack parameters set, so Bittrex thought I was doing a XSS attack. Which the only way to really check an XSS attack is to analyze the headers/data sent in the request, so maybe I was missing something.

kroitor commented 7 years ago

@jsonhuntrods thanks for this very comprehensive feedback! Appreciate it!

dezza commented 6 years ago

Hey guys. There are others who have succeeded :) https://github.com/toorop/go-bittrex/issues/23

Take a peek at https://github.com/cardigann/go-cloudflare-scraper/blob/master/cloudflare.go