Unlinking a device is one flow in the core: link::unlink
The desktop's sync_unlink and the ffi's unlink were both written out in full: try the revoke, clear the link either way, and log the outcome. link::unlink(db, held) now does that. Each client reads its link with state::credentials (with its seal) before the await and passes it in. DRY pass #2, batch 1, F3 (#5372). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+5
-14
@@ -526,23 +526,14 @@ impl Inkwell {
|
|||||||
/// so the revoke is attempted first, its outcome returned for the UI to report
|
/// so the revoke is attempted first, its outcome returned for the UI to report
|
||||||
/// honestly, and the link cleared either way.
|
/// honestly, and the link cleared either way.
|
||||||
pub async fn unlink(&self) -> Result<RevokeOutcome, CoreError> {
|
pub async fn unlink(&self) -> Result<RevokeOutcome, CoreError> {
|
||||||
// Read and release before the network call: a std MutexGuard isn't Send, so
|
// A token that won't open on this phone can't be revoked from here, so it
|
||||||
// it cannot be held across an await, and holding the store through a
|
// is skipped.
|
||||||
// round-trip would freeze every note operation in the UI. A token that won't
|
let held = match self.credentials() {
|
||||||
// open on this phone can't be revoked from here, so it is skipped.
|
Ok(held) => Some(held),
|
||||||
let link = match self.credentials() {
|
|
||||||
Ok(link) => Some(link),
|
|
||||||
Err(CoreError::NotLinked) => None,
|
Err(CoreError::NotLinked) => None,
|
||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e),
|
||||||
};
|
};
|
||||||
let revoked = match &link {
|
let revoked = link::unlink(&self.db, held).await.map_err(CoreError::store)?;
|
||||||
Some((base_url, token)) => client::revoke_self(base_url, token).await,
|
|
||||||
None => client::RevokeOutcome::Skipped,
|
|
||||||
};
|
|
||||||
|
|
||||||
let conn = self.db.conn().map_err(CoreError::store)?;
|
|
||||||
state::clear_link(&conn).map_err(CoreError::store)?;
|
|
||||||
log::info!("unlinked from server (server-side token: {revoked:?})");
|
|
||||||
Ok(revoked.into())
|
Ok(revoked.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+24
-2
@@ -1,4 +1,4 @@
|
|||||||
//! Linking a device to a server.
|
//! Linking a device to a server, and unlinking it.
|
||||||
//!
|
//!
|
||||||
//! One flow for every client. The desktop and Android each wrote it out, the same
|
//! One flow for every client. The desktop and Android each wrote it out, the same
|
||||||
//! steps in the same order; what differs between them is only how the token is
|
//! steps in the same order; what differs between them is only how the token is
|
||||||
@@ -6,9 +6,10 @@
|
|||||||
|
|
||||||
use rusqlite::Connection;
|
use rusqlite::Connection;
|
||||||
|
|
||||||
use super::client::{self, Identity};
|
use super::client::{self, Identity, RevokeOutcome};
|
||||||
use super::compat::Compatibility;
|
use super::compat::Compatibility;
|
||||||
use super::state::{self, TokenSeal};
|
use super::state::{self, TokenSeal};
|
||||||
|
use crate::local::Db;
|
||||||
|
|
||||||
/// How a device proves whose it is.
|
/// How a device proves whose it is.
|
||||||
pub enum Credential<'a> {
|
pub enum Credential<'a> {
|
||||||
@@ -88,3 +89,24 @@ pub fn store(
|
|||||||
log::info!("linked to {base_url}");
|
log::info!("linked to {base_url}");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Stop syncing, and retire this device's token on the server.
|
||||||
|
///
|
||||||
|
/// `held` is the link as `state::credentials` read it, which the caller reads and
|
||||||
|
/// releases before this awaits: a std MutexGuard isn't Send, and holding the store
|
||||||
|
/// through a round-trip would freeze every note operation. None skips the revoke.
|
||||||
|
///
|
||||||
|
/// The local half is unconditional. Someone unlinking because the device is being
|
||||||
|
/// sold or handed on must not be held to it by a server that is offline or gone,
|
||||||
|
/// so the revoke is tried first, its outcome returned for the UI to report
|
||||||
|
/// honestly, and the link cleared either way.
|
||||||
|
pub async fn unlink(db: &Db, held: Option<(String, String)>) -> Result<RevokeOutcome, String> {
|
||||||
|
let revoked = match &held {
|
||||||
|
Some((base_url, token)) => client::revoke_self(base_url, token).await,
|
||||||
|
None => RevokeOutcome::Skipped,
|
||||||
|
};
|
||||||
|
let conn = db.conn()?;
|
||||||
|
state::clear_link(&conn).map_err(|e| e.to_string())?;
|
||||||
|
log::info!("unlinked from server (server-side token: {revoked:?})");
|
||||||
|
Ok(revoked)
|
||||||
|
}
|
||||||
|
|||||||
@@ -121,21 +121,12 @@ pub struct UnlinkResult {
|
|||||||
/// honestly, and the link cleared either way.
|
/// honestly, and the link cleared either way.
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn sync_unlink(db: State<'_, Db>) -> Result<UnlinkResult, String> {
|
pub async fn sync_unlink(db: State<'_, Db>) -> Result<UnlinkResult, String> {
|
||||||
// Read and release before the network call: a std MutexGuard isn't Send, and
|
let held = {
|
||||||
// holding the store across a round-trip would freeze every note operation in
|
|
||||||
// the UI.
|
|
||||||
let link = {
|
|
||||||
let conn = db.conn()?;
|
let conn = db.conn()?;
|
||||||
state::credentials(&conn, None).map_err(|e| e.to_string())?
|
state::credentials(&conn, None).map_err(|e| e.to_string())?
|
||||||
};
|
};
|
||||||
let revoked = match &link {
|
let revoked = link::unlink(&db, held).await?;
|
||||||
Some((base_url, token)) => client::revoke_self(base_url, token).await,
|
|
||||||
None => client::RevokeOutcome::Skipped,
|
|
||||||
};
|
|
||||||
|
|
||||||
let conn = db.conn()?;
|
let conn = db.conn()?;
|
||||||
state::clear_link(&conn).map_err(|e| e.to_string())?;
|
|
||||||
log::info!("unlinked from server (server-side token: {revoked:?})");
|
|
||||||
Ok(UnlinkResult {
|
Ok(UnlinkResult {
|
||||||
status: state::status(&conn).map_err(|e| e.to_string())?,
|
status: state::status(&conn).map_err(|e| e.to_string())?,
|
||||||
revoked,
|
revoked,
|
||||||
|
|||||||
Reference in New Issue
Block a user