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}