2021-01-04 17:34:31 +00:00
|
|
|
use activitystreams::base::AnyBase;
|
|
|
|
use sled::{Db, Tree};
|
|
|
|
use std::{fmt, sync::Arc};
|
|
|
|
use url::Url;
|
|
|
|
use uuid::Uuid;
|
|
|
|
|
2021-01-06 08:21:17 +00:00
|
|
|
pub mod actions;
|
2021-01-04 17:34:31 +00:00
|
|
|
mod keys;
|
2021-01-06 08:21:17 +00:00
|
|
|
mod results;
|
2021-01-04 17:34:31 +00:00
|
|
|
|
2021-01-04 17:41:34 +00:00
|
|
|
pub(crate) use actions::ingest;
|
2021-01-16 04:25:06 +00:00
|
|
|
use keys::{ExtendedApplication, ExtendedPerson, PublicKey, PublicKeyInner};
|
2021-01-04 17:34:31 +00:00
|
|
|
|
|
|
|
pub trait ApubIds {
|
2021-01-06 08:21:17 +00:00
|
|
|
fn gen_id(&self) -> Option<Url>;
|
2021-01-04 17:34:31 +00:00
|
|
|
|
|
|
|
fn public_key(&self, id: &Url) -> Option<Url>;
|
|
|
|
fn following(&self, id: &Url) -> Option<Url>;
|
|
|
|
fn followers(&self, id: &Url) -> Option<Url>;
|
|
|
|
fn inbox(&self, id: &Url) -> Option<Url>;
|
|
|
|
fn outbox(&self, id: &Url) -> Option<Url>;
|
|
|
|
fn shared_inbox(&self) -> Url;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, thiserror::Error)]
|
|
|
|
pub enum StoreError {
|
|
|
|
#[error("{0}")]
|
|
|
|
Sled(#[from] sled::Error),
|
|
|
|
|
|
|
|
#[error("{0}")]
|
|
|
|
Transaction(#[from] sled::transaction::TransactionError),
|
|
|
|
|
|
|
|
#[error("{0}")]
|
|
|
|
Json(#[from] serde_json::Error),
|
|
|
|
|
|
|
|
#[error("Error generating keys")]
|
|
|
|
Key,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct Store {
|
|
|
|
apub_id: Tree,
|
|
|
|
id_apub: Tree,
|
|
|
|
objects: Tree,
|
2021-01-05 03:13:06 +00:00
|
|
|
deleted: Tree,
|
2021-01-04 17:34:31 +00:00
|
|
|
keys: Tree,
|
|
|
|
profile_key: Tree,
|
2021-01-17 07:27:13 +00:00
|
|
|
key_profile: Tree,
|
2021-01-16 04:25:06 +00:00
|
|
|
server_key: Tree,
|
2021-01-17 07:27:13 +00:00
|
|
|
key_server: Tree,
|
2021-01-04 17:34:31 +00:00
|
|
|
endpoints: Tree,
|
2021-01-05 02:23:17 +00:00
|
|
|
profile_endpoint: Tree,
|
2021-01-16 04:25:06 +00:00
|
|
|
server_endpoint: Tree,
|
2021-01-04 17:34:31 +00:00
|
|
|
info: Arc<dyn ApubIds + Send + Sync>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub enum StoredRecords {
|
2021-01-16 04:25:06 +00:00
|
|
|
Server(Uuid),
|
2021-01-14 04:43:43 +00:00
|
|
|
Report(Uuid),
|
2021-01-04 17:34:31 +00:00
|
|
|
Profile(Uuid),
|
|
|
|
Submission(Uuid),
|
|
|
|
Comment(Uuid),
|
|
|
|
React(Uuid),
|
|
|
|
File(Uuid),
|
|
|
|
Block(Uuid),
|
|
|
|
Follow(Uuid),
|
|
|
|
FollowRequest(Uuid),
|
2021-01-16 04:25:06 +00:00
|
|
|
ServerFollow(Uuid),
|
|
|
|
ServerFollowRequest(Uuid),
|
2021-01-04 17:34:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn url_from_ivec(ivec: sled::IVec) -> Option<Url> {
|
2021-01-17 21:01:37 +00:00
|
|
|
let s = String::from_utf8_lossy(&ivec);
|
|
|
|
s.parse::<Url>().ok()
|
2021-01-04 17:34:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn record_from_ivec(ivec: sled::IVec) -> Option<StoredRecords> {
|
2021-01-17 07:27:13 +00:00
|
|
|
StoredRecords::from_slice(&ivec)
|
|
|
|
.map_err(|e| log::warn!("{}", e))
|
|
|
|
.ok()
|
2021-01-04 17:34:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl StoredRecords {
|
|
|
|
fn from_slice(slice: &[u8]) -> Result<Self, StoredRecordsError> {
|
|
|
|
String::from_utf8_lossy(slice).parse::<Self>()
|
|
|
|
}
|
|
|
|
|
2021-01-16 04:25:06 +00:00
|
|
|
pub fn server(&self) -> Option<Uuid> {
|
|
|
|
match self {
|
|
|
|
Self::Server(id) => Some(*id),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-04 17:34:31 +00:00
|
|
|
pub fn profile(&self) -> Option<Uuid> {
|
|
|
|
match self {
|
|
|
|
Self::Profile(id) => Some(*id),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn submission(&self) -> Option<Uuid> {
|
|
|
|
match self {
|
|
|
|
Self::Submission(id) => Some(*id),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn comment(&self) -> Option<Uuid> {
|
|
|
|
match self {
|
|
|
|
Self::Comment(id) => Some(*id),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn react(&self) -> Option<Uuid> {
|
|
|
|
match self {
|
|
|
|
Self::React(id) => Some(*id),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn file(&self) -> Option<Uuid> {
|
|
|
|
match self {
|
|
|
|
Self::File(id) => Some(*id),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn block(&self) -> Option<Uuid> {
|
|
|
|
match self {
|
|
|
|
Self::Block(id) => Some(*id),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn follow(&self) -> Option<Uuid> {
|
|
|
|
match self {
|
|
|
|
Self::Follow(id) => Some(*id),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn follow_request(&self) -> Option<Uuid> {
|
|
|
|
match self {
|
|
|
|
Self::FollowRequest(id) => Some(*id),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
2021-01-16 17:48:12 +00:00
|
|
|
|
|
|
|
pub fn server_follow(&self) -> Option<Uuid> {
|
|
|
|
match self {
|
|
|
|
Self::ServerFollow(id) => Some(*id),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn server_follow_request(&self) -> Option<Uuid> {
|
|
|
|
match self {
|
|
|
|
Self::ServerFollowRequest(id) => Some(*id),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
2021-01-04 17:34:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, thiserror::Error)]
|
|
|
|
#[error("Error generating key")]
|
|
|
|
struct KeyError;
|
|
|
|
|
|
|
|
#[derive(serde::Deserialize, serde::Serialize)]
|
|
|
|
struct Keys {
|
|
|
|
public: String,
|
|
|
|
private: Option<String>,
|
|
|
|
}
|
|
|
|
|
2021-01-17 07:27:13 +00:00
|
|
|
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
2021-01-04 17:34:31 +00:00
|
|
|
struct Endpoints {
|
|
|
|
inbox: Url,
|
|
|
|
outbox: Url,
|
2021-01-17 07:27:13 +00:00
|
|
|
following: Option<Url>,
|
|
|
|
followers: Option<Url>,
|
|
|
|
shared_inbox: Option<Url>,
|
2021-01-04 17:34:31 +00:00
|
|
|
public_key: Url,
|
|
|
|
}
|
|
|
|
|
2021-01-17 07:27:13 +00:00
|
|
|
impl Endpoints {
|
|
|
|
fn inbox(&self) -> &Url {
|
|
|
|
self.shared_inbox.as_ref().unwrap_or(&self.inbox)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-04 17:34:31 +00:00
|
|
|
impl Store {
|
|
|
|
pub(crate) fn build(
|
|
|
|
ids: impl ApubIds + Send + Sync + 'static,
|
|
|
|
db: &Db,
|
|
|
|
) -> Result<Self, sled::Error> {
|
|
|
|
Ok(Store {
|
|
|
|
id_apub: db.open_tree("/profiles/apub/id-apub")?,
|
|
|
|
apub_id: db.open_tree("/profiles/apub/apub-id")?,
|
|
|
|
objects: db.open_tree("/profiles/apub/objects")?,
|
2021-01-05 03:13:06 +00:00
|
|
|
deleted: db.open_tree("/profiles/apub/deleted")?,
|
2021-01-04 17:34:31 +00:00
|
|
|
keys: db.open_tree("/profiles/apub/keys")?,
|
|
|
|
profile_key: db.open_tree("/profiles/apub/profile/key")?,
|
2021-01-17 07:27:13 +00:00
|
|
|
key_profile: db.open_tree("/profiles/apub/key/profile")?,
|
2021-01-16 04:25:06 +00:00
|
|
|
server_key: db.open_tree("/profiles/apub/server/key")?,
|
2021-01-17 07:27:13 +00:00
|
|
|
key_server: db.open_tree("/profiles/apub/key/server")?,
|
2021-01-04 17:34:31 +00:00
|
|
|
endpoints: db.open_tree("/profiles/apub/endpoints")?,
|
2021-01-05 02:23:17 +00:00
|
|
|
profile_endpoint: db.open_tree("/profiles/apub/profile/endpoint")?,
|
2021-01-16 04:25:06 +00:00
|
|
|
server_endpoint: db.open_tree("/profiles/apub/server/endpoint")?,
|
2021-01-04 17:34:31 +00:00
|
|
|
info: Arc::new(ids),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-01-16 04:25:06 +00:00
|
|
|
fn endpoints_for_server(&self, server_id: Uuid) -> Result<Option<Endpoints>, StoreError> {
|
|
|
|
let opt = self
|
|
|
|
.server_endpoint
|
|
|
|
.get(server_endpoint_id(server_id))?
|
|
|
|
.and_then(url_from_ivec);
|
|
|
|
|
|
|
|
if let Some(server_id) = opt {
|
|
|
|
if let Some(ivec) = self.endpoints.get(server_id.as_str())? {
|
|
|
|
let endpoints: Endpoints = serde_json::from_slice(&ivec)?;
|
|
|
|
return Ok(Some(endpoints));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(None)
|
|
|
|
}
|
|
|
|
|
2021-01-17 07:27:13 +00:00
|
|
|
pub fn key_for_server(&self, server_id: Uuid) -> Result<Option<Url>, StoreError> {
|
2021-01-16 04:25:06 +00:00
|
|
|
self.server_key
|
2021-01-16 17:48:12 +00:00
|
|
|
.get(server_key_id(server_id))
|
2021-01-16 04:25:06 +00:00
|
|
|
.map(|opt| opt.and_then(url_from_ivec))
|
|
|
|
.map_err(StoreError::from)
|
|
|
|
}
|
|
|
|
|
2021-01-17 07:27:13 +00:00
|
|
|
pub(super) fn server_for_key(&self, key_id: &Url) -> Result<Option<Uuid>, StoreError> {
|
|
|
|
self.key_server
|
|
|
|
.get(key_id.as_str())
|
|
|
|
.map(|opt| opt.and_then(uuid_from_ivec))
|
|
|
|
.map_err(StoreError::from)
|
|
|
|
}
|
|
|
|
|
2021-01-05 02:23:17 +00:00
|
|
|
fn endpoints_for_profile(&self, profile_id: Uuid) -> Result<Option<Endpoints>, StoreError> {
|
|
|
|
let opt = self
|
|
|
|
.profile_endpoint
|
|
|
|
.get(profile_endpoint_id(profile_id))?
|
|
|
|
.and_then(url_from_ivec);
|
|
|
|
|
|
|
|
if let Some(profile_id) = opt {
|
|
|
|
if let Some(ivec) = self.endpoints.get(profile_id.as_str())? {
|
|
|
|
let endpoints: Endpoints = serde_json::from_slice(&ivec)?;
|
|
|
|
return Ok(Some(endpoints));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(None)
|
|
|
|
}
|
|
|
|
|
2021-01-17 07:27:13 +00:00
|
|
|
pub fn key_for_profile(&self, profile_id: Uuid) -> Result<Option<Url>, StoreError> {
|
2021-01-04 17:34:31 +00:00
|
|
|
self.profile_key
|
|
|
|
.get(profile_key_id(profile_id))
|
|
|
|
.map(|opt| opt.and_then(url_from_ivec))
|
|
|
|
.map_err(StoreError::from)
|
|
|
|
}
|
|
|
|
|
2021-01-17 07:27:13 +00:00
|
|
|
pub(super) fn profile_for_key(&self, key_id: &Url) -> Result<Option<Uuid>, StoreError> {
|
|
|
|
self.key_profile
|
|
|
|
.get(key_id.as_str())
|
|
|
|
.map(|opt| opt.and_then(uuid_from_ivec))
|
|
|
|
.map_err(StoreError::from)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn public_key_for_id(&self, key_id: &Url) -> Result<Option<String>, StoreError> {
|
2021-01-04 17:34:31 +00:00
|
|
|
if let Some(ivec) = self.keys.get(key_id.as_str())? {
|
|
|
|
let keys: Keys = serde_json::from_slice(&ivec)?;
|
|
|
|
return Ok(Some(keys.public));
|
|
|
|
}
|
|
|
|
Ok(None)
|
|
|
|
}
|
|
|
|
|
2021-01-17 07:27:13 +00:00
|
|
|
pub fn private_key_for_id(&self, key_id: &Url) -> Result<Option<String>, StoreError> {
|
|
|
|
if let Some(ivec) = self.keys.get(key_id.as_str())? {
|
|
|
|
let keys: Keys = serde_json::from_slice(&ivec)?;
|
|
|
|
return Ok(keys.private);
|
|
|
|
}
|
|
|
|
Ok(None)
|
|
|
|
}
|
|
|
|
|
2021-01-16 04:25:06 +00:00
|
|
|
fn store_server_endpoints(
|
|
|
|
&self,
|
|
|
|
server_id: Uuid,
|
|
|
|
apub_id: &Url,
|
|
|
|
endpoints: Endpoints,
|
|
|
|
) -> Result<(), StoreError> {
|
|
|
|
let endpoints_vec = serde_json::to_vec(&endpoints)?;
|
|
|
|
self.endpoints.insert(apub_id.as_str(), endpoints_vec)?;
|
|
|
|
self.server_endpoint
|
|
|
|
.insert(server_endpoint_id(server_id), apub_id.as_str())?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn store_profile_endpoints(
|
2021-01-05 02:23:17 +00:00
|
|
|
&self,
|
|
|
|
profile_id: Uuid,
|
|
|
|
apub_id: &Url,
|
|
|
|
endpoints: Endpoints,
|
|
|
|
) -> Result<(), StoreError> {
|
|
|
|
let endpoints_vec = serde_json::to_vec(&endpoints)?;
|
|
|
|
self.endpoints.insert(apub_id.as_str(), endpoints_vec)?;
|
|
|
|
self.profile_endpoint
|
|
|
|
.insert(profile_endpoint_id(profile_id), apub_id.as_str())?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-01-16 04:25:06 +00:00
|
|
|
fn gen_server_keys(&self, server_id: Uuid, key_id: &Url) -> Result<String, StoreError> {
|
|
|
|
let keys = Keys::generate()?;
|
|
|
|
let keys_vec = serde_json::to_vec(&keys)?;
|
|
|
|
self.keys.insert(key_id.as_str(), keys_vec)?;
|
|
|
|
self.server_key
|
|
|
|
.insert(server_key_id(server_id), key_id.as_str())?;
|
2021-01-17 07:27:13 +00:00
|
|
|
self.key_server
|
|
|
|
.insert(key_id.as_str(), server_id.as_bytes())?;
|
2021-01-16 04:25:06 +00:00
|
|
|
Ok(keys.public)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn gen_profile_keys(&self, profile_id: Uuid, key_id: &Url) -> Result<String, StoreError> {
|
2021-01-05 02:23:17 +00:00
|
|
|
let keys = Keys::generate()?;
|
|
|
|
let keys_vec = serde_json::to_vec(&keys)?;
|
|
|
|
self.keys.insert(key_id.as_str(), keys_vec)?;
|
|
|
|
self.profile_key
|
|
|
|
.insert(profile_key_id(profile_id), key_id.as_str())?;
|
2021-01-17 07:27:13 +00:00
|
|
|
self.key_profile
|
|
|
|
.insert(key_id.as_str(), profile_id.as_bytes())?;
|
2021-01-05 02:23:17 +00:00
|
|
|
Ok(keys.public)
|
|
|
|
}
|
|
|
|
|
2021-01-16 04:25:06 +00:00
|
|
|
fn store_server_public_key(
|
|
|
|
&self,
|
|
|
|
server_id: Uuid,
|
|
|
|
key_id: &Url,
|
|
|
|
public_key: &str,
|
|
|
|
) -> Result<(), StoreError> {
|
|
|
|
let keys = Keys::from_public(public_key)?;
|
|
|
|
let keys_vec = serde_json::to_vec(&keys)?;
|
|
|
|
self.keys.insert(key_id.as_str(), keys_vec)?;
|
|
|
|
self.server_key
|
|
|
|
.insert(server_key_id(server_id), key_id.as_str())?;
|
2021-01-17 07:27:13 +00:00
|
|
|
self.key_server
|
|
|
|
.insert(key_id.as_str(), server_id.as_bytes())?;
|
2021-01-16 04:25:06 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-01-17 07:27:13 +00:00
|
|
|
fn store_profile_public_key(
|
2021-01-04 17:34:31 +00:00
|
|
|
&self,
|
|
|
|
profile_id: Uuid,
|
|
|
|
key_id: &Url,
|
|
|
|
public_key: &str,
|
|
|
|
) -> Result<(), StoreError> {
|
|
|
|
let keys = Keys::from_public(public_key)?;
|
|
|
|
let keys_vec = serde_json::to_vec(&keys)?;
|
|
|
|
self.keys.insert(key_id.as_str(), keys_vec)?;
|
|
|
|
self.profile_key
|
|
|
|
.insert(profile_key_id(profile_id), key_id.as_str())?;
|
2021-01-17 07:27:13 +00:00
|
|
|
self.key_profile
|
|
|
|
.insert(key_id.as_str(), profile_id.as_bytes())?;
|
2021-01-04 17:34:31 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-01-17 07:27:13 +00:00
|
|
|
pub(super) fn deleted(&self, id: &Url) -> Result<bool, StoreError> {
|
2021-01-05 03:13:06 +00:00
|
|
|
Ok(self.deleted.get(id.as_str())?.is_some())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn delete_object(&self, id: &Url) -> Result<(), StoreError> {
|
|
|
|
self.deleted.insert(id.as_str(), id.as_str())?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-01-17 07:27:13 +00:00
|
|
|
pub(super) fn object(&self, id: &Url) -> Result<Option<AnyBase>, StoreError> {
|
2021-01-04 17:34:31 +00:00
|
|
|
if let Some(ivec) = self.objects.get(id.as_str())? {
|
|
|
|
let any_base: AnyBase = serde_json::from_slice(&ivec)?;
|
|
|
|
return Ok(Some(any_base));
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(None)
|
|
|
|
}
|
|
|
|
|
2021-01-17 07:27:13 +00:00
|
|
|
pub(super) fn store_object(&self, any_base: &AnyBase) -> Result<(), StoreError> {
|
2021-01-04 17:34:31 +00:00
|
|
|
if let Some(id) = any_base.id() {
|
2021-01-05 02:23:17 +00:00
|
|
|
let obj_vec = serde_json::to_vec(any_base)?;
|
2021-01-04 17:34:31 +00:00
|
|
|
self.objects.insert(id.as_str(), obj_vec)?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-01-16 04:25:06 +00:00
|
|
|
fn apub_for_server_follow_request(&self, id: Uuid) -> Result<Option<Url>, StoreError> {
|
|
|
|
self.apub_for_id(StoredRecords::ServerFollowRequest(id))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn server_follow_request(&self, apub_id: &Url, id: Uuid) -> Result<(), StoreError> {
|
|
|
|
self.establish(apub_id, StoredRecords::ServerFollowRequest(id))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn apub_for_server_follow(&self, id: Uuid) -> Result<Option<Url>, StoreError> {
|
|
|
|
self.apub_for_id(StoredRecords::ServerFollow(id))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn server_follow(&self, apub_id: &Url, id: Uuid) -> Result<(), StoreError> {
|
|
|
|
self.establish(apub_id, StoredRecords::ServerFollow(id))
|
|
|
|
}
|
|
|
|
|
2021-01-17 07:27:13 +00:00
|
|
|
pub fn apub_for_server(&self, id: Uuid) -> Result<Option<Url>, StoreError> {
|
2021-01-16 04:25:06 +00:00
|
|
|
self.apub_for_id(StoredRecords::Server(id))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn server(&self, apub_id: &Url, id: Uuid) -> Result<(), StoreError> {
|
|
|
|
self.establish(apub_id, StoredRecords::Server(id))
|
|
|
|
}
|
|
|
|
|
2021-01-05 02:23:17 +00:00
|
|
|
fn apub_for_submission(&self, id: Uuid) -> Result<Option<Url>, StoreError> {
|
|
|
|
self.apub_for_id(StoredRecords::Submission(id))
|
2021-01-04 17:34:31 +00:00
|
|
|
}
|
|
|
|
|
2021-01-05 02:23:17 +00:00
|
|
|
fn submission(&self, apub_id: &Url, id: Uuid) -> Result<(), StoreError> {
|
|
|
|
self.establish(apub_id, StoredRecords::Submission(id))
|
2021-01-04 17:34:31 +00:00
|
|
|
}
|
|
|
|
|
2021-01-17 07:27:13 +00:00
|
|
|
pub fn apub_for_profile(&self, id: Uuid) -> Result<Option<Url>, StoreError> {
|
2021-01-05 02:23:17 +00:00
|
|
|
self.apub_for_id(StoredRecords::Profile(id))
|
2021-01-04 17:34:31 +00:00
|
|
|
}
|
|
|
|
|
2021-01-05 02:23:17 +00:00
|
|
|
fn profile(&self, apub_id: &Url, id: Uuid) -> Result<(), StoreError> {
|
|
|
|
self.establish(apub_id, StoredRecords::Profile(id))
|
2021-01-04 17:34:31 +00:00
|
|
|
}
|
|
|
|
|
2021-01-14 04:43:43 +00:00
|
|
|
fn report(&self, apub_id: &Url, id: Uuid) -> Result<(), StoreError> {
|
|
|
|
self.establish(apub_id, StoredRecords::Report(id))
|
|
|
|
}
|
|
|
|
|
2021-01-05 02:23:17 +00:00
|
|
|
fn apub_for_comment(&self, id: Uuid) -> Result<Option<Url>, StoreError> {
|
|
|
|
self.apub_for_id(StoredRecords::Comment(id))
|
2021-01-04 17:34:31 +00:00
|
|
|
}
|
|
|
|
|
2021-01-05 02:23:17 +00:00
|
|
|
fn comment(&self, apub_id: &Url, id: Uuid) -> Result<(), StoreError> {
|
|
|
|
self.establish(apub_id, StoredRecords::Comment(id))
|
2021-01-04 17:34:31 +00:00
|
|
|
}
|
|
|
|
|
2021-01-05 02:23:17 +00:00
|
|
|
fn apub_for_react(&self, id: Uuid) -> Result<Option<Url>, StoreError> {
|
|
|
|
self.apub_for_id(StoredRecords::React(id))
|
2021-01-04 17:34:31 +00:00
|
|
|
}
|
|
|
|
|
2021-01-05 02:23:17 +00:00
|
|
|
fn react(&self, apub_id: &Url, id: Uuid) -> Result<(), StoreError> {
|
2021-01-04 17:34:31 +00:00
|
|
|
self.establish(apub_id, StoredRecords::React(id))
|
|
|
|
}
|
|
|
|
|
2021-01-17 07:27:13 +00:00
|
|
|
fn apub_for_file(&self, id: Uuid) -> Result<Option<Url>, StoreError> {
|
|
|
|
self.apub_for_id(StoredRecords::File(id))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(super) fn file(&self, apub_id: &Url, id: Uuid) -> Result<(), StoreError> {
|
|
|
|
self.establish(apub_id, StoredRecords::File(id))
|
|
|
|
}
|
|
|
|
|
2021-01-05 02:23:17 +00:00
|
|
|
fn apub_for_follow(&self, id: Uuid) -> Result<Option<Url>, StoreError> {
|
|
|
|
self.apub_for_id(StoredRecords::Follow(id))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn follow(&self, apub_id: &Url, id: Uuid) -> Result<(), StoreError> {
|
2021-01-04 17:34:31 +00:00
|
|
|
self.establish(apub_id, StoredRecords::Follow(id))
|
|
|
|
}
|
|
|
|
|
2021-01-05 02:23:17 +00:00
|
|
|
fn apub_for_follow_request(&self, id: Uuid) -> Result<Option<Url>, StoreError> {
|
|
|
|
self.apub_for_id(StoredRecords::FollowRequest(id))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn follow_request(&self, apub_id: &Url, id: Uuid) -> Result<(), StoreError> {
|
2021-01-04 17:34:31 +00:00
|
|
|
self.establish(apub_id, StoredRecords::FollowRequest(id))
|
|
|
|
}
|
|
|
|
|
2021-01-05 02:23:17 +00:00
|
|
|
fn apub_for_block(&self, id: Uuid) -> Result<Option<Url>, StoreError> {
|
|
|
|
self.apub_for_id(StoredRecords::Block(id))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn block(&self, apub_id: &Url, id: Uuid) -> Result<(), StoreError> {
|
2021-01-04 17:34:31 +00:00
|
|
|
self.establish(apub_id, StoredRecords::Block(id))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn establish(&self, apub_id: &Url, id: StoredRecords) -> Result<(), StoreError> {
|
|
|
|
self.apub_id
|
|
|
|
.insert(apub_id.as_str(), id.to_string().as_bytes())?;
|
|
|
|
self.id_apub
|
|
|
|
.insert(id.to_string(), apub_id.as_str().as_bytes())?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-01-17 07:27:13 +00:00
|
|
|
pub(super) fn id_for_apub(&self, apub_id: &Url) -> Result<Option<StoredRecords>, StoreError> {
|
2021-01-04 17:34:31 +00:00
|
|
|
Ok(self
|
|
|
|
.apub_id
|
|
|
|
.get(apub_id.as_str())?
|
|
|
|
.and_then(record_from_ivec))
|
|
|
|
}
|
|
|
|
|
2021-01-05 02:23:17 +00:00
|
|
|
fn apub_for_id(&self, id: StoredRecords) -> Result<Option<Url>, StoreError> {
|
2021-01-04 17:34:31 +00:00
|
|
|
Ok(self.id_apub.get(id.to_string())?.and_then(url_from_ivec))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Keys {
|
|
|
|
fn from_public(public: &str) -> Result<Self, KeyError> {
|
|
|
|
use rsa::RSAPublicKey;
|
|
|
|
use rsa_pem::KeyExt;
|
|
|
|
|
|
|
|
RSAPublicKey::from_pem_pkcs8(public).map_err(|_| KeyError)?;
|
|
|
|
|
|
|
|
Ok(Keys {
|
|
|
|
public: public.to_owned(),
|
|
|
|
private: None,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn generate() -> Result<Self, KeyError> {
|
|
|
|
use rsa::RSAPrivateKey;
|
|
|
|
use rsa_pem::KeyExt;
|
|
|
|
|
|
|
|
let mut rng = rand::thread_rng();
|
|
|
|
|
|
|
|
let private_key = RSAPrivateKey::new(&mut rng, 2048).map_err(|_| KeyError)?;
|
|
|
|
let private = private_key.to_pem_pkcs8().map_err(|_| KeyError)?;
|
|
|
|
|
|
|
|
let public_key = private_key.to_public_key();
|
|
|
|
let public = public_key.to_pem_pkcs8().map_err(|_| KeyError)?;
|
|
|
|
|
|
|
|
Ok(Keys {
|
|
|
|
public,
|
|
|
|
private: Some(private),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-05 02:23:17 +00:00
|
|
|
fn profile_endpoint_id(profile_id: Uuid) -> String {
|
|
|
|
format!("/profile/{}/endpoint-id", profile_id)
|
2021-01-04 17:34:31 +00:00
|
|
|
}
|
|
|
|
|
2021-01-16 04:25:06 +00:00
|
|
|
fn server_endpoint_id(server_id: Uuid) -> String {
|
|
|
|
format!("/server/{}/endpoint-id", server_id)
|
|
|
|
}
|
|
|
|
|
2021-01-05 02:23:17 +00:00
|
|
|
fn profile_key_id(profile_id: Uuid) -> String {
|
|
|
|
format!("/profile/{}/key-id", profile_id)
|
2021-01-04 17:34:31 +00:00
|
|
|
}
|
|
|
|
|
2021-01-16 04:25:06 +00:00
|
|
|
fn server_key_id(server_id: Uuid) -> String {
|
|
|
|
format!("/server/{}/key-id", server_id)
|
|
|
|
}
|
|
|
|
|
2021-01-04 17:34:31 +00:00
|
|
|
impl fmt::Debug for Store {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
f.debug_struct("Store")
|
|
|
|
.field("relationship", &"Tree")
|
2021-01-05 02:23:17 +00:00
|
|
|
.field("apub_id", &"Tree")
|
|
|
|
.field("id_apub", &"Tree")
|
|
|
|
.field("objects", &"Tree")
|
2021-01-04 17:34:31 +00:00
|
|
|
.field("keys", &"Tree")
|
2021-01-05 02:23:17 +00:00
|
|
|
.field("profile_key", &"Tree")
|
2021-01-16 04:25:06 +00:00
|
|
|
.field("server_key", &"Tree")
|
2021-01-04 17:34:31 +00:00
|
|
|
.field("endpoints", &"Tree")
|
2021-01-05 02:23:17 +00:00
|
|
|
.field("profile_endpoint", &"Tree")
|
2021-01-16 04:25:06 +00:00
|
|
|
.field("server_endpoint", &"Tree")
|
2021-01-04 17:34:31 +00:00
|
|
|
.field("info", &"Rc<dyn ApubIds>")
|
|
|
|
.finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, thiserror::Error)]
|
2021-01-17 07:27:13 +00:00
|
|
|
#[error("Failed to parse StoredRecord: {0}")]
|
|
|
|
pub struct StoredRecordsError(String);
|
2021-01-04 17:34:31 +00:00
|
|
|
|
|
|
|
impl std::str::FromStr for StoredRecords {
|
|
|
|
type Err = StoredRecordsError;
|
|
|
|
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
2021-01-17 07:27:13 +00:00
|
|
|
let split_pos = s
|
|
|
|
.find(':')
|
|
|
|
.ok_or(StoredRecordsError(format!("no ':' in {}", s)))?;
|
2021-01-04 17:34:31 +00:00
|
|
|
|
|
|
|
let (kind, uuid) = s.split_at(split_pos);
|
|
|
|
let uuid = uuid.trim_start_matches(':');
|
|
|
|
|
2021-01-17 07:27:13 +00:00
|
|
|
let id = uuid
|
|
|
|
.parse::<Uuid>()
|
|
|
|
.map_err(|e| StoredRecordsError(e.to_string()))?;
|
2021-01-04 17:34:31 +00:00
|
|
|
|
|
|
|
let record = match kind {
|
2021-01-16 04:25:06 +00:00
|
|
|
"server" => StoredRecords::Server(id),
|
2021-01-14 04:43:43 +00:00
|
|
|
"report" => StoredRecords::Report(id),
|
2021-01-04 17:34:31 +00:00
|
|
|
"profile" => StoredRecords::Profile(id),
|
|
|
|
"submission" => StoredRecords::Submission(id),
|
|
|
|
"comment" => StoredRecords::Comment(id),
|
|
|
|
"react" => StoredRecords::React(id),
|
|
|
|
"file" => StoredRecords::File(id),
|
|
|
|
"block" => StoredRecords::Block(id),
|
|
|
|
"follow" => StoredRecords::Follow(id),
|
|
|
|
"follow-request" => StoredRecords::FollowRequest(id),
|
2021-01-16 04:25:06 +00:00
|
|
|
"server-follow" => StoredRecords::ServerFollow(id),
|
2021-01-17 07:27:13 +00:00
|
|
|
"server-follow-request" => StoredRecords::ServerFollowRequest(id),
|
|
|
|
other => return Err(StoredRecordsError(format!("record kind: {}", other))),
|
2021-01-04 17:34:31 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
Ok(record)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for StoredRecords {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
match self {
|
2021-01-16 04:25:06 +00:00
|
|
|
StoredRecords::Server(id) => write!(f, "server:{}", id),
|
2021-01-14 04:43:43 +00:00
|
|
|
StoredRecords::Report(id) => write!(f, "report:{}", id),
|
2021-01-04 17:34:31 +00:00
|
|
|
StoredRecords::Profile(id) => write!(f, "profile:{}", id),
|
|
|
|
StoredRecords::Submission(id) => write!(f, "submission:{}", id),
|
|
|
|
StoredRecords::Comment(id) => write!(f, "comment:{}", id),
|
|
|
|
StoredRecords::React(id) => write!(f, "react:{}", id),
|
|
|
|
StoredRecords::File(id) => write!(f, "file:{}", id),
|
|
|
|
StoredRecords::Block(id) => write!(f, "block:{}", id),
|
|
|
|
StoredRecords::Follow(id) => write!(f, "follow:{}", id),
|
|
|
|
StoredRecords::FollowRequest(id) => write!(f, "follow-request:{}", id),
|
2021-01-16 04:25:06 +00:00
|
|
|
StoredRecords::ServerFollow(id) => write!(f, "server-follow:{}", id),
|
|
|
|
StoredRecords::ServerFollowRequest(id) => write!(f, "server-follow-request:{}", id),
|
2021-01-04 17:34:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<KeyError> for StoreError {
|
|
|
|
fn from(_: KeyError) -> Self {
|
|
|
|
StoreError::Key
|
|
|
|
}
|
|
|
|
}
|
2021-01-17 07:27:13 +00:00
|
|
|
|
|
|
|
fn uuid_from_ivec(ivec: sled::IVec) -> Option<Uuid> {
|
|
|
|
Uuid::from_slice(&ivec).ok()
|
|
|
|
}
|