mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	network, web_service: Add Verification backend and use new lobby API
Added verify_backend to load user_data for members. and removed method to generate UID as this is now done server-side. Added GetUsername function and a "token" param to room_member. Also added a username to ChatEntry, so that the username can be shown (along with nicknames) in the chat dialog.
This commit is contained in:
		
							parent
							
								
									5f0e189238
								
							
						
					
					
						commit
						1a8841f96e
					
				
					 12 changed files with 262 additions and 45 deletions
				
			
		|  | @ -7,8 +7,10 @@ add_library(network STATIC | |||
|     room.h | ||||
|     room_member.cpp | ||||
|     room_member.h | ||||
|     verify_user.cpp | ||||
|     verify_user.h | ||||
| ) | ||||
| 
 | ||||
| create_target_directory_groups(network) | ||||
| 
 | ||||
| target_link_libraries(network PRIVATE common enet) | ||||
| target_link_libraries(network PRIVATE common cpp-jwt enet) | ||||
|  |  | |||
|  | @ -14,6 +14,7 @@ | |||
| #include "enet/enet.h" | ||||
| #include "network/packet.h" | ||||
| #include "network/room.h" | ||||
| #include "network/verify_user.h" | ||||
| 
 | ||||
| namespace Network { | ||||
| 
 | ||||
|  | @ -28,6 +29,9 @@ public: | |||
|     std::atomic<State> state{State::Closed}; ///< Current state of the room.
 | ||||
|     RoomInformation room_information;        ///< Information about this room.
 | ||||
| 
 | ||||
|     std::string verify_UID;              ///< A GUID which may be used for verfication.
 | ||||
|     mutable std::mutex verify_UID_mutex; ///< Mutex for verify_UID
 | ||||
| 
 | ||||
|     std::string password; ///< The password required to connect to this room.
 | ||||
| 
 | ||||
|     struct Member { | ||||
|  | @ -35,7 +39,9 @@ public: | |||
|         std::string console_id_hash; ///< A hash of the console ID of the member.
 | ||||
|         GameInfo game_info;          ///< The current game of the member
 | ||||
|         MacAddress mac_address;      ///< The assigned mac address of the member.
 | ||||
|         ENetPeer* peer;              ///< The remote peer.
 | ||||
|         /// Data of the user, often including authenticated forum username.
 | ||||
|         VerifyUser::UserData user_data; | ||||
|         ENetPeer* peer; ///< The remote peer.
 | ||||
|     }; | ||||
|     using MemberList = std::vector<Member>; | ||||
|     MemberList members;              ///< Information about the members of this room
 | ||||
|  | @ -48,6 +54,9 @@ public: | |||
|     /// Thread that receives and dispatches network packets
 | ||||
|     std::unique_ptr<std::thread> room_thread; | ||||
| 
 | ||||
|     /// Verification backend of the room
 | ||||
|     std::unique_ptr<VerifyUser::Backend> verify_backend; | ||||
| 
 | ||||
|     /// Thread function that will receive and dispatch messages until the room is destroyed.
 | ||||
|     void ServerLoop(); | ||||
|     void StartLoop(); | ||||
|  | @ -165,11 +174,6 @@ public: | |||
|      * to all other clients. | ||||
|      */ | ||||
|     void HandleClientDisconnection(ENetPeer* client); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Creates a random ID in the form 12345678-1234-1234-1234-123456789012 | ||||
|      */ | ||||
|     void CreateUniqueID(); | ||||
| }; | ||||
| 
 | ||||
| // RoomImpl
 | ||||
