android_native_keyring_store/by_service/
store.rs1use std::{collections::HashMap, sync::Arc};
2
3use jni::JavaVM;
4use keyring_core::{Entry, api::CredentialStoreApi};
5
6use crate::{error::AndroidKeyringResult, shared_preferences::Context};
7
8use super::{Cred, HasJavaVm};
9
10pub struct Store {
11 java_vm: Arc<JavaVM>,
12 context: Context,
13 instance_id: String,
14}
15
16impl std::fmt::Debug for Store {
17 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18 f.debug_struct("Store")
19 .field("vendor", &self.vendor())
20 .field("id", &self.id())
21 .field("context", &self.context.id())
22 .finish()
23 }
24}
25
26impl Store {
27 pub fn from_ndk_context() -> AndroidKeyringResult<Arc<Self>> {
30 let ctx = ndk_context::android_context();
31 let vm = ctx.vm().cast();
32 let activity = ctx.context();
33
34 let java_vm = unsafe { JavaVM::from_raw(vm)? };
35 let env = java_vm.attach_current_thread()?;
36
37 let j_context = unsafe { jni::objects::JObject::from_raw(activity as jni::sys::jobject) };
38 let context = Context::new(&env, j_context)?;
39 let java_vm = Arc::new(env.get_java_vm()?);
40 let instance_id = generate_instance_id();
41 Ok(Arc::new(Self {
42 java_vm,
43 context,
44 instance_id,
45 }))
46 }
47}
48
49impl CredentialStoreApi for Store {
50 fn vendor(&self) -> String {
51 "Android SharedPreferences/KeyStore (Legacy), https://github.com/open-source-cooperative/android-native-keyring-store".to_string()
52 }
53
54 fn id(&self) -> String {
55 self.instance_id.clone()
56 }
57
58 fn build(
59 &self,
60 service: &str,
61 user: &str,
62 _modifiers: Option<&HashMap<&str, &str>>,
63 ) -> keyring_core::Result<Entry> {
64 let credential = Cred::new(self.java_vm.clone(), self.context.clone(), service, user);
65
66 Ok(Entry::new_with_credential(Arc::new(credential)))
67 }
68
69 fn as_any(&self) -> &dyn std::any::Any {
70 self
71 }
72
73 fn debug_fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74 std::fmt::Debug::fmt(self, f)
75 }
76}
77
78impl HasJavaVm for Store {
79 fn java_vm(&self) -> &JavaVM {
80 &self.java_vm
81 }
82}
83
84fn generate_instance_id() -> String {
85 use std::time::{SystemTime, UNIX_EPOCH};
86
87 let now = SystemTime::now();
88 let elapsed = if now.lt(&UNIX_EPOCH) {
89 UNIX_EPOCH.duration_since(now).unwrap()
90 } else {
91 now.duration_since(UNIX_EPOCH).unwrap()
92 };
93
94 format!(
95 "One File per Service storage, Crate version {}, Instantiated at {}",
96 env!("CARGO_PKG_VERSION"),
97 elapsed.as_secs_f64()
98 )
99}