pub struct SealedFileMlsStorage { /* private fields */ }Expand description
MLS storage in files, every record sealed under a key derived from the operator’s store key.
This is the headless host’s stand-in for the platform keystore the mobile bindings use. What it protects against is someone who can read the directory but does not have the store key: a copied disk, a backup, another local user. Against that reader:
- Values are sealed. ChaCha20-Poly1305 under a key derived with HKDF from the store key and the account namespace, so a record copied into another account’s directory does not open.
- Keys are sealed too. The record’s
(key_type, key_id)travels inside the ciphertext, and file names are an HMAC under a second derived key. A listing reveals how many records of each kind exist, never which peers or groups they belong to. (The protocol-state store’s names are an unsalted digest, a format shared with the bindings.) - A record is bound to its slot. The associated data is the file name, and the decrypted header must name the key asked for, so a record moved onto another’s name does not open.
What it cannot protect against is the store key itself. It arrives from a
StoreKeyProvider, and on a host without a keystore that means in the
clear from the operator’s configuration (residual risk R18).
A record that does not authenticate is reported as
StorageError::CorruptedData, naming its file, and left in place.
The store never deletes on a read, because the common cause is a wrong key
and deleting on that would destroy the identity. Self::open checks the
key against a sealed check file first and refuses a wrong one before any
record is read, so a record that fails afterwards is damaged: the error
names the file, and what deleting it costs depends on what it held (the
engine regenerates a damaged protocol-state record key by itself).
Implementations§
Source§impl SealedFileMlsStorage
impl SealedFileMlsStorage
Sourcepub fn open(
root: impl AsRef<Path>,
namespace: &str,
provider: &dyn StoreKeyProvider,
) -> Result<Self, FileStoreError>
pub fn open( root: impl AsRef<Path>, namespace: &str, provider: &dyn StoreKeyProvider, ) -> Result<Self, FileStoreError>
Opens (creating if needed) the store at <root>/<namespace>/, sealed
under the key provider supplies.
The provider is asked once. The first open writes a sealed check file;
every later open must open it, and a key that does not is refused with
FileStoreError::WrongStoreKey before any record is read or changed.
A check file that is missing or damaged is rebuilt only when an
existing record opens under the key, which proves it. A check that
does not open over a store with no records is refused with
FileStoreError::KeyCheckUnverifiable, which names the check file.
A second store over the same directory is refused with
FileStoreError::InUse until this one is closed or dropped.
root should be a directory that survives an upgrade: this store holds
the device’s identity, and losing it gives the device a new address.
Examples found in repository?
44fn open_stores(
45 root: &std::path::Path,
46 key: &dyn StoreKeyProvider,
47) -> Result<(Arc<SealedFileMlsStorage>, Arc<FileProtocolStateStorage>), Box<dyn std::error::Error>>
48{
49 let namespace = account_storage_namespace(APP_ID, PROFILE);
50 // Two roots: MLS material may outlive an installation, protocol state
51 // must not.
52 let secure = SealedFileMlsStorage::open(root.join("keys"), &namespace, key)?;
53 let records = FileProtocolStateStorage::open(root.join("state"), &namespace)?;
54 Ok((Arc::new(secure), Arc::new(records)))
55}Sourcepub fn close(&self)
pub fn close(&self)
Releases the directory and refuses every later operation.
The lock goes at once, whoever still holds the store: an engine that was handed it, a host object its runtime has not freed yet. An operation in flight finishes first. Afterwards every operation is an error naming the directory, and a new store may open over it. Closing twice is closing once.
Sourcepub fn holds_records(
root: impl AsRef<Path>,
namespace: &str,
) -> Result<bool, FileStoreError>
pub fn holds_records( root: impl AsRef<Path>, namespace: &str, ) -> Result<bool, FileStoreError>
Whether <root>/<namespace>/ holds MLS records, without opening,
creating or locking anything.
A record file, not the directory and not a type directory. An open
refused after the account directory was made (a wrong key, a
protocol-state root that could not be created) leaves the directory,
its lock file and its key check, and no identity. A first write that
failed (a full disk, a crash) leaves a type directory with nothing in
it but a temporary. A directory that cannot be read, at either level,
is an FileStoreError::Io, never “no records”.
Trait Implementations§
Source§impl Debug for SealedFileMlsStorage
impl Debug for SealedFileMlsStorage
Source§impl MlsStorage for SealedFileMlsStorage
impl MlsStorage for SealedFileMlsStorage
Source§fn store(&self, key_type: &str, key_id: &str, data: &[u8]) -> StorageResult<()>
fn store(&self, key_type: &str, key_id: &str, data: &[u8]) -> StorageResult<()>
Source§fn load(&self, key_type: &str, key_id: &str) -> StorageResult<Option<Vec<u8>>>
fn load(&self, key_type: &str, key_id: &str) -> StorageResult<Option<Vec<u8>>>
Source§fn delete(&self, key_type: &str, key_id: &str) -> StorageResult<()>
fn delete(&self, key_type: &str, key_id: &str) -> StorageResult<()>
Source§fn list_keys(&self, key_type: &str) -> StorageResult<Vec<String>>
fn list_keys(&self, key_type: &str) -> StorageResult<Vec<String>>
Source§fn exists(&self, key_type: &str, key_id: &str) -> Result<bool, StorageError>
fn exists(&self, key_type: &str, key_id: &str) -> Result<bool, StorageError>
Source§fn clear_type(&self, key_type: &str) -> Result<(), StorageError>
fn clear_type(&self, key_type: &str) -> Result<(), StorageError>
Auto Trait Implementations§
impl !Freeze for SealedFileMlsStorage
impl RefUnwindSafe for SealedFileMlsStorage
impl Send for SealedFileMlsStorage
impl Sync for SealedFileMlsStorage
impl Unpin for SealedFileMlsStorage
impl UnsafeUnpin for SealedFileMlsStorage
impl UnwindSafe for SealedFileMlsStorage
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Declassify for T
impl<T> Declassify for T
type Declassified = T
fn declassify(self) -> T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> Paint for Twhere
T: ?Sized,
impl<T> Paint for Twhere
T: ?Sized,
Source§fn fg(&self, value: Color) -> Painted<&T>
fn fg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the foreground set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like red() and
green(), which have the same functionality but are
pithier.
§Example
Set foreground color to white using fg():
use yansi::{Paint, Color};
painted.fg(Color::White);Set foreground color to white using white().
use yansi::Paint;
painted.white();Source§fn bright_black(&self) -> Painted<&T>
fn bright_black(&self) -> Painted<&T>
Source§fn bright_red(&self) -> Painted<&T>
fn bright_red(&self) -> Painted<&T>
Source§fn bright_green(&self) -> Painted<&T>
fn bright_green(&self) -> Painted<&T>
Source§fn bright_yellow(&self) -> Painted<&T>
fn bright_yellow(&self) -> Painted<&T>
Source§fn bright_blue(&self) -> Painted<&T>
fn bright_blue(&self) -> Painted<&T>
Source§fn bright_magenta(&self) -> Painted<&T>
fn bright_magenta(&self) -> Painted<&T>
Source§fn bright_cyan(&self) -> Painted<&T>
fn bright_cyan(&self) -> Painted<&T>
Source§fn bright_white(&self) -> Painted<&T>
fn bright_white(&self) -> Painted<&T>
Source§fn bg(&self, value: Color) -> Painted<&T>
fn bg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the background set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like on_red() and
on_green(), which have the same functionality but
are pithier.
§Example
Set background color to red using fg():
use yansi::{Paint, Color};
painted.bg(Color::Red);Set background color to red using on_red().
use yansi::Paint;
painted.on_red();Source§fn on_primary(&self) -> Painted<&T>
fn on_primary(&self) -> Painted<&T>
Source§fn on_magenta(&self) -> Painted<&T>
fn on_magenta(&self) -> Painted<&T>
Source§fn on_bright_black(&self) -> Painted<&T>
fn on_bright_black(&self) -> Painted<&T>
Source§fn on_bright_red(&self) -> Painted<&T>
fn on_bright_red(&self) -> Painted<&T>
Source§fn on_bright_green(&self) -> Painted<&T>
fn on_bright_green(&self) -> Painted<&T>
Source§fn on_bright_yellow(&self) -> Painted<&T>
fn on_bright_yellow(&self) -> Painted<&T>
Source§fn on_bright_blue(&self) -> Painted<&T>
fn on_bright_blue(&self) -> Painted<&T>
Source§fn on_bright_magenta(&self) -> Painted<&T>
fn on_bright_magenta(&self) -> Painted<&T>
Source§fn on_bright_cyan(&self) -> Painted<&T>
fn on_bright_cyan(&self) -> Painted<&T>
Source§fn on_bright_white(&self) -> Painted<&T>
fn on_bright_white(&self) -> Painted<&T>
Source§fn attr(&self, value: Attribute) -> Painted<&T>
fn attr(&self, value: Attribute) -> Painted<&T>
Enables the styling Attribute value.
This method should be used rarely. Instead, prefer to use
attribute-specific builder methods like bold() and
underline(), which have the same functionality
but are pithier.
§Example
Make text bold using attr():
use yansi::{Paint, Attribute};
painted.attr(Attribute::Bold);Make text bold using using bold().
use yansi::Paint;
painted.bold();Source§fn rapid_blink(&self) -> Painted<&T>
fn rapid_blink(&self) -> Painted<&T>
Source§fn quirk(&self, value: Quirk) -> Painted<&T>
fn quirk(&self, value: Quirk) -> Painted<&T>
Enables the yansi Quirk value.
This method should be used rarely. Instead, prefer to use quirk-specific
builder methods like mask() and
wrap(), which have the same functionality but are
pithier.
§Example
Enable wrapping using .quirk():
use yansi::{Paint, Quirk};
painted.quirk(Quirk::Wrap);Enable wrapping using wrap().
use yansi::Paint;
painted.wrap();Source§fn clear(&self) -> Painted<&T>
👎Deprecated since 1.0.1: renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
fn clear(&self) -> Painted<&T>
renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
Source§fn whenever(&self, value: Condition) -> Painted<&T>
fn whenever(&self, value: Condition) -> Painted<&T>
Conditionally enable styling based on whether the Condition value
applies. Replaces any previous condition.
See the crate level docs for more details.
§Example
Enable styling painted only when both stdout and stderr are TTYs:
use yansi::{Paint, Condition};
painted.red().on_yellow().whenever(Condition::STDOUTERR_ARE_TTY);