Audacity 3.2.0
Public Types | Public Member Functions | Static Public Member Functions | Private Types | Private Member Functions | Private Attributes | List of all members
audacity::cloud::audiocom::OAuthService Class Referencefinal

Service responsible for OAuth authentication against the audio.com service. More...

#include <OAuthService.h>

Inheritance diagram for audacity::cloud::audiocom::OAuthService:
[legend]
Collaboration diagram for audacity::cloud::audiocom::OAuthService:
[legend]

Public Types

using AuthSuccessCallback = std::function< void(std::string_view)>
 
using AuthFailureCallback = std::function< void(unsigned, std::string_view)>
 
- Public Types inherited from Observer::Publisher< AuthStateChangedMessage >
using message_type = AuthStateChangedMessage
 
using CallbackReturn = std::conditional_t< true, void, bool >
 
using Callback = std::function< CallbackReturn(const AuthStateChangedMessage &) >
 Type of functions that can be connected to the Publisher. More...
 

Public Member Functions

bool HasAccessToken () const
 Indicates, that service has a valid access token, i. e. that the user is authorized. More...
 
bool HasRefreshToken () const
 
void ValidateAuth (AuthSuccessCallback completedHandler, AudiocomTrace, bool silent)
 Attempt to authorize the user. More...
 
bool HandleLinkURI (std::string_view uri, AudiocomTrace, AuthSuccessCallback completedHandler)
 Handle the OAuth callback. More...
 
void UnlinkAccount (AudiocomTrace)
 Removes access and refresh token, notifies about the logout. More...
 
std::string GetAccessToken () const
 Return the current access token, if any. More...
 
std::string MakeAudioComAuthorizeURL (std::string_view userId, std::string_view redirectUrl)
 Creates a link to authorize audio.com using current auth token. More...
 
void Authorize (std::string_view email, std::string_view password, AuthSuccessCallback successCallback, AuthFailureCallback failureCallback, AudiocomTrace trace)
 
void Register (std::string_view email, std::string_view password, AuthSuccessCallback successCallback, AuthFailureCallback failureCallback, AudiocomTrace trace)
 Register a new user with email and password. More...
 
- Public Member Functions inherited from Observer::Publisher< AuthStateChangedMessage >
 Publisher (ExceptionPolicy *pPolicy=nullptr, Alloc a={})
 Constructor supporting type-erased custom allocation/deletion. More...
 
 Publisher (Publisher &&)=default
 
Publisheroperator= (Publisher &&)=default
 
Subscription Subscribe (Callback callback)
 Connect a callback to the Publisher; later-connected are called earlier. More...
 
Subscription Subscribe (Object &obj, Return(Object::*callback)(Args...))
 Overload of Subscribe takes an object and pointer-to-member-function. More...
 

Static Public Member Functions

static std::string MakeOAuthRequestURL (std::string_view authClientId)
 Creates a link to authorization request dialog. More...
 

Private Types

using Clock = std::chrono::steady_clock
 

Private Member Functions

void AuthorisePassword (const ServiceConfig &config, std::string_view userName, std::string_view password, AudiocomTrace, std::function< void(std::string_view)> completedHandler)
 
void AuthoriseRefreshToken (const ServiceConfig &config, std::string_view refreshToken, AudiocomTrace, std::function< void(std::string_view)> completedHandler, bool silent)
 
void AuthoriseRefreshToken (const ServiceConfig &config, AudiocomTrace, std::function< void(std::string_view)> completedHandler, bool silent)
 
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)
 
void SafePublish (const AuthStateChangedMessage &message)
 

Private Attributes

std::recursive_mutex mMutex
 
Clock::time_point mTokenExpirationTime
 
std::string mAccessToken
 

Additional Inherited Members

- Static Public Attributes inherited from Observer::Publisher< AuthStateChangedMessage >
static constexpr bool notifies_all
 
- Protected Member Functions inherited from Observer::Publisher< AuthStateChangedMessage >
CallbackReturn Publish (const AuthStateChangedMessage &message)
 Send a message to connected callbacks. More...
 

Detailed Description

Service responsible for OAuth authentication against the audio.com service.

Definition at line 41 of file OAuthService.h.

Member Typedef Documentation

◆ AuthFailureCallback

using audacity::cloud::audiocom::OAuthService::AuthFailureCallback = std::function<void(unsigned, std::string_view)>

