Skip to content
This repository has been archived by the owner on Jul 16, 2020. It is now read-only.

Commit

Permalink
fix: #58 Add client secret support for authorization helpers.
Browse files Browse the repository at this point in the history
  • Loading branch information
JoshSnider committed Apr 16, 2018
1 parent 6a0567c commit 0876982
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 26 deletions.
64 changes: 51 additions & 13 deletions Tests/Tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ namespace MixerTests
#define VERSION_ID "135704"
#define SHARE_CODE "xe7dpqd5"

#define DO_NOT_APPROVE_CLIENT_ID "b33e730969b2f1234afd94dff745dd1d2c4e7557e168ebce"
#define DO_NOT_APPROVE_CLIENT_SECRET "98d47b58be9917e68769a9b687c8b68fb24daeed3d6a11aa5cfb65df44c54e59"

interactive_session g_activeSession = nullptr;

template <typename T>
Expand Down Expand Up @@ -401,7 +404,7 @@ void handle_unhandled_method(void* context, interactive_session session, const c
Logger::WriteMessage(("Unhandled method: " + std::string(methodJson, methodJsonLength)).c_str());
}

int do_short_code_auth(const std::string& clientId, std::string& refreshToken)
int do_short_code_auth(const std::string& clientId, const std::string& clientSecret, std::string& refreshToken)
{
int err = 0;
char shortCode[7];
Expand All @@ -410,19 +413,21 @@ int do_short_code_auth(const std::string& clientId, std::string& refreshToken)
size_t shortCodeHandleLength = sizeof(shortCodeHandle);

// Get an OAuth short code to display to the user.
ASSERT_RETERR(interactive_auth_get_short_code(clientId.c_str(), shortCode, &shortCodeLength, shortCodeHandle, &shortCodeHandleLength));
Logger::WriteMessage(("Approve access here: https://www.mixer.com/go?code=" + std::string(shortCode, shortCodeLength)).c_str());
ASSERT_RETERR(interactive_auth_get_short_code(clientId.c_str(), clientSecret.c_str(), shortCode, &shortCodeLength, shortCodeHandle, &shortCodeHandleLength));

std::string authUrl = std::string("https://www.mixer.com/go?code=") + shortCode;
ShellExecuteA(0, 0, authUrl.c_str(), nullptr, nullptr, SW_SHOW);

// Wait for OAuth token response.
char refreshTokenBuffer[1024];
size_t refreshTokenLength = sizeof(refreshTokenBuffer);
ASSERT_RETERR(interactive_auth_wait_short_code(clientId.c_str(), shortCodeHandle, refreshTokenBuffer, &refreshTokenLength));
ASSERT_RETERR(interactive_auth_wait_short_code(clientId.c_str(), clientSecret.c_str(), shortCodeHandle, refreshTokenBuffer, &refreshTokenLength));

refreshToken = std::string(refreshTokenBuffer, refreshTokenLength);
return 0;
}

