mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-08 12:37:01 +03:00
manage Spotify credentials
This commit is contained in:
@@ -13,14 +13,14 @@ esp_err_t store_nvs_value_len(nvs_type_t type, const char *key, void * data, siz
|
|||||||
esp_err_t store_nvs_value(nvs_type_t type, const char *key, void * data);
|
esp_err_t store_nvs_value(nvs_type_t type, const char *key, void * data);
|
||||||
esp_err_t get_nvs_value(nvs_type_t type, const char *key, void*value, const uint8_t buf_size);
|
esp_err_t get_nvs_value(nvs_type_t type, const char *key, void*value, const uint8_t buf_size);
|
||||||
void * get_nvs_value_alloc(nvs_type_t type, const char *key);
|
void * get_nvs_value_alloc(nvs_type_t type, const char *key);
|
||||||
void * get_nvs_value_alloc_for_partition(const char * partition,const char * namespace,nvs_type_t type, const char *key, size_t * size);
|
void * get_nvs_value_alloc_for_partition(const char * partition,const char * ns,nvs_type_t type, const char *key, size_t * size);
|
||||||
esp_err_t erase_nvs_for_partition(const char * partition, const char * namespace,const char *key);
|
esp_err_t erase_nvs_for_partition(const char * partition, const char * ns,const char *key);
|
||||||
esp_err_t store_nvs_value_len_for_partition(const char * partition,const char * namespace,nvs_type_t type, const char *key, const void * data,size_t data_len);
|
esp_err_t store_nvs_value_len_for_partition(const char * partition,const char * ns,nvs_type_t type, const char *key, const void * data,size_t data_len);
|
||||||
esp_err_t erase_nvs(const char *key);
|
esp_err_t erase_nvs(const char *key);
|
||||||
void print_blob(const char *blob, size_t len);
|
void print_blob(const char *blob, size_t len);
|
||||||
const char *type_to_str(nvs_type_t type);
|
const char *type_to_str(nvs_type_t type);
|
||||||
nvs_type_t str_to_type(const char *type);
|
nvs_type_t str_to_type(const char *type);
|
||||||
esp_err_t erase_nvs_partition(const char * partition, const char * namespace);
|
esp_err_t erase_nvs_partition(const char * partition, const char * ns);
|
||||||
void erase_settings_partition();
|
void erase_settings_partition();
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ static struct {
|
|||||||
struct arg_str *deviceName;
|
struct arg_str *deviceName;
|
||||||
// struct arg_int *volume;
|
// struct arg_int *volume;
|
||||||
struct arg_int *bitrate;
|
struct arg_int *bitrate;
|
||||||
|
struct arg_int *zeroConf;
|
||||||
struct arg_end *end;
|
struct arg_end *end;
|
||||||
} cspot_args;
|
} cspot_args;
|
||||||
static struct {
|
static struct {
|
||||||
@@ -656,6 +657,9 @@ static int do_cspot_config(int argc, char **argv){
|
|||||||
if(cspot_args.bitrate->count>0){
|
if(cspot_args.bitrate->count>0){
|
||||||
cjson_update_number(&cspot_config,cspot_args.bitrate->hdr.longopts,cspot_args.bitrate->ival[0]);
|
cjson_update_number(&cspot_config,cspot_args.bitrate->hdr.longopts,cspot_args.bitrate->ival[0]);
|
||||||
}
|
}
|
||||||
|
if(cspot_args.zeroConf->count>0){
|
||||||
|
cjson_update_number(&cspot_config,cspot_args.zeroConf->hdr.longopts,cspot_args.zeroConf->ival[0]);
|
||||||
|
}
|
||||||
|
|
||||||
if(!nerrors ){
|
if(!nerrors ){
|
||||||
fprintf(f,"Storing cspot parameters.\n");
|
fprintf(f,"Storing cspot parameters.\n");
|
||||||
@@ -668,6 +672,9 @@ static int do_cspot_config(int argc, char **argv){
|
|||||||
if(cspot_args.bitrate->count>0){
|
if(cspot_args.bitrate->count>0){
|
||||||
fprintf(f,"Bitrate changed to %u\n",cspot_args.bitrate->ival[0]);
|
fprintf(f,"Bitrate changed to %u\n",cspot_args.bitrate->ival[0]);
|
||||||
}
|
}
|
||||||
|
if(cspot_args.zeroConf->count>0){
|
||||||
|
fprintf(f,"ZeroConf changed to %u\n",cspot_args.zeroConf->ival[0]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(!nerrors ){
|
if(!nerrors ){
|
||||||
fprintf(f,"Done.\n");
|
fprintf(f,"Done.\n");
|
||||||
@@ -853,6 +860,10 @@ cJSON * cspot_cb(){
|
|||||||
if(cspot_values){
|
if(cspot_values){
|
||||||
cJSON_AddNumberToObject(values,cspot_args.bitrate->hdr.longopts,cJSON_GetNumberValue(cspot_values));
|
cJSON_AddNumberToObject(values,cspot_args.bitrate->hdr.longopts,cJSON_GetNumberValue(cspot_values));
|
||||||
}
|
}
|
||||||
|
cspot_values = cJSON_GetObjectItem(cspot_config,cspot_args.zeroConf->hdr.longopts);
|
||||||
|
if(cspot_values){
|
||||||
|
cJSON_AddNumberToObject(values,cspot_args.zeroConf->hdr.longopts,cJSON_GetNumberValue(cspot_values));
|
||||||
|
}
|
||||||
|
|
||||||
cJSON_Delete(cspot_config);
|
cJSON_Delete(cspot_config);
|
||||||
return values;
|
return values;
|
||||||
@@ -1286,6 +1297,7 @@ static void register_known_templates_config(){
|
|||||||
static void register_cspot_config(){
|
static void register_cspot_config(){
|
||||||
cspot_args.deviceName = arg_str1(NULL,"deviceName","","Device Name");
|
cspot_args.deviceName = arg_str1(NULL,"deviceName","","Device Name");
|
||||||
cspot_args.bitrate = arg_int1(NULL,"bitrate","96|160|320","Streaming Bitrate (kbps)");
|
cspot_args.bitrate = arg_int1(NULL,"bitrate","96|160|320","Streaming Bitrate (kbps)");
|
||||||
|
cspot_args.zeroConf = arg_int1(NULL,"zeroConf","0|1","Force use of ZeroConf");
|
||||||
// cspot_args.volume = arg_int1(NULL,"volume","","Spotify Volume");
|
// cspot_args.volume = arg_int1(NULL,"volume","","Spotify Volume");
|
||||||
cspot_args.end = arg_end(1);
|
cspot_args.end = arg_end(1);
|
||||||
const esp_console_cmd_t cmd = {
|
const esp_console_cmd_t cmd = {
|
||||||
|
|||||||
@@ -30,10 +30,16 @@
|
|||||||
#include "cspot_private.h"
|
#include "cspot_private.h"
|
||||||
#include "cspot_sink.h"
|
#include "cspot_sink.h"
|
||||||
#include "platform_config.h"
|
#include "platform_config.h"
|
||||||
|
#include "nvs_utilities.h"
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
|
|
||||||
static class cspotPlayer *player;
|
static class cspotPlayer *player;
|
||||||
|
|
||||||
|
static const struct {
|
||||||
|
const char *ns;
|
||||||
|
const char *credentials;
|
||||||
|
} spotify_ns = { .ns = "spotify", .credentials = "credentials" };
|
||||||
|
|
||||||
/****************************************************************************************
|
/****************************************************************************************
|
||||||
* Player's main class & task
|
* Player's main class & task
|
||||||
*/
|
*/
|
||||||
@@ -42,7 +48,11 @@ class cspotPlayer : public bell::Task {
|
|||||||
private:
|
private:
|
||||||
std::string name;
|
std::string name;
|
||||||
bell::WrappedSemaphore clientConnected;
|
bell::WrappedSemaphore clientConnected;
|
||||||
std::atomic<bool> isPaused, isConnected;
|
std::atomic<bool> isPaused;
|
||||||
|
enum states { ABORT, LINKED, DISCO };
|
||||||
|
std::atomic<states> state;
|
||||||
|
std::string credentials;
|
||||||
|
bool zeroConf;
|
||||||
|
|
||||||
int startOffset, volume = 0, bitrate = 160;
|
int startOffset, volume = 0, bitrate = 160;
|
||||||
httpd_handle_t serverHandle;
|
httpd_handle_t serverHandle;
|
||||||
@@ -57,6 +67,7 @@ private:
|
|||||||
void eventHandler(std::unique_ptr<cspot::SpircHandler::Event> event);
|
void eventHandler(std::unique_ptr<cspot::SpircHandler::Event> event);
|
||||||
void trackHandler(void);
|
void trackHandler(void);
|
||||||
size_t pcmWrite(uint8_t *pcm, size_t bytes, std::string_view trackId);
|
size_t pcmWrite(uint8_t *pcm, size_t bytes, std::string_view trackId);
|
||||||
|
void enableZeroConf(void);
|
||||||
|
|
||||||
void runTask();
|
void runTask();
|
||||||
|
|
||||||
@@ -80,7 +91,24 @@ cspotPlayer::cspotPlayer(const char* name, httpd_handle_t server, int port, cspo
|
|||||||
if ((item = cJSON_GetObjectItem(config, "bitrate")) != NULL) bitrate = item->valueint;
|
if ((item = cJSON_GetObjectItem(config, "bitrate")) != NULL) bitrate = item->valueint;
|
||||||
if ((item = cJSON_GetObjectItem(config, "deviceName") ) != NULL) this->name = item->valuestring;
|
if ((item = cJSON_GetObjectItem(config, "deviceName") ) != NULL) this->name = item->valuestring;
|
||||||
else this->name = name;
|
else this->name = name;
|
||||||
|
|
||||||
|
if ((item = cJSON_GetObjectItem(config, "zeroConf")) != NULL) {
|
||||||
|
zeroConf = item->valueint;
|
||||||
cJSON_Delete(config);
|
cJSON_Delete(config);
|
||||||
|
} else {
|
||||||
|
zeroConf = true;
|
||||||
|
cJSON_AddNumberToObject(config, "zeroConf", 1);
|
||||||
|
config_set_cjson_str_and_free("cspot_config", config);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get optional credentials from own NVS
|
||||||
|
if (!zeroConf) {
|
||||||
|
char *credentials = (char*) get_nvs_value_alloc_for_partition(NVS_DEFAULT_PART_NAME, spotify_ns.ns, NVS_TYPE_STR, spotify_ns.credentials, NULL);
|
||||||
|
if (credentials) {
|
||||||
|
this->credentials = credentials;
|
||||||
|
free(credentials);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (bitrate != 96 && bitrate != 160 && bitrate != 320) bitrate = 160;
|
if (bitrate != 96 && bitrate != 160 && bitrate != 320) bitrate = 160;
|
||||||
}
|
}
|
||||||
@@ -207,7 +235,7 @@ void cspotPlayer::eventHandler(std::unique_ptr<cspot::SpircHandler::Event> event
|
|||||||
}
|
}
|
||||||
case cspot::SpircHandler::EventType::DISC:
|
case cspot::SpircHandler::EventType::DISC:
|
||||||
cmdHandler(CSPOT_DISC);
|
cmdHandler(CSPOT_DISC);
|
||||||
isConnected = false;
|
state = DISCO;
|
||||||
break;
|
break;
|
||||||
case cspot::SpircHandler::EventType::SEEK: {
|
case cspot::SpircHandler::EventType::SEEK: {
|
||||||
cmdHandler(CSPOT_SEEK, std::get<int>(event->data));
|
cmdHandler(CSPOT_SEEK, std::get<int>(event->data));
|
||||||
@@ -265,7 +293,7 @@ void cspotPlayer::command(cspot_event_t event) {
|
|||||||
* generate any cspot::event */
|
* generate any cspot::event */
|
||||||
case CSPOT_DISC:
|
case CSPOT_DISC:
|
||||||
cmdHandler(CSPOT_DISC);
|
cmdHandler(CSPOT_DISC);
|
||||||
isConnected = false;
|
state = ABORT;
|
||||||
break;
|
break;
|
||||||
// spirc->setRemoteVolume does not generate a cspot::event so call cmdHandler
|
// spirc->setRemoteVolume does not generate a cspot::event so call cmdHandler
|
||||||
case CSPOT_VOLUME_UP:
|
case CSPOT_VOLUME_UP:
|
||||||
@@ -285,7 +313,7 @@ void cspotPlayer::command(cspot_event_t event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cspotPlayer::runTask() {
|
void cspotPlayer::enableZeroConf(void) {
|
||||||
httpd_uri_t request = {
|
httpd_uri_t request = {
|
||||||
.uri = "/spotify_info",
|
.uri = "/spotify_info",
|
||||||
.method = HTTP_GET,
|
.method = HTTP_GET,
|
||||||
@@ -299,20 +327,34 @@ void cspotPlayer::runTask() {
|
|||||||
request.handler = ::handlePOST;
|
request.handler = ::handlePOST;
|
||||||
httpd_register_uri_handler(serverHandle, &request);
|
httpd_register_uri_handler(serverHandle, &request);
|
||||||
|
|
||||||
// construct blob for that player
|
CSPOT_LOG(info, "ZeroConf mode (port %d)", serverPort);
|
||||||
blob = std::make_unique<cspot::LoginBlob>(name);
|
|
||||||
|
|
||||||
// Register mdns service, for spotify to find us
|
// Register mdns service, for spotify to find us
|
||||||
bell::MDNSService::registerService( blob->getDeviceName(), "_spotify-connect", "_tcp", "", serverPort,
|
bell::MDNSService::registerService( blob->getDeviceName(), "_spotify-connect", "_tcp", "", serverPort,
|
||||||
{ {"VERSION", "1.0"}, {"CPath", "/spotify_info"}, {"Stack", "SP"} });
|
{ {"VERSION", "1.0"}, {"CPath", "/spotify_info"}, {"Stack", "SP"} });
|
||||||
|
}
|
||||||
|
|
||||||
|
void cspotPlayer::runTask() {
|
||||||
|
bool useZeroConf = zeroConf;
|
||||||
|
|
||||||
|
// construct blob for that player
|
||||||
|
blob = std::make_unique<cspot::LoginBlob>(name);
|
||||||
|
|
||||||
CSPOT_LOG(info, "CSpot instance service name %s (id %s)", blob->getDeviceName().c_str(), blob->getDeviceId().c_str());
|
CSPOT_LOG(info, "CSpot instance service name %s (id %s)", blob->getDeviceName().c_str(), blob->getDeviceId().c_str());
|
||||||
|
|
||||||
|
if (!zeroConf && !credentials.empty()) {
|
||||||
|
blob->loadJson(credentials);
|
||||||
|
CSPOT_LOG(info, "Reusable credentials mode");
|
||||||
|
} else {
|
||||||
|
// whether we want it or not we must use ZeroConf
|
||||||
|
useZeroConf = true;
|
||||||
|
enableZeroConf();
|
||||||
|
}
|
||||||
|
|
||||||
// gone with the wind...
|
// gone with the wind...
|
||||||
while (1) {
|
while (1) {
|
||||||
clientConnected.wait();
|
if (useZeroConf) clientConnected.wait();
|
||||||
|
CSPOT_LOG(info, "Spotify client launched for %s", name.c_str());
|
||||||
CSPOT_LOG(info, "Spotify client connected for %s", name.c_str());
|
|
||||||
|
|
||||||
auto ctx = cspot::Context::createFromBlob(blob);
|
auto ctx = cspot::Context::createFromBlob(blob);
|
||||||
|
|
||||||
@@ -321,12 +363,26 @@ void cspotPlayer::runTask() {
|
|||||||
else ctx->config.audioFormat = AudioFormat_OGG_VORBIS_160;
|
else ctx->config.audioFormat = AudioFormat_OGG_VORBIS_160;
|
||||||
|
|
||||||
ctx->session->connectWithRandomAp();
|
ctx->session->connectWithRandomAp();
|
||||||
auto token = ctx->session->authenticate(blob);
|
ctx->config.authData = ctx->session->authenticate(blob);
|
||||||
|
|
||||||
// Auth successful
|
// Auth successful
|
||||||
if (token.size() > 0) {
|
if (ctx->config.authData.size() > 0) {
|
||||||
|
// we might have been forced to use zeroConf, so store credentials and reset zeroConf usage
|
||||||
|
if (!zeroConf) {
|
||||||
|
useZeroConf = false;
|
||||||
|
// can't call store_nvs... from a task running on EXTRAM stack
|
||||||
|
TimerHandle_t timer = xTimerCreate( "credentials", 1, pdFALSE, strdup(ctx->getCredentialsJson().c_str()),
|
||||||
|
[](TimerHandle_t xTimer) {
|
||||||
|
auto credentials = (char*) pvTimerGetTimerID(xTimer);
|
||||||
|
store_nvs_value_len_for_partition(NVS_DEFAULT_PART_NAME, spotify_ns.ns, NVS_TYPE_STR, spotify_ns.credentials, credentials, 0);
|
||||||
|
free(credentials);
|
||||||
|
xTimerDelete(xTimer, portMAX_DELAY);
|
||||||
|
} );
|
||||||
|
xTimerStart(timer, portMAX_DELAY);
|
||||||
|
}
|
||||||
|
|
||||||
spirc = std::make_unique<cspot::SpircHandler>(ctx);
|
spirc = std::make_unique<cspot::SpircHandler>(ctx);
|
||||||
isConnected = true;
|
state = LINKED;
|
||||||
|
|
||||||
// set call back to calculate a hash on trackId
|
// set call back to calculate a hash on trackId
|
||||||
spirc->getTrackPlayer()->setDataCallback(
|
spirc->getTrackPlayer()->setDataCallback(
|
||||||
@@ -347,7 +403,7 @@ void cspotPlayer::runTask() {
|
|||||||
cmdHandler(CSPOT_VOLUME, volume);
|
cmdHandler(CSPOT_VOLUME, volume);
|
||||||
|
|
||||||
// exit when player has stopped (received a DISC)
|
// exit when player has stopped (received a DISC)
|
||||||
while (isConnected) {
|
while (state == LINKED) {
|
||||||
ctx->session->handlePacket();
|
ctx->session->handlePacket();
|
||||||
|
|
||||||
// low-accuracy polling events
|
// low-accuracy polling events
|
||||||
@@ -371,23 +427,32 @@ void cspotPlayer::runTask() {
|
|||||||
spirc->setPause(true);
|
spirc->setPause(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// on disconnect, stay in the core loop unless we are in ZeroConf mode
|
||||||
|
if (state == DISCO) {
|
||||||
|
// update volume then
|
||||||
|
cJSON *config = config_alloc_get_cjson("cspot_config");
|
||||||
|
cJSON_DeleteItemFromObject(config, "volume");
|
||||||
|
cJSON_AddNumberToObject(config, "volume", volume);
|
||||||
|
config_set_cjson_str_and_free("cspot_config", config);
|
||||||
|
|
||||||
|
// in ZeroConf mod, stay connected (in this loop)
|
||||||
|
if (!zeroConf) state = LINKED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spirc->disconnect();
|
spirc->disconnect();
|
||||||
spirc.reset();
|
spirc.reset();
|
||||||
|
|
||||||
CSPOT_LOG(info, "disconnecting player %s", name.c_str());
|
CSPOT_LOG(info, "disconnecting player %s", name.c_str());
|
||||||
|
} else {
|
||||||
|
CSPOT_LOG(error, "failed authentication, forcing ZeroConf");
|
||||||
|
if (!useZeroConf) enableZeroConf();
|
||||||
|
useZeroConf = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we want to release memory ASAP and for sure
|
// we want to release memory ASAP and for sure
|
||||||
ctx.reset();
|
ctx.reset();
|
||||||
token.clear();
|
|
||||||
|
|
||||||
// update volume when we disconnect
|
|
||||||
cJSON *config = config_alloc_get_cjson("cspot_config");
|
|
||||||
cJSON_DeleteItemFromObject(config, "volume");
|
|
||||||
cJSON_AddNumberToObject(config, "volume", volume);
|
|
||||||
config_set_cjson_str_and_free("cspot_config", config);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
file(GLOB AACDEC_SOURCES "src/*.c")
|
file(GLOB AACDEC_SOURCES "src/*.c")
|
||||||
file(GLOB AACDEC_HEADERS "src/*.h" "oscl/*.h" "include/*.h")
|
file(GLOB AACDEC_HEADERS "src/*.h" "oscl/*.h" "include/*.h")
|
||||||
|
|
||||||
add_library(opencore-aacdec SHARED ${AACDEC_SOURCES})
|
add_library(opencore-aacdec STATIC ${AACDEC_SOURCES})
|
||||||
add_definitions(-DAAC_PLUS -DHQ_SBR -DPARAMETRICSTEREO -DC_EQUIVALENT)
|
if(NOT MSVC)
|
||||||
target_compile_options(opencore-aacdec PRIVATE -Wno-array-parameter)
|
target_compile_options(opencore-aacdec PRIVATE -Wno-array-parameter)
|
||||||
|
endif()
|
||||||
|
add_definitions(-DAAC_PLUS -DHQ_SBR -DPARAMETRICSTEREO -DC_EQUIVALENT)
|
||||||
target_include_directories(opencore-aacdec PUBLIC "src/" "oscl/" "include/")
|
target_include_directories(opencore-aacdec PUBLIC "src/" "oscl/" "include/")
|
||||||
@@ -31,8 +31,8 @@ class CryptoMbedTLS {
|
|||||||
CryptoMbedTLS();
|
CryptoMbedTLS();
|
||||||
~CryptoMbedTLS();
|
~CryptoMbedTLS();
|
||||||
// Base64
|
// Base64
|
||||||
std::vector<uint8_t> base64Decode(const std::string& data);
|
static std::vector<uint8_t> base64Decode(const std::string& data);
|
||||||
std::string base64Encode(const std::vector<uint8_t>& data);
|
static std::string base64Encode(const std::vector<uint8_t>& data);
|
||||||
|
|
||||||
// Sha1
|
// Sha1
|
||||||
void sha1Init();
|
void sha1Init();
|
||||||
|
|||||||
@@ -6,7 +6,16 @@
|
|||||||
#include "LoginBlob.h"
|
#include "LoginBlob.h"
|
||||||
#include "MercurySession.h"
|
#include "MercurySession.h"
|
||||||
#include "TimeProvider.h"
|
#include "TimeProvider.h"
|
||||||
|
#include "Crypto.h"
|
||||||
#include "protobuf/metadata.pb.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 {
|
namespace cspot {
|
||||||
struct Context {
|
struct Context {
|
||||||
@@ -26,6 +35,28 @@ struct Context {
|
|||||||
|
|
||||||
std::shared_ptr<TimeProvider> timeProvider;
|
std::shared_ptr<TimeProvider> timeProvider;
|
||||||
std::shared_ptr<cspot::MercurySession> session;
|
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(
|
static std::shared_ptr<Context> createFromBlob(
|
||||||
std::shared_ptr<LoginBlob> blob) {
|
std::shared_ptr<LoginBlob> blob) {
|
||||||
|
|||||||
@@ -3,3 +3,8 @@ LoginCredentials.auth_data max_size:512, fixed_length:false
|
|||||||
SystemInfo.system_information_string max_size:16, fixed_length:false
|
SystemInfo.system_information_string max_size:16, fixed_length:false
|
||||||
SystemInfo.device_id max_size:50, 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
|
||||||
|
|||||||
@@ -37,6 +37,11 @@ enum Os {
|
|||||||
OS_BCO = 0x16;
|
OS_BCO = 0x16;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum AccountType {
|
||||||
|
Spotify = 0x0;
|
||||||
|
Facebook = 0x1;
|
||||||
|
}
|
||||||
|
|
||||||
enum AuthenticationType {
|
enum AuthenticationType {
|
||||||
AUTHENTICATION_USER_PASS = 0x0;
|
AUTHENTICATION_USER_PASS = 0x0;
|
||||||
AUTHENTICATION_STORED_SPOTIFY_CREDENTIALS = 0x1;
|
AUTHENTICATION_STORED_SPOTIFY_CREDENTIALS = 0x1;
|
||||||
@@ -63,3 +68,27 @@ message ClientResponseEncrypted {
|
|||||||
required SystemInfo system_info = 0x32;
|
required SystemInfo system_info = 0x32;
|
||||||
optional string version_string = 0x46;
|
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;
|
||||||
|
}
|
||||||
@@ -142,8 +142,8 @@ void LoginBlob::loadJson(const std::string& json) {
|
|||||||
cJSON* root = cJSON_Parse(json.c_str());
|
cJSON* root = cJSON_Parse(json.c_str());
|
||||||
this->authType = cJSON_GetObjectItem(root, "authType")->valueint;
|
this->authType = cJSON_GetObjectItem(root, "authType")->valueint;
|
||||||
this->username = cJSON_GetObjectItem(root, "username")->valuestring;
|
this->username = cJSON_GetObjectItem(root, "username")->valuestring;
|
||||||
std::string authDataObject =
|
std::string authDataObject = cJSON_GetObjectItem(root, "authData")->valuestring;
|
||||||
cJSON_GetObjectItem(root, "authData")->valuestring;
|
this->authData = crypto->base64Decode(authDataObject);
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
#else
|
#else
|
||||||
auto root = nlohmann::json::parse(json);
|
auto root = nlohmann::json::parse(json);
|
||||||
|
|||||||
@@ -17,6 +17,10 @@
|
|||||||
#include "PlainConnection.h" // for PlainConnection, timeoutCallback
|
#include "PlainConnection.h" // for PlainConnection, timeoutCallback
|
||||||
#include "ShannonConnection.h" // for ShannonConnection
|
#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 =
|
using random_bytes_engine =
|
||||||
std::independent_bits_engine<std::default_random_engine, CHAR_BIT, uint8_t>;
|
std::independent_bits_engine<std::default_random_engine, CHAR_BIT, uint8_t>;
|
||||||
|
|
||||||
@@ -79,9 +83,13 @@ std::vector<uint8_t> Session::authenticate(std::shared_ptr<LoginBlob> blob) {
|
|||||||
auto packet = this->shanConn->recvPacket();
|
auto packet = this->shanConn->recvPacket();
|
||||||
switch (packet.command) {
|
switch (packet.command) {
|
||||||
case AUTH_SUCCESSFUL_COMMAND: {
|
case AUTH_SUCCESSFUL_COMMAND: {
|
||||||
|
APWelcome welcome;
|
||||||
CSPOT_LOG(debug, "Authorization successful");
|
CSPOT_LOG(debug, "Authorization successful");
|
||||||
|
pbDecode(welcome, APWelcome_fields, packet.data);
|
||||||
return std::vector<uint8_t>(
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case AUTH_DECLINED_COMMAND: {
|
case AUTH_DECLINED_COMMAND: {
|
||||||
|
|||||||
Reference in New Issue
Block a user