Definition at line 46 of file OAuthService.h.

◆ AuthSuccessCallback

using audacity::cloud::audiocom::OAuthService::AuthSuccessCallback = std::function<void(std::string_view)>

Definition at line 45 of file OAuthService.h.

◆ Clock

using audacity::cloud::audiocom::OAuthService::Clock = std::chrono::steady_clock
private

Definition at line 142 of file OAuthService.h.

Member Function Documentation

◆ AuthoriseCode()

void audacity::cloud::audiocom::OAuthService::AuthoriseCode ( const ServiceConfig config,
std::string_view  authorizationCode,
bool  useAudioComRedirectURI,
AudiocomTrace  trace,
std::function< void(std::string_view)>  completedHandler 
)
private

Definition at line 294 of file OAuthService.cpp.

297{
298 using namespace rapidjson;
299
300 Document document;
301 document.SetObject();
302
303 WriteCommonFields(document, "authorization_code", "all");
304
305 document.AddMember(
306 "code", StringRef(authorizationCode.data(), authorizationCode.size()),
307 document.GetAllocator());
308
309 const auto redirectURI = useAudioComRedirectURI ? config.GetOAuthRedirectURL() : std::string("audacity://link");
310
311 document.AddMember(
312 "redirect_uri", StringRef(redirectURI.data(), redirectURI.size()),
313 document.GetAllocator());
314
315 rapidjson::StringBuffer buffer;
316 rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
317 document.Accept(writer);
318
320 config, { buffer.GetString(), buffer.GetSize() }, trace,
321 std::move(completedHandler), false);
322}
void DoAuthorise(const ServiceConfig &config, std::string_view payload, AudiocomTrace, std::function< void(std::string_view)> completedHandler, bool silent)
void WriteCommonFields(rapidjson::Document &document, std::string_view grantType, std::string_view scope)

References DoAuthorise(), audacity::cloud::audiocom::ServiceConfig::GetOAuthRedirectURL(), and audacity::cloud::audiocom::anonymous_namespace{OAuthService.cpp}::WriteCommonFields().

Referenced by HandleLinkURI().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ AuthorisePassword()

void audacity::cloud::audiocom::OAuthService::AuthorisePassword ( const ServiceConfig config,
std::string_view  userName,
std::string_view  password,
AudiocomTrace  trace,
std::function< void(std::string_view)>  completedHandler 
)
private

Definition at line 230 of file OAuthService.cpp.

234{
235 using namespace rapidjson;
236
237 Document document;
238 document.SetObject();
239
240 WriteCommonFields(document, "password", "all");
241
242 document.AddMember(
243 "username", StringRef(userName.data(), userName.size()),
244 document.GetAllocator());
245
246 document.AddMember(
247 "password", StringRef(password.data(), password.size()),
248 document.GetAllocator());
249
250 rapidjson::StringBuffer buffer;
251 rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
252 document.Accept(writer);
253
255 config, { buffer.GetString(), buffer.GetSize() }, trace,
256 std::move(completedHandler), false);
257}

References DoAuthorise(), audacity::cloud::audiocom::anonymous_namespace{UserService.cpp}::userName, and audacity::cloud::audiocom::anonymous_namespace{OAuthService.cpp}::WriteCommonFields().

Referenced by HandleLinkURI().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ AuthoriseRefreshToken() [1/2]

void audacity::cloud::audiocom::OAuthService::AuthoriseRefreshToken ( const ServiceConfig config,
AudiocomTrace  trace,
std::function< void(std::string_view)>  completedHandler,
bool  silent 
)
private

Definition at line 283 of file OAuthService.cpp.

286{
287 std::lock_guard<std::recursive_mutex> lock(mMutex);
288
290 config, audacity::ToUTF8(refreshToken.Read()), trace,
291 std::move(completedHandler), silent);
292}
bool Read(T *pVar) const
overload of Read returning a boolean that is true if the value was previously defined *‍/
Definition: Prefs.h:207
void AuthoriseRefreshToken(const ServiceConfig &config, std::string_view refreshToken, AudiocomTrace, std::function< void(std::string_view)> completedHandler, bool silent)
std::string ToUTF8(const std::wstring &wstr)

References AuthoriseRefreshToken(), mMutex, Setting< T >::Read(), audacity::cloud::audiocom::anonymous_namespace{OAuthService.cpp}::refreshToken, and audacity::ToUTF8().

