Linking a device is one flow in the core: sync::link
The desktop's sync_link and the ffi's link_with_password/link_with_token were the same steps written out twice: probe, refuse an incompatible server before any credential is sent, log in or verify a pasted token, keep the link, and adopt the server's trash retention. link::authenticate(url, Credential) does the network half and link::store(conn, ..., seal) keeps it, sealed when the client has a seal. Each client now only reads its input and picks its seal. The desktop checks for a missing email/password before probing rather than after. Same error, sooner. DRY pass #2, batch 1, F2 (#5372). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+23
-33
@@ -41,7 +41,7 @@ use std::sync::Arc;
|
||||
|
||||
use inkwell_core::local::{self, Db};
|
||||
use inkwell_core::sync::blobs::BlobStore;
|
||||
use inkwell_core::sync::{client, compat, engine, push, sharing, state};
|
||||
use inkwell_core::sync::{client, compat, engine, link, push, sharing, state};
|
||||
|
||||
use models::{
|
||||
patch_from, BodyItem, BodyTag, ClientUpdate, Directory, Identity, Label, Note, NoteDraft,
|
||||
@@ -502,18 +502,12 @@ impl Inkwell {
|
||||
password: String,
|
||||
device_name: String,
|
||||
) -> Result<Identity, CoreError> {
|
||||
let probe = client::probe(&url).await.map_err(CoreError::network)?;
|
||||
if let compat::Compatibility::Incompatible { reason, .. } = &probe.compatibility {
|
||||
return Err(CoreError::Network {
|
||||
message: reason.clone(),
|
||||
});
|
||||
}
|
||||
let (token, identity) =
|
||||
client::device_login(&probe.base_url, &email, &password, &device_name)
|
||||
.await
|
||||
.map_err(CoreError::network)?;
|
||||
self.store_link(&probe.base_url, &token, probe.server.trash_retention_days)?;
|
||||
Ok(identity.into())
|
||||
let credential = link::Credential::Password {
|
||||
email: &email,
|
||||
password: &password,
|
||||
device_name: &device_name,
|
||||
};
|
||||
self.link(&url, credential).await
|
||||
}
|
||||
|
||||
/// Pair using a device token pasted from the web app — for anyone who would
|
||||
@@ -522,17 +516,7 @@ impl Inkwell {
|
||||
/// The token is verified before it is stored, so a copy/paste slip fails here
|
||||
/// rather than at the next sync.
|
||||
pub async fn link_with_token(&self, url: String, token: String) -> Result<Identity, CoreError> {
|
||||
let probe = client::probe(&url).await.map_err(CoreError::network)?;
|
||||
if let compat::Compatibility::Incompatible { reason, .. } = &probe.compatibility {
|
||||
return Err(CoreError::Network {
|
||||
message: reason.clone(),
|
||||
});
|
||||
}
|
||||
let identity = client::fetch_identity(&probe.base_url, &token)
|
||||
.await
|
||||
.map_err(CoreError::network)?;
|
||||
self.store_link(&probe.base_url, &token, probe.server.trash_retention_days)?;
|
||||
Ok(identity.into())
|
||||
self.link(&url, link::Credential::Token(&token)).await
|
||||
}
|
||||
|
||||
/// Stop syncing, and retire this device's token on the server.
|
||||
@@ -757,9 +741,19 @@ impl Inkwell {
|
||||
link.ok_or(CoreError::NotLinked)
|
||||
}
|
||||
|
||||
/// Persist a fresh link, adopting the server's retention window at the same time
|
||||
/// so the Trash view stops counting down against this device's offline default
|
||||
/// the moment it is no longer the policy in force.
|
||||
/// Both ways of linking, once the credential is chosen: ask the server, then
|
||||
/// keep the link sealed.
|
||||
async fn link(
|
||||
&self,
|
||||
url: &str,
|
||||
credential: link::Credential<'_>,
|
||||
) -> Result<Identity, CoreError> {
|
||||
let granted = link::authenticate(url, credential).await.map_err(CoreError::network)?;
|
||||
self.store_link(&granted.base_url, &granted.token, granted.retention_days)?;
|
||||
Ok(granted.identity.into())
|
||||
}
|
||||
|
||||
/// Keep a fresh link, sealed (`link::store`).
|
||||
fn store_link(
|
||||
&self,
|
||||
base_url: &str,
|
||||
@@ -767,12 +761,8 @@ impl Inkwell {
|
||||
retention_days: Option<u32>,
|
||||
) -> Result<(), CoreError> {
|
||||
let conn = self.db.conn().map_err(CoreError::store)?;
|
||||
state::set_sealed_link(&conn, base_url, token, &self.seal).map_err(CoreError::store)?;
|
||||
if let Some(days) = retention_days {
|
||||
state::set_server_retention(&conn, days as i64).map_err(CoreError::store)?;
|
||||
}
|
||||
log::info!("linked to {base_url}");
|
||||
Ok(())
|
||||
link::store(&conn, base_url, token, retention_days, Some(&self.seal))
|
||||
.map_err(CoreError::store)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user