parent
13d0c9401e
commit
b9b14a7118
|
@ -807,9 +807,9 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "j_db"
|
name = "j_db"
|
||||||
version = "0.1.0"
|
version = "0.1.2"
|
||||||
source = "registry+https://git.jojodev.com/joeyahines/_cargo-index.git"
|
source = "registry+https://git.jojodev.com/joeyahines/_cargo-index.git"
|
||||||
checksum = "1243e6cadfd7e022fed3e9bc1f1465e84da7fb22bc149d8fddea3ccac07ce0b0"
|
checksum = "ae76696901f0cd9f850fe6608f4ce640c055444a2f453382fb7deda45a141b75"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"json",
|
"json",
|
||||||
|
@ -1148,17 +1148,21 @@ dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"axum",
|
"axum",
|
||||||
"axum-macros",
|
"axum-macros",
|
||||||
|
"base64",
|
||||||
|
"bitflags 2.4.2",
|
||||||
"chrono",
|
"chrono",
|
||||||
"chrono-tz",
|
"chrono-tz",
|
||||||
"config",
|
"config",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"hex",
|
"hex",
|
||||||
"j_db",
|
"j_db",
|
||||||
|
"json",
|
||||||
"log",
|
"log",
|
||||||
"multer",
|
"multer",
|
||||||
"rand",
|
"rand",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"sha2",
|
||||||
"structopt",
|
"structopt",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
|
|
|
@ -6,7 +6,7 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
j_db = { version = "0.1.0", registry = "jojo-dev" }
|
j_db = { version = "0.1.2", registry = "jojo-dev" }
|
||||||
axum-macros = "0.4.1"
|
axum-macros = "0.4.1"
|
||||||
serde = "1.0.195"
|
serde = "1.0.195"
|
||||||
config = "0.14.0"
|
config = "0.14.0"
|
||||||
|
@ -22,6 +22,10 @@ env_logger = "0.11.0"
|
||||||
multer = "3.0.0"
|
multer = "3.0.0"
|
||||||
serde_json = "1.0.111"
|
serde_json = "1.0.111"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
|
sha2 = "0.10.8"
|
||||||
|
bitflags = "2.4.2"
|
||||||
|
json = "0.12.4"
|
||||||
|
base64 = "0.21.7"
|
||||||
|
|
||||||
[dependencies.axum]
|
[dependencies.axum]
|
||||||
version = "0.7.4"
|
version = "0.7.4"
|
||||||
|
|
85
src/main.rs
85
src/main.rs
|
@ -24,14 +24,46 @@ use rand::thread_rng;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use base64::Engine;
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
|
use crate::model::api_key::{ApiKey, ApiPermissions};
|
||||||
|
|
||||||
type PicContext = Arc<Context>;
|
type PicContext = Arc<Context>;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(StructOpt, Debug, Clone)]
|
||||||
|
#[structopt(about = "PicOx Commands")]
|
||||||
|
enum SubCommands {
|
||||||
|
/// Start the PicOx server
|
||||||
|
Start,
|
||||||
|
/// Create a Picox API Key
|
||||||
|
CreateKey {
|
||||||
|
/// Key description
|
||||||
|
description: String,
|
||||||
|
/// API Key permissions (WRITE, DELETE)
|
||||||
|
permissions: ApiPermissions
|
||||||
|
},
|
||||||
|
/// Dump the database state to json
|
||||||
|
Dump {
|
||||||
|
/// Output path
|
||||||
|
out_path: PathBuf,
|
||||||
|
},
|
||||||
|
/// Import the database state from json
|
||||||
|
Import {
|
||||||
|
/// Path to json containing DB state
|
||||||
|
db_file: PathBuf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, StructOpt)]
|
#[derive(Debug, Clone, StructOpt)]
|
||||||
struct Args {
|
struct Args {
|
||||||
|
/// Path to the config file
|
||||||
|
#[structopt(short, long, env = "PICOX_CONFIG")]
|
||||||
pub config: PathBuf,
|
pub config: PathBuf,
|
||||||
|
#[structopt(subcommand)]
|
||||||
|
pub command: SubCommands
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
@ -275,14 +307,7 @@ async fn query_album(
|
||||||
Ok(Response(resp))
|
Ok(Response(resp))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
async fn run_picox(db: Database, config: PicOxConfig) {
|
||||||
async fn main() {
|
|
||||||
let args = Args::from_args();
|
|
||||||
|
|
||||||
let config = PicOxConfig::new(args.config);
|
|
||||||
|
|
||||||
let db = Database::new(&config.db_path).unwrap();
|
|
||||||
|
|
||||||
let store_manager = StorageManager::new(config.storage_config.clone());
|
let store_manager = StorageManager::new(config.storage_config.clone());
|
||||||
|
|
||||||
let context = Context {
|
let context = Context {
|
||||||
|
@ -293,9 +318,6 @@ async fn main() {
|
||||||
|
|
||||||
let context = Arc::new(context);
|
let context = Arc::new(context);
|
||||||
|
|
||||||
// initialize tracing
|
|
||||||
tracing_subscriber::fmt::init();
|
|
||||||
// build our application with a route
|
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
// `GET /` goes to `root`
|
// `GET /` goes to `root`
|
||||||
.route("/api/album/create", post(create_album))
|
.route("/api/album/create", post(create_album))
|
||||||
|
@ -306,8 +328,47 @@ async fn main() {
|
||||||
.route("/api/image/", get(query_images))
|
.route("/api/image/", get(query_images))
|
||||||
.with_state(context);
|
.with_state(context);
|
||||||
|
|
||||||
// run our app with hyper, listening globally on port 3000
|
|
||||||
let listener = tokio::net::TcpListener::bind(&config.host).await.unwrap();
|
let listener = tokio::net::TcpListener::bind(&config.host).await.unwrap();
|
||||||
info!("Serving at {}", config.host);
|
info!("Serving at {}", config.host);
|
||||||
axum::serve(listener, app).await.unwrap();
|
axum::serve(listener, app).await.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
let args = Args::from_args();
|
||||||
|
|
||||||
|
// initialize tracing
|
||||||
|
tracing_subscriber::fmt::init();
|
||||||
|
|
||||||
|
let config = PicOxConfig::new(args.config);
|
||||||
|
|
||||||
|
let db = Database::new(&config.db_path).unwrap();
|
||||||
|
|
||||||
|
match args.command {
|
||||||
|
SubCommands::Start => {
|
||||||
|
run_picox(db, config).await;
|
||||||
|
}
|
||||||
|
SubCommands::CreateKey { description, permissions } => {
|
||||||
|
let (token, api_key) = ApiKey::create_new_key(&db, description, permissions).unwrap();
|
||||||
|
|
||||||
|
info!("New Key info: {:?}", api_key);
|
||||||
|
info!("Token: {}", base64::prelude::BASE64_STANDARD.encode(token));
|
||||||
|
db.db.flush().unwrap();
|
||||||
|
}
|
||||||
|
SubCommands::Dump {out_path} => {
|
||||||
|
info!("Dumping database state to {:?}", out_path);
|
||||||
|
|
||||||
|
tokio::fs::write(out_path, db.dump_db().unwrap().pretty(4)).await.unwrap();
|
||||||
|
}
|
||||||
|
SubCommands::Import { db_file } => {
|
||||||
|
info!("Importing database state from {:?}", db_file);
|
||||||
|
let db_state = tokio::fs::read(db_file).await.unwrap();
|
||||||
|
let db_state = String::from_utf8(db_state).unwrap();
|
||||||
|
let db_state = json::parse(&db_state).unwrap();
|
||||||
|
|
||||||
|
db.import_db(db_state).unwrap();
|
||||||
|
db.db.flush().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
use std::str::FromStr;
|
||||||
|
use base64::Engine;
|
||||||
|
use j_db::database::Database;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use bitflags::bitflags;
|
||||||
|
use rand::RngCore;
|
||||||
|
use sha2::Digest;
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
pub struct ApiPermissions: u32 {
|
||||||
|
const WRITE = 0b00000001;
|
||||||
|
const DELETE = 0b00000010;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for ApiPermissions {
|
||||||
|
type Err = bitflags::parser::ParseError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
bitflags::parser::from_str(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
pub struct ApiKey {
|
||||||
|
pub token_hash: String,
|
||||||
|
pub description: String,
|
||||||
|
pub permissions: ApiPermissions,
|
||||||
|
|
||||||
|
id: Option<u64>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ApiKey {
|
||||||
|
pub fn create_new_key(db: &Database, description: String, permissions: ApiPermissions) -> Result<(Vec<u8>, ApiKey), j_db::error::JDbError>{
|
||||||
|
let mut key = [0u8; 32];
|
||||||
|
rand::thread_rng().fill_bytes(&mut key);
|
||||||
|
|
||||||
|
let hash = sha2::Sha256::digest(key);
|
||||||
|
|
||||||
|
let api_key = ApiKey {
|
||||||
|
token_hash: base64::prelude::BASE64_STANDARD.encode(&hash),
|
||||||
|
description,
|
||||||
|
permissions,
|
||||||
|
id: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let api_key = db.insert(api_key)?;
|
||||||
|
|
||||||
|
Ok((key.to_vec(), api_key))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl j_db::model::JdbModel for ApiKey {
|
||||||
|
fn id(&self) -> Option<u64> {
|
||||||
|
self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_id(&mut self, id: u64) {
|
||||||
|
self.id = Some(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tree() -> String {
|
||||||
|
"ApiKey".to_string()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,2 +1,3 @@
|
||||||
pub mod album;
|
pub mod album;
|
||||||
pub mod image;
|
pub mod image;
|
||||||
|
pub mod api_key;
|
||||||
|
|
Loading…
Reference in New Issue