From ea66c78457ed2a689d712c13f4b5713a125c3f53 Mon Sep 17 00:00:00 2001 From: Tony Giorgio Date: Thu, 11 Apr 2024 16:14:24 -0500 Subject: [PATCH 1/2] Add ability to disable zaps --- migrations/2024-04-11-210151_disable_zaps/down.sql | 1 + migrations/2024-04-11-210151_disable_zaps/up.sql | 1 + src/db.rs | 6 ++++++ src/lnurlp.rs | 6 ++++++ src/models/app_user.rs | 11 +++++++++++ src/models/schema.rs | 1 + 6 files changed, 26 insertions(+) create mode 100644 migrations/2024-04-11-210151_disable_zaps/down.sql create mode 100644 migrations/2024-04-11-210151_disable_zaps/up.sql diff --git a/migrations/2024-04-11-210151_disable_zaps/down.sql b/migrations/2024-04-11-210151_disable_zaps/down.sql new file mode 100644 index 0000000..229b0a8 --- /dev/null +++ b/migrations/2024-04-11-210151_disable_zaps/down.sql @@ -0,0 +1 @@ +ALTER TABLE app_user DROP COLUMN disabled_zaps; diff --git a/migrations/2024-04-11-210151_disable_zaps/up.sql b/migrations/2024-04-11-210151_disable_zaps/up.sql new file mode 100644 index 0000000..56c58ae --- /dev/null +++ b/migrations/2024-04-11-210151_disable_zaps/up.sql @@ -0,0 +1 @@ +ALTER TABLE app_user ADD COLUMN disabled_zaps BOOLEAN NOT NULL DEFAULT FALSE; diff --git a/src/db.rs b/src/db.rs index 61aa75e..3e9bf21 100644 --- a/src/db.rs +++ b/src/db.rs @@ -29,6 +29,7 @@ pub(crate) trait DBConnection { federation_id: String, federation_invite_code: String, ) -> anyhow::Result<()>; + fn disable_user_zaps(&self, user: AppUser) -> anyhow::Result<()>; fn get_user_and_increment_counter(&self, name: &str) -> anyhow::Result>; fn insert_new_zap(&self, new_zap: Zap) -> anyhow::Result; fn get_zap_by_id(&self, id: i32) -> anyhow::Result>; @@ -73,6 +74,11 @@ impl DBConnection for PostgresConnection { user.update_federation(conn, federation_id, federation_invite_code) } + fn disable_user_zaps(&self, user: AppUser) -> anyhow::Result<()> { + let conn = &mut self.db.get()?; + user.disable_zaps(conn) + } + fn get_pending_invoices(&self) -> anyhow::Result> { let conn = &mut self.db.get()?; Invoice::get_by_state(conn, 0) diff --git a/src/lnurlp.rs b/src/lnurlp.rs index 071949c..b0f50f5 100644 --- a/src/lnurlp.rs +++ b/src/lnurlp.rs @@ -61,6 +61,12 @@ pub async fn lnurl_callback( } let user = user.expect("just checked"); + if user.disabled_zaps { + return Err(anyhow!( + "Internal error: User has disabled their address temporarily" + )); + } + let amount_msats = match params.amount { Some(amt) => amt, None => return Err(anyhow!(INVALID_AMT_ERR)), diff --git a/src/models/app_user.rs b/src/models/app_user.rs index 4863e96..3c4c78e 100644 --- a/src/models/app_user.rs +++ b/src/models/app_user.rs @@ -17,6 +17,7 @@ pub struct AppUser { pub federation_id: String, pub federation_invite_code: String, pub invoice_index: i32, + pub disabled_zaps: bool, } impl AppUser { @@ -99,11 +100,21 @@ impl AppUser { .set(( app_user::federation_id.eq(new_federation_id), app_user::federation_invite_code.eq(new_federation_invite_code), + app_user::disabled_zaps.eq(false), )) .execute(conn)?; Ok(()) } + + pub fn disable_zaps(&self, conn: &mut PgConnection) -> anyhow::Result<()> { + diesel::update(app_user::table) + .filter(app_user::name.eq(&self.name)) + .set((app_user::disabled_zaps.eq(true),)) + .execute(conn)?; + + Ok(()) + } } #[derive(Insertable)] diff --git a/src/models/schema.rs b/src/models/schema.rs index 6a61296..5e4e720 100644 --- a/src/models/schema.rs +++ b/src/models/schema.rs @@ -14,6 +14,7 @@ diesel::table! { #[max_length = 255] federation_invite_code -> Varchar, invoice_index -> Int4, + disabled_zaps -> Bool, } } From 1b5c800605908f9c4d9f30e75db1806f2426624e Mon Sep 17 00:00:00 2001 From: Tony Giorgio Date: Thu, 11 Apr 2024 16:24:11 -0500 Subject: [PATCH 2/2] Add disable zap api call --- src/main.rs | 7 ++++--- src/register.rs | 4 ++++ src/routes.rs | 56 +++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 62 insertions(+), 5 deletions(-) diff --git a/src/main.rs b/src/main.rs index 44cccd2..ba5d6c3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,9 +17,9 @@ use crate::{ invoice::handle_pending_invoices, mint::{setup_multimint, MultiMintWrapperTrait}, routes::{ - change_federation, check_pubkey, check_registration_info, check_username, health_check, - lnurl_callback_route, lnurl_verify_route, register_route, root, validate_cors, - well_known_lnurlp_route, well_known_nip5_route, + change_federation, check_pubkey, check_registration_info, check_username, disable_zaps, + health_check, lnurl_callback_route, lnurl_verify_route, register_route, root, + validate_cors, well_known_lnurlp_route, well_known_nip5_route, }, }; @@ -172,6 +172,7 @@ async fn main() -> anyhow::Result<()> { .route("/v1/check-pubkey/:pubkey", get(check_pubkey)) // DEPRECATED for check-registration .route("/v1/check-registration", post(check_registration_info)) .route("/v1/change-federation", post(change_federation)) + .route("/v1/disable-zaps", post(disable_zaps)) .route("/v1/register", post(register_route)) .route("/.well-known/nostr.json", get(well_known_nip5_route)) .route( diff --git a/src/register.rs b/src/register.rs index 932500f..2475246 100644 --- a/src/register.rs +++ b/src/register.rs @@ -50,6 +50,10 @@ pub fn change_user_federation( .update_user_federation(user, federation_id, federation_invite_code) } +pub fn disable_user_zaps(state: &State, user: AppUser) -> anyhow::Result<()> { + state.db.disable_user_zaps(user) +} + pub fn generate_random_name(state: &State) -> anyhow::Result { loop { let new_name = Generator::with_naming(names::Name::Numbered) diff --git a/src/routes.rs b/src/routes.rs index 473f91a..8b301ff 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -2,8 +2,8 @@ use crate::{ lnurlp::{lnurl_callback, verify, well_known_lnurlp}, nostr::well_known_nip5, register::{ - change_user_federation, check_available, check_registered_pubkey, ensure_added_federation, - get_user_by_pubkey, register, + change_user_federation, check_available, check_registered_pubkey, disable_user_zaps, + ensure_added_federation, get_user_by_pubkey, register, }, State, ALLOWED_LOCALHOST, ALLOWED_ORIGINS, ALLOWED_SUBDOMAIN, API_VERSION, }; @@ -25,6 +25,7 @@ use url::Url; const REGISTRATION_CHECK_EVENT_KIND: Kind = Kind::Custom(93_186); const NEW_FEDERATION_EVENT_KIND: Kind = Kind::Custom(93_187); +const DISABLE_ZAPS_EVENT_KIND: Kind = Kind::Custom(93_188); #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct LnUrlErrorResponse { @@ -199,6 +200,57 @@ pub async fn change_federation( } } +pub async fn disable_zaps( + origin: Option>, + Extension(state): Extension, + Json(event): Json, +) -> Result<(), (StatusCode, String)> { + validate_cors(origin)?; + + let pubkey = event.author(); + info!("disable_zaps: {}", pubkey); + + if event.verify().is_err() && event.kind() != DISABLE_ZAPS_EVENT_KIND { + error!("error in disable_zaps: bad event"); + return Err((StatusCode::BAD_REQUEST, "Bad event".to_string())); + } + + // make sure it was made recently + let created_at = event.created_at(); + let now = nostr::Timestamp::now(); + if created_at < now - 120_i64 && created_at > now + 120_i64 { + error!("error in disable_zaps: event time not in range"); + return Err(( + StatusCode::BAD_REQUEST, + "Event time not in range".to_string(), + )); + } + + match get_user_by_pubkey(&state, pubkey.to_string()) { + Ok(Some(u)) => { + info!("disable_zaps found user for pubkey: {}", pubkey); + + // got the user, now change the federation + match disable_user_zaps(&state, u) { + Ok(_) => { + info!( + "disable_zaps changed user federation for pubkey: {}", + pubkey + ); + Ok(()) + } + Err(e) => Err(handle_anyhow_error("disable_zaps", e)), + } + } + Ok(None) => { + error!("disable_zaps not found: {}", pubkey); + + Err((StatusCode::NOT_FOUND, "User not found".to_string())) + } + Err(e) => Err(handle_anyhow_error("disable_zaps", e)), + } +} + #[derive(Deserialize, Clone)] pub struct RegisterRequest { pub name: Option,