Here is the call graph for this function:

◆ AuthoriseRefreshToken() [2/2]

void audacity::cloud::audiocom::OAuthService::AuthoriseRefreshToken ( const ServiceConfig config,
std::string_view  refreshToken,
AudiocomTrace  trace,
std::function< void(std::string_view)>  completedHandler,
bool  silent 
)
private

Definition at line 259 of file OAuthService.cpp.

262{
263 using namespace rapidjson;
264
265 Document document;
266 document.SetObject();
267
268 WriteCommonFields(document, "refresh_token", "");
269
270 document.AddMember(
271 "refresh_token", StringRef(token.data(), token.size()),
272 document.GetAllocator());
273
274 rapidjson::StringBuffer buffer;
275 rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
276 document.Accept(writer);
277
279 config, { buffer.GetString(), buffer.GetSize() }, trace,
280 std::move(completedHandler), silent);
281}

References DoAuthorise(), and audacity::cloud::audiocom::anonymous_namespace{OAuthService.cpp}::WriteCommonFields().

Referenced by AuthoriseRefreshToken(), HandleLinkURI(), and ValidateAuth().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Authorize()

void audacity::cloud::audiocom::OAuthService::Authorize ( std::string_view  email,
std::string_view  password,
AuthSuccessCallback  successCallback,
AuthFailureCallback  failureCallback,
AudiocomTrace  trace 
)

Definition at line 376 of file OAuthService.cpp.

381{
382 using namespace audacity::network_manager;
383 using rapidjson::StringRef;
384
385 rapidjson::Document document;
386 document.SetObject();
387
388 WriteCommonFields(document, "password", "all");
389
390 document.AddMember(
391 "username", StringRef(email.data(), email.size()),
392 document.GetAllocator());
393
394 document.AddMember(
395 "password", StringRef(password.data(), password.size()),
396 document.GetAllocator());
397
398 rapidjson::StringBuffer buffer;
399 rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
400 document.Accept(writer);
401
402 Request request(GetServiceConfig().GetAPIUrl("/auth/token"));
405
406 auto response = NetworkManager::GetInstance().doPost(request, buffer.GetString(), buffer.GetSize());
407 response->setRequestFinishedCallback(
408 [response, this, trace,
409 onSuccess = std::move(onSuccess),
410 onFailure = std::move(onFailure)](auto) mutable
411 {
412 const auto httpCode = response->getHTTPCode();
413 const auto body = response->readAll<std::string>();
414 if(httpCode == 200)
415 ParseTokenResponse(body, std::move(onSuccess), std::move(onFailure), trace, false);
416 else
417 {
418 if(onFailure)
419 onFailure(httpCode, body);
420
421 SafePublish({ {}, body, trace, false, false });
422 }
423 });
424}
void SafePublish(const AuthStateChangedMessage &message)
void ParseTokenResponse(std::string_view response, AuthSuccessCallback successCallback, AuthFailureCallback failureCallback, AudiocomTrace trace, bool silent)
ResponsePtr doPost(const Request &request, const void *data, size_t size)
const ServiceConfig & GetServiceConfig()
Returns the instance of the ServiceConfig.

References audacity::network_manager::common_headers::Accept, audacity::network_manager::common_content_types::ApplicationJson, audacity::network_manager::common_headers::ContentType, audacity::network_manager::NetworkManager::doPost(), audacity::network_manager::NetworkManager::GetInstance(), audacity::cloud::audiocom::GetServiceConfig(), ParseTokenResponse(), SafePublish(), audacity::network_manager::Request::setHeader(), and audacity::cloud::audiocom::anonymous_namespace{OAuthService.cpp}::WriteCommonFields().

Here is the call graph for this function:

◆ DoAuthorise()

void audacity::cloud::audiocom::OAuthService::DoAuthorise ( const ServiceConfig config,
std::string_view  payload,
AudiocomTrace  trace,
std::function< void(std::string_view)>  completedHandler,
bool  silent 
)
private

Definition at line 476 of file OAuthService.cpp.

