Implemented feature:

- NIP-42 Can be enabled in nix module or as environment variable 'CONFIG_ENABLE_AUTH'
 - NIP-05 Still WIP, but building up slowly
This commit is contained in:
Tony Klink 2024-02-08 19:19:03 -06:00
parent 377da44eed
commit f7b74bd22c
Signed by: klink
GPG key ID: 85175567C4D19231
18 changed files with 1001 additions and 294 deletions

View file

@ -1,9 +1,7 @@
use std::collections::HashMap;
use crate::usernames::validators::validate_pubkey;
use crate::usernames::validators::{validate_pubkey, validate_relays};
use crate::utils::error::Error;
use nostr::key::XOnlyPublicKey;
use nostr::prelude::*;
use nostr::{key::XOnlyPublicKey, Keys};
use regex::Regex;
use serde::{Deserialize, Serialize};
use validator::Validate;
@ -12,27 +10,22 @@ lazy_static! {
static ref VALID_CHARACTERS: Regex = Regex::new(r"^[a-zA-Z0-9\_]+$").unwrap();
}
#[derive(Serialize, Deserialize, Debug, Validate)]
#[derive(Serialize, Deserialize, Debug, Validate, PartialEq, Clone)]
pub struct UserBody {
#[validate(length(min = 1), regex = "VALID_CHARACTERS")]
pub name: String,
#[validate(custom(function = "validate_pubkey"))]
pub pubkey: String,
pubkey: String,
#[validate(custom(function = "validate_relays"))]
pub relays: Vec<String>
}
impl UserBody {
pub fn get_pubkey(&self) -> XOnlyPublicKey {
let keys = Keys::from_pk_str(&self.pubkey).unwrap();
keys.public_key()
pub fn get_pubkey(&self) -> String {
nostr::Keys::from_pk_str(&self.pubkey).unwrap().public_key().to_string()
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Nip05 {
names: HashMap<String, String>,
}
#[derive(Serialize, Deserialize, Debug, Validate, Clone)]
pub struct UserQuery {
#[validate(length(min = 1))]

View file

@ -2,10 +2,6 @@ use crate::utils::error::Error;
use validator::Validate;
use warp::{Filter, Rejection};
pub fn with_client_ip() {}
pub fn with_user_body() {}
pub fn validate_body_filter<T: serde::de::DeserializeOwned + Send + Validate + 'static>(
) -> impl Filter<Extract = (T,), Error = Rejection> + Copy {
warp::body::json::<T>().and_then(|query: T| async move {

View file

@ -6,6 +6,8 @@ use crate::utils::structs::Context;
use serde_json::json;
use warp::{Rejection, Reply};
use super::dto::UserBody;
pub async fn get_account(
// account: Result<AccountPubkey, Error>,
account: Account,
@ -47,7 +49,7 @@ pub async fn get_account(
pub async fn get_user(user_query: UserQuery, context: Context) -> Result<impl Reply, Rejection> {
let mut subscriber = context.pubsub.subscribe(channels::MSG_NIP05).await;
let command = Command::DbReqGetUser(user_query.name);
let command = Command::DbReqGetNIP05(user_query.name);
context
.pubsub
.publish(
@ -61,7 +63,7 @@ pub async fn get_user(user_query: UserQuery, context: Context) -> Result<impl Re
if let Ok(message) = subscriber.recv().await {
match message.content {
Command::DbResUser(profile) => {
Command::DbResNIP05(profile) => {
let response = serde_json::to_value(profile).unwrap();
Ok(warp::reply::json(&response))
}
@ -76,3 +78,35 @@ pub async fn get_user(user_query: UserQuery, context: Context) -> Result<impl Re
)))
}
}
pub async fn create_user(user_body: UserBody, context: Context) -> Result<impl Reply, Rejection> {
let mut subscriber = context.pubsub.subscribe(channels::MSG_NIP05).await;
let command = Command::DbReqCreateNIP05(user_body);
context
.pubsub
.publish(
channels::MSG_NOOSE,
Message {
source: channels::MSG_NIP05,
content: command,
},
)
.await;
if let Ok(message) = subscriber.recv().await {
match message.content {
Command::DbResOk => {
Ok(warp::http::StatusCode::CREATED)
}
Command::ServiceError(e) => Err(warp::reject::custom(e)),
_ => Err(warp::reject::custom(Error::internal_with_message(
"Unhandeled message type",
))),
}
} else {
Err(warp::reject::custom(Error::internal_with_message(
"Unhandeled message type",
)))
}
}

View file

@ -1,9 +1,9 @@
use crate::noose::user::User;
// use super::accounts::create_account;
use super::dto::{Account, UserQuery};
use super::dto::{Account, UserBody, UserQuery};
use super::filter::{validate_body_filter, validate_query_filter};
use super::handler::{get_account, get_user};
use super::handler::{create_user, get_account, get_user};
use crate::utils::filter::with_context;
use crate::utils::structs::Context;
use warp::{Filter, Rejection, Reply};
@ -14,25 +14,37 @@ pub fn routes(context: Context) -> impl Filter<Extract = impl Reply, Error = Rej
index
.or(nip05_get(context.clone()))
// .or(account_create(context.clone()))
.or(nip05_create(context.clone()))
.with(&cors)
}
fn well_known() -> impl Filter<Extract = (), Error = Rejection> + Clone {
warp::get().and(warp::path(".well-known"))
fn well_known<M>(warp_method: M) -> impl Filter<Extract = (), Error = Rejection> + Clone
where
M: (Filter<Extract = (), Error = Rejection>) + Copy,
{
warp_method.and(warp::path(".well-known"))
}
fn nostr_well_known() -> impl Filter<Extract = (), Error = Rejection> + Clone {
well_known().and(warp::path("nostr.json"))
well_known(warp::get()).and(warp::path("nostr.json"))
}
pub fn nip05_get(context: Context) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
fn nip05_get(context: Context) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
nostr_well_known()
.and(validate_query_filter::<UserQuery>())
.and(with_context(context.clone()))
.and_then(get_user)
}
fn nip05_create(context: Context) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
well_known(warp::post())
.and(warp::path("nostr.json"))
.and(warp::body::content_length_limit(1024))
.and(validate_body_filter::<UserBody>())
.and(with_context(context.clone()))
.and_then(create_user)
}
// pub fn account_create(
// context: Context,
// ) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {

View file

@ -1,7 +1,7 @@
use super::dto::AccountPubkey;
use crate::utils::error::Error;
use nostr::prelude::FromPkStr;
use validator::{Validate, ValidationError};
use validator::{Validate, ValidationError, validate_url};
pub async fn validate_account_pubkey_query(
account_pubkey: AccountPubkey,
@ -25,6 +25,18 @@ pub fn validate_pubkey(value: &str) -> Result<(), ValidationError> {
match nostr::Keys::from_pk_str(value) {
Ok(_) => Ok(()),
Err(_) => Err(ValidationError::new("Unable to parse pk_str")),
Err(_) => Err(ValidationError::new("Failed to parse pubkey")),
}
}
pub fn validate_relays(relays: &Vec<String>) -> Result<(), ValidationError> {
if relays.is_empty() {
return Ok(())
}
if relays.iter().all(validate_url) {
return Ok(())
}
Err(ValidationError::new("Relays have wrong url format"))
}