@fedify/fedify 0.10.0-dev.194 → 0.10.0-dev.195

Sign up to get free protection for your applications and to get access to all the features.
Files changed (179) hide show
  1. package/CHANGES.md +41 -1
  2. package/esm/deps/jsr.io/@std/encoding/0.224.3/base64url.js +83 -0
  3. package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/mod.js +1 -1
  4. package/esm/federation/handler.js +1 -1
  5. package/esm/federation/middleware.js +18 -1
  6. package/esm/nodeinfo/types.js +1 -1
  7. package/esm/runtime/key.js +82 -0
  8. package/esm/testing/fixtures/w3id.org/security/multikey/v1 +35 -0
  9. package/esm/testing/fixtures/www.w3.org/ns/did/v1 +58 -0
  10. package/esm/vocab/application.yaml +15 -1
  11. package/esm/vocab/group.yaml +15 -1
  12. package/esm/vocab/multikey.yaml +33 -0
  13. package/esm/vocab/organization.yaml +15 -1
  14. package/esm/vocab/person.yaml +15 -1
  15. package/esm/vocab/service.yaml +15 -1
  16. package/esm/vocab/vocab.js +986 -13
  17. package/package.json +4 -1
  18. package/types/codegen/type.d.ts.map +1 -1
  19. package/types/deps/jsr.io/@std/async/{0.224.1 → 0.224.2}/delay.d.ts.map +1 -1
  20. package/types/deps/jsr.io/@std/encoding/0.224.3/base64url.d.ts +38 -0
  21. package/types/deps/jsr.io/@std/encoding/0.224.3/base64url.d.ts.map +1 -0
  22. package/types/deps/jsr.io/@std/http/{0.224.3 → 0.224.4}/_negotiation/common.d.ts.map +1 -1
  23. package/types/deps/jsr.io/@std/http/{0.224.3 → 0.224.4}/_negotiation/encoding.d.ts.map +1 -1
  24. package/types/deps/jsr.io/@std/http/{0.224.3 → 0.224.4}/_negotiation/language.d.ts.map +1 -1
  25. package/types/deps/jsr.io/@std/http/{0.224.3 → 0.224.4}/_negotiation/media_type.d.ts.map +1 -1
  26. package/types/deps/jsr.io/@std/http/{0.224.3 → 0.224.4}/negotiation.d.ts.map +1 -1
  27. package/types/deps/jsr.io/@std/path/1.0.0-rc.1/_common/assert_path.d.ts.map +1 -0
  28. package/types/deps/jsr.io/@std/path/1.0.0-rc.1/_common/basename.d.ts.map +1 -0
  29. package/types/deps/jsr.io/@std/path/1.0.0-rc.1/_common/constants.d.ts.map +1 -0
  30. package/types/deps/jsr.io/@std/path/1.0.0-rc.1/_common/dirname.d.ts.map +1 -0
  31. package/types/deps/jsr.io/@std/path/1.0.0-rc.1/_common/normalize.d.ts.map +1 -0
  32. package/types/deps/jsr.io/@std/path/1.0.0-rc.1/_common/normalize_string.d.ts.map +1 -0
  33. package/types/deps/jsr.io/@std/path/1.0.0-rc.1/_common/strip_trailing_separators.d.ts.map +1 -0
  34. package/types/deps/jsr.io/@std/path/1.0.0-rc.1/posix/_util.d.ts.map +1 -0
  35. package/types/deps/jsr.io/@std/path/1.0.0-rc.1/posix/basename.d.ts.map +1 -0
  36. package/types/deps/jsr.io/@std/path/1.0.0-rc.1/posix/dirname.d.ts.map +1 -0
  37. package/types/deps/jsr.io/@std/path/1.0.0-rc.1/posix/extname.d.ts.map +1 -0
  38. package/types/deps/jsr.io/@std/path/1.0.0-rc.1/posix/join.d.ts.map +1 -0
  39. package/types/deps/jsr.io/@std/path/1.0.0-rc.1/posix/normalize.d.ts.map +1 -0
  40. package/types/deps/jsr.io/@std/semver/0.224.3/_constants.d.ts.map +1 -0
  41. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/_shared.d.ts.map +1 -1
  42. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/_test_comparator_set.d.ts.map +1 -1
  43. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/can_parse.d.ts.map +1 -1
  44. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/compare.d.ts.map +1 -1
  45. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/constants.d.ts.map +1 -1
  46. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/difference.d.ts.map +1 -1
  47. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/equals.d.ts.map +1 -1
  48. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/format.d.ts.map +1 -1
  49. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/format_range.d.ts.map +1 -1
  50. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/greater_or_equal.d.ts.map +1 -1
  51. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/greater_than.d.ts.map +1 -1
  52. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/greater_than_range.d.ts.map +1 -1
  53. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/increment.d.ts.map +1 -1
  54. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/is_range.d.ts.map +1 -1
  55. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/is_semver.d.ts.map +1 -1
  56. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/less_or_equal.d.ts.map +1 -1
  57. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/less_than.d.ts.map +1 -1
  58. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/less_than_range.d.ts.map +1 -1
  59. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/max_satisfying.d.ts.map +1 -1
  60. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/min_satisfying.d.ts.map +1 -1
  61. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/mod.d.ts +1 -1
  62. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/mod.d.ts.map +1 -1
  63. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/not_equals.d.ts.map +1 -1
  64. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/parse.d.ts.map +1 -1
  65. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/parse_range.d.ts.map +1 -1
  66. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/range_intersects.d.ts.map +1 -1
  67. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/range_max.d.ts.map +1 -1
  68. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/range_min.d.ts.map +1 -1
  69. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/satisfies.d.ts.map +1 -1
  70. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/test_range.d.ts.map +1 -1
  71. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/try_parse.d.ts.map +1 -1
  72. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/try_parse_range.d.ts.map +1 -1
  73. package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/types.d.ts.map +1 -1
  74. package/types/deps/jsr.io/@std/text/{0.224.2 → 0.224.3}/_util.d.ts.map +1 -1
  75. package/types/deps/jsr.io/@std/text/{0.224.2 → 0.224.3}/case.d.ts.map +1 -1
  76. package/types/deps/jsr.io/@std/text/{0.224.2 → 0.224.3}/closest_string.d.ts.map +1 -1
  77. package/types/deps/jsr.io/@std/text/{0.224.2 → 0.224.3}/compare_similarity.d.ts.map +1 -1
  78. package/types/deps/jsr.io/@std/text/{0.224.2 → 0.224.3}/levenshtein_distance.d.ts.map +1 -1
  79. package/types/deps/jsr.io/@std/text/0.224.3/mod.d.ts.map +1 -0
  80. package/types/deps/jsr.io/@std/text/{0.224.2 → 0.224.3}/word_similarity_sort.d.ts.map +1 -1
  81. package/types/deps/jsr.io/@std/url/{0.224.0 → 0.224.1}/_strip.d.ts.map +1 -1
  82. package/types/deps/jsr.io/@std/url/0.224.1/basename.d.ts.map +1 -0
  83. package/types/deps/jsr.io/@std/url/0.224.1/dirname.d.ts.map +1 -0
  84. package/types/deps/jsr.io/@std/url/0.224.1/extname.d.ts.map +1 -0
  85. package/types/deps/jsr.io/@std/url/0.224.1/join.d.ts.map +1 -0
  86. package/types/deps/jsr.io/@std/url/0.224.1/mod.d.ts.map +1 -0
  87. package/types/deps/jsr.io/@std/url/0.224.1/normalize.d.ts.map +1 -0
  88. package/types/federation/context.d.ts +6 -1
  89. package/types/federation/context.d.ts.map +1 -1
  90. package/types/federation/middleware.d.ts.map +1 -1
  91. package/types/nodeinfo/types.d.ts +1 -1
  92. package/types/runtime/key.d.ts +20 -0
  93. package/types/runtime/key.d.ts.map +1 -1
  94. package/types/vocab/vocab.d.ts +249 -0
  95. package/types/vocab/vocab.d.ts.map +1 -1
  96. package/types/deps/jsr.io/@std/assert/0.226.0/assert.d.ts.map +0 -1
  97. package/types/deps/jsr.io/@std/assert/0.226.0/assertion_error.d.ts.map +0 -1
  98. package/types/deps/jsr.io/@std/semver/0.224.2/_constants.d.ts.map +0 -1
  99. package/types/deps/jsr.io/@std/text/0.224.2/mod.d.ts.map +0 -1
  100. package/types/deps/jsr.io/@std/url/0.224.0/basename.d.ts.map +0 -1
  101. package/types/deps/jsr.io/@std/url/0.224.0/dirname.d.ts.map +0 -1
  102. package/types/deps/jsr.io/@std/url/0.224.0/extname.d.ts.map +0 -1
  103. package/types/deps/jsr.io/@std/url/0.224.0/join.d.ts.map +0 -1
  104. package/types/deps/jsr.io/@std/url/0.224.0/mod.d.ts.map +0 -1
  105. package/types/deps/jsr.io/@std/url/0.224.0/normalize.d.ts.map +0 -1
  106. /package/esm/deps/jsr.io/@std/http/{0.224.3 → 0.224.4}/_negotiation/common.js +0 -0
  107. /package/esm/deps/jsr.io/@std/http/{0.224.3 → 0.224.4}/_negotiation/encoding.js +0 -0
  108. /package/esm/deps/jsr.io/@std/http/{0.224.3 → 0.224.4}/_negotiation/language.js +0 -0
  109. /package/esm/deps/jsr.io/@std/http/{0.224.3 → 0.224.4}/_negotiation/media_type.js +0 -0
  110. /package/esm/deps/jsr.io/@std/http/{0.224.3 → 0.224.4}/negotiation.js +0 -0
  111. /package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/_constants.js +0 -0
  112. /package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/_shared.js +0 -0
  113. /package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/_test_comparator_set.js +0 -0
  114. /package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/can_parse.js +0 -0
  115. /package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/compare.js +0 -0
  116. /package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/constants.js +0 -0
  117. /package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/difference.js +0 -0
  118. /package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/equals.js +0 -0
  119. /package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/format.js +0 -0
  120. /package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/format_range.js +0 -0
  121. /package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/greater_or_equal.js +0 -0
  122. /package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/greater_than.js +0 -0
  123. /package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/greater_than_range.js +0 -0
  124. /package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/increment.js +0 -0
  125. /package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/is_range.js +0 -0
  126. /package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/is_semver.js +0 -0
  127. /package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/less_or_equal.js +0 -0
  128. /package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/less_than.js +0 -0
  129. /package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/less_than_range.js +0 -0
  130. /package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/max_satisfying.js +0 -0
  131. /package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/min_satisfying.js +0 -0
  132. /package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/not_equals.js +0 -0
  133. /package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/parse.js +0 -0
  134. /package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/parse_range.js +0 -0
  135. /package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/range_intersects.js +0 -0
  136. /package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/range_max.js +0 -0
  137. /package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/range_min.js +0 -0
  138. /package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/satisfies.js +0 -0
  139. /package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/test_range.js +0 -0
  140. /package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/try_parse.js +0 -0
  141. /package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/try_parse_range.js +0 -0
  142. /package/esm/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/types.js +0 -0
  143. /package/types/deps/jsr.io/@std/http/{0.224.3 → 0.224.4}/_negotiation/common.d.ts +0 -0
  144. /package/types/deps/jsr.io/@std/http/{0.224.3 → 0.224.4}/_negotiation/encoding.d.ts +0 -0
  145. /package/types/deps/jsr.io/@std/http/{0.224.3 → 0.224.4}/_negotiation/language.d.ts +0 -0
  146. /package/types/deps/jsr.io/@std/http/{0.224.3 → 0.224.4}/_negotiation/media_type.d.ts +0 -0
  147. /package/types/deps/jsr.io/@std/http/{0.224.3 → 0.224.4}/negotiation.d.ts +0 -0
  148. /package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/_constants.d.ts +0 -0
  149. /package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/_shared.d.ts +0 -0
  150. /package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/_test_comparator_set.d.ts +0 -0
  151. /package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/can_parse.d.ts +0 -0
  152. /package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/compare.d.ts +0 -0
  153. /package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/constants.d.ts +0 -0
  154. /package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/difference.d.ts +0 -0
  155. /package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/equals.d.ts +0 -0
  156. /package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/format.d.ts +0 -0
  157. /package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/format_range.d.ts +0 -0
  158. /package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/greater_or_equal.d.ts +0 -0
  159. /package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/greater_than.d.ts +0 -0
  160. /package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/greater_than_range.d.ts +0 -0
  161. /package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/increment.d.ts +0 -0
  162. /package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/is_range.d.ts +0 -0
  163. /package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/is_semver.d.ts +0 -0
  164. /package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/less_or_equal.d.ts +0 -0
  165. /package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/less_than.d.ts +0 -0
  166. /package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/less_than_range.d.ts +0 -0
  167. /package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/max_satisfying.d.ts +0 -0
  168. /package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/min_satisfying.d.ts +0 -0
  169. /package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/not_equals.d.ts +0 -0
  170. /package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/parse.d.ts +0 -0
  171. /package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/parse_range.d.ts +0 -0
  172. /package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/range_intersects.d.ts +0 -0
  173. /package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/range_max.d.ts +0 -0
  174. /package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/range_min.d.ts +0 -0
  175. /package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/satisfies.d.ts +0 -0
  176. /package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/test_range.d.ts +0 -0
  177. /package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/try_parse.d.ts +0 -0
  178. /package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/try_parse_range.d.ts +0 -0
  179. /package/types/deps/jsr.io/@std/semver/{0.224.2 → 0.224.3}/types.d.ts +0 -0