479{
480 using namespace audacity::network_manager;
481
482 Request request(config.GetAPIUrl("/auth/token"));
483
484 request.setHeader(
486
487 request.setHeader(
489
490 auto response = NetworkManager::GetInstance().doPost(
491 request, payload.data(), payload.size());
492
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>();
498
499 if (httpCode != 200)
500 {
501 if (handler)
502 handler({});
503
504 // Token has expired?
505 if (httpCode == 422)
506 BasicUI::CallAfter([this, trace] { UnlinkAccount(trace); });
507 else
508 SafePublish({ {}, body, trace, false, silent });
509
510 return;
511 }
512 ParseTokenResponse(body, std::move(handler), {}, trace, silent);
513 });
514}
void UnlinkAccount(AudiocomTrace)
Removes access and refresh token, notifies about the logout.
void CallAfter(Action action)
Schedule an action to be done later, and in the main thread.
Definition: BasicUI.cpp:214

References audacity::network_manager::common_headers::Accept, audacity::network_manager::common_content_types::ApplicationJson, BasicUI::CallAfter(), audacity::network_manager::common_headers::ContentType, audacity::network_manager::NetworkManager::doPost(), audacity::cloud::audiocom::ServiceConfig::GetAPIUrl(), audacity::network_manager::NetworkManager::GetInstance(), audacity::cloud::audiocom::anonymous_namespace{AuthorizationHandler.cpp}::handler, ParseTokenResponse(), SafePublish(), audacity::network_manager::Request::setHeader(), and UnlinkAccount().

Referenced by AuthoriseCode(), AuthorisePassword(), and AuthoriseRefreshToken().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetAccessToken()

std::string audacity::cloud::audiocom::OAuthService::GetAccessToken ( ) const

Return the current access token, if any.

Definition at line 335 of file OAuthService.cpp.

336{
337 std::lock_guard<std::recursive_mutex> lock(mMutex);
338
339 if (Clock::now() < mTokenExpirationTime)
340 return mAccessToken;
341
342 return {};
343}

References mAccessToken, mMutex, and mTokenExpirationTime.

Referenced by HasAccessToken(), MakeAudioComAuthorizeURL(), audacity::cloud::audiocom::sync::LocalProjectSnapshot::UpdateProjectSnapshot(), and ValidateAuth().

Here is the caller graph for this function:

◆ HandleLinkURI()

bool audacity::cloud::audiocom::OAuthService::HandleLinkURI ( std::string_view  uri,
AudiocomTrace  trace,
AuthSuccessCallback  completedHandler 
)

Handle the OAuth callback.

Definition at line 126 of file OAuthService.cpp.

129{
131 {
132 if (completedHandler)
133 completedHandler({});
134 return false;
135 }
136
137 // It was observed, that sometimes link is passed as audacity://link/
138 // This is valid trace URI point of view, but we need to handle it separately
139 const auto argsStart = uri.find("?");
140
141 if (argsStart == std::string_view::npos)
142 {
143 if (completedHandler)
144 completedHandler({});
145 return false;
146 }
147
148 // Length is handled in IsPrefixed
149 auto args = uri.substr(argsStart + 1);
150
151 std::string_view token;
152 std::string_view username;
153 std::string_view password;
154 std::string_view authorizationCode;
155 auto useAudioComRedirectURI = false;
156
157 while (!args.empty())
158 {
159 const auto nextArg = args.find('&');
160
161 const auto arg = args.substr(0, nextArg);
162 args = nextArg == std::string_view::npos ? "" : args.substr(nextArg + 1);
163
164 if (IsPrefixed(arg, usernamePrefix))
165 username = arg.substr(usernamePrefix.length());
166 else if (IsPrefixed(arg, passwordPrefix))
167 password = arg.substr(passwordPrefix.length());
168 else if (IsPrefixed(arg, tokenPrefix))
169 token = arg.substr(tokenPrefix.length());
170 else if (IsPrefixed(arg, authorizationCodePrefix))
171 {
172 //authorization code was generated for audio.com, not audacity...
173 useAudioComRedirectURI = true;
174 authorizationCode = arg.substr(authorizationCodePrefix.length());
175 }
176 else if (IsPrefixed(arg, codePrefix))
177 authorizationCode = arg.substr(codePrefix.length());
178 }
179
180 // Some browsers (safari) add an extra trailing chars we don't need
181 size_t hashPos = authorizationCode.find('#');
182
183 if (hashPos != std::string::npos) {
184 authorizationCode = authorizationCode.substr(0, hashPos);
185 }
186
187 // We have a prioritized list of authorization methods
188 if (!authorizationCode.empty())
189 {
191 GetServiceConfig(), authorizationCode, useAudioComRedirectURI, trace,
192 std::move(completedHandler));
193 }
194 else if (!token.empty())
195 {
197 GetServiceConfig(), token, trace, std::move(completedHandler), false);
198 }
199 else if (!username.empty() && !password.empty())
200 {
202 GetServiceConfig(), audacity::UrlDecode(std::string(username)),
203 audacity::UrlDecode(std::string(password)), trace,
204 std::move(completedHandler));
205 }
206 else
207 {
208 if (completedHandler)
209 completedHandler({});
210
211 return false;
212 }
213
214 return true;
215}
bool IsPrefixedInsensitive(const HayType &hay, const PrefixType &prefix)
Definition: StringUtils.h:146
bool IsPrefixed(const HayType &hay, const PrefixType &prefix)
Definition: StringUtils.h:129
void AuthoriseCode(const ServiceConfig &config, std::string_view authorizationCode, bool useAudioComRedirectURI, AudiocomTrace, std::function< void(std::string_view)> completedHandler)
void AuthorisePassword(const ServiceConfig &config, std::string_view userName, std::string_view password, AudiocomTrace, std::function< void(std::string_view)> completedHandler)
constexpr size_t npos(-1)
std::string UrlDecode(const std::string &url)
Definition: UrlDecode.cpp:18

