Compare commits
5 Commits
debc8625fc
...
b759b8e00b
Author | SHA1 | Date | |
---|---|---|---|
b759b8e00b | |||
803ffae22c | |||
49a56f13ba | |||
07f7917152 | |||
35ca28316d |
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,3 +5,4 @@ db.db3
|
|||||||
cert.pem
|
cert.pem
|
||||||
key.rsa
|
key.rsa
|
||||||
content/
|
content/
|
||||||
|
.DS_Store
|
1681
api/Cargo.lock
generated
1681
api/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -7,12 +7,12 @@ edition = "2018"
|
|||||||
# 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]
|
||||||
rocket = "0.4.8"
|
rocket = { version = "=0.5.0-rc.3", features = ["json"] }
|
||||||
rocket_contrib = "0.4.6"
|
jsonwebtoken = "8.3.0"
|
||||||
jsonwebtoken = "7.2"
|
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
flate2 = "1.0.19"
|
flate2 = "1.0.19"
|
||||||
tar = "0.4.30"
|
tar = "0.4.30"
|
||||||
base64 = "0.13.0"
|
base64 = "0.13.0"
|
||||||
rusqlite = "0.24.2"
|
rusqlite = "0.29.0"
|
||||||
uuid = { version = "0.8", features = ["v4"] }
|
uuid = { version = "0.8", features = ["v4"] }
|
||||||
|
ubyte = "0.10.3"
|
||||||
|
@ -1,13 +1,9 @@
|
|||||||
// Copyright (c) 2021, Will Webberley. See LICENSE.
|
// Copyright (c) 2021, Will Webberley. See LICENSE.
|
||||||
|
|
||||||
#![feature(proc_macro_hygiene, decl_macro)]
|
use std::{env, str, fs::{self, File}, time::{SystemTime, UNIX_EPOCH}, io::Write, collections::HashSet};
|
||||||
#[macro_use] extern crate rocket_contrib;
|
use rocket::{self, routes, post, put, get, launch, config::Config, response::Responder, request::{Request, FromRequest, Outcome}, data::{Limits, ToByteUnit}, http::Status, serde::json::{json, Json, Value}};
|
||||||
|
|
||||||
use std::{env, str, fs::{self, File}, time::{SystemTime, UNIX_EPOCH}, io::Write};
|
|
||||||
use rocket::{self, routes, get, post, put, config::{Config, Limits}, response::Responder, request::{self, Request, FromRequest}, Outcome, http::Status};
|
|
||||||
use rocket_contrib::json::{Json, JsonValue};
|
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use jsonwebtoken::{self, encode, decode, Header, Validation, EncodingKey, DecodingKey};
|
use jsonwebtoken::{self, encode, decode, Header, Validation, EncodingKey, DecodingKey, Algorithm};
|
||||||
use rusqlite::{params, Connection};
|
use rusqlite::{params, Connection};
|
||||||
use flate2::read::GzDecoder;
|
use flate2::read::GzDecoder;
|
||||||
use tar::Archive;
|
use tar::Archive;
|
||||||
@ -73,10 +69,9 @@ fn generate_access_token(capsule_id: &str) -> Result<String> {
|
|||||||
// Verify the access JWT token, and checks still valid in DB. Returns the authenticated capsule.
|
// Verify the access JWT token, and checks still valid in DB. Returns the authenticated capsule.
|
||||||
fn validate_access_token(token: &str) -> Result<AuthenticatedCapsule> {
|
fn validate_access_token(token: &str) -> Result<AuthenticatedCapsule> {
|
||||||
// Validate the token integrity itself
|
// Validate the token integrity itself
|
||||||
let my_validation = Validation {
|
let mut my_validation = Validation::new(Algorithm::HS256);
|
||||||
validate_exp: false,
|
my_validation.validate_exp = false;
|
||||||
..Default::default()
|
my_validation.required_spec_claims = HashSet::new();
|
||||||
};
|
|
||||||
let claims = decode::<Claims>(&token, &DecodingKey::from_secret(get_jwt_secret().as_ref()), &my_validation)?.claims;
|
let claims = decode::<Claims>(&token, &DecodingKey::from_secret(get_jwt_secret().as_ref()), &my_validation)?.claims;
|
||||||
|
|
||||||
// Verify the token in the DB and retrieve the capsule info
|
// Verify the token in the DB and retrieve the capsule info
|
||||||
@ -96,13 +91,13 @@ fn validate_access_token(token: &str) -> Result<AuthenticatedCapsule> {
|
|||||||
#[derive(Responder)]
|
#[derive(Responder)]
|
||||||
enum Resp {
|
enum Resp {
|
||||||
#[response(status = 200)]
|
#[response(status = 200)]
|
||||||
Ok(JsonValue),
|
Ok(Value),
|
||||||
#[response(status = 500)]
|
#[response(status = 500)]
|
||||||
InternalServerError(JsonValue),
|
InternalServerError(Value),
|
||||||
#[response(status = 400)]
|
#[response(status = 400)]
|
||||||
BadRequest(JsonValue),
|
BadRequest(Value),
|
||||||
#[response(status = 404)]
|
#[response(status = 404)]
|
||||||
NotFound(JsonValue),
|
NotFound(Value),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/")]
|
#[get("/")]
|
||||||
@ -204,10 +199,11 @@ enum ApiTokenError {
|
|||||||
Missing,
|
Missing,
|
||||||
Invalid,
|
Invalid,
|
||||||
}
|
}
|
||||||
impl<'a, 'r> FromRequest<'a, 'r> for AuthenticatedCapsule {
|
#[rocket::async_trait]
|
||||||
|
impl<'r> FromRequest<'r> for AuthenticatedCapsule {
|
||||||
type Error = ApiTokenError;
|
type Error = ApiTokenError;
|
||||||
fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
|
async fn from_request(req: &'r Request<'_>) -> Outcome<Self, Self::Error> {
|
||||||
let keys: Vec<_> = request.headers().get("api-key").collect();
|
let keys: Vec<_> = req.headers().get("api-key").collect();
|
||||||
match keys.len() {
|
match keys.len() {
|
||||||
0 => Outcome::Failure((Status::BadRequest, ApiTokenError::Missing)),
|
0 => Outcome::Failure((Status::BadRequest, ApiTokenError::Missing)),
|
||||||
1 => {
|
1 => {
|
||||||
@ -267,14 +263,39 @@ fn deploy_capsule(capsule: Json<CapsuleDeployRequest>, authenticated_capsule: Au
|
|||||||
return Resp::Ok(json!({"message": "Your capsule was deployed", "url": url}));
|
return Resp::Ok(json!({"message": "Your capsule was deployed", "url": url}));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
#[derive(Serialize)]
|
||||||
|
struct CapsuleViewLog {
|
||||||
|
path: String,
|
||||||
|
timestamp: i32,
|
||||||
|
}
|
||||||
|
#[get("/logs")]
|
||||||
|
fn get_logs(authenticated_capsule: AuthenticatedCapsule) -> Resp {
|
||||||
|
let conn = match get_db() {
|
||||||
|
Ok(c) => c,
|
||||||
|
Err(_) => return Resp::InternalServerError(json!({"message": "Database problem"})),
|
||||||
|
};
|
||||||
|
let mut stmt = conn
|
||||||
|
.prepare("SELECT path, timestamp FROM view WHERE capsule_id = ?1 ORDER BY timestamp DESC LIMIT 100")
|
||||||
|
.unwrap();
|
||||||
|
let view_results = stmt.query_map(params![authenticated_capsule.id], |row| {
|
||||||
|
Ok(CapsuleViewLog {
|
||||||
|
path: row.get(0)?,
|
||||||
|
timestamp: row.get(1)?,
|
||||||
|
})
|
||||||
|
}).unwrap();
|
||||||
|
let views: Vec<CapsuleViewLog> = view_results.map(|view| view.unwrap()).collect();
|
||||||
|
return Resp::Ok(json!({"logs": &views}));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[launch]
|
||||||
|
fn rocket() -> _ {
|
||||||
// Create needed directories
|
// Create needed directories
|
||||||
fs::create_dir_all(CAPSULE_DIR).unwrap_or_default();
|
fs::create_dir_all(CAPSULE_DIR).unwrap_or_default();
|
||||||
|
|
||||||
// Initialise and launch Rocket
|
// Initialise and launch Rocket
|
||||||
let mut my_config = Config::active().unwrap();
|
let mut my_config = Config::default();
|
||||||
my_config.set_port(9000);
|
my_config.port = 9000;
|
||||||
my_config.set_limits(Limits::new().limit("json", 50 * 1024 * 1024)); // 50MB
|
my_config.limits = Limits::new().limit("json", 50.megabytes()); // 50MB
|
||||||
let app = rocket::custom(my_config);
|
let app = rocket::custom(my_config);
|
||||||
app.mount("/", routes![index, create_capsule, deploy_capsule]).launch();
|
app.mount("/", routes![index, create_capsule, deploy_capsule, get_logs])
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user