TooTallNate / node-spotify-web

Node.js implementation of the Spotify Web protocol
MIT License
696 stars 128 forks source link

Login not working #87

Closed bowilliams closed 9 years ago

bowilliams commented 10 years ago

Starting this morning, I'm not able to login. I've tried several accounts (all premium).

console.log('about to login');
Spotify.login(login.username, login.password, function (err, spotify) {
  console.log('logged in');

Never gets to logged in- it either hangs at about to login, or I get this error:

TypeError: Cannot read property 'version' of undefined
    at Spotify._resolveAP (/Users/bwilliams/repos/prosecco/local_spotify_player/node_modules/spotify-web/lib/spotify.js:306:50)
    at Spotify._onauth (/Users/bwilliams/repos/prosecco/local_spotify_player/node_modules/spotify-web/lib/spotify.js:294:10)
    at Request.callback (/Users/bwilliams/repos/prosecco/local_spotify_player/node_modules/spotify-web/node_modules/superagent/lib/node/index.js:584:30)
    at Request.<anonymous> (/Users/bwilliams/repos/prosecco/local_spotify_player/node_modules/spotify-web/node_modules/superagent/lib/node/index.js:133:10)
    at Request.EventEmitter.emit (events.js:117:20)
    at IncomingMessage.<anonymous> (/Users/bwilliams/repos/prosecco/local_spotify_player/node_modules/spotify-web/node_modules/superagent/lib/node/index.js:714:12)
    at IncomingMessage.EventEmitter.emit (events.js:117:20)
    at _stream_readable.js:920:16
    at process._tickCallback (node.js:415:13)
fuzeman commented 10 years ago

I've looked into this issue a bit, the 'ping_flash2' command has been changed (again), but it isn't a simple key change this time.

We will probably need to determine the new algorithm used for generating 'pong_flash2' responses. I've traced this back to a "ping_pong" method in "player.swf", but this would need to be deobfuscated.

Not sure how this was found originally, maybe someone else has some ideas?

bowilliams commented 10 years ago

Bummer, that's what I was afraid of! Thanks for looking.

adammw commented 10 years ago

I can't get it the way I'd like, seems like it's not a simple XOR operation anymore but a bit more complex logic, but I can brute force it (ugly I know, but it works): https://gist.github.com/adammw/7f192694c3ed0b13f1f9

reimertz commented 10 years ago

@adammw Good work, that really works!

AndreSteenbergen commented 10 years ago

Do you have means to run player.swf locally, or did you make 256 manual calls to sp_run?

I tried to find any way to calculate the correct number, but so far no luck ...

pablorusso commented 10 years ago

I have been working a bit with this too. I haven't had any luck in decompiling the flash file, but I managed to host the flash file in a local server and obtaining the real pong value using a headless selenium.

I am using flask to load a webserver and then I use selenium to fetch the page and look for the value, whichs opens a firefox to render the page. I managed to do it headless in linux with xvfb.

Final user don't see what is happeing behind the hood, but is slow, requires firefox and flash, so is not something you would like in a library.

Anyway I wanted to share this info, in case you can think of a better alternative based on this. Firefox is the real PITA, I couldn't find a better way to render a HTML+JS+Flash.

TooTallNate commented 10 years ago

In a perfect world we would fire up Shumway within Node.js and load up the player.swf file and invoke the ping_pong function directly.

I know that @adammw looked into this idea though and there were complications related to the fact that the swf file uses Adobe Alchemy to compile C code to Flash, which Shumway didn't support (at the time... not sure if that's changed or not).

pablorusso commented 10 years ago

Just in case it matters, the flash funtion I call is "sp_run"

Miladiir commented 10 years ago

@adammw 's solution doesnt work for me unfortunetly, atleast thats how I interprete it...

C:\Users\miladiir\Desktop\spotify-mp3-downloader-master>node app.js
Server running, to use, open http://localhost:1717 in your browser.
ReferenceError: message is not defined
    at Spotify.<anonymous> (C:\Users\miladiir\Desktop\spotify-mp3-downloader-mas
ter\app.js:104:15)
    at C:\Users\miladiir\Desktop\spotify-mp3-downloader-master\spotify-web\lib\s
potify.js:65:8
    at Spotify.onLogin (C:\Users\miladiir\Desktop\spotify-mp3-downloader-master\
spotify-web\lib\spotify.js:197:5)
    at Spotify.EventEmitter.emit (events.js:92:17)
    at Spotify._onuserinfo (C:\Users\miladiir\Desktop\spotify-mp3-downloader-mas
ter\spotify-web\lib\spotify.js:1239:8)
    at fn (C:\Users\miladiir\Desktop\spotify-mp3-downloader-master\spotify-web\l
ib\spotify.js:396:10)
    at Spotify._onmessage (C:\Users\miladiir\Desktop\spotify-mp3-downloader-mast
er\spotify-web\lib\spotify.js:412:5)
    at WebSocket.EventEmitter.emit (events.js:98:17)
    at Receiver.self._receiver.ontext (C:\Users\miladiir\node_modules\ws\lib\Web
Socket.js:697:10)
    at Receiver.opcodes.1.finish (C:\Users\miladiir\node_modules\ws\lib\Receiver
.js:397:14)
^C

Without the modification I don't get any message at all.

adammw commented 10 years ago

@Miladiir that's an exception in your code, not ours.

dralletje commented 10 years ago

Replaced Spotify.prototype.sendPong in lib/spotify.js with @adammw s code, but still not getting logged in. This is the debug log: https://gist.github.com/dralletje/fbeffd8a0afb1ed14468

Am I doing something wrong?

brandtabbott commented 10 years ago

@adammw thanks for the fix!

TooTallNate commented 10 years ago

You know, I'm not sure what changed on their end, but the current code in the repo is working for me again (without @adammw's patch).

