From 886ea44baea2f277a850781618a7255f3891269d Mon Sep 17 00:00:00 2001 From: Tony Giorgio Date: Mon, 11 Mar 2024 18:35:19 -0500 Subject: [PATCH] Free and paid signatures --- .env.sample | 1 + Cargo.lock | 113 +++++++++++++++- Cargo.toml | 2 + justfile | 2 +- migrations/2024-02-20-210617_user_info/up.sql | 8 ++ src/db.rs | 6 +- src/lnurlp.rs | 6 +- src/main.rs | 32 ++++- src/models/app_user.rs | 7 +- src/nostr.rs | 8 +- src/register.rs | 128 ++++++++++++++---- src/routes.rs | 23 +--- 12 files changed, 265 insertions(+), 71 deletions(-) diff --git a/.env.sample b/.env.sample index 5da4116..2fe5c28 100644 --- a/.env.sample +++ b/.env.sample @@ -2,4 +2,5 @@ DATABASE_URL=postgres://localhost/hermes FM_DB_PATH=./.fedimint-test-dir NSEC= DOMAIN_URL= +AUTH_PK= #HERMES_PORT=8080 diff --git a/Cargo.lock b/Cargo.lock index d81e261..587ca83 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -182,6 +182,17 @@ dependencies = [ "rustc_version", ] +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -490,6 +501,7 @@ dependencies = [ "async-trait", "axum", "base64 0.13.1", + "bls12_381", "chrono", "diesel", "dotenv", @@ -509,6 +521,7 @@ dependencies = [ "mockall", "mockito", "multimint", + "names", "nostr", "nostr-sdk", "pretty_env_logger", @@ -706,6 +719,45 @@ dependencies = [ "libloading", ] +[[package]] +name = "clap" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +dependencies = [ + "atty", + "bitflags 1.3.2", + "clap_derive", + "clap_lex", + "indexmap 1.9.3", + "once_cell", + "strsim", + "termcolor", + "textwrap", +] + +[[package]] +name = "clap_derive" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + [[package]] name = "colored" version = "2.1.0" @@ -1631,7 +1683,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 2.2.3", "slab", "tokio", "tokio-util", @@ -1658,6 +1710,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "hashbrown" version = "0.14.3" @@ -1694,6 +1752,15 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + [[package]] name = "hermit-abi" version = "0.3.6" @@ -1936,6 +2003,16 @@ dependencies = [ "quote", ] +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + [[package]] name = "indexmap" version = "2.2.3" @@ -1980,7 +2057,7 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.6", "libc", "windows-sys 0.52.0", ] @@ -2472,6 +2549,16 @@ dependencies = [ "tracing", ] +[[package]] +name = "names" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bddcd3bf5144b6392de80e04c347cd7fab2508f6df16a85fc496ecd5cec39bc" +dependencies = [ + "clap", + "rand", +] + [[package]] name = "native-tls" version = "0.2.11" @@ -2627,7 +2714,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.6", "libc", ] @@ -2696,6 +2783,12 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "os_str_bytes" +version = "6.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" + [[package]] name = "overload" version = "0.1.1" @@ -3595,6 +3688,12 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "strum" version = "0.24.1" @@ -3702,6 +3801,12 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" +[[package]] +name = "textwrap" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" + [[package]] name = "thiserror" version = "1.0.57" @@ -3872,7 +3977,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ - "indexmap", + "indexmap 2.2.3", "toml_datetime", "winnow", ] diff --git a/Cargo.toml b/Cargo.toml index a440c03..7331136 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ fedimint-core = "0.2.2" fedimint-client = "0.2.2" fedimint-wallet-client = "0.2.2" fedimint-mint-client = "0.2.2" +bls12_381 = { version = "0.7.1", features = [ "zeroize", "groups" ] } fedimint-ln-client = "0.2.2" futures = "0.3.28" url = "2.5.0" @@ -41,6 +42,7 @@ tokio = { version = "1.12.0", features = ["full"] } tower-http = { version = "0.4.0", features = ["cors"] } lazy-regex = "3.1.0" multimint = { git = "https://github.com/Kodylow/multimint", rev = "00df9d34f0244d0200eee4d285094b22b34cf38b" } +names = "0.14.0" [dev-dependencies] mockall = "0.11.2" diff --git a/justfile b/justfile index 327ef44..34dc932 100644 --- a/justfile +++ b/justfile @@ -5,7 +5,7 @@ test-integration: cargo test --features integration-tests run: - cargo run + RUST_LOG=debug cargo run release: cargo run --release diff --git a/migrations/2024-02-20-210617_user_info/up.sql b/migrations/2024-02-20-210617_user_info/up.sql index 620a0fb..56f3847 100644 --- a/migrations/2024-02-20-210617_user_info/up.sql +++ b/migrations/2024-02-20-210617_user_info/up.sql @@ -7,6 +7,9 @@ CREATE TABLE app_user ( federation_invite_code VARCHAR(255) NOT NULL ); +CREATE INDEX idx_app_user_unblinded_msg ON app_user (unblinded_msg); +CREATE INDEX idx_app_user_name ON app_user (name); + CREATE TABLE invoice ( id SERIAL PRIMARY KEY, federation_id VARCHAR(64) NOT NULL, @@ -17,9 +20,14 @@ CREATE TABLE invoice ( state INTEGER NOT NULL DEFAULT 0 ); +CREATE INDEX idx_invoice_state ON invoice (state); +CREATE INDEX idx_invoice_op_id ON invoice (op_id); + CREATE TABLE zaps ( id INTEGER NOT NULL PRIMARY KEY references invoice (id), request TEXT NOT NULL, event_id VARCHAR(64) ); + +CREATE INDEX idx_zaps_event_id ON zaps (event_id); diff --git a/src/db.rs b/src/db.rs index fe2448d..a244d65 100644 --- a/src/db.rs +++ b/src/db.rs @@ -13,7 +13,7 @@ use crate::models::{ #[cfg_attr(test, automock)] pub(crate) trait DBConnection { fn check_name_available(&self, name: String) -> anyhow::Result; - fn check_token_not_spent(&self, msg: String) -> anyhow::Result; + fn get_user_by_token(&self, msg: String) -> anyhow::Result>; fn insert_new_user(&self, name: NewAppUser) -> anyhow::Result; fn get_pending_invoices(&self) -> anyhow::Result>; fn insert_new_invoice(&self, invoice: NewInvoice) -> anyhow::Result; @@ -36,9 +36,9 @@ impl DBConnection for PostgresConnection { AppUser::check_available_name(conn, name) } - fn check_token_not_spent(&self, msg: String) -> anyhow::Result { + fn get_user_by_token(&self, msg: String) -> anyhow::Result> { let conn = &mut self.db.get()?; - AppUser::check_token_not_spent(conn, msg) + AppUser::get_by_token(conn, msg) } fn insert_new_user(&self, new_user: NewAppUser) -> anyhow::Result { diff --git a/src/lnurlp.rs b/src/lnurlp.rs index 62b6402..08e4669 100644 --- a/src/lnurlp.rs +++ b/src/lnurlp.rs @@ -188,7 +188,8 @@ mod tests_integration { let nostr = nostr_sdk::Client::new(&nostr_sk); // create blind signer - let signer = BlindSigner::derive(&[0u8; 32], 0, 0); + let free_signer = BlindSigner::derive(&[0u8; 32], 0, 0); + let paid_signer = BlindSigner::derive(&[0u8; 32], 0, 0); let mock_mm = Arc::new(mock_mm); let state = State { @@ -196,7 +197,8 @@ mod tests_integration { mm: mock_mm, secp: Secp256k1::new(), nostr, - auth_pk: signer.pk, + free_pk: free_signer.pk, + paid_pk: paid_signer.pk, domain: "http://hello.com".to_string(), }; diff --git a/src/main.rs b/src/main.rs index 3ca86c9..52b0218 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ use axum::http::{request::Parts, HeaderValue, Method, StatusCode, Uri}; use axum::routing::get; use axum::{extract::DefaultBodyLimit, routing::post}; use axum::{http, Extension, Router, TypedHeader}; +use bls12_381::G2Affine; use log::{error, info}; use nostr_sdk::nostr::{key::FromSkStr, Keys}; use secp256k1::{All, Secp256k1}; @@ -58,7 +59,8 @@ pub struct State { pub secp: Secp256k1, pub nostr: nostr_sdk::Client, pub domain: String, - pub auth_pk: AggregatePublicKey, + pub free_pk: AggregatePublicKey, + pub paid_pk: AggregatePublicKey, } #[tokio::main] @@ -82,9 +84,24 @@ async fn main() -> anyhow::Result<()> { .await .expect("should set up mints"); - let auth_pk = std::env::var("AUTH_PK").expect("AUTH_PK must be set"); - // no from_str impl so just decode from serde - let auth_pk: AggregatePublicKey = serde_json::from_str(&auth_pk).expect("Invalid AUTH_PK"); + let free_pk = std::env::var("FREE_PK").expect("FREE_PK must be set"); + let paid_pk = std::env::var("PAID_PK").expect("PAID_PK must be set"); + let free_pk: AggregatePublicKey = AggregatePublicKey( + G2Affine::from_compressed( + hex::decode(&free_pk).expect("Invalid key hex")[..] + .try_into() + .expect("Invalid key byte key"), + ) + .expect("Invalid FREE_PK"), + ); + let paid_pk: AggregatePublicKey = AggregatePublicKey( + G2Affine::from_compressed( + hex::decode(&paid_pk).expect("Invalid key hex")[..] + .try_into() + .expect("Invalid key byte key"), + ) + .expect("Invalid PAID_PK"), + ); // nostr let nostr_nsec_str = std::env::var("NSEC").expect("FM_DB_PATH must be set"); @@ -108,7 +125,8 @@ async fn main() -> anyhow::Result<()> { secp, nostr, domain, - auth_pk, + free_pk, + paid_pk, }; // spawn a task to check for previous pending invoices @@ -138,8 +156,8 @@ async fn main() -> anyhow::Result<()> { let server_router = Router::new() .route("/health-check", get(health_check)) - .route("/check-username/:username", get(check_username)) - .route("/register", post(register_route)) + .route("/v1/check-username/:username", get(check_username)) + .route("/v1/register", post(register_route)) .route("/.well-known/nostr.json", get(well_known_nip5_route)) .route( "/.well-known/lnurlp/:username", diff --git a/src/models/app_user.rs b/src/models/app_user.rs index 8e2fd51..f76b048 100644 --- a/src/models/app_user.rs +++ b/src/models/app_user.rs @@ -43,12 +43,11 @@ impl AppUser { == 0) } - pub fn check_token_not_spent(conn: &mut PgConnection, msg: String) -> anyhow::Result { + pub fn get_by_token(conn: &mut PgConnection, msg: String) -> anyhow::Result> { Ok(app_user::table .filter(app_user::unblinded_msg.eq(msg)) - .count() - .get_result::(conn)? - == 0) + .first::(conn) + .optional()?) } pub fn get_by_pubkey( diff --git a/src/nostr.rs b/src/nostr.rs index 1fed4de..5e249f5 100644 --- a/src/nostr.rs +++ b/src/nostr.rs @@ -11,7 +11,7 @@ pub fn well_known_nip5( let mut names = HashMap::new(); if let Some(user) = user { - names.insert(user.name, XOnlyPublicKey::from_str(&user.pubkey).unwrap()); + names.insert(user.name, XOnlyPublicKey::from_str(&user.pubkey)?); } Ok(names) @@ -43,7 +43,8 @@ mod tests_integration { let nostr = nostr_sdk::Client::new(&nostr_sk); // create blind signer - let signer = BlindSigner::derive(&[0u8; 32], 0, 0); + let free_signer = BlindSigner::derive(&[0u8; 32], 0, 0); + let paid_signer = BlindSigner::derive(&[0u8; 32], 0, 0); let mock_mm = Arc::new(mock_mm); let state = State { @@ -51,7 +52,8 @@ mod tests_integration { mm: mock_mm, secp: Secp256k1::new(), nostr, - auth_pk: signer.pk, + free_pk: free_signer.pk, + paid_pk: paid_signer.pk, domain: "http://127.0.0.1:8080".to_string(), }; diff --git a/src/register.rs b/src/register.rs index ee3ee1c..8b00a6f 100644 --- a/src/register.rs +++ b/src/register.rs @@ -1,12 +1,15 @@ use std::str::FromStr; use crate::{ + models::app_user::NewAppUser, routes::{RegisterRequest, RegisterResponse}, State, }; use fedimint_core::api::InviteCode; use lazy_regex::*; use log::error; +use names::Generator; +use nostr::prelude::XOnlyPublicKey; use reqwest::StatusCode; pub static ALPHANUMERIC_REGEX: Lazy = lazy_regex!("^[a-zA-Z0-9]+$"); @@ -28,30 +31,70 @@ pub fn check_available(state: &State, name: String) -> anyhow::Result { state.db.check_name_available(name) } +pub fn generate_random_name(state: &State) -> anyhow::Result { + loop { + let new_name = Generator::with_naming(names::Name::Numbered) + .next() + .expect("should generate name") + .replace('-', ""); + + if check_available(state, new_name.clone())? { + return Ok(new_name); + } + } +} + pub async fn register( state: &State, req: RegisterRequest, ) -> Result { - if !is_valid_name(&req.name) { + // validate user name & pubkey first + let requested_paid = req.name.is_some(); + if requested_paid && !is_valid_name(&req.name.clone().unwrap()) { return Err((StatusCode::BAD_REQUEST, "Unavailable".to_string())); } + XOnlyPublicKey::from_str(&req.pubkey) + .map_err(|_| (StatusCode::BAD_REQUEST, "Nostr Pubkey Invalid".to_string()))?; + + // a different signer based on paid vs free + let signer = if requested_paid { + state.paid_pk + } else { + state.free_pk + }; // verify token and double check that it has not been spent before - if !req.verify(state.auth_pk) { + if !req.verify(signer) { return Err((StatusCode::UNAUTHORIZED, "Invalid blind sig".to_string())); } - match state.db.check_token_not_spent(req.msg.0.to_string()) { - Ok(true) => (), - Ok(false) => { - return Err((StatusCode::BAD_REQUEST, "Already Registered".to_string())); + + let user_msg_hex = serde_json::to_string(&req.msg) + .map_err(|_| (StatusCode::BAD_REQUEST, "Nostr blinded message".to_string()))?; + match state.db.get_user_by_token(user_msg_hex.clone()) { + Ok(Some(u)) => { + // if token has already been spent, just return the registered user info + return Ok(RegisterResponse { name: u.name }); } + Ok(None) => (), Err(e) => { error!("Error in register: {e:?}"); return Err((StatusCode::INTERNAL_SERVER_ERROR, "ServerError".to_string())); } } - match state.db.check_name_available(req.name.clone()) { + let name_to_register = if requested_paid { + req.name.clone().unwrap().clone() + } else { + match generate_random_name(state) { + Ok(s) => s, + Err(e) => { + error!("Error in register name generator: {e:?}"); + return Err((StatusCode::INTERNAL_SERVER_ERROR, "ServerError".to_string())); + } + } + }; + + match state.db.check_name_available(name_to_register.clone()) { Ok(true) => (), Ok(false) => { return Err((StatusCode::BAD_REQUEST, "Unavailable".to_string())); @@ -81,8 +124,17 @@ pub async fn register( } } - match state.db.insert_new_user(req.into()) { - Ok(_) => Ok(RegisterResponse {}), + let new_user = NewAppUser { + pubkey: req.pubkey, + name: name_to_register.clone(), + federation_id: req.federation_id.to_string(), + unblinded_msg: user_msg_hex, + federation_invite_code: req.federation_invite_code, + }; + match state.db.insert_new_user(new_user) { + Ok(_) => Ok(RegisterResponse { + name: name_to_register, + }), Err(e) => { error!("Errorgister: {e:?}"); Err((StatusCode::INTERNAL_SERVER_ERROR, "ServerError".to_string())) @@ -183,14 +235,16 @@ mod tests_integration { let nostr = nostr_sdk::Client::new(&nostr_sk); // create blind signer - let signer = BlindSigner::derive(&[0u8; 32], 0, 0); + let free_signer = BlindSigner::derive(&[0u8; 32], 0, 0); + let paid_signer = BlindSigner::derive(&[0u8; 32], 0, 0); let state = State { db: db.clone(), mm: mock_mm, secp: Secp256k1::new(), nostr, - auth_pk: signer.pk, + free_pk: free_signer.pk, + paid_pk: paid_signer.pk, domain: "http://127.0.0.1:8080".to_string(), }; @@ -233,7 +287,8 @@ mod tests_integration { let nostr = nostr_sdk::Client::new(&nostr_sk); // create blind signer - let signer = BlindSigner::derive(&[0u8; 32], 0, 0); + let free_signer = BlindSigner::derive(&[0u8; 32], 0, 0); + let paid_signer = BlindSigner::derive(&[0u8; 32], 0, 0); let mock_mm = Arc::new(mock_mm); let state = State { @@ -241,7 +296,8 @@ mod tests_integration { mm: mock_mm, secp: Secp256k1::new(), nostr, - auth_pk: signer.pk, + free_pk: free_signer.pk, + paid_pk: paid_signer.pk, domain: "http://127.0.0.1:8080".to_string(), }; @@ -249,7 +305,7 @@ mod tests_integration { let msg = tbs::Message::from_bytes(b"register_username_tests"); let blinding_key = BlindingKey::random(); let blinded_msg = blind_message(msg, blinding_key); - let blind_sig = signer.blind_sign(blinded_msg); + let blind_sig = paid_signer.blind_sign(blinded_msg); let sig = unblind_signature(blinding_key, blind_sig); let connect = InviteCode::new( @@ -258,8 +314,8 @@ mod tests_integration { FederationId::dummy(), ); let req = RegisterRequest { - name: "registername".to_string(), - pubkey: "".to_string(), + name: Some("registername".to_string()), + pubkey: "552a9d06810f306bfc085cb1e1c26102554138a51fa3a7fdf98f5b03a945143a".to_string(), federation_id: connect.federation_id(), federation_invite_code: connect.to_string(), msg, @@ -298,7 +354,8 @@ mod tests_integration { let nostr = nostr_sdk::Client::new(&nostr_sk); // create blind signer - let signer = BlindSigner::derive(&[0u8; 32], 0, 0); + let free_signer = BlindSigner::derive(&[0u8; 32], 0, 0); + let paid_signer = BlindSigner::derive(&[0u8; 32], 0, 0); let mock_mm = Arc::new(mock_mm); let state = State { @@ -306,7 +363,8 @@ mod tests_integration { mm: mock_mm, secp: Secp256k1::new(), nostr, - auth_pk: signer.pk, + free_pk: free_signer.pk, + paid_pk: paid_signer.pk, domain: "http://127.0.0.1:8080".to_string(), }; @@ -324,8 +382,8 @@ mod tests_integration { FederationId::dummy(), ); let req = RegisterRequest { - name: "newfederationusername".to_string(), - pubkey: "".to_string(), + name: Some("newfederationusername".to_string()), + pubkey: "552a9d06810f306bfc085cb1e1c26102554138a51fa3a7fdf98f5b03a945143a".to_string(), federation_id: connect.federation_id(), federation_invite_code: connect.to_string(), msg, @@ -359,7 +417,8 @@ mod tests_integration { let nostr = nostr_sdk::Client::new(&nostr_sk); // create blind signer - let signer = BlindSigner::derive(&[0u8; 32], 0, 0); + let free_signer = BlindSigner::derive(&[0u8; 32], 0, 0); + let paid_signer = BlindSigner::derive(&[0u8; 32], 0, 0); let mock_mm = Arc::new(mock_mm); let state = State { @@ -367,7 +426,8 @@ mod tests_integration { mm: mock_mm, secp: Secp256k1::new(), nostr, - auth_pk: signer.pk, + free_pk: free_signer.pk, + paid_pk: paid_signer.pk, domain: "http://127.0.0.1:8080".to_string(), }; @@ -375,7 +435,7 @@ mod tests_integration { let msg = tbs::Message::from_bytes(b"register_username_already_spent_token_tests"); let blinding_key = BlindingKey::random(); let blinded_msg = blind_message(msg, blinding_key); - let blind_sig = signer.blind_sign(blinded_msg); + let blind_sig = paid_signer.blind_sign(blinded_msg); let sig = unblind_signature(blinding_key, blind_sig); let connect = InviteCode::new( @@ -384,8 +444,8 @@ mod tests_integration { FederationId::dummy(), ); let req = RegisterRequest { - name: "registername1".to_string(), - pubkey: "".to_string(), + name: Some("registername1".to_string()), + pubkey: "552a9d06810f306bfc085cb1e1c26102554138a51fa3a7fdf98f5b03a945143a".to_string(), federation_id: connect.federation_id(), federation_invite_code: connect.to_string(), msg, @@ -394,24 +454,32 @@ mod tests_integration { // let the first user register sucessfully match register(&state, req).await { - Ok(_) => (), + Ok(r) => { + assert_eq!(r.name, "registername1"); + } Err(_) => { panic!("shouldn't error") } } // second username attempting to register with the same msg + // should return the first username it registered with let req2 = RegisterRequest { - name: "registername2".to_string(), - pubkey: "".to_string(), + name: Some("registername2".to_string()), + pubkey: "552a9d06810f306bfc085cb1e1c26102554138a51fa3a7fdf98f5b03a945143a".to_string(), federation_id: connect.federation_id(), federation_invite_code: connect.to_string(), msg, sig, }; - if register(&state, req2).await.is_ok() { - panic!("should not succeed") + match register(&state, req2).await { + Ok(r) => { + assert_eq!(r.name, "registername1"); + } + Err(_) => { + panic!("shouldn't error") + } } } } diff --git a/src/routes.rs b/src/routes.rs index 31adb27..40d9dac 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -1,6 +1,5 @@ use crate::{ lnurlp::{lnurl_callback, verify, well_known_lnurlp}, - models::app_user::NewAppUser, nostr::well_known_nip5, register::{check_available, register}, State, ALLOWED_LOCALHOST, ALLOWED_ORIGINS, ALLOWED_SUBDOMAIN, API_VERSION, @@ -35,7 +34,7 @@ pub async fn check_username( #[derive(Deserialize)] pub struct RegisterRequest { - pub name: String, + pub name: Option, pub pubkey: String, pub federation_id: FederationId, pub federation_invite_code: String, @@ -49,20 +48,10 @@ impl RegisterRequest { } } -impl From for NewAppUser { - fn from(request: RegisterRequest) -> Self { - NewAppUser { - pubkey: request.pubkey, - name: request.name, - federation_id: request.federation_id.to_string(), - unblinded_msg: request.msg.0.to_string(), - federation_invite_code: request.federation_invite_code, - } - } -} - #[derive(Serialize)] -pub struct RegisterResponse {} +pub struct RegisterResponse { + pub name: String, +} pub async fn register_route( origin: Option>, @@ -89,10 +78,10 @@ pub struct UserWellKnownNip5Resp { pub async fn well_known_nip5_route( Extension(state): Extension, - Json(req): Json, + Query(params): Query, ) -> Result, (StatusCode, String)> { debug!("well_known_nip5_route"); - match well_known_nip5(&state, req.name) { + match well_known_nip5(&state, params.name) { Ok(res) => Ok(Json(UserWellKnownNip5Resp { names: res })), Err(e) => Err((StatusCode::INTERNAL_SERVER_ERROR, e.to_string())), }