Skip to content
File

Blob: src/worker/dav/props.ts

typescript101 lines
1import type { QName } from "@/worker/xml/namespaces";
2import { CALDAV_NS, CARDDAV_NS, DAV_NS, sameQName } from "@/worker/xml/namespaces";
3 
4export const LIVE_DAV_PROPS = [
5 "creationdate",
6 "displayname",
7 "getcontentlanguage",
8 "getcontentlength",
9 "getcontenttype",
10 "getetag",
11 "getlastmodified",
12 "lockdiscovery",
13 "resourcetype",
14 "supportedlock",
15] as const;
16 
17// Computed/protected DAV props that are never writable as dead props on any resource.
18// RFC 3744 (ACL), RFC 4791 (CalDAV), RFC 6352 (CardDAV), RFC 6578 (sync).
19const PROTECTED_DAV_LOCAL_NAMES_ALL = new Set<string>([
20 "getcontentlength",
21 "getcontenttype",
22 "getetag",
23 "getlastmodified",
24 "creationdate",
25 "lockdiscovery",
26 "supportedlock",
27 "resourcetype",
28 "supported-report-set",
29 "sync-token",
30 "owner",
31 "group",
32 "principal-collection-set",
33 "current-user-principal",
34 "current-user-privilege-set",
35 "supported-privilege-set",
36 "acl",
37 "acl-restrictions",
38 "inherited-acl-set",
39]);
40 
41const PROTECTED_CALDAV_LOCAL_NAMES = new Set<string>([
42 "supported-calendar-data",
43 "supported-calendar-component-set",
44 "max-resource-size",
45 "calendar-home-set",
46 "calendar-user-address-set",
47 "calendar-user-type",
48 "schedule-inbox-URL",
49 "schedule-outbox-URL",
50]);
51 
52const PROTECTED_CARDDAV_LOCAL_NAMES = new Set<string>([
53 "supported-address-data",
54 "max-resource-size",
55 "addressbook-home-set",
56]);
57 
58export function davProp(localName: string): QName {
59 return { nsUri: DAV_NS, localName };
60}
61 
62// Resource kinds for protected property policy. Collections accept displayname as a
63// settable property where the RFCs allow it; objects keep displayname as a live prop.
64export type DavResourcePropKind =
65 | "file-resource"
66 | "calendar-home"
67 | "calendar-collection"
68 | "calendar-object"
69 | "addressbook-home"
70 | "addressbook-collection"
71 | "addressbook-object";
72 
73export function isProtectedLivePropForResource(prop: QName, kind: DavResourcePropKind): boolean {
74 if (prop.nsUri === DAV_NS) {
75 if (PROTECTED_DAV_LOCAL_NAMES_ALL.has(prop.localName)) return true;
76 // RFC 4791 4.2 / RFC 6352 5.2: displayname is mutable on calendar and address book
77 // collections; on file resources and objects, treat it as protected like other live props.
78 if (prop.localName === "displayname") {
79 return (
80 kind === "file-resource" ||
81 kind === "calendar-object" ||
82 kind === "addressbook-object" ||
83 kind === "calendar-home" ||
84 kind === "addressbook-home"
85 );
86 }
87 return false;
88 }
89 if (prop.nsUri === CALDAV_NS) return PROTECTED_CALDAV_LOCAL_NAMES.has(prop.localName);
90 if (prop.nsUri === CARDDAV_NS) return PROTECTED_CARDDAV_LOCAL_NAMES.has(prop.localName);
91 return false;
92}
93 
94export function includesProp(props: QName[], wanted: QName): boolean {
95 return props.some((prop) => sameQName(prop, wanted));
96}
97 
98export function defaultAllpropNames(): QName[] {
99 return LIVE_DAV_PROPS.map((name) => davProp(name));
100}