References AuthoriseCode(), AuthorisePassword(), AuthoriseRefreshToken(), audacity::cloud::audiocom::anonymous_namespace{OAuthService.cpp}::authorizationCodePrefix, audacity::cloud::audiocom::anonymous_namespace{OAuthService.cpp}::codePrefix, audacity::cloud::audiocom::GetServiceConfig(), IsPrefixed(), IsPrefixedInsensitive(), Tuple::detail::npos(), audacity::cloud::audiocom::anonymous_namespace{OAuthService.cpp}::passwordPrefix, audacity::cloud::audiocom::anonymous_namespace{OAuthService.cpp}::tokenPrefix, audacity::cloud::audiocom::anonymous_namespace{OAuthService.cpp}::uriPrefix, audacity::UrlDecode(), and audacity::cloud::audiocom::anonymous_namespace{OAuthService.cpp}::usernamePrefix.

Referenced by audacity::cloud::audiocom::LinkWithTokenDialog::OnContinue().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ HasAccessToken()

bool audacity::cloud::audiocom::OAuthService::HasAccessToken ( ) const

Indicates, that service has a valid access token, i. e. that the user is authorized.

Definition at line 324 of file OAuthService.cpp.

325{
326 return !GetAccessToken().empty();
327}
std::string GetAccessToken() const
Return the current access token, if any.

References GetAccessToken().

Referenced by audacity::cloud::audiocom::anonymous_namespace{CloudSyncService.cpp}::PerformProjectGetRequest(), and ValidateAuth().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ HasRefreshToken()

bool audacity::cloud::audiocom::OAuthService::HasRefreshToken ( ) const

Indicates, that the service has a possibly valid refresh token, which can be used to authorize the user

Definition at line 329 of file OAuthService.cpp.

330{
331 std::lock_guard<std::recursive_mutex> lock(mMutex);
332 return !refreshToken.Read().empty();
333}

References mMutex, Setting< T >::Read(), and audacity::cloud::audiocom::anonymous_namespace{OAuthService.cpp}::refreshToken.

Referenced by ValidateAuth().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ MakeAudioComAuthorizeURL()

std::string audacity::cloud::audiocom::OAuthService::MakeAudioComAuthorizeURL ( std::string_view  userId,
std::string_view  redirectUrl 
)

Creates a link to authorize audio.com using current auth token.

Definition at line 358 of file OAuthService.cpp.

359{
360 auto token = GetAccessToken();
361
362 // Remove token type from the token string
363 size_t pos = token.find(' ');
364 if (pos != std::string::npos) {
365 token = token.substr(pos + 1);
366 }
367
368 return concat(
369 GetServiceConfig().GetAuthWithRedirectURL(), "?",
370 tokenPrefix, token, "&",
371 userPrefix, userId, "&",
372 urlPrefix, redirectUrl
373 );
374}

