fix: carry the owner's path into WebDAV events and expand tilde before touch

WebDAV emits the same GUI events the FS controllers do, and had the same
confusion: the payload was masked for the actor and addressed to the owner. A
recipient mounting a shared folder in Finder reproduced the disappearing-item
symptom exactly.

/touch prefixed `/` before expanding, so `~/AppData/<app>/f.txt` became a literal
`/~/...` that no longer looked like a tilde path — the shape puter.js sends for
every app-relative write answered 404.
This commit is contained in:
Juan Castro committed 2026-09-30 16:21:39 -04:00
1 parent ec4d3b31cf
commit b126cf9c5a
3 files changed
+17 -3

No files matched your search

@@ -1050,11 +1050,12 @@ export class LegacyFSController extends PuterController {
legacyCode: 'bad_request',
});
const targetPath = await expandClientPath(
const expanded = await expandClientPath(
this.stores.fsEntry,
rawPath.startsWith('/') ? rawPath : `/${rawPath}`,
rawPath,
actor.user?.username,
);
const targetPath = expanded.startsWith('/') ? expanded : `/${expanded}`;
const parentPath = pathPosix.dirname(targetPath);
if (parentPath === '/') {
throw new HttpError(400, 'Cannot touch in root', {
@@ -138,6 +138,17 @@ describe('writes inside a folder shared with write', () => {
expect(await ownerListing(s)).toContain('from-recipient.txt');
}, 180_000);
it('touch still expands a tilde path', async () => {
const s = await shareAFolder();
const touched = await post('/touch', s.owner.token, {
path: '~/SharedDir/from-tilde.txt',
});
expect(touched.status).toBe(200);
expect(await ownerListing(s)).toContain('from-tilde.txt');
}, 180_000);
// Addressed to the owner, so it carries the path the owner can resolve.
it('publishes the owner’s real path on events about their entries', async () => {
const s = await shareAFolder();
@@ -1174,7 +1174,9 @@ export class WebDAVController extends PuterController {
void Promise.resolve()
.then(async () => {
const response = {
...(await toLegacyEntry(this.clients.event, entry)),
...(await toLegacyEntry(this.clients.event, entry, {
forOwner: true,
})),
...extra,
from_new_service: true,
};