Skip to content

Commit 03a047e

Browse files
committed
wip: macro to ease Data boilerplate
1 parent 726b6f8 commit 03a047e

File tree

27 files changed

+321
-379
lines changed

27 files changed

+321
-379
lines changed

README.md

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88

99
<hr>
1010

11-
`sandpolis` is a **virtual estate monitoring/management tool** (VEM²) under
12-
active development.
11+
`sandpolis` is a **virtual estate manager** (VEM) for people with too many
12+
computers.
1313

1414
<p align="center">
1515
<img src="https://raw.githubusercontent.com/fossable/sandpolis/master/.github/images/overview.png" />
@@ -42,14 +42,40 @@ attack surface that includes both `Machine A` and `Machine B`. If `Machine A`
4242
happens to have a weak password or one that's shared with another website, then
4343
the attack surface is consequently expanded with appropriate probabilities.
4444

45-
Mapping these relationships automatically is possible because Sandpolis runs an
46-
agent on `Machine A` and `Machine B`.
45+
### Why sovereignty over your virtual estate is important
46+
47+
With virtual estates, it's not always clear who is in control of what and
48+
exactly how much control they have.
49+
50+
Control is usually divided among multiple parties. For example, control of your
51+
Github repos is shared between you and Github Inc (and probably Microsoft too).
52+
Control of your physical iPhone is shared between you and Apple (with Apple
53+
argubly having the majority). Control of your password manager is hopefully not
54+
shared with anyone.
55+
56+
While it's impossible to know exactly what percentage of control we have over
57+
our virtual estates, it definitely seems to be trending down. People are willing
58+
to give up control for features and convenience, and they didn't seem to notice
59+
the tradeoff.
60+
61+
If we don't prioritize control of our virtual estates, we might eventually lose
62+
it altogether. Imagine an alternate reality where all we have are thin clients!
63+
64+
Sandpolis is a tool designed to help realize as much sovereignty over your
65+
virtual estate as possible. It provides total control over the devices you own
66+
(via a local agent process) and visualizes how those devices interact with parts
67+
of your virtual estate that you don't directly own (such as cloud services).
68+
69+
There's no going back to the level of computing sovereignty we had before the
70+
Internet, but we don't want the opposite extreme either. We want a healthy
71+
medium of _partial sovereignty_ where people are aware and accepting of the
72+
control tradeoffs they are making.
4773

4874
## Security Warning
4975

50-
Sandpolis is an extremely high-value attack target as it provides management
51-
capabilities on your virtual estate. To compensate, strong security measures are
52-
available:
76+
The Sandpolis server is an extremely high-value attack target as it provides
77+
management capabilities over your virtual estate. To compensate, strong security
78+
measures are available:
5379

5480
- All connections to a server use mTLS and require a valid client certificate.
5581
The server automatically rotates these certificates periodically, but the
@@ -60,16 +86,21 @@ available:
6086
- User permissions restrict what users are able to do and on what instances.
6187

6288
Even with several layers of strong authentication, there's always risk that the
63-
Sandpolis server can be compromised. If the risks of introducing a "single point
64-
of compromise" outweigh the convenience of having a unified management
65-
interface, then **don't use Sandpolis**.
89+
server can be compromised. If the risks of introducing a _single point of
90+
compromise_ outweigh the convenience of having a unified management interface,
91+
then **you don't have to use Sandpolis**.
6692

6793
You can choose how much trust you allocate to the Sandpolis network. For
6894
example, agents can optionally run in _read only_ mode which still provides
6995
useful monitoring information, but prohibits all write operations (including
7096
agent updates). This can significantly mitigate potential damage in the event of
7197
server compromise.
7298

99+
## How it works
100+
101+
Sandpolis runs an agent on your devices and allows you to interact with them
102+
from a client application.
103+
73104
## Layers
74105

75106
Features are organized into _layers_ that can be toggled on/off in the UI. If

sandpolis-account/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@
33
### Attack surface map
44

55
### Compromise tracing
6+
7+
### Control mapping

sandpolis-core/src/lib.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,3 +295,41 @@ mod test_realm_name {
295295
);
296296
}
297297
}
298+
299+
/// A user's username is forever unchangable.
300+
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
301+
pub struct UserName(String);
302+
303+
impl Deref for UserName {
304+
type Target = String;
305+
306+
fn deref(&self) -> &Self::Target {
307+
&self.0
308+
}
309+
}
310+
311+
impl FromStr for UserName {
312+
type Err = anyhow::Error;
313+
314+
fn from_str(s: &str) -> Result<Self> {
315+
let name = UserName(s.to_string());
316+
name.validate()?;
317+
Ok(name)
318+
}
319+
}
320+
321+
impl Validate for UserName {
322+
fn validate(&self) -> Result<(), ValidationErrors> {
323+
if Regex::new("^[a-z0-9]{4,32}$").unwrap().is_match(&self.0) {
324+
Ok(())
325+
} else {
326+
Err(ValidationErrors::new())
327+
}
328+
}
329+
}
330+
331+
impl Default for UserName {
332+
fn default() -> Self {
333+
UserName("admin".to_string())
334+
}
335+
}

sandpolis-database/src/lib.rs

