Implement Rust-owned Android local and HTTPS onboarding (#95)
This commit is contained in:
1 parent
66b1d4a4c4
commit
36e5f55283
46 files changed
+3002
-79
No files matched your search
@@ -0,0 +1,187 @@
|
||||
//! Mechanical Android onboarding exports; all setup decisions remain in storage.
|
||||
use crate::{
|
||||
MobileOnboardingDiscovery, MobileOnboardingFfiError, MobileOnboardingOutcome,
|
||||
MobileOnboardingProgress, MobilePrivateRuntime, MobileSecretBackend,
|
||||
platform::SecretBackendAdapter,
|
||||
};
|
||||
use ironstorage::{
|
||||
mobile_onboarding::{
|
||||
MobileOnboardingRequest,
|
||||
android::{AndroidOnboarding, AndroidOnboardingStatus},
|
||||
},
|
||||
repository::SecretBytes,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Clone, uniffi::Record)]
|
||||
pub struct MobileAndroidSetupKey {
|
||||
pub fingerprint: String,
|
||||
pub user_ids: Vec<String>,
|
||||
}
|
||||
#[derive(Clone, uniffi::Record)]
|
||||
pub struct MobileAndroidSetupStatus {
|
||||
pub configured: bool,
|
||||
pub connected: bool,
|
||||
pub existing_clone: bool,
|
||||
pub keys: Vec<MobileAndroidSetupKey>,
|
||||
pub selected_key: Option<String>,
|
||||
pub title: String,
|
||||
pub detail: String,
|
||||
}
|
||||
impl From<AndroidOnboardingStatus> for MobileAndroidSetupStatus {
|
||||
fn from(status: AndroidOnboardingStatus) -> Self {
|
||||
Self {
|
||||
title: status.title,
|
||||
detail: status.detail,
|
||||
configured: status.configured,
|
||||
connected: status.connected,
|
||||
existing_clone: status.existing_clone,
|
||||
selected_key: status.selected_key,
|
||||
keys: status
|
||||
.keys
|
||||
.into_iter()
|
||||
.map(|key| MobileAndroidSetupKey {
|
||||
fingerprint: key.fingerprint().as_str().into(),
|
||||
user_ids: key.user_ids().to_vec(),
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(uniffi::Object)]
|
||||
pub struct MobileAndroidOnboarding {
|
||||
setup: Arc<AndroidOnboarding>,
|
||||
}
|
||||
impl MobileAndroidOnboarding {
|
||||
pub(crate) fn new(
|
||||
runtime: &MobilePrivateRuntime,
|
||||
backend: Arc<dyn MobileSecretBackend>,
|
||||
) -> Result<Arc<Self>, MobileOnboardingFfiError> {
|
||||
Ok(Arc::new(Self {
|
||||
setup: Arc::new(AndroidOnboarding::new(
|
||||
&runtime.storage,
|
||||
Arc::new(SecretBackendAdapter(backend)),
|
||||
)?),
|
||||
}))
|
||||
}
|
||||
}
|
||||
fn secret(value: Option<String>) -> Option<SecretBytes> {
|
||||
value.map(|value| SecretBytes::new(value.into_bytes()))
|
||||
}
|
||||
fn outcome(
|
||||
value: ironstorage::mobile_onboarding::MobileOnboardingOutcome,
|
||||
) -> MobileOnboardingOutcome {
|
||||
MobileOnboardingOutcome {
|
||||
title: value.title().into(),
|
||||
detail: value.detail().into(),
|
||||
}
|
||||
}
|
||||
#[uniffi::export]
|
||||
impl MobileAndroidOnboarding {
|
||||
pub fn status(&self) -> Result<MobileAndroidSetupStatus, MobileOnboardingFfiError> {
|
||||
Ok(self.setup.status()?.into())
|
||||
}
|
||||
pub fn generate(
|
||||
&self,
|
||||
user_id: String,
|
||||
passphrase: String,
|
||||
) -> Result<MobileAndroidSetupStatus, MobileOnboardingFfiError> {
|
||||
Ok(self
|
||||
.setup
|
||||
.generate(&user_id, SecretBytes::new(passphrase.into_bytes()))?
|
||||
.into())
|
||||
}
|
||||
pub fn import_key(
|
||||
&self,
|
||||
armor: String,
|
||||
passphrase: Option<String>,
|
||||
) -> Result<MobileAndroidSetupStatus, MobileOnboardingFfiError> {
|
||||
Ok(self
|
||||
.setup
|
||||
.import(SecretBytes::new(armor.into_bytes()), secret(passphrase))?
|
||||
.into())
|
||||
}
|
||||
pub fn setup_local(
|
||||
&self,
|
||||
fingerprint: String,
|
||||
passphrase: Option<String>,
|
||||
) -> Result<MobileOnboardingOutcome, MobileOnboardingFfiError> {
|
||||
Ok(outcome(
|
||||
self.setup.setup_local(&fingerprint, secret(passphrase))?,
|
||||
))
|
||||
}
|
||||
pub fn remote(
|
||||
&self,
|
||||
server_url: String,
|
||||
account: String,
|
||||
repository_path: String,
|
||||
application_token: String,
|
||||
) -> Result<Arc<MobileAndroidRemoteOnboarding>, MobileOnboardingFfiError> {
|
||||
Ok(Arc::new(MobileAndroidRemoteOnboarding {
|
||||
setup: Arc::clone(&self.setup),
|
||||
request: MobileOnboardingRequest::new(
|
||||
server_url,
|
||||
account,
|
||||
repository_path,
|
||||
application_token.into_bytes(),
|
||||
)?,
|
||||
}))
|
||||
}
|
||||
pub fn replace_token(
|
||||
&self,
|
||||
account: String,
|
||||
application_token: String,
|
||||
) -> Result<(), MobileOnboardingFfiError> {
|
||||
Ok(self
|
||||
.setup
|
||||
.replace_token(account, SecretBytes::new(application_token.into_bytes()))?)
|
||||
}
|
||||
pub fn cancel(&self) {
|
||||
self.setup.cancel();
|
||||
}
|
||||
pub fn progress(&self) -> MobileOnboardingProgress {
|
||||
let progress = self.setup.progress();
|
||||
MobileOnboardingProgress {
|
||||
phase: progress.phase().into(),
|
||||
title: progress.title().into(),
|
||||
detail: progress.detail().into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(uniffi::Object)]
|
||||
pub struct MobileAndroidRemoteOnboarding {
|
||||
setup: Arc<AndroidOnboarding>,
|
||||
request: MobileOnboardingRequest,
|
||||
}
|
||||
|
||||
#[uniffi::export]
|
||||
impl MobileAndroidRemoteOnboarding {
|
||||
pub fn discover(&self) -> Result<MobileOnboardingDiscovery, MobileOnboardingFfiError> {
|
||||
let value = self.setup.discover(&self.request)?;
|
||||
Ok(MobileOnboardingDiscovery {
|
||||
branches: value.branches().to_vec(),
|
||||
selected_branch: value.selected_branch() as u32,
|
||||
})
|
||||
}
|
||||
pub fn clone_store(
|
||||
&self,
|
||||
branch: String,
|
||||
fingerprint: String,
|
||||
passphrase: Option<String>,
|
||||
use_existing: bool,
|
||||
) -> Result<MobileOnboardingOutcome, MobileOnboardingFfiError> {
|
||||
Ok(outcome(self.setup.clone_store(
|
||||
&self.request,
|
||||
&branch,
|
||||
&fingerprint,
|
||||
secret(passphrase),
|
||||
use_existing,
|
||||
)?))
|
||||
}
|
||||
pub fn connect(&self) -> Result<MobileOnboardingOutcome, MobileOnboardingFfiError> {
|
||||
Ok(outcome(self.setup.connect(&self.request)?))
|
||||
}
|
||||
pub fn cancel(&self) {
|
||||
self.setup.cancel();
|
||||
}
|
||||
}
|
||||
@@ -81,6 +81,8 @@ uniffi::setup_scaffolding!();
|
||||
|
||||
mod android_keystore;
|
||||
pub use android_keystore::*;
|
||||
mod android_onboarding;
|
||||
pub use android_onboarding::*;
|
||||
mod platform;
|
||||
pub use platform::*;
|
||||
|
||||
|
||||
@@ -96,10 +96,16 @@ pub struct MobilePrivateStorageLayout {
|
||||
|
||||
#[derive(uniffi::Object)]
|
||||
pub struct MobilePrivateRuntime {
|
||||
storage: PrivateStorage,
|
||||
pub(crate) storage: PrivateStorage,
|
||||
}
|
||||
#[uniffi::export]
|
||||
impl MobilePrivateRuntime {
|
||||
pub fn android_onboarding(
|
||||
&self,
|
||||
backend: Arc<dyn MobileSecretBackend>,
|
||||
) -> Result<Arc<crate::MobileAndroidOnboarding>, crate::MobileOnboardingFfiError> {
|
||||
crate::MobileAndroidOnboarding::new(self, backend)
|
||||
}
|
||||
pub fn android_secret_backend(
|
||||
&self,
|
||||
keystore: Arc<dyn crate::MobileAndroidKeystore>,
|
||||
|
||||
Reference in new issue
Block a user