Skip to content

Commit

Permalink
Change ModifyLandingPage to base64-encode
Browse files Browse the repository at this point in the history
It also uses #! instead of # (to avoid anchor-jump problems). And puts "dev" and "debug" flags in the params when indicated.
  • Loading branch information
adam-p committed May 14, 2019
1 parent 7929758 commit 9277431
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 21 deletions.
6 changes: 6 additions & 0 deletions base64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,10 @@ std::vector<BYTE> B64Decode(const std::string& b64encoded) {
return ret;
}

std::string TrimPadding(const std::string& s) {
auto trimmed = s;
trimmed.erase(s.find_last_not_of("=") + 1);
return trimmed;
}

} // namespace base64
2 changes: 2 additions & 0 deletions base64.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ std::string B64Encode(const BYTE* buf, unsigned int bufLen);

std::vector<BYTE> B64Decode(const std::string& b64encoded);

std::string TrimPadding(const std::string& s);

} // namespace base64

#endif //PSICASHLIB_BASE64_H
8 changes: 8 additions & 0 deletions base64_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,11 @@ TEST(TestBase64, Decode)
v = B64Decode("Zm9vYg");
ASSERT_EQ(v, want);
}

TEST(TestBase64, TrimPadding)
{
ASSERT_EQ(TrimPadding("abc"), "abc");
ASSERT_EQ(TrimPadding("abc="), "abc");
ASSERT_EQ(TrimPadding("abc=="), "abc");
ASSERT_EQ(TrimPadding("abc==="), "abc");
}
20 changes: 16 additions & 4 deletions psicash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ PsiCash::~PsiCash() {

Error PsiCash::Init(const char* user_agent, const char* file_store_root,
MakeHTTPRequestFn make_http_request_fn, bool test) {
test_ = test;
if (test) {
server_scheme_ = dev::kAPIServerScheme;
server_hostname_ = dev::kAPIServerHostname;
Expand Down Expand Up @@ -288,32 +289,43 @@ Result<string> PsiCash::ModifyLandingPage(const string& url_string) const {
psicash_data["tokens"] = auth_tokens[kEarnerTokenType];
}

if (test_) {
psicash_data["dev"] = 1;
psicash_data["debug"] = 1;
}

// Get the metadata (sponsor ID, etc.)
psicash_data["metadata"] = user_data_->GetRequestMetadata();

string json_data;
try {
// The third argument is "ensure ASCII"
json_data = psicash_data.dump(-1, ' ', true);
json_data = psicash_data.dump(-1, ' ', // disable indent
true); // ensure ASCII
}
catch (json::exception& e) {
return MakeCriticalError(
utils::Stringer("json dump failed: ", e.what(), "; id:", e.id).c_str());
}

// Base64-encode the JSON
auto b64 = base64::TrimPadding(base64::B64Encode(json_data));

// Our preference is to put the our data into the URL's fragment/hash/anchor,
// because we'd prefer the data not be sent to the server.
// But if there already is a fragment value then we'll put our data into the query parameters.
// (Because altering the fragment is more likely to have negative consequences
// for the page than adding a query parameter that will be ignored.)

if (url.fragment_.empty()) {
url.fragment_ = kLandingPageParamKey + "=" + URL::Encode(json_data, true);
// When setting in the fragment, we use "#!psicash=etc". The ! prevents the
// fragment from accidentally functioning as a jump-to anchor on a landing page
// (where we don't control element IDs, etc.).
url.fragment_ = "!" + kLandingPageParamKey + "=" + b64;
} else {
if (!url.query_.empty()) {
url.query_ += "&";
}
url.query_ += kLandingPageParamKey + "=" + URL::Encode(json_data, true);
url.query_ += kLandingPageParamKey + "=" + b64;
}

return url.ToString();
Expand Down
1 change: 1 addition & 0 deletions psicash.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@ class PsiCash {
RefreshState(const std::vector<std::string>& purchase_classes, bool allow_recursion);

protected:
bool test_;
std::string user_agent_;
std::string server_scheme_;
std::string server_hostname_;
Expand Down
32 changes: 15 additions & 17 deletions psicash_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,8 @@ TEST_F(TestPsiCash, RemovePurchases) {

TEST_F(TestPsiCash, ModifyLandingPage) {
PsiCashTester pc;
auto err = pc.Init(user_agent_, GetTempDir().c_str(), nullptr, true);
// Pass false for test so that we don't get "dev" and "debug" in all the params
auto err = pc.Init(user_agent_, GetTempDir().c_str(), nullptr, false);
ASSERT_FALSE(err);

const string key_part = "psicash=";
Expand All @@ -660,7 +661,7 @@ TEST_F(TestPsiCash, ModifyLandingPage) {
ASSERT_EQ(url_out.scheme_host_path_, url_in.scheme_host_path_);
ASSERT_EQ(url_out.query_, url_in.query_);
ASSERT_EQ(url_out.fragment_,
key_part + URL::Encode("{\"metadata\":{},\"tokens\":null,\"v\":1}", true));
"!"s + key_part + base64::TrimPadding(base64::B64Encode("{\"metadata\":{},\"tokens\":null,\"v\":1}")));

url_in = {"https://asdf.sadf.gf", "gfaf=asdf", ""};
res = pc.ModifyLandingPage(url_in.ToString());
Expand All @@ -669,7 +670,7 @@ TEST_F(TestPsiCash, ModifyLandingPage) {
ASSERT_EQ(url_out.scheme_host_path_, url_in.scheme_host_path_);
ASSERT_EQ(url_out.query_, url_in.query_);
ASSERT_EQ(url_out.fragment_,
key_part + URL::Encode("{\"metadata\":{},\"tokens\":null,\"v\":1}", true));
"!"s + key_part + base64::TrimPadding(base64::B64Encode("{\"metadata\":{},\"tokens\":null,\"v\":1}")));

url_in = {"https://asdf.sadf.gf/asdfilj/adf", "gfaf=asdf", ""};
res = pc.ModifyLandingPage(url_in.ToString());
Expand All @@ -678,7 +679,7 @@ TEST_F(TestPsiCash, ModifyLandingPage) {
ASSERT_EQ(url_out.scheme_host_path_, url_in.scheme_host_path_);
ASSERT_EQ(url_out.query_, url_in.query_);
ASSERT_EQ(url_out.fragment_,
key_part + URL::Encode("{\"metadata\":{},\"tokens\":null,\"v\":1}", true));
"!"s + key_part + base64::TrimPadding(base64::B64Encode("{\"metadata\":{},\"tokens\":null,\"v\":1}")));

url_in = {"https://asdf.sadf.gf/asdfilj/adf.html", "gfaf=asdf", ""};
res = pc.ModifyLandingPage(url_in.ToString());
Expand All @@ -687,15 +688,15 @@ TEST_F(TestPsiCash, ModifyLandingPage) {
ASSERT_EQ(url_out.scheme_host_path_, url_in.scheme_host_path_);
ASSERT_EQ(url_out.query_, url_in.query_);
ASSERT_EQ(url_out.fragment_,
key_part + URL::Encode("{\"metadata\":{},\"tokens\":null,\"v\":1}", true));
"!"s + key_part + base64::TrimPadding(base64::B64Encode("{\"metadata\":{},\"tokens\":null,\"v\":1}")));

url_in = {"https://asdf.sadf.gf/asdfilj/adf.html", "", "regffd"};
res = pc.ModifyLandingPage(url_in.ToString());
ASSERT_TRUE(res);
url_out.Parse(*res);
ASSERT_EQ(url_out.scheme_host_path_, url_in.scheme_host_path_);
ASSERT_EQ(url_out.query_,
key_part + URL::Encode("{\"metadata\":{},\"tokens\":null,\"v\":1}", true));
key_part + base64::TrimPadding(base64::B64Encode("{\"metadata\":{},\"tokens\":null,\"v\":1}")));
ASSERT_EQ(url_out.fragment_, url_in.fragment_);

url_in = {"https://asdf.sadf.gf/asdfilj/adf.html", "adfg=asdf&vfjnk=fadjn", "regffd"};
Expand All @@ -705,7 +706,7 @@ TEST_F(TestPsiCash, ModifyLandingPage) {
ASSERT_EQ(url_out.scheme_host_path_, url_in.scheme_host_path_);
ASSERT_EQ(url_out.query_,
url_in.query_ + "&" + key_part +
URL::Encode("{\"metadata\":{},\"tokens\":null,\"v\":1}", true));
base64::TrimPadding(base64::B64Encode("{\"metadata\":{},\"tokens\":null,\"v\":1}")));
ASSERT_EQ(url_out.fragment_, url_in.fragment_);

//
Expand All @@ -720,9 +721,8 @@ TEST_F(TestPsiCash, ModifyLandingPage) {
url_out.Parse(*res);
ASSERT_EQ(url_out.scheme_host_path_, url_in.scheme_host_path_);
ASSERT_EQ(url_out.query_, url_in.query_);
ASSERT_EQ(url_out.fragment_, key_part + URL::Encode("{\"metadata\":{\"k\":\"v\"},\"tokens\":"
"null,\"v\":1}",
true));
ASSERT_EQ(url_out.fragment_,
"!"s + key_part + base64::TrimPadding(base64::B64Encode("{\"metadata\":{\"k\":\"v\"},\"tokens\":null,\"v\":1}")));

// With tokens

Expand All @@ -737,9 +737,8 @@ TEST_F(TestPsiCash, ModifyLandingPage) {
url_out.Parse(*res);
ASSERT_EQ(url_out.scheme_host_path_, url_in.scheme_host_path_);
ASSERT_EQ(url_out.query_, url_in.query_);
ASSERT_EQ(url_out.fragment_, key_part + URL::Encode("{\"metadata\":{\"k\":\"v\"},\"tokens\":"
"\"kEarnerTokenType\",\"v\":1}",
true));
ASSERT_EQ(url_out.fragment_,
"!"s + key_part + base64::TrimPadding(base64::B64Encode("{\"metadata\":{\"k\":\"v\"},\"tokens\":\"kEarnerTokenType\",\"v\":1}")));

// Some tokens, but no earner token (different code path)
auth_tokens = {{kSpenderTokenType, "kSpenderTokenType"},
Expand All @@ -752,9 +751,8 @@ TEST_F(TestPsiCash, ModifyLandingPage) {
url_out.Parse(*res);
ASSERT_EQ(url_out.scheme_host_path_, url_in.scheme_host_path_);
ASSERT_EQ(url_out.query_, url_in.query_);
ASSERT_EQ(url_out.fragment_, key_part + URL::Encode("{\"metadata\":{\"k\":\"v\"},\"tokens\":"
"null,\"v\":1}",
true));
ASSERT_EQ(url_out.fragment_,
"!"s + key_part + base64::TrimPadding(base64::B64Encode("{\"metadata\":{\"k\":\"v\"},\"tokens\":null,\"v\":1}")));

//
// Errors
Expand Down Expand Up @@ -1221,8 +1219,8 @@ TEST_F(TestPsiCash, NewExpiringPurchase) {
ASSERT_TRUE(purchase_result->purchase->server_time_expiry);
ASSERT_TRUE(purchase_result->purchase->local_time_expiry);
auto local_now = datetime::DateTime::Now();
ASSERT_NEAR(purchase_result->purchase->server_time_expiry->MillisSinceEpoch(), local_now.MillisSinceEpoch(), 5000);
ASSERT_NEAR(purchase_result->purchase->local_time_expiry->MillisSinceEpoch(), local_now.MillisSinceEpoch(), 5000);
ASSERT_NEAR(purchase_result->purchase->server_time_expiry->MillisSinceEpoch(), local_now.MillisSinceEpoch(), 5000) << "Try resyncing your local clock";
// Check UserData -- purchase should still be valid
ASSERT_EQ(pc.user_data().GetLastTransactionID(), purchase_result->purchase->id);
auto purchases = pc.GetPurchases();
Expand Down

0 comments on commit 9277431

Please sign in to comment.