References audacity::cloud::audiocom::anonymous_namespace{OAuthService.cpp}::concat(), GetAccessToken(), audacity::cloud::audiocom::GetServiceConfig(), Tuple::detail::npos(), audacity::cloud::audiocom::anonymous_namespace{OAuthService.cpp}::tokenPrefix, audacity::cloud::audiocom::anonymous_namespace{OAuthService.cpp}::urlPrefix, audacity::cloud::audiocom::anonymous_namespace{UserService.cpp}::userId, and audacity::cloud::audiocom::anonymous_namespace{OAuthService.cpp}::userPrefix.

Here is the call graph for this function:

◆ MakeOAuthRequestURL()

std::string audacity::cloud::audiocom::OAuthService::MakeOAuthRequestURL ( std::string_view  authClientId)
static

Creates a link to authorization request dialog.

Definition at line 345 of file OAuthService.cpp.

346{
347 using namespace audacity::network_manager;
348
349 return concat(
350 GetServiceConfig().GetAPIUrl("/auth/authorize?"),
351 authClientPrefix, authClientId, "&",
352 responseTypePrefix, "code", "&",
353 clientIdPrefix, GetServiceConfig().GetOAuthClientID(),
354 "&redirect_uri=audacity://link"
355 );
356}

References audacity::cloud::audiocom::anonymous_namespace{OAuthService.cpp}::authClientPrefix, audacity::cloud::audiocom::anonymous_namespace{OAuthService.cpp}::clientIdPrefix, audacity::cloud::audiocom::anonymous_namespace{OAuthService.cpp}::concat(), audacity::cloud::audiocom::GetServiceConfig(), and audacity::cloud::audiocom::anonymous_namespace{OAuthService.cpp}::responseTypePrefix.

Referenced by LoginDialog::ContinueAuthorize().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ParseTokenResponse()

void audacity::cloud::audiocom::OAuthService::ParseTokenResponse ( std::string_view  response,
AuthSuccessCallback  successCallback,
AuthFailureCallback  failureCallback,
AudiocomTrace  trace,
bool  silent 
)
private

Definition at line 516 of file OAuthService.cpp.

521{
522 rapidjson::Document document;
523 document.Parse(body.data(), body.size());
524
525 if (!document.IsObject())
526 {
527 if (failureCallback)
528 failureCallback(200, body);
529
530 SafePublish({ {}, body, trace, false, silent });
531 return;
532 }
533
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();
538
539 {
540 std::lock_guard<std::recursive_mutex> lock(mMutex);
541
542 mAccessToken = std::string(tokenType) + " " + accessToken;
544 Clock::now() + std::chrono::seconds(expiresIn);
545 }
546
548 [token = std::string(newRefreshToken)]()
549 {
550 // At this point access token is already written,
551 // only refresh token is updated.
552 refreshToken.Write(token);
553 gPrefs->Flush();
554 });
555
556 if (successCallback)
557 successCallback(mAccessToken);
558
559 // The callback only needs the access token, so invoke it immediately.
560 // Networking is thread safe
561 SafePublish({ mAccessToken, {}, trace, true, silent });
562}
audacity::BasicSettings * gPrefs
Definition: Prefs.cpp:68
bool Write(const T &value)
Write value to config and return true if successful.
Definition: Prefs.h:259
virtual bool Flush() noexcept=0

References BasicUI::CallAfter(), audacity::BasicSettings::Flush(), gPrefs, mAccessToken, mMutex, mTokenExpirationTime, audacity::cloud::audiocom::anonymous_namespace{OAuthService.cpp}::refreshToken, SafePublish(), and Setting< T >::Write().

Referenced by Authorize(), DoAuthorise(), and Register().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Register()

void audacity::cloud::audiocom::OAuthService::Register ( std::string_view  email,
std::string_view  password,
AuthSuccessCallback  successCallback,
AuthFailureCallback  failureCallback,
AudiocomTrace  trace 
)

Register a new user with email and password.

Definition at line 426 of file OAuthService.cpp.

