1
0
mirror of https://github.com/pcvolkmer/arsnova-client.git synced 2025-04-19 19:16:51 +00:00

feat: extract user ID from client token

This commit is contained in:
Paul-Christian Volkmer 2023-12-22 04:51:27 +01:00
parent 5d7a4ebfa0
commit a9b0e2f49a
2 changed files with 30 additions and 0 deletions

View File

@ -21,6 +21,7 @@ serde_json = "1.0"
tokio = { version = "1.35", features = ["rt-multi-thread", "macros"], default-features = false } tokio = { version = "1.35", features = ["rt-multi-thread", "macros"], default-features = false }
tokio-tungstenite = { version = "0.21", features = ["connect", "rustls-tls-webpki-roots"], default-features = false } tokio-tungstenite = { version = "0.21", features = ["connect", "rustls-tls-webpki-roots"], default-features = false }
url = "2.5" url = "2.5"
base64 = "0.21"
[profile.release] [profile.release]
opt-level = "s" opt-level = "s"

View File

@ -22,9 +22,12 @@ use std::fmt::{Display, Formatter};
use std::marker::PhantomData; use std::marker::PhantomData;
use std::time::Duration; use std::time::Duration;
use base64::engine::general_purpose::STANDARD_NO_PAD;
use base64::Engine;
use futures_util::{SinkExt, StreamExt}; use futures_util::{SinkExt, StreamExt};
use reqwest::{IntoUrl, StatusCode}; use reqwest::{IntoUrl, StatusCode};
use serde::Deserialize; use serde::Deserialize;
use serde_json::json;
use tokio::join; use tokio::join;
use tokio::sync::mpsc::Sender; use tokio::sync::mpsc::Sender;
use tokio_tungstenite::connect_async; use tokio_tungstenite::connect_async;
@ -41,6 +44,11 @@ struct LoginResponse {
token: String, token: String,
} }
#[derive(Deserialize, Debug)]
struct TokenClaim {
sub: String,
}
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
struct MembershipResponse { struct MembershipResponse {
#[serde(rename = "id")] #[serde(rename = "id")]
@ -252,6 +260,27 @@ impl Client<LoggedOut> {
} }
impl Client<LoggedIn> { impl Client<LoggedIn> {
/// Get user ID extracted from client token
///
/// This method fails if the token cannot be parsed
fn get_user_id(&self) -> Result<String, ClientError> {
let token = self.token.clone().unwrap_or_default();
let mut token_parts = token.split('.');
match token_parts.nth(1) {
None => Err(ParserError("Unparsable token".into())),
Some(part) => match STANDARD_NO_PAD.decode(part) {
Ok(d) => match serde_json::from_str::<TokenClaim>(
&String::from_utf8(d).unwrap_or_default(),
) {
Ok(claim) => Ok(claim.sub),
Err(err) => Err(ParserError(format!("Unparsable token claim: {}", err))),
},
Err(err) => Err(ParserError(format!("Unparsable token: {}", err))),
},
}
}
/// Logout the client and discard existing token if not logged in /// Logout the client and discard existing token if not logged in
/// ///
/// If successful the result will be of type `Client<LoggedOut>` /// If successful the result will be of type `Client<LoggedOut>`