Development Documentation (main branch) - For stable release docs, see docs.rs/eidetica
Skip to main content

PasswordStore

Struct PasswordStore 

Source
pub struct PasswordStore<S: Store> { /* private fields */ }
Expand description

Password-encrypted store wrapper.

Wraps any Store type with transparent AES-256-GCM encryption using password-derived keys (Argon2id). The type parameter S specifies the wrapped store type, and PasswordStore<S> delegates Store::Data to S::Data — encryption is a transport-level concern invisible at the type level.

§Type Parameter

  • S - The wrapped store type (e.g., DocStore, Table<T>)

§State Machine

PasswordStore has three states (derived from internal fields):

  1. Uninitialized - Created via get_store(), no encryption configured
  2. Locked - Has encryption config, not yet decrypted
  3. Unlocked - Decrypted and ready to use

State transitions:

  • get_store() → Uninitialized (new) or Locked (existing)
  • initialize() → Unlocked (from Uninitialized only)
  • open() → Unlocked (from Locked only)

§Security

  • Encryption: AES-256-GCM authenticated encryption
  • Key Derivation: Argon2id memory-hard password hashing
  • Nonces: Unique random nonce per encryption operation
  • Zeroization: The converted password, temporary and cached keys, and local plaintext JSON buffers live in zeroizing owners that clear their current allocation on drop, including on errors, cancellation and unwinding
  • Diagnostics: Errors about malformed decrypted metadata or rows do not include decrypted content

§Limitations

  • Password Loss: Losing the password means permanent data loss
  • Performance: Encryption/decryption overhead on every operation
  • Metadata: Backends can observe record counts, ciphertext sizes, and access patterns
  • Memory: Cleanup is best-effort for the owners above. Caller copies, plaintext returned to the application, parsed Doc/CRDT values, parser, KDF, cipher and allocator copies are not erased, and the registered encryptor (with its password and key) lives until the last clone of the transaction drops

§Examples

Creating a new encrypted store:

let tx = db.new_transaction().await?;
let mut encrypted = tx.get_store::<PasswordStore<DocStore>>("secrets").await?;
encrypted.initialize("my_password", Doc::new()).await?;

let docstore = encrypted.inner().await?;
docstore.set("key", "secret value").await?;
tx.commit().await?;

Opening an existing encrypted store:

let tx = db.new_transaction().await?;
let mut store = tx.get_store::<PasswordStore<DocStore>>("secrets").await?;
store.open("my_password")?;

let docstore = store.inner().await?;
let value = docstore.get("key").await?;

Implementations§

Source§

impl<S: Store> PasswordStore<S>

Source

pub async fn initialize( &mut self, password: impl Into<String>, wrapped_config: Doc, ) -> Result<()>

Initialize encryption on an uninitialized store

This configures encryption for a PasswordStore that was obtained via get_store(). The wrapped store’s type (derived from S) and config are encrypted and stored in the PasswordStore’s configuration in _index.

After calling this method, the store transitions to the Unlocked state and is ready to use.

§Arguments
  • password - Password for encryption. After the state check, it is converted and moved into a zeroizing owner before any fallible work. An argument rejected by the state check, and copies the caller retains, are not zeroized by this method.
  • wrapped_config - Configuration for wrapped store
§Returns

Ok(()) on success, the store is now unlocked

§Errors
  • Returns error if store is not in Uninitialized state
  • Returns error if encryption fails
§Examples
let tx = db.new_transaction().await?;
let mut encrypted = tx.get_store::<PasswordStore<DocStore>>("secrets").await?;
encrypted.initialize("my_password", Doc::new()).await?;

let docstore = encrypted.inner().await?;
docstore.set("key", "secret value").await?;
tx.commit().await?;
Source

pub fn open(&mut self, password: impl Into<String>) -> Result<()>

Open (unlock) the encrypted store with a password

This decrypts the wrapped store configuration and caches the password for subsequent encrypt/decrypt operations.

§Arguments
  • password - Password to decrypt the store
§Returns

Ok(()) if password is correct, Err otherwise

