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
|
||||
key.rsa
|
||||
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
|
||||
|
||||
[dependencies]
|
||||
rocket = "0.4.8"
|
||||
rocket_contrib = "0.4.6"
|
||||
jsonwebtoken = "7.2"
|
||||
rocket = { version = "=0.5.0-rc.3", features = ["json"] }
|
||||
jsonwebtoken = "8.3.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
flate2 = "1.0.19"
|
||||
tar = "0.4.30"
|
||||
base64 = "0.13.0"
|
||||
rusqlite = "0.24.2"
|
||||
rusqlite = "0.29.0"
|
||||
uuid = { version = "0.8", features = ["v4"] }
|
||||
ubyte = "0.10.3"
|
||||
|
@ -1,13 +1,9 @@
|
||||
// Copyright (c) 2021, Will Webberley. See LICENSE.
|
||||
|
||||
#![feature(proc_macro_hygiene, decl_macro)]
|
||||
#[macro_use] extern crate rocket_contrib;
|
||||
|
||||
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 std::{env, str, fs::{self, File}, time::{SystemTime, UNIX_EPOCH}, io::Write, collections::HashSet};
|
||||
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 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 flate2::read::GzDecoder;
|
||||
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.
|
||||
fn validate_access_token(token: &str) -> Result<AuthenticatedCapsule> {
|
||||
// Validate the token integrity itself
|
||||
let my_validation = Validation {
|
||||
validate_exp: false,
|
||||
..Default::default()
|
||||
};
|
||||
let mut my_validation = Validation::new(Algorithm::HS256);
|
||||
my_validation.validate_exp = false;
|
||||
my_validation.required_spec_claims = HashSet::new();
|
||||
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
|
||||
@ -96,13 +91,13 @@ fn validate_access_token(token: &str) -> Result<AuthenticatedCapsule> {
|
||||
#[derive(Responder)]
|
||||
enum Resp {
|
||||
#[response(status = 200)]
|
||||
Ok(JsonValue),
|
||||
Ok(Value),
|
||||
#[response(status = 500)]
|
||||
InternalServerError(JsonValue),
|
||||
InternalServerError(Value),
|
||||
#[response(status = 400)]
|
||||
BadRequest(JsonValue),
|
||||
BadRequest(Value),
|
||||
#[response(status = 404)]
|
||||
NotFound(JsonValue),
|
||||
NotFound(Value),
|
||||
}
|
||||
|
||||
#[get("/")]
|
||||
@ -204,10 +199,11 @@ enum ApiTokenError {
|
||||
Missing,
|
||||
Invalid,
|
||||
}
|
||||
impl<'a, 'r> FromRequest<'a, 'r> for AuthenticatedCapsule {
|
||||
#[rocket::async_trait]
|
||||
impl<'r> FromRequest<'r> for AuthenticatedCapsule {
|
||||
type Error = ApiTokenError;
|
||||
fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
|
||||
let keys: Vec<_> = request.headers().get("api-key").collect();
|
||||
async fn from_request(req: &'r Request<'_>) -> Outcome<Self, Self::Error> {
|
||||
let keys: Vec<_> = req.headers().get("api-key").collect();
|
||||
match keys.len() {
|
||||
0 => Outcome::Failure((Status::BadRequest, ApiTokenError::Missing)),
|
||||
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}));
|
||||
}
|
||||
|
||||
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
|
||||
fs::create_dir_all(CAPSULE_DIR).unwrap_or_default();
|
||||
|
||||
// Initialise and launch Rocket
|
||||
let mut my_config = Config::active().unwrap();
|
||||
my_config.set_port(9000);
|
||||
my_config.set_limits(Limits::new().limit("json", 50 * 1024 * 1024)); // 50MB
|
||||
let mut my_config = Config::default();
|
||||
my_config.port = 9000;
|
||||
my_config.limits = Limits::new().limit("json", 50.megabytes()); // 50MB
|
||||
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