Can anybody else confirm?

Miladiir commented 10 years ago

Yep.

I used npm install spotify-web so not entirely sure if it is the code from master or from some tag, but it definetly works without the fix again. Seems a little bit slower than before though.

patrickrb commented 10 years ago

I seem to be running into this issue as of this morning.

TooTallNate commented 10 years ago

Yup :(

On Mon, Jul 28, 2014 at 8:15 AM, Patrick Burns notifications@github.com wrote:

I seem to be running into this issue as of this morning.

— Reply to this email directly or view it on GitHub https://github.com/TooTallNate/node-spotify-web/issues/87#issuecomment-50352036 .

patrickrb commented 10 years ago

I tried putting @adammw brute force into the spotify.js, no luck. Can we open the issue back up?

juanmito commented 10 years ago

Any idea?

I've been working on this issue. I've only discover that 5º position on pong is 4º ping position XOR 37, and last ping position (19) changes first pong position sometimes. I'm trying to find any pattern. I think it should be great if anyone who discover something could share it here. I'll post my discovers if anyone want :)

AndreSteenbergen commented 10 years ago

It looks like the algorithm got a lot smarter, it is not relating one index to one other. It seems it is changing the internals quite a lot, the final byte looks like it triggers some sort of if/ else effect.

The final byte seems to trigger position 1, 2, 6, 7 and 9, but it also varies at what number it uses the if/ else branche ....

document.querySelector('[id_=_player]').sprun("12 23 125 43 56 72 56 76 45 34 12 64 127 143 1 2 3 4 5 10") "116 189 235 111 47 29 228 95 97 132" document.querySelector('[id=_player]').sp_run("12 23 125 43 56 72 56 76 45 34 12 64 127 143 1 2 3 4 5 11") "116 70 228 111 47 29 235 164 97 175"

document.querySelector('[id_=_player]').sprun("0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0") "95 159 26 39 208 37 53 150 97 187" document.querySelector('[id=_player]').sp_run("0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1") "95 100 53 39 208 37 26 109 97 144"

10 and 11 here both give: "95 159 26 39 208 37 53 150 97 187"

adammw commented 10 years ago

Yep, looks really complex. I'm guessing the idea is that to brute force the algorithm will take a non-trivial amount of time. So I've found pretty much the same as you @juanmito and @AndreSteenbergen: https://gist.github.com/adammw/150435df1e8987606a7e

adammw commented 10 years ago

Interesting. I decided to investigate byte 3 further and found that it depends on input byte 7 when input byte 6 is zero, and then only on input byte 6 for all other values. But it doesn't seem to be an XOR of byte 6 so it's only so helpful. Update: it uses the same 256-item sequence though: https://gist.github.com/adammw/31d7fcf571947f62cea0 (gives byte 3 output) Update: I was wrong. This is crazy.

juanmito commented 10 years ago

Its really complex. Almost all inputs affect all outputs

