Skip to content

Commit 9277431

Browse files
committed
Change ModifyLandingPage to base64-encode
It also uses #! instead of # (to avoid anchor-jump problems). And puts "dev" and "debug" flags in the params when indicated.
1 parent 7929758 commit 9277431

File tree

6 files changed

+48
-21
lines changed

6 files changed

+48
-21
lines changed

base64.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,4 +130,10 @@ std::vector<BYTE> B64Decode(const std::string& b64encoded) {
130130
return ret;
131131
}
132132

133+
std::string TrimPadding(const std::string& s) {
134+
auto trimmed = s;
135+
trimmed.erase(s.find_last_not_of("=") + 1);
136+
return trimmed;
137+
}
138+
133139
} // namespace base64

base64.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ std::string B64Encode(const BYTE* buf, unsigned int bufLen);
3333

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

36+
std::string TrimPadding(const std::string& s);
37+
3638
} // namespace base64
3739

3840
#endif //PSICASHLIB_BASE64_H

base64_test.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,11 @@ TEST(TestBase64, Decode)
8080
v = B64Decode("Zm9vYg");
8181
ASSERT_EQ(v, want);
8282
}
83+
84+
TEST(TestBase64, TrimPadding)
85+
{
86+
ASSERT_EQ(TrimPadding("abc"), "abc");
87+
ASSERT_EQ(TrimPadding("abc="), "abc");
88+
ASSERT_EQ(TrimPadding("abc=="), "abc");
89+
ASSERT_EQ(TrimPadding("abc==="), "abc");
90+
}

psicash.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ PsiCash::~PsiCash() {
8888

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

292+
if (test_) {
293+
psicash_data["dev"] = 1;
294+
psicash_data["debug"] = 1;
295+
}
296+
291297
// Get the metadata (sponsor ID, etc.)
292298
psicash_data["metadata"] = user_data_->GetRequestMetadata();
293299

294300
string json_data;
295301
try {
296-
// The third argument is "ensure ASCII"
297-
json_data = psicash_data.dump(-1, ' ', true);
302+
json_data = psicash_data.dump(-1, ' ', // disable indent
303+
true); // ensure ASCII
298304
}
299305
catch (json::exception& e) {
300306
return MakeCriticalError(
301307
utils::Stringer("json dump failed: ", e.what(), "; id:", e.id).c_str());
302308
}
303309

310+
// Base64-encode the JSON
311+
auto b64 = base64::TrimPadding(base64::B64Encode(json_data));
312+
304313
// Our preference is to put the our data into the URL's fragment/hash/anchor,
305314
// because we'd prefer the data not be sent to the server.
306315
// But if there already is a fragment value then we'll put our data into the query parameters.
307316
// (Because altering the fragment is more likely to have negative consequences
308317
// for the page than adding a query parameter that will be ignored.)
309318

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

319331
return url.ToString();

psicash.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,7 @@ class PsiCash {
368368
RefreshState(const std::vector<std::string>& purchase_classes, bool allow_recursion);
369369

370370
protected:
371+
bool test_;
371372
std::string user_agent_;
372373
std::string server_scheme_;
373374
std::string server_hostname_;

psicash_test.cpp

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -643,7 +643,8 @@ TEST_F(TestPsiCash, RemovePurchases) {
643643

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

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

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

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

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

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

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

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

727727
// With tokens
728728

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

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

759757
//
760758
// Errors
@@ -1221,8 +1219,8 @@ TEST_F(TestPsiCash, NewExpiringPurchase) {
12211219
ASSERT_TRUE(purchase_result->purchase->server_time_expiry);
12221220
ASSERT_TRUE(purchase_result->purchase->local_time_expiry);
12231221
auto local_now = datetime::DateTime::Now();
1224-
ASSERT_NEAR(purchase_result->purchase->server_time_expiry->MillisSinceEpoch(), local_now.MillisSinceEpoch(), 5000);
12251222
ASSERT_NEAR(purchase_result->purchase->local_time_expiry->MillisSinceEpoch(), local_now.MillisSinceEpoch(), 5000);
1223+
ASSERT_NEAR(purchase_result->purchase->server_time_expiry->MillisSinceEpoch(), local_now.MillisSinceEpoch(), 5000) << "Try resyncing your local clock";
12261224
// Check UserData -- purchase should still be valid
12271225
ASSERT_EQ(pc.user_data().GetLastTransactionID(), purchase_result->purchase->id);
12281226
auto purchases = pc.GetPurchases();

0 commit comments

Comments
 (0)