Skip to content

Commit

Permalink
Change federation
Browse files Browse the repository at this point in the history
  • Loading branch information
TonyGiorgio committed Apr 11, 2024
1 parent 61e04b2 commit 0d28f86
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 7 deletions.
16 changes: 16 additions & 0 deletions src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ pub(crate) trait DBConnection {
fn get_user_by_name(&self, name: String) -> anyhow::Result<Option<AppUser>>;
fn get_user_by_id(&self, id: i32) -> anyhow::Result<Option<AppUser>>;
fn get_user_by_pubkey(&self, pubkey: String) -> anyhow::Result<Option<AppUser>>;
fn update_user_federation(
&self,
user: AppUser,
federation_id: String,
federation_invite_code: String,
) -> anyhow::Result<()>;
fn get_user_and_increment_counter(&self, name: &str) -> anyhow::Result<Option<AppUser>>;
fn insert_new_zap(&self, new_zap: Zap) -> anyhow::Result<Zap>;
fn get_zap_by_id(&self, id: i32) -> anyhow::Result<Option<Zap>>;
Expand Down Expand Up @@ -57,6 +63,16 @@ impl DBConnection for PostgresConnection {
new_user.insert(conn)
}

fn update_user_federation(
&self,
user: AppUser,
federation_id: String,
federation_invite_code: String,
) -> anyhow::Result<()> {
let conn = &mut self.db.get()?;
user.update_federation(conn, federation_id, federation_invite_code)
}

fn get_pending_invoices(&self) -> anyhow::Result<Vec<Invoice>> {
let conn = &mut self.db.get()?;
Invoice::get_by_state(conn, 0)
Expand Down
7 changes: 4 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ use crate::{
invoice::handle_pending_invoices,
mint::{setup_multimint, MultiMintWrapperTrait},
routes::{
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, health_check,
lnurl_callback_route, lnurl_verify_route, register_route, root, validate_cors,
well_known_lnurlp_route, well_known_nip5_route,
},
};

Expand Down Expand Up @@ -171,6 +171,7 @@ async fn main() -> anyhow::Result<()> {
.route("/v1/check-username/:username", get(check_username))
.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/register", post(register_route))
.route("/.well-known/nostr.json", get(well_known_nip5_route))
.route(
Expand Down
17 changes: 17 additions & 0 deletions src/models/app_user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,23 @@ impl AppUser {
.first::<AppUser>(conn)
.optional()?)
}

pub fn update_federation(
&self,
conn: &mut PgConnection,
new_federation_id: String,
new_federation_invite_code: String,
) -> anyhow::Result<()> {
diesel::update(app_user::table)
.filter(app_user::name.eq(&self.name))
.set((
app_user::federation_id.eq(new_federation_id),
app_user::federation_invite_code.eq(new_federation_invite_code),
))
.execute(conn)?;

Ok(())
}
}

#[derive(Insertable)]
Expand Down
11 changes: 11 additions & 0 deletions src/register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@ pub fn get_user_by_pubkey(state: &State, pubkey: String) -> anyhow::Result<Optio
state.db.get_user_by_pubkey(pubkey)
}

pub fn change_user_federation(
state: &State,
user: AppUser,
federation_id: String,
federation_invite_code: String,
) -> anyhow::Result<()> {
state
.db
.update_user_federation(user, federation_id, federation_invite_code)
}

pub fn generate_random_name(state: &State) -> anyhow::Result<String> {
loop {
let new_name = Generator::with_naming(names::Name::Numbered)
Expand Down
79 changes: 75 additions & 4 deletions src/routes.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use crate::{
lnurlp::{lnurl_callback, verify, well_known_lnurlp},
nostr::well_known_nip5,
register::{check_available, check_registered_pubkey, get_user_by_pubkey, register},
register::{
change_user_federation, check_available, check_registered_pubkey, get_user_by_pubkey,
register,
},
State, ALLOWED_LOCALHOST, ALLOWED_ORIGINS, ALLOWED_SUBDOMAIN, API_VERSION,
};
use axum::extract::{Path, Query};
Expand All @@ -10,7 +13,7 @@ use axum::http::StatusCode;
use axum::response::{IntoResponse, Redirect, Response};
use axum::Extension;
use axum::{Json, TypedHeader};
use fedimint_core::{config::FederationId, Amount};
use fedimint_core::{api::InviteCode, config::FederationId, Amount};
use fedimint_ln_common::lightning_invoice::Bolt11Invoice;
use log::{error, info};
use nostr::{Event, Kind};
Expand All @@ -21,6 +24,7 @@ use tbs::AggregatePublicKey;
use url::Url;

const REGISTRATION_CHECK_EVENT_KIND: Kind = Kind::Custom(93_186);
const NEW_FEDERATION_EVENT_KIND: Kind = Kind::Custom(93_187);

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct LnUrlErrorResponse {
Expand Down Expand Up @@ -94,7 +98,7 @@ pub async fn check_registration_info(
return Err((StatusCode::BAD_REQUEST, "Bad event".to_string()));
}

// make sure it was made in the last 30 seconds
// 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 {
Expand All @@ -111,7 +115,12 @@ pub async fn check_registration_info(

Ok(Json(RegistrationInfo {
name: Some(u.name),
federation_id: Some(u.federation_id),
federation_id: Some(FederationId::from_str(&u.federation_id).map_err(|_| {
(
StatusCode::INTERNAL_SERVER_ERROR,
"FederationId invalid".to_string(),
)
})?),
}))
}
Ok(None) => {
Expand All @@ -126,6 +135,68 @@ pub async fn check_registration_info(
}
}

pub async fn change_federation(
origin: Option<TypedHeader<Origin>>,
Extension(state): Extension<State>,
Json(event): Json<Event>,
) -> Result<(), (StatusCode, String)> {
validate_cors(origin)?;

let pubkey = event.author();
info!("change_federation: {}", pubkey);

if event.verify().is_err() && event.kind() != NEW_FEDERATION_EVENT_KIND {
error!("error in change_federation: 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 change_federation: event time not in range");
return Err((
StatusCode::BAD_REQUEST,
"Event time not in range".to_string(),
));
}

// get the federation invite code and parse it
let federation_invite_code = InviteCode::from_str(event.content())
.map_err(|_| (StatusCode::BAD_REQUEST, "InviteCode Invalid".to_string()))?;
let federation_id = federation_invite_code.federation_id();

match get_user_by_pubkey(&state, pubkey.to_string()) {
Ok(Some(u)) => {
info!("change_federation found user for pubkey: {}", pubkey);

// got the user, now change the federation
match change_user_federation(
&state,
u,
federation_id.to_string(),
federation_invite_code.to_string(),
) {
Ok(_) => {
info!(
"change_federation changed user federation for pubkey: {}, {}",
pubkey,
federation_id.to_string()
);
Ok(())
}
Err(e) => Err(handle_anyhow_error("change_federation", e)),
}
}
Ok(None) => {
error!("change_federation not found: {}", pubkey);

Err((StatusCode::NOT_FOUND, "User not found".to_string()))
}
Err(e) => Err(handle_anyhow_error("change_federation", e)),
}
}

#[derive(Deserialize, Clone)]
pub struct RegisterRequest {
pub name: Option<String>,
Expand Down

0 comments on commit 0d28f86

Please sign in to comment.