431{
432 using namespace audacity::network_manager;
433 using rapidjson::StringRef;
434
435 rapidjson::Document document;
436 document.SetObject();
437
438 WriteClientFields(document);
439
440 document.AddMember(
441 "email", StringRef(email.data(), email.size()),
442 document.GetAllocator());
443
444 document.AddMember(
445 "password", StringRef(password.data(), password.size()),
446 document.GetAllocator());
447
448 rapidjson::StringBuffer buffer;
449 rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
450 document.Accept(writer);
451
452 Request request(GetServiceConfig().GetAPIUrl("/auth/register"));
455
456 auto response = NetworkManager::GetInstance().doPost(request, buffer.GetString(), buffer.GetSize());
457 response->setRequestFinishedCallback(
458 [response, this, trace,
459 successCallback = std::move(successCallback),
460 failureCallback = std::move(failureCallback)] (auto) mutable
461 {
462 const auto httpCode = response->getHTTPCode();
463 const auto body = response->readAll<std::string>();
464 if(httpCode == 200)
465 ParseTokenResponse(body, std::move(successCallback), std::move(failureCallback), trace, false);
466 else
467 {
468 if(failureCallback)
469 failureCallback(httpCode, body);
470
471 SafePublish({ {}, body, trace, false, false });
472 }
473 });
474}

References audacity::network_manager::common_headers::Accept, audacity::network_manager::common_content_types::ApplicationJson, audacity::network_manager::common_headers::ContentType, audacity::network_manager::NetworkManager::doPost(), audacity::network_manager::NetworkManager::GetInstance(), audacity::cloud::audiocom::GetServiceConfig(), ParseTokenResponse(), SafePublish(), audacity::network_manager::Request::setHeader(), and audacity::cloud::audiocom::anonymous_namespace{OAuthService.cpp}::WriteClientFields().

Here is the call graph for this function:

◆ SafePublish()

void audacity::cloud::audiocom::OAuthService::SafePublish ( const AuthStateChangedMessage message)
private

Definition at line 564 of file OAuthService.cpp.

565{
566 BasicUI::CallAfter([this, message]() { Publish(message); });
567}
CallbackReturn Publish(const AuthStateChangedMessage &message)
Send a message to connected callbacks.
Definition: Observer.h:207

References BasicUI::CallAfter(), and Observer::Publisher< AuthStateChangedMessage >::Publish().

Referenced by Authorize(), DoAuthorise(), ParseTokenResponse(), and Register().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ UnlinkAccount()

void audacity::cloud::audiocom::OAuthService::UnlinkAccount ( AudiocomTrace  trace)

Removes access and refresh token, notifies about the logout.

Definition at line 217 of file OAuthService.cpp.

218{
219 std::lock_guard<std::recursive_mutex> lock(mMutex);
220
221 mAccessToken.clear();
223 gPrefs->Flush();
224
225 // Unlink account is expected to be called only
226 // on UI thread
227 Publish({ {}, {}, trace, false });
228}

References audacity::BasicSettings::Flush(), gPrefs, mAccessToken, mMutex, Observer::Publisher< AuthStateChangedMessage >::Publish(), audacity::cloud::audiocom::anonymous_namespace{OAuthService.cpp}::refreshToken, and Setting< T >::Write().

Referenced by DoAuthorise(), audacity::cloud::audiocom::sync::ProjectCloudUIExtension::OnCloudStatusChanged(), and audacity::cloud::audiocom::anonymous_namespace{OAuthService.cpp}::OAuthServiceSettingsResetHandler::OnSettingResetEnd().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ValidateAuth()

void audacity::cloud::audiocom::OAuthService::ValidateAuth ( AuthSuccessCallback  completedHandler,
AudiocomTrace  trace,
bool  silent 
)

Attempt to authorize the user.

Definition at line 111 of file OAuthService.cpp.

114{
116 {
117 if (completedHandler)
118 completedHandler(GetAccessToken());
119 return;
120 }
121
123 GetServiceConfig(), trace, std::move(completedHandler), silent);
124}
bool HasAccessToken() const
Indicates, that service has a valid access token, i. e. that the user is authorized.

References AuthoriseRefreshToken(), GetAccessToken(), audacity::cloud::audiocom::GetServiceConfig(), HasAccessToken(), and HasRefreshToken().

Referenced by audacity::cloud::audiocom::UploadService::Upload().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ mAccessToken

std::string audacity::cloud::audiocom::OAuthService::mAccessToken
private

Definition at line 147 of file OAuthService.h.

Referenced by GetAccessToken(), ParseTokenResponse(), and UnlinkAccount().

◆ mMutex

std::recursive_mutex audacity::cloud::audiocom::OAuthService::mMutex
mutableprivate

◆ mTokenExpirationTime

Clock::time_point audacity::cloud::audiocom::OAuthService::mTokenExpirationTime
private

Definition at line 146 of file OAuthService.h.

Referenced by GetAccessToken(), and ParseTokenResponse().


The documentation for this class was generated from the following files: