Skip to content
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

Bring back username/password to make it work under CDN #154

Merged
merged 7 commits into from
Sep 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[submodule "cspot/bell"]
path = cspot/bell
url = https://github.com/philippe44/bell
branch = misc
branch = develop
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ After building the app, the only thing you need to do is to run it through CLI.
$ ./cspotcli

```
If you run it with no parameter, it will use ZeroConf to advertise itself. This means that until at least one **local** Spotify Connect application has discovered and connected it, it will not be registered to Spotify servers. As a consequence, Spotify's WebAPI will not be able to see it. If you want the player to be registered at start-up, you need to either use username/password all the time or at least once to create a credentials file and then re-use that file. Run it with -u/-p/-c once and then run it with -c only. See command's line help.

Now open a real Spotify app and you should see a cspot device on your local network. Use it to play audio.

Expand Down
2 changes: 1 addition & 1 deletion cspot/bell
Submodule bell updated 471 files
31 changes: 31 additions & 0 deletions cspot/include/CSpotContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,16 @@
#include "LoginBlob.h"
#include "MercurySession.h"
#include "TimeProvider.h"
#include "Crypto.h"
#include "protobuf/metadata.pb.h"
#include "protobuf/authentication.pb.h" // for AuthenticationType_AUTHE...
#ifdef BELL_ONLY_CJSON
#include "cJSON.h"
#else
#include "nlohmann/detail/json_pointer.hpp" // for json_pointer<>::string_t
#include "nlohmann/json.hpp" // for basic_json<>::object_t, basic_json
#include "nlohmann/json_fwd.hpp" // for json
#endif

namespace cspot {
struct Context {
Expand All @@ -26,6 +35,28 @@ struct Context {

std::shared_ptr<TimeProvider> timeProvider;
std::shared_ptr<cspot::MercurySession> session;
std::string getCredentialsJson() {
#ifdef BELL_ONLY_CJSON
cJSON* json_obj = cJSON_CreateObject();
cJSON_AddStringToObject(json_obj, "authData", Crypto::base64Encode(config.authData).c_str());
cJSON_AddNumberToObject(json_obj, "authType", AuthenticationType_AUTHENTICATION_STORED_SPOTIFY_CREDENTIALS);
cJSON_AddStringToObject(json_obj, "username", config.username.c_str());

char* str = cJSON_PrintUnformatted(json_obj);
cJSON_Delete(json_obj);
std::string json_objStr(str);
free(str);

return json_objStr;
#else
nlohmann::json obj;
obj["authData"] = Crypto::base64Encode(config.authData);
obj["authType"] = AuthenticationType_AUTHENTICATION_STORED_SPOTIFY_CREDENTIALS;
obj["username"] = config.username;

return obj.dump();
#endif
}

static std::shared_ptr<Context> createFromBlob(
std::shared_ptr<LoginBlob> blob) {
Expand Down
7 changes: 6 additions & 1 deletion cspot/protobuf/authentication.options
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,9 @@ LoginCredentials.username max_size:30, fixed_length:false
LoginCredentials.auth_data max_size:512, fixed_length:false
SystemInfo.system_information_string max_size:16, fixed_length:false
SystemInfo.device_id max_size:50, fixed_length:false
ClientResponseEncrypted.version_string max_size:32, fixed_length:false
ClientResponseEncrypted.version_string max_size:32, fixed_length:false
APWelcome.canonical_username max_size:30, fixed_length:false
APWelcome.reusable_auth_credentials max_size:512, fixed_length:false
APWelcome.lfs_secret max_size:128, fixed_length:false
AccountInfoFacebook.access_token max_size:128, fixed_length:false
AccountInfoFacebook.machine_id max_size:50, fixed_length:false
29 changes: 29 additions & 0 deletions cspot/protobuf/authentication.proto
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ enum Os {
OS_BCO = 0x16;
}

enum AccountType {
Spotify = 0x0;
Facebook = 0x1;
}

enum AuthenticationType {
AUTHENTICATION_USER_PASS = 0x0;
AUTHENTICATION_STORED_SPOTIFY_CREDENTIALS = 0x1;
Expand All @@ -62,4 +67,28 @@ message ClientResponseEncrypted {
required LoginCredentials login_credentials = 0xa;
required SystemInfo system_info = 0x32;
optional string version_string = 0x46;
}

message APWelcome {
required string canonical_username = 0xa;
required AccountType account_type_logged_in = 0x14;
required AccountType credentials_type_logged_in = 0x19;
required AuthenticationType reusable_auth_credentials_type = 0x1e;
required bytes reusable_auth_credentials = 0x28;
optional bytes lfs_secret = 0x32;
optional AccountInfo account_info = 0x3c;
optional AccountInfoFacebook fb = 0x46;
}

message AccountInfo {
optional AccountInfoSpotify spotify = 0x1;
optional AccountInfoFacebook facebook = 0x2;
}

message AccountInfoSpotify {
}

message AccountInfoFacebook {
optional string access_token = 0x1;
optional string machine_id = 0x2;
}
2 changes: 1 addition & 1 deletion cspot/src/CDNAudioFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#include "Utils.h" // for bigNumAdd, bytesToHexString, string...
#include "WrappedSemaphore.h" // for WrappedSemaphore
#ifdef BELL_ONLY_CJSON
#include "cJSON.h "
#include "cJSON.h"
#else
#include "nlohmann/json.hpp" // for basic_json<>::object_t, basic_json
#include "nlohmann/json_fwd.hpp" // for json
Expand Down
2 changes: 1 addition & 1 deletion cspot/src/LoginBlob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#include "Logger.h" // for CSPOT_LOG
#include "protobuf/authentication.pb.h" // for AuthenticationType_AUTHE...
#ifdef BELL_ONLY_CJSON
#include "cJSON.h "
#include "cJSON.h"
#else
#include "nlohmann/detail/json_pointer.hpp" // for json_pointer<>::string_t
#include "nlohmann/json.hpp" // for basic_json<>::object_t, basic_json
Expand Down
10 changes: 9 additions & 1 deletion cspot/src/Session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
#include "PlainConnection.h" // for PlainConnection, timeoutCallback
#include "ShannonConnection.h" // for ShannonConnection

#include "pb_decode.h"
#include "NanoPBHelper.h" // for pbPutString, pbEncode, pbDecode
#include "protobuf/authentication.pb.h"

using random_bytes_engine =
std::independent_bits_engine<std::default_random_engine, CHAR_BIT, uint8_t>;

Expand Down Expand Up @@ -79,9 +83,13 @@ std::vector<uint8_t> Session::authenticate(std::shared_ptr<LoginBlob> blob) {
auto packet = this->shanConn->recvPacket();
switch (packet.command) {
case AUTH_SUCCESSFUL_COMMAND: {
APWelcome welcome;
CSPOT_LOG(debug, "Authorization successful");
pbDecode(welcome, APWelcome_fields, packet.data);
return std::vector<uint8_t>(
{0x1}); // TODO: return actual reusable credentaials to be stored somewhere
welcome.reusable_auth_credentials.bytes,
welcome.reusable_auth_credentials.bytes + welcome.reusable_auth_credentials.size
);
break;
}
case AUTH_DECLINED_COMMAND: {
Expand Down
13 changes: 9 additions & 4 deletions targets/cli/CommandLineArguments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@
#include "protobuf/metadata.pb.h" // for AudioFormat_OGG_VORBIS_160, AudioF...

CommandLineArguments::CommandLineArguments(std::string u, std::string p,
bool shouldShowHelp)
: username(u), password(p), shouldShowHelp(shouldShowHelp) {}
std::string c, bool shouldShowHelp)
: username(u), password(p), credentials(c), shouldShowHelp(shouldShowHelp) {}

std::shared_ptr<CommandLineArguments> CommandLineArguments::parse(int argc,
char** argv) {

if (argc == 1) {
return std::make_shared<CommandLineArguments>("", "", false);
return std::make_shared<CommandLineArguments>("", "", "", false);
}
auto result = std::make_shared<CommandLineArguments>("", "", false);
auto result = std::make_shared<CommandLineArguments>("", "", "", false);
for (int i = 1; i < argc; i++) {
auto stringVal = std::string(argv[i]);

Expand All @@ -36,6 +36,11 @@ std::shared_ptr<CommandLineArguments> CommandLineArguments::parse(int argc,
throw std::invalid_argument("expected path after the password flag");
}
result->password = std::string(argv[++i]);
} else if (stringVal == "-c" || stringVal == "--credentials") {
if (i >= argc - 1) {
throw std::invalid_argument("expected path after the credentials flag");
}
result->credentials = std::string(argv[++i]);
} else if (stringVal == "-b" || stringVal == "--bitrate") {
if (i >= argc - 1) {
throw std::invalid_argument("expected path after the bitrate flag");
Expand Down
8 changes: 6 additions & 2 deletions targets/cli/CommandLineArguments.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ class CommandLineArguments {
* The spotify password.
*/
std::string password;
/**
* A file to store/read reusable credentials from
*/
std::string credentials;
/**
* Bitrate setting.
*/
Expand All @@ -31,8 +35,8 @@ class CommandLineArguments {
* This is a constructor which initializez all the fields of CommandLineArguments
* @param shouldShowHelp determines whether the help text should be printed.
*/
CommandLineArguments(std::string username, std::string password,
bool shouldShowHelp);
CommandLineArguments(std::string username, std::string password,
std::string credentials, bool shouldShowHelp);

/**
* Parses command line arguments, as they are passed to main().
Expand Down
22 changes: 20 additions & 2 deletions targets/cli/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include <stdexcept> // for invalid_argument
#include <type_traits> // for remove_extent_t
#include <vector> // for vector
#include <iostream>
#include <fstream>

#include "BellHTTPServer.h" // for BellHTTPServer
#include "BellLogger.h" // for setDefaultLogger, AbstractLogger
Expand Down Expand Up @@ -148,6 +150,7 @@ int main(int argc, char** argv) {
std::cout << "-p, --password your spotify password, note that "
"if you use facebook login you can set a password in your "
"account settings\n";
std::cout << "-c, --credentials json file to store/load reusable credentials\n";
std::cout << "-b, --bitrate bitrate (320, 160, 96)\n";
std::cout << "\n";
std::cout << "ddd 2022\n";
Expand All @@ -162,6 +165,14 @@ int main(int argc, char** argv) {
loginBlob->loadUserPass(args->username, args->password);
loggedInSemaphore->give();
}
// reusable credentials
else if (!args->credentials.empty()) {
std::ifstream file(args->credentials);
std::ostringstream credentials;
credentials << file.rdbuf();
loginBlob->loadJson(credentials.str());
loggedInSemaphore->give();
}
// ZeroconfAuthenticator
else {
zeroconfServer->blob = loginBlob;
Expand All @@ -182,10 +193,17 @@ int main(int argc, char** argv) {

CSPOT_LOG(info, "Creating player");
ctx->session->connectWithRandomAp();
auto token = ctx->session->authenticate(loginBlob);
ctx->config.authData = ctx->session->authenticate(loginBlob);

// Auth successful
if (token.size() > 0) {
if (ctx->config.authData.size() > 0) {
// when credentials file and username are set, then store reusable credentials
if (!args->credentials.empty() && !args->username.empty()) {
std::ofstream file(args->credentials);
file << ctx->getCredentialsJson();
}

// Start spirc task
auto handler = std::make_shared<cspot::SpircHandler>(ctx);

// Start handling mercury messages
Expand Down
Loading