Delegates reach the whole locked account #68

Merged
jcoffey-dev merged 2 commits from fix/delegate-whole-account into main 2026-09-28 01:22:48 +00:00
4 changed files with 55 additions and 7 deletions
Showing only changes of commit 9f6761c9dd - Show all commits
+7
View File
@@ -840,6 +840,13 @@ impl AccessToken {
/// inbuxa: AL-5: this account's delegation into a locked account, if it /// inbuxa: AL-5: this account's delegation into a locked account, if it
/// has one that hasn't ended. /// has one that hasn't ended.
/// inbuxa: AL-6, AL-7: a delegate at organize or full, who may add to
/// the locked account as its owner could, top-level folders included.
pub fn delegate_may_write(&self, account_id: u32) -> bool {
self.delegation(account_id)
.is_some_and(|d| d.access != inbuxa_features::lock::Access::Read)
}
pub fn delegation(&self, account_id: u32) -> Option<&super::Delegation> { pub fn delegation(&self, account_id: u32) -> Option<&super::Delegation> {
let now = now(); let now = now();
self.inner self.inner
+9 -4
View File
@@ -226,9 +226,14 @@ impl FileNodeCopy for Server {
} }
}; };
if let Err(err) = // inbuxa: AL-7: a writing delegate may add at the top
validate_file_node_hierarchy(None, &file_node, is_shared, &cache, &created_folders) if let Err(err) = validate_file_node_hierarchy(
{ None,
&file_node,
is_shared && !access_token.delegate_may_write(account_id),
&cache,
&created_folders,
) {
response.not_created.append(id, err); response.not_created.append(id, err);
continue 'create; continue 'create;
} }
@@ -362,7 +367,7 @@ impl FileNodeCopy for Server {
); );
continue 'create; continue 'create;
} }
} else if is_shared { } else if is_shared && !access_token.delegate_may_write(account_id) {
response.not_created.append( response.not_created.append(
id, id,
SetError::forbidden() SetError::forbidden()
+9 -3
View File
@@ -149,9 +149,15 @@ impl FileNodeSet for Server {
}; };
// Validate hierarchy // Validate hierarchy
if let Err(err) = // inbuxa: AL-7: a writing delegate may add at the top of a
validate_file_node_hierarchy(None, &file_node, is_shared, &cache, &created_folders) // locked account, which may hold no folders at all
{ if let Err(err) = validate_file_node_hierarchy(
None,
&file_node,
is_shared && !access_token.delegate_may_write(account_id),
&cache,
&created_folders,
) {
response.not_created.append(id, err); response.not_created.append(id, err);
continue 'create; continue 'create;
} }
+30
View File
@@ -193,6 +193,15 @@ pub async fn test(test: &mut TestServer) {
assert_eq!(name, method, "AL-7: {method} refused to the delegate: {response}"); assert_eq!(name, method, "AL-7: {method} refused to the delegate: {response}");
} }
// AL-6: reading adds nothing, not even at the top of empty Files
let (_, response) = delegate
.call(
"FileNode/set",
json!({"accountId": owner_id, "create": {"f": {"name": "Notes", "parentId": null}}}),
)
.await;
assert!(response["created"].get("f").is_none(), "AL-6: a read delegate added a file: {response}");
// The delegate reads the mail that arrived // The delegate reads the mail that arrived
let (_, found) = delegate let (_, found) = delegate
.call( .call(
@@ -236,6 +245,27 @@ pub async fn test(test: &mut TestServer) {
"AL-5: {response}" "AL-5: {response}"
); );
// AL-7: organize adds at the top of the locked account's Files, which
// held none, and sees what it made
let (_, response) = delegate
.call(
"FileNode/set",
json!({"accountId": owner_id, "create": {"f": {"name": "Handover notes", "parentId": null}}}),
)
.await;
let folder_id = response["created"]["f"]["id"]
.as_str()
.unwrap_or_else(|| panic!("AL-7: organize couldn't add to empty Files: {response}"))
.to_string();
let (_, response) = delegate
.call("FileNode/get", json!({"accountId": owner_id, "ids": [folder_id]}))
.await;
assert_eq!(
response["list"].as_array().map(Vec::len),
Some(1),
"AL-7: the delegate can't see the folder it made: {response}"
);
// Test 12, AL-6, AL-7: organize makes folders it can see, moves mail, // Test 12, AL-6, AL-7: organize makes folders it can see, moves mail,
// never deletes it // never deletes it
let (_, mailboxes) = delegate let (_, mailboxes) = delegate