0 --> 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 1 --> 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 2 --> 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 3 --> 0 1 2 3 4 5 6 7 4 --> 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 5 --> 0 1 2 3 4 6 --> 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 7 --> 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 8 --> 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 9 --> 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

ghost commented 10 years ago

Maybe we can try another solution. Instead of emulating player.swf functionality, we could call and use it to get the pong chain and follow the workflow. Any idea of executing the swf file directly from node and calling sp_run function?

madjam002 commented 10 years ago

I've been trying this evening to call sp_run using Shumway, but I don't fully understand it. Using Shumway, I console.log'd all calls to ExternalInterface.addCallback and the following callbacks got registered:

sp_hasSound
sp_load
sp_play
sp_playpause
sp_stop
sp_pause
sp_resume
sp_time
sp_seek
sp_playerState
sp_setVolume
sp_getVolume
sp_getDuration
sp_initializePlayerById
sp_addPlayer
sp_removePlayerAtIndex 

No sp_run there :( It's probably because the part of player.swf that does the pong stuff is obfuscated whilst the rest isn't, and I don't think Shumway understands it.

Even if sp_run was there, I haven't figured out a way to invoke any of the external callbacks :(

TooTallNate commented 10 years ago

Most likely sp_run is part of the native C code (Alchemy-compiled) portion of the SWF, which indeed, Shumway does not (yet) support. See https://github.com/mozilla/shumway/issues/1110 for some more details.

madjam002 commented 10 years ago

Ah thanks for that! I wasn't even aware Flash allowed you to use C!

AndreSteenbergen commented 10 years ago

Couldn't the swf be run from an own server somewhere, as hsalps has done for spotlite (example: http://spotlite.cloudapp.net/api/pong/139_8_161_89_158_172_20_143_185_165_0_71_169_174_31_176_77_61_116_87)

madjam002 commented 10 years ago

Yeah that's a possibility. PhantomJS can be used to invoke sp_run in an actual webpage. This could be done on a remote server somewhere, but the library is then dependant on that server being up. I guess an advantage to that is when Spotify updates the "ping pong", only the server needs updating and we don't need to wait for a new version of the library.

With regards to Shumway, I managed to extract the abc of the spotify pong method and tried to run it using Shumway, but I got errors about Unknown Op's or something. Digging deeper I discovered that operands lix8 0x33 and a bunch more were being looked up in opcodes.ts but haven't yet been implemented in Shumway. I have very little knowledge about Flash and Actionscript so I'm not really sure what that means at this point :P If anyone wants the abc of the spotify pong function I can upload it later :) I guess I'll be reading up on the AVM2 spec at some point then to see what all this means!

juanmito commented 10 years ago

Hmm, how could you invoke sp_run using PhantomJS? Has anybody used this software?

dralletje commented 10 years ago

As far as I know, PhantomJs can not run flash at all. PhantomJs does only include a browser with a DOM and javascript, no flash player.

Maybe ask the author of spotlite how he did this?

aaiyer commented 10 years ago

shumay has an avm2 impl -- https://github.com/mozilla/shumway/tree/master/src/avm2 -- including some nice disam tools for avm2 bytecode... will experiment when I have more time..

madjam002 commented 10 years ago

@dralletje That's true actually. Ages ago when I was playing around with Spotify's websocket stuff I managed to use PhantomJS to call some functions, but they have dropped support for flash since then. Still, something similar like Awesomium could be used.

jhvst commented 10 years ago

SlimerJS, which is like PhantomJS but runs Gecko, is able to run flash if corresponding addons are installed. Though in my opinion running something like that alongside this libary is bit unpractical, even if it would work.

madjam002 commented 10 years ago

@9uuso I don't think SlimerJS is truly headless, which would cause problems on servers unless you're running something like xvfb. But yeah I agree that the library should probably be as lightweight as possible. Shumway or something similar would be the way to go, but unfortunately I don't think Shumway has implemented all of the avm2 opcodes which are necessary to get the ping_pong function working.

I think @AndreSteenbergen's idea is the best for now, just have an HTTP API which we can query which runs something like SlimerJS (with xvfb) or Awesomium to access the actual flash file.

1994rstefan commented 10 years ago

Hello, I also think @AndreSteenbergen's idea is the best for now. I already set up everything on my local computer. Currently someone can send a request like "http://xxx/12 23 125 43 56 72 56 76 45 34 12 64 127 143 1 2 3 4 5 10" and will get the Pong as the response. I am going to upload this tommorow and publish a working link here if someone is interested.

TooTallNate commented 10 years ago

@1994rstefan Can you open-source the "server" portion so that we can spin up our own and check out the code?

juanmito commented 10 years ago

@1994rstefan Thanks a lot :)

