diff --git a/schema/api.capnp b/schema/api.capnp index b307b3e..1cfd5ca 100644 --- a/schema/api.capnp +++ b/schema/api.capnp @@ -1,6 +1,49 @@ +# Copyright © 2020 Gregor Reitzenstein +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + @0xfd92ce9be2369b8e; +interface Diflouroborane { + # Upon initial connection this is the interface a program is presented with, serving as the + # common point to access specific subsystems. Keep in mind that one can use pipelining to make this + # just as efficient as direct calls — e.g. access the authentication system and call + # `initializeAuthentication` on it in one roundtrip, provided one gets granted access to the + # Authentication subsystem (which in all fairness is a reasonable assumption) + + authentication @0 () -> ( auth :Authentication ); + # Then authentication subsystem handles authentication of clients and servers. Multiple + # authentication is possible, see the `Authentication` interface for details. + + permissions @1 () -> ( perm :Permissions ); + # Permission subsystem to manage permissions and systems underlying the authorization process + + machines @2 () -> ( mach :Machines ); + # Diflouroborane stores machine¹ information in an opaque internal database. This interface is + # the only stable process of modifying that information +} + struct Maybe(Value) { + # An optional value, i.e. a value which is either explicity present or explicity not present. + # Similar to `Maybe` in Haskell and `Option` in OCaml or Rust union { some @0 :Value; none @1 :Void; @@ -8,17 +51,16 @@ struct Maybe(Value) { } struct Either(Left, Right) { + # Sum type over two values. A more general type than Rust's `Result` type. + # If this type is used to convey the result of a possibly failed computation the `Left` type + # shall be used for the error while the `Right` type shall be the value. (Mnemonic: 'right' also + # means 'correct') union { left @0 :Left; right @1 :Right; } } -struct Subject { - id @0 :Text; - domain @1 :Text; -} - struct Machine { name @0 :Text; location @1 :Text; @@ -31,23 +73,42 @@ enum Status { blocked @2; } -interface BffhAdmin { - getAllSubjects @0 () -> (subjects :List(Subject) ); +struct UUID { + lsg @0 :UInt64; # least significant + msg @1 :UInt64; # most significant +} - getAllMachines @1 () -> (machines :List(Machine) ); - addMachine @2 (name :Text, location :Text ) -> (); +interface Machines { + interface Manage { + setBlocked @0 ( blocked :Bool ) -> (); + # Block or Unblock the machine. A blocked machine can not be used. - machineSetState @3 (name :Text, state :Status ) -> (); + return @1 () -> (); + # Forcefully marking a machine as `returned` — i.e. not used. + } - authentication @4 () -> ( auth :Authentication ); + interface Return { + # The only way of getting a `return` interface is by successfully calling `use`. This means + # only the user that marked a machine as `used` can return it again. (Baring force override) + return @0 () -> (); + } + + manage @0 ( uuid :UUID ) -> ( manage :Manage ); + + use @1 ( uuid :UUID ) -> ( return :Return ); + # Use a machine, identified by its UUID. If the caller is allowed to and the machine is + # available to being used a `return` Capability will be returned — the person using a machine is + # after all the only person that can return the machine after use. } interface Permissions { - getAllSubjects @0 () -> (subjects :List(Subject) ); -} + getAllSubjects @0 () -> ( subjects :List(Text) ); + getAllObjects @1 () -> ( objects :List(Text) ); + getAllAction @2 () -> ( actions :List(Text) ); + getAllRoles @3 () -> ( roles :List(Text) ); -interface Notification { - machineChangeState @0 (machine :Machine ) -> (); + removePolicy @4 ( p :List(Text) ) -> (); + addPolicy @5 ( p :List(Text) ) -> (); } interface Authentication { diff --git a/src/api.rs b/src/api.rs index cb71f23..9896818 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1,6 +1,6 @@ // module needs to be top level for generated functions to be in scope: // https://github.com/capnproto/capnproto-rust/issues/16 -pub(crate) mod api_capnp { +pub(crate) mod api { include!(concat!(env!("OUT_DIR"), "/schema/api_capnp.rs")); } @@ -14,28 +14,34 @@ use casbin::MgmtApi; use crate::machine::{MachineDB, Machine, Status, save}; use crate::auth::Authentication; +use capnp::{Error}; +use capnp_rpc::RpcSystem; +use capnp_rpc::twoparty::VatNetwork; +use capnp_rpc::rpc_twoparty_capnp::Side; + +use api::diflouroborane; + pub fn init() { } pub async fn process_socket(e: Mutable, m: Mutable, a: Authentication, socket: TcpStream) - -> Result<(), capnp::Error> + -> Result<(), Error> { - let auth = api_capnp::authentication::ToClient::new(a).into_client::<::capnp_rpc::Server>(); + let auth = api::authentication::ToClient::new(a).into_client::(); let api = Api { e, m, auth }; - let a = api_capnp::bffh_admin::ToClient::new(api).into_client::<::capnp_rpc::Server>(); - let netw = capnp_rpc::twoparty::VatNetwork::new(socket.clone(), socket, - capnp_rpc::rpc_twoparty_capnp::Side::Server, Default::default()); - let rpc = capnp_rpc::RpcSystem::new(Box::new(netw), Some(a.clone().client)); + let a = api::diflouroborane::ToClient::new(api).into_client::(); + let netw = VatNetwork::new(socket.clone(), socket, Side::Server, Default::default()); + let rpc = RpcSystem::new(Box::new(netw), Some(a.clone().client)); rpc.await } struct Api { e: Mutable, m: Mutable, - auth: api_capnp::authentication::Client, + auth: api::authentication::Client, } -impl api_capnp::bffh_admin::Server for Api { +impl diflouroborane::Server for Api { fn get_all_subjects(&mut self, _params: api_capnp::bffh_admin::GetAllSubjectsParams, mut results: api_capnp::bffh_admin::GetAllSubjectsResults)