1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
//
// Wildland Project
//
// Copyright © 2022 Golem Foundation
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 3 as published by
// the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use std::collections::HashMap;
use std::path::PathBuf;
use std::sync::Arc;
use serde::{Deserialize, Serialize};
use thiserror::Error;
use uuid::Uuid;
use super::error::CatlibResult;
use crate::Storage;
pub type PubKey = [u8; 32];
#[derive(Error, Debug, Clone)]
#[repr(C)]
pub enum PubKeyError {
#[error("Size of the public key should be equal to 32 bytes")]
KeySizeMismatch,
}
pub fn new_pub_key(input: Vec<u8>) -> Result<PubKey, PubKeyError> {
let mut result = [0; 32];
if input.len() != 32 {
return Err(PubKeyError::KeySizeMismatch);
}
result.copy_from_slice(&input[..32]);
Ok(result)
}
impl From<WildlandPubKey> for PubKey {
fn from(identity: WildlandPubKey) -> Self {
identity.0
}
}
#[derive(Debug, Clone, PartialEq, Hash, Eq, Serialize, Deserialize)]
pub struct WildlandPubKey(pub PubKey);
impl WildlandPubKey {
pub fn hex_encode(&self) -> String {
hex::encode(self.0)
}
pub fn get_pub_key(&self) -> PubKey {
self.0
}
}
impl From<PubKey> for WildlandPubKey {
fn from(pubkey: [u8; 32]) -> Self {
Self(pubkey)
}
}
pub type ContainerPath = std::path::PathBuf;
/// Association of a device public key with the FEK (Forest Encryption Key) encrypted with it.
///
pub type Devices = HashMap<WildlandPubKey, Vec<u8>>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CatlibContainerFilter {
HasUuid(Uuid),
HasExactPath(PathBuf),
HasPathStartingWith(PathBuf),
Or(Box<CatlibContainerFilter>, Box<CatlibContainerFilter>),
And(Box<CatlibContainerFilter>, Box<CatlibContainerFilter>),
Not(Box<CatlibContainerFilter>),
Any(Vec<CatlibContainerFilter>),
}
/// `ForestManifest` trait is an API providing methods needed to operate on the forest's
/// state. It should be implemented by Cat-Lib instance and should be
/// treated as a kind of a proxy layer between Wildland Core and the external
/// persistent data storage instance (for e.g. database).
///
#[cfg_attr(test, mockall::automock)]
pub trait ForestManifest: std::fmt::Debug + Send + Sync {
fn version(&self) -> u64;
/// Add manifest Device (pubkey with Forest Encryption Key encrypted with this key)
///
/// Returns whether the value was newly inserted. That is:
///
/// - If the device did not previously exist, `true` is returned.
/// - If the device already exists, `false` is returned.
///
fn add_device(&self, device: WildlandPubKey, encrypted_fek: Vec<u8>) -> CatlibResult<bool>;
/// Delete manifest Signer
///
/// Returns whether the value was already present. That is:
///
/// - If the device did not previously exist, `false` is returned.
/// - If the device existed in the set, `true` is returned.
///
fn delete_device(&self, device: WildlandPubKey) -> CatlibResult<bool>;
/// Return list of Forest Containers
///
fn find_containers(
&self,
filters: Option<CatlibContainerFilter>, // Passing filter allows db client to optimize query (filtering by lambda does not)
) -> CatlibResult<Vec<Arc<dyn ContainerManifest>>>;
/// Delete Forest
///
/// **WARN: The underlying objects are not removed recursively**
///
fn delete(&self) -> CatlibResult<bool>;
/// Create an empty container, bound to the Forest.
///
/// To set container path, use [`crate::Container::change_path`]
///
fn create_container(
&self,
container_uuid: Uuid,
data: Vec<u8>,
path: ContainerPath,
storages: Vec<Storage>,
) -> CatlibResult<Arc<dyn ContainerManifest>>;
/// Set Forest arbitrary data
///
fn set_data(&self, data: Vec<u8>) -> CatlibResult<()>;
/// Retrieve Forest's metadata
///
fn data(&self) -> CatlibResult<Vec<u8>>;
/// Retrieve Forest's owner identity
///
fn owner(&self) -> WildlandPubKey;
/// Retrieve Forests's devices
///
fn devices(&self) -> CatlibResult<Devices>;
/// Fetch every Storage Template from the forest.
fn get_storage_templates(&self) -> CatlibResult<Vec<(Uuid, Vec<u8>)>>;
/// Save StorageTemplate data in CatLib.
///
/// It creates a new record if `template_id` is None.
///
/// Returns uuid of the saved template.
fn save_storage_template(
&self,
template_id: Option<Uuid>,
value: Vec<u8>,
) -> CatlibResult<Uuid>;
}
/// `ContainerManifest` trait is an API providing methods needed to manipulate container's
/// configuration state. It should be implemented by Cat-Lib instance and should be
/// treated as a kind of a proxy layer between Wildland Core and the external
/// persistent data storage instance (for e.g. database).
///
#[cfg_attr(test, mockall::automock)]
pub trait ContainerManifest: std::fmt::Debug + Send + Sync {
fn version(&self) -> u64;
/// Lists the storages that the given container use in order to keep the data.
///
fn get_storages(&self) -> CatlibResult<Vec<Vec<u8>>>;
/// This operation adds a given Storage Backend to the container.
/// The procedure involves starting the data sync mechanism between the new storage
/// and the other present storages.
///
/// Container can have multiple storages. Given container should has exact copies
/// of the data on every storage.
///
fn add_storage(&self, storage: Vec<u8>) -> CatlibResult<()>;
/// Overwrites the storages of a container
///
/// Storages vector cannot be empty
fn overwrite_storages(&self, storages: Vec<Vec<u8>>) -> CatlibResult<()>;
/// Deletes all records regarding the container from the
/// database.
///
fn delete(&self) -> CatlibResult<()>;
/// Return [`crate::Forest`] that contains the [`crate::Container`].
///
fn forest(&self) -> CatlibResult<Arc<dyn ForestManifest>>;
/// Returns the unique ID of the container.
///
fn uuid(&self) -> Uuid;
/// Overrides container path.
///
fn change_path(&self, path: ContainerPath) -> CatlibResult<()>;
/// Get path from the given container.
///
fn get_path(&self) -> CatlibResult<ContainerPath>;
/// Retrieve Forest's owner identity
///
fn owner(&self) -> CatlibResult<WildlandPubKey>;
/// Retrieves containers arbitrary metadata
///
fn data(&self) -> CatlibResult<Vec<u8>>;
/// Sets metadata
///
fn set_data(&self, data: Vec<u8>) -> CatlibResult<()>;
}