summaryrefslogtreecommitdiff
path: root/src/web_service/verify_user_jwt.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/web_service/verify_user_jwt.cpp')
-rw-r--r--src/web_service/verify_user_jwt.cpp69
1 files changed, 69 insertions, 0 deletions
diff --git a/src/web_service/verify_user_jwt.cpp b/src/web_service/verify_user_jwt.cpp
new file mode 100644
index 000000000..129eb1968
--- /dev/null
+++ b/src/web_service/verify_user_jwt.cpp
@@ -0,0 +1,69 @@
1// SPDX-FileCopyrightText: Copyright 2018 Citra Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#if defined(__GNUC__) || defined(__clang__)
5#pragma GCC diagnostic push
6#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
7#endif
8#include <jwt/jwt.hpp>
9#if defined(__GNUC__) || defined(__clang__)
10#pragma GCC diagnostic pop
11#endif
12
13#include <system_error>
14#include "common/logging/log.h"
15#include "web_service/verify_user_jwt.h"
16#include "web_service/web_backend.h"
17#include "web_service/web_result.h"
18
19namespace WebService {
20
21static std::string public_key;
22std::string GetPublicKey(const std::string& host) {
23 if (public_key.empty()) {
24 Client client(host, "", ""); // no need for credentials here
25 public_key = client.GetPlain("/jwt/external/key.pem", true).returned_data;
26 if (public_key.empty()) {
27 LOG_ERROR(WebService, "Could not fetch external JWT public key, verification may fail");
28 } else {
29 LOG_INFO(WebService, "Fetched external JWT public key (size={})", public_key.size());
30 }
31 }
32 return public_key;
33}
34
35VerifyUserJWT::VerifyUserJWT(const std::string& host) : pub_key(GetPublicKey(host)) {}
36
37Network::VerifyUser::UserData VerifyUserJWT::LoadUserData(const std::string& verify_uid,
38 const std::string& token) {
39 const std::string audience = fmt::format("external-{}", verify_uid);
40 using namespace jwt::params;
41 std::error_code error;
42
43 // We use the Citra backend so the issuer is citra-core
44 auto decoded =
45 jwt::decode(token, algorithms({"rs256"}), error, secret(pub_key), issuer("citra-core"),
46 aud(audience), validate_iat(true), validate_jti(true));
47 if (error) {
48 LOG_INFO(WebService, "Verification failed: category={}, code={}, message={}",
49 error.category().name(), error.value(), error.message());
50 return {};
51 }
52 Network::VerifyUser::UserData user_data{};
53 if (decoded.payload().has_claim("username")) {
54 user_data.username = decoded.payload().get_claim_value<std::string>("username");
55 }
56 if (decoded.payload().has_claim("displayName")) {
57 user_data.display_name = decoded.payload().get_claim_value<std::string>("displayName");
58 }
59 if (decoded.payload().has_claim("avatarUrl")) {
60 user_data.avatar_url = decoded.payload().get_claim_value<std::string>("avatarUrl");
61 }
62 if (decoded.payload().has_claim("roles")) {
63 auto roles = decoded.payload().get_claim_value<std::vector<std::string>>("roles");
64 user_data.moderator = std::find(roles.begin(), roles.end(), "moderator") != roles.end();
65 }
66 return user_data;
67}
68
69} // namespace WebService