Comments (15)
Hi @hillstub!
Thank you for testing the project on your Denon receiver. Too bad it does not work!
I had a look to the Spotify ZeroConf documentation and indeed, the path is not hard coded and can change. I added an optional parameter to take it into account. By the way, librespot
uses /
as path, but does not check it so everything works. I still set /
as the default path.
According to the documentation, ERROR-BAD-REQUEST
means "Web server problem or critically malformed request". That's not good...
I saw in the documentation that you can provide an optional version parameter to the requests. If the Spotify SDK in Denon receiver is backward compatible, it could help to give the version. librespot
indicates version 2.7.1
. The documentation speaks about 2.9.0
. Maybe you can modify src/net.rs
and test both version number:
// [...]
let response = minreq::get(base_url)
.with_param("action", "getInfo")
.with_param("version", "2.7.1") // add this line and test both 2.7.1 and 2.9.0
.send()?;
// [...]
let response = minreq::post(base_url)
.with_header("Content-Type", "application/x-www-form-urlencoded")
.with_param("action", "addUser")
.with_param("version", "2.7.1") // add this line and test both 2.7.1 and 2.9.0
.with_param("userName", username)
.with_param("blob", encrypted_blob)
.with_param("clientKey", my_public_key)
.send()?;
// [...]
If this does not work, I have another idea. But I need to change code first.
By the way, can you send the result of the following command:
curl -X GET http://IP:PORT/spotify?action=getInfo
It could help to understand how the Denon receiver is working. You can redact deviceID
or any other personal information.
from spotify-connect.
Hi Timothee,
Thanks for your reply! I retrieved the device info which shows it's using version 2.7.1:
{
"status": 101,
"statusString": "OK",
"spotifyError": 0,
"version": "2.7.1",
"deviceID": "REDACTED",
"remoteName": "Denon AVR-X1600H",
"activeUser": "REDACTED",
"accountReq": "DONTCARE",
"deviceType": "AVR",
"publicKey": "REDACTED",
"brandDisplayName": "Denon",
"modelDisplayName": "Denon AVR-X1600H",
"libraryVersion": "3.55.23-g85f0da1e",
"resolverVersion": "0",
"groupStatus": "NONE",
"tokenType": "accesstoken",
"clientID": "REDACTED",
"productID": 24,
"scope": "streaming",
"availability": "",
"voiceSupport": "NO"
}
When I added this version number to the different request, I'm still getting the same error.
I forgot to tell yesterday that I do get emails from Spotify about a login attempt - so at least something is happening at the Spotify backend.
from spotify-connect.
From the documentation you mentioned it seemed that tokenType
is also a mandatory field. In the add_user
function, I added the following:
.with_param("tokenType", "default")
It now shows the following error:
Found `Denon AVR-X1600H`. Trying to connect...
thread 'main' panicked at 'Authentication on the remote device failed: "ERROR-LOGIN-FAILED"', src/main.rs:65:6
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
(and I don't seem to get an email from Spotify about a login attempt)
from spotify-connect.
I set up MITMProxy to intercept the traffic between the official Spotify app and the receiver. This is the addUser
request in curl format:
curl --compressed -H 'Connection: keep-alive' -H 'Content-Type: application/x-www-form-urlencoded' -H 'Keep-Alive: 0' -H 'User-Agent: Spotify/REDACTED' -X POST http://{IP}/spotify -d
'action=addUser
&userName=REDACTED
&blob=REDACTED
&clientKey=
&tokenType=accesstoken
&loginId=REDACTED
&deviceName=REDACTED
&deviceId=REDACTED
&version=2.7.1'
from spotify-connect.
Thanks for the getInfo
and the addUser
interception!
I forgot to tell yesterday that I do get emails from Spotify about a login attempt - so at least something is happening at the Spotify backend.
(and I don't seem to get an email from Spotify about a login attempt)
The tool I created log you on Spotify to get reusable credentials. So, even if the login failed on your receiver, you should have made a successful connection to Spotify in the tool. If you don't see successful connection now, it is certainly because the reusable credentials are cached. If the cache is present, the connection to Spotify is not made. You can try to delete the cache ($HOME/.cache/spotify-connect/credentials.json
) to see what exactly triggers an email from Spotify.
It seems that your receiver accept token as a form of authentication. I didn't have enough time to implement it, but I pushed some changes to prepare for token authentication.
And there is something new you can try: direct username/password authentication, instead of using them to get the reusable credentials. To try it, add the following option on the command line:
spotify-connect --auth-type password IP PORT [PATH]
This new authentication flow is working great with librespot
. I hope it would be the case on your hardware too!
from spotify-connect.
Hi Timothee,
Thanks for starting to implement the authentication using a token!
I tested the direct username/password authentication - unfortunately that didn't work..
from spotify-connect.
I just pushed a new version. Token authentication is implemented.
spotify-connect --auth-type token IP PORT [PATH]
It works great with librespot
. But librespot
is only relying on the content of the blob. And for now, the different authentication methods only change the way the blob is created. Official hardware may also use other query parameters. Can you try both the code as is, and with a .with_param("tokenType", "accesstoken")
in the net::add_user()
?
If it is still not working, I will have to simulate a Spotify Connect endpoint as close as possible to your receiver and log all the messages received from the official Spotify client.
MITM would not be enough, because at least one private key is necessary to decrypt the blob. Getting the private key from the official client or from your receiver is beyond my competences.
from spotify-connect.
I have simulated a Spotify Connect endpoint and used the official Spotify client to communicate with it. This is what I learnt from this experiment.
The presence and value of tokenType
in the getInfo
request change the way the official client try to authenticate:
- If there is no
tokenType
or if its value isdefault
, the client construct a blob with what I call reusable credentials, encrypt it and send it with theclientKey
(necessary to decrypt the blob on the other side). - If
tokenType
isaccesstoken
, the client does not send aclientKey
. So, the blob is not encrypted. I suspect that the blob field is populated with the token directly (at least, they look similar). But"tokenType": "accesstoken"
alone is not enough. AclientId
field should be present. The value should be a validclientId
(one can ask for aclientId
in the Spotify dashboard). Giving theclientId
from the official Spotify client does not work. Perhaps there is aclientId
verification on Spotify servers (or a blacklist in the official client) to avoid usurpation. I think the token should be generated for thisclientId
, with the specifiedscope
.
What I don't understand yet is the loginId
field in the addUser
request. It is different each time, like the token. Are they linked? Or is it simply a unique identifier for this login request?
I will try to make a new version which take everything I noticed into account. But I wanted to write down what I learned first.
from spotify-connect.
I just pushed a version which take both default
and accesstoken
into account. I have a good feeling about this! @hillstub, can you test both authentication methods and tell me if its working?
spotify-connect --auth-type default-token IP PORT [PATH]
spotify-connect --auth-type access-token IP PORT [PATH]
from spotify-connect.
Awesome that you did all the research in getting this some steps closer to solving this.
Did you commit the last version? I got the following error when trying access-token
:
error: "access-token" isn't a valid value for '--auth-type <AUTH_TYPE>'
[possible values: reusable, password, token]
from spotify-connect.
Yes, the last version with access-token
as been pushed in the middle of the night. Are you up-to-date? It seems your version is on commit 36d5421, while it should be on c236043 for the latest version.
You should execute this to get the latest version:
git pull
cargo install --path .
Maybe your git pull
failed. It can happen if you had uncommitted changes for example.
from spotify-connect.
Whoops - forgot to run the last command.
It worked! Woot woot! Thank you for solving this!!
The only thing is that once I authenticated and try running the spotify-connect command again (with and without removing credentials.json
) it fails with the following error:
thread 'main' panicked at 'Authentication on the remote device failed: "{\"spotifyError\":12,\"status\":202,\"statusString\":\"ERROR-LOGIN-FAILED\"}"', src/main.rs:117:6
from spotify-connect.
It worked! Woot woot! Thank you for solving this!!
At last! This is such a good news!
🎉 🎉 🎉 🎉 🎉 🎉 🎉 🎉 🎉
The only thing is that once I authenticated and try running the spotify-connect command again (with and without removing credentials.json) it fails with the following error:
Maybe the login attempt fails if you are already logged in. Try to log out, before running the command once again.
According to the documentation, you should be able to log out by sending an empty POST request:
curl -X POST http://<IP>:<PORT>/<PATH>
If it does not work, you can try to turn off and on your receiver to log out.
from spotify-connect.
Thanks, Timothee!
I had to use the following command to log out the user:
curl -X POST -d action=resetUsers http://<IP>:<PORT>/<PATH>
After that it was possible to login again using the spotify-connect
command.
In the (near) future, I'll follow your approach to write a C++ library so that I can use this on an ESP32. Will link to your repository as soon as I have something working.
from spotify-connect.
I read the documentation too fast... Well done finding the missing action
in the request.
I am glad to see that it works correctly. Next step, I will change the default behaviour to automatically choose the best authentication method according to the context. Other methods will still be supported, behind the --auth-type
flag.
Good luck writing your C++ library! ESP32 are cool little beast.
I am closing this issue now that it is working on your receiver. Many thanks for your help and for testing all the versions!
from spotify-connect.
Related Issues (2)
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from spotify-connect.