Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/map
diff options
context:
space:
mode:
authorRoman Kuznetsov <r.kuznetsow@gmail.com>2018-08-23 14:46:20 +0300
committerDaria Volvenkova <d.volvenkova@corp.mail.ru>2018-08-24 11:56:01 +0300
commit6e572cb3ac036a91812eb78fb5f4aadc2932f392 (patch)
treed1d9ce1ebf12d9a98d6b7e411f6ca44fc58a4a69 /map
parent5ebbef25db75c5b264ed6853c21808137f8449b9 (diff)
Added client-server interaction for subscription validation
Diffstat (limited to 'map')
-rw-r--r--map/framework.cpp2
-rw-r--r--map/subscription.cpp165
-rw-r--r--map/subscription.hpp18
3 files changed, 171 insertions, 14 deletions
diff --git a/map/framework.cpp b/map/framework.cpp
index e736dce18c..6aa632eacd 100644
--- a/map/framework.cpp
+++ b/map/framework.cpp
@@ -503,8 +503,6 @@ Framework::Framework(FrameworkParams const & params)
InitTransliteration();
LOG(LDEBUG, ("Transliterators initialized"));
-
- m_subscription->Validate();
}
Framework::~Framework()
diff --git a/map/subscription.cpp b/map/subscription.cpp
index 437f232589..1708415153 100644
--- a/map/subscription.cpp
+++ b/map/subscription.cpp
@@ -1,19 +1,87 @@
#include "map/subscription.hpp"
+#include "platform/http_client.hpp"
#include "platform/platform.hpp"
+#include "coding/serdes_json.hpp"
#include "coding/sha1.hpp"
+#include "coding/writer.hpp"
#include "base/assert.hpp"
+#include "base/logging.hpp"
+#include "base/visitor.hpp"
+
+#include "std/target_os.hpp"
+
+#include <utility>
+
+#define STAGE_PURCHASE_SERVER
+#include "private.h"
namespace
{
std::string const kSubscriptionId = "SubscriptionId";
+std::string const kServerUrl = PURCHASE_SERVER_URL;
+#if defined(OMIM_OS_IPHONE)
+std::string const kProductId = "ad.removal.apple";
+std::string const kReceiptType = "apple";
+#elif defined(OMIM_OS_ANDROID)
+std::string const kProductId = "ad.removal.google";
+std::string const kReceiptType = "google";
+#else
+std::string const kProductId {};
+std::string const kReceiptType {};
+#endif
std::string GetSubscriptionId()
{
return coding::SHA1::CalculateBase64ForString(GetPlatform().UniqueClientId());
}
+
+std::string ValidationUrl()
+{
+ if (kServerUrl.empty())
+ return {};
+ return kServerUrl + "purchases/is_purchased";
+}
+
+struct ReceiptData
+{
+ std::string m_data;
+ std::string m_type;
+
+ ReceiptData(std::string const & data, std::string const & type)
+ : m_data(data)
+ , m_type(type)
+ {}
+
+ DECLARE_VISITOR(visitor(m_data, "data"),
+ visitor(m_type, "type"))
+};
+
+struct ValidationData
+{
+ std::string m_productId;
+ ReceiptData m_receipt;
+
+ ValidationData(std::string const & productId, std::string const & receiptData,
+ std::string const & receiptType)
+ : m_productId(productId)
+ , m_receipt(receiptData, receiptType)
+ {}
+
+ DECLARE_VISITOR(visitor(m_productId, "product_id"),
+ visitor(m_receipt, "receipt"))
+};
+
+struct ValidationResult
+{
+ bool m_isValid = true;
+ std::string m_error;
+
+ DECLARE_VISITOR(visitor(m_isValid, "valid"),
+ visitor(m_error, "error"))
+};
} // namespace
Subscription::Subscription()
@@ -32,29 +100,104 @@ void Subscription::Register(SubscriptionListener * listener)
listener->OnSubscriptionChanged(IsActive());
}
+void Subscription::SetValidationCallback(ValidationCallback && callback)
+{
+ CHECK_THREAD_CHECKER(m_threadChecker, ());
+ m_validationCallback = std::move(callback);
+}
+
bool Subscription::IsActive() const
{
return m_isActive;
}
-void Subscription::Validate()
+void Subscription::Validate(std::string const & receiptData, std::string const & accessToken)
{
CHECK_THREAD_CHECKER(m_threadChecker, ());
- //TODO: check on server.
- bool isValid = false;
+ std::string const url = ValidationUrl();
+ if (url.empty())
+ {
+ ApplyValidation(ValidationCode::NotActive);
+ return;
+ }
- m_isActive = isValid;
- if (isValid)
+ auto const status = GetPlatform().ConnectionStatus();
+ if (status == Platform::EConnectionType::CONNECTION_NONE)
{
- m_subscriptionId = GetSubscriptionId();
- GetPlatform().GetSecureStorage().Save(kSubscriptionId, m_subscriptionId);
+ ApplyValidation(ValidationCode::Failure);
+ return;
}
- else
+
+ GetPlatform().RunTask(Platform::Thread::Network, [this, url, receiptData, accessToken]()
{
- GetPlatform().GetSecureStorage().Remove(kSubscriptionId);
+ platform::HttpClient request(url);
+ request.SetRawHeader("Accept", "application/json");
+ request.SetRawHeader("User-Agent", GetPlatform().GetAppUserAgent());
+ if (!accessToken.empty())
+ request.SetRawHeader("Authorization", "Bearer " + accessToken);
+
+ std::string jsonStr;
+ {
+ using Sink = MemWriter<std::string>;
+ Sink sink(jsonStr);
+ coding::SerializerJson<Sink> serializer(sink);
+ serializer(ValidationData(kProductId, receiptData, kReceiptType));
+ }
+ request.SetBodyData(std::move(jsonStr), "application/json");
+
+ ValidationCode code = ValidationCode::Failure;
+ if (request.RunHttpRequest())
+ {
+ auto const resultCode = request.ErrorCode();
+ if (resultCode >= 200 && resultCode < 300)
+ {
+ ValidationResult result;
+ {
+ coding::DeserializerJson des(request.ServerResponse());
+ des(result);
+ }
+
+ code = result.m_isValid ? ValidationCode::Active : ValidationCode::NotActive;
+ if (!result.m_error.empty())
+ LOG(LWARNING, ("Validation URL:", url, "Subscription error:", result.m_error));
+ }
+ else
+ {
+ LOG(LWARNING, ("Validation URL:", url, "Unexpected server error. Code =", resultCode, request.ServerResponse()));
+ }
+ }
+ else
+ {
+ LOG(LWARNING, ("Validation URL:", url, "Request failed."));
+ }
+
+ GetPlatform().RunTask(Platform::Thread::Gui, [this, code]() { ApplyValidation(code); });
+ });
+}
+
+void Subscription::ApplyValidation(ValidationCode code)
+{
+ CHECK_THREAD_CHECKER(m_threadChecker, ());
+
+ if (code != ValidationCode::Failure)
+ {
+ bool const isActive = (code == ValidationCode::Active);
+ m_isActive = isActive;
+ if (isActive)
+ {
+ m_subscriptionId = GetSubscriptionId();
+ GetPlatform().GetSecureStorage().Save(kSubscriptionId, m_subscriptionId);
+ }
+ else
+ {
+ GetPlatform().GetSecureStorage().Remove(kSubscriptionId);
+ }
+
+ for (auto & listener : m_listeners)
+ listener->OnSubscriptionChanged(isActive);
}
- for (auto & listener : m_listeners)
- listener->OnSubscriptionChanged(isValid);
+ if (m_validationCallback)
+ m_validationCallback(code);
}
diff --git a/map/subscription.hpp b/map/subscription.hpp
index 793135c231..83cc98f1eb 100644
--- a/map/subscription.hpp
+++ b/map/subscription.hpp
@@ -3,6 +3,7 @@
#include "base/thread_checker.hpp"
#include <atomic>
+#include <functional>
#include <string>
#include <vector>
@@ -16,15 +17,30 @@ public:
class Subscription
{
public:
+ enum class ValidationCode
+ {
+ Active, // Subscription is active.
+ NotActive, // Subscription is not active.
+ Failure, // Validation failed, real subscription status is unknown, current one acts.
+ };
+
+ using ValidationCallback = std::function<void(ValidationCode)>;
+
Subscription();
void Register(SubscriptionListener * listener);
+ void SetValidationCallback(ValidationCallback && callback);
+
bool IsActive() const;
- void Validate();
+ void Validate(std::string const & receiptData, std::string const & accessToken);
private:
+ void ApplyValidation(ValidationCode code);
+
std::atomic<bool> m_isActive;
std::string m_subscriptionId;
std::vector<SubscriptionListener *> m_listeners;
+ ValidationCallback m_validationCallback;
+
ThreadChecker m_threadChecker;
};