Skip to content

Commit

Permalink
Merge pull request #64 from go-bazzinga/user-metadata-endpoint
Browse files Browse the repository at this point in the history
added user metadata rest endpoints
  • Loading branch information
rosarp-gobazzinga authored Feb 16, 2024
2 parents 4290ab2 + aadc67b commit 1caa105
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 16 deletions.
34 changes: 29 additions & 5 deletions src/auth/generate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use k256::SecretKey;
use rand::distributions::Alphanumeric;
use rand::Rng;
use sec1::LineEnding::CRLF;
use tracing::log::warn;

pub fn key_pair() -> Result<KeyPair, String> {
let mnemonic = Mnemonic::new(MnemonicType::for_key_size(256).unwrap(), Language::English);
Expand Down Expand Up @@ -48,11 +49,34 @@ fn get_random_string() -> String {
.collect()
}

pub fn to_hex_string(bytes: Vec<u8>) -> String {
bytes.iter().fold(String::new(), |mut acc, &byte| {
acc.push_str(&format!("{:02x}", byte));
acc
})
pub fn to_hex_string(number: u64) -> String {
number
.to_be_bytes()
.iter()
.fold(String::new(), |mut acc, &byte| {
acc.push_str(&format!("{:02x}", byte));
acc
})
}

pub fn from_hex_string(hex_string: &str) -> Result<u64, String> {
let mut iter = hex_string.chars();
let mut byte_arr = Vec::with_capacity(hex_string.len());

while let Some(c1) = iter.next() {
let word8 = iter
.next()
.map(|c2| u8::from_str_radix(&format!("{}{}", c1, c2), 16).unwrap())
.unwrap();
byte_arr.push(word8);
}
match byte_arr.as_slice().try_into() {
Ok(b) => Ok(u64::from_be_bytes(b)),
Err(error) => {
warn!("{}", error);
Err("Could not convert to u64".to_owned())
}
}
}

#[derive(Default, Clone)]
Expand Down
9 changes: 1 addition & 8 deletions src/auth/identity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ pub async fn get_session_response(
let expiration = Utc::now() + Duration::days(30);
let expiration = expiration.timestamp_nanos_opt().unwrap().unsigned_abs();

// delegation
let delegation = Delegation {
pubkey: client_temp_identity.public_key().unwrap(),
expiration,
Expand Down Expand Up @@ -123,13 +122,7 @@ pub async fn get_session_response(
_delegation: agent_js::DelegationChain {
delegations: vec![agent_js::SignedDelegation {
delegation: agent_js::Delegation {
expiration: generate::to_hex_string(
signed_delegation
.delegation
.expiration
.to_be_bytes()
.to_vec(),
),
expiration: generate::to_hex_string(signed_delegation.delegation.expiration),
pubkey: signed_delegation.delegation.pubkey,
targets: None,
},
Expand Down
16 changes: 14 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod auth;
mod error_template;
mod fileserve;
mod init;
mod metadata;
mod page;
mod providers;
mod store;
Expand Down Expand Up @@ -54,8 +55,17 @@ mod handlers {
#[cfg(feature = "ssr")]
#[tokio::main]
async fn main() {
use crate::{app::App, auth::identity, fileserve::file_and_error_handler, init};
use axum::{routing::get, Router};
use crate::{
app::App,
auth::identity,
fileserve::file_and_error_handler,
init,
metadata::user::{get_user_canister, update_user_metadata},
};
use axum::{
routing::{get, post},
Router,
};
use axum_extra::extract::cookie::Key;
use handlers::*;
use leptos::*;
Expand Down Expand Up @@ -90,6 +100,8 @@ async fn main() {
"/api/*fn_name",
get(server_fn_handler).post(server_fn_handler),
)
.route("/rest_api/update_user_metadata", post(update_user_metadata))
.route("/rest_api/get_user_canister", post(get_user_canister))
.leptos_routes_with_handler(routes, get(leptos_routes_handler))
.fallback(file_and_error_handler)
.layer(service)
Expand Down
1 change: 1 addition & 0 deletions src/metadata/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod user;
102 changes: 102 additions & 0 deletions src/metadata/user.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
use crate::{
auth::{agent_js, generate::from_hex_string, identity::AppState},
store::cloudflare::{read_metadata, write_kv},
};
use axum::{extract::State, Json};
use ic_agent::{
identity::{DelegatedIdentity, Delegation, Secp256k1Identity, SignedDelegation},
Identity,
};
use k256::SecretKey;
use serde::Deserialize;
use std::collections::HashMap;
use tracing::log::info;

pub async fn update_user_metadata(
State(app_state): State<AppState>,
Json(user_details): Json<UserDetails>,
) -> Result<String, String> {
let delegated_identity: DelegatedIdentity =
user_details.delegation_identity.try_into().unwrap();
let user_principal_id = delegated_identity.sender().unwrap();
let user_pubkey = delegated_identity.public_key().unwrap();
let mut metadata: HashMap<&str, &str> = HashMap::with_capacity(2);
metadata.insert("user_canister_id", &user_details.user_canister_id);
metadata.insert("user_name", &user_details.user_name);

let _ignore = write_kv(
&user_principal_id.to_text(),
"",
metadata,
&app_state.cloudflare_config,
)
.await;

Ok("Successful".to_owned())
}

pub async fn get_user_canister(
State(app_state): State<AppState>,
Json(user_principal_id): Json<String>,
) -> Result<String, String> {
info!("{}", user_principal_id);

match read_metadata(&user_principal_id, &app_state.cloudflare_config).await {
Some(user_metadata) => {
let user_canister_id = match user_metadata.get("user_canister_id") {
Some(c) => c,
None => return Err("User details not found".to_owned()),
};
Ok(user_canister_id.to_owned())
}
None => Err("User not found".to_owned()),
}
}

async fn verify_signature(signature: String) -> bool {
true
}

impl TryFrom<agent_js::DelegationIdentity> for DelegatedIdentity {
type Error = String;

fn try_from(delegation_identity: agent_js::DelegationIdentity) -> Result<Self, Self::Error> {
info!("DelegationIdentity into");
let js_signed_delegation = delegation_identity._delegation.delegations;
if js_signed_delegation.len() == 0 {
return Err("No signed delegations found".to_owned());
}
let js_signed_delegation = js_signed_delegation.get(0).unwrap();
let js_delegation = js_signed_delegation.delegation.to_owned();
let exp1 = match from_hex_string(&js_delegation.expiration) {
Ok(val) => val,
Err(error) => return Err(error),
};

let delegation = Delegation {
pubkey: js_delegation.pubkey,
expiration: exp1,
targets: None,
};
let signed_delegation = SignedDelegation {
delegation,
signature: js_signed_delegation.signature.to_owned(),
};

let secret_key = SecretKey::from_slice(delegation_identity._inner[1].as_slice()).unwrap();
let client_temp_identity = Secp256k1Identity::from_private_key(secret_key);
let delegated_identity = DelegatedIdentity::new(
delegation_identity._delegation.public_key,
Box::new(client_temp_identity),
vec![signed_delegation],
);
Ok(delegated_identity)
}
}

#[derive(Deserialize, Debug)]
pub struct UserDetails {
delegation_identity: agent_js::DelegationIdentity,
user_canister_id: String,
user_name: String,
}
2 changes: 1 addition & 1 deletion src/store/cloudflare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ pub async fn read_metadata(
}
},
Err(error) => {
error!("Error read_metadata: {}", error);
warn!("Error read_metadata: {}", error);
None
}
}
Expand Down

0 comments on commit 1caa105

Please sign in to comment.