-
Notifications
You must be signed in to change notification settings - Fork 19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New parameters to https://www.pandora.com/api/v1/auth/login #45
Comments
I've just ran into this issue as well (stopping my 2+ years of work towards my client in its tracks). I'm inspecting the source code to see how these value are generated - if you want to, you can use my tool to download the sources (the download button is in the top right): https://toolbox.epimetheus.tk/#source_code |
There seem to be no significant Web app source changes between version 1.153.0 (the last version I have before the change) and the latest 1.158.1, suggesting that this was a server-side change that's been long coming. |
These new properties seem to be used for bot mitigation, in a new feature referred to as "Detector" internally. |
There are references to White Ops. |
The White Ops report is embedded into the login request - that's what those values are for. Unfortunately, the script is obfuscated... |
Note the "hoplon" subdomain - a Hoplon is a Greek shield. |
Another script is accessed by the script linked above: https://s.hoplon.pandora.com/sri/config.json |
This may be the end for unofficial REST API usage; the bot detection seems to be highly reliant on the browser environment, and there aren't even public SDKs available. Is the JSON API's authToken compatible with the REST API? If so, perhaps the initial login can be done with it, as this bot detection seems to be used only for login. |
@hacker1024 Please edit your initial post instead of posting multiple times in a row. Looking at PromyLOPh/pianobar#236 this was probably overdue. Pandora never really liked 3rd party developers using their web API’s. Can I remove the documentation for that API from this repository? |
It looks like the JSON API authToken is actually compatible with the REST API! That means existing software can use the JSON API for logging in and no other code needs to be updated. I think it's worth keeping the REST documentation up, as it's still usable in this way. |
so how can we login pandora? |
@GodStar88 Use the JSON API to obtain the |
thank you for your reply, I tried that, but i can't login pandora |
@GodStar88 what's going wrong exactly? Can you share your code? |
I tried postman, I can't login |
There are 3 new fields for authentication. If they are missing, the login fails as if it's invalid credentials.
Where:
Repeatedly using the same Hoplon URL parameters seems to work fine, although I am suspicious this may change as the web client version number changes. The response from Hoplon is malformed JSON; string substitute "\\x26" -> "&" and "\\x3D" -> "=" to make it valid (These strings are presented here as quoted for C/C++; i.e., these are 4-character strings starting with a single backslash). In the resulting JSON, members
The encryption is an RC4 variant bastardized for ASCII.
The encryption map is then constructed, and characters in the input are then encrypted one at a time. There's some funky stuff to deal with Unicode characters, reminiscent of UTF-8 encoding, that encodes them as multiple bytes. For reference, I've included a C++ implementation of this encryption below.
|
@GodStar88 This whole system is designed to block bots. I think you're out of luck. |
Any update on this? I've been doing research as well and here are a few additional notes. As noted, OZ_SG is an encrypted JSON encoded array of messages, including various data from browser information to events. OZ_TC is used for the encryption. OZ_TC and OZ_DT come from a call to /config.json. I've captured the unencrypted values of OZ_SG for several logins, some manual and some automated via selenium/chromium. Of course, the manual logins are successful while the automated ones are not. After looking through OZ_SG, the only thing that strikes me as a potential bot indicator are document event logs that are stored, which hold things like keystrokes and other page actions. That being said, if that was all there was to it, then you should be able to intercept the function to generate OZ_SG before encryption takes place and replace the messages with those captured from a valid / human session. However, that doesn't seem to work. I'm thinking one of two things are happening (possibly more).
In summary, I'm trying to identify the true purpose of OZ_DT and how it is used. My original inclination was that it is a base64 encoded cryptographic hash of the config.json page (since config.json is dynamically loaded by pagespeed.js). As this data and OZ_TC change on each call to config.json, it could be that OZ_TC is used as a key for this hash. I think OZ_DT may hold some secrets in understanding what is happening. I'm also interested in knowing why replacing (the unencrypted) OZ_SG with values from a valid previous session isn't working. Timing could be a factor. Also, it's very clear that the combination of username, password, OZ_TC, OZ_DT, and OZ_SG is a one-time-use credential. Resubmitting previously accepted values doesn't work. |
I copied the OZ_TC, OZ_DT, and OZ_SG values from an intercepted request into my code and managed to log in with the same credentials, but not with another account. |
I think I missed an email where someone asked for an example of using JSON authentication to obtain a token to be used with the REST API, to be used with CURL. I can't find that message again, but I'll respond here nonetheless: Logging in with the JSON API is a multi-step process, requiring partner authentication and sync-time handling. I can use my WIP Dart package to build a CLI tool that takes credentials and spits out an authentication token, if that's helpful to anyone? Dart can compile directly to machine code, as well as JavaScript. |
@hacker1024 I was the one asking about that. A tool as you describe would certainly be useful. |
This would be a godsend if you're able :) |
@H0r53 @FireController1847 |
Sweet, thanks a ton. I managed to get the JSON endpoint up and running after quite a lot of trail and error. It appears as though the REST API does not accept the userAuthToken achieved via the JSON API. I'm not sure why that is the case so this will be super helpful |
I used the JSON API for the tool, but it worked for the REST API for me... |
Really? Maybe I was doing something wrong, I'll take another shot at it tonight. |
@hacker1024 So I just took another shot at it, and it appears that the access token that I am getting through the JSON api is invalid for use with the REST api, but yours is not. What partner are you using for authentication? At the moment I am using IOS because that is the only one I could get the |
@FireController1847 I'm using Android, and I've also been able to use the old credentials I mentioned in #48. |
Sure thing. I've been using a testing account for all of this so I have no problem sharing these, I'll delete them once you're done working with them. I switched to using the same android one as you and still cannot use Username: I will note, now that I've switched to Android the auth tokens look a lot more similar now. |
Interesting - that token does in fact give me the error you described. It's missing a Can you try this one: |
Strange, the one you provided me has worked. Also, the second equal at the end was not a typo that is how I have been receiving them, I find it strange that you are receiving them differently than me haha. Maybe we should continue this discussion on a platform like Discord? If you want, of course. My username is FireController1847#3577 |
Sure thing. @PromyLOPh, could you also maybe enable GitHub discussions? |
@hacker1024 Yeah, done. Please move discussions there. |
@PromyLOPh you provided a C++ implementation of the encryption - would it be possible to provide the corresponding decryption routine? |
Apologies, the question was intended for @perette |
@H0r53 Sorry, I have no plans to implement the decryption. I am curious what you need it for? With a breakpoint set in the JavaScript in the right place, you can retrieve the unencrypted messages using a browser's inspection window. |
@perette let's say I was limited to intercepting / forwarding requests without the luxury of a browser's devtools. With decryption it would become easier to recover messages, adjust, and re-encrypt. |
I'm a little bit late to the party, but here are some things I've noticed.
|
I'm late to the game but I'm very interested in adding playlist support to pianobar (PromyLOPh/pianobar#656). I been sniffing the REST API of the web app and I think I've figured out what I need to do, but have no idea how do proceed using the JSON API. What is the status of logging in using the RESP API 2024, is it hopeless? Is the JSON API's authToken still compatible with the REST API? It seems like all new Pandora related development stopped 3 years ago? |
@H0r53 re: providing decryption: No. Although it could potentially be helpful in working with the REST API, I've migrated back to the JSON API where it's not needed. Also, no time, and I don't have the cryptographic knowledge without a bunch of brushing up. It is some variant of RC4, so perhaps you could adapt or crib from an RC4 decrypt implementation? |
@perette Thanks for the quick response! Where I'm stuck is that I haven't been able to find any documentation on how to retrieve a list of playlists using the JSON API. From looking at some of @hacker1024 dart code I think it's playlists.v7.getTracks but when I tired to guess what the format of the parameters is I just back the super helpful response:
My request was:
Where XXX was the userAuthToken obtained by pianobar and ZZZ is my listenerid. |
I could create the decryption routine but I don't really care to at this point. It's been a few years since I've been interested in this. Regarding the question "How can pandora tell if a request is from an actual browser if OZ_SG is not sending any data? It must be through OZ_TC/OZ_DT" - there are several ways that the backend can detect if a request is sent from an actual browser, including device fingerprinting, TLS fingerprinting and more. @skiphansen - it should be noted that Pandora does not want people to automate login, streaming, or any other bot activity. This repo is not an official Pandora API Doc. To bypass the security measures in place you will need to hack your way through them. This is also a public forum so Pandora is likely to be monitoring the discussion at this point. Any solutions shared would be easy for them to react to. |
@H0r53 I understand this repo isn't official. My interest is in adding playlist support to pianobar not creating a new app. I know that pianobar isn't an officially authorized app, but it seems pretty clear that Pandora is tolerating it to some extent considering how long it's been around and some change log comments I've seen in other programs where they have changed changed their user agent to copy pianobar's in order to login. If anything since I believe playlists are a feature only supported for paid accounts if anything supporting them might cause a few uses to upgrade to a subscription. It would be easier to use the JSON API, but I can't find any documentation on how to use the JSON API to list Pandora playlists. I have experience reverse engineering things by protocol sniffing, but I have zero experience with reverse engineering APKs, hence that's the approach I've taken so far. I think I know how to get playlists from the REST API and hence my interest. |
Up until yesterday, both the pandora.com web site and my own code were using the REST API to login with no problem, sending 4 parameters (existingAuthToken, username, password, keepLoggedIn). But now the web site is sending three more parameters named OZ_TC, OZ_DT, OZ_SG. The contents are encoded or encrypted. Without those 3 parameters, my code is now getting back: {"message":"Invalid username and/or password","errorCode":0,"errorString":"AUTH_INVALID_USERNAME_PASSWORD"}
Anyone know what those parameters are?
The text was updated successfully, but these errors were encountered: