@fedify/vocab-tools 2.4.0-dev.2056 → 2.4.0-dev.2065
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/deno.json +1 -1
- package/dist/mod.cjs +181 -58
- package/dist/mod.js +181 -58
- package/package.json +1 -1
- package/src/__snapshots__/class.test.ts.deno.snap +21022 -7593
- package/src/__snapshots__/class.test.ts.node.snap +21022 -7593
- package/src/__snapshots__/class.test.ts.snap +21022 -7593
- package/src/class.ts +13 -0
- package/src/constructor.ts +1 -0
- package/src/property.ts +172 -58
package/deno.json
CHANGED
package/dist/mod.cjs
CHANGED
|
@@ -8,7 +8,7 @@ let yaml = require("yaml");
|
|
|
8
8
|
let es_toolkit = require("es-toolkit");
|
|
9
9
|
//#region deno.json
|
|
10
10
|
var name = "@fedify/vocab-tools";
|
|
11
|
-
var version = "2.4.0-dev.
|
|
11
|
+
var version = "2.4.0-dev.2065+b09fdd33";
|
|
12
12
|
//#endregion
|
|
13
13
|
//#region src/type.ts
|
|
14
14
|
const HEURISTICS_CONTEXTS = [
|
|
@@ -1425,6 +1425,7 @@ async function* generateCloner(typeUri, types) {
|
|
|
1425
1425
|
{ id: values.id ?? this.id },
|
|
1426
1426
|
options
|
|
1427
1427
|
);
|
|
1428
|
+
copyPortableProvenance(this, clone);
|
|
1428
1429
|
`;
|
|
1429
1430
|
else yield `const clone = super.clone(values, options) as unknown as ${type.name};`;
|
|
1430
1431
|
for (const property of type.properties) {
|
|
@@ -1672,14 +1673,27 @@ async function* generateProperty(type, property, types, moduleVarNames) {
|
|
|
1672
1673
|
${JSON.stringify(version)},
|
|
1673
1674
|
);
|
|
1674
1675
|
return await tracer.startActiveSpan("activitypub.lookup_object", async (span) => {
|
|
1675
|
-
|
|
1676
|
+
const dereferencePortable = async (
|
|
1677
|
+
portableUrl: URL,
|
|
1678
|
+
extra: {
|
|
1679
|
+
inferredGateways?: readonly URL[];
|
|
1680
|
+
response?: RemoteDocument;
|
|
1681
|
+
contextLoader?: DocumentLoader;
|
|
1682
|
+
} = {},
|
|
1683
|
+
) => {
|
|
1676
1684
|
try {
|
|
1677
|
-
const obj = await dereferencePortableIri(
|
|
1685
|
+
const obj = await dereferencePortableIri(portableUrl, {
|
|
1678
1686
|
documentLoader,
|
|
1679
|
-
contextLoader,
|
|
1687
|
+
contextLoader: extra.contextLoader ?? contextLoader,
|
|
1680
1688
|
tracerProvider,
|
|
1681
1689
|
gateways: options.gateways,
|
|
1690
|
+
inferredGateways: extra.inferredGateways,
|
|
1691
|
+
response: extra.response,
|
|
1682
1692
|
verifyPortableObject: options.verifyPortableObject,
|
|
1693
|
+
referrer: {
|
|
1694
|
+
object: this,
|
|
1695
|
+
property: ${JSON.stringify(property.uri)},
|
|
1696
|
+
},
|
|
1683
1697
|
suppressError: options.suppressError,
|
|
1684
1698
|
crossOrigin: options.crossOrigin,
|
|
1685
1699
|
span,
|
|
@@ -1692,7 +1706,10 @@ async function* generateProperty(type, property, types, moduleVarNames) {
|
|
|
1692
1706
|
}),
|
|
1693
1707
|
});
|
|
1694
1708
|
if (obj != null) {
|
|
1695
|
-
span.setAttribute(
|
|
1709
|
+
span.setAttribute(
|
|
1710
|
+
"activitypub.object.id",
|
|
1711
|
+
(obj.id ?? portableUrl).href,
|
|
1712
|
+
);
|
|
1696
1713
|
span.setAttribute(
|
|
1697
1714
|
"activitypub.object.type",
|
|
1698
1715
|
// @ts-ignore: obj.constructor always has a typeId.
|
|
@@ -1709,8 +1726,21 @@ async function* generateProperty(type, property, types, moduleVarNames) {
|
|
|
1709
1726
|
} finally {
|
|
1710
1727
|
span.end();
|
|
1711
1728
|
}
|
|
1712
|
-
}
|
|
1729
|
+
};
|
|
1730
|
+
if (isPortableIri(url)) return await dereferencePortable(url);
|
|
1713
1731
|
const lookupUrl = formatIri(url);
|
|
1732
|
+
const portableMode = isPortableMode(this, options);
|
|
1733
|
+
if (portableMode) {
|
|
1734
|
+
const compatible = parseCompatibleEf61Reference(url);
|
|
1735
|
+
if (compatible === null) {
|
|
1736
|
+
span.end();
|
|
1737
|
+
return rejectMalformedCompatibleReference(lookupUrl, options);
|
|
1738
|
+
} else if (compatible != null) {
|
|
1739
|
+
return await dereferencePortable(compatible.id, {
|
|
1740
|
+
inferredGateways: [compatible.gateway],
|
|
1741
|
+
});
|
|
1742
|
+
}
|
|
1743
|
+
}
|
|
1714
1744
|
let fetchResult: RemoteDocument;
|
|
1715
1745
|
try {
|
|
1716
1746
|
fetchResult = await documentLoader(lookupUrl);
|
|
@@ -1730,52 +1760,90 @@ async function* generateProperty(type, property, types, moduleVarNames) {
|
|
|
1730
1760
|
throw error;
|
|
1731
1761
|
}
|
|
1732
1762
|
const { document, documentUrl } = fetchResult;
|
|
1733
|
-
|
|
1763
|
+
// In portable mode, the document may turn out to be a portable object,
|
|
1764
|
+
// which has to be verified with the same context documents:
|
|
1765
|
+
const snapshot = portableMode
|
|
1766
|
+
? createSnapshotContextLoader(contextLoader)
|
|
1767
|
+
: null;
|
|
1734
1768
|
try {
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1769
|
+
let claim: PortableResponseClaim | null | undefined;
|
|
1770
|
+
try {
|
|
1771
|
+
const baseUrl = parseIri(documentUrl);
|
|
1772
|
+
const obj = await this.#${property.singularName}_fromJsonLd(
|
|
1773
|
+
document,
|
|
1774
|
+
{
|
|
1775
|
+
documentLoader,
|
|
1776
|
+
contextLoader: snapshot?.loader ?? contextLoader,
|
|
1777
|
+
tracerProvider,
|
|
1778
|
+
baseUrl,
|
|
1779
|
+
}
|
|
1780
|
+
);
|
|
1781
|
+
if (snapshot == null) {
|
|
1782
|
+
markUnverifiedPortableClaim(obj, url, documentUrl);
|
|
1783
|
+
} else {
|
|
1784
|
+
claim = getPortableResponseClaim(documentUrl, obj.id);
|
|
1785
|
+
}
|
|
1786
|
+
if (claim === undefined) {
|
|
1787
|
+
if (
|
|
1788
|
+
obj?.id != null &&
|
|
1789
|
+
!isTrustedIriOrigin(options, obj.id, baseUrl)
|
|
1790
|
+
) {
|
|
1791
|
+
if (options.crossOrigin === "throw") {
|
|
1792
|
+
throw new Error(
|
|
1793
|
+
"The object's @id (" + obj.id.href + ") has a different origin " +
|
|
1794
|
+
"than the document URL (" + baseUrl.href + "); refusing to return " +
|
|
1795
|
+
"the object. If you want to bypass this check and are aware of" +
|
|
1796
|
+
'the security implications, set the crossOrigin option to "trust".'
|
|
1797
|
+
);
|
|
1798
|
+
}
|
|
1799
|
+
getLogger(["fedify", "vocab"]).warn(
|
|
1800
|
+
"The object's @id ({objectId}) has a different origin than the document " +
|
|
1801
|
+
"URL ({documentUrl}); refusing to return the object. If you want to " +
|
|
1802
|
+
"bypass this check and are aware of the security implications, " +
|
|
1803
|
+
'set the crossOrigin option to "trust".',
|
|
1804
|
+
{ ...fetchResult, objectId: obj.id.href },
|
|
1805
|
+
);
|
|
1806
|
+
span.end();
|
|
1807
|
+
return null;
|
|
1808
|
+
}
|
|
1809
|
+
span.setAttribute("activitypub.object.id", (obj.id ?? url).href);
|
|
1810
|
+
span.setAttribute(
|
|
1811
|
+
"activitypub.object.type",
|
|
1812
|
+
// @ts-ignore: obj.constructor always has a typeId.
|
|
1813
|
+
obj.constructor.typeId.href
|
|
1746
1814
|
);
|
|
1815
|
+
span.end();
|
|
1816
|
+
return obj;
|
|
1747
1817
|
}
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
"
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1818
|
+
} catch (e) {
|
|
1819
|
+
if (options.suppressError) {
|
|
1820
|
+
getLogger(["fedify", "vocab"]).error(
|
|
1821
|
+
"Failed to parse {url}: {error}",
|
|
1822
|
+
{ error: e, url: lookupUrl }
|
|
1823
|
+
);
|
|
1824
|
+
span.end();
|
|
1825
|
+
return null;
|
|
1826
|
+
}
|
|
1827
|
+
span.setStatus({
|
|
1828
|
+
code: SpanStatusCode.ERROR,
|
|
1829
|
+
message: String(e),
|
|
1830
|
+
});
|
|
1831
|
+
span.end();
|
|
1832
|
+
throw e;
|
|
1756
1833
|
}
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
);
|
|
1763
|
-
return obj;
|
|
1764
|
-
} catch (e) {
|
|
1765
|
-
if (options.suppressError) {
|
|
1766
|
-
getLogger(["fedify", "vocab"]).error(
|
|
1767
|
-
"Failed to parse {url}: {error}",
|
|
1768
|
-
{ error: e, url: lookupUrl }
|
|
1769
|
-
);
|
|
1770
|
-
return null;
|
|
1834
|
+
// The document stands for a portable object, so it is verified as
|
|
1835
|
+
// one instead of being trusted because of where it came from:
|
|
1836
|
+
if (claim === null) {
|
|
1837
|
+
span.end();
|
|
1838
|
+
return rejectMalformedCompatibleReference(documentUrl, options);
|
|
1771
1839
|
}
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1840
|
+
return await dereferencePortable(claim.id, {
|
|
1841
|
+
inferredGateways: claim.inferredGateways,
|
|
1842
|
+
response: fetchResult,
|
|
1843
|
+
contextLoader: snapshot?.loader,
|
|
1775
1844
|
});
|
|
1776
|
-
throw e;
|
|
1777
1845
|
} finally {
|
|
1778
|
-
|
|
1846
|
+
snapshot?.release();
|
|
1779
1847
|
}
|
|
1780
1848
|
});
|
|
1781
1849
|
}
|
|
@@ -1888,18 +1956,31 @@ async function* generateProperty(type, property, types, moduleVarNames) {
|
|
|
1888
1956
|
if (this.${await getFieldName(property.uri)}.length < 1) return null;
|
|
1889
1957
|
let v = this.${await getFieldName(property.uri)}[0];
|
|
1890
1958
|
if (!(v instanceof URL) &&
|
|
1891
|
-
v.id != null &&
|
|
1892
|
-
!isTrustedIriOrigin(options, v.id, ${trustOwner}) &&
|
|
1893
1959
|
!this.${await getFieldName(property.uri, "#_trust")}.has(0)) {
|
|
1894
|
-
|
|
1960
|
+
if (v.id == null) {
|
|
1961
|
+
if (isUnsecuredPortableObject(this)) {
|
|
1962
|
+
warnUnverifiableEmbeddedObject(this, ${JSON.stringify(property.uri)});
|
|
1963
|
+
return null;
|
|
1964
|
+
}
|
|
1965
|
+
} else if (
|
|
1966
|
+
!isTrustedIriOrigin(options, v.id, ${trustOwner}) ||
|
|
1967
|
+
isUnsecuredPortableObject(this) ||
|
|
1968
|
+
mustDereferencePortableObject(this, ${trustOwner}, v.id, options)
|
|
1969
|
+
) {
|
|
1970
|
+
v = v.id;
|
|
1971
|
+
}
|
|
1895
1972
|
}
|
|
1896
1973
|
if (v instanceof URL) {
|
|
1897
1974
|
const fetched =
|
|
1898
1975
|
await this.#fetch${(0, es_toolkit.pascalCase)(property.singularName)}(v, options);
|
|
1899
1976
|
if (fetched == null) return null;
|
|
1977
|
+
// Not cached, so that it is verified when the portable object
|
|
1978
|
+
// policy applies later:
|
|
1979
|
+
if (isUnverifiedPortableClaim(fetched)) return fetched;
|
|
1900
1980
|
this.${await getFieldName(property.uri)}[0] = fetched;
|
|
1901
1981
|
this.${await getFieldName(property.uri, "#_trust")}.add(0);
|
|
1902
1982
|
this._cachedJsonLd = undefined;
|
|
1983
|
+
recordPortableReferrer(this, fetched, ${JSON.stringify(property.uri)});
|
|
1903
1984
|
return fetched;
|
|
1904
1985
|
}
|
|
1905
1986
|
`;
|
|
@@ -1929,12 +2010,16 @@ async function* generateProperty(type, property, types, moduleVarNames) {
|
|
|
1929
2010
|
}
|
|
1930
2011
|
yield `
|
|
1931
2012
|
if (v?.id != null &&
|
|
1932
|
-
${type.trustEmbeddedObjects === false ? "" : "this.id != null && "}!isTrustedIriOrigin(options, v.id, ${trustOwner})
|
|
2013
|
+
((${type.trustEmbeddedObjects === false ? "" : "this.id != null && "}!isTrustedIriOrigin(options, v.id, ${trustOwner})) ||
|
|
2014
|
+
isUnsecuredPortableObject(this) ||
|
|
2015
|
+
mustDereferencePortableObject(
|
|
2016
|
+
this, ${trustOwner}, v.id, options,
|
|
2017
|
+
)) &&
|
|
1933
2018
|
!this.${await getFieldName(property.uri, "#_trust")}.has(0)) {
|
|
1934
2019
|
if (options.crossOrigin === "throw") {
|
|
1935
2020
|
throw new Error(
|
|
1936
2021
|
"The property object's @id (" + v.id.href + ") has a different " +
|
|
1937
|
-
"origin than the property owner's @id (" + ${type.trustEmbeddedObjects === false ? "\"untrusted metadata\"" : "this.id
|
|
2022
|
+
"origin than the property owner's @id (" + ${type.trustEmbeddedObjects === false ? "\"untrusted metadata\"" : "(this.id?.href ?? null)"} + "); " +
|
|
1938
2023
|
"refusing to return the object. If you want to bypass this " +
|
|
1939
2024
|
"check and are aware of the security implications, set the " +
|
|
1940
2025
|
'crossOrigin option to "trust".'
|
|
@@ -1946,10 +2031,11 @@ async function* generateProperty(type, property, types, moduleVarNames) {
|
|
|
1946
2031
|
"return the object. If you want to bypass this check and are " +
|
|
1947
2032
|
"aware of the security implications, set the crossOrigin option " +
|
|
1948
2033
|
'to "trust".',
|
|
1949
|
-
{ objectId: v.id.href, parentObjectId: ${type.trustEmbeddedObjects === false ? "\"untrusted metadata\"" : "this.id
|
|
2034
|
+
{ objectId: v.id.href, parentObjectId: ${type.trustEmbeddedObjects === false ? "\"untrusted metadata\"" : "(this.id?.href ?? null)"} },
|
|
1950
2035
|
);
|
|
1951
2036
|
return null;
|
|
1952
2037
|
}
|
|
2038
|
+
recordPortableReferrer(this, v, ${JSON.stringify(property.uri)});
|
|
1953
2039
|
return v;
|
|
1954
2040
|
}
|
|
1955
2041
|
`;
|
|
@@ -1996,18 +2082,34 @@ async function* generateProperty(type, property, types, moduleVarNames) {
|
|
|
1996
2082
|
for (let i = 0; i < vs.length; i++) {
|
|
1997
2083
|
let v = vs[i];
|
|
1998
2084
|
if (!(v instanceof URL) &&
|
|
1999
|
-
v.id != null &&
|
|
2000
|
-
!isTrustedIriOrigin(options, v.id, ${trustOwner}) &&
|
|
2001
2085
|
!this.${await getFieldName(property.uri, "#_trust")}.has(i)) {
|
|
2002
|
-
|
|
2086
|
+
if (v.id == null) {
|
|
2087
|
+
if (isUnsecuredPortableObject(this)) {
|
|
2088
|
+
warnUnverifiableEmbeddedObject(this, ${JSON.stringify(property.uri)});
|
|
2089
|
+
continue;
|
|
2090
|
+
}
|
|
2091
|
+
} else if (
|
|
2092
|
+
!isTrustedIriOrigin(options, v.id, ${trustOwner}) ||
|
|
2093
|
+
isUnsecuredPortableObject(this) ||
|
|
2094
|
+
mustDereferencePortableObject(this, ${trustOwner}, v.id, options)
|
|
2095
|
+
) {
|
|
2096
|
+
v = v.id;
|
|
2097
|
+
}
|
|
2003
2098
|
}
|
|
2004
2099
|
if (v instanceof URL) {
|
|
2005
2100
|
const fetched =
|
|
2006
2101
|
await this.#fetch${(0, es_toolkit.pascalCase)(property.singularName)}(v, options);
|
|
2007
2102
|
if (fetched == null) continue;
|
|
2103
|
+
// Not cached, so that it is verified when the portable object
|
|
2104
|
+
// policy applies later:
|
|
2105
|
+
if (isUnverifiedPortableClaim(fetched)) {
|
|
2106
|
+
yield fetched;
|
|
2107
|
+
continue;
|
|
2108
|
+
}
|
|
2008
2109
|
vs[i] = fetched;
|
|
2009
2110
|
this.${await getFieldName(property.uri, "#_trust")}.add(i);
|
|
2010
2111
|
this._cachedJsonLd = undefined;
|
|
2112
|
+
recordPortableReferrer(this, fetched, ${JSON.stringify(property.uri)});
|
|
2011
2113
|
yield fetched;
|
|
2012
2114
|
continue;
|
|
2013
2115
|
}
|
|
@@ -2038,12 +2140,16 @@ async function* generateProperty(type, property, types, moduleVarNames) {
|
|
|
2038
2140
|
}
|
|
2039
2141
|
yield `
|
|
2040
2142
|
if (v?.id != null &&
|
|
2041
|
-
${type.trustEmbeddedObjects === false ? "" : "this.id != null && "}!isTrustedIriOrigin(options, v.id, ${trustOwner})
|
|
2143
|
+
((${type.trustEmbeddedObjects === false ? "" : "this.id != null && "}!isTrustedIriOrigin(options, v.id, ${trustOwner})) ||
|
|
2144
|
+
isUnsecuredPortableObject(this) ||
|
|
2145
|
+
mustDereferencePortableObject(
|
|
2146
|
+
this, ${trustOwner}, v.id, options,
|
|
2147
|
+
)) &&
|
|
2042
2148
|
!this.${await getFieldName(property.uri, "#_trust")}.has(i)) {
|
|
2043
2149
|
if (options.crossOrigin === "throw") {
|
|
2044
2150
|
throw new Error(
|
|
2045
2151
|
"The property object's @id (" + v.id.href + ") has a different " +
|
|
2046
|
-
"origin than the property owner's @id (" + ${type.trustEmbeddedObjects === false ? "\"untrusted metadata\"" : "this.id
|
|
2152
|
+
"origin than the property owner's @id (" + ${type.trustEmbeddedObjects === false ? "\"untrusted metadata\"" : "(this.id?.href ?? null)"} + "); " +
|
|
2047
2153
|
"refusing to return the object. If you want to bypass this " +
|
|
2048
2154
|
"check and are aware of the security implications, set the " +
|
|
2049
2155
|
'crossOrigin option to "trust".'
|
|
@@ -2055,10 +2161,11 @@ async function* generateProperty(type, property, types, moduleVarNames) {
|
|
|
2055
2161
|
"return the object. If you want to bypass this check and are " +
|
|
2056
2162
|
"aware of the security implications, set the crossOrigin " +
|
|
2057
2163
|
'option to "trust".',
|
|
2058
|
-
{ objectId: v.id.href, parentObjectId: ${type.trustEmbeddedObjects === false ? "\"untrusted metadata\"" : "this.id
|
|
2164
|
+
{ objectId: v.id.href, parentObjectId: ${type.trustEmbeddedObjects === false ? "\"untrusted metadata\"" : "(this.id?.href ?? null)"} },
|
|
2059
2165
|
);
|
|
2060
2166
|
continue;
|
|
2061
2167
|
}
|
|
2168
|
+
recordPortableReferrer(this, v, ${JSON.stringify(property.uri)});
|
|
2062
2169
|
yield v;
|
|
2063
2170
|
}
|
|
2064
2171
|
}
|
|
@@ -2080,7 +2187,23 @@ const INTERNAL_RUNTIME_IMPORTS = [
|
|
|
2080
2187
|
"isTrustedIriOrigin",
|
|
2081
2188
|
"normalizeJsonLdIris"
|
|
2082
2189
|
].join(",\n ");
|
|
2083
|
-
const PORTABLE_DEREFERENCE_IMPORTS = [
|
|
2190
|
+
const PORTABLE_DEREFERENCE_IMPORTS = [
|
|
2191
|
+
"copyPortableProvenance",
|
|
2192
|
+
"createSnapshotContextLoader",
|
|
2193
|
+
"dereferencePortableIri",
|
|
2194
|
+
"getPortableResponseClaim",
|
|
2195
|
+
"isPortableIri",
|
|
2196
|
+
"isPortableMode",
|
|
2197
|
+
"isUnsecuredPortableObject",
|
|
2198
|
+
"isUnverifiedPortableClaim",
|
|
2199
|
+
"markUnverifiedPortableClaim",
|
|
2200
|
+
"mustDereferencePortableObject",
|
|
2201
|
+
"parseCompatibleEf61Reference",
|
|
2202
|
+
"type PortableResponseClaim",
|
|
2203
|
+
"recordPortableReferrer",
|
|
2204
|
+
"rejectMalformedCompatibleReference",
|
|
2205
|
+
"warnUnverifiableEmbeddedObject"
|
|
2206
|
+
].join(",\n ");
|
|
2084
2207
|
const SIGNED_REPRESENTATION_IMPORTS = [
|
|
2085
2208
|
"enterSignedValueScope",
|
|
2086
2209
|
"resolveSignedValues",
|