adding user

master
Avril 3 years ago
parent ca989eb51d
commit 1f3e9b22d0
Signed by: flanchan
GPG Key ID: 284488987C31F630

63
Cargo.lock generated

@ -119,12 +119,6 @@ dependencies = [
"safemem",
]
[[package]]
name = "build_const"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39"
[[package]]
name = "byte-tools"
version = "0.3.1"
@ -161,6 +155,19 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
dependencies = [
"libc",
"num-integer",
"num-traits",
"time",
"winapi 0.3.9",
]
[[package]]
name = "cloudabi"
version = "0.0.3"
@ -189,15 +196,6 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634"
[[package]]
name = "crc"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb"
dependencies = [
"build_const",
]
[[package]]
name = "crypto-mac"
version = "0.9.1"
@ -210,11 +208,10 @@ dependencies = [
[[package]]
name = "cryptohelpers"
version = "1.5.1"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cfc491baaffd7cbd6acc02ebd23564760d83a2c17e1a47e6a04a8d5a86e7fb5"
checksum = "31fca6629a75c37a8831f93133f86e20efb8dd7a94060e32635ebf9a62aca12f"
dependencies = [
"crc",
"getrandom 0.1.15",
"hex-literal",
"hmac",
@ -224,7 +221,6 @@ dependencies = [
"serde",
"serde_derive",
"sha2",
"tokio",
]
[[package]]
@ -232,6 +228,8 @@ name = "datse"
version = "0.1.0"
dependencies = [
"base64 0.13.0",
"bitflags",
"chrono",
"color-eyre",
"cryptohelpers",
"futures",
@ -245,6 +243,7 @@ dependencies = [
"regex",
"serde",
"smallmap",
"stack-vec",
"tokio",
"uuid",
"warp",
@ -890,6 +889,25 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "num-integer"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
dependencies = [
"autocfg 1.0.1",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
dependencies = [
"autocfg 1.0.1",
]
[[package]]
name = "num_cpus"
version = "1.13.0"
@ -1428,6 +1446,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "735b09f6ab554c4165d045a7d67b3b7b5248acb39463dffba38ebced1b9110e2"
dependencies = [
"rustc_version",
"serde",
]
[[package]]
@ -1442,6 +1461,12 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "stack-vec"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "969d02b2cf038972b7f2d285f246044771da9fb8cc26a9d6b129236b784d3bd6"
[[package]]
name = "subtle"
version = "2.3.0"

@ -21,8 +21,10 @@ client = []
[dependencies]
base64 = "0.13.0"
bitflags = "1.2.1"
chrono = "0.4.19"
color-eyre = {version = "0.5", default-features=false}
cryptohelpers = {version = "1.5.1", features= ["sha256", "rsa", "serde"]}
cryptohelpers = { version = "1.6", default-features=false, features = ["sha256", "rsa", "serialise", "aes"] }
futures = "0.3.8"
generational-arena = {version = "0.2.8", features= ["serde"]}
getrandom = "0.2.0"
@ -33,7 +35,8 @@ pretty_env_logger = "0.4.0"
rand = "0.7.3"
regex = "1.4.2"
serde = {version = "1.0", features = ["derive"]}
smallmap = "1.2"
smallmap = {version = "1.2", features= ["serde"]}
stack-vec = "0.1.0"
tokio = {version = "0.2", features = ["full"]}
uuid = {version = "0.8.1", features = ["v4","serde"]}
warp = "0.2.5"

@ -0,0 +1,122 @@
//! Data structures for the in-memory map.
use super::*;
use std::{
collections::HashMap,
};
use generational_arena::{
Arena, Index,
};
use cryptohelpers::{
rsa::{
RsaPublicKey, RsaPrivateKey,
Signature,
},
aes::AesKey,
sha256::Sha256Hash,
};
/// An absolute (nested) index
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct AbsoluteIndex(Vec<Index>);
/// Possible value types of the data map
#[derive(Debug, Serialize, Deserialize)]
pub enum Data
{
Byte(u8),
Char(char),
Bool(bool),
/// Signed integer
SI(i64),
/// Unsigned integer
UI(u64),
/// Floating-point integer
FI(f64),
/// A UTF-8 text string
Text(String),
/// A binary blob
Binary(Vec<u8>),
/// A reference index to an item within the same `Datamap` as this one.
RelativeRef(Index),
/// A reference to an item N deep within nested `Map` elements.
///
/// The first `Index` specifies the `Map` data item at the root `Datamap` that contains the next, et cetera. The pointed to value is the last index.
AbsoluteRef(AbsoluteIndex),
/// A list of atoms
List(Vec<Atom>),
/// Another datamap
Map(Datamap),
/// An AES key
AesKey(AesKey),
/// An RSA keypair
RsaKeypair(RsaPrivateKey, RsaPublicKey),
/// An RSA private key
RsaPrivate(RsaPrivateKey),
/// An RSA public key
RsaPublic(RsaPublicKey),
/// A SHA256 hash
Hash(Sha256Hash),
/// A unique ID
Uuid(uuid::Uuid),
/// An RSA signature
Signature(Signature),
/// Nothing
Null,
}
/// An entry that may or may not be encrypted
#[derive(Debug, Serialize, Deserialize)]
pub enum MaybeEncrypted
{
Encrypted(Vec<u8>),
Unencrypted(Data),
}
/// Information about a map entry.
#[derive(Debug, Serialize, Deserialize)]
pub struct Info
{
alt_name: Option<(String, String)>,
created: u64,
modified: u64,
enable_versioning: bool,
hidden: bool,
owner: Option<Vec<user::EntityID>>, //starts as the user that created (i.e. same as `created_by`), or `None` if ownership is disabled
signed: Option<Vec<Signature>>,
perms: user::Permissions,
created_by: user::UserID,
log: Vec<event::Event>,
}
/// The root data containing map
#[derive(Debug, Serialize, Deserialize)]
pub struct Datamap
{
data: Arena<Atom>,
ident: HashMap<Identifier, Index>,
}
/// A value in a datamap, contains the information about the value and the value itself.
///
/// May also contain previous versions of this atom
#[derive(Debug, Serialize, Deserialize)]
pub struct Atom(MaybeEncrypted, Info, Vec<Atom>);
/// An identifier for an item in a `Datamap`, or an item nested within many `Datamap`s.
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct Identifier(String);

@ -0,0 +1,28 @@
//! When events happen to datamaps
use super::*;
/// What happened in the event
#[derive(Debug, Serialize, Deserialize)]
pub enum EventKind
{
Created,
Modified,
Deleted,
Renamed(String), // Previous name
Cloned(data::AbsoluteIndex), // Index of the new item
Moved,
Comment(String),
}
/// An event that happened to a data entry
#[derive(Debug, Serialize, Deserialize)]
pub struct Event
{
who: Option<user::UserID>,
what: EventKind,
when: u64,
signed: Option<cryptohelpers::rsa::Signature>,
}

@ -6,8 +6,12 @@ pub struct Config
}
mod event;
mod user;
mod data;
mod state;
#[cfg(feature="server-http")] pub mod web;
#[cfg(feature="server-tcp")] pub mod tcp;

@ -1,69 +1,9 @@
//! Server state
use super::*;
use std::{
collections::HashMap,
};
use generational_arena::{
Arena, Index,
};
/// Possible value types of the data map
#[derive(Debug, Serialize, Deserialize)]
pub enum Data
{
Byte(u8),
Char(char),
Bool(bool),
SI(i64),
UI(u64),
FI(f64),
Text(String),
Binary(Vec<u8>),
/// A reference index to an item within the same `Datamap` as this one.
RelativeRef(Index),
/// A reference to an item N deep within nested `Map` elements.
///
/// The first `Index` specifies the `Map` data item at the root `Datamap` that contains the next, et cetera. The pointed to value is the last index.
AbsoluteRef(Vec<Index>),
List(Vec<Atom>),
Map(Datamap),
Null,
}
/// Information about a map entry.
#[derive(Debug, Serialize, Deserialize)]
pub struct Info
{
created: u64,
modified: u64,
//TODO: Info about who owns it, perms, etc.
}
/// The root data containing map
#[derive(Debug, Serialize, Deserialize)]
pub struct Datamap
{
data: Arena<Atom>,
ident: HashMap<Identifier, Index>,
}
/// A value in a datamap, contains the information about the value and the value itself.
#[derive(Debug, Serialize, Deserialize)]
pub struct Atom(Data, Info);
/// An identifier for an item in a `Datamap`, or an item nested within many `Datamap`s.
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct Identifier(String);
/// Contains the state of the whole program
#[derive(Debug)]
pub struct ServerState
{
root: Datamap,
root: data::Datamap,
}

@ -0,0 +1,276 @@
//! Information about users, perms, etc
use super::*;
use std::collections::HashMap;
use std::borrow::Cow;
use bitflags::bitflags;
/// The ID type used for backing user/group IDs
type GenericID = uuid::Uuid;
/// A user group ID
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
pub struct GroupID(GenericID);
/// A unique user ID
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
pub struct UserID(GenericID);
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct User
{
id: UserID,
name: String,
hidden: bool,
desc: Option<String>,
comment: Option<String>,
/// Corresponds to a Unix `superuser`.
///
/// All permissions checks are bypassed for a user with this set.
is_god: bool,
groups: Vec<GroupID>,
}
/// A group is a way of setting permissions for a whole set of users.
///
/// Users have groups, not the other way around.
/// A user can have multiple groups or none.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Group
{
id: GroupID,
hidden: bool,
/// Corresponds to a Unix `superuser`.
///
/// All permissions checks are bypassed for a user in a group with this set.
is_god: bool,
name: String,
desc: Option<String>,
comment: Option<String>,
inherits: Option<Vec<GroupID>>,
}
pub trait AsEntityId
{
fn entity_id(&self) -> Cow<'_, EntityID>;
}
impl AsEntityId for EntityID
{
#[inline(always)] fn entity_id(&self) -> Cow<'_, EntityID> {
Cow::Borrowed(self)
}
}
impl AsEntityId for UserID
{
fn entity_id(&self) -> Cow<'_, EntityID> {
Cow::Owned(EntityID::User(self.clone()))
}
}
impl AsEntityId for GroupID
{
fn entity_id(&self) -> Cow<'_, EntityID> {
Cow::Owned(EntityID::Group(self.clone()))
}
}
impl<'a, T> AsEntityId for &'a T
where T: AsEntityId
{
#[inline(always)] fn entity_id(&self) -> Cow<'_, EntityID> {
T::entity_id(self)
}
}
/// A trait for items that can have permissions bits set for them.
/// Users and groups implement this.
pub trait Entity
{
fn generic_id(&self) -> &GenericID;
fn name(&self) -> &str;
fn desc(&self) -> Option<&str>;
fn comment(&self) -> Option<&str>;
fn superuser(&self) -> bool;
/// # Note
/// This does not flatten inherited groups, that needs to be performed later
fn groups(&self) -> &[GroupID];
}
impl Entity for User
{
#[inline] fn generic_id(&self) -> &GenericID
{
&self.id.0
}
#[inline] fn name(&self) -> &str
{
&self.name[..]
}
#[inline] fn desc(&self) -> Option<&str>
{
self.desc.as_ref().map(String::as_str)
}
#[inline] fn comment(&self) -> Option<&str>
{
self.comment.as_ref().map(String::as_str)
}
#[inline] fn superuser(&self) -> bool
{
self.is_god
}
/// # Note
/// This does not flatten inherited groups, that needs to be performed later
#[inline] fn groups(&self) -> &[GroupID]
{
&self.groups[..]
}
}
impl Entity for Group
{
#[inline] fn generic_id(&self) -> &GenericID
{
&self.id.0
}
#[inline] fn name(&self) -> &str
{
&self.name[..]
}
#[inline] fn desc(&self) -> Option<&str>
{
self.desc.as_ref().map(String::as_str)
}
#[inline] fn comment(&self) -> Option<&str>
{
self.comment.as_ref().map(String::as_str)
}
#[inline] fn superuser(&self) -> bool
{
self.is_god
}
/// # Note
/// This does not flatten inherited groups, that needs to be performed later
#[inline] fn groups(&self) -> &[GroupID]
{
self.inherits.as_ref().map(Vec::as_slice).unwrap_or(&[])
}
}
/// Either a single user or a group of users
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
pub enum EntityID
{
User(UserID),
Group(GroupID),
}
impl UserID
{
/// Attempt to find this user in this userspace
pub fn find_in_space<'a>(&self, space: &'a Userspace) -> Option<&'a User>
{
space.users.get(self)
}
/// Attempt to find a mutable reference to this user in this userspace
pub fn find_in_space_mut<'a>(&self, space: &'a mut Userspace) -> Option<&'a mut User>
{
space.users.get_mut(self)
}
}
impl GroupID
{
/// Attempt to find this group in this userspace
pub fn find_in_space<'a>(&self, space: &'a Userspace) -> Option<&'a Group>
{
space.groups.get(self)
}
/// Attempt to find a mutable reference to this group in this userspace
pub fn find_in_space_mut<'a>(&self, space: &'a mut Userspace) -> Option<&'a mut Group>
{
space.groups.get_mut(self)
}
}
impl EntityID
{
/// Attempt to find the entity that implements this ID in this space
pub fn find_in_space<'a>(&self, space: &'a Userspace) -> Option<&'a (dyn Entity + 'static)>
{
match self {
Self::User(id) => space.users.get(id).map(|x| x as &dyn Entity),
Self::Group(id) => space.groups.get(id).map(|x| x as &dyn Entity),
}
}
}
bitflags! {
/// A permission a user or group has for a data item.
#[derive(Serialize, Deserialize)]
struct Permission: u32 {
/// Cannot read or write the item.
///
/// However they can see it, unless it is marked "hidden".
const NONE = 0;
/// Can read from the item but cannot write to it
const READ = 1;
/// Can write to the item
///
/// This does not imply `READ`.
const WRITE = 2;
/// Full access
const FULL = Self::READ.bits | Self::WRITE.bits;
}
}
/// A set of permissions informations for users and/or groups
#[derive(Debug, Serialize, Deserialize)]
pub struct Permissions
{
blanket: Permission,
spec: smallmap::Map<EntityID, Permission>,
}
/// Contains all users and groups
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Userspace
{
// use maps here for easier lookup, despite duplicating ID data
users: HashMap<UserID, User>,
groups: HashMap<GroupID, Group>,
}
impl Userspace
{
/// Is this `User` or `Group` ID present in this space?
pub fn contains_id(&self, ent: &impl AsEntityId) -> bool
{
ent.entity_id().find_in_space(self).is_some()
}
}
Loading…
Cancel
Save