1994rstefan commented 10 years ago

Sure https://github.com/1994rstefan/Spotify-Ping-Pong-API

But it is realy ugly currently ;D You have to start the server.js with node and then open http://localhost:8080/browser.html in your local browser. The node server queues ping requests, the browser checks for new pings and sends back the pong via ajax to the node server which then response with the pong to the inital request.

pablorusso commented 10 years ago

Hey,

I have gone that road. I have implemented a local server, with xvfb and an old version of phantomJS that supports flash. You can see my implementation in python here https://github.com/pablorusso/Spotify2.bundle/tree/local_flash (its a plex media server spotify plugin)

As I was not building a library, the solution was not that bad but it still has lot of drawbacks (very slow and linux only); Its more a workaround to be able to listen spotify in my living :-P In case you want to try it, note that I haven't updated yet the player.swf file in my github repo.

Btw, I have too tried different tools and approaches to reverse de C code inside the flash without any luck.

On Wed, Jul 30, 2014 at 6:59 PM, Stefan notifications@github.com wrote:

Sure https://github.com/1994rstefan/Spotify-Ping-Pong-API

But it is realy ugly currently ;D You have to start the server.js with node and then open http://localhost:8080/browser.html in your local browser. The node server queues ping requests, the browser checks for new pings and sends back the pong via ajax to the node server which then response with the pong to the inital request.

— Reply to this email directly or view it on GitHub https://github.com/TooTallNate/node-spotify-web/issues/87#issuecomment-50686189 .

Pablo.- http://about.me/russopablo

madjam002 commented 10 years ago

I also experimented earlier with a server using atom-shell as the browser for running player.swf. atom-shell isn't headless, but I've pushed it to github anyway as it might be of some use.

https://github.com/madjam002/node-spotify-pingpong

This could be run on a server somewhere using xvfb. Horrible implementation for now, but I was just experimenting :)

juanmito commented 10 years ago

@madjam002 Could I use your implementation using another browser instead atom-shell? I've been experimenting some problems installing Atom..

madjam002 commented 10 years ago

What problems are you having with atom-shell? You shouldn't need to install Atom (the text editor), only atom-shell. You can follow the guide at https://github.com/atom/atom-shell/blob/master/docs/tutorial/quick-start.md

I'll have a look into using other browsers later if I have time :)

juanmito commented 10 years ago

Yes, i've tried downloading the zip file, but, when i'm going to execute it, it says: ./atom: Cannot execute binary file.

madjam002 commented 10 years ago

What operating system are you using and which atom-shell release are you downloading? Make sure it's the x64 or ia32 depending on your processor.

juanmito commented 10 years ago

Yes, I know. I've using Ubuntu Linux x64, but don't know what happen exactly.

madjam002 commented 10 years ago

Hmm okay, I'm not sure sorry. I haven't tried atom-shell on Linux, only OS X :P I'll look at using other browsers later :)

juanmito commented 10 years ago

Nah, don't worry, I'll try to run atom later.. thx anyway :)

juanmito commented 10 years ago

Finally, i've been using the solution proposed by @1994rstefan. I wanted to use it in a Raspberry PI, but I realized that there is no flash plugin for Rasp, and I couldn't read player.swf.

Thanks for all. Btw, has anybody done any discover about the new pingpong algorithm?

AndreSteenbergen commented 10 years ago

The problem with this algorithm is all indexes from ping are affecting some value on the pong. I have tried to go through the AVM bytecode, but that is a job for a monk, and by the time the algorithm is found, it will be changed again. I guess a lot of the 256 ^ 20 options will end up in the same pong, but going down that road isn't going to really work either. We would need huge storage capabilities, for something lame as a ping pong ...

madjam002 commented 10 years ago

I think now we need to try and work out a solution which is practical for the library. If we're going down the road of calling the pong function directly, maybe a hosted API like Spotlite? In that case we would need to work out a way of setting up a central server for this.

At the moment that seems like the only practical way until something like Shumway is capable of running it.