move folder

This commit is contained in:
2022-01-02 23:46:08 +01:00
parent 835f7df0f6
commit a0732a4593
58 changed files with 73 additions and 83 deletions

2126
backend/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

24
backend/Cargo.toml Normal file
View File

@@ -0,0 +1,24 @@
[package]
name = "cryptgeon"
version = "1.3.2"
authors = ["cupcakearmy <hi@nicco.io>"]
edition = "2021"
[[bin]]
name = "cryptgeon"
path = "src/main.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
actix-web = "3"
actix-files = "0.5"
serde = "1"
serde_json = "1"
lazy_static = "1"
ring = "0.16"
bs62 = "0.1"
memcache = "0.16"
byte-unit = "4"
dotenv = "0.15"
mime = "0.3"

10
backend/src/client.rs Normal file
View File

@@ -0,0 +1,10 @@
use actix_files::{Files, NamedFile};
use actix_web::{web, Responder};
pub fn init(cfg: &mut web::ServiceConfig) {
cfg.service(Files::new("/", "./frontend/build").index_file("index.html"));
}
pub async fn fallback_fn() -> impl Responder {
NamedFile::open("./frontend/build/index.html")
}

27
backend/src/main.rs Normal file
View File

@@ -0,0 +1,27 @@
use actix_web::{middleware, web, App, HttpServer};
use dotenv::dotenv;
#[macro_use]
extern crate lazy_static;
mod client;
mod note;
mod size;
mod store;
#[actix_web::main]
async fn main() -> std::io::Result<()> {
dotenv().ok();
return HttpServer::new(|| {
App::new()
.wrap(middleware::Compress::default())
.wrap(middleware::DefaultHeaders::default())
.configure(size::init)
.configure(note::init)
.configure(client::init)
.default_service(web::resource("").route(web::get().to(client::fallback_fn)))
})
.bind("0.0.0.0:5000")?
.run()
.await;
}

5
backend/src/note/mod.rs Normal file
View File

@@ -0,0 +1,5 @@
mod model;
mod routes;
pub use model::*;
pub use routes::*;

27
backend/src/note/model.rs Normal file
View File

@@ -0,0 +1,27 @@
use bs62;
use ring::rand::SecureRandom;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone)]
pub struct Note {
pub meta: String,
pub contents: String,
pub views: Option<u8>,
pub expiration: Option<u32>,
}
#[derive(Serialize, Deserialize, Clone)]
pub struct NoteInfo {}
#[derive(Serialize, Deserialize, Clone)]
pub struct NotePublic {
pub meta: String,
pub contents: String,
}
pub fn generate_id() -> String {
let mut id: [u8; 32] = [0; 32];
let sr = ring::rand::SystemRandom::new();
let _ = sr.fill(&mut id);
return bs62::encode_data(&id);
}

137
backend/src/note/routes.rs Normal file
View File

@@ -0,0 +1,137 @@
use actix_web::{delete, get, post, web, HttpResponse, Responder};
use serde::{Deserialize, Serialize};
use std::time::SystemTime;
use crate::note::{generate_id, Note, NoteInfo, NotePublic};
use crate::size::LIMIT;
use crate::store;
pub fn now() -> u32 {
SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_secs() as u32
}
#[derive(Serialize, Deserialize)]
struct NotePath {
id: String,
}
#[get("/{id}")]
async fn one(path: web::Path<NotePath>) -> impl Responder {
let p = path.into_inner();
let note = store::get(&p.id);
match note {
None => return HttpResponse::NotFound().finish(),
Some(_) => return HttpResponse::Ok().json(NoteInfo {}),
}
}
#[derive(Serialize, Deserialize)]
struct CreateResponse {
id: String,
}
#[post("/")]
async fn create(note: web::Json<Note>) -> impl Responder {
let mut n = note.into_inner();
let id = generate_id();
let bad_req = HttpResponse::BadRequest().finish();
if n.views == None && n.expiration == None {
return bad_req;
}
match n.views {
Some(v) => {
if v > 100 {
return bad_req;
}
}
_ => {}
}
match n.expiration {
Some(e) => {
if e > 360 {
return bad_req;
}
let expiration = now() + (e * 60);
n.expiration = Some(expiration);
}
_ => {}
}
store::set(&id.clone(), &n.clone());
return HttpResponse::Ok().json(CreateResponse { id: id });
}
#[delete("/{id}")]
async fn delete(path: web::Path<NotePath>) -> impl Responder {
let p = path.into_inner();
let note = store::get(&p.id);
match note {
None => return HttpResponse::NotFound().finish(),
Some(note) => {
let mut changed = note.clone();
if changed.views == None && changed.expiration == None {
return HttpResponse::BadRequest().finish();
}
match changed.views {
Some(v) => {
changed.views = Some(v - 1);
let id = p.id.clone();
if v <= 1 {
store::del(&id);
} else {
store::set(&id, &changed.clone());
}
}
_ => {}
}
let n = now();
match changed.expiration {
Some(e) => {
if e < n {
store::del(&p.id.clone());
return HttpResponse::BadRequest().finish();
}
}
_ => {}
}
return HttpResponse::Ok().json(NotePublic {
contents: changed.contents,
meta: changed.meta,
});
}
}
}
#[derive(Serialize, Deserialize)]
struct Status {
version: String,
max_size: usize,
}
#[get("/status")]
async fn status() -> impl Responder {
println!("Limit: {}", *LIMIT);
return HttpResponse::Ok().json(Status {
version: option_env!("CARGO_PKG_VERSION")
.unwrap_or("Unknown")
.to_string(),
max_size: *LIMIT,
});
}
pub fn init(cfg: &mut web::ServiceConfig) {
cfg.service(
web::scope("/api")
.service(
web::scope("/notes")
.service(one)
.service(create)
.service(delete)
.service(status),
)
.service(status),
);
}

20
backend/src/size.rs Normal file
View File

@@ -0,0 +1,20 @@
use actix_web::web;
use byte_unit::Byte;
use mime;
lazy_static! {
pub static ref LIMIT: usize =
Byte::from_str(std::env::var("SIZE_LIMIT").unwrap_or("1 KiB".to_string()))
.unwrap()
.get_bytes() as usize;
}
pub fn init(cfg: &mut web::ServiceConfig) {
println!("Limit: {}", *LIMIT);
let json = web::JsonConfig::default().limit(*LIMIT);
let plain = web::PayloadConfig::default()
.limit(*LIMIT)
.mimetype(mime::STAR_STAR);
cfg.data(json);
cfg.data(plain);
}

36
backend/src/store.rs Normal file
View File

@@ -0,0 +1,36 @@
use memcache;
use crate::note::now;
use crate::note::Note;
lazy_static! {
static ref CLIENT: memcache::Client = memcache::connect(format!(
"memcache://{}?timeout=10&tcp_nodelay=true",
std::env::var("MEMCACHE").unwrap_or("127.0.0.1:11211".to_string())
))
.unwrap();
}
pub fn set(id: &String, note: &Note) {
let serialized = serde_json::to_string(&note.clone()).unwrap();
let expiration: u32 = match note.expiration {
Some(e) => e - now(),
None => 0,
};
CLIENT.set(id, serialized, expiration).unwrap();
}
pub fn get(id: &String) -> Option<Note> {
let value: Option<String> = CLIENT.get(&id).unwrap();
match value {
None => return None,
Some(s) => {
let deserialize: Note = serde_json::from_str(&s).unwrap();
return Some(deserialize);
}
}
}
pub fn del(id: &String) {
CLIENT.delete(id).unwrap();
}