caldav-adapter 8.2.2 → 8.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/common/tags.js CHANGED
@@ -7,6 +7,24 @@ const cal = 'urn:ietf:params:xml:ns:caldav';
7
7
  const cs = 'http://calendarserver.org/ns/';
8
8
  const ical = 'http://apple.com/ns/ical/';
9
9
 
10
+ /**
11
+ * Encode special characters for XML content to prevent parsing errors
12
+ * @param {string} str - String to encode
13
+ * @returns {string} - XML-safe encoded string
14
+ */
15
+ function encodeXMLEntities(str) {
16
+ if (typeof str !== 'string') {
17
+ return str;
18
+ }
19
+
20
+ return str
21
+ .replaceAll('&', '&') // Must be first to avoid double-encoding
22
+ .replaceAll('<', '&lt;')
23
+ .replaceAll('>', '&gt;')
24
+ .replaceAll('"', '&quot;')
25
+ .replaceAll("'", '&#39;');
26
+ }
27
+
10
28
  module.exports = function (options) {
11
29
  const log = winston({ ...options, label: 'tags' });
12
30
  const tags = {
@@ -59,13 +77,13 @@ module.exports = function (options) {
59
77
 
60
78
  if (resource === 'calendar')
61
79
  return {
62
- [buildTag(dav, 'displayname')]: calendar.name
80
+ [buildTag(dav, 'displayname')]: encodeXMLEntities(calendar.name)
63
81
  };
64
82
 
65
83
  if (resource === 'calendarProppatch')
66
84
  return response(ctx.url, status[200], [
67
85
  {
68
- [buildTag(dav, 'displayname')]: calendar.name
86
+ [buildTag(dav, 'displayname')]: encodeXMLEntities(calendar.name)
69
87
  }
70
88
  ]);
71
89
  }
@@ -216,8 +234,11 @@ module.exports = function (options) {
216
234
  doc: 'https://tools.ietf.org/html/rfc4791#section-9.6',
217
235
  async resp({ event, ctx, calendar }) {
218
236
  const ics = await options.data.buildICS(ctx, event, calendar);
237
+ // Use entity encoding instead of CDATA for better API compatibility
238
+ // This ensures special characters are properly encoded while maintaining
239
+ // compatibility with tsdav and other CalDAV clients that expect string content
219
240
  return {
220
- [buildTag(cal, 'calendar-data')]: { $cdata: ics }
241
+ [buildTag(cal, 'calendar-data')]: encodeXMLEntities(ics)
221
242
  };
222
243
  }
223
244
  },
@@ -238,13 +259,17 @@ module.exports = function (options) {
238
259
  async resp({ resource, ctx, calendar }) {
239
260
  if (resource === 'calendar')
240
261
  return {
241
- [buildTag(cal, 'calendar-description')]: calendar.description
262
+ [buildTag(cal, 'calendar-description')]: encodeXMLEntities(
263
+ calendar.description
264
+ )
242
265
  };
243
266
 
244
267
  if (resource === 'calendarProppatch')
245
268
  return response(ctx.url, status[200], [
246
269
  {
247
- [buildTag(cal, 'calendar-description')]: calendar.description
270
+ [buildTag(cal, 'calendar-description')]: encodeXMLEntities(
271
+ calendar.description
272
+ )
248
273
  }
249
274
  ]);
250
275
  }
@@ -254,13 +279,17 @@ module.exports = function (options) {
254
279
  async resp({ resource, ctx, calendar }) {
255
280
  if (resource === 'calendar')
256
281
  return {
257
- [buildTag(cal, 'calendar-timezone')]: calendar.timezone
282
+ [buildTag(cal, 'calendar-timezone')]: encodeXMLEntities(
283
+ calendar.timezone
284
+ )
258
285
  };
259
286
 
260
287
  if (resource === 'calendarProppatch')
261
288
  return response(ctx.url, status[200], [
262
289
  {
263
- [buildTag(cal, 'calendar-timezone')]: calendar.timezone
290
+ [buildTag(cal, 'calendar-timezone')]: encodeXMLEntities(
291
+ calendar.timezone
292
+ )
264
293
  }
265
294
  ]);
266
295
  }
@@ -386,13 +415,17 @@ module.exports = function (options) {
386
415
  async resp({ resource, ctx, calendar }) {
387
416
  if (resource === 'calendar')
388
417
  return {
389
- [buildTag(ical, 'calendar-color')]: calendar.color
418
+ [buildTag(ical, 'calendar-color')]: encodeXMLEntities(
419
+ calendar.color
420
+ )
390
421
  };
391
422
 
392
423
  if (resource === 'calendarProppatch')
393
424
  return response(ctx.url, status[200], [
394
425
  {
395
- [buildTag(ical, 'calendar-color')]: calendar.color
426
+ [buildTag(ical, 'calendar-color')]: encodeXMLEntities(
427
+ calendar.color
428
+ )
396
429
  }
397
430
  ]);
398
431
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "caldav-adapter",
3
3
  "description": "CalDAV server for Node.js and Koa. Modernized and maintained for Forward Email.",
4
- "version": "8.2.2",
4
+ "version": "8.2.4",
5
5
  "author": "Sanders DeNardi and Forward Email LLC",
6
6
  "contributors": [
7
7
  "Sanders DeNardi <sedenardi@gmail.com> (http://www.sandersdenardi.com/)",
@@ -3,6 +3,24 @@ const xml = require('../../../common/xml');
3
3
  const { response, status } = require('../../../common/x-build');
4
4
  const winston = require('../../../common/winston');
5
5
 
6
+ /**
7
+ * Encode special characters for XML content to prevent parsing errors
8
+ * @param {string} str - String to encode
9
+ * @returns {string} - XML-safe encoded string
10
+ */
11
+ function encodeXMLEntities(str) {
12
+ if (typeof str !== 'string') {
13
+ return str;
14
+ }
15
+
16
+ return str
17
+ .replaceAll('&', '&amp;') // Must be first to avoid double-encoding
18
+ .replaceAll('<', '&lt;')
19
+ .replaceAll('>', '&gt;')
20
+ .replaceAll('"', '&quot;')
21
+ .replaceAll("'", '&#39;');
22
+ }
23
+
6
24
  module.exports = function (options) {
7
25
  const log = winston({
8
26
  ...options,
@@ -37,7 +55,7 @@ module.exports = function (options) {
37
55
  'D:getetag': options.data.getETag(ctx, event)
38
56
  },
39
57
  {
40
- 'CAL:calendar-data': ics
58
+ 'CAL:calendar-data': encodeXMLEntities(ics)
41
59
  }
42
60
  ]);
43
61
  });
@@ -2,6 +2,24 @@ const { setMissingMethod } = require('../../../common/response');
2
2
  const winston = require('../../../common/winston');
3
3
  const { response, status } = require('../../../common/x-build');
4
4
 
5
+ /**
6
+ * Encode special characters for XML content to prevent parsing errors
7
+ * @param {string} str - String to encode
8
+ * @returns {string} - XML-safe encoded string
9
+ */
10
+ function encodeXMLEntities(str) {
11
+ if (typeof str !== 'string') {
12
+ return str;
13
+ }
14
+
15
+ return str
16
+ .replaceAll('&', '&amp;') // Must be first to avoid double-encoding
17
+ .replaceAll('<', '&lt;')
18
+ .replaceAll('>', '&gt;')
19
+ .replaceAll('"', '&quot;')
20
+ .replaceAll("'", '&#39;');
21
+ }
22
+
5
23
  module.exports = function (options) {
6
24
  const log = winston({ ...options, label: 'calendar/get' });
7
25
 
@@ -23,7 +41,7 @@ module.exports = function (options) {
23
41
  'D:getetag': options.data.getETag(ctx, calendar)
24
42
  },
25
43
  {
26
- 'CAL:calendar-data': ics
44
+ 'CAL:calendar-data': encodeXMLEntities(ics)
27
45
  }
28
46
  ]);
29
47
  }
@@ -52,7 +70,7 @@ module.exports = function (options) {
52
70
  'D:getetag': options.data.getETag(ctx, calendar)
53
71
  },
54
72
  {
55
- 'CAL:calendar-data': ics
73
+ 'CAL:calendar-data': encodeXMLEntities(ics)
56
74
  }
57
75
  ]);
58
76
  };