@sockethub/platform-carddav 1.0.0-beta.1 → 1.0.0-beta.2
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/README.md +13 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.js +151 -41
- package/dist/index.js.map +7 -7
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -12,6 +12,19 @@ including IPv6 embeddings of private ranges and the local-use NAT64 prefix
|
|
|
12
12
|
Authentication supports Basic, Digest, or a caller-provided Bearer token
|
|
13
13
|
through the standard Sockethub credentials flow.
|
|
14
14
|
|
|
15
|
+
## Discovery cache
|
|
16
|
+
|
|
17
|
+
Each `query`, `create`, `update`, and `delete` needs the account's address book list to
|
|
18
|
+
check the target. The platform caches that discovery result in memory for
|
|
19
|
+
`packageConfig.discoveryCacheTtlMs` (default `300000`, 5 minutes; `0`
|
|
20
|
+
disables the cache). Entries are keyed by an HMAC of the protocol, service URL,
|
|
21
|
+
and credentials. The HMAC uses a per-process random secret, and only
|
|
22
|
+
collection metadata is stored. A `fetch` always discovers fresh. Within the TTL,
|
|
23
|
+
an address book added on the server is not visible to targeted actions, and a removed
|
|
24
|
+
one is still accepted as a target (the server then rejects the request). An
|
|
25
|
+
authentication, not-found, or unknown-address-book error drops the entry, so the next
|
|
26
|
+
request rediscovers. The cache is lost when the platform process restarts.
|
|
27
|
+
|
|
15
28
|
## Authentication
|
|
16
29
|
|
|
17
30
|
Send credentials before performing CardDAV actions. Use either a username and
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,10 @@ import type { ActivityStream, PlatformCallback, PlatformInterface, PlatformSchem
|
|
|
2
2
|
import type { CardDavCredentials } from "./types.js";
|
|
3
3
|
export default class CardDav implements PlatformInterface {
|
|
4
4
|
private readonly log;
|
|
5
|
-
|
|
5
|
+
private readonly discovery;
|
|
6
|
+
config: StatelessPlatformConfig & {
|
|
7
|
+
discoveryCacheTtlMs: number;
|
|
8
|
+
};
|
|
6
9
|
constructor(session: PlatformSession);
|
|
7
10
|
get schema(): PlatformSchemaStruct;
|
|
8
11
|
isInitialized(): boolean;
|
|
@@ -13,6 +16,7 @@ export default class CardDav implements PlatformInterface {
|
|
|
13
16
|
update(job: ActivityStream, credentials: CardDavCredentials, done: PlatformCallback): void;
|
|
14
17
|
delete(job: ActivityStream, credentials: CardDavCredentials, done: PlatformCallback): void;
|
|
15
18
|
private client;
|
|
19
|
+
private discoveryKey;
|
|
16
20
|
private book;
|
|
17
21
|
private mutation;
|
|
18
22
|
private fail;
|
package/dist/index.js
CHANGED
|
@@ -15762,7 +15762,7 @@ var require_ajv_formats_draft2019 = __commonJS(function(exports, module) {
|
|
|
15762
15762
|
|
|
15763
15763
|
// ../dav/dist/index.js
|
|
15764
15764
|
import { createRequire as createRequire2 } from "node:module";
|
|
15765
|
-
import { createHash, randomBytes } from "node:crypto";
|
|
15765
|
+
import { createHash, createHmac, randomBytes } from "node:crypto";
|
|
15766
15766
|
import { lookup as dnsLookup } from "node:dns";
|
|
15767
15767
|
import { isIP } from "node:net";
|
|
15768
15768
|
var __commonJS2 = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
@@ -39185,7 +39185,7 @@ function createGuardedLookup(allowPrivateAddresses) {
|
|
|
39185
39185
|
if (!allowPrivateAddresses) {
|
|
39186
39186
|
for (const { address } of addresses) {
|
|
39187
39187
|
if (isBlockedAddress(address)) {
|
|
39188
|
-
callback(new Error(`blocked non-public address
|
|
39188
|
+
callback(new Error(`blocked non-public address for ${hostname}`));
|
|
39189
39189
|
return;
|
|
39190
39190
|
}
|
|
39191
39191
|
}
|
|
@@ -42746,6 +42746,82 @@ function isDavCollectionChild(collectionId, resourceId) {
|
|
|
42746
42746
|
return false;
|
|
42747
42747
|
}
|
|
42748
42748
|
}
|
|
42749
|
+
|
|
42750
|
+
class DiscoveryCache {
|
|
42751
|
+
maxEntries;
|
|
42752
|
+
secret = randomBytes(32);
|
|
42753
|
+
entries = new Map;
|
|
42754
|
+
pending = new Map;
|
|
42755
|
+
timer;
|
|
42756
|
+
timerAt = Number.POSITIVE_INFINITY;
|
|
42757
|
+
constructor(maxEntries = 1000) {
|
|
42758
|
+
this.maxEntries = maxEntries;
|
|
42759
|
+
}
|
|
42760
|
+
key(...identity) {
|
|
42761
|
+
return createHmac("sha256", this.secret).update(JSON.stringify(identity)).digest("hex");
|
|
42762
|
+
}
|
|
42763
|
+
async get(key, ttlMs, discover) {
|
|
42764
|
+
if (!(ttlMs > 0))
|
|
42765
|
+
return discover();
|
|
42766
|
+
const hit = this.entries.get(key);
|
|
42767
|
+
if (hit && hit.expires > Date.now())
|
|
42768
|
+
return hit.value;
|
|
42769
|
+
const inFlight = this.pending.get(key);
|
|
42770
|
+
if (inFlight)
|
|
42771
|
+
return inFlight;
|
|
42772
|
+
const promise = discover();
|
|
42773
|
+
this.pending.set(key, promise);
|
|
42774
|
+
try {
|
|
42775
|
+
const value = await promise;
|
|
42776
|
+
if (this.pending.get(key) === promise)
|
|
42777
|
+
this.store(key, value, Date.now() + ttlMs);
|
|
42778
|
+
return value;
|
|
42779
|
+
} finally {
|
|
42780
|
+
if (this.pending.get(key) === promise)
|
|
42781
|
+
this.pending.delete(key);
|
|
42782
|
+
}
|
|
42783
|
+
}
|
|
42784
|
+
delete(key) {
|
|
42785
|
+
this.entries.delete(key);
|
|
42786
|
+
this.pending.delete(key);
|
|
42787
|
+
}
|
|
42788
|
+
get size() {
|
|
42789
|
+
return this.entries.size;
|
|
42790
|
+
}
|
|
42791
|
+
store(key, value, expires) {
|
|
42792
|
+
this.entries.delete(key);
|
|
42793
|
+
if (this.entries.size >= this.maxEntries) {
|
|
42794
|
+
this.sweep();
|
|
42795
|
+
if (this.entries.size >= this.maxEntries)
|
|
42796
|
+
this.entries.delete(this.entries.keys().next().value);
|
|
42797
|
+
}
|
|
42798
|
+
this.entries.set(key, { expires, value });
|
|
42799
|
+
this.schedule(expires);
|
|
42800
|
+
}
|
|
42801
|
+
sweep() {
|
|
42802
|
+
const now = Date.now();
|
|
42803
|
+
for (const [key, entry] of this.entries)
|
|
42804
|
+
if (entry.expires <= now)
|
|
42805
|
+
this.entries.delete(key);
|
|
42806
|
+
}
|
|
42807
|
+
schedule(at) {
|
|
42808
|
+
if (this.timer && at >= this.timerAt)
|
|
42809
|
+
return;
|
|
42810
|
+
clearTimeout(this.timer);
|
|
42811
|
+
this.timerAt = at;
|
|
42812
|
+
this.timer = setTimeout(() => {
|
|
42813
|
+
this.timer = undefined;
|
|
42814
|
+
this.timerAt = Number.POSITIVE_INFINITY;
|
|
42815
|
+
this.sweep();
|
|
42816
|
+
let next = Number.POSITIVE_INFINITY;
|
|
42817
|
+
for (const entry of this.entries.values())
|
|
42818
|
+
next = Math.min(next, entry.expires);
|
|
42819
|
+
if (next !== Number.POSITIVE_INFINITY)
|
|
42820
|
+
this.schedule(next);
|
|
42821
|
+
}, Math.min(Math.max(0, at - Date.now()), 2147483647));
|
|
42822
|
+
this.timer.unref?.();
|
|
42823
|
+
}
|
|
42824
|
+
}
|
|
42749
42825
|
function unquote(value) {
|
|
42750
42826
|
return value.startsWith('"') ? value.slice(1, -1).replace(/\\(.)/g, "$1") : value;
|
|
42751
42827
|
}
|
|
@@ -43199,7 +43275,7 @@ var ActivityStreamSchema = {
|
|
|
43199
43275
|
var package_default = {
|
|
43200
43276
|
name: "@sockethub/schemas",
|
|
43201
43277
|
description: "JSON schema files for validating Sockethub Activity Streams",
|
|
43202
|
-
version: "3.0.0-beta.
|
|
43278
|
+
version: "3.0.0-beta.2",
|
|
43203
43279
|
type: "module",
|
|
43204
43280
|
private: false,
|
|
43205
43281
|
author: "Nick Jennings <nick@silverbucket.net>",
|
|
@@ -43269,7 +43345,7 @@ var package_default = {
|
|
|
43269
43345
|
"ajv-formats": "^2.1.1",
|
|
43270
43346
|
"ajv-formats-draft2019": "^1.6.1"
|
|
43271
43347
|
},
|
|
43272
|
-
gitHead: "
|
|
43348
|
+
gitHead: "1f74d4e07311496f0acc021855137bc197d79eab",
|
|
43273
43349
|
types: "./dist/index.d.ts"
|
|
43274
43350
|
};
|
|
43275
43351
|
|
|
@@ -43374,8 +43450,11 @@ var SockethubConfigSchema = {
|
|
|
43374
43450
|
"@sockethub/platform-caldav",
|
|
43375
43451
|
"@sockethub/platform-dummy",
|
|
43376
43452
|
"@sockethub/platform-feeds",
|
|
43453
|
+
"@sockethub/platform-email",
|
|
43377
43454
|
"@sockethub/platform-irc",
|
|
43378
43455
|
"@sockethub/platform-metadata",
|
|
43456
|
+
"@sockethub/platform-messenger",
|
|
43457
|
+
"@sockethub/platform-instagram",
|
|
43379
43458
|
"@sockethub/platform-xmpp"
|
|
43380
43459
|
]
|
|
43381
43460
|
},
|
|
@@ -43391,7 +43470,8 @@ var SockethubConfigSchema = {
|
|
|
43391
43470
|
connectTimeoutMs: { type: "integer", minimum: 1 },
|
|
43392
43471
|
allowPrivateAddresses: { type: "boolean" },
|
|
43393
43472
|
allowInsecureHttp: { type: "boolean" },
|
|
43394
|
-
concurrency: { type: "integer", minimum: 1 }
|
|
43473
|
+
concurrency: { type: "integer", minimum: 1 },
|
|
43474
|
+
discoveryCacheTtlMs: { type: "integer", minimum: 0 }
|
|
43395
43475
|
}
|
|
43396
43476
|
},
|
|
43397
43477
|
"@sockethub/platform-caldav": {
|
|
@@ -43401,7 +43481,20 @@ var SockethubConfigSchema = {
|
|
|
43401
43481
|
connectTimeoutMs: { type: "integer", minimum: 1 },
|
|
43402
43482
|
allowPrivateAddresses: { type: "boolean" },
|
|
43403
43483
|
allowInsecureHttp: { type: "boolean" },
|
|
43404
|
-
concurrency: { type: "integer", minimum: 1 }
|
|
43484
|
+
concurrency: { type: "integer", minimum: 1 },
|
|
43485
|
+
discoveryCacheTtlMs: { type: "integer", minimum: 0 }
|
|
43486
|
+
}
|
|
43487
|
+
},
|
|
43488
|
+
"@sockethub/platform-email": {
|
|
43489
|
+
type: "object",
|
|
43490
|
+
additionalProperties: false,
|
|
43491
|
+
properties: {
|
|
43492
|
+
connectTimeoutMs: {
|
|
43493
|
+
type: "integer",
|
|
43494
|
+
minimum: 5000,
|
|
43495
|
+
maximum: 120000
|
|
43496
|
+
},
|
|
43497
|
+
allowPrivateAddresses: { type: "boolean" }
|
|
43405
43498
|
}
|
|
43406
43499
|
},
|
|
43407
43500
|
"@sockethub/platform-dummy": {
|
|
@@ -43424,7 +43517,8 @@ var SockethubConfigSchema = {
|
|
|
43424
43517
|
type: "object",
|
|
43425
43518
|
additionalProperties: false,
|
|
43426
43519
|
properties: {
|
|
43427
|
-
connectTimeoutMs: { type: "number" }
|
|
43520
|
+
connectTimeoutMs: { type: "number" },
|
|
43521
|
+
allowPrivateAddresses: { type: "boolean" }
|
|
43428
43522
|
}
|
|
43429
43523
|
},
|
|
43430
43524
|
"@sockethub/platform-xmpp": {
|
|
@@ -43534,6 +43628,12 @@ var SockethubConfigSchema = {
|
|
|
43534
43628
|
default: 20,
|
|
43535
43629
|
description: "Maximum persistent instances per client IP, including HTTP actions. 0 disables the cap."
|
|
43536
43630
|
},
|
|
43631
|
+
maxStartsPerIpPerMinute: {
|
|
43632
|
+
type: "integer",
|
|
43633
|
+
minimum: 0,
|
|
43634
|
+
default: 60,
|
|
43635
|
+
description: "Maximum new persistent instances a client IP may start per minute, " + "including HTTP actions. Bounds fork/teardown churn that the " + "concurrent caps allow. Reusing a running instance does not count. " + "0 disables the cap."
|
|
43636
|
+
},
|
|
43537
43637
|
maxPlatformInstances: {
|
|
43538
43638
|
type: "number",
|
|
43539
43639
|
minimum: 0,
|
|
@@ -43842,8 +43942,10 @@ function splitEscaped(value, separator) {
|
|
|
43842
43942
|
result.push(current);
|
|
43843
43943
|
return result;
|
|
43844
43944
|
}
|
|
43845
|
-
|
|
43846
|
-
|
|
43945
|
+
function unescapeText(value) {
|
|
43946
|
+
return value.replaceAll(/\\([nN,;\\])/g, (_match, character) => character === "n" || character === "N" ? `
|
|
43947
|
+
` : character);
|
|
43948
|
+
}
|
|
43847
43949
|
var escapeText = (value) => value.replace(/\r\n?/g, `
|
|
43848
43950
|
`).replaceAll("\\", "\\\\").replaceAll(`
|
|
43849
43951
|
`, "\\n").replaceAll(";", "\\;").replaceAll(",", "\\,");
|
|
@@ -44079,20 +44181,20 @@ function params(value) {
|
|
|
44079
44181
|
}
|
|
44080
44182
|
function fold(line) {
|
|
44081
44183
|
const chunks = [];
|
|
44082
|
-
let
|
|
44083
|
-
|
|
44084
|
-
|
|
44085
|
-
|
|
44086
|
-
|
|
44087
|
-
|
|
44088
|
-
|
|
44089
|
-
|
|
44090
|
-
|
|
44091
|
-
|
|
44092
|
-
|
|
44093
|
-
|
|
44094
|
-
}
|
|
44095
|
-
chunks.push(
|
|
44184
|
+
let start = 0;
|
|
44185
|
+
let end = 0;
|
|
44186
|
+
let octets = 0;
|
|
44187
|
+
for (const char of line) {
|
|
44188
|
+
const size = Buffer.byteLength(char, "utf8");
|
|
44189
|
+
if (octets + size > (chunks.length ? 74 : 75)) {
|
|
44190
|
+
chunks.push(line.slice(start, end));
|
|
44191
|
+
start = end;
|
|
44192
|
+
octets = 0;
|
|
44193
|
+
}
|
|
44194
|
+
octets += size;
|
|
44195
|
+
end += char.length;
|
|
44196
|
+
}
|
|
44197
|
+
chunks.push(line.slice(start));
|
|
44096
44198
|
return chunks.join(`\r
|
|
44097
44199
|
`);
|
|
44098
44200
|
}
|
|
@@ -44383,7 +44485,7 @@ class CardDavClient extends DavClient {
|
|
|
44383
44485
|
var package_default2 = {
|
|
44384
44486
|
name: "@sockethub/platform-carddav",
|
|
44385
44487
|
description: "A Sockethub platform for CardDAV address books and contacts",
|
|
44386
|
-
version: "1.0.0-beta.
|
|
44488
|
+
version: "1.0.0-beta.2",
|
|
44387
44489
|
type: "module",
|
|
44388
44490
|
private: false,
|
|
44389
44491
|
license: "LGPL-3.0+",
|
|
@@ -44412,21 +44514,21 @@ var package_default2 = {
|
|
|
44412
44514
|
test: "bun test src/"
|
|
44413
44515
|
},
|
|
44414
44516
|
dependencies: {
|
|
44415
|
-
"@sockethub/dav": "^1.0.0-beta.
|
|
44416
|
-
"@sockethub/schemas": "^3.0.0-beta.
|
|
44517
|
+
"@sockethub/dav": "^1.0.0-beta.2",
|
|
44518
|
+
"@sockethub/schemas": "^3.0.0-beta.2"
|
|
44417
44519
|
},
|
|
44418
44520
|
devDependencies: {
|
|
44419
44521
|
"@types/bun": "latest"
|
|
44420
44522
|
},
|
|
44421
44523
|
peerDependencies: {
|
|
44422
|
-
"@sockethub/server": "^5.0.0-beta.
|
|
44524
|
+
"@sockethub/server": "^5.0.0-beta.2"
|
|
44423
44525
|
},
|
|
44424
44526
|
peerDependenciesMeta: {
|
|
44425
44527
|
"@sockethub/server": {
|
|
44426
44528
|
optional: true
|
|
44427
44529
|
}
|
|
44428
44530
|
},
|
|
44429
|
-
gitHead: "
|
|
44531
|
+
gitHead: "1f74d4e07311496f0acc021855137bc197d79eab"
|
|
44430
44532
|
};
|
|
44431
44533
|
|
|
44432
44534
|
// src/schema.ts
|
|
@@ -44719,13 +44821,15 @@ var CONTEXT = buildCanonicalContext(PlatformCardDavSchema.contextUrl);
|
|
|
44719
44821
|
|
|
44720
44822
|
class CardDav {
|
|
44721
44823
|
log;
|
|
44824
|
+
discovery = new DiscoveryCache;
|
|
44722
44825
|
config = {
|
|
44723
44826
|
persist: false,
|
|
44724
44827
|
requireCredentials: ["fetch", "query", "create", "update", "delete"],
|
|
44725
44828
|
connectTimeoutMs: 15000,
|
|
44726
44829
|
allowPrivateAddresses: false,
|
|
44727
44830
|
allowInsecureHttp: false,
|
|
44728
|
-
concurrency: 10
|
|
44831
|
+
concurrency: 10,
|
|
44832
|
+
discoveryCacheTtlMs: 300000
|
|
44729
44833
|
};
|
|
44730
44834
|
constructor(session) {
|
|
44731
44835
|
this.log = session.log;
|
|
@@ -44748,40 +44852,40 @@ class CardDav {
|
|
|
44748
44852
|
summary: "CardDAV address books",
|
|
44749
44853
|
totalItems: items.length,
|
|
44750
44854
|
items
|
|
44751
|
-
})).catch((error) => this.fail(job, error, done)).finally(() => client.close().catch(() => {}));
|
|
44855
|
+
})).catch((error) => this.fail(job, error, done, credentials)).finally(() => client.close().catch(() => {}));
|
|
44752
44856
|
}
|
|
44753
44857
|
query(job, credentials, done) {
|
|
44754
44858
|
const client = this.client(credentials);
|
|
44755
|
-
this.book(client, job.target?.id ?? "").then((book) => client.query(book, job.object ?? {})).then((items) => done(null, {
|
|
44859
|
+
this.book(client, credentials, job.target?.id ?? "").then((book) => client.query(book, job.object ?? {})).then((items) => done(null, {
|
|
44756
44860
|
"@context": CONTEXT,
|
|
44757
44861
|
...job.id ? { id: job.id } : {},
|
|
44758
44862
|
type: "collection",
|
|
44759
44863
|
summary: "CardDAV contacts",
|
|
44760
44864
|
totalItems: items.length,
|
|
44761
44865
|
items
|
|
44762
|
-
})).catch((error) => this.fail(job, error, done)).finally(() => client.close().catch(() => {}));
|
|
44866
|
+
})).catch((error) => this.fail(job, error, done, credentials)).finally(() => client.close().catch(() => {}));
|
|
44763
44867
|
}
|
|
44764
44868
|
create(job, credentials, done) {
|
|
44765
44869
|
const client = this.client(credentials);
|
|
44766
|
-
this.book(client, job.target?.id ?? "").then((book) => client.create(book, job.object)).then((result) => done(null, this.mutation(job, "create", result))).catch((error) => this.fail(job, error, done)).finally(() => client.close().catch(() => {}));
|
|
44870
|
+
this.book(client, credentials, job.target?.id ?? "").then((book) => client.create(book, job.object)).then((result) => done(null, this.mutation(job, "create", result))).catch((error) => this.fail(job, error, done, credentials)).finally(() => client.close().catch(() => {}));
|
|
44767
44871
|
}
|
|
44768
44872
|
update(job, credentials, done) {
|
|
44769
44873
|
const client = this.client(credentials);
|
|
44770
44874
|
const input = job.object;
|
|
44771
|
-
this.book(client, job.target?.id ?? "").then((book) => {
|
|
44875
|
+
this.book(client, credentials, job.target?.id ?? "").then((book) => {
|
|
44772
44876
|
if (!isDavCollectionChild(book.id, input.id))
|
|
44773
44877
|
throw new DavFailure("carddav:invalid-resource");
|
|
44774
44878
|
return client.update(input);
|
|
44775
|
-
}).then((result) => done(null, this.mutation(job, "update", result))).catch((error) => this.fail(job, error, done)).finally(() => client.close().catch(() => {}));
|
|
44879
|
+
}).then((result) => done(null, this.mutation(job, "update", result))).catch((error) => this.fail(job, error, done, credentials)).finally(() => client.close().catch(() => {}));
|
|
44776
44880
|
}
|
|
44777
44881
|
delete(job, credentials, done) {
|
|
44778
44882
|
const client = this.client(credentials);
|
|
44779
44883
|
const input = job.object;
|
|
44780
|
-
this.book(client, job.target?.id ?? "").then((book) => {
|
|
44884
|
+
this.book(client, credentials, job.target?.id ?? "").then((book) => {
|
|
44781
44885
|
if (!isDavCollectionChild(book.id, input.id))
|
|
44782
44886
|
throw new DavFailure("carddav:invalid-resource");
|
|
44783
44887
|
return client.delete(input.id, input.etag);
|
|
44784
|
-
}).then(() => done(null, this.mutation(job, "delete", { id: input.id }))).catch((error) => this.fail(job, error, done)).finally(() => client.close().catch(() => {}));
|
|
44888
|
+
}).then(() => done(null, this.mutation(job, "delete", { id: input.id }))).catch((error) => this.fail(job, error, done, credentials)).finally(() => client.close().catch(() => {}));
|
|
44785
44889
|
}
|
|
44786
44890
|
client(credentials) {
|
|
44787
44891
|
const { url, ...authentication } = credentials.object;
|
|
@@ -44790,14 +44894,18 @@ class CardDav {
|
|
|
44790
44894
|
allowInsecureHttp: this.config.allowInsecureHttp
|
|
44791
44895
|
});
|
|
44792
44896
|
}
|
|
44793
|
-
|
|
44897
|
+
discoveryKey(credentials) {
|
|
44898
|
+
return this.discovery.key("carddav", credentials.object);
|
|
44899
|
+
}
|
|
44900
|
+
async book(client, credentials, id) {
|
|
44794
44901
|
let normalized;
|
|
44795
44902
|
try {
|
|
44796
44903
|
normalized = new URL(id).href;
|
|
44797
44904
|
} catch {
|
|
44798
44905
|
throw new DavFailure("carddav:invalid-address-book");
|
|
44799
44906
|
}
|
|
44800
|
-
const
|
|
44907
|
+
const books = await this.discovery.get(this.discoveryKey(credentials), this.config.discoveryCacheTtlMs, () => client.discoverAddressBooks());
|
|
44908
|
+
const book = books.find((item) => item.id === normalized);
|
|
44801
44909
|
if (!book)
|
|
44802
44910
|
throw new DavFailure("carddav:invalid-address-book");
|
|
44803
44911
|
return book;
|
|
@@ -44817,7 +44925,9 @@ class CardDav {
|
|
|
44817
44925
|
}
|
|
44818
44926
|
};
|
|
44819
44927
|
}
|
|
44820
|
-
fail(job, error, done) {
|
|
44928
|
+
fail(job, error, done, credentials) {
|
|
44929
|
+
if (credentials && error instanceof DavFailure && /:(authentication-failed|not-found|invalid-address-book)$/.test(error.code))
|
|
44930
|
+
this.discovery.delete(this.discoveryKey(credentials));
|
|
44821
44931
|
const code = error instanceof DavFailure ? error.code : `carddav:invalid-${job.type}`;
|
|
44822
44932
|
this.log.error(`CardDAV ${job.type} failed for actor ${job.actor.id}`, {
|
|
44823
44933
|
code,
|
|
@@ -44835,4 +44945,4 @@ export {
|
|
|
44835
44945
|
parseVCard
|
|
44836
44946
|
};
|
|
44837
44947
|
|
|
44838
|
-
//# debugId=
|
|
44948
|
+
//# debugId=DCD67AD60F21618364756E2164756E21
|