int do_auth(const std::string& clientId, std::string& auth)
int do_auth(const std::string& clientId, const std::string& clientSecret, std::string& auth)
{
int err = 0;
// Attempt to read refresh info if it exists.
Expand All @@ -434,7 +439,7 @@ int do_auth(const std::string& clientId, std::string& auth)
std::string refreshToken = ssRefreshToken.str();
if (refreshToken.empty())
{
ASSERT_RETERR(do_short_code_auth(clientId, refreshToken));
ASSERT_RETERR(do_short_code_auth(clientId, clientSecret, refreshToken));

std::ofstream refreshTokenFile;
refreshTokenFile.open("refreshtoken", std::ios::trunc);
Expand All @@ -454,7 +459,7 @@ int do_auth(const std::string& clientId, std::string& auth)
{
char tokenBuffer[1024];
size_t tokenBufferLength = sizeof(tokenBuffer);
err = interactive_auth_refresh_token(clientId.c_str(), refreshToken.c_str(), tokenBuffer, &tokenBufferLength);
err = interactive_auth_refresh_token(clientId.c_str(), clientSecret.c_str(), refreshToken.c_str(), tokenBuffer, &tokenBufferLength);
if (!err)
{
refreshToken = std::string(tokenBuffer, tokenBufferLength);
Expand All @@ -463,7 +468,7 @@ int do_auth(const std::string& clientId, std::string& auth)

if (err)
{
ASSERT_RETERR(do_short_code_auth(clientId, refreshToken));
ASSERT_RETERR(do_short_code_auth(clientId, clientSecret, refreshToken));
}

// Cache the refresh token
Expand Down Expand Up @@ -526,7 +531,40 @@ TEST_CLASS(Tests)
std::string shareCode = SHARE_CODE;
std::string auth;

ASSERT_NOERR(do_auth(clientId, auth));
ASSERT_NOERR(do_auth(clientId, "", auth));

interactive_session session;
Logger::WriteMessage("Connecting...");
ASSERT_NOERR(interactive_open_session(auth.c_str(), versionId.c_str(), shareCode.c_str(), true, &session));

// Simulate 60 frames/sec for 1 seconds.
const int fps = 60;
const int seconds = 1;
for (int i = 0; i < fps * seconds; ++i)
{
ASSERT_NOERR(interactive_run(session, 1));
std::this_thread::sleep_for(std::chrono::milliseconds(1000 / fps));
}

Logger::WriteMessage("Disconnecting...");
interactive_close_session(session);

Assert::IsTrue(0 == err);
}

TEST_METHOD(ConnectWithSecretTest)
{
g_start = std::chrono::high_resolution_clock::now();
interactive_config_debug(interactive_debug_trace, handle_debug_message);

int err = 0;
std::string clientId = DO_NOT_APPROVE_CLIENT_ID;
std::string clientSecret = DO_NOT_APPROVE_CLIENT_SECRET;
std::string versionId = VERSION_ID;
std::string shareCode = SHARE_CODE;
std::string auth;

ASSERT_NOERR(do_auth(clientId, clientSecret, auth));

interactive_session session;
Logger::WriteMessage("Connecting...");
Expand Down Expand Up @@ -558,7 +596,7 @@ TEST_CLASS(Tests)
std::string shareCode = SHARE_CODE;
std::string auth;

ASSERT_NOERR(do_auth(clientId, auth));
ASSERT_NOERR(do_auth(clientId, "", auth));

interactive_session session;
ASSERT_NOERR(interactive_open_session(auth.c_str(), versionId.c_str(), shareCode.c_str(), true, &session));
Expand Down Expand Up @@ -599,7 +637,7 @@ TEST_CLASS(Tests)
std::string shareCode = SHARE_CODE;
std::string auth;

ASSERT_NOERR(do_auth(clientId, auth));
ASSERT_NOERR(do_auth(clientId, "", auth));

interactive_session session;
ASSERT_NOERR(interactive_open_session(auth.c_str(), versionId.c_str(), shareCode.c_str(), false, &session));
Expand Down Expand Up @@ -650,7 +688,7 @@ TEST_CLASS(Tests)
std::string shareCode = SHARE_CODE;
std::string auth;

ASSERT_NOERR(do_auth(clientId, auth));
ASSERT_NOERR(do_auth(clientId, "", auth));

interactive_session session;
Logger::WriteMessage("Connecting...");
Expand Down Expand Up @@ -735,7 +773,7 @@ TEST_CLASS(Tests)
std::string shareCode = SHARE_CODE;
std::string auth;

ASSERT_NOERR(do_auth(clientId, auth));
ASSERT_NOERR(do_auth(clientId, "", auth));

interactive_session session;
Logger::WriteMessage("Connecting...");
Expand Down
Binary file modified samples/InteractiveSample/InteractiveSample.cpp
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ int authorize(std::string& authorization)
size_t shortCodeLength = sizeof(shortCode);
char shortCodeHandle[1024];
size_t shortCodeHandleLength = sizeof(shortCodeHandle);
err = interactive_auth_get_short_code(CLIENT_ID, shortCode, &shortCodeLength, shortCodeHandle, &shortCodeHandleLength);
err = interactive_auth_get_short_code(CLIENT_ID, nullptr, shortCode, &shortCodeLength, shortCodeHandle, &shortCodeHandleLength);
if (err) return err;

std::wstring oauthUrl = converter.from_bytes(std::string("https://www.mixer.com/go?code=") + shortCode);
Expand All @@ -47,7 +47,7 @@ int authorize(std::string& authorization)
// Wait for OAuth token response.
char refreshTokenBuffer[1024];
size_t refreshTokenLength = sizeof(refreshTokenBuffer);
err = interactive_auth_wait_short_code(CLIENT_ID, shortCodeHandle, refreshTokenBuffer, &refreshTokenLength);
err = interactive_auth_wait_short_code(CLIENT_ID, nullptr, shortCodeHandle, refreshTokenBuffer, &refreshTokenLength);
if (err)
{
if (MIXER_ERROR_TIMED_OUT == err)
Expand Down
4 changes: 2 additions & 2 deletions samples/InteractiveXboxSample/Game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@ int authorize(std::string& authorization)
size_t shortCodeLength = sizeof(shortCode);
char shortCodeHandle[1024];
size_t shortCodeHandleLength = sizeof(shortCodeHandle);
err = interactive_auth_get_short_code(CLIENT_ID, shortCode, &shortCodeLength, shortCodeHandle, &shortCodeHandleLength);
err = interactive_auth_get_short_code(CLIENT_ID, nullptr, shortCode, &shortCodeLength, shortCodeHandle, &shortCodeHandleLength);
if (err) return err;

std::cout << "Visit " << "https://www.mixer.com/go?code=" << shortCode;

// Wait for OAuth token response.
char refreshTokenBuffer[1024];
size_t refreshTokenLength = sizeof(refreshTokenBuffer);
err = interactive_auth_wait_short_code(CLIENT_ID, shortCodeHandle, refreshTokenBuffer, &refreshTokenLength);
err = interactive_auth_wait_short_code(CLIENT_ID, nullptr, shortCodeHandle, refreshTokenBuffer, &refreshTokenLength);
if (err)
{
if (MIXER_ERROR_TIMED_OUT == err)
Expand Down
6 changes: 3 additions & 3 deletions source/interactivity.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ extern "C" {
/// <remarks>
/// This is a blocking function that waits on network IO.
/// </remarks>
int interactive_auth_get_short_code(const char* clientId, char* shortCode, size_t* shortCodeLength, char* shortCodeHandle, size_t* shortCodeHandleLength);
int interactive_auth_get_short_code(const char* clientId, const char* clientSecret, char* shortCode, size_t* shortCodeLength, char* shortCodeHandle, size_t* shortCodeHandleLength);

/// <summary>
/// Wait for a <c>shortCode</c> to be authorized or rejected after presenting the OAuth short code web page. The resulting <c>refreshToken</c>
Expand All @@ -163,7 +163,7 @@ extern "C" {
/// <remarks>
/// This is a blocking function that waits on network IO.
/// </remarks>
int interactive_auth_wait_short_code(const char* clientId, const char* shortCodeHandle, char* refreshToken, size_t* refreshTokenLength);
int interactive_auth_wait_short_code(const char* clientId, const char* clientSecret, const char* shortCodeHandle, char* refreshToken, size_t* refreshTokenLength);

/// <summary>
/// Determine if a <c>refreshToken</c> returned by <c>interactive_auth_wait_short_code</c> is stale. A token is stale if it has exceeded its half-life.
Expand All @@ -176,7 +176,7 @@ extern "C" {
/// <remarks>
/// This is a blocking function that waits on network IO.
/// </remarks>
int interactive_auth_refresh_token(const char* clientId, const char* staleToken, char* refreshToken, size_t* refreshTokenLength);
int interactive_auth_refresh_token(const char* clientId, const char* clientSecret, const char* staleToken, char* refreshToken, size_t* refreshTokenLength);

/// <summary>
/// Parse a <c>refreshToken</c> to get the authorization header that should be passed to <c>interactive_open_session()</c>.
Expand Down
40 changes: 34 additions & 6 deletions source/internal/interactive_auth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ int interactive_auth_parse_refresh_token(const char* refreshToken, char* authori
return MIXER_OK;
}

int interactive_auth_get_short_code(const char* clientId, char* shortCode, size_t* shortCodeLength, char* shortCodeHandle, size_t* shortCodeHandleLength)
int interactive_auth_get_short_code(const char* clientId, const char* clientSecret, char* shortCode, size_t* shortCodeLength, char* shortCodeHandle, size_t* shortCodeHandleLength)
{
if (nullptr == clientId || nullptr == shortCode || nullptr == shortCodeLength || nullptr == shortCodeHandle || nullptr == shortCodeHandleLength)
{
Expand All @@ -75,7 +75,16 @@ int interactive_auth_get_short_code(const char* clientId, char* shortCode, size_
std::string oauthCodeUrl = "https://mixer.com/api/v1/oauth/shortcode";

// Construct the json body
std::string jsonBody = "{ \"client_id\": \"" + std::string(clientId) + "\", \"scope\": \"interactive:robot:self\" }";
std::string jsonBody;
if (nullptr == clientSecret)
{
jsonBody = std::string("{ \"client_id\": \"") + clientId + "\", \"scope\": \"interactive:robot:self\" }";
}
else
{
jsonBody = std::string("{ \"client_id\": \"") + clientId + "\", \"client_secret\": \"" + clientSecret + "\", \"scope\": \"interactive:robot:self\" }";
}

std::unique_ptr<http_client> client = http_factory::make_http_client();
RETURN_IF_FAILED(client->make_request(oauthCodeUrl, "POST", nullptr, jsonBody, response));
if (200 != response.statusCode)
Expand Down Expand Up @@ -110,7 +119,7 @@ int interactive_auth_get_short_code(const char* clientId, char* shortCode, size_
return MIXER_OK;
}

int interactive_auth_wait_short_code(const char* clientId, const char* shortCodeHandle, char* refreshToken, size_t* refreshTokenLength)
int interactive_auth_wait_short_code(const char* clientId, const char* clientSecret, const char* shortCodeHandle, char* refreshToken, size_t* refreshTokenLength)
{
// Poll that shortcode until it is validated or times out.
std::unique_ptr<http_client> httpClient = http_factory::make_http_client();
Expand Down Expand Up @@ -155,7 +164,17 @@ int interactive_auth_wait_short_code(const char* clientId, const char* shortCode
// Exchange oauth code for oauth token.
std::string refreshTokenData;
const std::string exchangeUrl = "https://mixer.com/api/v1/oauth/token";
std::string jsonBody = "{ \"client_id\": \"" + std::string(clientId) + "\", \"code\": \"" + oauthCode + "\", \"grant_type\": \"authorization_code\" }";

std::string jsonBody;
if (nullptr == clientSecret)
{
jsonBody = std::string("{ \"client_id\": \"") + clientId + "\", \"code\": \"" + oauthCode + "\", \"grant_type\": \"authorization_code\" }";
}
else
{
jsonBody = std::string("{ \"client_id\": \"") + clientId + "\", \"client_secret\": \"" + clientSecret + "\", \"code\": \"" + oauthCode + "\", \"grant_type\": \"authorization_code\" }";
}

httpClient->make_request(exchangeUrl, "POST", nullptr, jsonBody, response);
if (200 != response.statusCode)
{
Expand All @@ -177,7 +196,7 @@ int interactive_auth_wait_short_code(const char* clientId, const char* shortCode
return MIXER_OK;
}

int interactive_auth_refresh_token(const char* clientId, const char* staleToken, char* refreshToken, size_t* refreshTokenLength)
int interactive_auth_refresh_token(const char* clientId, const char* clientSecret, const char* staleToken, char* refreshToken, size_t* refreshTokenLength)
{
if (nullptr == clientId || nullptr == staleToken || nullptr == refreshToken || nullptr == refreshTokenLength)
{
Expand Down Expand Up @@ -208,7 +227,16 @@ int interactive_auth_refresh_token(const char* clientId, const char* staleToken,

http_response response;
const std::string exchangeUrl = "https://mixer.com/api/v1/oauth/token";
std::string jsonBody = "{ \"client_id\": \"" + std::string(clientId) + "\", \"refresh_token\": \"" + refreshTokenData + "\", \"grant_type\": \"refresh_token\" }";

std::string jsonBody;
if (nullptr == clientSecret || 0 == strlen(clientSecret))
{
jsonBody = std::string("{ \"client_id\": \"") + clientId + "\", \"refresh_token\": \"" + refreshTokenData + "\", \"grant_type\": \"refresh_token\" }";
}
{
jsonBody = std::string("{ \"client_id\": \"") + clientId + "\", \"client_secret\": \"" + clientSecret + "\", \"refresh_token\": \"" + refreshTokenData + "\", \"grant_type\": \"refresh_token\" }";
}

std::unique_ptr<http_client> httpClient = http_factory::make_http_client();
httpClient->make_request(exchangeUrl, "POST", nullptr, jsonBody, response);
if (200 != response.statusCode)
Expand Down

0 comments on commit 0876982

Please sign in to comment.