From 042bb271148aa99e21ee3c36f5c27a647a725f6b Mon Sep 17 00:00:00 2001 From: Terry Mancey Date: Tue, 6 Aug 2019 23:05:38 +0200 Subject: [PATCH] Issue with Ads Payments (August 5) Fixes https://github.com/brave/brave-browser/issues/5548 * Fix race condition where same token was reused due to network latency etc. * Fix issue where only 1 failed confirmation was retried per session * Migrate failed confirmation tokens which return HTTP_NOT_FOUND due to race condition * Fix HTTP_BAD_REQUEST errors when retrying failed confirmations if the confirmation was already created --- .../internal/confirmation_info.cc | 8 +- .../internal/confirmation_info.h | 3 + .../internal/confirmations_impl.cc | 71 ++++- .../internal/confirmations_impl.h | 11 +- .../confirmations/internal/redeem_token.cc | 247 ++++++++++-------- .../bat/confirmations/internal/redeem_token.h | 16 +- 6 files changed, 216 insertions(+), 140 deletions(-) diff --git a/vendor/bat-native-confirmations/src/bat/confirmations/internal/confirmation_info.cc b/vendor/bat-native-confirmations/src/bat/confirmations/internal/confirmation_info.cc index 3db4ff19f731..06b37b11aea8 100644 --- a/vendor/bat-native-confirmations/src/bat/confirmations/internal/confirmation_info.cc +++ b/vendor/bat-native-confirmations/src/bat/confirmations/internal/confirmation_info.cc @@ -14,7 +14,9 @@ ConfirmationInfo::ConfirmationInfo() : token_info(TokenInfo()), payment_token(nullptr), blinded_payment_token(nullptr), - credential("") {} + credential(""), + timestamp_in_seconds(0), + created(false) {} ConfirmationInfo::ConfirmationInfo(const ConfirmationInfo& info) : id(info.id), @@ -23,7 +25,9 @@ ConfirmationInfo::ConfirmationInfo(const ConfirmationInfo& info) : token_info(info.token_info), payment_token(info.payment_token), blinded_payment_token(info.blinded_payment_token), - credential(info.credential) {} + credential(info.credential), + timestamp_in_seconds(info.timestamp_in_seconds), + created(info.created) {} ConfirmationInfo::~ConfirmationInfo() {} diff --git a/vendor/bat-native-confirmations/src/bat/confirmations/internal/confirmation_info.h b/vendor/bat-native-confirmations/src/bat/confirmations/internal/confirmation_info.h index 00df164845e5..9b3bb821089a 100644 --- a/vendor/bat-native-confirmations/src/bat/confirmations/internal/confirmation_info.h +++ b/vendor/bat-native-confirmations/src/bat/confirmations/internal/confirmation_info.h @@ -6,6 +6,7 @@ #ifndef BAT_CONFIRMATIONS_INTERNAL_CONFIRMATION_INFO_H_ #define BAT_CONFIRMATIONS_INTERNAL_CONFIRMATION_INFO_H_ +#include #include #include "bat/confirmations/confirmation_type.h" @@ -30,6 +31,8 @@ struct ConfirmationInfo { Token payment_token; BlindedToken blinded_payment_token; std::string credential; + uint64_t timestamp_in_seconds; + bool created; }; } // namespace confirmations diff --git a/vendor/bat-native-confirmations/src/bat/confirmations/internal/confirmations_impl.cc b/vendor/bat-native-confirmations/src/bat/confirmations/internal/confirmations_impl.cc index 3b86c2551dff..b30287974b06 100644 --- a/vendor/bat-native-confirmations/src/bat/confirmations/internal/confirmations_impl.cc +++ b/vendor/bat-native-confirmations/src/bat/confirmations/internal/confirmations_impl.cc @@ -82,9 +82,9 @@ void ConfirmationsImpl::MaybeStart() { auto start_timer_in = CalculateTokenRedemptionTimeInSeconds(); StartPayingOutRedeemedTokens(start_timer_in); - RetryFailedConfirmations(); - RefillTokensIfNecessary(); + + StartRetryingFailedConfirmations(); } void ConfirmationsImpl::NotifyAdsIfConfirmationsIsReady() { @@ -194,6 +194,12 @@ base::Value ConfirmationsImpl::GetConfirmationsAsDictionary( confirmation_dictionary.SetKey("credential", base::Value(confirmation.credential)); + confirmation_dictionary.SetKey("timestamp_in_seconds", + base::Value(std::to_string(confirmation.timestamp_in_seconds))); + + confirmation_dictionary.SetKey("created", + base::Value(confirmation.created)); + list.GetList().push_back(std::move(confirmation_dictionary)); } @@ -529,6 +535,24 @@ bool ConfirmationsImpl::GetConfirmationsFromDictionary( continue; } + // Timestamp + auto* timestamp_in_seconds_value = + confirmation_dictionary->FindKey("timestamp_in_seconds"); + if (timestamp_in_seconds_value) { + auto timestamp_in_seconds = + std::stoull(timestamp_in_seconds_value->GetString()); + + confirmation_info.timestamp_in_seconds = timestamp_in_seconds; + } + + // Created + auto* created_value = confirmation_dictionary->FindKey("created"); + if (created_value) { + confirmation_info.created = created_value->GetBool(); + } else { + confirmation_info.created = true; + } + confirmations->push_back(confirmation_info); } @@ -803,24 +827,37 @@ void ConfirmationsImpl::AppendConfirmationToQueue( confirmations_.push_back(confirmation_info); SaveState(); + + BLOG(INFO) << "Added " << confirmation_info.id + << " confirmation id with " << confirmation_info.creative_instance_id + << " creative instance id for " << std::string(confirmation_info.type) + << " to the confirmations queue"; + + if (!IsRetryingFailedConfirmations()) { + StartRetryingFailedConfirmations(); + } } void ConfirmationsImpl::RemoveConfirmationFromQueue( const ConfirmationInfo& confirmation_info) { - auto id = confirmation_info.id; - auto it = std::find_if(confirmations_.begin(), confirmations_.end(), [=](const ConfirmationInfo& info) { - return (info.id == id); + return (info.id == confirmation_info.id); }); if (it == confirmations_.end()) { + BLOG(WARNING) << "Failed to remove " << confirmation_info.id + << " confirmation id with " << confirmation_info.creative_instance_id + << " creative instance id for " << std::string(confirmation_info.type) + << " from the confirmations queue"; + return; } - BLOG(INFO) << "Removed " << confirmation_info.creative_instance_id + BLOG(INFO) << "Removed " << confirmation_info.id + << " confirmation id with " << confirmation_info.creative_instance_id << " creative instance id for " << std::string(confirmation_info.type) - << " from the confirmation queue"; + << " from the confirmations queue"; confirmations_.erase(it); @@ -1076,13 +1113,15 @@ void ConfirmationsImpl::UpdateNextTokenRedemptionDate() { SaveState(); } +void ConfirmationsImpl::StartRetryingFailedConfirmations() { + auto start_timer_in = + brave_base::random::Geometric(kRetryFailedConfirmationsAfterSeconds); + + StartRetryingFailedConfirmations(start_timer_in); +} + void ConfirmationsImpl::StartRetryingFailedConfirmations( const uint64_t start_timer_in) { - if (confirmations_.size() == 0) { - BLOG(INFO) << "No failed confirmations to retry"; - return; - } - StopRetryingFailedConfirmations(); confirmations_client_->SetTimer(start_timer_in, @@ -1098,14 +1137,20 @@ void ConfirmationsImpl::StartRetryingFailedConfirmations( << " seconds"; } -void ConfirmationsImpl::RetryFailedConfirmations() const { +void ConfirmationsImpl::RetryFailedConfirmations() { + StopRetryingFailedConfirmations(); + if (confirmations_.size() == 0) { BLOG(INFO) << "No failed confirmations to retry"; return; } ConfirmationInfo confirmation_info(confirmations_.front()); + RemoveConfirmationFromQueue(confirmation_info); + redeem_token_->Redeem(confirmation_info); + + StartRetryingFailedConfirmations(); } void ConfirmationsImpl::StopRetryingFailedConfirmations() { diff --git a/vendor/bat-native-confirmations/src/bat/confirmations/internal/confirmations_impl.h b/vendor/bat-native-confirmations/src/bat/confirmations/internal/confirmations_impl.h index a04b0b61a6a9..2ad15673b214 100644 --- a/vendor/bat-native-confirmations/src/bat/confirmations/internal/confirmations_impl.h +++ b/vendor/bat-native-confirmations/src/bat/confirmations/internal/confirmations_impl.h @@ -46,9 +46,7 @@ class ConfirmationsImpl : public Confirmations { // Confirmations void AppendConfirmationToQueue(const ConfirmationInfo& confirmation_info); - void RemoveConfirmationFromQueue(const ConfirmationInfo& confirmation_info); - void StartRetryingFailedConfirmations(const uint64_t start_timer_in); - bool IsRetryingFailedConfirmations() const; + void StartRetryingFailedConfirmations(); // Ads rewards void UpdateAdsRewards(const bool should_refresh) override; @@ -80,8 +78,8 @@ class ConfirmationsImpl : public Confirmations { bool OnTimer(const uint32_t timer_id) override; // Refill tokens - void RefillTokensIfNecessary() const; void StartRetryingToGetRefillSignedTokens(const uint64_t start_timer_in); + void RefillTokensIfNecessary() const; // Redeem unblinded tokens void ConfirmAd(std::unique_ptr info) override; @@ -108,7 +106,10 @@ class ConfirmationsImpl : public Confirmations { // Confirmations uint32_t retry_failed_confirmations_timer_id_; - void RetryFailedConfirmations() const; + void RemoveConfirmationFromQueue(const ConfirmationInfo& confirmation_info); + void StartRetryingFailedConfirmations(const uint64_t start_timer_in); + bool IsRetryingFailedConfirmations() const; + void RetryFailedConfirmations(); void StopRetryingFailedConfirmations(); std::vector confirmations_; diff --git a/vendor/bat-native-confirmations/src/bat/confirmations/internal/redeem_token.cc b/vendor/bat-native-confirmations/src/bat/confirmations/internal/redeem_token.cc index 1401cf0969e7..e37afd470cdb 100644 --- a/vendor/bat-native-confirmations/src/bat/confirmations/internal/redeem_token.cc +++ b/vendor/bat-native-confirmations/src/bat/confirmations/internal/redeem_token.cc @@ -14,6 +14,7 @@ #include "bat/confirmations/internal/unblinded_tokens.h" #include "bat/confirmations/internal/create_confirmation_request.h" #include "bat/confirmations/internal/fetch_payment_token_request.h" +#include "bat/confirmations/internal/time.h" #include "base/logging.h" #include "base/guid.h" @@ -21,13 +22,16 @@ #include "base/values.h" #include "brave_base/random.h" #include "net/http/http_status_code.h" +#include "base/base64.h" using std::placeholders::_1; using std::placeholders::_2; using std::placeholders::_3; +using challenge_bypass_ristretto::BlindedToken; using challenge_bypass_ristretto::SignedToken; using challenge_bypass_ristretto::BatchDLEQProof; +using challenge_bypass_ristretto::VerificationSignature; using challenge_bypass_ristretto::PublicKey; namespace confirmations { @@ -58,18 +62,32 @@ void RedeemToken::Redeem( } auto token_info = unblinded_tokens_->GetToken(); + unblinded_tokens_->RemoveToken(token_info); + CreateConfirmation(creative_instance_id, token_info, confirmation_type); + + confirmations_->RefillTokensIfNecessary(); } void RedeemToken::Redeem( - const ConfirmationInfo& confirmation_info) { - CreateConfirmation(confirmation_info); + const ConfirmationInfo& confirmation) { + BLOG(INFO) << "Redeem"; + + if (!confirmation.created) { + CreateConfirmation(confirmation); + + confirmations_->RefillTokensIfNecessary(); + + return; + } + + FetchPaymentToken(confirmation); } /////////////////////////////////////////////////////////////////////////////// void RedeemToken::CreateConfirmation( - const ConfirmationInfo& confirmation_info) { + const ConfirmationInfo& confirmation) { BLOG(INFO) << "CreateConfirmation"; BLOG(INFO) << "POST /v1/confirmation/{confirmation_id}/{credential}"; @@ -77,16 +95,14 @@ void RedeemToken::CreateConfirmation( BLOG(INFO) << "URL Request:"; - auto url = request.BuildUrl(confirmation_info.id, - confirmation_info.credential); + auto url = request.BuildUrl(confirmation.id, confirmation.credential); BLOG(INFO) << " URL: " << url; auto method = request.GetMethod(); auto confirmation_request_dto = request.CreateConfirmationRequestDTO( - confirmation_info.creative_instance_id, - confirmation_info.blinded_payment_token, - confirmation_info.type); + confirmation.creative_instance_id, confirmation.blinded_payment_token, + confirmation.type); auto body = request.BuildBody(confirmation_request_dto); BLOG(INFO) << " Body: " << body; @@ -101,7 +117,7 @@ void RedeemToken::CreateConfirmation( BLOG(INFO) << " Content_type: " << content_type; auto callback = std::bind(&RedeemToken::OnCreateConfirmation, - this, url, _1, _2, _3, confirmation_info); + this, url, _1, _2, _3, confirmation); confirmations_client_->LoadURL(url, headers, body, content_type, method, callback); @@ -112,35 +128,34 @@ void RedeemToken::CreateConfirmation( const TokenInfo& token_info, const ConfirmationType confirmation_type) { DCHECK(!creative_instance_id.empty()); - DCHECK(unblinded_tokens_->TokenExists(token_info)); - ConfirmationInfo confirmation_info; + ConfirmationInfo confirmation; - confirmation_info.id = base::GenerateGUID(); + confirmation.id = base::GenerateGUID(); - confirmation_info.creative_instance_id = creative_instance_id; + confirmation.creative_instance_id = creative_instance_id; - confirmation_info.type = confirmation_type; + confirmation.type = confirmation_type; - confirmation_info.token_info = token_info; + confirmation.token_info = token_info; auto payment_tokens = helper::Security::GenerateTokens(1); - confirmation_info.payment_token = payment_tokens.front(); + confirmation.payment_token = payment_tokens.front(); auto blinded_payment_tokens = helper::Security::BlindTokens(payment_tokens); auto blinded_payment_token = blinded_payment_tokens.front(); - confirmation_info.blinded_payment_token = blinded_payment_token; + confirmation.blinded_payment_token = blinded_payment_token; CreateConfirmationRequest request; - auto confirmation_request_dto = - request.CreateConfirmationRequestDTO(creative_instance_id, + auto payload = request.CreateConfirmationRequestDTO(creative_instance_id, blinded_payment_token, confirmation_type); - confirmation_info.credential = - request.CreateCredential(token_info, confirmation_request_dto); + confirmation.credential = request.CreateCredential(token_info, payload); - CreateConfirmation(confirmation_info); + confirmation.timestamp_in_seconds = Time::NowInSeconds(); + + CreateConfirmation(confirmation); } void RedeemToken::OnCreateConfirmation( @@ -148,8 +163,8 @@ void RedeemToken::OnCreateConfirmation( const int response_status_code, const std::string& response, const std::map& headers, - const ConfirmationInfo& confirmation_info) { - DCHECK(!confirmation_info.id.empty()); + const ConfirmationInfo& confirmation) { + DCHECK(!confirmation.id.empty()); BLOG(INFO) << "OnCreateConfirmation"; @@ -162,47 +177,47 @@ void RedeemToken::OnCreateConfirmation( BLOG(INFO) << " " << header.first << ": " << header.second; } - if (response_status_code != net::HTTP_CREATED && - response_status_code != net::HTTP_BAD_REQUEST) { + if (response_status_code != net::HTTP_CREATED) { BLOG(ERROR) << "Failed to create confirmation"; - OnRedeem(FAILED, confirmation_info); + OnRedeem(FAILED, confirmation, false); return; } - if (response_status_code != net::HTTP_BAD_REQUEST) { - // Parse JSON response - base::Optional dictionary = base::JSONReader::Read(response); - if (!dictionary || !dictionary->is_dict()) { - BLOG(ERROR) << "Failed to parse response: " << response; - OnRedeem(FAILED, confirmation_info); - return; - } + // Parse JSON response + base::Optional dictionary = base::JSONReader::Read(response); + if (!dictionary || !dictionary->is_dict()) { + BLOG(ERROR) << "Failed to parse response: " << response; + OnRedeem(FAILED, confirmation); + return; + } - // Get id - auto* id_value = dictionary->FindKey("id"); - if (!id_value) { - BLOG(ERROR) << "Response missing id"; - OnRedeem(FAILED, confirmation_info); - return; - } + // Get id + auto* id_value = dictionary->FindKey("id"); + if (!id_value) { + BLOG(ERROR) << "Response missing id"; + OnRedeem(FAILED, confirmation); + return; + } - auto id = id_value->GetString(); + auto id = id_value->GetString(); - // Validate id - if (id != confirmation_info.id) { - BLOG(ERROR) << "Response id: " << id - << " does not match confirmation id: " << confirmation_info.id; - OnRedeem(FAILED, confirmation_info); - return; - } + // Validate id + if (id != confirmation.id) { + BLOG(ERROR) << "Response id: " << id + << " does not match confirmation id: " << confirmation.id; + OnRedeem(FAILED, confirmation); + return; } + ConfirmationInfo created_confirmation(confirmation); + created_confirmation.created = true; + // Fetch payment token - FetchPaymentToken(confirmation_info); + FetchPaymentToken(created_confirmation); } -void RedeemToken::FetchPaymentToken(const ConfirmationInfo& confirmation_info) { - DCHECK(!confirmation_info.id.empty()); +void RedeemToken::FetchPaymentToken(const ConfirmationInfo& confirmation) { + DCHECK(!confirmation.id.empty()); BLOG(INFO) << "FetchPaymentToken"; @@ -211,13 +226,13 @@ void RedeemToken::FetchPaymentToken(const ConfirmationInfo& confirmation_info) { BLOG(INFO) << "URL Request:"; - auto url = request.BuildUrl(confirmation_info.id); + auto url = request.BuildUrl(confirmation.id); BLOG(INFO) << " URL: " << url; auto method = request.GetMethod(); auto callback = std::bind(&RedeemToken::OnFetchPaymentToken, - this, url, _1, _2, _3, confirmation_info); + this, url, _1, _2, _3, confirmation); confirmations_client_->LoadURL(url, {}, "", "", method, callback); } @@ -227,7 +242,7 @@ void RedeemToken::OnFetchPaymentToken( const int response_status_code, const std::string& response, const std::map& headers, - const ConfirmationInfo& confirmation_info) { + const ConfirmationInfo& confirmation) { BLOG(INFO) << "OnFetchPaymentToken"; BLOG(INFO) << "URL Request Response:"; @@ -239,9 +254,20 @@ void RedeemToken::OnFetchPaymentToken( BLOG(INFO) << " " << header.first << ": " << header.second; } + if (response_status_code != HTTP_NOT_FOUND) { + if (!Verify(confirmation)) { + BLOG(ERROR) << "Failed to verify confirmation"; + OnRedeem(FAILED, confirmation, false); + return; + } + + Redeem(confirmation.creative_instance_id, confirmation.type); + return; + } + if (response_status_code != net::HTTP_OK) { BLOG(ERROR) << "Failed to fetch payment token"; - OnRedeem(FAILED, confirmation_info); + OnRedeem(FAILED, confirmation); return; } @@ -249,7 +275,7 @@ void RedeemToken::OnFetchPaymentToken( base::Optional dictionary = base::JSONReader::Read(response); if (!dictionary || !dictionary->is_dict()) { BLOG(ERROR) << "Failed to parse response: " << response; - OnRedeem(FAILED, confirmation_info); + OnRedeem(FAILED, confirmation); return; } @@ -257,7 +283,7 @@ void RedeemToken::OnFetchPaymentToken( auto* id_value = dictionary->FindKey("id"); if (!id_value) { BLOG(ERROR) << "Response missing id"; - OnRedeem(FAILED, confirmation_info); + OnRedeem(FAILED, confirmation); return; } @@ -267,7 +293,7 @@ void RedeemToken::OnFetchPaymentToken( auto* payment_token_value = dictionary->FindKey("paymentToken"); if (!payment_token_value) { BLOG(ERROR) << "Response missing paymentToken"; - OnRedeem(FAILED, confirmation_info); + OnRedeem(FAILED, confirmation); return; } @@ -275,7 +301,7 @@ void RedeemToken::OnFetchPaymentToken( base::DictionaryValue* payment_token_dictionary; if (!payment_token_value->GetAsDictionary(&payment_token_dictionary)) { BLOG(ERROR) << "Response missing paymentToken dictionary"; - OnRedeem(FAILED, confirmation_info); + OnRedeem(FAILED, confirmation); return; } @@ -283,7 +309,7 @@ void RedeemToken::OnFetchPaymentToken( auto* public_key_value = payment_token_dictionary->FindKey("publicKey"); if (!public_key_value) { BLOG(ERROR) << "Response missing publicKey in paymentToken dictionary"; - OnRedeem(FAILED, confirmation_info); + OnRedeem(FAILED, confirmation); return; } auto public_key_base64 = public_key_value->GetString(); @@ -293,7 +319,7 @@ void RedeemToken::OnFetchPaymentToken( if (!confirmations_->IsValidPublicKeyForCatalogIssuers(public_key_base64)) { BLOG(ERROR) << "Response public_key: " << public_key_base64 << " was not found in the catalog issuers"; - OnRedeem(FAILED, confirmation_info); + OnRedeem(FAILED, confirmation); return; } @@ -301,7 +327,7 @@ void RedeemToken::OnFetchPaymentToken( auto* batch_proof_value = payment_token_dictionary->FindKey("batchProof"); if (!batch_proof_value) { BLOG(ERROR) << "Response missing batchProof in paymentToken dictionary"; - OnRedeem(FAILED, confirmation_info); + OnRedeem(FAILED, confirmation); return; } @@ -312,14 +338,14 @@ void RedeemToken::OnFetchPaymentToken( auto* signed_tokens_value = payment_token_dictionary->FindKey("signedTokens"); if (!signed_tokens_value) { BLOG(ERROR) << "Response missing signedTokens in paymentToken dictionary"; - OnRedeem(FAILED, confirmation_info); + OnRedeem(FAILED, confirmation); return; } base::ListValue signed_token_base64_values(signed_tokens_value->GetList()); if (signed_token_base64_values.GetSize() != 1) { BLOG(ERROR) << "Too many signedTokens"; - OnRedeem(FAILED, confirmation_info); + OnRedeem(FAILED, confirmation); return; } @@ -331,8 +357,8 @@ void RedeemToken::OnFetchPaymentToken( } // Verify and unblind payment token - auto payment_tokens = {confirmation_info.payment_token}; - auto blinded_payment_tokens = {confirmation_info.blinded_payment_token}; + auto payment_tokens = {confirmation.payment_token}; + auto blinded_payment_tokens = {confirmation.blinded_payment_token}; auto unblinded_payment_tokens = batch_proof.verify_and_unblind( payment_tokens, blinded_payment_tokens, signed_tokens, public_key); @@ -343,13 +369,13 @@ void RedeemToken::OnFetchPaymentToken( BLOG(ERROR) << " Batch proof: " << batch_proof_base64; BLOG(ERROR) << " Payment tokens (" << payment_tokens.size() << "):"; - auto payment_token_base64 = confirmation_info.payment_token.encode_base64(); + auto payment_token_base64 = confirmation.payment_token.encode_base64(); BLOG(ERROR) << " " << payment_token_base64; BLOG(ERROR) << " Blinded payment tokens (" << blinded_payment_tokens.size() << "):"; auto blinded_payment_token_base64 = - confirmation_info.blinded_payment_token.encode_base64(); + confirmation.blinded_payment_token.encode_base64(); BLOG(ERROR) << " " << blinded_payment_token_base64; BLOG(ERROR) << " Signed tokens (" << signed_tokens.size() << "):"; @@ -360,7 +386,7 @@ void RedeemToken::OnFetchPaymentToken( BLOG(ERROR) << " Public key: " << public_key_base64; - OnRedeem(FAILED, confirmation_info); + OnRedeem(FAILED, confirmation); return; } @@ -371,7 +397,8 @@ void RedeemToken::OnFetchPaymentToken( unblinded_payment_token_info.public_key = public_key_base64; if (unblinded_payment_tokens_->TokenExists(unblinded_payment_token_info)) { - OnRedeem(FAILED, confirmation_info, false); + BLOG(ERROR) << "Duplicate unblinded payment token"; + OnRedeem(FAILED, confirmation, false); return; } @@ -389,66 +416,62 @@ void RedeemToken::OnFetchPaymentToken( << unblinded_payment_tokens_->Count() << " unblinded payment tokens"; confirmations_->AppendTransactionToHistory( - estimated_redemption_value, confirmation_info.type); + estimated_redemption_value, confirmation.type); - OnRedeem(SUCCESS, confirmation_info, false); + OnRedeem(SUCCESS, confirmation, false); } void RedeemToken::OnRedeem( const Result result, - const ConfirmationInfo& confirmation_info, + const ConfirmationInfo& confirmation, const bool should_retry) { - confirmations_->RemoveConfirmationFromQueue(confirmation_info); - - if (result != SUCCESS) { - BLOG(WARNING) << "Failed to redeem token with " - << confirmation_info.creative_instance_id - << " creative instance id for " - << std::string(confirmation_info.type); + BLOG(WARNING) << "Failed to redeem " << confirmation.id + << " confirmation id with " << confirmation.creative_instance_id + << " creative instance id for " << std::string(confirmation.type); if (should_retry) { - BLOG(INFO) << "Retry " << confirmation_info.creative_instance_id - << " creative instance id for " - << std::string(confirmation_info.type); - - BLOG(INFO) << "Added " << confirmation_info.creative_instance_id - << " creative instance id for " - << std::string(confirmation_info.type) - << " to the confirmations queue"; - - confirmations_->AppendConfirmationToQueue(confirmation_info); + confirmations_->AppendConfirmationToQueue(confirmation); } } else { - BLOG(INFO) << "Successfully redeemed token with " - << confirmation_info.creative_instance_id - << " creative instance id for " << std::string(confirmation_info.type); + BLOG(INFO) << "Successfully redeemed " << confirmation.id + << " confirmation id with " << confirmation.creative_instance_id + << " creative instance id for " << std::string(confirmation.type); + } +} + +bool RedeemToken::Verify( + const ConfirmationInfo& confirmation) const { + std::string credential; + base::Base64Decode(confirmation.credential, &credential); + + base::Optional value = base::JSONReader::Read(credential); + if (!value || !value->is_dict()) { + return false; } - if (unblinded_tokens_->RemoveToken(confirmation_info.token_info)) { - BLOG(INFO) << "Removed " << - confirmation_info.token_info.unblinded_token.encode_base64() - << " unblinded token"; + base::DictionaryValue* dictionary = nullptr; + if (!value->GetAsDictionary(&dictionary)) { + return false; } - if (!confirmations_->IsRetryingFailedConfirmations()) { - ScheduleNextRetryForFailedConfirmations(); + auto* signature_value = dictionary->FindKey("signature"); + if (!signature_value) { + return false; } - confirmations_->RefillTokensIfNecessary(); -} + auto signature = signature_value->GetString(); + auto verification_signature = VerificationSignature::decode_base64(signature); -void RedeemToken::ScheduleNextRetryForFailedConfirmations() const { - auto start_timer_in = CalculateTimerForNextRetryForFailedConfirmations(); - confirmations_->StartRetryingFailedConfirmations(start_timer_in); -} + CreateConfirmationRequest request; + auto payload = request.CreateConfirmationRequestDTO( + confirmation.creative_instance_id, confirmation.blinded_payment_token, + confirmation.type); -uint64_t RedeemToken::CalculateTimerForNextRetryForFailedConfirmations() const { - auto start_timer_in = kRetryFailedConfirmationsAfterSeconds; - auto rand_delay = brave_base::random::Geometric(start_timer_in); - start_timer_in = rand_delay; + auto unblinded_token = confirmation.token_info.unblinded_token; + auto verification_key = unblinded_token.derive_verification_key(); - return start_timer_in; + return verification_key.verify(verification_signature, payload); } } // namespace confirmations diff --git a/vendor/bat-native-confirmations/src/bat/confirmations/internal/redeem_token.h b/vendor/bat-native-confirmations/src/bat/confirmations/internal/redeem_token.h index 4daf284b5053..a44f50cc6199 100644 --- a/vendor/bat-native-confirmations/src/bat/confirmations/internal/redeem_token.h +++ b/vendor/bat-native-confirmations/src/bat/confirmations/internal/redeem_token.h @@ -39,11 +39,11 @@ class RedeemToken { const std::string& creative_instance_id, const ConfirmationType confirmation_type); void Redeem( - const ConfirmationInfo& confirmation_info); + const ConfirmationInfo& confirmation); private: void CreateConfirmation( - const ConfirmationInfo& confirmation_info); + const ConfirmationInfo& confirmation); void CreateConfirmation( const std::string& creative_instance_id, const TokenInfo& token_info, @@ -53,24 +53,24 @@ class RedeemToken { const int response_status_code, const std::string& response, const std::map& headers, - const ConfirmationInfo& confirmation_info); + const ConfirmationInfo& confirmation); void FetchPaymentToken( - const ConfirmationInfo& confirmation_info); + const ConfirmationInfo& confirmation); void OnFetchPaymentToken( const std::string& url, const int response_status_code, const std::string& response, const std::map& headers, - const ConfirmationInfo& confirmation_info); + const ConfirmationInfo& confirmation); void OnRedeem( const Result result, - const ConfirmationInfo& confirmation_info, + const ConfirmationInfo& confirmation, const bool should_retry = true); - void ScheduleNextRetryForFailedConfirmations() const; - uint64_t CalculateTimerForNextRetryForFailedConfirmations() const; + bool Verify( + const ConfirmationInfo& confirmation) const; ConfirmationsImpl* confirmations_; // NOT OWNED ConfirmationsClient* confirmations_client_; // NOT OWNED