17#include <rapidjson/document.h>
18#include <rapidjson/writer.h>
44const std::string_view
uriPrefix =
"audacity://link";
58 using namespace rapidjson;
65 Value(clientID.data(), clientID.size(), document.GetAllocator()),
66 document.GetAllocator());
70 Value(clientSecret.data(), clientSecret.size(), document.GetAllocator()),
71 document.GetAllocator());
76 using namespace rapidjson;
79 "grant_type", StringRef(grantType.data(), grantType.size()),
80 document.GetAllocator());
83 "scope", StringRef(
scope.data(),
scope.size()), document.GetAllocator());
87 rapidjson::Document& document, std::string_view grantType, std::string_view
scope)
93template<
typename Elem,
typename First,
typename ...Others>
94void append(std::basic_string<Elem>& dest,
First&& first, Others&& ...others)
97 if constexpr (
sizeof...(others) != 0)
98 append(dest, std::forward<Others>(others)...);
101template<
typename First,
typename ...Others>
104 std::basic_string<typename First::value_type> dest(first);
105 append(dest, std::forward<Others>(others)...);
112 std::function<
void(std::string_view)> completedHandler,
AudiocomTrace trace,
117 if (completedHandler)
128 std::function<
void(std::string_view)> completedHandler)
132 if (completedHandler)
133 completedHandler({});
139 const auto argsStart = uri.find(
"?");
143 if (completedHandler)
144 completedHandler({});
149 auto args = uri.substr(argsStart + 1);
151 std::string_view token;
152 std::string_view username;
153 std::string_view password;
154 std::string_view authorizationCode;
155 auto useAudioComRedirectURI =
false;
157 while (!args.empty())
159 const auto nextArg = args.find(
'&');
161 const auto arg = args.substr(0, nextArg);
173 useAudioComRedirectURI =
true;
177 authorizationCode = arg.substr(
codePrefix.length());
181 size_t hashPos = authorizationCode.find(
'#');
184 authorizationCode = authorizationCode.substr(0, hashPos);
188 if (!authorizationCode.empty())
192 std::move(completedHandler));
194 else if (!token.empty())
199 else if (!username.empty() && !password.empty())
204 std::move(completedHandler));
208 if (completedHandler)
209 completedHandler({});
219 std::lock_guard<std::recursive_mutex> lock(
mMutex);
227 Publish({ {}, {}, trace,
false });
233 std::function<
void(std::string_view)> completedHandler)
235 using namespace rapidjson;
238 document.SetObject();
244 document.GetAllocator());
247 "password", StringRef(password.data(), password.size()),
248 document.GetAllocator());
250 rapidjson::StringBuffer buffer;
251 rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
252 document.Accept(writer);
255 config, { buffer.GetString(), buffer.GetSize() }, trace,
256 std::move(completedHandler),
false);
261 std::function<
void(std::string_view)> completedHandler,
bool silent)
263 using namespace rapidjson;
266 document.SetObject();
271 "refresh_token", StringRef(token.data(), token.size()),
272 document.GetAllocator());
274 rapidjson::StringBuffer buffer;
275 rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
276 document.Accept(writer);
279 config, { buffer.GetString(), buffer.GetSize() }, trace,
280 std::move(completedHandler), silent);
285 std::function<
void(std::string_view)> completedHandler,
bool silent)
287 std::lock_guard<std::recursive_mutex> lock(
mMutex);
291 std::move(completedHandler), silent);
295 const ServiceConfig& config, std::string_view authorizationCode,
bool useAudioComRedirectURI,
296 AudiocomTrace trace, std::function<
void(std::string_view)> completedHandler)
298 using namespace rapidjson;
301 document.SetObject();
306 "code", StringRef(authorizationCode.data(), authorizationCode.size()),
307 document.GetAllocator());
309 const auto redirectURI = useAudioComRedirectURI ? config.
GetOAuthRedirectURL() : std::string(
"audacity://link");
312 "redirect_uri", StringRef(redirectURI.data(), redirectURI.size()),
313 document.GetAllocator());
315 rapidjson::StringBuffer buffer;
316 rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
317 document.Accept(writer);
320 config, { buffer.GetString(), buffer.GetSize() }, trace,
321 std::move(completedHandler),
false);
331 std::lock_guard<std::recursive_mutex> lock(
mMutex);
337 std::lock_guard<std::recursive_mutex> lock(
mMutex);
354 "&redirect_uri=audacity://link"
363 size_t pos = token.find(
' ');
365 token = token.substr(pos + 1);
377 std::string_view password,
383 using rapidjson::StringRef;
385 rapidjson::Document document;
386 document.SetObject();
391 "username", StringRef(email.data(), email.size()),
392 document.GetAllocator());
395 "password", StringRef(password.data(), password.size()),
396 document.GetAllocator());
398 rapidjson::StringBuffer buffer;
399 rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
400 document.Accept(writer);
407 response->setRequestFinishedCallback(
408 [response,
this, trace,
409 onSuccess = std::move(onSuccess),
410 onFailure = std::move(onFailure)](
auto)
mutable
412 const auto httpCode = response->getHTTPCode();
413 const auto body = response->readAll<std::string>();
419 onFailure(httpCode, body);
427 std::string_view password,
433 using rapidjson::StringRef;
435 rapidjson::Document document;
436 document.SetObject();
441 "email", StringRef(email.data(), email.size()),
442 document.GetAllocator());
445 "password", StringRef(password.data(), password.size()),
446 document.GetAllocator());
448 rapidjson::StringBuffer buffer;
449 rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
450 document.Accept(writer);
457 response->setRequestFinishedCallback(
458 [response,
this, trace,
459 successCallback = std::move(successCallback),
460 failureCallback = std::move(failureCallback)] (
auto)
mutable
462 const auto httpCode = response->getHTTPCode();
463 const auto body = response->readAll<std::string>();
465 ParseTokenResponse(body, std::move(successCallback), std::move(failureCallback), trace,
false);
469 failureCallback(httpCode, body);
491 request, payload.data(), payload.size());
493 response->setRequestFinishedCallback(
494 [response,
this,
handler = std::move(completedHandler), silent,
495 trace](
auto)
mutable {
496 const auto httpCode = response->getHTTPCode();
497 const auto body = response->readAll<std::string>();
522 rapidjson::Document document;
523 document.Parse(body.data(), body.size());
525 if (!document.IsObject())
528 failureCallback(200, body);
534 const auto tokenType = document[
"token_type"].GetString();
535 const auto accessToken = document[
"access_token"].GetString();
536 const auto expiresIn = document[
"expires_in"].GetInt64();
537 const auto newRefreshToken = document[
"refresh_token"].GetString();
540 std::lock_guard<std::recursive_mutex> lock(
mMutex);
542 mAccessToken = std::string(tokenType) +
" " + accessToken;
544 Clock::now() + std::chrono::seconds(expiresIn);
548 [token = std::string(newRefreshToken)]()
Toolkit-neutral facade for basic user interface services.
Declare functions to perform UTF-8 to std::wstring conversions.
Declare an interface for HTTP response.
Declare a class for performing HTTP requests.
audacity::BasicSettings * gPrefs
Declare a class for constructing HTTP requests.
bool IsPrefixedInsensitive(const HayType &hay, const PrefixType &prefix)
bool IsPrefixed(const HayType &hay, const PrefixType &prefix)
Declare a function to decode an URL encode string.
Declare a function to perform URL encoding of a string.
CallbackReturn Publish(const AuthStateChangedMessage &message)
Send a message to connected callbacks.
Allows custom logic for preferences reset event.
bool Write(const T &value)
Write value to config and return true if successful.
void Invalidate() override
bool Read(T *pVar) const
overload of Read returning a boolean that is true if the value was previously defined */
Specialization of Setting for strings.
virtual bool Flush() noexcept=0
Service responsible for OAuth authentication against the audio.com service.
bool HasRefreshToken() const
void AuthoriseRefreshToken(const ServiceConfig &config, std::string_view refreshToken, AudiocomTrace, std::function< void(std::string_view)> completedHandler, bool silent)
std::function< void(std::string_view)> AuthSuccessCallback
void Register(std::string_view email, std::string_view password, AuthSuccessCallback successCallback, AuthFailureCallback failureCallback, AudiocomTrace trace)
Register a new user with email and password.
void Authorize(std::string_view email, std::string_view password, AuthSuccessCallback successCallback, AuthFailureCallback failureCallback, AudiocomTrace trace)
void SafePublish(const AuthStateChangedMessage &message)
void AuthoriseCode(const ServiceConfig &config, std::string_view authorizationCode, bool useAudioComRedirectURI, AudiocomTrace, std::function< void(std::string_view)> completedHandler)
void DoAuthorise(const ServiceConfig &config, std::string_view payload, AudiocomTrace, std::function< void(std::string_view)> completedHandler, bool silent)
void ParseTokenResponse(std::string_view response, AuthSuccessCallback successCallback, AuthFailureCallback failureCallback, AudiocomTrace trace, bool silent)
std::string MakeAudioComAuthorizeURL(std::string_view userId, std::string_view redirectUrl)
Creates a link to authorize audio.com using current auth token.
void ValidateAuth(AuthSuccessCallback completedHandler, AudiocomTrace, bool silent)
Attempt to authorize the user.
void AuthorisePassword(const ServiceConfig &config, std::string_view userName, std::string_view password, AudiocomTrace, std::function< void(std::string_view)> completedHandler)
void UnlinkAccount(AudiocomTrace)
Removes access and refresh token, notifies about the logout.
static std::string MakeOAuthRequestURL(std::string_view authClientId)
Creates a link to authorization request dialog.
Clock::time_point mTokenExpirationTime
std::function< void(unsigned, std::string_view)> AuthFailureCallback
bool HasAccessToken() const
Indicates, that service has a valid access token, i. e. that the user is authorized.
bool HandleLinkURI(std::string_view uri, AudiocomTrace, AuthSuccessCallback completedHandler)
Handle the OAuth callback.
std::recursive_mutex mMutex
std::string GetAccessToken() const
Return the current access token, if any.
Configuration for the audio.com.
std::string GetOAuthRedirectURL() const
OAuth2 redirect URL. Only used to satisfy the protocol.
std::string GetOAuthClientSecret() const
OAuth2 client secret.
std::string GetAPIUrl(std::string_view apiURI) const
Helper to construct the full URLs for the API.
std::string GetOAuthClientID() const
OAuth2 client ID.
void OnSettingResetBegin() override
Happens before preferences reset.
void OnSettingResetEnd() override
Happens after preferences reset.
static NetworkManager & GetInstance()
ResponsePtr doPost(const Request &request, const void *data, size_t size)
Request & setHeader(const std::string &name, std::string value)
void CallAfter(Action action)
Schedule an action to be done later, and in the main thread.
constexpr size_t npos(-1)
static CommandContext::TargetFactory::SubstituteInUnique< InteractiveOutputTargets > scope
AuthorizationHandler handler
const std::string_view userPrefix
void append(std::basic_string< Elem > &dest, First &&first, Others &&...others)
const std::string_view clientIdPrefix
const std::string_view codePrefix
static PreferencesResetHandler::Registration< OAuthServiceSettingsResetHandler > resetHandler
void WriteClientFields(rapidjson::Document &document)
const std::string_view usernamePrefix
const std::string_view passwordPrefix
StringSetting refreshToken
const std::string_view authClientPrefix
const std::string_view tokenPrefix
const std::string_view authorizationCodePrefix
const std::string_view urlPrefix
auto concat(First &&first, Others &&...others)
const std::string_view uriPrefix
const std::string_view responseTypePrefix
void WriteCommonFields(rapidjson::Document &document, std::string_view grantType, std::string_view scope)
void WriteAccessFields(rapidjson::Document &document, std::string_view grantType, std::string_view scope)
OAuthService & GetOAuthService()
Returns the instance of the OAuthService.
const ServiceConfig & GetServiceConfig()
Returns the instance of the ServiceConfig.
const std::string ApplicationJson
std::string ToUTF8(const std::wstring &wstr)
std::string UrlDecode(const std::string &url)
Performs single-time global handler registration.
Message that is sent when authorization state changes.