Web API, Web UI #86
|
@ -260,6 +260,12 @@ version = "0.2.8"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.13.0"
|
||||
|
@ -331,7 +337,7 @@ version = "1.2.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38b6553abdb9d2d8f262f0b5bccf807321d5b7d1a12796bcede8e1f150e85f2e"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"base64 0.13.0",
|
||||
"chrono",
|
||||
"hex",
|
||||
"lazy_static",
|
||||
|
@ -994,9 +1000,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "generator"
|
||||
version = "0.7.0"
|
||||
version = "0.6.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1d9279ca822891c1a4dae06d185612cf8fc6acfe5dff37781b41297811b12ee"
|
||||
checksum = "061d3be1afec479d56fa3bd182bf966c7999ec175fcfdb87ac14d417241366c6"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
|
@ -1463,10 +1469,24 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jsonwebtoken"
|
||||
version = "7.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afabcc15e437a6484fc4f12d0fd63068fe457bf93f1c148d3d9649c60b103f32"
|
||||
dependencies = [
|
||||
"base64 0.12.3",
|
||||
"pem",
|
||||
"ring",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"simple_asn1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "juniper"
|
||||
version = "0.15.6"
|
||||
source = "git+https://github.com/graphql-rust/juniper?branch=master#ae199387fcf3a46888ef8464acb6011a149268c1"
|
||||
version = "0.15.5"
|
||||
source = "git+https://github.com/graphql-rust/juniper?branch=master#84a07c4a93f96d4352a9a6a23732c46eae486be6"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bson",
|
||||
|
@ -1486,8 +1506,8 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "juniper_codegen"
|
||||
version = "0.15.6"
|
||||
source = "git+https://github.com/graphql-rust/juniper?branch=master#ae199387fcf3a46888ef8464acb6011a149268c1"
|
||||
version = "0.15.5"
|
||||
source = "git+https://github.com/graphql-rust/juniper?branch=master#84a07c4a93f96d4352a9a6a23732c46eae486be6"
|
||||
dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
|
@ -1498,7 +1518,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "juniper_rocket_async"
|
||||
version = "0.5.1"
|
||||
source = "git+https://github.com/graphql-rust/juniper?branch=master#ae199387fcf3a46888ef8464acb6011a149268c1"
|
||||
source = "git+https://github.com/graphql-rust/juniper?branch=master#84a07c4a93f96d4352a9a6a23732c46eae486be6"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"juniper",
|
||||
|
@ -1568,11 +1588,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "loom"
|
||||
version = "0.5.0"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7aa5348dc45fa5f2419b6dd4ea20345e6b01b1fcc9d176a322eada1ac3f382ba"
|
||||
checksum = "a0e8460f2f2121162705187214720353c517b97bdfb3494c0b1e33d83ebe4bed"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if 0.1.10",
|
||||
"generator",
|
||||
"scoped-tls",
|
||||
"serde",
|
||||
|
@ -1713,7 +1733,7 @@ dependencies = [
|
|||
"aes-ctr",
|
||||
"aes-gcm",
|
||||
"atomic",
|
||||
"base64",
|
||||
"base64 0.13.0",
|
||||
"byteorder",
|
||||
"dashmap",
|
||||
"futures",
|
||||
|
@ -1868,6 +1888,17 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.44"
|
||||
|
@ -2036,6 +2067,17 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pem"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd56cbd21fea48d0c440b41cd69c589faacade08c992d9a54e471b79d0fd13eb"
|
||||
dependencies = [
|
||||
"base64 0.13.0",
|
||||
"once_cell",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.1.0"
|
||||
|
@ -2526,7 +2568,7 @@ version = "0.11.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2296f2fac53979e8ccbc4a1136b25dcefd37be9ed7e4a1f6b05a6029c84ff124"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"base64 0.13.0",
|
||||
"bytes",
|
||||
"encoding_rs",
|
||||
"futures-core",
|
||||
|
@ -2572,7 +2614,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "rocket"
|
||||
version = "0.5.0-dev"
|
||||
source = "git+https://github.com/SergioBenitez/Rocket?branch=master#7595450adc1aa3892004f02b606706597eb924e9"
|
||||
source = "git+https://github.com/SergioBenitez/Rocket?branch=master#0d53e23bf6cb86f9136fa8b37a92ba8076aacf67"
|
||||
dependencies = [
|
||||
"async-stream",
|
||||
"async-trait",
|
||||
|
@ -2595,6 +2637,7 @@ dependencies = [
|
|||
"rocket_codegen",
|
||||
"rocket_http",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"state",
|
||||
"tempfile",
|
||||
"time 0.2.26",
|
||||
|
@ -2609,7 +2652,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "rocket_codegen"
|
||||
version = "0.5.0-dev"
|
||||
source = "git+https://github.com/SergioBenitez/Rocket?branch=master#7595450adc1aa3892004f02b606706597eb924e9"
|
||||
source = "git+https://github.com/SergioBenitez/Rocket?branch=master#0d53e23bf6cb86f9136fa8b37a92ba8076aacf67"
|
||||
dependencies = [
|
||||
"devise",
|
||||
"glob",
|
||||
|
@ -2624,7 +2667,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "rocket_cors"
|
||||
version = "0.5.2"
|
||||
source = "git+https://git.agnos.is/projectmoon/rocket_cors?branch=sync-rocket-version#a25ba220140030e4553936a8ae130af0d89318dd"
|
||||
source = "git+https://git.agnos.is/projectmoon/rocket_cors?branch=sync-rocket-version#acd524db2594b6117160d78983941bc52db69a28"
|
||||
dependencies = [
|
||||
"log",
|
||||
"regex",
|
||||
|
@ -2639,7 +2682,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "rocket_http"
|
||||
version = "0.5.0-dev"
|
||||
source = "git+https://github.com/SergioBenitez/Rocket?branch=master#7595450adc1aa3892004f02b606706597eb924e9"
|
||||
source = "git+https://github.com/SergioBenitez/Rocket?branch=master#0d53e23bf6cb86f9136fa8b37a92ba8076aacf67"
|
||||
dependencies = [
|
||||
"cookie",
|
||||
"either",
|
||||
|
@ -2861,7 +2904,7 @@ version = "0.7.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7007ae39c0ae535438e5b8047e89d50d5dc1f0d6ed0f8c19c54c8ad1d814817"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"base64 0.13.0",
|
||||
"ring",
|
||||
"ruma-identifiers",
|
||||
"ruma-serde",
|
||||
|
@ -2891,7 +2934,7 @@ version = "0.8.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"base64 0.13.0",
|
||||
"blake2b_simd",
|
||||
"constant_time_eq",
|
||||
"crossbeam-utils",
|
||||
|
@ -3086,6 +3129,17 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "simple_asn1"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "692ca13de57ce0613a363c8c2f1de925adebc81b04c923ac60c5488bb44abe4b"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "0.3.5"
|
||||
|
@ -3270,9 +3324,8 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "state"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b54c22963194db84a59ee48e1fa9ed6c1fa9909ad5db92a700aa6fe956d632b"
|
||||
version = "0.4.2"
|
||||
source = "git+https://github.com/SergioBenitez/state.git?rev=8f94dc#8f94dce673b7d4b0e7b96c808a84f5e2a4be4a60"
|
||||
dependencies = [
|
||||
"loom",
|
||||
]
|
||||
|
@ -3440,12 +3493,15 @@ dependencies = [
|
|||
name = "tenebrous-api"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"jsonwebtoken",
|
||||
"juniper",
|
||||
"juniper_rocket_async",
|
||||
"log",
|
||||
"prost",
|
||||
"rocket",
|
||||
"rocket_cors",
|
||||
"serde",
|
||||
"tenebrous-rpc",
|
||||
"tonic",
|
||||
"tracing-subscriber",
|
||||
|
@ -3691,7 +3747,7 @@ checksum = "2ac42cd97ac6bd2339af5bcabf105540e21e45636ec6fa6aae5e85d44db31be0"
|
|||
dependencies = [
|
||||
"async-stream",
|
||||
"async-trait",
|
||||
"base64",
|
||||
"base64 0.13.0",
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
|
|
|
@ -9,8 +9,11 @@ log = "0.4"
|
|||
tracing-subscriber = "0.2"
|
||||
tonic = { version = "0.4" }
|
||||
prost = "0.7"
|
||||
jsonwebtoken = "7.2"
|
||||
chrono = "0.4"
|
||||
serde = {version = "1.0", features = ["derive"] }
|
||||
tenebrous-rpc = { path = "../rpc" }
|
||||
juniper = { git = "https://github.com/graphql-rust/juniper", branch = "master" }
|
||||
juniper_rocket_async = { git = "https://github.com/graphql-rust/juniper", branch = "master" }
|
||||
rocket = { git = "https://github.com/SergioBenitez/Rocket", branch = "master" }
|
||||
rocket = { git = "https://github.com/SergioBenitez/Rocket", branch = "master", features = ["json"] }
|
||||
rocket_cors = { git = "https://github.com/lawliet89/rocket_cors", branch = "master" }
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
use crate::config::{create_config, Config};
|
||||
use crate::schema::{self, Context, Schema};
|
||||
use log::info;
|
||||
use rocket::http::Method;
|
||||
use rocket::serde::{json::Json, Deserialize};
|
||||
use rocket::{response::content, Rocket, State};
|
||||
use rocket_cors::AllowedOrigins;
|
||||
use std::env;
|
||||
use tracing_subscriber::filter::EnvFilter;
|
||||
|
||||
#[rocket::get("/")]
|
||||
fn graphiql() -> content::Html<String> {
|
||||
juniper_rocket_async::graphiql_source("/graphql", None)
|
||||
}
|
||||
|
||||
#[rocket::get("/graphql?<request>")]
|
||||
async fn get_graphql_handler(
|
||||
context: &State<Context>,
|
||||
request: juniper_rocket_async::GraphQLRequest,
|
||||
schema: &State<Schema>,
|
||||
) -> juniper_rocket_async::GraphQLResponse {
|
||||
request.execute(&*schema, &*context).await
|
||||
}
|
||||
|
||||
#[rocket::post("/graphql", data = "<request>")]
|
||||
async fn post_graphql_handler(
|
||||
context: &State<Context>,
|
||||
request: juniper_rocket_async::GraphQLRequest,
|
||||
schema: &State<Schema>,
|
||||
) -> juniper_rocket_async::GraphQLResponse {
|
||||
request.execute(&*schema, &*context).await
|
||||
}
|
||||
|
||||
pub async fn run() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let filter = if env::var("RUST_LOG").is_ok() {
|
||||
EnvFilter::from_default_env()
|
||||
} else {
|
||||
EnvFilter::new("tenebrous_api=info,tonic=info,rocket=info,rocket_cors=info")
|
||||
};
|
||||
|
||||
tracing_subscriber::fmt().with_env_filter(filter).init();
|
||||
|
||||
log::info!("Setting up gRPC connection");
|
||||
let rocket = Rocket::build();
|
||||
let config = create_config(&rocket);
|
||||
|
||||
info!("Allowed CORS origins: {}", config.allowed_origins.join(","));
|
||||
|
||||
//TODO move to config
|
||||
let client = tenebrous_rpc::create_client("http://localhost:9090", "abc123").await?;
|
||||
|
||||
let context = Context {
|
||||
dicebot_client: client,
|
||||
};
|
||||
|
||||
let schema = schema::schema();
|
||||
|
||||
let allowed_origins = AllowedOrigins::some_exact(&config.allowed_origins);
|
||||
|
||||
let cors = rocket_cors::CorsOptions {
|
||||
allowed_origins,
|
||||
allowed_methods: vec![Method::Get, Method::Post]
|
||||
.into_iter()
|
||||
.map(From::from)
|
||||
.collect(),
|
||||
allow_credentials: true,
|
||||
..Default::default()
|
||||
}
|
||||
.to_cors()?;
|
||||
|
||||
let routes: Vec<rocket::Route> = {
|
||||
rocket::routes![graphiql, get_graphql_handler, post_graphql_handler]
|
||||
.into_iter()
|
||||
.chain(crate::auth::routes().into_iter())
|
||||
.collect()
|
||||
};
|
||||
|
||||
rocket
|
||||
.mount("/", routes)
|
||||
.attach(cors)
|
||||
.manage(context)
|
||||
.manage(schema)
|
||||
.manage(config)
|
||||
.launch()
|
||||
.await
|
||||
.expect("server to launch");
|
||||
Ok(())
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
use crate::config::Config;
|
||||
use chrono::{Duration, Utc};
|
||||
use jsonwebtoken::{decode, encode, Algorithm, DecodingKey, EncodingKey, Header, Validation};
|
||||
use rocket::response::status::Custom;
|
||||
use rocket::{
|
||||
http::Status,
|
||||
serde::{json::Json, Deserialize, Serialize},
|
||||
};
|
||||
use rocket::{routes, Route, State};
|
||||
use std::error::Error;
|
||||
|
||||
pub(crate) fn routes() -> Vec<Route> {
|
||||
routes![login]
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct Claims {
|
||||
exp: usize,
|
||||
sub: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct LoginRequest<'a> {
|
||||
username: &'a str,
|
||||
password: &'a str,
|
||||
}
|
||||
|
||||
#[rocket::post("/login", data = "<request>")]
|
||||
async fn login<'a>(
|
||||
request: Json<LoginRequest<'a>>,
|
||||
config: &State<Config>,
|
||||
) -> Result<String, Custom<String>> {
|
||||
let expiration = Utc::now()
|
||||
.checked_add_signed(Duration::seconds(60))
|
||||
.expect("clock went awry")
|
||||
.timestamp();
|
||||
|
||||
let claims = Claims {
|
||||
exp: expiration as usize,
|
||||
sub: request.username.to_owned(),
|
||||
};
|
||||
|
||||
let token = encode(
|
||||
&Header::default(),
|
||||
&claims,
|
||||
&EncodingKey::from_secret(config.jwt_secret.as_ref()),
|
||||
)
|
||||
.map_err(|e| Custom(Status::InternalServerError, e.to_string()))?;
|
||||
|
||||
Ok(token)
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
use rocket::{Phase, Rocket};
|
||||
|
||||
/// Config values for the API service. Available as a rocket request
|
||||
/// guard.
|
||||
pub struct Config {
|
||||
/// The list of origins allowed to access the service.
|
||||
pub allowed_origins: Vec<String>,
|
||||
|
||||
/// The secret key for signing JWTs.
|
||||
pub jwt_secret: String,
|
||||
}
|
||||
|
||||
pub fn create_config<T: Phase>(rocket: &Rocket<T>) -> Config {
|
||||
let figment = rocket.figment();
|
||||
let allowed_origins: Vec<String> = figment.extract_inner("origins").expect("origins");
|
||||
let jwt_secret: String = figment.extract_inner("jwt_secret").expect("jwt_secret");
|
||||
|
||||
Config {
|
||||
allowed_origins,
|
||||
jwt_secret,
|
||||
}
|
||||
}
|
|
@ -1 +1,4 @@
|
|||
pub mod api;
|
||||
pub mod auth;
|
||||
pub mod config;
|
||||
pub mod schema;
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
use log::info;
|
||||
use rocket::http::Method;
|
||||
use rocket::serde::{json::Json, Deserialize};
|
||||
use rocket::{response::content, Rocket, State};
|
||||
use rocket_cors::AllowedOrigins;
|
||||
use std::env;
|
||||
use tenebrous_api::config::{create_config, Config};
|
||||
use tenebrous_api::schema::{self, Context, Schema};
|
||||
use tracing_subscriber::filter::EnvFilter;
|
||||
|
||||
|
@ -31,52 +33,6 @@ async fn post_graphql_handler(
|
|||
|
||||
#[rocket::main]
|
||||
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let filter = if env::var("RUST_LOG").is_ok() {
|
||||
EnvFilter::from_default_env()
|
||||
} else {
|
||||
EnvFilter::new("tenebrous_api=info,tonic=info,rocket=info,rocket_cors=info")
|
||||
};
|
||||
|
||||
tracing_subscriber::fmt().with_env_filter(filter).init();
|
||||
|
||||
log::info!("Setting up gRPC connection");
|
||||
let client = tenebrous_rpc::create_client("http://localhost:9090", "abc123").await?;
|
||||
|
||||
let context = Context {
|
||||
dicebot_client: client,
|
||||
};
|
||||
|
||||
let schema = schema::schema();
|
||||
|
||||
let rocket = Rocket::build();
|
||||
let figment = rocket.figment();
|
||||
|
||||
let allowed_origins: Vec<String> = figment.extract_inner("origins").expect("origins");
|
||||
info!("Allowed CORS origins: {}", allowed_origins.join(","));
|
||||
|
||||
let allowed_origins = AllowedOrigins::some_exact(&allowed_origins);
|
||||
|
||||
let cors = rocket_cors::CorsOptions {
|
||||
allowed_origins,
|
||||
allowed_methods: vec![Method::Get, Method::Post]
|
||||
.into_iter()
|
||||
.map(From::from)
|
||||
.collect(),
|
||||
allow_credentials: true,
|
||||
..Default::default()
|
||||
}
|
||||
.to_cors()?;
|
||||
|
||||
rocket
|
||||
.mount(
|
||||
"/",
|
||||
rocket::routes![graphiql, get_graphql_handler, post_graphql_handler],
|
||||
)
|
||||
.attach(cors)
|
||||
.manage(context)
|
||||
.manage(schema)
|
||||
.launch()
|
||||
.await
|
||||
.expect("server to launch");
|
||||
tenebrous_api::api::run().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue