Skip to content

Commit 46cba28

Browse files
authored
Syw UID2-3679 cpp sdk base64 v4 token (#26)
* added new CLion<=>Docker<=>Mac OS dev instructions * able to decrypt Base64 (non url friendly) encoded v4 ad tokens * changed to release version 3.1.0
1 parent 70e0606 commit 46cba28

5 files changed

+82
-13
lines changed

CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
cmake_minimum_required(VERSION 3.12)
22

3-
project("uid2-client" VERSION 3.0.1)
3+
project("uid2-client" VERSION 3.1.0)
44

55
configure_file(VERSION.in VERSION @ONLY)
66

README.md

+9
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,15 @@ sudo ln -s $(brew --prefix llvm@14)/bin/clang-format /usr/local/bin/clang-format
4949
sudo ln -s $(brew --prefix llvm@14)/bin/clang-tidy /usr/local/bin/clang-tidy-14
5050
```
5151

52+
## Build and Test in CLion Using Docker on Mac OS
53+
Run
54+
```
55+
docker build -t clion/ubuntu/cpp-env:1.0 -f tools/Dockerfile.cpp-env-ubuntu .
56+
```
57+
And [setup a Docker Toolchain in CLion](https://www.jetbrains.com/help/clion/clion-toolchains-in-docker.html)
58+
59+
And you would be able to develop and test within CLion easily.
60+
5261
## Build, Test, Install
5362

5463
To build, run unit tests, and install under the default prefix (`/usr/local`):

lib/uid2encryption.cpp

+10-4
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,12 @@ DecryptionResult DecryptToken(const std::string& token, const KeyContainer& keys
4444
return DecryptionResult::MakeError(DecryptionStatus::INVALID_PAYLOAD);
4545
}
4646

47-
const std::string headerStr = token.substr(0, 4);
48-
const bool isBase64UrlEncoding = std::any_of(headerStr.begin(), headerStr.end(), [](char c) { return c == '-' || c == '_'; });
47+
// check the whole ad token string instead of the headerStr to make sure
48+
const bool isBase64UrlEncoding = std::any_of(token.begin(), token.end(), [](char c) { return c == '-' || c == '_'; });
4949
try {
5050
std::vector<std::uint8_t> encryptedId;
5151
std::vector<std::uint8_t> headerBytes;
52+
const std::string headerStr = token.substr(0, 4);
5253

5354
if (isBase64UrlEncoding) {
5455
uid2::UID2Base64UrlCoder::Decode(headerStr, headerBytes);
@@ -69,8 +70,13 @@ DecryptionResult DecryptToken(const std::string& token, const KeyContainer& keys
6970
return DecryptTokenV3(encryptedId, keys, now, identityScope, checkValidity);
7071
}
7172
if (headerBytes[1] == static_cast<std::uint8_t>(AdvertisingTokenVersion::V4)) {
72-
// same as V3 but use Base64URL encoding
73-
uid2::UID2Base64UrlCoder::Decode(token, encryptedId);
73+
if (isBase64UrlEncoding) {
74+
// same as V3 but use Base64URL encoding
75+
uid2::UID2Base64UrlCoder::Decode(token, encryptedId);
76+
} else {
77+
// handling the rare situation where participant changed the encoding from Base64URL to Base64
78+
macaron::Base64::Decode(token, encryptedId);
79+
}
7480
return DecryptTokenV3(encryptedId, keys, now, identityScope, checkValidity);
7581
}
7682
return DecryptionResult::MakeError(DecryptionStatus::INVALID_PAYLOAD);

test/encryption_tests_v4.cpp

+34-8
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include <gtest/gtest.h>
1010

11+
#include <algorithm>
1112
#include <sstream>
1213

1314
using namespace uid2;
@@ -116,15 +117,43 @@ std::string GenerateUid2TokenV4AndValidate(
116117
return advertisingToken;
117118
}
118119

120+
void DecryptAndAssertSuccess(UID2Client& client, const std::string& advertisingTokenString, Timestamp timestamp = Timestamp::Now())
121+
{
122+
const auto res = client.Decrypt(advertisingTokenString, timestamp);
123+
EXPECT_TRUE(res.IsSuccess());
124+
EXPECT_EQ(DecryptionStatus::SUCCESS, res.GetStatus());
125+
EXPECT_EQ(EXAMPLE_UID, res.GetUid());
126+
}
127+
128+
TEST(EncryptionTestsV4, CanDecryptV4TokenEncodedAsBase64)
129+
{
130+
UID2Client client("ep", "ak", CLIENT_SECRET, IdentityScope::UID2);
131+
client.RefreshJson(KeySetToJson({MASTER_KEY, SITE_KEY}));
132+
std::string advertisingToken;
133+
134+
// for testing purposes, the token must have some Base64URL encoding characters
135+
do {
136+
advertisingToken = GenerateUid2TokenV4AndValidate(EXAMPLE_UID, MASTER_KEY, SITE_ID, SITE_KEY, EncryptTokenParams());
137+
} while (!std::any_of(advertisingToken.begin(), advertisingToken.end(), [](char c) { return c == '-' || c == '_'; }));
138+
139+
std::vector<std::uint8_t> adTokenBytes;
140+
uid2::UID2Base64UrlCoder::Decode(advertisingToken, adTokenBytes);
141+
142+
// explicitly encode into Base64 (non-URL friendly) encoding again
143+
const auto base64NonURLAdTokenV4 = macaron::Base64::Encode(adTokenBytes);
144+
const bool isBase64NonUrlEncoding =
145+
std::any_of(base64NonURLAdTokenV4.begin(), base64NonURLAdTokenV4.end(), [](char c) { return c == '=' || c == '+' || c == '/'; });
146+
EXPECT_TRUE(isBase64NonUrlEncoding);
147+
148+
DecryptAndAssertSuccess(client, base64NonURLAdTokenV4);
149+
}
150+
119151
TEST(EncryptionTestsV4, SmokeTest)
120152
{
121153
UID2Client client("ep", "ak", CLIENT_SECRET, IdentityScope::UID2);
122154
client.RefreshJson(KeySetToJson({MASTER_KEY, SITE_KEY}));
123155
const auto advertisingToken = GenerateUid2TokenV4AndValidate(EXAMPLE_UID, MASTER_KEY, SITE_ID, SITE_KEY, EncryptTokenParams());
124-
const auto res = client.Decrypt(advertisingToken, Timestamp::Now());
125-
EXPECT_TRUE(res.IsSuccess());
126-
EXPECT_EQ(DecryptionStatus::SUCCESS, res.GetStatus());
127-
EXPECT_EQ(EXAMPLE_UID, res.GetUid());
156+
DecryptAndAssertSuccess(client, advertisingToken);
128157
}
129158

130159
TEST(EncryptionTestsV4, EmptyKeyContainer)
@@ -188,10 +217,7 @@ TEST(EncryptionTestsV4, TokenExpiryAndCustomNow)
188217
EXPECT_FALSE(res.IsSuccess());
189218
EXPECT_EQ(DecryptionStatus::EXPIRED_TOKEN, res.GetStatus());
190219

191-
res = client.Decrypt(advertisingToken, expiry.AddSeconds(-1));
192-
EXPECT_TRUE(res.IsSuccess());
193-
EXPECT_EQ(DecryptionStatus::SUCCESS, res.GetStatus());
194-
EXPECT_EQ(EXAMPLE_UID, res.GetUid());
220+
DecryptAndAssertSuccess(client, advertisingToken, expiry.AddSeconds(-1));
195221
}
196222

197223
TEST(EncryptDataTestsV4, SiteIdFromToken)

tools/Dockerfile.cpp-env-ubuntu

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Based on https://github.com/JetBrains/clion-remote/blob/master/Dockerfile.cpp-env-ubuntu
2+
# Build and run:
3+
# docker build -t clion/ubuntu/cpp-env:1.0 -f Dockerfile.cpp-env-ubuntu .
4+
5+
FROM ubuntu:22.04
6+
7+
RUN DEBIAN_FRONTEND="noninteractive" apt-get update && apt-get -y install tzdata
8+
9+
RUN apt-get update \
10+
&& apt-get install -y build-essential \
11+
gcc \
12+
g++ \
13+
gdb \
14+
clang \
15+
make \
16+
ninja-build \
17+
cmake \
18+
autoconf \
19+
automake \
20+
libtool \
21+
valgrind \
22+
locales-all \
23+
dos2unix \
24+
rsync \
25+
tar \
26+
libssl-dev \
27+
libgtest-dev \
28+
&& apt-get clean

0 commit comments

Comments
 (0)