Setup API

This commit is contained in:
Kieran 2024-11-04 21:14:58 +00:00
parent f7279c8707
commit d1ab59a0aa
No known key found for this signature in database
GPG Key ID: DE71CEB3925BE941
8 changed files with 581 additions and 7 deletions

349
Cargo.lock generated
View File

@ -17,6 +17,16 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
[[package]]
name = "aead"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
dependencies = [
"crypto-common",
"generic-array",
]
[[package]]
name = "ahash"
version = "0.8.11"
@ -71,6 +81,12 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236"
[[package]]
name = "arrayvec"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
[[package]]
name = "async-stream"
version = "0.3.6"
@ -155,6 +171,16 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "base58ck"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c8d66485a3a2ea485c1913c4572ce0256067a5377ac8c75c4960e1cda98605f"
dependencies = [
"bitcoin-internals 0.3.0",
"bitcoin_hashes 0.14.0",
]
[[package]]
name = "base64"
version = "0.21.7"
@ -173,12 +199,99 @@ version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
[[package]]
name = "bech32"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d"
[[package]]
name = "binascii"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72"
[[package]]
name = "bip39"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33415e24172c1b7d6066f6d999545375ab8e1d95421d6784bdfff9496f292387"
dependencies = [
"bitcoin_hashes 0.13.0",
"serde",
"unicode-normalization",
]
[[package]]
name = "bitcoin"
version = "0.32.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "788902099d47c8682efe6a7afb01c8d58b9794ba66c06affd81c3d6b560743eb"
dependencies = [
"base58ck",
"bech32",
"bitcoin-internals 0.3.0",
"bitcoin-io",
"bitcoin-units",
"bitcoin_hashes 0.14.0",
"hex-conservative 0.2.1",
"hex_lit",
"secp256k1",
"serde",
]
[[package]]
name = "bitcoin-internals"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb"
[[package]]
name = "bitcoin-internals"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30bdbe14aa07b06e6cfeffc529a1f099e5fbe249524f8125358604df99a4bed2"
dependencies = [
"serde",
]
[[package]]
name = "bitcoin-io"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf"
[[package]]
name = "bitcoin-units"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5285c8bcaa25876d07f37e3d30c303f2609179716e11d688f51e8f1fe70063e2"
dependencies = [
"bitcoin-internals 0.3.0",
"serde",
]
[[package]]
name = "bitcoin_hashes"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b"
dependencies = [
"bitcoin-internals 0.2.0",
"hex-conservative 0.1.2",
]
[[package]]
name = "bitcoin_hashes"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16"
dependencies = [
"bitcoin-io",
"hex-conservative 0.2.1",
"serde",
]
[[package]]
name = "bitflags"
version = "2.6.0"
@ -197,6 +310,15 @@ dependencies = [
"generic-array",
]
[[package]]
name = "block-padding"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93"
dependencies = [
"generic-array",
]
[[package]]
name = "bumpalo"
version = "3.16.0"
@ -221,6 +343,15 @@ version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da"
[[package]]
name = "cbc"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6"
dependencies = [
"cipher",
]
[[package]]
name = "cc"
version = "1.1.31"
@ -236,6 +367,30 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chacha20"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818"
dependencies = [
"cfg-if",
"cipher",
"cpufeatures",
]
[[package]]
name = "chacha20poly1305"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35"
dependencies = [
"aead",
"chacha20",
"cipher",
"poly1305",
"zeroize",
]
[[package]]
name = "chrono"
version = "0.4.38"
@ -246,10 +401,22 @@ dependencies = [
"iana-time-zone",
"js-sys",
"num-traits",
"serde",
"wasm-bindgen",
"windows-targets 0.52.6",
]
[[package]]
name = "cipher"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
dependencies = [
"crypto-common",
"inout",
"zeroize",
]
[[package]]
name = "concurrent-queue"
version = "2.5.0"
@ -392,6 +559,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"rand_core",
"typenum",
]
@ -722,8 +890,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
"cfg-if",
"js-sys",
"libc",
"wasi",
"wasm-bindgen",
]
[[package]]
@ -834,6 +1004,27 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "hex-conservative"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20"
[[package]]
name = "hex-conservative"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd"
dependencies = [
"arrayvec",
]
[[package]]
name = "hex_lit"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd"
[[package]]
name = "hkdf"
version = "0.12.4"
@ -1081,6 +1272,28 @@ version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb"
[[package]]
name = "inout"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
dependencies = [
"block-padding",
"generic-array",
]
[[package]]
name = "instant"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
dependencies = [
"cfg-if",
"js-sys",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "ipnet"
version = "2.10.1"
@ -1167,9 +1380,11 @@ name = "lnvps"
version = "0.1.0"
dependencies = [
"anyhow",
"base64 0.22.1",
"chrono",
"config",
"log",
"nostr",
"pretty_env_logger",
"reqwest",
"rocket",
@ -1304,6 +1519,18 @@ dependencies = [
"tempfile",
]
[[package]]
name = "negentropy"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e664971378a3987224f7a0e10059782035e89899ae403718ee07de85bec42afe"
[[package]]
name = "negentropy"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a88da9dd148bbcdce323dd6ac47d369b4769d4a3b78c6c52389b9269f77932"
[[package]]
name = "nom"
version = "7.1.3"
@ -1314,6 +1541,31 @@ dependencies = [
"minimal-lexical",
]
[[package]]
name = "nostr"
version = "0.35.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56db234b2e07901e372f34e9463f91590579cd8e6dbd34ed2ccc7e461e4ba639"
dependencies = [
"base64 0.22.1",
"bech32",
"bip39",
"bitcoin",
"cbc",
"chacha20",
"chacha20poly1305",
"getrandom",
"instant",
"negentropy 0.3.1",
"negentropy 0.4.3",
"once_cell",
"scrypt",
"serde",
"serde_json",
"unicode-normalization",
"url",
]
[[package]]
name = "nu-ansi-term"
version = "0.46.0"
@ -1402,6 +1654,12 @@ version = "1.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
[[package]]
name = "opaque-debug"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
[[package]]
name = "openssl"
version = "0.10.68"
@ -1491,6 +1749,17 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "password-hash"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166"
dependencies = [
"base64ct",
"rand_core",
"subtle",
]
[[package]]
name = "paste"
version = "1.0.15"
@ -1503,6 +1772,16 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d61c5ce1153ab5b689d0c074c4e7fc613e942dfb7dd9eea5ab202d2ad91fe361"
[[package]]
name = "pbkdf2"
version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
dependencies = [
"digest",
"hmac",
]
[[package]]
name = "pear"
version = "0.2.9"
@ -1625,6 +1904,17 @@ version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
[[package]]
name = "poly1305"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf"
dependencies = [
"cpufeatures",
"opaque-debug",
"universal-hash",
]
[[package]]
name = "powerfmt"
version = "0.2.0"
@ -1868,6 +2158,7 @@ dependencies = [
"rocket_codegen",
"rocket_http",
"serde",
"serde_json",
"state",
"tempfile",
"time",
@ -2035,6 +2326,15 @@ version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]]
name = "salsa20"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213"
dependencies = [
"cipher",
]
[[package]]
name = "schannel"
version = "0.1.26"
@ -2056,6 +2356,39 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "scrypt"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f"
dependencies = [
"password-hash",
"pbkdf2",
"salsa20",
"sha2",
]
[[package]]
name = "secp256k1"
version = "0.29.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113"
dependencies = [
"bitcoin_hashes 0.14.0",
"rand",
"secp256k1-sys",
"serde",
]
[[package]]
name = "secp256k1-sys"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9"
dependencies = [
"cc",
]
[[package]]
name = "security-framework"
version = "2.11.1"
@ -2105,6 +2438,7 @@ version = "1.0.132"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03"
dependencies = [
"indexmap",
"itoa",
"memchr",
"ryu",
@ -2852,9 +3186,9 @@ checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
[[package]]
name = "unicode-normalization"
version = "0.1.24"
version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956"
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
dependencies = [
"tinyvec",
]
@ -2883,6 +3217,16 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
[[package]]
name = "universal-hash"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
dependencies = [
"crypto-common",
"subtle",
]
[[package]]
name = "untrusted"
version = "0.9.0"
@ -2898,6 +3242,7 @@ dependencies = [
"form_urlencoded",
"idna",
"percent-encoding",
"serde",
]
[[package]]

View File

@ -15,5 +15,7 @@ serde = { version = "1.0.213", features = ["derive"] }
reqwest = { version = "0.12.8", features = ["json"] }
serde_json = "1.0.132"
sqlx = { version = "0.8.2", features = ["mysql", "chrono", "migrate", "runtime-tokio"] }
rocket = "0.5.1"
chrono = "0.4.38"
rocket = { version = "0.5.1", features = ["json"] }
chrono = { version = "0.4.38", features = ["serde"] }
nostr = { version = "0.35.0", default-features = false, features = ["std"] }
base64 = "0.22.1"

46
src/api.rs Normal file
View File

@ -0,0 +1,46 @@
use crate::db;
use crate::nip98::Nip98Auth;
use crate::provisioner::Provisioner;
use anyhow::Error;
use rocket::serde::json::Json;
use rocket::{get, routes, Responder, Route, State};
use serde::{Deserialize, Serialize};
pub fn routes() -> Vec<Route> {
routes![v1_list_vms]
}
type ApiResult<T> = Result<Json<ApiData<T>>, ApiError>;
#[derive(Serialize)]
struct ApiData<T: Serialize> {
pub data: T,
}
impl<T: Serialize> ApiData<T> {
pub fn ok(data: T) -> ApiResult<T> {
Ok(Json::from(ApiData { data }))
}
}
#[derive(Responder)]
#[response(status = 500)]
struct ApiError {
pub error: String,
}
impl From<Error> for ApiError {
fn from(value: Error) -> Self {
Self {
error: value.to_string(),
}
}
}
#[get("/api/v1/vms")]
async fn v1_list_vms(auth: Nip98Auth, provisioner: &State<Provisioner>) -> ApiResult<Vec<db::Vm>> {
let pubkey = auth.event.pubkey.to_bytes();
let uid = provisioner.upsert_user(&pubkey).await?;
let vms = provisioner.list_vms(uid).await?;
ApiData::ok(vms)
}

32
src/cors.rs Normal file
View File

@ -0,0 +1,32 @@
use rocket::fairing::{Fairing, Info, Kind};
use rocket::http::{Header, Method, Status};
use rocket::{Request, Response};
use std::io::Cursor;
pub struct CORS;
#[rocket::async_trait]
impl Fairing for CORS {
fn info(&self) -> Info {
Info {
name: "CORS headers",
kind: Kind::Response,
}
}
async fn on_response<'r>(&self, req: &'r Request<'_>, response: &mut Response<'r>) {
response.set_header(Header::new("Access-Control-Allow-Origin", "*"));
response.set_header(Header::new(
"Access-Control-Allow-Methods",
"PUT, GET, HEAD, DELETE, OPTIONS, POST",
));
response.set_header(Header::new("Access-Control-Allow-Headers", "*"));
response.set_header(Header::new("Access-Control-Allow-Credentials", "true"));
// force status 200 for options requests
if req.method() == Method::Options {
response.set_status(Status::Ok);
response.set_sized_body(None, Cursor::new(""))
}
}
}

View File

@ -1,5 +1,8 @@
use chrono::{DateTime, Utc};
use rocket::serde::Serialize;
use sqlx::FromRow;
#[derive(Serialize, FromRow)]
/// Users who buy VM's
pub struct User {
/// Unique ID of this user (database generated)
@ -10,11 +13,13 @@ pub struct User {
pub created: DateTime<Utc>,
}
#[derive(Serialize)]
/// The type of VM host
pub enum VmHostKind {
Proxmox,
}
#[derive(Serialize, FromRow)]
/// A VM host
pub struct VmHost {
pub id: u64,
@ -30,6 +35,7 @@ pub struct VmHost {
pub api_token: String,
}
#[derive(Serialize, FromRow)]
pub struct VmHostDisk {
pub id: u64,
pub host_id: u64,
@ -40,29 +46,34 @@ pub struct VmHostDisk {
pub enabled: bool,
}
#[derive(Serialize)]
pub enum DiskType {
HDD,
SSD,
}
#[derive(Serialize)]
pub enum DiskInterface {
SATA,
SCSI,
PCIe,
}
#[derive(Serialize, FromRow)]
pub struct VmOsImage {
pub id: u64,
pub name: String,
pub enabled: bool,
}
#[derive(Serialize, FromRow)]
pub struct IpRange {
pub id: u64,
pub cidr: String,
pub enabled: bool,
}
#[derive(Serialize, FromRow)]
pub struct Vm {
/// Unique VM ID (Same in proxmox)
pub id: u64,

View File

@ -1,16 +1,25 @@
extern crate core;
use crate::cors::CORS;
use crate::provisioner::Provisioner;
use crate::settings::Settings;
use anyhow::Error;
use config::{Config, File};
use log::error;
use rocket::routes;
use sqlx::MySqlPool;
mod api;
mod cors;
mod db;
mod nip98;
mod provisioner;
mod proxmox;
mod settings;
mod vm;
#[rocket::main]
async fn main() -> Result<(), anyhow::Error> {
async fn main() -> Result<(), Error> {
pretty_env_logger::init();
let config: Settings = Config::builder()
@ -20,7 +29,17 @@ async fn main() -> Result<(), anyhow::Error> {
let db = MySqlPool::connect(&config.db).await?;
sqlx::migrate!("./migrations").run(&db).await?;
let provisioner = Provisioner::new(db.clone());
let provisioner = Provisioner::new(db);
if let Err(e) = rocket::build()
.attach(CORS)
.manage(provisioner)
.mount("/", api::routes())
.launch()
.await
{
error!("{}", e);
}
Ok(())
}

92
src/nip98.rs Normal file
View File

@ -0,0 +1,92 @@
use base64::prelude::BASE64_STANDARD;
use base64::Engine;
use log::info;
use nostr::{Event, JsonUtil, Kind, Timestamp};
use rocket::http::uri::{Absolute, Uri};
use rocket::http::Status;
use rocket::request::{FromRequest, Outcome};
use rocket::{async_trait, Request};
pub struct Nip98Auth {
pub event: Event,
}
#[async_trait]
impl<'r> FromRequest<'r> for Nip98Auth {
type Error = &'static str;
async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
if let Some(auth) = request.headers().get_one("authorization") {
if auth.starts_with("Nostr ") {
let event = if let Ok(j) = BASE64_STANDARD.decode(&auth[6..]) {
if let Ok(ev) = Event::from_json(j) {
ev
} else {
return Outcome::Error((Status::new(403), "Invalid nostr event"));
}
} else {
return Outcome::Error((Status::new(403), "Invalid auth string"));
};
if event.kind != Kind::HttpAuth {
return Outcome::Error((Status::new(401), "Wrong event kind"));
}
if event
.created_at
.as_u64()
.abs_diff(Timestamp::now().as_u64())
> 600
{
return Outcome::Error((Status::new(401), "Created timestamp is out of range"));
}
// check url tag
if let Some(url) = event.tags.iter().find_map(|t| {
let vec = t.as_slice();
if vec[0] == "u" {
Some(vec[1].clone())
} else {
None
}
}) {
if let Ok(u_req) = Uri::parse::<Absolute>(&url) {
if request.uri().path() != u_req.absolute().unwrap().path() {
return Outcome::Error((Status::new(401), "U tag does not match"));
}
} else {
return Outcome::Error((Status::new(401), "Invalid U tag"));
}
} else {
return Outcome::Error((Status::new(401), "Missing url tag"));
}
// check method tag
if let Some(method) = event.tags.iter().find_map(|t| {
let vec = t.as_slice();
if vec[0] == "method" {
Some(vec[1].clone())
} else {
None
}
}) {
if request.method().to_string() != *method {
return Outcome::Error((Status::new(401), "Method tag incorrect"));
}
} else {
return Outcome::Error((Status::new(401), "Missing method tag"));
}
if let Err(_err) = event.verify() {
return Outcome::Error((Status::new(401), "Event signature invalid"));
}
info!("{}", event.as_json());
Outcome::Success(Nip98Auth { event })
} else {
Outcome::Error((Status::new(403), "Auth scheme must be Nostr"))
}
} else {
Outcome::Error((Status::new(403), "Auth header not found"))
}
}
}

View File

@ -1,8 +1,9 @@
use crate::db;
use crate::vm::VMSpec;
use anyhow::Error;
use sqlx::MySqlPool;
use sqlx::{MySqlPool, Row};
#[derive(Debug, Clone)]
pub struct Provisioner {
db: MySqlPool,
}
@ -16,4 +17,30 @@ impl Provisioner {
pub async fn provision(&self, spec: VMSpec) -> Result<db::Vm, Error> {
todo!()
}
/// Insert/Fetch user id
pub async fn upsert_user(&self, pubkey: &[u8; 32]) -> Result<u64, Error> {
let res = sqlx::query("insert ignore into users(pubkey) values(?) returning id")
.bind(pubkey.as_slice())
.fetch_optional(&self.db)
.await?;
match res {
None => sqlx::query("select id from users where pubkey = ?")
.bind(pubkey.as_slice())
.fetch_one(&self.db)
.await?
.try_get(0)
.map_err(Error::new),
Some(res) => res.try_get(0).map_err(Error::new),
}
}
/// List VM's owned by a specific user
pub async fn list_vms(&self, id: u64) -> Result<Vec<db::Vm>, Error> {
sqlx::query_as("select * from vm where user_id = ?")
.bind(&id)
.fetch_all(&self.db)
.await
.map_err(Error::new)
}
}