@fedify/fedify 0.11.0-dev.243 → 0.11.0-dev.245

Sign up to get free protection for your applications and to get access to all the features.
package/CHANGES.md CHANGED
@@ -25,6 +25,10 @@ To be released.
25
25
  - Added `Context.getFeaturedUri()` method.
26
26
  - Added `{ type: "featured"; handle: string }` case to `ParseUriResult`
27
27
  type.
28
+ - Added `Federation.setFeaturedTagsDispatcher()` method.
29
+ - Added `Context.getFeaturedTagsUri()` method.
30
+ - Added `{ type: "featuredTags"; handle: string }` case to
31
+ `ParseUriResult` type.
28
32
 
29
33
  - Frequently used JSON-LD contexts are now preloaded. [[#74]]
30
34
 
@@ -49,15 +53,64 @@ To be released.
49
53
  - `Collection.current`
50
54
  - `Collection.first`
51
55
  - `Collection.last`
52
- - `Collection.items`
53
56
  - `CollectionPage.partOf`
54
57
  - `CollectionPage.next`
55
58
  - `CollectionPage.prev`
56
59
 
60
+ - Added `featured` property to `Actor` types in Activity Vocabulary API.
61
+ [[#78]]
62
+
63
+ - Added `Application.getFeatured()` method.
64
+ - Added `Application.featuredId` property.
65
+ - `new Application()` constructor now accepts `featured` option.
66
+ - `Application.clone()` method now accepts `featured` option.
67
+ - Added `Group.getFeatured()` method.
68
+ - Added `Group.featuredId` property.
69
+ - `new Group()` constructor now accepts `featured` option.
70
+ - `Group.clone()` method now accepts `featured` option.
71
+ - Added `Organization.getFeatured()` method.
72
+ - Added `Organization.featuredId` property.
73
+ - `new Organization()` constructor now accepts `featured` option.
74
+ - `Organization.clone()` method now accepts `featured` option.
75
+ - Added `Person.getFeatured()` method.
76
+ - Added `Person.featuredId` property.
77
+ - `new Person()` constructor now accepts `featured` option.
78
+ - `Person.clone()` method now accepts `featured` option.
79
+ - Added `Service.getFeatured()` method.
80
+ - Added `Service.featuredId` property.
81
+ - `new Service()` constructor now accepts `featured` option.
82
+ - `Service.clone()` method now accepts `featured` option.
83
+
84
+ - Added `featuredTags` property to `Actor` types in Activity Vocabulary API.
85
+ [[#78]]
86
+
87
+ - Added `Application.getFeaturedTags()` method.
88
+ - Added `Application.featuredTagsId` property.
89
+ - `new Application()` constructor now accepts `featuredTags` option.
90
+ - `Application.clone()` method now accepts `featuredTags` option.
91
+ - Added `Group.getFeaturedTags()` method.
92
+ - Added `Group.featuredTagsId` property.
93
+ - `new Group()` constructor now accepts `featuredTags` option.
94
+ - `Group.clone()` method now accepts `featuredTags` option.
95
+ - Added `Organization.getFeaturedTags()` method.
96
+ - Added `Organization.featuredTagsId` property.
97
+ - `new Organization()` constructor now accepts `featuredTags` option.
98
+ - `Organization.clone()` method now accepts `featuredTags` option.
99
+ - Added `Person.getFeaturedTags()` method.
100
+ - Added `Person.featuredTagsId` property.
101
+ - `new Person()` constructor now accepts `featuredTags` option.
102
+ - `Person.clone()` method now accepts `featuredTags` option.
103
+ - Added `Service.getFeaturedTags()` method.
104
+ - Added `Service.featuredTagsId` property.
105
+ - `new Service()` constructor now accepts `featuredTags` option.
106
+ - `Service.clone()` method now accepts `featuredTags` option.
107
+
57
108
  - Added `target` property to `Activity` class in Activity Vocabulary API.
58
109
 
59
110
  - Added `Activity.getTarget()` method.
60
111
  - Added `Activity.getTargets()` method.
112
+ - Added `Activity.targetId` property.
113
+ - Added `Activity.targetIds` property.
61
114
  - `new Activity()` constructor now accepts `target` option.
62
115
  - `new Activity()` constructor now accepts `targets` option.
63
116
  - `Activity.clone()` method now accepts `target` option.
@@ -67,6 +120,8 @@ To be released.
67
120
 
68
121
  - Added `Activity.getResult()` method.
69
122
  - Added `Activity.getResults()` method.
123
+ - Added `Activity.resultId` property.
124
+ - Added `Activity.resultIds` property.
70
125
  - `new Activity()` constructor now accepts `result` option.
71
126
  - `new Activity()` constructor now accepts `results` option.
72
127
  - `Activity.clone()` method now accepts `result` option.
@@ -76,6 +131,8 @@ To be released.
76
131
 
77
132
  - Added `Activity.getOrigin()` method.
78
133
  - Added `Activity.getOrigins()` method.
134
+ - Added `Activity.originId` property.
135
+ - Added `Activity.originIds` property.
79
136
  - `new Activity()` constructor now accepts `origin` option.
80
137
  - `new Activity()` constructor now accepts `origins` option.
81
138
  - `Activity.clone()` method now accepts `origin` option.
@@ -85,6 +142,8 @@ To be released.
85
142
 
86
143
  - Added `Activity.getInstrument()` method.
87
144
  - Added `Activity.getInstruments()` method.
145
+ - Added `Activity.instrumentId` property.
146
+ - Added `Activity.instrumentIds` property.
88
147
  - `new Activity()` constructor now accepts `instrument` option.
89
148
  - `new Activity()` constructor now accepts `instruments` option.
90
149
  - `Activity.clone()` method now accepts `instrument` option.
@@ -103,6 +162,10 @@ To be released.
103
162
  - Renamed `InboxListenerSetter` interface to `InboxListenerSetters`.
104
163
  - Added `InboxListenerSetters.setSharedKeyDispatcher()` method.
105
164
 
165
+ - Followed up the [change in `eddsa-jcs-2022` specification][eddsa-jcs-2022]
166
+ for Object Integrity Proofs. [[FEP-8b32], [#54]]
167
+
168
+ [eddsa-jcs-2022]: https://codeberg.org/fediverse/fep/pulls/338
106
169
  [#71]: https://github.com/dahlia/fedify/issues/71
107
170
  [#74]: https://github.com/dahlia/fedify/issues/74
108
171
  [#76]: https://github.com/dahlia/fedify/pull/76
@@ -4,7 +4,7 @@ import { accepts } from "../deps/jsr.io/@std/http/0.224.5/negotiation.js";
4
4
  import { verifyRequest } from "../sig/http.js";
5
5
  import { doesActorOwnKey } from "../sig/owner.js";
6
6
  import { verifyObject } from "../sig/proof.js";
7
- import { Activity, Object, OrderedCollection, OrderedCollectionPage, } from "../vocab/vocab.js";
7
+ import { Activity, Link, Object, OrderedCollection, OrderedCollectionPage, } from "../vocab/vocab.js";
8
8
  export function acceptsJsonLd(request) {
9
9
  const types = accepts(request);
10
10
  if (types == null)
@@ -146,7 +146,7 @@ function filterCollectionItems(items, collectionName, filterPredicate) {
146
146
  let logged = false;
147
147
  for (const item of items) {
148
148
  let mappedItem;
149
- if (item instanceof Object || item instanceof URL) {
149
+ if (item instanceof Object || item instanceof Link || item instanceof URL) {
150
150
  mappedItem = item;
151
151
  }
152
152
  else if (item.id == null)
@@ -49,6 +49,7 @@ export class Federation {
49
49
  #followersCallbacks;
50
50
  #likedCallbacks;
51
51
  #featuredCallbacks;
52
+ #featuredTagsCallbacks;
52
53
  #inboxListeners;
53
54
  #inboxErrorHandler;
54
55
  #sharedInboxKeyDispatcher;
@@ -348,6 +349,20 @@ export class Federation {
348
349
  "URI. Set the property with Context.getFeaturedUri(handle).");
349
350
  }
350
351
  }
352
+ if (this.#featuredTagsCallbacks != null &&
353
+ this.#featuredTagsCallbacks.dispatcher != null) {
354
+ if (actor?.featuredTagsId == null) {
355
+ logger.warn("You configured a featured tags collection dispatcher, but the " +
356
+ "actor does not have a featuredTags property. Set the property " +
357
+ "with Context.getFeaturedTagsUri(handle).");
358
+ }
359
+ else if (actor.featuredTagsId.href != context.getFeaturedTagsUri(handle).href) {
360
+ logger.warn("You configured a featured tags collection dispatcher, but the " +
361
+ "actor's featuredTags property does not match the featured tags " +
362
+ "collection URI. Set the property with " +
363
+ "Context.getFeaturedTagsUri(handle).");
364
+ }
365
+ }
351
366
  if (this.#router.has("inbox")) {
352
367
  if (actor.inboxId == null) {
353
368
  logger.warn("You configured inbox listeners, but the actor does not " +
@@ -716,6 +731,51 @@ export class Federation {
716
731
  };
717
732
  return setters;
718
733
  }
734
+ /**
735
+ * Registers a featured tags collection dispatcher.
736
+ * @param path The URI path pattern for the featured tags collection.
737
+ * The syntax is based on URI Template
738
+ * ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
739
+ * must have one variable: `{handle}`.
740
+ * @param dispatcher A featured tags collection callback to register.
741
+ * @returns An object with methods to set other featured tags collection
742
+ * callbacks.
743
+ * @throws {@link RouterError} Thrown if the path pattern is invalid.
744
+ * @since 0.11.0
745
+ */
746
+ setFeaturedTagsDispatcher(path, dispatcher) {
747
+ if (this.#router.has("featuredTags")) {
748
+ throw new RouterError("Featured tags collection dispatcher already set.");
749
+ }
750
+ const variables = this.#router.add(path, "featuredTags");
751
+ if (variables.size !== 1 || !variables.has("handle")) {
752
+ throw new RouterError("Path for featured tags collection dispatcher must have one " +
753
+ "variable: {handle}");
754
+ }
755
+ const callbacks = {
756
+ dispatcher,
757
+ };
758
+ this.#featuredTagsCallbacks = callbacks;
759
+ const setters = {
760
+ setCounter(counter) {
761
+ callbacks.counter = counter;
762
+ return setters;
763
+ },
764
+ setFirstCursor(cursor) {
765
+ callbacks.firstCursor = cursor;
766
+ return setters;
767
+ },
768
+ setLastCursor(cursor) {
769
+ callbacks.lastCursor = cursor;
770
+ return setters;
771
+ },
772
+ authorize(predicate) {
773
+ callbacks.authorizePredicate = predicate;
774
+ return setters;
775
+ },
776
+ };
777
+ return setters;
778
+ }
719
779
  /**
720
780
  * Assigns the URL path for the inbox and starts setting inbox listeners.
721
781
  *
@@ -1062,6 +1122,16 @@ export class Federation {
1062
1122
  onNotFound,
1063
1123
  onNotAcceptable,
1064
1124
  });
1125
+ case "featuredTags":
1126
+ return await handleCollection(request, {
1127
+ name: "featured tags",
1128
+ handle: route.values.handle,
1129
+ context,
1130
+ collectionCallbacks: this.#featuredTagsCallbacks,
1131
+ onUnauthorized,
1132
+ onNotFound,
1133
+ onNotAcceptable,
1134
+ });
1065
1135
  default: {
1066
1136
  const response = onNotFound(request);
1067
1137
  return response instanceof Promise ? await response : response;
@@ -1174,6 +1244,13 @@ class ContextImpl {
1174
1244
  }
1175
1245
  return new URL(path, this.#url);
1176
1246
  }
1247
+ getFeaturedTagsUri(handle) {
1248
+ const path = this.#router.build("featuredTags", { handle });
1249
+ if (path == null) {
1250
+ throw new RouterError("No featured tags collection path registered.");
1251
+ }
1252
+ return new URL(path, this.#url);
1253
+ }
1177
1254
  parseUri(uri) {
1178
1255
  if (uri.origin !== this.#url.origin)
1179
1256
  return null;
@@ -1213,6 +1290,9 @@ class ContextImpl {
1213
1290
  else if (route.name === "featured") {
1214
1291
  return { type: "featured", handle: route.values.handle };
1215
1292
  }
1293
+ else if (route.name === "featuredTags") {
1294
+ return { type: "featuredTags", handle: route.values.handle };
1295
+ }
1216
1296
  return null;
1217
1297
  }
1218
1298
  getHandleFromActorUri(actorUri) {
package/esm/sig/proof.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import * as dntShim from "../_dnt.shims.js";
2
+ import { Activity, Multikey } from "../vocab/mod.js";
3
+ import { getLogger } from "@logtape/logtape";
2
4
  // @ts-ignore: json-canon is not typed
3
5
  import serialize from "json-canon";
4
6
  import { DataIntegrityProof } from "../vocab/vocab.js";
5
7
  import { fetchKey, validateCryptoKey } from "./key.js";
6
- import { Activity, Multikey } from "../vocab/mod.js";
7
- import { getLogger } from "@logtape/logtape";
8
8
  const logger = getLogger(["fedify", "sig", "proof"]);
9
9
  /**
10
10
  * Creates a proof for the given object.
@@ -32,13 +32,8 @@ export async function createProof(object, privateKey, keyId, { contextLoader, co
32
32
  const msgDigest = await dntShim.crypto.subtle.digest("SHA-256", msgBytes);
33
33
  created ??= dntShim.Temporal.Now.instant();
34
34
  const proofConfig = {
35
- // The below commented out line is needed according to section 3.3.1 of
36
- // the Data Integrity EdDSA Cryptosuites v1.0 spec, the FEP-8b32 spec does
37
- // not reflect this step; however, the FEP-8b32 spec will be updated to
38
- // be consistent with the Data Integrity EdDSA Cryptosuites v1.0 spec
39
- // some time soon. Before that happens, the below line is commented out.
40
- // See also: https://socialhub.activitypub.rocks/t/fep-8b32-object-integrity-proofs/2725/91?u=hongminhee
41
- // "@context": (compactMsg as any)["@context"],
35
+ // deno-lint-ignore no-explicit-any
36
+ "@context": compactMsg["@context"],
42
37
  type: "DataIntegrityProof",
43
38
  cryptosuite: "eddsa-jcs-2022",
44
39
  verificationMethod: keyId.href,
@@ -98,13 +93,8 @@ export async function verifyProof(jsonLd, proof, options = {}) {
98
93
  return null;
99
94
  const publicKeyPromise = fetchKey(proof.verificationMethodId, Multikey, options);
100
95
  const proofConfig = {
101
- // The below commented out line is needed according to section 3.3.1 of
102
- // the Data Integrity EdDSA Cryptosuites v1.0 spec, the FEP-8b32 spec does
103
- // not reflect this step; however, the FEP-8b32 spec will be updated to
104
- // be consistent with the Data Integrity EdDSA Cryptosuites v1.0 spec
105
- // some time soon. Before that happens, the below line is commented out.
106
- // See also: https://socialhub.activitypub.rocks/t/fep-8b32-object-integrity-proofs/2725/91?u=hongminhee
107
- // "@context": (jsonLd as any)["@context"],
96
+ // deno-lint-ignore no-explicit-any
97
+ "@context": jsonLd["@context"],
108
98
  type: "DataIntegrityProof",
109
99
  cryptosuite: proof.cryptosuite,
110
100
  verificationMethod: proof.verificationMethodId.href,
@@ -15,6 +15,9 @@ defaultContext:
15
15
  featured:
16
16
  "@id": "toot:featured"
17
17
  "@type": "@id"
18
+ featuredTags:
19
+ "@id": "toot:featuredTags"
20
+ "@type": "@id"
18
21
  discoverable: "toot:discoverable"
19
22
  suspended: "toot:suspended"
20
23
  memorial: "toot:memorial"
@@ -157,6 +160,17 @@ properties:
157
160
  range:
158
161
  - "https://www.w3.org/ns/activitystreams#Collection"
159
162
 
163
+ - singularName: featuredTags
164
+ functional: true
165
+ uri: "http://joinmastodon.org/ns#featuredTags"
166
+ description: |
167
+ What is known in Mastodon as "featured hashtags", hashtags that are featured
168
+ at people's profiles, is implemented using an extra property `featuredTags`
169
+ on the actor object that points to a {@link Collection} of {@link Hashtag}
170
+ objects specifically.
171
+ range:
172
+ - "https://www.w3.org/ns/activitystreams#Collection"
173
+
160
174
  - pluralName: streams
161
175
  singularName: stream
162
176
  singularAccessor: false
@@ -9,7 +9,13 @@ description: |
9
9
 
10
10
  Refer to the Activity Streams 2.0 Core specification for a complete
11
11
  description of the Collection type.
12
- defaultContext: "https://www.w3.org/ns/activitystreams"
12
+ defaultContext:
13
+ - "https://www.w3.org/ns/activitystreams"
14
+ - "https://w3id.org/security/data-integrity/v1"
15
+ - toot: "http://joinmastodon.org/ns#"
16
+ sensitive: "as:sensitive"
17
+ Emoji: "toot:Emoji"
18
+ Hashtag: "as:Hashtag"
13
19
 
14
20
  properties:
15
21
  - singularName: totalItems
@@ -57,3 +63,4 @@ properties:
57
63
  or unordered.
58
64
  range:
59
65
  - "https://www.w3.org/ns/activitystreams#Object"
66
+ - "https://www.w3.org/ns/activitystreams#Link"
@@ -7,7 +7,13 @@ description: |
7
7
  Used to represent distinct subsets of items from a `Collection`.
8
8
  Refer to the Activity Streams 2.0 Core for a complete description of
9
9
  the `CollectionPage` object.
10
- defaultContext: "https://www.w3.org/ns/activitystreams"
10
+ defaultContext:
11
+ - "https://www.w3.org/ns/activitystreams"
12
+ - "https://w3id.org/security/data-integrity/v1"
13
+ - toot: "http://joinmastodon.org/ns#"
14
+ sensitive: "as:sensitive"
15
+ Emoji: "toot:Emoji"
16
+ Hashtag: "as:Hashtag"
11
17
 
12
18
  properties:
13
19
  - singularName: partOf
@@ -15,6 +15,9 @@ defaultContext:
15
15
  featured:
16
16
  "@id": "toot:featured"
17
17
  "@type": "@id"
18
+ featuredTags:
19
+ "@id": "toot:featuredTags"
20
+ "@type": "@id"
18
21
  discoverable: "toot:discoverable"
19
22
  suspended: "toot:suspended"
20
23
  memorial: "toot:memorial"
@@ -157,6 +160,17 @@ properties:
157
160
  range:
158
161
  - "https://www.w3.org/ns/activitystreams#Collection"
159
162
 
163
+ - singularName: featuredTags
164
+ functional: true
165
+ uri: "http://joinmastodon.org/ns#featuredTags"
166
+ description: |
167
+ What is known in Mastodon as "featured hashtags", hashtags that are featured
168
+ at people's profiles, is implemented using an extra property `featuredTags`
169
+ on the actor object that points to a {@link Collection} of {@link Hashtag}
170
+ objects specifically.
171
+ range:
172
+ - "https://www.w3.org/ns/activitystreams#Collection"
173
+
160
174
  - pluralName: streams
161
175
  singularName: stream
162
176
  singularAccessor: false
@@ -6,7 +6,13 @@ entity: true
6
6
  description: |
7
7
  A subtype of {@link Collection} in which members of the logical collection
8
8
  are assumed to always be strictly ordered.
9
- defaultContext: "https://www.w3.org/ns/activitystreams"
9
+ defaultContext:
10
+ - "https://www.w3.org/ns/activitystreams"
11
+ - "https://w3id.org/security/data-integrity/v1"
12
+ - toot: "http://joinmastodon.org/ns#"
13
+ sensitive: "as:sensitive"
14
+ Emoji: "toot:Emoji"
15
+ Hashtag: "as:Hashtag"
10
16
 
11
17
  properties:
12
18
  - pluralName: items
@@ -18,3 +24,4 @@ properties:
18
24
  or unordered.
19
25
  range:
20
26
  - "https://www.w3.org/ns/activitystreams#Object"
27
+ - "https://www.w3.org/ns/activitystreams#Link"
@@ -7,7 +7,13 @@ description: |
7
7
  Used to represent ordered subsets of items from an `OrderedCollection`.
8
8
  Refer to the Activity Streams 2.0 Core for a complete description of
9
9
  the `OrderedCollectionPage` object.
10
- defaultContext: "https://www.w3.org/ns/activitystreams"
10
+ defaultContext:
11
+ - "https://www.w3.org/ns/activitystreams"
12
+ - "https://w3id.org/security/data-integrity/v1"
13
+ - toot: "http://joinmastodon.org/ns#"
14
+ sensitive: "as:sensitive"
15
+ Emoji: "toot:Emoji"
16
+ Hashtag: "as:Hashtag"
11
17
 
12
18
  properties:
13
19
  - singularName: startIndex
@@ -15,6 +15,9 @@ defaultContext:
15
15
  featured:
16
16
  "@id": "toot:featured"
17
17
  "@type": "@id"
18
+ featuredTags:
19
+ "@id": "toot:featuredTags"
20
+ "@type": "@id"
18
21
  discoverable: "toot:discoverable"
19
22
  suspended: "toot:suspended"
20
23
  memorial: "toot:memorial"
@@ -157,6 +160,17 @@ properties:
157
160
  range:
158
161
  - "https://www.w3.org/ns/activitystreams#Collection"
159
162
 
163
+ - singularName: featuredTags
164
+ functional: true
165
+ uri: "http://joinmastodon.org/ns#featuredTags"
166
+ description: |
167
+ What is known in Mastodon as "featured hashtags", hashtags that are featured
168
+ at people's profiles, is implemented using an extra property `featuredTags`
169
+ on the actor object that points to a {@link Collection} of {@link Hashtag}
170
+ objects specifically.
171
+ range:
172
+ - "https://www.w3.org/ns/activitystreams#Collection"
173
+
160
174
  - pluralName: streams
161
175
  singularName: stream
162
176
  singularAccessor: false
@@ -15,6 +15,9 @@ defaultContext:
15
15
  featured:
16
16
  "@id": "toot:featured"
17
17
  "@type": "@id"
18
+ featuredTags:
19
+ "@id": "toot:featuredTags"
20
+ "@type": "@id"
18
21
  discoverable: "toot:discoverable"
19
22
  suspended: "toot:suspended"
20
23
  memorial: "toot:memorial"
@@ -157,6 +160,17 @@ properties:
157
160
  range:
158
161
  - "https://www.w3.org/ns/activitystreams#Collection"
159
162
 
163
+ - singularName: featuredTags
164
+ functional: true
165
+ uri: "http://joinmastodon.org/ns#featuredTags"
166
+ description: |
167
+ What is known in Mastodon as "featured hashtags", hashtags that are featured
168
+ at people's profiles, is implemented using an extra property `featuredTags`
169
+ on the actor object that points to a {@link Collection} of {@link Hashtag}
170
+ objects specifically.
171
+ range:
172
+ - "https://www.w3.org/ns/activitystreams#Collection"
173
+
160
174
  - pluralName: streams
161
175
  singularName: stream
162
176
  singularAccessor: false
@@ -15,6 +15,9 @@ defaultContext:
15
15
  featured:
16
16
  "@id": "toot:featured"
17
17
  "@type": "@id"
18
+ featuredTags:
19
+ "@id": "toot:featuredTags"
20
+ "@type": "@id"
18
21
  discoverable: "toot:discoverable"
19
22
  suspended: "toot:suspended"
20
23
  memorial: "toot:memorial"
@@ -157,6 +160,17 @@ properties:
157
160
  range:
158
161
  - "https://www.w3.org/ns/activitystreams#Collection"
159
162
 
163
+ - singularName: featuredTags
164
+ functional: true
165
+ uri: "http://joinmastodon.org/ns#featuredTags"
166
+ description: |
167
+ What is known in Mastodon as "featured hashtags", hashtags that are featured
168
+ at people's profiles, is implemented using an extra property `featuredTags`
169
+ on the actor object that points to a {@link Collection} of {@link Hashtag}
170
+ objects specifically.
171
+ range:
172
+ - "https://www.w3.org/ns/activitystreams#Collection"
173
+
160
174
  - pluralName: streams
161
175
  singularName: stream
162
176
  singularAccessor: false