Lines changed: 16 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,10 @@ impl DatabaseLayer {
9090
/// `Data` is what's stored in a database!
9191
pub trait Data
9292
where
93-
Self: ToInput + Clone + PartialEq + Send + Sync,
93+
Self: ToInput + Clone + PartialEq + Send + Sync + Default,
9494
{
9595
fn id(&self) -> DataIdentifier;
96-
fn set_id(&mut self, id: DataIdentifier);
96+
// fn set_id(&mut self, id: DataIdentifier);
9797
}
9898

9999
/// `Data` that maintains a history of its value over time.
@@ -102,7 +102,7 @@ where
102102
Self: Data,
103103
{
104104
fn timestamp(&self) -> DbTimestamp;
105-
fn set_timestamp(&self, timestamp: DbTimestamp);
105+
// fn set_timestamp(&self, timestamp: DbTimestamp);
106106

107107
fn timestamp_key() -> KeyDefinition<KeyOptions> {
108108
KeyDefinition::new(
@@ -194,7 +194,7 @@ impl<T: Data> Drop for Resident<T> {
194194
}
195195
}
196196

197-
impl<T: Data + Default + 'static> Resident<T> {
197+
impl<T: Data + 'static> Resident<T> {
198198
/// Create a new `Watch` when there's only one row in the database.
199199
pub fn singleton(db: Arc<native_db::Database<'static>>) -> Result<Self> {
200200
let r = db.r_transaction()?;
@@ -298,16 +298,17 @@ impl<T: HistoricalData> Resident<T> {
298298
let r = self.db.r_transaction()?;
299299

300300
// TODO use the most restrictive condition first for performance
301-
let mut it = r.scan().secondary(T::timestamp_key())?.range(range)?;
301+
// let mut it = r.scan().secondary(T::timestamp_key())?.range(range)?;
302302

303-
for (key_def, key) in secondary_keys.into_iter() {
304-
it = it.and(r.scan().secondary(key_def)?.equal(match key {
305-
KeyEntry::Default(key) => key,
306-
KeyEntry::Optional(key) => key.unwrap(), // TODO
307-
})?);
308-
}
303+
// for (key_def, key) in secondary_keys.into_iter() {
304+
// it = it.and(r.scan().secondary(key_def)?.equal(match key {
305+
// KeyEntry::Default(key) => key,
306+
// KeyEntry::Optional(key) => key.unwrap(), // TODO
307+
// })?);
308+
// }
309309

310-
Ok(it.try_collect()?)
310+
// Ok(it.try_collect()?)
311+
todo!()
311312
}
312313
}
313314

@@ -318,33 +319,20 @@ mod test_resident {
318319
use native_db::Models;
319320
use native_db::*;
320321
use native_model::{Model, native_model};
321-
use sandpolis_macros::{Data, HistoricalData};
322+
use sandpolis_macros::{Data, HistoricalData, data};
322323
use serde::{Deserialize, Serialize};
323324
use tokio::time::{Duration, sleep};
324325

325-
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, Default, Data)]
326-
#[native_model(id = 5, version = 1)]
327-
#[native_db]
326+
#[data]
328327
pub struct TestData {
329-
#[primary_key]
330-
pub _id: DataIdentifier,
331-
332328
#[secondary_key]
333329
pub a: String,
334330
#[secondary_key]
335331
pub b: String,
336332
}
337333

338-
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, Default, Data, HistoricalData)]
339-
#[native_model(id = 6, version = 1)]
340-
#[native_db]
334+
#[data(history)]
341335
pub struct TestHistoryData {
342-
#[primary_key]
343-
pub _id: DataIdentifier,
344-
345-
#[secondary_key]
346-
pub _timestamp: DbTimestamp,
347-
348336
#[secondary_key]
349337
pub a: String,
350338
pub b: String,

sandpolis-instance/src/lib.rs

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,22 @@
11
use anyhow::Result;
22
use clap::Parser;
33
use native_db::ToKey;
4-
use native_db::*;
5-
use native_model::{Model, native_model};
4+
use native_model::Model;
65
use sandpolis_core::{ClusterId, InstanceId};
76
use sandpolis_database::{Data, DataIdentifier, DatabaseLayer, Resident};
8-
use sandpolis_macros::Data;
7+
use sandpolis_macros::data;
98
use serde::{Deserialize, Serialize, de::DeserializeOwned};
109
use std::{cmp::Ordering, ops::Deref};
1110

1211
pub mod cli;
1312

14-
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, Data)]
15-
#[native_model(id = 15, version = 1)]
16-
#[native_db]
13+
#[data]
1714
pub struct InstanceLayerData {
18-
#[primary_key]
19-
pub _id: DataIdentifier,
20-
2115
pub cluster_id: ClusterId,
2216
pub instance_id: InstanceId,
2317
pub os_info: os_info::Info,
2418
}
2519

26-
impl Default for InstanceLayerData {
27-
fn default() -> Self {
28-
Self {
29-
_id: DataIdentifier::default(),
30-
cluster_id: ClusterId::default(),
31-
instance_id: InstanceId::default(),
32-
os_info: os_info::get(),
33-
}
34-
}
35-
}
36-
3720
#[derive(Clone)]
3821
pub struct InstanceLayer {
3922
data: Resident<InstanceLayerData>,

0 commit comments

Comments
 (0)