@sockethub/platform-carddav 1.0.0-beta.0 → 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 +19 -2
- package/dist/index.d.ts +5 -1
- package/dist/index.js +212 -56
- package/dist/index.js.map +9 -9
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -5,8 +5,25 @@ creating, updating, and deleting vCard contacts.
|
|
|
5
5
|
|
|
6
6
|
The platform accepts public HTTPS services by default. Administrators may opt
|
|
7
7
|
in to HTTP or private-network services with `allowInsecureHttp` and
|
|
8
|
-
`allowPrivateAddresses`.
|
|
9
|
-
|
|
8
|
+
`allowPrivateAddresses`. Address checks use the shared outbound URL guard,
|
|
9
|
+
including IPv6 embeddings of private ranges and the local-use NAT64 prefix
|
|
10
|
+
`64:ff9b:1::/48`. See
|
|
11
|
+
[Outbound URL guard](../../docs/configuration.md#outbound-url-guard).
|
|
12
|
+
Authentication supports Basic, Digest, or a caller-provided Bearer token
|
|
13
|
+
through the standard Sockethub credentials flow.
|
|
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.
|
|
10
27
|
|
|
11
28
|
## Authentication
|
|
12
29
|
|
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,14 +43517,16 @@ 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": {
|
|
43431
43525
|
type: "object",
|
|
43432
43526
|
additionalProperties: false,
|
|
43433
43527
|
properties: {
|
|
43434
|
-
connectTimeoutMs: { type: "number" }
|
|
43528
|
+
connectTimeoutMs: { type: "number" },
|
|
43529
|
+
allowPrivateAddresses: { type: "boolean" }
|
|
43435
43530
|
}
|
|
43436
43531
|
},
|
|
43437
43532
|
"@sockethub/platform-metadata": {
|
|
@@ -43521,11 +43616,29 @@ var SockethubConfigSchema = {
|
|
|
43521
43616
|
type: "object",
|
|
43522
43617
|
additionalProperties: false,
|
|
43523
43618
|
properties: {
|
|
43619
|
+
maxInstancesPerSession: {
|
|
43620
|
+
type: "integer",
|
|
43621
|
+
minimum: 0,
|
|
43622
|
+
default: 10,
|
|
43623
|
+
description: "Maximum persistent instances per socket session. 0 disables the cap."
|
|
43624
|
+
},
|
|
43625
|
+
maxInstancesPerIp: {
|
|
43626
|
+
type: "integer",
|
|
43627
|
+
minimum: 0,
|
|
43628
|
+
default: 20,
|
|
43629
|
+
description: "Maximum persistent instances per client IP, including HTTP actions. 0 disables the cap."
|
|
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
|
+
},
|
|
43524
43637
|
maxPlatformInstances: {
|
|
43525
43638
|
type: "number",
|
|
43526
43639
|
minimum: 0,
|
|
43527
43640
|
default: 100,
|
|
43528
|
-
description: "Upper bound on concurrently running platform instances " + "(child processes). Each persistent-platform actor forks " + "its own process, so an unbounded count is a resource " + "exhaustion risk on public instances. 0 disables the cap."
|
|
43641
|
+
description: "Upper bound on concurrently running persistent platform instances " + "(child processes). Each persistent-platform actor forks " + "its own process, so an unbounded count is a resource " + "exhaustion risk on public instances. 0 disables the cap."
|
|
43529
43642
|
}
|
|
43530
43643
|
}
|
|
43531
43644
|
},
|
|
@@ -43706,33 +43819,66 @@ var SockethubConfigSchema = {
|
|
|
43706
43819
|
};
|
|
43707
43820
|
var SockethubConfigSchemaId = versionedSchemaId(SockethubConfigSchema.$id, package_default.version);
|
|
43708
43821
|
|
|
43709
|
-
// ../schemas/src/
|
|
43710
|
-
var
|
|
43711
|
-
var
|
|
43822
|
+
// ../schemas/src/helpers/codegen.ts
|
|
43823
|
+
var available;
|
|
43824
|
+
var warned = false;
|
|
43825
|
+
function isCodegenAvailable() {
|
|
43826
|
+
if (available === undefined) {
|
|
43827
|
+
try {
|
|
43828
|
+
new Function("return true");
|
|
43829
|
+
available = true;
|
|
43830
|
+
} catch {
|
|
43831
|
+
available = false;
|
|
43832
|
+
}
|
|
43833
|
+
}
|
|
43834
|
+
return available;
|
|
43835
|
+
}
|
|
43836
|
+
function warnCodegenUnavailable() {
|
|
43837
|
+
if (warned) {
|
|
43838
|
+
return;
|
|
43839
|
+
}
|
|
43840
|
+
warned = true;
|
|
43841
|
+
console.warn("[@sockethub/schemas] Schema validation is disabled: this environment's Content Security Policy blocks `new Function`, which Ajv needs to compile schemas. The Sockethub server still validates every message.");
|
|
43842
|
+
}
|
|
43712
43843
|
|
|
43713
43844
|
// ../schemas/src/validator.ts
|
|
43714
|
-
var
|
|
43845
|
+
var import_ajv = __toESM(require_ajv(), 1);
|
|
43715
43846
|
var import_ajv_formats = __toESM(require_dist(), 1);
|
|
43716
43847
|
var import_ajv_formats_draft2019 = __toESM(require_ajv_formats_draft2019(), 1);
|
|
43717
|
-
var ajv2 = new import_ajv2.default({ strictTypes: false, allErrors: true });
|
|
43718
|
-
import_ajv_formats.default(ajv2);
|
|
43719
|
-
import_ajv_formats_draft2019.default(ajv2);
|
|
43720
43848
|
var schemaURL = "https://sockethub.org/schemas/v0";
|
|
43721
43849
|
var schemas = {};
|
|
43722
43850
|
var systemContextsRegistered = false;
|
|
43723
43851
|
schemas[`${schemaURL}/activity-stream`] = ActivityStreamSchema;
|
|
43724
|
-
|
|
43725
|
-
|
|
43852
|
+
var ajv;
|
|
43853
|
+
function getAjv() {
|
|
43854
|
+
if (!isCodegenAvailable()) {
|
|
43855
|
+
warnCodegenUnavailable();
|
|
43856
|
+
return;
|
|
43857
|
+
}
|
|
43858
|
+
if (!ajv) {
|
|
43859
|
+
const instance = new import_ajv.default({ strictTypes: false, allErrors: true });
|
|
43860
|
+
import_ajv_formats.default(instance);
|
|
43861
|
+
import_ajv_formats_draft2019.default(instance);
|
|
43862
|
+
for (const uri in schemas) {
|
|
43863
|
+
instance.addSchema(schemas[uri], uri);
|
|
43864
|
+
}
|
|
43865
|
+
ajv = instance;
|
|
43866
|
+
}
|
|
43867
|
+
return ajv;
|
|
43726
43868
|
}
|
|
43727
43869
|
function registerSystemContext(platformId, contextUrl) {
|
|
43728
43870
|
registerPlatformContext(platformId, contextUrl, `${schemaURL}/context/${platformId}/messages`, `${schemaURL}/context/${platformId}/credentials`);
|
|
43871
|
+
const instance = getAjv();
|
|
43872
|
+
if (!instance) {
|
|
43873
|
+
return;
|
|
43874
|
+
}
|
|
43729
43875
|
const messageSchemaRef = `${schemaURL}/context/${platformId}/messages`;
|
|
43730
|
-
if (!
|
|
43731
|
-
|
|
43876
|
+
if (!instance.getSchema(messageSchemaRef)) {
|
|
43877
|
+
instance.addSchema({}, messageSchemaRef);
|
|
43732
43878
|
}
|
|
43733
43879
|
const credentialsSchemaRef = `${schemaURL}/context/${platformId}/credentials`;
|
|
43734
|
-
if (!
|
|
43735
|
-
|
|
43880
|
+
if (!instance.getSchema(credentialsSchemaRef)) {
|
|
43881
|
+
instance.addSchema({}, credentialsSchemaRef);
|
|
43736
43882
|
}
|
|
43737
43883
|
}
|
|
43738
43884
|
function registerSystemPlatformContexts() {
|
|
@@ -43796,8 +43942,10 @@ function splitEscaped(value, separator) {
|
|
|
43796
43942
|
result.push(current);
|
|
43797
43943
|
return result;
|
|
43798
43944
|
}
|
|
43799
|
-
|
|
43800
|
-
|
|
43945
|
+
function unescapeText(value) {
|
|
43946
|
+
return value.replaceAll(/\\([nN,;\\])/g, (_match, character) => character === "n" || character === "N" ? `
|
|
43947
|
+
` : character);
|
|
43948
|
+
}
|
|
43801
43949
|
var escapeText = (value) => value.replace(/\r\n?/g, `
|
|
43802
43950
|
`).replaceAll("\\", "\\\\").replaceAll(`
|
|
43803
43951
|
`, "\\n").replaceAll(";", "\\;").replaceAll(",", "\\,");
|
|
@@ -44033,20 +44181,20 @@ function params(value) {
|
|
|
44033
44181
|
}
|
|
44034
44182
|
function fold(line) {
|
|
44035
44183
|
const chunks = [];
|
|
44036
|
-
let
|
|
44037
|
-
|
|
44038
|
-
|
|
44039
|
-
|
|
44040
|
-
|
|
44041
|
-
|
|
44042
|
-
|
|
44043
|
-
|
|
44044
|
-
|
|
44045
|
-
|
|
44046
|
-
|
|
44047
|
-
|
|
44048
|
-
}
|
|
44049
|
-
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));
|
|
44050
44198
|
return chunks.join(`\r
|
|
44051
44199
|
`);
|
|
44052
44200
|
}
|
|
@@ -44337,7 +44485,7 @@ class CardDavClient extends DavClient {
|
|
|
44337
44485
|
var package_default2 = {
|
|
44338
44486
|
name: "@sockethub/platform-carddav",
|
|
44339
44487
|
description: "A Sockethub platform for CardDAV address books and contacts",
|
|
44340
|
-
version: "1.0.0-beta.
|
|
44488
|
+
version: "1.0.0-beta.2",
|
|
44341
44489
|
type: "module",
|
|
44342
44490
|
private: false,
|
|
44343
44491
|
license: "LGPL-3.0+",
|
|
@@ -44366,21 +44514,21 @@ var package_default2 = {
|
|
|
44366
44514
|
test: "bun test src/"
|
|
44367
44515
|
},
|
|
44368
44516
|
dependencies: {
|
|
44369
|
-
"@sockethub/dav": "^1.0.0-beta.
|
|
44370
|
-
"@sockethub/schemas": "^3.0.0-beta.
|
|
44517
|
+
"@sockethub/dav": "^1.0.0-beta.2",
|
|
44518
|
+
"@sockethub/schemas": "^3.0.0-beta.2"
|
|
44371
44519
|
},
|
|
44372
44520
|
devDependencies: {
|
|
44373
44521
|
"@types/bun": "latest"
|
|
44374
44522
|
},
|
|
44375
44523
|
peerDependencies: {
|
|
44376
|
-
"@sockethub/server": "^5.0.0-beta.
|
|
44524
|
+
"@sockethub/server": "^5.0.0-beta.2"
|
|
44377
44525
|
},
|
|
44378
44526
|
peerDependenciesMeta: {
|
|
44379
44527
|
"@sockethub/server": {
|
|
44380
44528
|
optional: true
|
|
44381
44529
|
}
|
|
44382
44530
|
},
|
|
44383
|
-
gitHead: "
|
|
44531
|
+
gitHead: "1f74d4e07311496f0acc021855137bc197d79eab"
|
|
44384
44532
|
};
|
|
44385
44533
|
|
|
44386
44534
|
// src/schema.ts
|
|
@@ -44673,13 +44821,15 @@ var CONTEXT = buildCanonicalContext(PlatformCardDavSchema.contextUrl);
|
|
|
44673
44821
|
|
|
44674
44822
|
class CardDav {
|
|
44675
44823
|
log;
|
|
44824
|
+
discovery = new DiscoveryCache;
|
|
44676
44825
|
config = {
|
|
44677
44826
|
persist: false,
|
|
44678
44827
|
requireCredentials: ["fetch", "query", "create", "update", "delete"],
|
|
44679
44828
|
connectTimeoutMs: 15000,
|
|
44680
44829
|
allowPrivateAddresses: false,
|
|
44681
44830
|
allowInsecureHttp: false,
|
|
44682
|
-
concurrency: 10
|
|
44831
|
+
concurrency: 10,
|
|
44832
|
+
discoveryCacheTtlMs: 300000
|
|
44683
44833
|
};
|
|
44684
44834
|
constructor(session) {
|
|
44685
44835
|
this.log = session.log;
|
|
@@ -44702,40 +44852,40 @@ class CardDav {
|
|
|
44702
44852
|
summary: "CardDAV address books",
|
|
44703
44853
|
totalItems: items.length,
|
|
44704
44854
|
items
|
|
44705
|
-
})).catch((error) => this.fail(job, error, done)).finally(() => client.close().catch(() => {}));
|
|
44855
|
+
})).catch((error) => this.fail(job, error, done, credentials)).finally(() => client.close().catch(() => {}));
|
|
44706
44856
|
}
|
|
44707
44857
|
query(job, credentials, done) {
|
|
44708
44858
|
const client = this.client(credentials);
|
|
44709
|
-
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, {
|
|
44710
44860
|
"@context": CONTEXT,
|
|
44711
44861
|
...job.id ? { id: job.id } : {},
|
|
44712
44862
|
type: "collection",
|
|
44713
44863
|
summary: "CardDAV contacts",
|
|
44714
44864
|
totalItems: items.length,
|
|
44715
44865
|
items
|
|
44716
|
-
})).catch((error) => this.fail(job, error, done)).finally(() => client.close().catch(() => {}));
|
|
44866
|
+
})).catch((error) => this.fail(job, error, done, credentials)).finally(() => client.close().catch(() => {}));
|
|
44717
44867
|
}
|
|
44718
44868
|
create(job, credentials, done) {
|
|
44719
44869
|
const client = this.client(credentials);
|
|
44720
|
-
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(() => {}));
|
|
44721
44871
|
}
|
|
44722
44872
|
update(job, credentials, done) {
|
|
44723
44873
|
const client = this.client(credentials);
|
|
44724
44874
|
const input = job.object;
|
|
44725
|
-
this.book(client, job.target?.id ?? "").then((book) => {
|
|
44875
|
+
this.book(client, credentials, job.target?.id ?? "").then((book) => {
|
|
44726
44876
|
if (!isDavCollectionChild(book.id, input.id))
|
|
44727
44877
|
throw new DavFailure("carddav:invalid-resource");
|
|
44728
44878
|
return client.update(input);
|
|
44729
|
-
}).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(() => {}));
|
|
44730
44880
|
}
|
|
44731
44881
|
delete(job, credentials, done) {
|
|
44732
44882
|
const client = this.client(credentials);
|
|
44733
44883
|
const input = job.object;
|
|
44734
|
-
this.book(client, job.target?.id ?? "").then((book) => {
|
|
44884
|
+
this.book(client, credentials, job.target?.id ?? "").then((book) => {
|
|
44735
44885
|
if (!isDavCollectionChild(book.id, input.id))
|
|
44736
44886
|
throw new DavFailure("carddav:invalid-resource");
|
|
44737
44887
|
return client.delete(input.id, input.etag);
|
|
44738
|
-
}).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(() => {}));
|
|
44739
44889
|
}
|
|
44740
44890
|
client(credentials) {
|
|
44741
44891
|
const { url, ...authentication } = credentials.object;
|
|
@@ -44744,14 +44894,18 @@ class CardDav {
|
|
|
44744
44894
|
allowInsecureHttp: this.config.allowInsecureHttp
|
|
44745
44895
|
});
|
|
44746
44896
|
}
|
|
44747
|
-
|
|
44897
|
+
discoveryKey(credentials) {
|
|
44898
|
+
return this.discovery.key("carddav", credentials.object);
|
|
44899
|
+
}
|
|
44900
|
+
async book(client, credentials, id) {
|
|
44748
44901
|
let normalized;
|
|
44749
44902
|
try {
|
|
44750
44903
|
normalized = new URL(id).href;
|
|
44751
44904
|
} catch {
|
|
44752
44905
|
throw new DavFailure("carddav:invalid-address-book");
|
|
44753
44906
|
}
|
|
44754
|
-
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);
|
|
44755
44909
|
if (!book)
|
|
44756
44910
|
throw new DavFailure("carddav:invalid-address-book");
|
|
44757
44911
|
return book;
|
|
@@ -44771,7 +44925,9 @@ class CardDav {
|
|
|
44771
44925
|
}
|
|
44772
44926
|
};
|
|
44773
44927
|
}
|
|
44774
|
-
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));
|
|
44775
44931
|
const code = error instanceof DavFailure ? error.code : `carddav:invalid-${job.type}`;
|
|
44776
44932
|
this.log.error(`CardDAV ${job.type} failed for actor ${job.actor.id}`, {
|
|
44777
44933
|
code,
|
|
@@ -44789,4 +44945,4 @@ export {
|
|
|
44789
44945
|
parseVCard
|
|
44790
44946
|
};
|
|
44791
44947
|
|
|
44792
|
-
//# debugId=
|
|
44948
|
+
//# debugId=DCD67AD60F21618364756E2164756E21
|