|  | @ -238,6 +242,9 @@ void Room::RoomImpl::HandleJoinRequest(const ENetEvent* event) { | |||
|     std::string pass; | ||||
|     packet >> pass; | ||||
| 
 | ||||
|     std::string token; | ||||
|     packet >> token; | ||||
| 
 | ||||
|     if (pass != password) { | ||||
|         SendWrongPassword(event->peer); | ||||
|         return; | ||||
|  | @ -276,6 +283,13 @@ void Room::RoomImpl::HandleJoinRequest(const ENetEvent* event) { | |||
|     member.nickname = nickname; | ||||
|     member.peer = event->peer; | ||||
| 
 | ||||
|     std::string uid; | ||||
|     { | ||||
|         std::lock_guard<std::mutex> lock(verify_UID_mutex); | ||||
|         uid = verify_UID; | ||||
|     } | ||||
|     member.user_data = verify_backend->LoadUserData(uid, token); | ||||
| 
 | ||||
|     { | ||||
|         std::lock_guard<std::mutex> lock(member_mutex); | ||||
|         members.push_back(std::move(member)); | ||||
|  | @ -407,7 +421,6 @@ void Room::RoomImpl::BroadcastRoomInformation() { | |||
|     packet << room_information.name; | ||||
|     packet << room_information.description; | ||||
|     packet << room_information.member_slots; | ||||
|     packet << room_information.uid; | ||||
|     packet << room_information.port; | ||||
|     packet << room_information.preferred_game; | ||||
| 
 | ||||
|  | @ -419,6 +432,9 @@ void Room::RoomImpl::BroadcastRoomInformation() { | |||
|             packet << member.mac_address; | ||||
|             packet << member.game_info.name; | ||||
|             packet << member.game_info.id; | ||||
|             packet << member.user_data.username; | ||||
|             packet << member.user_data.display_name; | ||||
|             packet << member.user_data.avatar_url; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -511,6 +527,7 @@ void Room::RoomImpl::HandleChatPacket(const ENetEvent* event) { | |||
|     Packet out_packet; | ||||
|     out_packet << static_cast<u8>(IdChatMessage); | ||||
|     out_packet << sending_member->nickname; | ||||
|     out_packet << sending_member->user_data.username; | ||||
|     out_packet << message; | ||||
| 
 | ||||
|     ENetPacket* enet_packet = enet_packet_create(out_packet.GetData(), out_packet.GetDataSize(), | ||||
|  | @ -567,20 +584,6 @@ void Room::RoomImpl::HandleClientDisconnection(ENetPeer* client) { | |||
|     BroadcastRoomInformation(); | ||||
| } | ||||
| 
 | ||||
| void Room::RoomImpl::CreateUniqueID() { | ||||
|     std::uniform_int_distribution<> dis(0, 9999); | ||||
|     std::ostringstream stream; | ||||
|     stream << std::setfill('0') << std::setw(4) << dis(random_gen); | ||||
|     stream << std::setfill('0') << std::setw(4) << dis(random_gen) << "-"; | ||||
|     stream << std::setfill('0') << std::setw(4) << dis(random_gen) << "-"; | ||||
|     stream << std::setfill('0') << std::setw(4) << dis(random_gen) << "-"; | ||||
|     stream << std::setfill('0') << std::setw(4) << dis(random_gen) << "-"; | ||||
|     stream << std::setfill('0') << std::setw(4) << dis(random_gen); | ||||
|     stream << std::setfill('0') << std::setw(4) << dis(random_gen); | ||||
|     stream << std::setfill('0') << std::setw(4) << dis(random_gen); | ||||
|     room_information.uid = stream.str(); | ||||
| } | ||||
| 
 | ||||
| // Room
 | ||||
| Room::Room() : room_impl{std::make_unique<RoomImpl>()} {} | ||||
| 
 | ||||
|  | @ -589,7 +592,7 @@ Room::~Room() = default; | |||
| bool Room::Create(const std::string& name, const std::string& description, | ||||
|                   const std::string& server_address, u16 server_port, const std::string& password, | ||||
|                   const u32 max_connections, const std::string& preferred_game, | ||||
|                   u64 preferred_game_id) { | ||||
|                   u64 preferred_game_id, std::unique_ptr<VerifyUser::Backend> verify_backend) { | ||||
|     ENetAddress address; | ||||
|     address.host = ENET_HOST_ANY; | ||||
|     if (!server_address.empty()) { | ||||
|  | @ -597,8 +600,8 @@ bool Room::Create(const std::string& name, const std::string& description, | |||
|     } | ||||
|     address.port = server_port; | ||||
| 
 | ||||
|     // In order to send the room is full message to the connecting client, we need to leave one slot
 | ||||
|     // open so enet won't reject the incoming connection without telling us
 | ||||
|     // In order to send the room is full message to the connecting client, we need to leave one
 | ||||
|     // slot open so enet won't reject the incoming connection without telling us
 | ||||
|     room_impl->server = enet_host_create(&address, max_connections + 1, NumChannels, 0, 0); | ||||
|     if (!room_impl->server) { | ||||
|         return false; | ||||
|  | @ -612,7 +615,7 @@ bool Room::Create(const std::string& name, const std::string& description, | |||
|     room_impl->room_information.preferred_game = preferred_game; | ||||
|     room_impl->room_information.preferred_game_id = preferred_game_id; | ||||
|     room_impl->password = password; | ||||
|     room_impl->CreateUniqueID(); | ||||
|     room_impl->verify_backend = std::move(verify_backend); | ||||
| 
 | ||||
|     room_impl->StartLoop(); | ||||
|     return true; | ||||
|  | @ -626,12 +629,20 @@ const RoomInformation& Room::GetRoomInformation() const { | |||
|     return room_impl->room_information; | ||||
| } | ||||
| 
 | ||||
| std::string Room::GetVerifyUID() const { | ||||
|     std::lock_guard<std::mutex> lock(room_impl->verify_UID_mutex); | ||||
|     return room_impl->verify_UID; | ||||
| } | ||||
| 
 | ||||
| std::vector<Room::Member> Room::GetRoomMemberList() const { | ||||
|     std::vector<Room::Member> member_list; | ||||
|     std::lock_guard<std::mutex> lock(room_impl->member_mutex); | ||||
|     for (const auto& member_impl : room_impl->members) { | ||||
|         Member member; | ||||
|         member.nickname = member_impl.nickname; | ||||
|         member.username = member_impl.user_data.username; | ||||
|         member.display_name = member_impl.user_data.display_name; | ||||
|         member.avatar_url = member_impl.user_data.avatar_url; | ||||
|         member.mac_address = member_impl.mac_address; | ||||
|         member.game_info = member_impl.game_info; | ||||
|         member_list.push_back(member); | ||||
|  | @ -643,6 +654,11 @@ bool Room::HasPassword() const { | |||
|     return !room_impl->password.empty(); | ||||
| } | ||||
| 
 | ||||
| void Room::SetVerifyUID(const std::string& uid) { | ||||
|     std::lock_guard<std::mutex> lock(room_impl->verify_UID_mutex); | ||||
|     room_impl->verify_UID = uid; | ||||
| } | ||||
| 
 | ||||
| void Room::Destroy() { | ||||
|     room_impl->state = State::Closed; | ||||
|     room_impl->room_thread->join(); | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ | |||
| #include <string> | ||||
| #include <vector> | ||||
| #include "common/common_types.h" | ||||
| #include "network/verify_user.h" | ||||
| 
 | ||||
| namespace Network { | ||||
| 
 | ||||
|  | @ -27,7 +28,6 @@ struct RoomInformation { | |||
|     std::string name;           ///< Name of the server
 | ||||
|     std::string description;    ///< Server description
 | ||||
|     u32 member_slots;           ///< Maximum number of members in this room
 | ||||
|     std::string uid;            ///< The unique ID of the room
 | ||||
|     u16 port;                   ///< The port of this room
 | ||||
|     std::string preferred_game; ///< Game to advertise that you want to play
 | ||||
|     u64 preferred_game_id;      ///< Title ID for the advertised game
 | ||||
|  | @ -72,9 +72,12 @@ public: | |||
|     }; | ||||
| 
 | ||||
|     struct Member { | ||||
|         std::string nickname;   ///< The nickname of the member.
 | ||||
|         GameInfo game_info;     ///< The current game of the member
 | ||||
|         MacAddress mac_address; ///< The assigned mac address of the member.
 | ||||
|         std::string nickname;     ///< The nickname of the member.
 | ||||
|         std::string username;     ///< The web services username of the member. Can be empty.
 | ||||
|         std::string display_name; ///< The web services display name of the member. Can be empty.
 | ||||
|         std::string avatar_url;   ///< Url to the member's avatar. Can be empty.
 | ||||
|         GameInfo game_info;       ///< The current game of the member
 | ||||
|         MacAddress mac_address;   ///< The assigned mac address of the member.
 | ||||
|     }; | ||||
| 
 | ||||
|     Room(); | ||||
|  | @ -90,6 +93,11 @@ public: | |||
|      */ | ||||
|     const RoomInformation& GetRoomInformation() const; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Gets the verify UID of this room. | ||||
|      */ | ||||
|     std::string GetVerifyUID() const; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Gets a list of the mbmers connected to the room. | ||||
|      */ | ||||
|  | @ -108,7 +116,13 @@ public: | |||
|                 const std::string& server = "", u16 server_port = DefaultRoomPort, | ||||
|                 const std::string& password = "", | ||||
|                 const u32 max_connections = MaxConcurrentConnections, | ||||
|                 const std::string& preferred_game = "", u64 preferred_game_id = 0); | ||||
|                 const std::string& preferred_game = "", u64 preferred_game_id = 0, | ||||
|                 std::unique_ptr<VerifyUser::Backend> verify_backend = nullptr); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Sets the verification GUID of the room. | ||||
|      */ | ||||
|     void SetVerifyUID(const std::string& uid); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Destroys the socket | ||||
|  |  | |||
|  | @ -33,7 +33,11 @@ public: | |||
|     void SetState(const State new_state); | ||||
|     bool IsConnected() const; | ||||
| 
 | ||||
|     std::string nickname;   ///< The nickname of this member.
 | ||||
|     std::string nickname; ///< The nickname of this member.
 | ||||
| 
 | ||||
|     std::string username;              ///< The username of this member.
 | ||||
|     mutable std::mutex username_mutex; ///< Mutex for locking username.
 | ||||
| 
 | ||||
|     MacAddress mac_address; ///< The mac_address of this member.
 | ||||
| 
 | ||||
|     std::mutex network_mutex; ///< Mutex that controls access to the `client` variable.
 | ||||
|  | @ -80,7 +84,7 @@ public: | |||
|      */ | ||||
|     void SendJoinRequest(const std::string& nickname, const std::string& console_id_hash, | ||||
|                          const MacAddress& preferred_mac = NoPreferredMac, | ||||
|                          const std::string& password = ""); | ||||
|                          const std::string& password = "", const std::string& token = ""); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Extracts a MAC Address from a received ENet packet. | ||||
|  | @ -210,7 +214,8 @@ void RoomMember::RoomMemberImpl::Send(Packet&& packet) { | |||
| void RoomMember::RoomMemberImpl::SendJoinRequest(const std::string& nickname, | ||||
|                                                  const std::string& console_id_hash, | ||||
|                                                  const MacAddress& preferred_mac, | ||||
|                                                  const std::string& password) { | ||||
|                                                  const std::string& password, | ||||
|                                                  const std::string& token) { | ||||
|     Packet packet; | ||||
|     packet << static_cast<u8>(IdJoinRequest); | ||||
|     packet << nickname; | ||||
|  | @ -218,6 +223,7 @@ void RoomMember::RoomMemberImpl::SendJoinRequest(const std::string& nickname, | |||
|     packet << preferred_mac; | ||||
|     packet << network_version; | ||||
|     packet << password; | ||||
|     packet << token; | ||||
|     Send(std::move(packet)); | ||||
| } | ||||
| 
 | ||||
|  | @ -232,7 +238,6 @@ void RoomMember::RoomMemberImpl::HandleRoomInformationPacket(const ENetEvent* ev | |||
|     packet >> info.name; | ||||
|     packet >> info.description; | ||||
|     packet >> info.member_slots; | ||||
|     packet >> info.uid; | ||||
|     packet >> info.port; | ||||
|     packet >> info.preferred_game; | ||||
|     room_information.name = info.name; | ||||
|  | @ -250,6 +255,16 @@ void RoomMember::RoomMemberImpl::HandleRoomInformationPacket(const ENetEvent* ev | |||
|         packet >> member.mac_address; | ||||
|         packet >> member.game_info.name; | ||||
|         packet >> member.game_info.id; | ||||
|         packet >> member.username; | ||||
|         packet >> member.display_name; | ||||
|         packet >> member.avatar_url; | ||||
| 
 | ||||
|         { | ||||
|             std::lock_guard<std::mutex> lock(username_mutex); | ||||
|             if (member.nickname == nickname) { | ||||
|                 username = member.username; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     Invoke(room_information); | ||||
| } | ||||
|  | @ -297,6 +312,7 @@ void RoomMember::RoomMemberImpl::HandleChatPacket(const ENetEvent* event) { | |||
| 
 | ||||
|     ChatEntry chat_entry{}; | ||||
|     packet >> chat_entry.nickname; | ||||
|     packet >> chat_entry.username; | ||||
|     packet >> chat_entry.message; | ||||
|     Invoke<ChatEntry>(chat_entry); | ||||
| } | ||||
|  | @ -391,6 +407,11 @@ const std::string& RoomMember::GetNickname() const { | |||
|     return room_member_impl->nickname; | ||||
| } | ||||
| 
 | ||||
| const std::string& RoomMember::GetUsername() const { | ||||
|     std::lock_guard<std::mutex> lock(room_member_impl->username_mutex); | ||||
|     return room_member_impl->username; | ||||
| } | ||||
| 
 | ||||
| const MacAddress& RoomMember::GetMacAddress() const { | ||||
|     ASSERT_MSG(IsConnected(), "Tried to get MAC address while not connected"); | ||||
|     return room_member_impl->mac_address; | ||||
|  | @ -402,7 +423,8 @@ RoomInformation RoomMember::GetRoomInformation() const { | |||
| 
 | ||||
| void RoomMember::Join(const std::string& nick, const std::string& console_id_hash, | ||||
|                       const char* server_addr, u16 server_port, u16 client_port, | ||||
|                       const MacAddress& preferred_mac, const std::string& password) { | ||||
|                       const MacAddress& preferred_mac, const std::string& password, | ||||
|                       const std::string& token) { | ||||
|     // If the member is connected, kill the connection first
 | ||||
|     if (room_member_impl->loop_thread && room_member_impl->loop_thread->joinable()) { | ||||
|         Leave(); | ||||
|  | @ -435,7 +457,7 @@ void RoomMember::Join(const std::string& nick, const std::string& console_id_has | |||
|     if (net > 0 && event.type == ENET_EVENT_TYPE_CONNECT) { | ||||
|         room_member_impl->nickname = nick; | ||||
|         room_member_impl->StartLoop(); | ||||
|         room_member_impl->SendJoinRequest(nick, console_id_hash, preferred_mac, password); | ||||
|         room_member_impl->SendJoinRequest(nick, console_id_hash, preferred_mac, password, token); | ||||
|         SendGameInfo(room_member_impl->current_game_info); | ||||
|     } else { | ||||
|         enet_peer_disconnect(room_member_impl->server, 0); | ||||
|  |  | |||
|  | @ -35,7 +35,9 @@ struct WifiPacket { | |||
| /// Represents a chat message.
 | ||||
| struct ChatEntry { | ||||
|     std::string nickname; ///< Nickname of the client who sent this message.
 | ||||
|     std::string message;  ///< Body of the message.
 | ||||
|     /// Web services username of the client who sent this message, can be empty.
 | ||||
|     std::string username; | ||||
|     std::string message; ///< Body of the message.
 | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  | @ -64,7 +66,10 @@ public: | |||
|     }; | ||||
| 
 | ||||
|     struct MemberInformation { | ||||
|         std::string nickname;   ///< Nickname of the member.
 | ||||
|         std::string nickname;     ///< Nickname of the member.
 | ||||
|         std::string username;     ///< The web services username of the member. Can be empty.
 | ||||
|         std::string display_name; ///< The web services display name of the member. Can be empty.
 | ||||
|         std::string avatar_url;   ///< Url to the member's avatar. Can be empty.
 | ||||
|         GameInfo game_info;     ///< Name of the game they're currently playing, or empty if they're
 | ||||
|                                 /// not playing anything.
 | ||||
|         MacAddress mac_address; ///< MAC address associated with this member.
 | ||||
|  | @ -100,6 +105,11 @@ public: | |||
|      */ | ||||
|     const std::string& GetNickname() const; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Returns the username of the RoomMember. | ||||
|      */ | ||||
|     const std::string& GetUsername() const; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Returns the MAC address of the RoomMember. | ||||
|      */ | ||||
|  | @ -123,7 +133,7 @@ public: | |||
|     void Join(const std::string& nickname, const std::string& console_id_hash, | ||||
|               const char* server_addr = "127.0.0.1", const u16 server_port = DefaultRoomPort, | ||||
|               const u16 client_port = 0, const MacAddress& preferred_mac = NoPreferredMac, | ||||
|               const std::string& password = ""); | ||||
|               const std::string& password = "", const std::string& token = ""); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Sends a WiFi packet to the room. | ||||
|  |  | |||
							
								
								
									
										18
									
								
								src/network/verify_user.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/network/verify_user.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | |||
| // Copyright 2018 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include "network/verify_user.h" | ||||
| 
 | ||||
| namespace Network::VerifyUser { | ||||
| 
 | ||||
| Backend::~Backend() = default; | ||||
| 
 | ||||
| NullBackend::~NullBackend() = default; | ||||
| 
 | ||||
| UserData NullBackend::LoadUserData([[maybe_unused]] const std::string& verify_UID, | ||||
|                                    [[maybe_unused]] const std::string& token) { | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| } // namespace Network::VerifyUser
 | ||||
							
								
								
									
										45
									
								
								src/network/verify_user.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/network/verify_user.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,45 @@ | |||
| // Copyright 2018 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <string> | ||||
| #include "common/logging/log.h" | ||||
| 
 | ||||
| namespace Network::VerifyUser { | ||||
| 
 | ||||
| struct UserData { | ||||
|     std::string username; | ||||
|     std::string display_name; | ||||
|     std::string avatar_url; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * A backend used for verifying users and loading user data. | ||||
|  */ | ||||
| class Backend { | ||||
| public: | ||||
|     virtual ~Backend(); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Verifies the given token and loads the information into a UserData struct. | ||||
|      * @param verify_UID A GUID that may be used for verification. | ||||
|      * @param token A token that contains user data and verification data. The format and content is | ||||
|      * decided by backends. | ||||
|      */ | ||||
|     virtual UserData LoadUserData(const std::string& verify_UID, const std::string& token) = 0; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * A null backend where the token is ignored. | ||||
|  * No verification is performed here and the function returns an empty UserData. | ||||
|  */ | ||||
| class NullBackend final : public Backend { | ||||
| public: | ||||
|     ~NullBackend(); | ||||
| 
 | ||||
|     UserData LoadUserData(const std::string& verify_UID, const std::string& token) override; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Network::VerifyUser
 | ||||
|  | @ -5,6 +5,8 @@ add_library(web_service STATIC | |||
|     telemetry_json.h | ||||
|     verify_login.cpp | ||||
|     verify_login.h | ||||
|     verify_user_jwt.cpp | ||||
|     verify_user_jwt.h | ||||
|     web_backend.cpp | ||||
|     web_backend.h | ||||
| ) | ||||
|  | @ -15,4 +17,4 @@ get_directory_property(OPENSSL_LIBS | |||
|         DIRECTORY ${PROJECT_SOURCE_DIR}/externals/libressl | ||||
|         DEFINITION OPENSSL_LIBS) | ||||
| target_compile_definitions(web_service PRIVATE -DCPPHTTPLIB_OPENSSL_SUPPORT) | ||||
| target_link_libraries(web_service PRIVATE common json-headers ${OPENSSL_LIBS} httplib lurlparser) | ||||
| target_link_libraries(web_service PRIVATE common network json-headers ${OPENSSL_LIBS} httplib lurlparser cpp-jwt) | ||||
|  |  | |||
							
								
								
									
										56
									
								
								src/web_service/verify_user_jwt.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								src/web_service/verify_user_jwt.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,56 @@ | |||
| // Copyright 2018 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <system_error> | ||||
| #include <jwt/jwt.hpp> | ||||
| #include "common/logging/log.h" | ||||
| #include "common/web_result.h" | ||||
| #include "web_service/verify_user_jwt.h" | ||||
| #include "web_service/web_backend.h" | ||||
| 
 | ||||
| namespace WebService { | ||||
| 
 | ||||
| static std::string public_key; | ||||
| std::string GetPublicKey(const std::string& host) { | ||||
|     if (public_key.empty()) { | ||||
|         Client client(host, "", ""); // no need for credentials here
 | ||||
|         public_key = client.GetJson("/jwt/external/key.pem", true).returned_data; | ||||
|         if (public_key.empty()) { | ||||
|             LOG_ERROR(WebService, "Could not fetch external JWT public key, verification may fail"); | ||||
|         } else { | ||||
|             LOG_INFO(WebService, "Fetched external JWT public key (size={})", public_key.size()); | ||||
|         } | ||||
|     } | ||||
|     return public_key; | ||||
| } | ||||
| 
 | ||||
| VerifyUserJWT::VerifyUserJWT(const std::string& host) : pub_key(GetPublicKey(host)) {} | ||||
| 
 | ||||
| Network::VerifyUser::UserData VerifyUserJWT::LoadUserData(const std::string& verify_UID, | ||||
|                                                           const std::string& token) { | ||||
|     const std::string audience = fmt::format("external-{}", verify_UID); | ||||
|     using namespace jwt::params; | ||||
|     std::error_code error; | ||||
|     auto decoded = | ||||
|         jwt::decode(token, algorithms({"rs256"}), error, secret(pub_key), issuer("citra-core"), | ||||
|                     aud(audience), validate_iat(true), validate_jti(true)); | ||||
|     if (error) { | ||||
|         LOG_INFO(WebService, "Verification failed: category={}, code={}, message={}", | ||||
|                  error.category().name(), error.value(), error.message()); | ||||
|         return {}; | ||||
|     } | ||||
|     Network::VerifyUser::UserData user_data{}; | ||||
|     if (decoded.payload().has_claim("username")) { | ||||
|         user_data.username = decoded.payload().get_claim_value<std::string>("username"); | ||||
|     } | ||||
|     if (decoded.payload().has_claim("displayName")) { | ||||
|         user_data.display_name = decoded.payload().get_claim_value<std::string>("displayName"); | ||||
|     } | ||||
|     if (decoded.payload().has_claim("avatarUrl")) { | ||||
|         user_data.avatar_url = decoded.payload().get_claim_value<std::string>("avatarUrl"); | ||||
|     } | ||||
|     return user_data; | ||||
| } | ||||
| 
 | ||||
| } // namespace WebService
 | ||||
							
								
								
									
										25
									
								
								src/web_service/verify_user_jwt.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/web_service/verify_user_jwt.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,25 @@ | |||
| // Copyright 2018 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <fmt/format.h> | ||||
| #include "network/verify_user.h" | ||||
| #include "web_service/web_backend.h" | ||||
| 
 | ||||
| namespace WebService { | ||||
| 
 | ||||
| class VerifyUserJWT final : public Network::VerifyUser::Backend { | ||||
| public: | ||||
|     VerifyUserJWT(const std::string& host); | ||||
|     ~VerifyUserJWT() = default; | ||||
| 
 | ||||
|     Network::VerifyUser::UserData LoadUserData(const std::string& verify_UID, | ||||
|                                                const std::string& token) override; | ||||
| 
 | ||||
| private: | ||||
|     std::string pub_key; | ||||
| }; | ||||
| 
 | ||||
| } // namespace WebService
 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue