diff --git a/src/session.rs b/src/session.rs index 49e2b2f..98397f7 100644 --- a/src/session.rs +++ b/src/session.rs @@ -1,17 +1,20 @@ +use std::io; use std::{fs, path::PathBuf}; use anyhow::Context; use axum::{extract::State, routing::post, Json, Router}; use serde::{Deserialize, Serialize}; use starknet::core::types::FieldElement; +use thiserror::Error; use tokio::sync::mpsc::{channel, Receiver, Sender}; use tower_http::cors::CorsLayer; use tracing::trace; use url::Url; -use crate::credential::{Credentials, SLOT_DIR}; +use crate::credential::{self, Credentials, SLOT_DIR}; use crate::{browser, server::LocalServer}; +const SESSION_CREATION_PAGE: &str = "https://x.cartridge.gg/slot/session"; const SESSION_FILE_BASE_NAME: &str = "session.json"; #[derive(Debug, Clone, Serialize, Deserialize)] @@ -40,6 +43,21 @@ pub struct SessionCredentials { pub authorization: Vec, } +#[derive(Debug, Error)] +pub enum Error { + #[error(transparent)] + IO(#[from] io::Error), + + #[error(transparent)] + Auth(#[from] credential::Error), + + #[error(transparent)] + Serde(#[from] serde_json::Error), + + #[error(transparent)] + Other(#[from] anyhow::Error), +} + /// Retrieves the session for the given chain id of the currently authenticated user. /// Returns `None` if no session can be found for the chain id. /// @@ -47,7 +65,7 @@ pub struct SessionCredentials { /// /// This function will return an error if there is no authenticated user. /// -pub fn get(chain_id: FieldElement) -> anyhow::Result> { +pub fn get(chain_id: FieldElement) -> Result, Error> { let credentials = Credentials::load()?; let username = credentials.account.expect("id must exist").id; let path = get_file_path(&username, chain_id); @@ -66,7 +84,7 @@ pub fn get(chain_id: FieldElement) -> anyhow::Result> { /// /// This function will return an error if there is no authenticated user. /// -pub fn store(chain_id: FieldElement, session: &SessionDetails) -> anyhow::Result { +pub fn store(chain_id: FieldElement, session: &SessionDetails) -> Result { // TODO: maybe can store the authenticated user in a global variable so that // we don't have to call load again if we already did it before. let credentials = Credentials::load()?; @@ -94,7 +112,7 @@ pub fn store(chain_id: FieldElement, session: &SessionDetails) -> anyhow::Result /// This function will return an error if there is no authenticated user. /// #[tracing::instrument(level = "trace", skip(rpc_url), fields(policies = policies.len()))] -pub async fn create(rpc_url: U, policies: &[Policy]) -> anyhow::Result +pub async fn create(rpc_url: U, policies: &[Policy]) -> Result where U: Into, { @@ -104,7 +122,7 @@ where let rpc_url: Url = rpc_url.into(); let mut rx = open_session_creation_page(&username, rpc_url.as_str(), policies)?; - rx.recv().await.context("Channel dropped.") + Ok(rx.recv().await.context("Channel dropped.")?) } /// Starts the session creation process by opening the browser to the Cartridge keychain to prompt @@ -115,7 +133,7 @@ fn open_session_creation_page( policies: &[Policy], ) -> anyhow::Result> { let params = prepare_query_params(username, rpc_url, policies)?; - let url = format!("https://x.cartridge.gg/slot/session?{params}"); + let url = format!("{SESSION_CREATION_PAGE}?{params}"); let (tx, rx) = channel::(1); let server = callback_server(tx)?; @@ -154,10 +172,9 @@ fn prepare_query_params( /// Create the callback server that will receive the session token from the browser. fn callback_server(tx: Sender) -> anyhow::Result { - let handler = move |State(tx): State>, - Json(session): Json| async move { + let handler = move |tx: State>, session: Json| async move { trace!("Received session token from the browser."); - tx.send(session).await.expect("qed; channel closed"); + tx.0.send(session.0).await.expect("qed; channel closed"); }; let router = Router::new() @@ -178,7 +195,7 @@ fn get_file_path(username: &str, chain_id: FieldElement) -> PathBuf { #[cfg(test)] mod tests { #[test] - fn get_session() {} + fn get_session_when_not_authenticated() {} #[test] fn store_session() {}