package/CHANGES.md CHANGED
@@ -18,7 +18,7 @@ To be released.
18
18
  - The `importSpki()` function now accepts Ed25519 keys.
19
19
  - The `exportJwk()` function now exports Ed25519 keys.
20
20
 
21
- - Now multiple key pairs can be registered for an actor.
21
+ - Now multiple key pairs can be registered for an actor. [[FEP-521a], [#55]]
22
22
 
23
23
  - Added `Context.getActorKeyPairs()` method.
24
24
  - Deprecated `Context.getActorKey()` method.
@@ -31,6 +31,45 @@ To be released.
31
31
  - Deprecated the third parameter of the `ActorDispatcher` callback type.
32
32
  Use `Context.getActorKeyPairs()` method instead.
33
33
 
34
+ - Added `Multikey` class to Activity Vocabulary API. [[FEP-521a], [#55]]
35
+
36
+ - Added `importMultibaseKey()` function.
37
+ - Added `exportMultibaseKey()` function.
38
+
39
+ - Added `assertionMethod` property to the `Actor` types in the Activity
40
+ Vocabulary API. [[FEP-521a], [#55]]
41
+
42
+ - Added `Application.getAssertionMethod()` method.
43
+ - Added `Application.getAssertionMethods()` method.
44
+ - `new Application()` constructor now accepts `assertionMethod` option.
45
+ - `new Application()` constructor now accepts `assertionMethods` option.
46
+ - `Application.clone()` method now accepts `assertionMethod` option.
47
+ - `Application.clone()` method now accepts `assertionMethods` option.
48
+ - Added `Group.getAssertionMethod()` method.
49
+ - Added `Group.getAssertionMethods()` method.
50
+ - `new Group()` constructor now accepts `assertionMethod` option.
51
+ - `new Group()` constructor now accepts `assertionMethods` option.
52
+ - `Group.clone()` method now accepts `assertionMethod` option.
53
+ - `Group.clone()` method now accepts `assertionMethods` option.
54
+ - Added `Organization.getAssertionMethod()` method.
55
+ - Added `Organization.getAssertionMethods()` method.
56
+ - `new Organization()` constructor now accepts `assertionMethod` option.
57
+ - `new Organization()` constructor now accepts `assertionMethods` option.
58
+ - `Organization.clone()` method now accepts `assertionMethod` option.
59
+ - `Organization.clone()` method now accepts `assertionMethods` option.
60
+ - Added `Person.getAssertionMethod()` method.
61
+ - Added `Person.getAssertionMethods()` method.
62
+ - `new Person()` constructor now accepts `assertionMethod` option.
63
+ - `new Person()` constructor now accepts `assertionMethods` option.
64
+ - `Person.clone()` method now accepts `assertionMethod` option.
65
+ - `Person.clone()` method now accepts `assertionMethods` option.
66
+ - Added `Service.getAssertionMethod()` method.
67
+ - Added `Service.getAssertionMethods()` method.
68
+ - `new Service()` constructor now accepts `assertionMethod` option.
69
+ - `new Service()` constructor now accepts `assertionMethods` option.
70
+ - `Service.clone()` method now accepts `assertionMethod` option.
71
+ - `Service.clone()` method now accepts `assertionMethods` option.
72
+
34
73
  - Deprecated `treatHttps` option in `FederationParameters` interface.
35
74
  Instead, use the [x-forwarded-fetch] library to recognize the
36
75
  `X-Forwarded-Host` and `X-Forwarded-Proto` headers.
@@ -43,6 +82,7 @@ To be released.
43
82
  `url`.
44
83
 
45
84
  [#55]: https://github.com/dahlia/fedify/issues/55
85
+ [FEP-521a]: https://codeberg.org/fediverse/fep/src/branch/main/fep/521a/fep-521a.md
46
86
  [x-forwarded-fetch]: https://github.com/dahlia/x-forwarded-fetch
47
87
 
48
88
 
@@ -0,0 +1,83 @@
1
+ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
2
+ // This module is browser compatible.
3
+ /**
4
+ * Utilities for
5
+ * {@link https://www.rfc-editor.org/rfc/rfc4648.html#section-5 | base64url}
6
+ * encoding and decoding.
7
+ *
8
+ * This module is browser compatible.
9
+ *
10
+ * @module
11
+ */
12
+ import * as base64 from "./base64.js";
13
+ /**
14
+ * Some variants allow or require omitting the padding '=' signs:
15
+ * https://en.wikipedia.org/wiki/Base64#The_URL_applications
16
+ *
17
+ * @param base64url
18
+ */
19
+ function addPaddingToBase64url(base64url) {
20
+ if (base64url.length % 4 === 2)
21
+ return base64url + "==";
22
+ if (base64url.length % 4 === 3)
23
+ return base64url + "=";
24
+ if (base64url.length % 4 === 1) {
25
+ throw new TypeError("Illegal base64url string!");
26
+ }
27
+ return base64url;
28
+ }
29
+ function convertBase64urlToBase64(b64url) {
30
+ if (!/^[-_A-Z0-9]*?={0,2}$/i.test(b64url)) {
31
+ // Contains characters not part of base64url spec.
32
+ throw new TypeError("Failed to decode base64url: invalid character");
33
+ }
34
+ return addPaddingToBase64url(b64url).replace(/\-/g, "+").replace(/_/g, "/");
35
+ }
36
+ function convertBase64ToBase64url(b64) {
37
+ return b64.endsWith("=")
38
+ ? b64.endsWith("==")
39
+ ? b64.replace(/\+/g, "-").replace(/\//g, "_").slice(0, -2)
40
+ : b64.replace(/\+/g, "-").replace(/\//g, "_").slice(0, -1)
41
+ : b64.replace(/\+/g, "-").replace(/\//g, "_");
42
+ }
43
+ /**
44
+ * Convert data into a base64url-encoded string.
45
+ *
46
+ * @see {@link https://www.rfc-editor.org/rfc/rfc4648.html#section-5}
47
+ *
48
+ * @param data The data to encode.
49
+ * @returns The base64url-encoded string.
50
+ *
51
+ * @example Usage
52
+ * ```ts
53
+ * import { encodeBase64Url } from "@std/encoding/base64url";
54
+ * import { assertEquals } from "@std/assert/assert-equals";
55
+ *
56
+ * assertEquals(encodeBase64Url("foobar"), "Zm9vYmFy");
57
+ * ```
58
+ */
59
+ export function encodeBase64Url(data) {
60
+ return convertBase64ToBase64url(base64.encodeBase64(data));
61
+ }
62
+ /**
63
+ * Decodes a given base64url-encoded string.
64
+ *
65
+ * @see {@link https://www.rfc-editor.org/rfc/rfc4648.html#section-5}
66
+ *
67
+ * @param b64url The base64url-encoded string to decode.
68
+ * @returns The decoded data.
69
+ *
70
+ * @example Usage
71
+ * ```ts
72
+ * import { decodeBase64Url } from "@std/encoding/base64url";
73
+ * import { assertEquals } from "@std/assert/assert-equals";
74
+ *
75
+ * assertEquals(
76
+ * decodeBase64Url("Zm9vYmFy"),
77
+ * new TextEncoder().encode("foobar")
78
+ * );
79
+ * ```
80
+ */
81
+ export function decodeBase64Url(b64url) {
82
+ return base64.decodeBase64(convertBase64urlToBase64(b64url));
83
+ }
@@ -269,7 +269,7 @@
269
269
  * If you want to know if a version satisfies or does not satisfy a range, use the
270
270
  * {@linkcode satisfies} function.
271
271
  *
272
- * This module is browser compatible.
272
+ *
273
273
  *
274
274
 
275
275
  *
@@ -1,6 +1,6 @@
1
1
  import * as dntShim from "../_dnt.shims.js";
2
2
  import { getLogger } from "@logtape/logtape";
3
- import { accepts } from "../deps/jsr.io/@std/http/0.224.3/negotiation.js";
3
+ import { accepts } from "../deps/jsr.io/@std/http/0.224.4/negotiation.js";
4
4
  import { verifyRequest } from "../sig/http.js";
5
5
  import { doesActorOwnKey } from "../sig/owner.js";
6
6
  import { Activity, Link, Object, OrderedCollection, OrderedCollectionPage, } from "../vocab/vocab.js";
@@ -5,7 +5,7 @@ import { exportJwk, importJwk, validateCryptoKey } from "../sig/key.js";
5
5
  import { getKeyOwner } from "../sig/owner.js";
6
6
  import { handleNodeInfo, handleNodeInfoJrd } from "../nodeinfo/handler.js";
7
7
  import { fetchDocumentLoader, getAuthenticatedDocumentLoader, kvCache, } from "../runtime/docloader.js";
8
- import { Activity, CryptographicKey } from "../vocab/mod.js";
8
+ import { Activity, CryptographicKey, Multikey, } from "../vocab/mod.js";
9
9
  import { handleWebFinger } from "../webfinger/handler.js";
10
10
  import { buildCollectionSynchronizationHeader } from "./collection.js";
11
11
  import { handleActor, handleCollection, handleInbox, handleObject, } from "./handler.js";
@@ -307,6 +307,18 @@ export class Federation {
307
307
  "URI. Set the property with Context.getInboxUri().");
308
308
  }
309
309
  }
310
+ if (callbacks.keyPairsDispatcher != null) {
311
+ if (actor.publicKeyId == null) {
312
+ logger.warn("You configured a key pairs dispatcher, but the actor does " +
313
+ "not have a publicKey property. Set the property with " +
314
+ "Context.getActorKeyPairs(handle).");
315
+ }
316
+ if (actor.assertionMethodId == null) {
317
+ logger.warn("You configured a key pairs dispatcher, but the actor does " +
318
+ "not have an assertionMethod property. Set the property " +
319
+ "with Context.getActorKeyPairs(handle).");
320
+ }
321
+ }
310
322
  return actor;
311
323
  },
312
324
  };
@@ -961,6 +973,11 @@ class ContextImpl {
961
973
  owner,
962
974
  publicKey: keyPair.publicKey,
963
975
  }),
976
+ multikey: new Multikey({
977
+ id: keyPair.keyId,
978
+ controller: owner,
979
+ publicKey: keyPair.publicKey,
980
+ }),
964
981
  };
965
982
  result.push(newPair);
966
983
  }
@@ -1,4 +1,4 @@
1
- import { format } from "../deps/jsr.io/@std/semver/0.224.2/mod.js";
1
+ import { format } from "../deps/jsr.io/@std/semver/0.224.3/mod.js";
2
2
  /**
3
3
  * Converts a {@link NodeInfo} object to a JSON value.
4
4
  * @param nodeInfo The {@link NodeInfo} object to convert.
@@ -1,5 +1,12 @@
1
1
  import * as dntShim from "../_dnt.shims.js";
2
+ import { createPublicKey } from "node:crypto";
3
+ import { concat } from "../deps/jsr.io/@std/bytes/0.224.0/concat.js";
2
4
  import { decodeBase64, encodeBase64 } from "../deps/jsr.io/@std/encoding/0.224.3/base64.js";
5
+ import { decodeBase64Url } from "../deps/jsr.io/@std/encoding/0.224.3/base64url.js";
6
+ import { decodeHex } from "../deps/jsr.io/@std/encoding/0.224.3/hex.js";
7
+ import { Integer, Sequence } from "asn1js";
8
+ import { decode, encode } from "multibase";
9
+ import { addPrefix, getCodeFromData, rmPrefix } from "multicodec";
3
10
  import { PublicKeyInfo } from "pkijs";
4
11
  import { validateCryptoKey } from "../sig/key.js";
5
12
  const algorithms = {
@@ -44,3 +51,78 @@ export async function exportSpki(key) {
44
51
  pem = (pem.match(/.{1,64}/g) || []).join("\n");
45
52
  return `-----BEGIN PUBLIC KEY-----\n${pem}\n-----END PUBLIC KEY-----\n`;
46
53
  }
54
+ /**
55
+ * Imports a [Multibase]-encoded public key.
56
+ *
57
+ * [Multibase]: https://www.w3.org/TR/vc-data-integrity/#multibase-0
58
+ * @param key The Multibase-encoded public key.
59
+ * @returns The imported public key.
60
+ * @throws {TypeError} If the key is invalid or unsupported.
61
+ * @since 0.10.0
62
+ */
63
+ export async function importMultibaseKey(key) {
64
+ const decoded = decode(key);
65
+ const code = getCodeFromData(decoded);
66
+ const content = rmPrefix(decoded);
67
+ if (code === 0x1205) { // rsa-pub
68
+ const keyObject = createPublicKey({
69
+ // deno-lint-ignore no-explicit-any
70
+ key: content,
71
+ format: "der",
72
+ type: "pkcs1",
73
+ });
74
+ const spki = keyObject.export({ type: "spki", format: "der" }).buffer;
75
+ return await dntShim.crypto.subtle.importKey("spki", spki, { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }, true, ["verify"]);
76
+ }
77
+ else if (code === 0xed) { // ed25519-pub
78
+ return await dntShim.crypto.subtle.importKey("raw", content, "Ed25519", true, ["verify"]);
79
+ }
80
+ else {
81
+ throw new TypeError("Unsupported key type: " + code);
82
+ }
83
+ }
84
+ /**
85
+ * Exports a public key in [Multibase] format.
86
+ *
87
+ * [Multibase]: https://www.w3.org/TR/vc-data-integrity/#multibase-0
88
+ * @param key The public key to export.
89
+ * @returns The exported public key in Multibase format.
90
+ * @throws {TypeError} If the key is invalid or unsupported.
91
+ * @since 0.10.0
92
+ */
93
+ export async function exportMultibaseKey(key) {
94
+ let content;
95
+ let code;
96
+ if (key.algorithm.name === "Ed25519") {
97
+ content = await dntShim.crypto.subtle.exportKey("raw", key);
98
+ code = 0xed; // ed25519-pub
99
+ }
100
+ else if (key.algorithm.name === "RSASSA-PKCS1-v1_5" &&
101
+ key.algorithm.hash.name ===
102
+ "SHA-256") {
103
+ const jwk = await dntShim.crypto.subtle.exportKey("jwk", key);
104
+ const n = concat([new Uint8Array([0]), decodeBase64Url(jwk.n)]);
105
+ const sequence = new Sequence({
106
+ value: [
107
+ new Integer({
108
+ isHexOnly: true,
109
+ valueHex: n,
110
+ }),
111
+ new Integer({
112
+ isHexOnly: true,
113
+ valueHex: decodeBase64Url(jwk.e),
114
+ }),
115
+ ],
116
+ });
117
+ content = sequence.toBER(false);
118
+ code = 0x1205; // rsa-pub
119
+ }
120
+ else {
121
+ throw new TypeError("Unsupported key type: " + JSON.stringify(key.algorithm));
122
+ }
123
+ const codeHex = code.toString(16);
124
+ const codeBytes = decodeHex(codeHex.length % 2 < 1 ? codeHex : "0" + codeHex);
125
+ const prefixed = addPrefix(codeBytes, new Uint8Array(content));
126
+ const encoded = encode("base58btc", prefixed);
127
+ return new TextDecoder().decode(encoded);
128
+ }
@@ -0,0 +1,35 @@
1
+ {
2
+ "@context": {
3
+ "id": "@id",
4
+ "type": "@type",
5
+ "@protected": true,
6
+ "Multikey": {
7
+ "@id": "https://w3id.org/security#Multikey",
8
+ "@context": {
9
+ "@protected": true,
10
+ "id": "@id",
11
+ "type": "@type",
12
+ "controller": {
13
+ "@id": "https://w3id.org/security#controller",
14
+ "@type": "@id"
15
+ },
16
+ "revoked": {
17
+ "@id": "https://w3id.org/security#revoked",
18
+ "@type": "http://www.w3.org/2001/XMLSchema#dateTime"
19
+ },
20
+ "expires": {
21
+ "@id": "https://w3id.org/security#expiration",
22
+ "@type": "http://www.w3.org/2001/XMLSchema#dateTime"
23
+ },
24
+ "publicKeyMultibase": {
25
+ "@id": "https://w3id.org/security#publicKeyMultibase",
26
+ "@type": "https://w3id.org/security#multibase"
27
+ },
28
+ "secretKeyMultibase": {
29
+ "@id": "https://w3id.org/security#secretKeyMultibase",
30
+ "@type": "https://w3id.org/security#multibase"
31
+ }
32
+ }
33
+ }
34
+ }
35
+ }
@@ -0,0 +1,58 @@
1
+ {
2
+ "@context": {
3
+ "@protected": true,
4
+ "id": "@id",
5
+ "type": "@type",
6
+
7
+ "alsoKnownAs": {
8
+ "@id": "https://www.w3.org/ns/activitystreams#alsoKnownAs",
9
+ "@type": "@id"
10
+ },
11
+ "assertionMethod": {
12
+ "@id": "https://w3id.org/security#assertionMethod",
13
+ "@type": "@id",
14
+ "@container": "@set"
15
+ },
16
+ "authentication": {
17
+ "@id": "https://w3id.org/security#authenticationMethod",
18
+ "@type": "@id",
19
+ "@container": "@set"
20
+ },
21
+ "capabilityDelegation": {
22
+ "@id": "https://w3id.org/security#capabilityDelegationMethod",
23
+ "@type": "@id",
24
+ "@container": "@set"
25
+ },
26
+ "capabilityInvocation": {
27
+ "@id": "https://w3id.org/security#capabilityInvocationMethod",
28
+ "@type": "@id",
29
+ "@container": "@set"
30
+ },
31
+ "controller": {
32
+ "@id": "https://w3id.org/security#controller",
33
+ "@type": "@id"
34
+ },
35
+ "keyAgreement": {
36
+ "@id": "https://w3id.org/security#keyAgreementMethod",
37
+ "@type": "@id",
38
+ "@container": "@set"
39
+ },
40
+ "service": {
41
+ "@id": "https://www.w3.org/ns/did#service",
42
+ "@type": "@id",
43
+ "@context": {
44
+ "@protected": true,
45
+ "id": "@id",
46
+ "type": "@type",
47
+ "serviceEndpoint": {
48
+ "@id": "https://www.w3.org/ns/did#serviceEndpoint",
49
+ "@type": "@id"
50
+ }
51
+ }
52
+ },
53
+ "verificationMethod": {
54
+ "@id": "https://w3id.org/security#verificationMethod",
55
+ "@type": "@id"
56
+ }
57
+ }
58
+ }
@@ -7,6 +7,8 @@ description: Describes a software application.
7
7
  defaultContext:
8
8
  - "https://www.w3.org/ns/activitystreams"
9
9
  - "https://w3id.org/security/v1"
10
+ - "https://www.w3.org/ns/did/v1"
11
+ - "https://w3id.org/security/multikey/v1"
10
12
  - manuallyApprovesFollowers: "as:manuallyApprovesFollowers"
11
13
  toot: "http://joinmastodon.org/ns#"
12
14
  discoverable: "toot:discoverable"
@@ -38,6 +40,18 @@ properties:
38
40
  range:
39
41
  - "https://w3id.org/security#Key"
40
42
 
43
+ - pluralName: assertionMethods
44
+ singularName: assertionMethod
45
+ singularAccessor: true
46
+ uri: "https://w3id.org/security#assertionMethod"
47
+ description: |
48
+ Represents this actor's public keys. It serves as equivalent to
49
+ the `publicKeys` property, but is used for [FEP-521a] compliance.
50
+
51
+ [FEP-521a]: https://codeberg.org/fediverse/fep/src/branch/main/fep/521a/fep-521a.md
52
+ range:
53
+ - "https://w3id.org/security#Multikey"
54
+
41
55
  - singularName: manuallyApprovesFollowers
42
56
  functional: true
43
57
  uri: "https://www.w3.org/ns/activitystreams#manuallyApprovesFollowers"
@@ -67,7 +81,7 @@ properties:
67
81
  followers, and a specific actor who also follows the recipient actor,
68
82
  and the server has failed to de-duplicate the recipients list.
69
83
  Such deduplication MUST be performed by comparing the `id` of the activities
70
- and dropping any activities already seen.
84
+ and dropping any activities already seen.
71
85
  range:
72
86
  - "https://www.w3.org/ns/activitystreams#OrderedCollection"
73
87
 
@@ -7,6 +7,8 @@ description: Represents a formal or informal collective of Actors.
7
7
  defaultContext:
8
8
  - "https://www.w3.org/ns/activitystreams"
9
9
  - "https://w3id.org/security/v1"
10
+ - "https://www.w3.org/ns/did/v1"
11
+ - "https://w3id.org/security/multikey/v1"
10
12
  - manuallyApprovesFollowers: "as:manuallyApprovesFollowers"
11
13
  toot: "http://joinmastodon.org/ns#"
12
14
  discoverable: "toot:discoverable"
@@ -38,6 +40,18 @@ properties:
38
40
  range:
39
41
  - "https://w3id.org/security#Key"
40
42
 
43
+ - pluralName: assertionMethods
44
+ singularName: assertionMethod
45
+ singularAccessor: true
46
+ uri: "https://w3id.org/security#assertionMethod"
47
+ description: |
48
+ Represents this actor's public keys. It serves as equivalent to
49
+ the `publicKeys` property, but is used for [FEP-521a] compliance.
50
+
51
+ [FEP-521a]: https://codeberg.org/fediverse/fep/src/branch/main/fep/521a/fep-521a.md
52
+ range:
53
+ - "https://w3id.org/security#Multikey"
54
+
41
55
  - singularName: manuallyApprovesFollowers
42
56
  functional: true
43
57
  uri: "https://www.w3.org/ns/activitystreams#manuallyApprovesFollowers"
@@ -67,7 +81,7 @@ properties:
67
81
  followers, and a specific actor who also follows the recipient actor,
68
82
  and the server has failed to de-duplicate the recipients list.
69
83
  Such deduplication MUST be performed by comparing the `id` of the activities
70
- and dropping any activities already seen.
84
+ and dropping any activities already seen.
71
85
  range:
72
86
  - "https://www.w3.org/ns/activitystreams#OrderedCollection"
73
87
 
@@ -0,0 +1,33 @@
1
+ $schema: ../codegen/schema.yaml
2
+ name: Multikey
3
+ uri: "https://w3id.org/security#Multikey"
4
+ entity: true
5
+ description: |
6
+ Represents a key owned by an actor according to [FEP-521a: Representing
7
+ actor's public keys.][1]
8
+
9
+ [1]: https://codeberg.org/fediverse/fep/src/branch/main/fep/521a/fep-521a.md
10
+ defaultContext: "https://w3id.org/security/multikey/v1"
11
+
12
+ properties:
13
+ - singularName: controller
14
+ functional: true
15
+ uri: "https://w3id.org/security#controller"
16
+ description: An actor who owns this key.
17
+ range:
18
+ - "https://www.w3.org/ns/activitystreams#Application"
19
+ - "https://www.w3.org/ns/activitystreams#Group"
20
+ - "https://www.w3.org/ns/activitystreams#Organization"
21
+ - "https://www.w3.org/ns/activitystreams#Person"
22
+ - "https://www.w3.org/ns/activitystreams#Service"
23
+
24
+ - singularName: publicKey
25
+ functional: true
26
+ uri: "https://w3id.org/security#publicKeyMultibase"
27
+ description: |
28
+ A [Multibase]-encoded value of a [Multicodec] prefix and the key.
29
+
30
+ [Multibase]: https://www.w3.org/TR/vc-data-integrity/#multibase-0
31
+ [Multicodec]: https://github.com/multiformats/multicodec/
32
+ range:
33
+ - "fedify:multibaseKey"
@@ -7,6 +7,8 @@ description: Represents an organization.
7
7
  defaultContext:
8
8
  - "https://www.w3.org/ns/activitystreams"
9
9
  - "https://w3id.org/security/v1"
10
+ - "https://www.w3.org/ns/did/v1"
11
+ - "https://w3id.org/security/multikey/v1"
10
12
  - manuallyApprovesFollowers: "as:manuallyApprovesFollowers"
11
13
  toot: "http://joinmastodon.org/ns#"
12
14
  discoverable: "toot:discoverable"
@@ -38,6 +40,18 @@ properties:
38
40
  range:
39
41
  - "https://w3id.org/security#Key"
40
42
 
43
+ - pluralName: assertionMethods
44
+ singularName: assertionMethod
45
+ singularAccessor: true
46
+ uri: "https://w3id.org/security#assertionMethod"
47
+ description: |
48
+ Represents this actor's public keys. It serves as equivalent to
49
+ the `publicKeys` property, but is used for [FEP-521a] compliance.
50
+
51
+ [FEP-521a]: https://codeberg.org/fediverse/fep/src/branch/main/fep/521a/fep-521a.md
52
+ range:
53
+ - "https://w3id.org/security#Multikey"
54
+
41
55
  - singularName: manuallyApprovesFollowers
42
56
  functional: true
43
57
  uri: "https://www.w3.org/ns/activitystreams#manuallyApprovesFollowers"
@@ -67,7 +81,7 @@ properties:
67
81
  followers, and a specific actor who also follows the recipient actor,
68
82
  and the server has failed to de-duplicate the recipients list.
69
83
  Such deduplication MUST be performed by comparing the `id` of the activities
70
- and dropping any activities already seen.
84
+ and dropping any activities already seen.
71
85
  range:
72
86
  - "https://www.w3.org/ns/activitystreams#OrderedCollection"
73
87
 
@@ -7,6 +7,8 @@ description: Represents an individual person.
7
7
  defaultContext:
8
8
  - "https://www.w3.org/ns/activitystreams"
9
9
  - "https://w3id.org/security/v1"
10
+ - "https://www.w3.org/ns/did/v1"
11
+ - "https://w3id.org/security/multikey/v1"
10
12
  - manuallyApprovesFollowers: "as:manuallyApprovesFollowers"
11
13
  toot: "http://joinmastodon.org/ns#"
12
14
  discoverable: "toot:discoverable"
@@ -38,6 +40,18 @@ properties:
38
40
  range:
39
41
  - "https://w3id.org/security#Key"
40
42
 
43
+ - pluralName: assertionMethods
44
+ singularName: assertionMethod
45
+ singularAccessor: true
46
+ uri: "https://w3id.org/security#assertionMethod"
47
+ description: |
48
+ Represents this actor's public keys. It serves as equivalent to
49
+ the `publicKeys` property, but is used for [FEP-521a] compliance.
50
+
51
+ [FEP-521a]: https://codeberg.org/fediverse/fep/src/branch/main/fep/521a/fep-521a.md
52
+ range:
53
+ - "https://w3id.org/security#Multikey"
54
+
41
55
  - singularName: manuallyApprovesFollowers
42
56
  functional: true
43
57
  uri: "https://www.w3.org/ns/activitystreams#manuallyApprovesFollowers"
@@ -67,7 +81,7 @@ properties:
67
81
  followers, and a specific actor who also follows the recipient actor,
68
82
  and the server has failed to de-duplicate the recipients list.
69
83
  Such deduplication MUST be performed by comparing the `id` of the activities
70
- and dropping any activities already seen.
84
+ and dropping any activities already seen.
71
85
  range:
72
86
  - "https://www.w3.org/ns/activitystreams#OrderedCollection"
73
87
 
@@ -7,6 +7,8 @@ description: Represents a service of any kind.
7
7
  defaultContext:
8
8
  - "https://www.w3.org/ns/activitystreams"
9
9
  - "https://w3id.org/security/v1"
10
+ - "https://www.w3.org/ns/did/v1"
11
+ - "https://w3id.org/security/multikey/v1"
10
12
  - manuallyApprovesFollowers: "as:manuallyApprovesFollowers"
11
13
  toot: "http://joinmastodon.org/ns#"
12
14
  discoverable: "toot:discoverable"
@@ -38,6 +40,18 @@ properties:
38
40
  range:
39
41
  - "https://w3id.org/security#Key"
40
42
 
43
+ - pluralName: assertionMethods
44
+ singularName: assertionMethod
45
+ singularAccessor: true
46
+ uri: "https://w3id.org/security#assertionMethod"
47
+ description: |
48
+ Represents this actor's public keys. It serves as equivalent to
49
+ the `publicKeys` property, but is used for [FEP-521a] compliance.
50
+
51
+ [FEP-521a]: https://codeberg.org/fediverse/fep/src/branch/main/fep/521a/fep-521a.md
52
+ range:
53
+ - "https://w3id.org/security#Multikey"
54
+
41
55
  - singularName: manuallyApprovesFollowers
42
56
  functional: true
43
57
  uri: "https://www.w3.org/ns/activitystreams#manuallyApprovesFollowers"
@@ -67,7 +81,7 @@ properties:
67
81
  followers, and a specific actor who also follows the recipient actor,
68
82
  and the server has failed to de-duplicate the recipients list.
69
83
  Such deduplication MUST be performed by comparing the `id` of the activities
70
- and dropping any activities already seen.
84
+ and dropping any activities already seen.
71
85
  range:
72
86
  - "https://www.w3.org/ns/activitystreams#OrderedCollection"
73
87