Android sharing sends the opened device token, not the sealed one
CI & Build / Python lint (push) Successful in 2s
CI & Build / Build now, or wait for Android? (push) Successful in 3s
Android / Build, or is the channel already serving this? (push) Successful in 3s
Desktop (Tauri) / Build, or is the channel already serving this? (push) Successful in 2s
CI & Build / Python tests (push) Successful in 12s
CI & Build / Web typecheck and unit tests (push) Successful in 13s
Android / Core and FFI clippy and tests (push) Successful in 34s
CI & Build / integration (push) Successful in 1m39s
CI & Build / Build & push image (push) Skipped
Desktop (Tauri) / Web tests, clippy, Rust tests and rustfmt (push) Successful in 1m58s
Desktop (Tauri) / Windows installer (cross-compiled) (push) Successful in 3m5s
Desktop (Tauri) / Tauri desktop (Linux) (push) Successful in 4m11s
Desktop (Tauri) / Update manifest (push) Successful in 4s
Android / Kotlin + Rust (APK) (push) Successful in 9m17s
Android / Build the server image (push) Successful in 1s
CI & Build / Python lint (push) Successful in 2s
CI & Build / Build now, or wait for Android? (push) Successful in 3s
Android / Build, or is the channel already serving this? (push) Successful in 3s
Desktop (Tauri) / Build, or is the channel already serving this? (push) Successful in 2s
CI & Build / Python tests (push) Successful in 12s
CI & Build / Web typecheck and unit tests (push) Successful in 13s
Android / Core and FFI clippy and tests (push) Successful in 34s
CI & Build / integration (push) Successful in 1m39s
CI & Build / Build & push image (push) Skipped
Desktop (Tauri) / Web tests, clippy, Rust tests and rustfmt (push) Successful in 1m58s
Desktop (Tauri) / Windows installer (cross-compiled) (push) Successful in 3m5s
Desktop (Tauri) / Tauri desktop (Linux) (push) Successful in 4m11s
Desktop (Tauri) / Update manifest (push) Successful in 4s
Android / Kotlin + Rust (APK) (push) Successful in 9m17s
Android / Build the server image (push) Successful in 1s
Android has stored its device token sealed ("sealed:…") since 8592b83, and
core's sharing calls read the token from the store themselves. The ffi opened
it in credentials() and then threw the result away, so every Share-sheet
request went out as `Bearer sealed:…` and the server refused it.
The sharing functions now take the server address and token from the caller.
The ffi passes what credentials() opened; the desktop, which stores its token
plain, reads it through sharing::stored_link. A new ffi test serves one request
on a loopback port and checks the bearer token that arrives (#5381).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+31
-13
@@ -5,6 +5,11 @@
|
||||
//! device token. The one thing kept locally is the note's `shared` flag, set from
|
||||
//! the server's answer so the card's chip changes at once rather than at the next
|
||||
//! sync (which brings the same value).
|
||||
//!
|
||||
//! The server address and token come from the CALLER, never from the store here.
|
||||
//! A stored token may be sealed (Android keeps it under a Keystore key, see
|
||||
//! `state::TokenSeal`), and only the caller holds the seal that opens it. Reading it
|
||||
//! here sent `sealed:…` as the bearer token, and every share call was refused (#5381).
|
||||
|
||||
use rusqlite::params;
|
||||
|
||||
@@ -17,7 +22,11 @@ use crate::local::Db;
|
||||
pub const NEEDS_SERVER: &str =
|
||||
"Sharing is between people on a server. Link this device to one in Sync to share notes.";
|
||||
|
||||
fn link(db: &Db) -> Result<(String, String), String> {
|
||||
/// The server address and token AS STORED, or [`NEEDS_SERVER`].
|
||||
///
|
||||
/// Only for a client that stores its token plain, as the desktop does. A client
|
||||
/// with a seal opens the token itself (`state::open_token`) and passes that.
|
||||
pub fn stored_link(db: &Db) -> Result<(String, String), String> {
|
||||
let conn = db.conn()?;
|
||||
let link = state::read(&conn).map_err(|e| e.to_string())?;
|
||||
match (link.server_url, link.device_token) {
|
||||
@@ -38,33 +47,42 @@ fn mark_shared(db: &Db, note_id: &str, shares: &[NoteShare]) -> Result<(), Strin
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn directory(db: &Db) -> Result<Directory, String> {
|
||||
let (url, token) = link(db)?;
|
||||
client::directory(&url, &token).await
|
||||
pub async fn directory(url: &str, token: &str) -> Result<Directory, String> {
|
||||
client::directory(url, token).await
|
||||
}
|
||||
|
||||
pub async fn list(db: &Db, note_id: &str) -> Result<Vec<NoteShare>, String> {
|
||||
let (url, token) = link(db)?;
|
||||
let shares = client::list_shares(&url, &token, note_id).await?;
|
||||
pub async fn list(
|
||||
db: &Db,
|
||||
url: &str,
|
||||
token: &str,
|
||||
note_id: &str,
|
||||
) -> Result<Vec<NoteShare>, String> {
|
||||
let shares = client::list_shares(url, token, note_id).await?;
|
||||
mark_shared(db, note_id, &shares)?;
|
||||
Ok(shares)
|
||||
}
|
||||
|
||||
pub async fn share(
|
||||
db: &Db,
|
||||
url: &str,
|
||||
token: &str,
|
||||
note_id: &str,
|
||||
target: &ShareTarget,
|
||||
permission: &str,
|
||||
) -> Result<Vec<NoteShare>, String> {
|
||||
let (url, token) = link(db)?;
|
||||
let shares = client::share_note(&url, &token, note_id, target, permission).await?;
|
||||
let shares = client::share_note(url, token, note_id, target, permission).await?;
|
||||
mark_shared(db, note_id, &shares)?;
|
||||
Ok(shares)
|
||||
}
|
||||
|
||||
pub async fn unshare(db: &Db, note_id: &str, share_id: &str) -> Result<Vec<NoteShare>, String> {
|
||||
let (url, token) = link(db)?;
|
||||
let shares = client::unshare_note(&url, &token, note_id, share_id).await?;
|
||||
pub async fn unshare(
|
||||
db: &Db,
|
||||
url: &str,
|
||||
token: &str,
|
||||
note_id: &str,
|
||||
share_id: &str,
|
||||
) -> Result<Vec<NoteShare>, String> {
|
||||
let shares = client::unshare_note(url, token, note_id, share_id).await?;
|
||||
mark_shared(db, note_id, &shares)?;
|
||||
Ok(shares)
|
||||
}
|
||||
@@ -85,7 +103,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn an_unlinked_device_explains_that_sharing_needs_a_server() {
|
||||
assert_eq!(link(&db()).unwrap_err(), NEEDS_SERVER);
|
||||
assert_eq!(stored_link(&db()).unwrap_err(), NEEDS_SERVER);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user