aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKatharina Fey <kookie@spacekookie.de>2018-06-12 13:52:23 +0200
committerKatharina Fey <kookie@spacekookie.de>2018-06-12 13:52:23 +0200
commitf33840c1fff697a8467a78941687a71036b3c395 (patch)
tree1bf5740f8c95b12812b3622841b4c67d278adf73
parente47c2198c8f92003eb95f15a4311420e3b06c878 (diff)
Working on the http layer, adding 'create' route
Many things here are not ideal. There is very little checking that's being done, for this we need to tweak the core API a bit further. There are some corner cases that aren't caught. Authentication isn't being done yet. And it's not 100% clear yet where those scopes should live. But...there is progress being made. The API will develop and hopefully soon-ish we'll also be able to add versioning via a new serde-versioning crate being written (hint hint). The basic problem is that we need to build a system that works for two kinds of settings: remotely, administered via a few users, on a different computer with limited access and local, used by a single user and application stack (http interface for browser plugins, file API for everything else). The latter is the focus of development for now, but before we hit 1.0 (aka stable for production) there are more issues to be resolved. Also...if lockchain is to be used as a keystore in poke, we need to figure out how to allow easier integration of the core storage components into other applications (maybe some guides). Also...all of this should be documented in other places than just my ramblings in commit messages 😅
-rw-r--r--lockchain-http/src/handlers.rs83
-rw-r--r--lockchain-http/src/lib.rs19
-rw-r--r--lockchain-http/src/model.rs8
-rw-r--r--lockchain-http/src/state.rs70
4 files changed, 151 insertions, 29 deletions
diff --git a/lockchain-http/src/handlers.rs b/lockchain-http/src/handlers.rs
index c943cef..93649a9 100644
--- a/lockchain-http/src/handlers.rs
+++ b/lockchain-http/src/handlers.rs
@@ -6,6 +6,7 @@ use lockchain::{
};
use model::*;
+use state::ApiState;
use std::intrinsics;
use std::sync::{Arc, Mutex};
@@ -15,45 +16,69 @@ type HttpRequestState<T> = HttpRequest<Arc<Mutex<T>>>;
/// GET /vault
///
/// Check the documentation for more information about how to provide payloads
-pub fn get_vaults<B: Body>(req: HttpRequestState<impl Vault<B>>) -> impl Responder {
- let meta = req.state().lock().unwrap().metadata();
+pub fn get_vaults<B, V>(req: HttpRequestState<ApiState<B, V>>) -> impl Responder
+where
+ B: Body,
+ V: Vault<B>,
+{
+ let state = req.state().lock().unwrap();
Json(VaultList {
- vaults: vec![meta.name],
- count: meta.size,
+ vaults: state.vaults().iter().map(|s| s.to_string()).collect(),
+ count: state.count(),
})
}
/// PUT /vault
///
/// Check the documentation for more information about how to provide payloads
-pub fn create_vault<B, V>(_req: HttpRequestState<V>) -> impl Responder
+pub fn create_vault<B, V>(
+ (item, req): (Json<VaultCreate>, HttpRequestState<ApiState<B, V>>),
+) -> impl Responder
where
B: Body,
V: Vault<B>,
{
- format!("Unimplemented!")
+ let mut state = req.state().lock().unwrap();
+ let location = if state.bound_scope {
+ state.working_dir.clone().join(&item.location)
+ } else {
+ (&item.location).into()
+ };
+
+ state.add_vault(&item.name, V::new(&item.name, location.to_str().unwrap()));
+ Json(VaultCreateResponse {
+ name: item.name.clone(),
+ created: true,
+ error: None,
+ })
}
/// POST /vault/{vault-id}
-pub fn update_vault<B: Body>(_req: HttpRequestState<impl Vault<B>>) -> impl Responder {
+pub fn update_vault<B, V>(_req: HttpRequestState<ApiState<B, V>>) -> impl Responder
+where
+ B: Body,
+ V: Vault<B>,
+{
format!("Unimplemented!")
}
/// DELETE /vault/{vault-id}
-pub fn delete_vault<B: Body>(_req: HttpRequestState<impl Vault<B>>) -> impl Responder {
+pub fn delete_vault<B, V>(_req: HttpRequestState<ApiState<B, V>>) -> impl Responder
+where
+ B: Body,
+ V: Vault<B>,
+{
format!("Unimplemented!")
}
/// GET /vault/{vault-id}/records/{record-id}
-pub fn get_record<B, V>(req: HttpRequestState<V>) -> impl Responder
+pub fn get_record<B, V>(req: HttpRequestState<ApiState<B, V>>) -> impl Responder
where
B: Body,
V: Vault<B>,
{
format!("Unimplemented!")
-
-
// Ok(Json(CarrierMessage {
// error: Ok(()),
// data: Some(Record::new("name", "category", vec!["test", "foo"])),
@@ -61,34 +86,58 @@ where
}
/// PUT /vault/{vault-id}/records
-pub fn create_record<B: Body>(_req: HttpRequestState<impl Vault<B>>) -> impl Responder {
+pub fn create_record<B, V>(_req: HttpRequestState<ApiState<B, V>>) -> impl Responder
+where
+ B: Body,
+ V: Vault<B>,
+{
format!("Unimplemented!")
}
/// POST /vault/{vault-id}/records/{record-id}
-pub fn update_record<B: Body>(_req: HttpRequestState<impl Vault<B>>) -> impl Responder {
+pub fn update_record<B, V>(_req: HttpRequestState<ApiState<B, V>>) -> impl Responder
+where
+ B: Body,
+ V: Vault<B>,
+{
format!("Unimplemented!")
}
/// DELETE /vault/{vault-id}/records/{record-id}
-pub fn delete_record<B: Body>(_req: HttpRequestState<impl Vault<B>>) -> impl Responder {
+pub fn delete_record<B, V>(_req: HttpRequestState<ApiState<B, V>>) -> impl Responder
+where
+ B: Body,
+ V: Vault<B>,
+{
format!("Unimplemented!")
}
/// PUT /authenticate
-pub fn authenticate<B: Body>(_req: HttpRequestState<impl Vault<B>>) -> impl Responder {
+pub fn authenticate<B, V>(_req: HttpRequestState<ApiState<B, V>>) -> impl Responder
+where
+ B: Body,
+ V: Vault<B>,
+{
format!("Unimplemented!")
}
/// PUT /de-authenticate
-pub fn deauthenticate<B: Body>(_req: HttpRequestState<impl Vault<B>>) -> impl Responder {
+pub fn deauthenticate<B, V>(_req: HttpRequestState<ApiState<B, V>>) -> impl Responder
+where
+ B: Body,
+ V: Vault<B>,
+{
format!("Unimplemented!")
}
/// GET /api
///
/// Check the documentation for more information about how to provide payloads
-pub fn api_data<B: Body, V: Vault<B>>(_: HttpRequestState<V>) -> impl Responder {
+pub fn api_data<B: Body, V: Vault<B>>(_: HttpRequestState<ApiState<B, V>>) -> impl Responder
+where
+ B: Body,
+ V: Vault<B>,
+{
Json(ApiInformation {
version: "1.0".into(),
providers: vec![
diff --git a/lockchain-http/src/lib.rs b/lockchain-http/src/lib.rs
index 382ee86..bd0720f 100644
--- a/lockchain-http/src/lib.rs
+++ b/lockchain-http/src/lib.rs
@@ -25,14 +25,17 @@ extern crate actix_web;
extern crate lockchain_core as lockchain;
mod handlers;
-mod state;
-mod model;
-pub use model::CarrierMessage;
+pub mod model;
+pub mod state;
use actix_web::{http, server, App};
use lockchain::traits::{Body, Vault};
+use state::ApiState;
use std::sync::{Arc, Mutex};
+/// A simple rename of the long generic types that are returned for a new server
+pub type HttpApi<V> = server::HttpServer<App<Arc<Mutex<V>>>>;
+
/// Create a new lockchain-http server for a vault state
///
/// Lifetime wise, vault needs to long as long as the server, which is returned to
@@ -54,11 +57,11 @@ use std::sync::{Arc, Mutex};
/// DataVault::<EncryptedBody>::new("name", "some-location"),
/// ).run();
/// ```
-pub fn create_server<B: Body + 'static>(
- bind: &str,
- port: &str,
- state: impl Vault<B> + 'static,
-) -> server::HttpServer<App<Arc<Mutex<impl Vault<B> + 'static>>>> {
+pub fn create_server<B, V>(bind: &str, port: &str, state: ApiState<B, V>) -> HttpApi<ApiState<B, V>>
+where
+ B: Body + 'static,
+ V: Vault<B> + 'static,
+{
let state = Arc::new(Mutex::new(state));
server::new(move || {
diff --git a/lockchain-http/src/model.rs b/lockchain-http/src/model.rs
index ce92e1a..e16a4b0 100644
--- a/lockchain-http/src/model.rs
+++ b/lockchain-http/src/model.rs
@@ -37,3 +37,11 @@ pub struct VaultCreate {
pub name: String,
pub location: String,
}
+
+/// Response to creating a new vault
+#[derive(Serialize, Deserialize)]
+pub struct VaultCreateResponse {
+ pub name: String,
+ pub created: bool,
+ pub error: Option<String>,
+}
diff --git a/lockchain-http/src/state.rs b/lockchain-http/src/state.rs
index 45d92b1..80cd2b7 100644
--- a/lockchain-http/src/state.rs
+++ b/lockchain-http/src/state.rs
@@ -1,7 +1,29 @@
use lockchain::traits::{AutoEncoder, Body, Vault};
use std::collections::HashMap;
use std::marker::PhantomData;
+use std::path::PathBuf;
+/// An in-memory API state object which is delegated to all handlers
+///
+/// This mechanism serves two purposes
+///
+/// 1. Configuration of the API, beyond simple paramters provided to
+/// the server_start call
+/// 2. Buffering and pre-loading of certain vault components that need
+/// to be accessed via the handlers
+///
+/// It provides some simple query functions for handlers to work on,
+/// as well as expose raw configuration fields to be written
+///
+/// ```
+/// let state: ApiState<B, V> = ApiState {
+/// bound_scope: false,
+/// working_dir: ".".into(),
+/// ..
+/// };
+/// ```
+///
+/// (Replace `B` and `V` with your generics 🙂)
pub struct ApiState<B, V>
where
B: Body,
@@ -9,6 +31,45 @@ where
{
vaults: HashMap<String, Option<V>>,
_phantom: PhantomData<B>,
+
+ /// Signal if the API handlers are allowed outside their working dir
+ pub bound_scope: bool,
+ /// Provide a working directory
+ pub working_dir: PathBuf,
+}
+
+impl<B, V> ApiState<B, V>
+where
+ B: Body,
+ V: Vault<B>,
+{
+ /// Return a list of string slices for each vault in scope
+ pub fn vaults(&self) -> Vec<&str> {
+ self.vaults.iter().map(|(k, _)| k.as_str()).collect()
+ }
+ /// Simply return the number of known vaults
+ pub fn count(&self) -> usize {
+ self.vaults.len()
+ }
+
+ pub fn add_vault(&mut self, name: &str, vault: V) {
+ self.vaults.insert(name.into(), Some(vault));
+ }
+}
+
+impl<B, V> Default for ApiState<B, V>
+where
+ B: Body,
+ V: Vault<B>,
+{
+ fn default() -> Self {
+ Self {
+ vaults: Default::default(),
+ _phantom: PhantomData,
+ bound_scope: true,
+ working_dir: Default::default(),
+ }
+ }
}
#[derive(Serialize, Deserialize)]
@@ -24,8 +85,8 @@ where
B: Body,
V: Vault<B>,
{
- fn from(me: ApiState<B, V>) -> SerializedState {
- SerializedState {
+ fn from(me: ApiState<B, V>) -> Self {
+ Self {
vaults: me
.vaults
.into_iter()
@@ -43,8 +104,8 @@ where
B: Body,
V: Vault<B>,
{
- fn from(me: SerializedState) -> ApiState<B, V> {
- ApiState {
+ fn from(me: SerializedState) -> Self {
+ Self {
vaults: me.vaults.into_iter().fold(
HashMap::new(),
|mut acc: HashMap<String, Option<V>>, k| {
@@ -53,6 +114,7 @@ where
},
),
_phantom: PhantomData,
+ ..Default::default()
}
}
}