Skip to main content

tauri_plugin_keyring_store/
lib.rs

1#![doc(
2    html_logo_url = "https://raw.githubusercontent.com/s00d/tauri-plugin-keyring-store/main/assets/docs-logo.png",
3    html_favicon_url = "https://raw.githubusercontent.com/s00d/tauri-plugin-keyring-store/main/assets/docs-logo.png"
4)]
5
6//! OS keychain / credential-manager storage with a Stronghold-shaped API (sessions, vault
7//! locations, optional SLIP10/BIP39 procedures). See the crate README for IPC and guest-js.
8//!
9//! ## Rust usage
10//!
11//! ```rust,no_run
12//! use tauri::Manager;
13//! use tauri_plugin_keyring_store::KeyringExt;
14//!
15//! fn example<R: tauri::Runtime>(app: &tauri::AppHandle<R>) {
16//!   let _svc = app.keyring().store.service();
17//! }
18//! ```
19//!
20//! ## Examples (naming helpers)
21//!
22//! ```rust
23//! use tauri_plugin_keyring_store::{join_prefix, split_prefixed};
24//!
25//! # fn main() -> Result<(), tauri_plugin_keyring_store::Error> {
26//! let account = join_prefix("billing", "stripe_sk")?;
27//! assert_eq!(split_prefixed(&account)?, ("billing".into(), "stripe_sk".into()));
28//! # Ok(())
29//! # }
30//! ```
31
32mod backend;
33mod commands;
34mod error;
35mod models;
36pub mod naming;
37mod plugin;
38mod store;
39
40mod backup_crypto;
41
42#[cfg(feature = "crypto")]
43mod crypto;
44
45pub use error::{Error, Result};
46pub use models::*;
47pub use naming::{join_prefix, split_prefixed, PREFIX_SEPARATOR};
48pub use plugin::KeyringPlugin;
49pub use store::{KeyringStore, SessionRegistry};
50
51use tauri::plugin::{Builder as PluginBuilder, TauriPlugin};
52use tauri::{Manager, Runtime};
53
54/// Access managed [`KeyringPlugin`] state from [`tauri::App`], [`tauri::AppHandle`], or [`tauri::WebviewWindow`].
55///
56/// Registered by [`init`] or [`Builder::build`].
57pub trait KeyringExt<R: Runtime> {
58    /// Returns the shared plugin state (store + session registry).
59    fn keyring(&self) -> &KeyringPlugin;
60}
61
62impl<R: Runtime, T: Manager<R>> KeyringExt<R> for T {
63    fn keyring(&self) -> &KeyringPlugin {
64        self.state::<KeyringPlugin>().inner()
65    }
66}
67
68/// Configure [`KeyringPlugin`] before mounting (service name defaults to the app identifier).
69///
70/// # Example
71///
72/// ```rust,no_run
73/// use tauri_plugin_keyring_store::Builder;
74///
75/// fn plugin() -> tauri::plugin::TauriPlugin<tauri::Wry> {
76///     Builder::new()
77///         .service("com.example.myapp.keyring")
78///         .build()
79/// }
80/// ```
81#[derive(Default)]
82pub struct Builder {
83    service: Option<String>,
84}
85
86impl Builder {
87    /// Same as [`Default::default`].
88    pub fn new() -> Self {
89        Self::default()
90    }
91
92    /// Override the keychain/credential-manager **service** string (Stronghold has no direct equivalent).
93    pub fn service(mut self, service: impl Into<String>) -> Self {
94        self.service = Some(service.into());
95        self
96    }
97
98    /// Build the plugin for registration via [`tauri::Builder::plugin`].
99    pub fn build<R: Runtime>(self) -> TauriPlugin<R> {
100        let service_hint = self.service;
101        PluginBuilder::new("keyring-store")
102            .setup(move |app, _api| {
103                let service = service_hint.unwrap_or_else(|| app.config().identifier.clone());
104                app.manage(KeyringPlugin::new(service));
105                Ok(())
106            })
107            .invoke_handler(tauri::generate_handler![
108                commands::get_passwords,
109                commands::set_passwords,
110                commands::delete_passwords,
111                commands::password_exists,
112                commands::export_passwords_plain,
113                commands::import_passwords_plain,
114                commands::export_passwords_encrypted,
115                commands::import_passwords_encrypted,
116                commands::ping,
117                commands::initialize,
118                commands::destroy,
119                commands::save,
120                commands::create_client,
121                commands::load_client,
122                commands::get_store_record,
123                commands::save_store_record,
124                commands::remove_store_record,
125                commands::save_secret,
126                commands::remove_secret,
127                commands::execute_procedure,
128            ])
129            .build()
130    }
131}
132
133/// Registers the plugin with default options (`service` = bundle identifier).
134///
135/// Shorthand for `Builder::default().build()`. Use [`Builder`] to set a custom service name.
136pub fn init<R: Runtime>() -> TauriPlugin<R> {
137    Builder::default().build()
138}