§Errors
  • Returns error if store is Uninitialized (use initialize() first)
  • Returns error if store is already Unlocked
  • Returns error if password is incorrect
§Security

The password is cached in memory (with zeroization on drop) for convenience. After the state check, it is converted and moved into a zeroizing owner before any fallible work; an argument rejected by the state check, and copies the caller retains, are not zeroized by this method. Errors about malformed decrypted metadata or a mismatched wrapped type do not include decrypted content.

Source

pub fn is_open(&self) -> bool

Check if the store is currently unlocked (password cached)

Source

pub fn is_initialized(&self) -> bool

Check if the store is initialized (has encryption configuration)

Source

pub async fn inner(&self) -> Result<S>

Get the wrapped store, providing transparent encryption.

Returns the inner S store instance that transparently encrypts data on write and decrypts on read. The wrapped store is unaware of encryption — all crypto operations are handled by an encryptor registered with the transaction during open() or initialize().

§Errors
  • Returns error if store is not opened (call open() first)
§Examples
let mut encrypted = tx2.get_store::<PasswordStore<DocStore>>("test").await?;
encrypted.open("pass")?;

let docstore = encrypted.inner().await?;
docstore.set("key", "value").await?; // Automatically encrypted

Trait Implementations§

Source§

impl<S: Store> Registered for PasswordStore<S>

Source§

fn type_id() -> &'static str

Returns a unique identifier for this type. Read more
Source§

fn supports_type_id(type_id: &str) -> bool

Check if this type supports loading from a stored type_id. Read more
Source§

impl<S: Store> Store for PasswordStore<S>

Source§

type Data = <S as Store>::Data

The CRDT data type used for local (staged) data in this store. Read more
Source§

fn state_model() -> StoreStateModel<Self::Data>

Representation of this store’s cached current state. Read more
Source§

fn load<'life0, 'async_trait>( txn: &'life0 Transaction, subtree_name: String, ) -> Pin<Box<dyn Future<Output = Result<Self>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Creates a new Store handle associated with a specific transaction. Read more
Source§

fn register<'life0, 'async_trait>( txn: &'life0 Transaction, subtree_name: String, ) -> Pin<Box<dyn Future<Output = Result<Self>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Initializes a new subtree and registers it in the _index. Read more
Source§

fn name(&self) -> &str

Returns the name of this subtree.
Source§

fn transaction(&self) -> &Transaction

Returns a reference to the transaction this Store is associated with. Read more
Source§

fn default_config() -> Doc

Returns the default configuration for this Store type as a Doc. Read more
Source§

fn open<'life0, 'async_trait>( txn: &'life0 Transaction, name: impl 'async_trait + Into<String> + Send, ) -> Pin<Box<dyn Future<Output = Result<Self>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Opens this Store on a transaction, registering the subtree if it does not yet exist. Read more
Source§

fn get_config<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<Doc>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Gets the current configuration for this Store from the _index subtree. Read more
Source§

fn set_config<'life0, 'async_trait>( &'life0 self, config: Doc, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Sets the configuration for this Store in the _index subtree. Read more
Source§

fn get_height_strategy<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<Option<HeightStrategy>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Gets the height strategy for this Store from the _index subtree. Read more
Source§

fn set_height_strategy<'life0, 'async_trait>( &'life0 self, strategy: Option<HeightStrategy>, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Sets the height strategy for this Store in the _index subtree. Read more
Source§

fn local_data(&self) -> Result<Option<Self::Data>>

Returns the local (staged) data for this store from the current transaction. Read more

Auto Trait Implementations§

§

impl<S> Freeze for PasswordStore<S>

§

impl<S> !RefUnwindSafe for PasswordStore<S>

§

impl<S> Send for PasswordStore<S>

§

impl<S> Sync for PasswordStore<S>

§

impl<S> Unpin for PasswordStore<S>
where S: Unpin,

§

impl<S> UnsafeUnpin for PasswordStore<S>

§

impl<S> !UnwindSafe for PasswordStore<S>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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 more
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
§

impl<T> PolicyExt for T
where T: ?Sized,

§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] only if self and other return Action::Follow. Read more
§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,