@open-charging-cloud/wwcp-poi 0.1.0 → 0.1.1
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/CHANGELOG.md +155 -1
- package/README.md +70 -8
- package/dist/common.d.ts +9 -0
- package/dist/common.d.ts.map +1 -1
- package/dist/history/apply.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1671 -198
- package/dist/index.js.map +1 -1
- package/dist/keys.d.ts.map +1 -1
- package/dist/network/certificates.d.ts +6 -4
- package/dist/network/certificates.d.ts.map +1 -1
- package/dist/network/evTaler.d.ts +13 -0
- package/dist/network/evTaler.d.ts.map +1 -1
- package/dist/network/identifications.d.ts +15 -2
- package/dist/network/identifications.d.ts.map +1 -1
- package/dist/network/partyKeys.d.ts.map +1 -1
- package/dist/network/roamingNetwork.d.ts +9 -0
- package/dist/network/roamingNetwork.d.ts.map +1 -1
- package/dist/network/versionTexts.d.ts +3 -2
- package/dist/network/versionTexts.d.ts.map +1 -1
- package/dist/network/writtenForm.d.ts +24 -0
- package/dist/network/writtenForm.d.ts.map +1 -0
- package/dist/proofs/keyStatement.d.ts +6 -1
- package/dist/proofs/keyStatement.d.ts.map +1 -1
- package/dist/proofs/signingKeyCertificate.d.ts +5 -0
- package/dist/proofs/signingKeyCertificate.d.ts.map +1 -1
- package/dist/proofs/stationProof.d.ts +3 -2
- package/dist/proofs/stationProof.d.ts.map +1 -1
- package/dist/proofs/trustContext.d.ts +50 -0
- package/dist/proofs/trustContext.d.ts.map +1 -0
- package/dist/verifier/chargingStation.d.ts +2 -1
- package/dist/verifier/chargingStation.d.ts.map +1 -1
- package/dist/verifier/trust.d.ts +3 -2
- package/dist/verifier/trust.d.ts.map +1 -1
- package/dist/verifier/version.d.ts +2 -1
- package/dist/verifier/version.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -736,6 +736,25 @@ function optionalTimestamp(object, property, what) {
|
|
|
736
736
|
const text = optionalString(object, property, what);
|
|
737
737
|
return text === void 0 ? void 0 : parseTimestamp(text, what ?? `The timestamp '${property}'`);
|
|
738
738
|
}
|
|
739
|
+
function timestampAt(object, property) {
|
|
740
|
+
const text = get(object, property);
|
|
741
|
+
if (typeof text !== "string")
|
|
742
|
+
return void 0;
|
|
743
|
+
try {
|
|
744
|
+
return parseTimestamp(text);
|
|
745
|
+
} catch {
|
|
746
|
+
return void 0;
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
function mandatoryText(object, property, what) {
|
|
750
|
+
if (get(object, property) === void 0)
|
|
751
|
+
throw new POIError(`Missing JSON property '${property}'!`);
|
|
752
|
+
return requireString(object, property, what);
|
|
753
|
+
}
|
|
754
|
+
function nonemptyText(object, property) {
|
|
755
|
+
const text = get(object, property);
|
|
756
|
+
return typeof text === "string" && text.length > 0 ? text : void 0;
|
|
757
|
+
}
|
|
739
758
|
var timeOf = (at) => at === void 0 ? Date.now() : typeof at === "number" ? at : typeof at === "string" ? parseTimestamp(at) : at.getTime();
|
|
740
759
|
function firstText(i18n2) {
|
|
741
760
|
if (!isObject(i18n2))
|
|
@@ -859,6 +878,13 @@ var isDotNetBase64 = (text) => {
|
|
|
859
878
|
const significant = text.replace(/[ \t\r\n]/gu, "");
|
|
860
879
|
return significant.length % 4 === 0 && /^[A-Za-z0-9+/]*={0,2}$/u.test(significant);
|
|
861
880
|
};
|
|
881
|
+
var isDeterministicCbor = (bytes) => {
|
|
882
|
+
try {
|
|
883
|
+
return bytesEqual(encode(decodeDeterministicCbor(bytes)), bytes);
|
|
884
|
+
} catch {
|
|
885
|
+
return false;
|
|
886
|
+
}
|
|
887
|
+
};
|
|
862
888
|
var POIPublicKey = class _POIPublicKey {
|
|
863
889
|
constructor(id, key, keyBytes, notBefore, notAfter, holder, usages, json) {
|
|
864
890
|
this.id = id;
|
|
@@ -914,11 +940,11 @@ var POIPublicKey = class _POIPublicKey {
|
|
|
914
940
|
}
|
|
915
941
|
try {
|
|
916
942
|
key = CoseKey.parse(keyBytes);
|
|
917
|
-
if (!bytesEqual(encode(decodeDeterministicCbor(keyBytes)), keyBytes))
|
|
918
|
-
throw new POIError("not deterministic CBOR");
|
|
919
943
|
} catch (e) {
|
|
920
944
|
throw new POIError(`Invalid COSE key: ${e instanceof Error ? e.message : String(e)}`);
|
|
921
945
|
}
|
|
946
|
+
if (!isDeterministicCbor(keyBytes))
|
|
947
|
+
throw new POIError(`Invalid COSE key: Invalid deterministic CBOR: the key of the public key '${id}' is not written as the deterministic CBOR of its COSE key!`);
|
|
922
948
|
if (key.isPrivate)
|
|
923
949
|
throw new POIError("A public key must not contain private parts!");
|
|
924
950
|
const notBefore = optionalTimestamp(json, "notBefore", `The notBefore of the key '${id}'`);
|
|
@@ -1102,6 +1128,7 @@ function parseAuditPath(value, algorithm, what) {
|
|
|
1102
1128
|
// src/network/identifications.ts
|
|
1103
1129
|
var objectsOf = (value) => isArray(value) ? value.filter(isObject) : [];
|
|
1104
1130
|
var idOf = (entity) => typeof entity["@id"] === "string" ? entity["@id"] : "";
|
|
1131
|
+
var inRoamingNetwork = (error, parameter) => `The given JSON representation of a roaming network is invalid: ${error} (Parameter '${parameter}')`;
|
|
1105
1132
|
var ignoringCase = (text) => Array.from(text, (character) => {
|
|
1106
1133
|
const upper = character.toUpperCase();
|
|
1107
1134
|
return upper.length === character.length ? upper : character;
|
|
@@ -1170,7 +1197,80 @@ function duplicateParking(parkingOperators, operators) {
|
|
|
1170
1197
|
], ignoringCase) ?? givenTwice("parking sensor", childrenOf(parkingOperators, "parkingSensors"), ignoringCase) ?? givenTwice("parking space group", childrenOf(parkingOperators, "parkingSpaceGroups"), ignoringCase) ?? givenTwice("parking space template", childrenOf(parkingOperators, "parkingSpaceTemplates"), ignoringCase) ?? // Parking products compare with case.
|
|
1171
1198
|
givenTwice("parking product", childrenOf(parkingOperators, "parkingProducts"), withCase);
|
|
1172
1199
|
}
|
|
1173
|
-
function
|
|
1200
|
+
function duplicateNotifiedBodyNumber(bodies) {
|
|
1201
|
+
const seen = /* @__PURE__ */ new Map();
|
|
1202
|
+
for (const body of bodies) {
|
|
1203
|
+
const number = get(body, "notifiedBodyNumber");
|
|
1204
|
+
if (typeof number !== "string")
|
|
1205
|
+
continue;
|
|
1206
|
+
const other = seen.get(number);
|
|
1207
|
+
if (other !== void 0)
|
|
1208
|
+
return `The notified body number '${number}' of the conformity assessment body '${idOf(body)}' is the one of the conformity assessment body '${other}' already!`;
|
|
1209
|
+
seen.set(number, idOf(body));
|
|
1210
|
+
}
|
|
1211
|
+
return void 0;
|
|
1212
|
+
}
|
|
1213
|
+
var PARTIES_IN_ORDER = [
|
|
1214
|
+
"chargingStationManufacturers",
|
|
1215
|
+
"eMobilityProviders",
|
|
1216
|
+
"gridOperators",
|
|
1217
|
+
"parkingOperators",
|
|
1218
|
+
"transparencySoftwareManufacturers",
|
|
1219
|
+
"conformityAssessmentBodies",
|
|
1220
|
+
"energyMeterManufacturers",
|
|
1221
|
+
"chargingStationOperators"
|
|
1222
|
+
];
|
|
1223
|
+
var IDENTIFIED = {
|
|
1224
|
+
chargingStationManufacturers: void 0,
|
|
1225
|
+
chargingStationModels: void 0,
|
|
1226
|
+
transparencySoftwareManufacturers: void 0,
|
|
1227
|
+
conformityAssessmentBodies: void 0,
|
|
1228
|
+
energyMeterManufacturers: void 0,
|
|
1229
|
+
energyMeterModels: void 0,
|
|
1230
|
+
chargingStationOperators: "charging station operator",
|
|
1231
|
+
chargingTariffs: "charging tariff",
|
|
1232
|
+
chargingPools: "charging pool",
|
|
1233
|
+
chargingStations: "charging station",
|
|
1234
|
+
EVSEs: "EVSE",
|
|
1235
|
+
energyMeter: void 0,
|
|
1236
|
+
EVSETemplates: "EVSE template",
|
|
1237
|
+
chargingConnectors: void 0,
|
|
1238
|
+
chargingStationTemplates: "charging station template",
|
|
1239
|
+
energyMeterTemplates: void 0,
|
|
1240
|
+
EVSEGroups: "EVSE group",
|
|
1241
|
+
chargingStationGroups: "charging station group"
|
|
1242
|
+
};
|
|
1243
|
+
function invalidIdentification(content) {
|
|
1244
|
+
const ofEntity = (entity, kind) => {
|
|
1245
|
+
const id = entity["@id"];
|
|
1246
|
+
if (id === void 0)
|
|
1247
|
+
return "Missing JSON property '@id'!";
|
|
1248
|
+
if (typeof id !== "string" && kind !== void 0)
|
|
1249
|
+
return `Invalid '${kind} identification'!`;
|
|
1250
|
+
return within(entity);
|
|
1251
|
+
};
|
|
1252
|
+
const within = (object) => {
|
|
1253
|
+
for (const [property, value] of Object.entries(object)) {
|
|
1254
|
+
if (property === "customData" || !(property in IDENTIFIED))
|
|
1255
|
+
continue;
|
|
1256
|
+
const kind = IDENTIFIED[property];
|
|
1257
|
+
for (const entity of isArray(value) ? value.filter(isObject) : isObject(value) ? [value] : []) {
|
|
1258
|
+
const error = ofEntity(entity, kind);
|
|
1259
|
+
if (error !== void 0)
|
|
1260
|
+
return error;
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
return void 0;
|
|
1264
|
+
};
|
|
1265
|
+
for (const property of PARTIES_IN_ORDER)
|
|
1266
|
+
for (const party of objectsOf(get(content, property))) {
|
|
1267
|
+
const error = ofEntity(party, IDENTIFIED[property]);
|
|
1268
|
+
if (error !== void 0)
|
|
1269
|
+
return error;
|
|
1270
|
+
}
|
|
1271
|
+
return void 0;
|
|
1272
|
+
}
|
|
1273
|
+
function duplicateIdentification(content, of) {
|
|
1174
1274
|
const operators = objectsOf(get(content, "chargingStationOperators"));
|
|
1175
1275
|
const providers = objectsOf(get(content, "eMobilityProviders"));
|
|
1176
1276
|
const gridOperators = objectsOf(get(content, "gridOperators"));
|
|
@@ -1179,7 +1279,20 @@ function duplicateIdentification(content) {
|
|
|
1179
1279
|
const bodies = objectsOf(get(content, "conformityAssessmentBodies"));
|
|
1180
1280
|
const meterOwners = [...operators, ...gridOperators];
|
|
1181
1281
|
const groupOwners = [...operators, ...providers];
|
|
1182
|
-
|
|
1282
|
+
const gridConnectionPoint = () => ofAnother(gridOperators, "gridConnectionPoints", (point, gridOperator, other) => `The grid connection point '${point}' of the grid operator '${gridOperator}' must be unique within the roaming network, but the grid operator '${other}' has it too!`);
|
|
1283
|
+
const energyMeter = () => givenTwice("energy meter", energyMetersOf(operators, gridOperators), ignoringCase);
|
|
1284
|
+
const parking = () => duplicateParking(parkingOperators, operators);
|
|
1285
|
+
const release = () => ofAnother(softwareManufacturers, "transparencySoftware", (id, manufacturer, other) => `The transparency software release '${id}' of the manufacturer '${manufacturer}' is one of the manufacturer '${other}' already!`);
|
|
1286
|
+
const certificate = () => ofAnother(bodies, "certificates", (id, body, other) => `The certificate '${id}' of the conformity assessment body '${body}' is one of the conformity assessment body '${other}' already!`);
|
|
1287
|
+
const number = () => duplicateNotifiedBodyNumber(bodies);
|
|
1288
|
+
const energyMeterGroup = () => givenTwice("energy meter group", childrenOf(meterOwners, "energyMeterGroups"), ignoringCase);
|
|
1289
|
+
const providerGroup = () => givenTwice("EVSE group", childrenOf(groupOwners, "EVSEGroups"), groupId("EG")) ?? givenTwice("charging station group", childrenOf(groupOwners, "chargingStationGroups"), groupId("SG")) ?? givenTwice("charging pool group", childrenOf(groupOwners, "chargingPoolGroups"), groupId("PG"));
|
|
1290
|
+
const tariffOffer = () => givenTwice("charging tariff offer", childrenOf(groupOwners, "chargingTariffOffers"), ignoringCase);
|
|
1291
|
+
const energyMeterTemplate = () => givenTwice("energy meter template", childrenOf(meterOwners, "energyMeterTemplates"), ignoringCase);
|
|
1292
|
+
if (of === "change set")
|
|
1293
|
+
return gridConnectionPoint() ?? energyMeter() ?? parking() ?? release() ?? certificate() ?? number() ?? energyMeterGroup() ?? providerGroup() ?? tariffOffer() ?? energyMeterTemplate();
|
|
1294
|
+
const ofParameter = (parameter, error) => error === void 0 ? void 0 : inRoamingNetwork(error, parameter);
|
|
1295
|
+
return ofParameter("GridOperators", gridConnectionPoint()) ?? ofParameter("ChargingStationOperators", energyMeter()) ?? ofParameter("ParkingOperators", parking()) ?? ofParameter("EMobilityProviders", providerGroup() ?? tariffOffer()) ?? ofParameter("TransparencySoftwareManufacturers", release()) ?? ofParameter("ConformityAssessmentBodies", certificate() ?? number()) ?? ofParameter("ChargingStationOperators", energyMeterGroup() ?? energyMeterTemplate());
|
|
1183
1296
|
}
|
|
1184
1297
|
|
|
1185
1298
|
// src/network/effective.ts
|
|
@@ -1513,11 +1626,11 @@ var AT_EDGES = new RegExp(`^[${WHITESPACE}]+|[${WHITESPACE}]+$`, "gu");
|
|
|
1513
1626
|
var isText = (value) => typeof value === "string" && AS_GIVEN.test(value);
|
|
1514
1627
|
var trimmed = (text) => text.replace(AT_EDGES, "");
|
|
1515
1628
|
var shown = (value) => typeof value === "string" ? value : JSON.stringify(value);
|
|
1516
|
-
function invalidText(
|
|
1629
|
+
function invalidText(entity, properties) {
|
|
1517
1630
|
for (const [property, description] of Object.entries(properties)) {
|
|
1518
1631
|
const value = get(entity, property);
|
|
1519
1632
|
if (value !== void 0 && !isText(value))
|
|
1520
|
-
return `
|
|
1633
|
+
return `Invalid ${description} '${shown(value)}'!`;
|
|
1521
1634
|
}
|
|
1522
1635
|
return void 0;
|
|
1523
1636
|
}
|
|
@@ -1528,22 +1641,23 @@ function versionTwice(holder, whose) {
|
|
|
1528
1641
|
for (const [property, description] of Object.entries(MODEL_VERSIONS)) {
|
|
1529
1642
|
const versions = get(holder, property);
|
|
1530
1643
|
if (isArray(versions) && new Set(versions).size !== versions.length)
|
|
1531
|
-
return `A ${description} of ${whose} must not be given twice
|
|
1644
|
+
return `A ${description} of ${whose} must not be given twice! (Parameter 'Versions')`;
|
|
1532
1645
|
}
|
|
1533
1646
|
return void 0;
|
|
1534
1647
|
}
|
|
1535
|
-
function invalidModelVersion(what, model) {
|
|
1648
|
+
function invalidModelVersion(what, kind, model) {
|
|
1536
1649
|
for (const [property, description] of Object.entries(MODEL_VERSIONS)) {
|
|
1537
1650
|
const versions = get(model, property);
|
|
1538
1651
|
if (versions === void 0)
|
|
1539
1652
|
continue;
|
|
1540
1653
|
if (!isArray(versions))
|
|
1541
|
-
return `The ${
|
|
1654
|
+
return `The ${description} must be a JSON array!`;
|
|
1542
1655
|
const invalid = versions.find((version) => !isText(version));
|
|
1543
1656
|
if (invalid !== void 0)
|
|
1544
|
-
return `
|
|
1657
|
+
return `Invalid ${description} '${shown(invalid)}'!`;
|
|
1545
1658
|
}
|
|
1546
|
-
|
|
1659
|
+
const twice2 = versionTwice(model, `the ${what} '${idOf2(model)}'`);
|
|
1660
|
+
return twice2 === void 0 ? void 0 : `The given JSON representation of ${kind} is invalid: ${twice2}`;
|
|
1547
1661
|
}
|
|
1548
1662
|
function invalidVersionText(content) {
|
|
1549
1663
|
const operators = objectsOf2(get(content, "chargingStationOperators"));
|
|
@@ -1551,11 +1665,28 @@ function invalidVersionText(content) {
|
|
|
1551
1665
|
const stations = operators.flatMap((operator) => objectsOf2(get(operator, "chargingPools"))).flatMap((pool) => objectsOf2(get(pool, "chargingStations")));
|
|
1552
1666
|
const children = (parties, property) => parties.flatMap((party) => objectsOf2(get(party, property)));
|
|
1553
1667
|
const first = (items, error) => items.map(error).find((found) => found !== void 0);
|
|
1554
|
-
return first(stations, (station) => invalidText(
|
|
1668
|
+
return first(stations, (station) => invalidText(station, DEVICE_TEXTS)) ?? first(children(operators, "chargingStationTemplates"), (template) => invalidText(template, TEMPLATE_TEXTS)) ?? first(energyMetersOf(operators, gridOperators), (meter) => invalidText(meter, DEVICE_TEXTS)) ?? first(children([...operators, ...gridOperators], "energyMeterTemplates"), (template) => invalidText(template, TEMPLATE_TEXTS)) ?? first(children(objectsOf2(get(content, "chargingStationManufacturers")), "chargingStationModels"), (model) => invalidModelVersion("charging station model", "a charging station model", model)) ?? first(children(objectsOf2(get(content, "energyMeterManufacturers")), "energyMeterModels"), (model) => invalidModelVersion("energy meter model", "an energy meter model", model));
|
|
1555
1669
|
}
|
|
1556
1670
|
|
|
1557
1671
|
// src/network/certificates.ts
|
|
1558
1672
|
var MODEL_PROPERTIES = ["chargingStationManufacturerId", "chargingStationModel", "energyMeterManufacturerId", "energyMeterModel"];
|
|
1673
|
+
var CERTIFICATE_PROPERTIES = [
|
|
1674
|
+
"@context",
|
|
1675
|
+
"@id",
|
|
1676
|
+
...MODEL_PROPERTIES,
|
|
1677
|
+
"hardwareRevisions",
|
|
1678
|
+
"firmwareVersions",
|
|
1679
|
+
"verifiedTransparencySoftwareIds",
|
|
1680
|
+
"compatibleTransparencySoftwareIds",
|
|
1681
|
+
"energyMeters",
|
|
1682
|
+
"documentNumber",
|
|
1683
|
+
"documentURL",
|
|
1684
|
+
"notBefore",
|
|
1685
|
+
"notAfter",
|
|
1686
|
+
"legislation",
|
|
1687
|
+
"statedBy"
|
|
1688
|
+
];
|
|
1689
|
+
var CERTIFIED_METER_PROPERTIES = ["manufacturerId", "modelId", "hardwareRevisions", "firmwareVersions"];
|
|
1559
1690
|
var RELEASES = ["verifiedTransparencySoftwareIds", "compatibleTransparencySoftwareIds"];
|
|
1560
1691
|
var idAt = (json, property) => {
|
|
1561
1692
|
const value = get(json, property);
|
|
@@ -1630,13 +1761,26 @@ function invalidReleaseId(certificate) {
|
|
|
1630
1761
|
function invalidEnergyMeter(meter) {
|
|
1631
1762
|
if (!isObject(meter))
|
|
1632
1763
|
return "Expected an object.";
|
|
1633
|
-
|
|
1764
|
+
const unknown = Object.keys(meter).find((property) => !CERTIFIED_METER_PROPERTIES.includes(property));
|
|
1765
|
+
if (unknown !== void 0)
|
|
1766
|
+
return `Unknown property '${unknown}'.`;
|
|
1767
|
+
for (const property of ["manufacturerId", "modelId"]) {
|
|
1768
|
+
if (meter[property] !== void 0 && typeof meter[property] !== "string")
|
|
1769
|
+
return `${property}: expected a string.`;
|
|
1634
1770
|
if (idAt(meter, property) === "")
|
|
1635
1771
|
return `${property}: expected a nonempty string.`;
|
|
1772
|
+
}
|
|
1636
1773
|
const model = `certified energy meter model '${idAt(meter, "modelId")}' of '${idAt(meter, "manufacturerId")}'`;
|
|
1637
|
-
return invalidCertifiedVersion(meter) ?? versionTwice(meter, `the ${model}`) ?? (textsOf(meter, "hardwareRevisions").length === 0 ? `The ${model} must name at least one hardware revision
|
|
1774
|
+
return invalidCertifiedVersion(meter) ?? versionTwice(meter, `the ${model}`) ?? (textsOf(meter, "hardwareRevisions").length === 0 ? `The ${model} must name at least one hardware revision! (Parameter 'HardwareRevisions')` : void 0) ?? (textsOf(meter, "firmwareVersions").length === 0 ? `The ${model} must name at least one firmware version! (Parameter 'FirmwareVersions')` : void 0);
|
|
1638
1775
|
}
|
|
1639
1776
|
function invalidArgument(certificate) {
|
|
1777
|
+
const unknown = Object.keys(certificate).find((property) => !CERTIFICATE_PROPERTIES.includes(property));
|
|
1778
|
+
if (unknown !== void 0)
|
|
1779
|
+
return `Unknown property '${unknown}'.`;
|
|
1780
|
+
if (certificate["@id"] !== void 0 && typeof certificate["@id"] !== "string")
|
|
1781
|
+
return "@id: expected a string.";
|
|
1782
|
+
if (idAt(certificate, "@id") === "")
|
|
1783
|
+
return "@id: expected a nonempty string.";
|
|
1640
1784
|
const modelError = MODEL_PROPERTIES.map((property) => notText(certificate, property)).find((error) => error !== void 0);
|
|
1641
1785
|
if (modelError !== void 0)
|
|
1642
1786
|
return modelError;
|
|
@@ -1667,25 +1811,25 @@ function invalidConstruction(certificate, id) {
|
|
|
1667
1811
|
if (twice2 !== void 0)
|
|
1668
1812
|
return twice2;
|
|
1669
1813
|
if (textsOf(certificate, "hardwareRevisions").length === 0)
|
|
1670
|
-
return `The certificate '${id}' must name at least one hardware revision of its model
|
|
1814
|
+
return `The certificate '${id}' must name at least one hardware revision of its model! (Parameter 'HardwareRevisions')`;
|
|
1671
1815
|
if (textsOf(certificate, "firmwareVersions").length === 0)
|
|
1672
|
-
return `The certificate '${id}' must name at least one firmware version of its model
|
|
1816
|
+
return `The certificate '${id}' must name at least one firmware version of its model! (Parameter 'FirmwareVersions')`;
|
|
1673
1817
|
const legislation = get(certificate, "legislation");
|
|
1674
1818
|
if (typeof legislation === "string" && trimmed(legislation) === "")
|
|
1675
|
-
return
|
|
1819
|
+
return "A legislation must not be empty. (Parameter 'Legislation')";
|
|
1676
1820
|
if (endsBeforeItBegins(certificate))
|
|
1677
|
-
return
|
|
1821
|
+
return "notBefore must not exceed notAfter. (Parameter 'NotBefore')";
|
|
1678
1822
|
const [verified = [], compatible = []] = RELEASES.map((property) => textsOf(certificate, property).map(trimmed));
|
|
1679
1823
|
if (new Set(verified).size !== verified.length || new Set(compatible).size !== compatible.length)
|
|
1680
|
-
return
|
|
1824
|
+
return "Empty or duplicate TransparencySoftware reference.";
|
|
1681
1825
|
if (verified.length === 0 && compatible.length === 0)
|
|
1682
|
-
return
|
|
1826
|
+
return "A document must identify at least one software release.";
|
|
1683
1827
|
const verifiedKeys = new Set(verified.map(idKey));
|
|
1684
1828
|
if (compatible.some((release) => verifiedKeys.has(idKey(release))))
|
|
1685
|
-
return
|
|
1829
|
+
return "A release cannot be both verified and merely compatible in the same document.";
|
|
1686
1830
|
const energyMeters = objectsOf2(get(certificate, "energyMeters"));
|
|
1687
1831
|
if (forMeter && energyMeters.length > 0)
|
|
1688
|
-
return `The certificate '${id}' of an energy meter model names no energy meters
|
|
1832
|
+
return `The certificate '${id}' of an energy meter model names no energy meters! (Parameter 'EnergyMeters')`;
|
|
1689
1833
|
const models = /* @__PURE__ */ new Map();
|
|
1690
1834
|
for (const meter of energyMeters) {
|
|
1691
1835
|
const key = `${idKey(idAt(meter, "manufacturerId"))}\0${idKey(idAt(meter, "modelId"))}`;
|
|
@@ -1693,15 +1837,47 @@ function invalidConstruction(certificate, id) {
|
|
|
1693
1837
|
models.set(key, { first: model?.first ?? meter, count: (model?.count ?? 0) + 1 });
|
|
1694
1838
|
}
|
|
1695
1839
|
const twiceNamed = [...models.values()].find((model) => model.count > 1)?.first;
|
|
1696
|
-
return twiceNamed === void 0 ? void 0 : `The energy meter model '${idAt(twiceNamed, "modelId")}' of '${idAt(twiceNamed, "manufacturerId")}' must not be given twice in the certificate '${id}'
|
|
1840
|
+
return twiceNamed === void 0 ? void 0 : `The energy meter model '${idAt(twiceNamed, "modelId")}' of '${idAt(twiceNamed, "manufacturerId")}' must not be given twice in the certificate '${id}'! (Parameter 'EnergyMeters')`;
|
|
1697
1841
|
}
|
|
1698
1842
|
function invalidCertificate(certificate) {
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1843
|
+
return invalidArgument(certificate) ?? invalidConstruction(certificate, idAt(certificate, "@id"));
|
|
1844
|
+
}
|
|
1845
|
+
var NOTIFIED_BODY_NUMBER = /^[0-9]{4}$/u;
|
|
1846
|
+
function invalidNotifiedTexts(body) {
|
|
1847
|
+
const number = get(body, "notifiedBodyNumber");
|
|
1848
|
+
const notifiedFor = get(body, "notifiedFor");
|
|
1849
|
+
if (number !== void 0 && typeof number !== "string")
|
|
1850
|
+
return "The notified body number must be a text!";
|
|
1851
|
+
if (notifiedFor !== void 0 && (!isArray(notifiedFor) || notifiedFor.some((legislation) => typeof legislation !== "string")))
|
|
1852
|
+
return "The legislations notified for must be a JSON array of texts!";
|
|
1853
|
+
const legislations = textsOf(body, "notifiedFor");
|
|
1854
|
+
if (legislations.slice(1).some((legislation, index) => ordinal(legislations[index] ?? "", legislation) > 0))
|
|
1855
|
+
return `The legislations the conformity assessment body '${typeof body["@id"] === "string" ? body["@id"] : ""}' is notified for are written in their ordinal order!`;
|
|
1856
|
+
return void 0;
|
|
1857
|
+
}
|
|
1858
|
+
function invalidBody(body) {
|
|
1859
|
+
const id = typeof body["@id"] === "string" ? body["@id"] : "";
|
|
1860
|
+
const invalid = (message, parameter) => `The given JSON representation of a conformity assessment body is invalid: ${message} (Parameter '${parameter}')`;
|
|
1861
|
+
const number = get(body, "notifiedBodyNumber");
|
|
1862
|
+
if (typeof number === "string" && !NOTIFIED_BODY_NUMBER.test(number))
|
|
1863
|
+
return invalid(`The notified body number '${number}' of the conformity assessment body '${id}' must be four digits!`, "NotifiedBodyNumber");
|
|
1864
|
+
const notifiedFor = textsOf(body, "notifiedFor");
|
|
1865
|
+
if (notifiedFor.some((legislation) => trimmed(legislation) === ""))
|
|
1866
|
+
return invalid(`A legislation the conformity assessment body '${id}' is notified for must not be empty!`, "NotifiedFor");
|
|
1867
|
+
if (new Set(notifiedFor).size !== notifiedFor.length)
|
|
1868
|
+
return invalid(`A legislation the conformity assessment body '${id}' is notified for must not be given twice!`, "NotifiedFor");
|
|
1869
|
+
const notNotified = objectsOf2(get(body, "certificates")).sort((left, right) => ordinal(idAt(left, "@id"), idAt(right, "@id"))).find((certificate) => typeof certificate["legislation"] === "string" && !notifiedFor.includes(certificate["legislation"]));
|
|
1870
|
+
if (notNotified !== void 0)
|
|
1871
|
+
return invalid(`The certificate '${idAt(notNotified, "@id")}' is issued under the legislation '${notNotified["legislation"]}', which the conformity assessment body '${id}' is not notified for!`, "Certificates");
|
|
1872
|
+
return void 0;
|
|
1702
1873
|
}
|
|
1703
1874
|
function invalidCertificates(content) {
|
|
1704
|
-
|
|
1875
|
+
for (const body of objectsOf2(get(content, "conformityAssessmentBodies"))) {
|
|
1876
|
+
const error = invalidNotifiedTexts(body) ?? objectsOf2(get(body, "certificates")).map(invalidCertificate).find((certificateError) => certificateError !== void 0) ?? invalidBody(body);
|
|
1877
|
+
if (error !== void 0)
|
|
1878
|
+
return error;
|
|
1879
|
+
}
|
|
1880
|
+
return void 0;
|
|
1705
1881
|
}
|
|
1706
1882
|
|
|
1707
1883
|
// src/qidigital/json.ts
|
|
@@ -1973,6 +2149,8 @@ var EV_TALER_EXCHANGE_CONTEXT = CONTEXT_PREFIX + "roamingNetwork/evTalerExchange
|
|
|
1973
2149
|
var EV_TALER_PAYMENT_OPTION = "EVTaler";
|
|
1974
2150
|
var EV_TALER_PAYMENT_MEANS = "EV_TALER";
|
|
1975
2151
|
var CROCKFORD_BASE32 = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
|
|
2152
|
+
var MERCHANT_PROPERTIES = ["@context", "merchantBaseURL", "merchantPublicKey", "exchanges"];
|
|
2153
|
+
var EXCHANGE_PROPERTIES = ["@context", "masterPublicKey", "baseURL", "currency", "name"];
|
|
1976
2154
|
var CURRENCIES = new Set(`EUR CHF USD CZK GBP HRK PLN RON RSD RUB SEK AED AFN ALL AMD AOA ARS AUD AWG AZN BAM BBD BDT BGN BHD BIF
|
|
1977
2155
|
BMD BND BOB BRL BSD BTN BWP BYN BZD CAD CDF CLP CNY COP CRC CUP CVE DJF DKK DOP DZD EGP ERN ETB FJD FKP
|
|
1978
2156
|
GEL GHS GIP GMD GNF GTQ GYD HKD HNL HTG HUF IDR ILS INR IQD IRR ISK JMD JOD JPY KES KGS KHR KMF KPW KRW
|
|
@@ -2044,6 +2222,26 @@ function lenientI18N(value) {
|
|
|
2044
2222
|
}
|
|
2045
2223
|
return [...texts2];
|
|
2046
2224
|
}
|
|
2225
|
+
var unread = (json, properties) => Object.keys(json).find((property) => !properties.includes(property));
|
|
2226
|
+
function notWrittenAsRead(json, read) {
|
|
2227
|
+
if ("merchantPublicKey" in read) {
|
|
2228
|
+
const property2 = unread(json, MERCHANT_PROPERTIES);
|
|
2229
|
+
if (property2 !== void 0)
|
|
2230
|
+
return `The EV Taler merchant must not name the property '${property2}'!`;
|
|
2231
|
+
if (get(json, "merchantBaseURL") !== read.merchantBaseURL)
|
|
2232
|
+
return `The merchant base URL '${tokenText(get(json, "merchantBaseURL") ?? "")}' is written as '${read.merchantBaseURL}'!`;
|
|
2233
|
+
return void 0;
|
|
2234
|
+
}
|
|
2235
|
+
const exchange = (error) => `Invalid exchange of an EV Taler merchant: ${error}`;
|
|
2236
|
+
const property = unread(json, EXCHANGE_PROPERTIES);
|
|
2237
|
+
if (property !== void 0)
|
|
2238
|
+
return exchange(`The exchange '${read.masterPublicKey}' must not name the property '${property}'!`);
|
|
2239
|
+
if (get(json, "baseURL") !== read.baseURL)
|
|
2240
|
+
return exchange(`The base URL '${tokenText(get(json, "baseURL") ?? "")}' of the exchange '${read.masterPublicKey}' is written as '${read.baseURL}'!`);
|
|
2241
|
+
if (get(json, "currency") !== read.currency)
|
|
2242
|
+
return exchange(`The currency '${tokenText(get(json, "currency") ?? "")}' of the exchange '${read.masterPublicKey}' is written as '${read.currency}'!`);
|
|
2243
|
+
return void 0;
|
|
2244
|
+
}
|
|
2047
2245
|
function exchangeOf(json) {
|
|
2048
2246
|
const context = get(json, "@context");
|
|
2049
2247
|
if (context !== void 0 && context !== EV_TALER_EXCHANGE_CONTEXT)
|
|
@@ -2089,6 +2287,7 @@ function evTalerMerchantOf(value) {
|
|
|
2089
2287
|
if (!isArray(exchangesJSON))
|
|
2090
2288
|
return invalid("The exchanges of an EV Taler merchant must be a JSON array!");
|
|
2091
2289
|
const exchanges = [];
|
|
2290
|
+
const read = [];
|
|
2092
2291
|
for (const exchangeJSON of exchangesJSON) {
|
|
2093
2292
|
if (!isObject(exchangeJSON))
|
|
2094
2293
|
return invalid("An exchange of an EV Taler merchant must be a JSON object!");
|
|
@@ -2096,6 +2295,7 @@ function evTalerMerchantOf(value) {
|
|
|
2096
2295
|
if (typeof exchange === "string")
|
|
2097
2296
|
return invalid(`Invalid exchange of an EV Taler merchant: ${exchange}`);
|
|
2098
2297
|
exchanges.push(exchange);
|
|
2298
|
+
read.push([exchangeJSON, exchange]);
|
|
2099
2299
|
}
|
|
2100
2300
|
const urlError = invalidBaseURL(merchantBaseURL, "merchant base URL");
|
|
2101
2301
|
if (urlError !== void 0)
|
|
@@ -2104,11 +2304,13 @@ function evTalerMerchantOf(value) {
|
|
|
2104
2304
|
return invalid("A merchant accepts at least one exchange! (Parameter 'Exchanges')");
|
|
2105
2305
|
if (new Set(exchanges.map((exchange) => exchange.masterPublicKey)).size !== exchanges.length)
|
|
2106
2306
|
return invalid("An exchange must not be given twice! (Parameter 'Exchanges')");
|
|
2107
|
-
|
|
2307
|
+
const merchant = {
|
|
2108
2308
|
merchantBaseURL: merchantBaseURL.text,
|
|
2109
2309
|
merchantPublicKey,
|
|
2110
2310
|
exchanges: exchanges.sort((left, right) => ordinal(left.masterPublicKey, right.masterPublicKey))
|
|
2111
2311
|
};
|
|
2312
|
+
const notWritten2 = notWrittenAsRead(value, merchant) ?? read.map(([json, exchange]) => notWrittenAsRead(json, exchange)).find((error) => error !== void 0);
|
|
2313
|
+
return notWritten2 === void 0 ? merchant : invalid(notWritten2);
|
|
2112
2314
|
}
|
|
2113
2315
|
var namesEVTaler = (paymentOptions) => isArray(paymentOptions) && paymentOptions.some((option) => typeof option === "string" && ignoringCase(trimmed(option)) === ignoringCase(EV_TALER_PAYMENT_OPTION));
|
|
2114
2316
|
function invalidPaymentOptions(entity, what) {
|
|
@@ -2176,6 +2378,7 @@ var PARTIES = [
|
|
|
2176
2378
|
["energyMeterManufacturers", "energy meter manufacturer", "an"],
|
|
2177
2379
|
["chargingStationOperators", "charging station operator", "a"]
|
|
2178
2380
|
];
|
|
2381
|
+
var KEY_PROPERTIES = ["@id", "@context", "key", "notBefore", "notAfter", "holder", "usages"];
|
|
2179
2382
|
function keysOf(party, property, description) {
|
|
2180
2383
|
const value = get(party, property);
|
|
2181
2384
|
if (value === void 0)
|
|
@@ -2186,7 +2389,9 @@ function keysOf(party, property, description) {
|
|
|
2186
2389
|
if (!isObject(item))
|
|
2187
2390
|
throw new POIError(`Invalid ${description} '${compactJSON(item)}'!`);
|
|
2188
2391
|
try {
|
|
2189
|
-
|
|
2392
|
+
const key = POIPublicKey.parse(item);
|
|
2393
|
+
onlyProperties(item, KEY_PROPERTIES, `The public key '${key.id}'`);
|
|
2394
|
+
return key;
|
|
2190
2395
|
} catch (e) {
|
|
2191
2396
|
throw new POIError(`Invalid ${description} '${compactJSON(item)}': ${e instanceof Error ? e.message : String(e)}`);
|
|
2192
2397
|
}
|
|
@@ -2229,6 +2434,1139 @@ function invalidPartyKeys(content) {
|
|
|
2229
2434
|
return void 0;
|
|
2230
2435
|
}
|
|
2231
2436
|
|
|
2437
|
+
// src/network/writtenForm.ts
|
|
2438
|
+
var idOf4 = (value) => isObject(value) && typeof value["@id"] === "string" ? value["@id"] : "";
|
|
2439
|
+
var ORDERED_TEXTS = /* @__PURE__ */ new Set([
|
|
2440
|
+
"facilities",
|
|
2441
|
+
"paymentOptions",
|
|
2442
|
+
"uiFeatures",
|
|
2443
|
+
"features",
|
|
2444
|
+
"parkingRestrictions",
|
|
2445
|
+
"services",
|
|
2446
|
+
"standards",
|
|
2447
|
+
"nutsCodes",
|
|
2448
|
+
"vehicleTypes",
|
|
2449
|
+
"euVehicleCategories",
|
|
2450
|
+
"parkingSpaceIds",
|
|
2451
|
+
"certificateIds",
|
|
2452
|
+
"chargingTariffIds",
|
|
2453
|
+
"acceptedEMobilityProviderIds",
|
|
2454
|
+
"paymentMeans",
|
|
2455
|
+
"paymentBrands",
|
|
2456
|
+
"signatureMethods",
|
|
2457
|
+
"connectorTypes",
|
|
2458
|
+
"EVSEIds",
|
|
2459
|
+
"chargingStationIds",
|
|
2460
|
+
"chargingPoolIds",
|
|
2461
|
+
"energyMeterIds",
|
|
2462
|
+
"EVSEGroupIds",
|
|
2463
|
+
"chargingStationGroupIds",
|
|
2464
|
+
"chargingPoolGroupIds",
|
|
2465
|
+
"chargingStationOperatorIds",
|
|
2466
|
+
"eMobilityProviderIds",
|
|
2467
|
+
"parkingSensorIds",
|
|
2468
|
+
"parkingProductIds",
|
|
2469
|
+
"measurands",
|
|
2470
|
+
"notifiedFor",
|
|
2471
|
+
"verifiedTransparencySoftwareIds",
|
|
2472
|
+
"compatibleTransparencySoftwareIds",
|
|
2473
|
+
"cardTypes",
|
|
2474
|
+
"dimensions",
|
|
2475
|
+
"usages"
|
|
2476
|
+
]);
|
|
2477
|
+
var LEFT_OUT_WHEN_EMPTY = /* @__PURE__ */ new Set([
|
|
2478
|
+
"acceptedEMobilityProviderIds",
|
|
2479
|
+
"authenticationModes",
|
|
2480
|
+
"brands",
|
|
2481
|
+
"cardTypes",
|
|
2482
|
+
"certificateIds",
|
|
2483
|
+
"certificates",
|
|
2484
|
+
"chargingConnectors",
|
|
2485
|
+
"chargingPoolGroupIds",
|
|
2486
|
+
"chargingPoolGroups",
|
|
2487
|
+
"chargingPoolIds",
|
|
2488
|
+
"chargingPoolTemplates",
|
|
2489
|
+
"chargingPools",
|
|
2490
|
+
"chargingStationGroupIds",
|
|
2491
|
+
"chargingStationGroups",
|
|
2492
|
+
"chargingStationIds",
|
|
2493
|
+
"chargingStationManufacturers",
|
|
2494
|
+
"chargingStationModels",
|
|
2495
|
+
"chargingStationOperatorIds",
|
|
2496
|
+
"chargingStationOperators",
|
|
2497
|
+
"chargingStationTemplates",
|
|
2498
|
+
"chargingStations",
|
|
2499
|
+
"chargingTariffGroups",
|
|
2500
|
+
"chargingTariffIds",
|
|
2501
|
+
"chargingTariffOffers",
|
|
2502
|
+
"chargingTariffTemplates",
|
|
2503
|
+
"chargingTariffs",
|
|
2504
|
+
"conditions",
|
|
2505
|
+
"conformityAssessmentBodies",
|
|
2506
|
+
"connectorTypes",
|
|
2507
|
+
"daysOfWeek",
|
|
2508
|
+
"dimensions",
|
|
2509
|
+
"eMobilityProviderIds",
|
|
2510
|
+
"eMobilityProviders",
|
|
2511
|
+
"euVehicleCategories",
|
|
2512
|
+
"EVSEGroupIds",
|
|
2513
|
+
"EVSEGroups",
|
|
2514
|
+
"EVSEIds",
|
|
2515
|
+
"EVSETemplates",
|
|
2516
|
+
"EVSEs",
|
|
2517
|
+
"energyMeterGroups",
|
|
2518
|
+
"energyMeterIds",
|
|
2519
|
+
"energyMeterManufacturers",
|
|
2520
|
+
"energyMeterModels",
|
|
2521
|
+
"energyMeterTemplates",
|
|
2522
|
+
"energyMeters",
|
|
2523
|
+
"facilities",
|
|
2524
|
+
"features",
|
|
2525
|
+
"gridConnectionPoints",
|
|
2526
|
+
"gridOperators",
|
|
2527
|
+
"identityKeys",
|
|
2528
|
+
"images",
|
|
2529
|
+
"locationLanguages",
|
|
2530
|
+
"marketLocationIds",
|
|
2531
|
+
"measurands",
|
|
2532
|
+
"meteringLocationIds",
|
|
2533
|
+
"models",
|
|
2534
|
+
"notifiedFor",
|
|
2535
|
+
"nutsCodes",
|
|
2536
|
+
"parkingGarages",
|
|
2537
|
+
"parkingOperators",
|
|
2538
|
+
"parkingProductIds",
|
|
2539
|
+
"parkingProducts",
|
|
2540
|
+
"parkingRestrictions",
|
|
2541
|
+
"parkingSensorIds",
|
|
2542
|
+
"parkingSensors",
|
|
2543
|
+
"parkingSpaceGroups",
|
|
2544
|
+
"parkingSpaceIds",
|
|
2545
|
+
"parkingSpaceTemplates",
|
|
2546
|
+
"parkingSpaces",
|
|
2547
|
+
"paymentBrands",
|
|
2548
|
+
"paymentMeans",
|
|
2549
|
+
"paymentOptions",
|
|
2550
|
+
"publicKeys",
|
|
2551
|
+
"relatedLocations",
|
|
2552
|
+
"services",
|
|
2553
|
+
"signatureMethods",
|
|
2554
|
+
"signingKeys",
|
|
2555
|
+
"standards",
|
|
2556
|
+
"templateIds",
|
|
2557
|
+
"transparencySoftware",
|
|
2558
|
+
"transparencySoftwareManufacturers",
|
|
2559
|
+
"transparencySoftwareStatus",
|
|
2560
|
+
"uiFeatures",
|
|
2561
|
+
"usages",
|
|
2562
|
+
"vehicleTypes"
|
|
2563
|
+
]);
|
|
2564
|
+
var TEXTS_IN_LANGUAGES = /* @__PURE__ */ new Set(["name", "description", "comment", "assistanceServiceDetails", "arrivalInstructions", "additionalInformation"]);
|
|
2565
|
+
var WRITTEN_ALSO_EMPTY = {
|
|
2566
|
+
certificates: ["verifiedTransparencySoftwareIds", "compatibleTransparencySoftwareIds"],
|
|
2567
|
+
openSourceLicenses: ["URLs"]
|
|
2568
|
+
};
|
|
2569
|
+
var PARTY_NAMES = {
|
|
2570
|
+
chargingStationOperators: "Charging Station Operator",
|
|
2571
|
+
eMobilityProviders: "E-Mobility Provider",
|
|
2572
|
+
chargingStationManufacturers: "Charging Station Manufacturer",
|
|
2573
|
+
energyMeterManufacturers: "Energy Meter Manufacturer",
|
|
2574
|
+
transparencySoftwareManufacturers: "Transparency Software Manufacturer",
|
|
2575
|
+
conformityAssessmentBodies: "Conformity Assessment Body"
|
|
2576
|
+
};
|
|
2577
|
+
var KEY_PROPERTIES2 = ["@id", "@context", "key", "notBefore", "notAfter", "holder", "usages"];
|
|
2578
|
+
var ENTITY_PROPERTIES = {
|
|
2579
|
+
"": [
|
|
2580
|
+
"@context",
|
|
2581
|
+
"@id",
|
|
2582
|
+
"chargingStationManufacturerIds",
|
|
2583
|
+
"chargingStationManufacturers",
|
|
2584
|
+
"chargingStationOperatorIds",
|
|
2585
|
+
"chargingStationOperators",
|
|
2586
|
+
"conformityAssessmentBodies",
|
|
2587
|
+
"conformityAssessmentBodyIds",
|
|
2588
|
+
"created",
|
|
2589
|
+
"customData",
|
|
2590
|
+
"dataLicenseIds",
|
|
2591
|
+
"dataLicenses",
|
|
2592
|
+
"dataSource",
|
|
2593
|
+
"description",
|
|
2594
|
+
"eMobilityProviderIds",
|
|
2595
|
+
"eMobilityProviders",
|
|
2596
|
+
"eTags",
|
|
2597
|
+
"energyMeterManufacturerIds",
|
|
2598
|
+
"energyMeterManufacturers",
|
|
2599
|
+
"gridOperatorIds",
|
|
2600
|
+
"gridOperators",
|
|
2601
|
+
"lastChange",
|
|
2602
|
+
"name",
|
|
2603
|
+
"operator",
|
|
2604
|
+
"parkingOperatorIds",
|
|
2605
|
+
"parkingOperators",
|
|
2606
|
+
"transparencySoftwareManufacturerIds",
|
|
2607
|
+
"transparencySoftwareManufacturers",
|
|
2608
|
+
"treeHashAlgorithms"
|
|
2609
|
+
],
|
|
2610
|
+
"operator": [
|
|
2611
|
+
"@context",
|
|
2612
|
+
"@id",
|
|
2613
|
+
"address",
|
|
2614
|
+
"created",
|
|
2615
|
+
"customData",
|
|
2616
|
+
"dataSource",
|
|
2617
|
+
"description",
|
|
2618
|
+
"eMailAddress",
|
|
2619
|
+
"homepage",
|
|
2620
|
+
"hotline",
|
|
2621
|
+
"hotlineEMailAddress",
|
|
2622
|
+
"identityKeys",
|
|
2623
|
+
"keyStatement",
|
|
2624
|
+
"lastChange",
|
|
2625
|
+
"minConsensus",
|
|
2626
|
+
"name",
|
|
2627
|
+
"signingKeyCertificates"
|
|
2628
|
+
],
|
|
2629
|
+
"chargingStationOperators": [
|
|
2630
|
+
"@context",
|
|
2631
|
+
"@id",
|
|
2632
|
+
"EVSEGroupIds",
|
|
2633
|
+
"EVSEGroups",
|
|
2634
|
+
"EVSETemplateIds",
|
|
2635
|
+
"EVSETemplates",
|
|
2636
|
+
"address",
|
|
2637
|
+
"brandIds",
|
|
2638
|
+
"brands",
|
|
2639
|
+
"chargingPoolGroupIds",
|
|
2640
|
+
"chargingPoolGroups",
|
|
2641
|
+
"chargingPoolIds",
|
|
2642
|
+
"chargingPoolTemplateIds",
|
|
2643
|
+
"chargingPoolTemplates",
|
|
2644
|
+
"chargingPools",
|
|
2645
|
+
"chargingStationGroupIds",
|
|
2646
|
+
"chargingStationGroups",
|
|
2647
|
+
"chargingStationTemplateIds",
|
|
2648
|
+
"chargingStationTemplates",
|
|
2649
|
+
"chargingTariffGroupIds",
|
|
2650
|
+
"chargingTariffGroups",
|
|
2651
|
+
"chargingTariffIds",
|
|
2652
|
+
"chargingTariffOfferIds",
|
|
2653
|
+
"chargingTariffOffers",
|
|
2654
|
+
"chargingTariffTemplateIds",
|
|
2655
|
+
"chargingTariffTemplates",
|
|
2656
|
+
"chargingTariffs",
|
|
2657
|
+
"created",
|
|
2658
|
+
"customData",
|
|
2659
|
+
"dataLicenseIds",
|
|
2660
|
+
"dataLicenses",
|
|
2661
|
+
"dataSource",
|
|
2662
|
+
"description",
|
|
2663
|
+
"eMailAddress",
|
|
2664
|
+
"energyMeterGroupIds",
|
|
2665
|
+
"energyMeterGroups",
|
|
2666
|
+
"energyMeterTemplateIds",
|
|
2667
|
+
"energyMeterTemplates",
|
|
2668
|
+
"evTaler",
|
|
2669
|
+
"exception",
|
|
2670
|
+
"geoLocation",
|
|
2671
|
+
"homepage",
|
|
2672
|
+
"hotline",
|
|
2673
|
+
"identityKeys",
|
|
2674
|
+
"lastChange",
|
|
2675
|
+
"logos",
|
|
2676
|
+
"name",
|
|
2677
|
+
"parkingSpaceIds",
|
|
2678
|
+
"parkingSpaces",
|
|
2679
|
+
"signingKeys",
|
|
2680
|
+
"stackTrace",
|
|
2681
|
+
"telephone",
|
|
2682
|
+
"termsAndConditions",
|
|
2683
|
+
"uri"
|
|
2684
|
+
],
|
|
2685
|
+
"eMobilityProviders": [
|
|
2686
|
+
"@context",
|
|
2687
|
+
"@id",
|
|
2688
|
+
"EVSEGroupIds",
|
|
2689
|
+
"EVSEGroups",
|
|
2690
|
+
"address",
|
|
2691
|
+
"chargingPoolGroupIds",
|
|
2692
|
+
"chargingPoolGroups",
|
|
2693
|
+
"chargingStationGroupIds",
|
|
2694
|
+
"chargingStationGroups",
|
|
2695
|
+
"chargingTariffOfferIds",
|
|
2696
|
+
"chargingTariffOffers",
|
|
2697
|
+
"created",
|
|
2698
|
+
"customData",
|
|
2699
|
+
"dataLicenses",
|
|
2700
|
+
"dataSource",
|
|
2701
|
+
"description",
|
|
2702
|
+
"eMailAddress",
|
|
2703
|
+
"geoLocation",
|
|
2704
|
+
"homepage",
|
|
2705
|
+
"hotline",
|
|
2706
|
+
"identityKeys",
|
|
2707
|
+
"lastChange",
|
|
2708
|
+
"logos",
|
|
2709
|
+
"name",
|
|
2710
|
+
"signingKeys",
|
|
2711
|
+
"telephone",
|
|
2712
|
+
"termsAndConditions",
|
|
2713
|
+
"uri"
|
|
2714
|
+
],
|
|
2715
|
+
"gridOperators": [
|
|
2716
|
+
"@context",
|
|
2717
|
+
"@id",
|
|
2718
|
+
"address",
|
|
2719
|
+
"created",
|
|
2720
|
+
"customData",
|
|
2721
|
+
"dataSource",
|
|
2722
|
+
"description",
|
|
2723
|
+
"energyMeterGroupIds",
|
|
2724
|
+
"energyMeterGroups",
|
|
2725
|
+
"energyMeterTemplateIds",
|
|
2726
|
+
"energyMeterTemplates",
|
|
2727
|
+
"gridConnectionPointIds",
|
|
2728
|
+
"gridConnectionPoints",
|
|
2729
|
+
"homepage",
|
|
2730
|
+
"hotline",
|
|
2731
|
+
"identityKeys",
|
|
2732
|
+
"lastChange",
|
|
2733
|
+
"name",
|
|
2734
|
+
"signingKeys"
|
|
2735
|
+
],
|
|
2736
|
+
"parkingOperators": [
|
|
2737
|
+
"@context",
|
|
2738
|
+
"@id",
|
|
2739
|
+
"address",
|
|
2740
|
+
"created",
|
|
2741
|
+
"customData",
|
|
2742
|
+
"dataSource",
|
|
2743
|
+
"description",
|
|
2744
|
+
"homepage",
|
|
2745
|
+
"hotline",
|
|
2746
|
+
"identityKeys",
|
|
2747
|
+
"lastChange",
|
|
2748
|
+
"name",
|
|
2749
|
+
"parkingGarageIds",
|
|
2750
|
+
"parkingGarages",
|
|
2751
|
+
"parkingProductIds",
|
|
2752
|
+
"parkingProducts",
|
|
2753
|
+
"parkingSensorIds",
|
|
2754
|
+
"parkingSensors",
|
|
2755
|
+
"parkingSpaceGroupIds",
|
|
2756
|
+
"parkingSpaceGroups",
|
|
2757
|
+
"parkingSpaceIds",
|
|
2758
|
+
"parkingSpaceTemplateIds",
|
|
2759
|
+
"parkingSpaceTemplates",
|
|
2760
|
+
"parkingSpaces",
|
|
2761
|
+
"signingKeys"
|
|
2762
|
+
],
|
|
2763
|
+
"chargingStationManufacturers": [
|
|
2764
|
+
"@context",
|
|
2765
|
+
"@id",
|
|
2766
|
+
"address",
|
|
2767
|
+
"chargingStationModelIds",
|
|
2768
|
+
"chargingStationModels",
|
|
2769
|
+
"created",
|
|
2770
|
+
"customData",
|
|
2771
|
+
"dataLicenses",
|
|
2772
|
+
"dataSource",
|
|
2773
|
+
"description",
|
|
2774
|
+
"eMailAddress",
|
|
2775
|
+
"geoLocation",
|
|
2776
|
+
"homepage",
|
|
2777
|
+
"hotline",
|
|
2778
|
+
"identityKeys",
|
|
2779
|
+
"lastChange",
|
|
2780
|
+
"logos",
|
|
2781
|
+
"name",
|
|
2782
|
+
"signingKeys",
|
|
2783
|
+
"telephone",
|
|
2784
|
+
"termsAndConditions",
|
|
2785
|
+
"uri"
|
|
2786
|
+
],
|
|
2787
|
+
"energyMeterManufacturers": [
|
|
2788
|
+
"@context",
|
|
2789
|
+
"@id",
|
|
2790
|
+
"address",
|
|
2791
|
+
"created",
|
|
2792
|
+
"customData",
|
|
2793
|
+
"dataLicenses",
|
|
2794
|
+
"dataSource",
|
|
2795
|
+
"description",
|
|
2796
|
+
"eMailAddress",
|
|
2797
|
+
"energyMeterModelIds",
|
|
2798
|
+
"energyMeterModels",
|
|
2799
|
+
"geoLocation",
|
|
2800
|
+
"homepage",
|
|
2801
|
+
"hotline",
|
|
2802
|
+
"identityKeys",
|
|
2803
|
+
"lastChange",
|
|
2804
|
+
"logos",
|
|
2805
|
+
"name",
|
|
2806
|
+
"signingKeys",
|
|
2807
|
+
"telephone",
|
|
2808
|
+
"termsAndConditions",
|
|
2809
|
+
"uri"
|
|
2810
|
+
],
|
|
2811
|
+
"transparencySoftwareManufacturers": [
|
|
2812
|
+
"@context",
|
|
2813
|
+
"@id",
|
|
2814
|
+
"address",
|
|
2815
|
+
"craRole",
|
|
2816
|
+
"created",
|
|
2817
|
+
"customData",
|
|
2818
|
+
"dataLicenses",
|
|
2819
|
+
"dataSource",
|
|
2820
|
+
"description",
|
|
2821
|
+
"eMailAddress",
|
|
2822
|
+
"geoLocation",
|
|
2823
|
+
"homepage",
|
|
2824
|
+
"hotline",
|
|
2825
|
+
"identityKeys",
|
|
2826
|
+
"lastChange",
|
|
2827
|
+
"logos",
|
|
2828
|
+
"name",
|
|
2829
|
+
"securityAdvisories",
|
|
2830
|
+
"signingKeys",
|
|
2831
|
+
"telephone",
|
|
2832
|
+
"termsAndConditions",
|
|
2833
|
+
"transparencySoftware",
|
|
2834
|
+
"transparencySoftwareIds",
|
|
2835
|
+
"uri",
|
|
2836
|
+
"vulnerabilityContact",
|
|
2837
|
+
"vulnerabilityDisclosurePolicy",
|
|
2838
|
+
"vulnerabilityReporting"
|
|
2839
|
+
],
|
|
2840
|
+
"conformityAssessmentBodies": [
|
|
2841
|
+
"@context",
|
|
2842
|
+
"@id",
|
|
2843
|
+
"address",
|
|
2844
|
+
"certificateIds",
|
|
2845
|
+
"certificates",
|
|
2846
|
+
"created",
|
|
2847
|
+
"customData",
|
|
2848
|
+
"dataLicenses",
|
|
2849
|
+
"dataSource",
|
|
2850
|
+
"description",
|
|
2851
|
+
"eMailAddress",
|
|
2852
|
+
"geoLocation",
|
|
2853
|
+
"homepage",
|
|
2854
|
+
"hotline",
|
|
2855
|
+
"identityKeys",
|
|
2856
|
+
"lastChange",
|
|
2857
|
+
"logos",
|
|
2858
|
+
"name",
|
|
2859
|
+
"notifiedBodyNumber",
|
|
2860
|
+
"notifiedFor",
|
|
2861
|
+
"signingKeys",
|
|
2862
|
+
"telephone",
|
|
2863
|
+
"termsAndConditions",
|
|
2864
|
+
"uri"
|
|
2865
|
+
],
|
|
2866
|
+
"chargingTariffs": [
|
|
2867
|
+
"@context",
|
|
2868
|
+
"@id",
|
|
2869
|
+
"created",
|
|
2870
|
+
"currency",
|
|
2871
|
+
"customData",
|
|
2872
|
+
"dataSource",
|
|
2873
|
+
"description",
|
|
2874
|
+
"elements",
|
|
2875
|
+
"energyMix",
|
|
2876
|
+
"lastChange",
|
|
2877
|
+
"maxPrice",
|
|
2878
|
+
"minPrice",
|
|
2879
|
+
"name",
|
|
2880
|
+
"paymentBrands",
|
|
2881
|
+
"paymentMeans",
|
|
2882
|
+
"tariffType",
|
|
2883
|
+
"tariffURL",
|
|
2884
|
+
"templateIds",
|
|
2885
|
+
"validFrom",
|
|
2886
|
+
"validUntil"
|
|
2887
|
+
],
|
|
2888
|
+
"chargingTariffTemplates": [
|
|
2889
|
+
"@context",
|
|
2890
|
+
"@id",
|
|
2891
|
+
"created",
|
|
2892
|
+
"currency",
|
|
2893
|
+
"customData",
|
|
2894
|
+
"dataSource",
|
|
2895
|
+
"description",
|
|
2896
|
+
"elements",
|
|
2897
|
+
"energyMix",
|
|
2898
|
+
"lastChange",
|
|
2899
|
+
"maxPrice",
|
|
2900
|
+
"minPrice",
|
|
2901
|
+
"name",
|
|
2902
|
+
"paymentBrands",
|
|
2903
|
+
"paymentMeans",
|
|
2904
|
+
"tariffType",
|
|
2905
|
+
"tariffURL",
|
|
2906
|
+
"validFrom",
|
|
2907
|
+
"validUntil"
|
|
2908
|
+
],
|
|
2909
|
+
"chargingTariffGroups": [
|
|
2910
|
+
"@context",
|
|
2911
|
+
"@id",
|
|
2912
|
+
"chargingTariffIds",
|
|
2913
|
+
"created",
|
|
2914
|
+
"customData",
|
|
2915
|
+
"dataSource",
|
|
2916
|
+
"description",
|
|
2917
|
+
"lastChange",
|
|
2918
|
+
"name"
|
|
2919
|
+
],
|
|
2920
|
+
"chargingTariffOffers": [
|
|
2921
|
+
"@context",
|
|
2922
|
+
"@id",
|
|
2923
|
+
"EVSEGroupIds",
|
|
2924
|
+
"chargingPoolGroupIds",
|
|
2925
|
+
"chargingStationGroupIds",
|
|
2926
|
+
"chargingStationOperatorIds",
|
|
2927
|
+
"chargingTariff",
|
|
2928
|
+
"created",
|
|
2929
|
+
"customData",
|
|
2930
|
+
"dataSource",
|
|
2931
|
+
"description",
|
|
2932
|
+
"discount",
|
|
2933
|
+
"eMobilityProviderIds",
|
|
2934
|
+
"lastChange",
|
|
2935
|
+
"maxSessionsPerContract",
|
|
2936
|
+
"name",
|
|
2937
|
+
"notAfter",
|
|
2938
|
+
"notBefore",
|
|
2939
|
+
"openingTimes",
|
|
2940
|
+
"sessions"
|
|
2941
|
+
],
|
|
2942
|
+
"elements": ["@context", "priceComponents", "restrictions"],
|
|
2943
|
+
"chargingPools": [
|
|
2944
|
+
"@context",
|
|
2945
|
+
"@id",
|
|
2946
|
+
"accessibility",
|
|
2947
|
+
"address",
|
|
2948
|
+
"arrivalInstructions",
|
|
2949
|
+
"assistanceServiceDetails",
|
|
2950
|
+
"authenticationModes",
|
|
2951
|
+
"brandIds",
|
|
2952
|
+
"brands",
|
|
2953
|
+
"chargingStationIds",
|
|
2954
|
+
"chargingStations",
|
|
2955
|
+
"chargingWhenClosed",
|
|
2956
|
+
"created",
|
|
2957
|
+
"customData",
|
|
2958
|
+
"dataLicenses",
|
|
2959
|
+
"dataSource",
|
|
2960
|
+
"description",
|
|
2961
|
+
"energyMeterIds",
|
|
2962
|
+
"energyMeters",
|
|
2963
|
+
"energyMix",
|
|
2964
|
+
"entranceAddress",
|
|
2965
|
+
"entranceLocation",
|
|
2966
|
+
"exitAddress",
|
|
2967
|
+
"exitLocation",
|
|
2968
|
+
"facilities",
|
|
2969
|
+
"features",
|
|
2970
|
+
"geoLocation",
|
|
2971
|
+
"gridConnectionPoint",
|
|
2972
|
+
"gridConnectionPointId",
|
|
2973
|
+
"hotline",
|
|
2974
|
+
"images",
|
|
2975
|
+
"lastChange",
|
|
2976
|
+
"locationLanguages",
|
|
2977
|
+
"name",
|
|
2978
|
+
"nutsCodes",
|
|
2979
|
+
"openingTimes",
|
|
2980
|
+
"parkingRestrictions",
|
|
2981
|
+
"parkingType",
|
|
2982
|
+
"paymentOptions",
|
|
2983
|
+
"relatedLocations",
|
|
2984
|
+
"services",
|
|
2985
|
+
"standards",
|
|
2986
|
+
"templateIds",
|
|
2987
|
+
"timeZone",
|
|
2988
|
+
"uiFeatures"
|
|
2989
|
+
],
|
|
2990
|
+
"chargingPoolTemplates": [
|
|
2991
|
+
"@context",
|
|
2992
|
+
"@id",
|
|
2993
|
+
"accessibility",
|
|
2994
|
+
"address",
|
|
2995
|
+
"arrivalInstructions",
|
|
2996
|
+
"assistanceServiceDetails",
|
|
2997
|
+
"authenticationModes",
|
|
2998
|
+
"brandIds",
|
|
2999
|
+
"brands",
|
|
3000
|
+
"chargingTariffId",
|
|
3001
|
+
"chargingWhenClosed",
|
|
3002
|
+
"created",
|
|
3003
|
+
"customData",
|
|
3004
|
+
"dataLicenseIds",
|
|
3005
|
+
"dataLicenses",
|
|
3006
|
+
"dataSource",
|
|
3007
|
+
"description",
|
|
3008
|
+
"energyMix",
|
|
3009
|
+
"entranceAddress",
|
|
3010
|
+
"entranceLocation",
|
|
3011
|
+
"exitAddress",
|
|
3012
|
+
"exitLocation",
|
|
3013
|
+
"facilities",
|
|
3014
|
+
"features",
|
|
3015
|
+
"geoLocation",
|
|
3016
|
+
"gridConnectionPointId",
|
|
3017
|
+
"hotline",
|
|
3018
|
+
"images",
|
|
3019
|
+
"lastChange",
|
|
3020
|
+
"locationLanguages",
|
|
3021
|
+
"name",
|
|
3022
|
+
"nutsCodes",
|
|
3023
|
+
"openingTimes",
|
|
3024
|
+
"parkingRestrictions",
|
|
3025
|
+
"parkingType",
|
|
3026
|
+
"paymentOptions",
|
|
3027
|
+
"relatedLocations",
|
|
3028
|
+
"services",
|
|
3029
|
+
"standards",
|
|
3030
|
+
"timeZone",
|
|
3031
|
+
"uiFeatures"
|
|
3032
|
+
],
|
|
3033
|
+
"chargingPoolGroups": [
|
|
3034
|
+
"@context",
|
|
3035
|
+
"@id",
|
|
3036
|
+
"chargingPoolIds",
|
|
3037
|
+
"created",
|
|
3038
|
+
"customData",
|
|
3039
|
+
"dataSource",
|
|
3040
|
+
"description",
|
|
3041
|
+
"lastChange",
|
|
3042
|
+
"name"
|
|
3043
|
+
],
|
|
3044
|
+
"chargingStations": [
|
|
3045
|
+
"@context",
|
|
3046
|
+
"@id",
|
|
3047
|
+
"EVSEIds",
|
|
3048
|
+
"EVSEs",
|
|
3049
|
+
"accessibility",
|
|
3050
|
+
"address",
|
|
3051
|
+
"brandIds",
|
|
3052
|
+
"brands",
|
|
3053
|
+
"calibrationInfo",
|
|
3054
|
+
"certificateIds",
|
|
3055
|
+
"certificationInfo",
|
|
3056
|
+
"created",
|
|
3057
|
+
"customData",
|
|
3058
|
+
"dataSource",
|
|
3059
|
+
"description",
|
|
3060
|
+
"energyMeterIds",
|
|
3061
|
+
"energyMeters",
|
|
3062
|
+
"euVehicleCategories",
|
|
3063
|
+
"features",
|
|
3064
|
+
"firmwareVersion",
|
|
3065
|
+
"geoLocation",
|
|
3066
|
+
"hardwareRevision",
|
|
3067
|
+
"hotline",
|
|
3068
|
+
"images",
|
|
3069
|
+
"lastChange",
|
|
3070
|
+
"manufacturerId",
|
|
3071
|
+
"maxPower",
|
|
3072
|
+
"modelId",
|
|
3073
|
+
"modelURL",
|
|
3074
|
+
"name",
|
|
3075
|
+
"openingTimes",
|
|
3076
|
+
"parkingSpaceIds",
|
|
3077
|
+
"physicalReference",
|
|
3078
|
+
"publicKeys",
|
|
3079
|
+
"serialNumber",
|
|
3080
|
+
"signatureMethods",
|
|
3081
|
+
"templateIds",
|
|
3082
|
+
"transparencySoftwareStatus",
|
|
3083
|
+
"vehicleTypes"
|
|
3084
|
+
],
|
|
3085
|
+
"chargingStationTemplates": [
|
|
3086
|
+
"@context",
|
|
3087
|
+
"@id",
|
|
3088
|
+
"accessibility",
|
|
3089
|
+
"address",
|
|
3090
|
+
"brandIds",
|
|
3091
|
+
"brands",
|
|
3092
|
+
"calibrationInfo",
|
|
3093
|
+
"certificateIds",
|
|
3094
|
+
"certificationInfo",
|
|
3095
|
+
"chargingTariffId",
|
|
3096
|
+
"created",
|
|
3097
|
+
"customData",
|
|
3098
|
+
"dataSource",
|
|
3099
|
+
"description",
|
|
3100
|
+
"euVehicleCategories",
|
|
3101
|
+
"features",
|
|
3102
|
+
"firmwareVersion",
|
|
3103
|
+
"geoLocation",
|
|
3104
|
+
"hardwareRevision",
|
|
3105
|
+
"hotline",
|
|
3106
|
+
"images",
|
|
3107
|
+
"lastChange",
|
|
3108
|
+
"manufacturerId",
|
|
3109
|
+
"maxPower",
|
|
3110
|
+
"modelId",
|
|
3111
|
+
"modelURL",
|
|
3112
|
+
"name",
|
|
3113
|
+
"openingTimes",
|
|
3114
|
+
"parkingSpaceIds",
|
|
3115
|
+
"physicalReference",
|
|
3116
|
+
"signatureMethods",
|
|
3117
|
+
"transparencySoftwareStatus",
|
|
3118
|
+
"vehicleTypes"
|
|
3119
|
+
],
|
|
3120
|
+
"chargingStationGroups": [
|
|
3121
|
+
"@context",
|
|
3122
|
+
"@id",
|
|
3123
|
+
"chargingStationIds",
|
|
3124
|
+
"created",
|
|
3125
|
+
"customData",
|
|
3126
|
+
"dataSource",
|
|
3127
|
+
"description",
|
|
3128
|
+
"lastChange",
|
|
3129
|
+
"name"
|
|
3130
|
+
],
|
|
3131
|
+
"EVSEs": [
|
|
3132
|
+
"@context",
|
|
3133
|
+
"@id",
|
|
3134
|
+
"acceptedEMobilityProviderIds",
|
|
3135
|
+
"brandIds",
|
|
3136
|
+
"brands",
|
|
3137
|
+
"chargingConnectorIds",
|
|
3138
|
+
"chargingConnectors",
|
|
3139
|
+
"chargingModes",
|
|
3140
|
+
"chargingTariffIds",
|
|
3141
|
+
"created",
|
|
3142
|
+
"currentTypes",
|
|
3143
|
+
"customData",
|
|
3144
|
+
"dataSource",
|
|
3145
|
+
"description",
|
|
3146
|
+
"energyMeter",
|
|
3147
|
+
"extendedOperationTimeout",
|
|
3148
|
+
"floorLevel",
|
|
3149
|
+
"geoLocation",
|
|
3150
|
+
"images",
|
|
3151
|
+
"iso15118Certificate",
|
|
3152
|
+
"lastChange",
|
|
3153
|
+
"maxCurrent",
|
|
3154
|
+
"maxPower",
|
|
3155
|
+
"maxReservationDuration",
|
|
3156
|
+
"maxVoltage",
|
|
3157
|
+
"name",
|
|
3158
|
+
"operationTimeout",
|
|
3159
|
+
"physicalReference",
|
|
3160
|
+
"reachDistance",
|
|
3161
|
+
"standards",
|
|
3162
|
+
"templateIds"
|
|
3163
|
+
],
|
|
3164
|
+
"EVSETemplates": [
|
|
3165
|
+
"@context",
|
|
3166
|
+
"@id",
|
|
3167
|
+
"acceptedEMobilityProviderIds",
|
|
3168
|
+
"brandIds",
|
|
3169
|
+
"brands",
|
|
3170
|
+
"chargingConnectorIds",
|
|
3171
|
+
"chargingConnectors",
|
|
3172
|
+
"chargingModes",
|
|
3173
|
+
"chargingTariffId",
|
|
3174
|
+
"created",
|
|
3175
|
+
"currentTypes",
|
|
3176
|
+
"customData",
|
|
3177
|
+
"dataSource",
|
|
3178
|
+
"description",
|
|
3179
|
+
"extendedOperationTimeout",
|
|
3180
|
+
"floorLevel",
|
|
3181
|
+
"geoLocation",
|
|
3182
|
+
"images",
|
|
3183
|
+
"lastChange",
|
|
3184
|
+
"maxCurrent",
|
|
3185
|
+
"maxPower",
|
|
3186
|
+
"maxReservationDuration",
|
|
3187
|
+
"maxVoltage",
|
|
3188
|
+
"name",
|
|
3189
|
+
"operationTimeout",
|
|
3190
|
+
"physicalReference",
|
|
3191
|
+
"reachDistance",
|
|
3192
|
+
"standards"
|
|
3193
|
+
],
|
|
3194
|
+
"EVSEGroups": [
|
|
3195
|
+
"@context",
|
|
3196
|
+
"@id",
|
|
3197
|
+
"EVSEIds",
|
|
3198
|
+
"created",
|
|
3199
|
+
"customData",
|
|
3200
|
+
"dataSource",
|
|
3201
|
+
"description",
|
|
3202
|
+
"lastChange",
|
|
3203
|
+
"name"
|
|
3204
|
+
],
|
|
3205
|
+
"chargingConnectors": [
|
|
3206
|
+
"@context",
|
|
3207
|
+
"@id",
|
|
3208
|
+
"cableLength",
|
|
3209
|
+
"cableManagementSystem",
|
|
3210
|
+
"cableWeight",
|
|
3211
|
+
"chargingTariffIds",
|
|
3212
|
+
"currentTypes",
|
|
3213
|
+
"format",
|
|
3214
|
+
"images",
|
|
3215
|
+
"lockable",
|
|
3216
|
+
"maxCurrent",
|
|
3217
|
+
"maxPower",
|
|
3218
|
+
"maxVoltage",
|
|
3219
|
+
"standards",
|
|
3220
|
+
"type"
|
|
3221
|
+
],
|
|
3222
|
+
"energyMeter": [
|
|
3223
|
+
"@context",
|
|
3224
|
+
"@id",
|
|
3225
|
+
"certificateIds",
|
|
3226
|
+
"created",
|
|
3227
|
+
"customData",
|
|
3228
|
+
"dataSource",
|
|
3229
|
+
"description",
|
|
3230
|
+
"firmwareVersion",
|
|
3231
|
+
"hardwareRevision",
|
|
3232
|
+
"lastChange",
|
|
3233
|
+
"manufacturerId",
|
|
3234
|
+
"modelId",
|
|
3235
|
+
"modelURL",
|
|
3236
|
+
"name",
|
|
3237
|
+
"publicKeys",
|
|
3238
|
+
"role",
|
|
3239
|
+
"serialNumber",
|
|
3240
|
+
"signatureMethods",
|
|
3241
|
+
"templateIds",
|
|
3242
|
+
"transparencySoftwareStatus"
|
|
3243
|
+
],
|
|
3244
|
+
"energyMeterTemplates": [
|
|
3245
|
+
"@context",
|
|
3246
|
+
"@id",
|
|
3247
|
+
"certificateIds",
|
|
3248
|
+
"created",
|
|
3249
|
+
"customData",
|
|
3250
|
+
"dataSource",
|
|
3251
|
+
"description",
|
|
3252
|
+
"firmwareVersion",
|
|
3253
|
+
"hardwareRevision",
|
|
3254
|
+
"lastChange",
|
|
3255
|
+
"manufacturerId",
|
|
3256
|
+
"modelId",
|
|
3257
|
+
"modelURL",
|
|
3258
|
+
"name",
|
|
3259
|
+
"role",
|
|
3260
|
+
"signatureMethods",
|
|
3261
|
+
"transparencySoftwareStatus"
|
|
3262
|
+
],
|
|
3263
|
+
"energyMeterGroups": [
|
|
3264
|
+
"@context",
|
|
3265
|
+
"@id",
|
|
3266
|
+
"created",
|
|
3267
|
+
"customData",
|
|
3268
|
+
"dataSource",
|
|
3269
|
+
"description",
|
|
3270
|
+
"energyMeterIds",
|
|
3271
|
+
"lastChange",
|
|
3272
|
+
"name"
|
|
3273
|
+
],
|
|
3274
|
+
"transparencySoftwareStatus": ["@context", "certificateId", "legalStatus", "transparencySoftwareId"],
|
|
3275
|
+
"gridConnectionPoints": [
|
|
3276
|
+
"@context",
|
|
3277
|
+
"@id",
|
|
3278
|
+
"address",
|
|
3279
|
+
"connectionAgreementId",
|
|
3280
|
+
"connectionType",
|
|
3281
|
+
"contractedExportApparentPower",
|
|
3282
|
+
"contractedExportPower",
|
|
3283
|
+
"contractedImportApparentPower",
|
|
3284
|
+
"contractedImportPower",
|
|
3285
|
+
"customData",
|
|
3286
|
+
"description",
|
|
3287
|
+
"energyMeter",
|
|
3288
|
+
"geoLocation",
|
|
3289
|
+
"gridOperator",
|
|
3290
|
+
"gridOperatorId",
|
|
3291
|
+
"maintainedBy",
|
|
3292
|
+
"marketLocationIds",
|
|
3293
|
+
"meteringLocationIds",
|
|
3294
|
+
"name",
|
|
3295
|
+
"networkLocationId",
|
|
3296
|
+
"nominalFrequency",
|
|
3297
|
+
"nominalVoltage",
|
|
3298
|
+
"voltageLevel"
|
|
3299
|
+
],
|
|
3300
|
+
"chargingStationModels": [
|
|
3301
|
+
"@context",
|
|
3302
|
+
"@id",
|
|
3303
|
+
"connectorTypes",
|
|
3304
|
+
"currentTypes",
|
|
3305
|
+
"customData",
|
|
3306
|
+
"datasheetURL",
|
|
3307
|
+
"description",
|
|
3308
|
+
"firmwareVersions",
|
|
3309
|
+
"hardwareRevisions",
|
|
3310
|
+
"images",
|
|
3311
|
+
"manufacturerId",
|
|
3312
|
+
"maxPower",
|
|
3313
|
+
"name",
|
|
3314
|
+
"numberOfEVSEs",
|
|
3315
|
+
"productURL"
|
|
3316
|
+
],
|
|
3317
|
+
"energyMeterModels": [
|
|
3318
|
+
"@context",
|
|
3319
|
+
"@id",
|
|
3320
|
+
"accuracyClass",
|
|
3321
|
+
"currentTypes",
|
|
3322
|
+
"customData",
|
|
3323
|
+
"datasheetURL",
|
|
3324
|
+
"description",
|
|
3325
|
+
"firmwareVersions",
|
|
3326
|
+
"hardwareRevisions",
|
|
3327
|
+
"images",
|
|
3328
|
+
"manufacturerId",
|
|
3329
|
+
"maxCurrent",
|
|
3330
|
+
"measurands",
|
|
3331
|
+
"name",
|
|
3332
|
+
"productURL",
|
|
3333
|
+
"signatureMethods"
|
|
3334
|
+
]
|
|
3335
|
+
};
|
|
3336
|
+
var PROPERTIES_OF = {
|
|
3337
|
+
...ENTITY_PROPERTIES,
|
|
3338
|
+
geoLocation: ["@context", "lat", "lng", "alt", "projection"],
|
|
3339
|
+
priceComponents: ["@context", "type", "price", "stepSize", "vat"],
|
|
3340
|
+
publicKeys: ["@context", "@id", "key", "certificateChain"],
|
|
3341
|
+
signingKeys: KEY_PROPERTIES2,
|
|
3342
|
+
identityKeys: KEY_PROPERTIES2,
|
|
3343
|
+
signingKey: KEY_PROPERTIES2,
|
|
3344
|
+
keyStatement: ["@context", "roamingNetworkId", "roamingNetworkOperatorId", "identityKeys", "minConsensus", "signedAt", "validUntil", "signatures"],
|
|
3345
|
+
signatures: ["algorithm", "keyId", "value"],
|
|
3346
|
+
signingKeyCertificates: ["@context", "roamingNetworkOperatorId", "signingKey", "signedAt", "algorithm", "keyId", "value"],
|
|
3347
|
+
evTaler: ["@context", "merchantBaseURL", "merchantPublicKey", "exchanges"],
|
|
3348
|
+
exchanges: ["@context", "masterPublicKey", "baseURL", "currency", "name"]
|
|
3349
|
+
};
|
|
3350
|
+
var TRIMMED = /* @__PURE__ */ new Set([
|
|
3351
|
+
"@id",
|
|
3352
|
+
"currency",
|
|
3353
|
+
"chargingTariffId",
|
|
3354
|
+
"manufacturerId",
|
|
3355
|
+
"modelId",
|
|
3356
|
+
"transparencySoftwareId",
|
|
3357
|
+
"version",
|
|
3358
|
+
"vulnerabilityContact",
|
|
3359
|
+
"energyMeterManufacturerId",
|
|
3360
|
+
"energyMeterModel",
|
|
3361
|
+
"roamingNetworkId",
|
|
3362
|
+
"roamingNetworkOperatorId",
|
|
3363
|
+
"sourceCodeRepository",
|
|
3364
|
+
"declarationOfConformity",
|
|
3365
|
+
"softwareBillOfMaterials",
|
|
3366
|
+
"documentURL"
|
|
3367
|
+
]);
|
|
3368
|
+
var URLS = /* @__PURE__ */ new Set(["homepage", "datasheetURL", "vulnerabilityReporting", "vulnerabilityDisclosurePolicy", "securityAdvisories", "merchantBaseURL", "baseURL"]);
|
|
3369
|
+
var NAMED_VALUES = {
|
|
3370
|
+
role: ["battery", "evse", "grid", "gridConnectionPoint", "pool", "pv", "station", "wind"],
|
|
3371
|
+
legalStatus: ["forInformationOnly", "germanCalibrationLaw", "verified"],
|
|
3372
|
+
signatureMethods: ["AlfenCrypt01", "AlfenCrypt03", "ChargePointCrypt01", "EDL40", "EMHCrypt01", "MennekesCrypt01", "OCMF", "PCDF"]
|
|
3373
|
+
};
|
|
3374
|
+
var RELEASE_PROPERTIES = [
|
|
3375
|
+
"@context",
|
|
3376
|
+
"@id",
|
|
3377
|
+
"name",
|
|
3378
|
+
"version",
|
|
3379
|
+
"openSourceLicenses",
|
|
3380
|
+
"sourceCodeRepository",
|
|
3381
|
+
"supportUntil",
|
|
3382
|
+
"declarationOfConformity",
|
|
3383
|
+
"softwareBillOfMaterials",
|
|
3384
|
+
"howToUse",
|
|
3385
|
+
"moreInformation",
|
|
3386
|
+
"logo"
|
|
3387
|
+
];
|
|
3388
|
+
var LICENSE_PROPERTIES = ["@context", "@id", "description", "URLs"];
|
|
3389
|
+
var KNOWN_DATA_LICENSES = /* @__PURE__ */ new Set([
|
|
3390
|
+
"None",
|
|
3391
|
+
"PDDL",
|
|
3392
|
+
"ODC-By",
|
|
3393
|
+
"ODbL",
|
|
3394
|
+
"dl-de/by-2-0",
|
|
3395
|
+
"dl-de/zero-2-0",
|
|
3396
|
+
"GeoLizenz_V1.3",
|
|
3397
|
+
"CC BY 4.0",
|
|
3398
|
+
"CC BY-SA 4.0",
|
|
3399
|
+
"CC BY-ND 4.0",
|
|
3400
|
+
"CC BY-NC 4.0",
|
|
3401
|
+
"CC BY-NC-SA 4.0",
|
|
3402
|
+
"CC BY-NC-ND 4.0"
|
|
3403
|
+
]);
|
|
3404
|
+
var DAYS_OF_WEEK = ["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY", "SUNDAY"];
|
|
3405
|
+
var TIMESTAMP_PROPERTIES = /* @__PURE__ */ new Set(["created", "lastChange", "validFrom", "validUntil", "notBefore", "notAfter", "signedAt", "supportUntil"]);
|
|
3406
|
+
var TIMESTAMP3 = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
|
|
3407
|
+
function orderKeys(items, property) {
|
|
3408
|
+
if (property === "signingKeyCertificates" && items.every(isObject))
|
|
3409
|
+
return items.map((item) => `${idOf4(isObject(item) ? item["signingKey"] : void 0)}\0${isObject(item) ? asText(item["keyId"]) : ""}`);
|
|
3410
|
+
if (property === "authenticationModes" && items.every(isObject))
|
|
3411
|
+
return items.map((item) => isObject(item) ? asText(item["type"]) : "");
|
|
3412
|
+
if (property === "transparencySoftwareStatus" && items.every(isObject))
|
|
3413
|
+
return items.map((item) => isObject(item) ? asText(item["transparencySoftwareId"]) : "");
|
|
3414
|
+
if (property === "exchanges" && items.every(isObject))
|
|
3415
|
+
return items.map((item) => isObject(item) ? asText(item["masterPublicKey"]) : "");
|
|
3416
|
+
if (property === "daysOfWeek")
|
|
3417
|
+
return items.map((item) => String(DAYS_OF_WEEK.indexOf(typeof item === "string" ? item : "")).padStart(2, "0"));
|
|
3418
|
+
if (items.length > 0 && items.every((item) => isObject(item) && typeof item["@id"] === "string"))
|
|
3419
|
+
return items.map(idOf4);
|
|
3420
|
+
if (property !== void 0 && ORDERED_TEXTS.has(property) && items.every((item) => typeof item === "string"))
|
|
3421
|
+
return items.map((item) => typeof item === "string" ? item : "");
|
|
3422
|
+
return void 0;
|
|
3423
|
+
}
|
|
3424
|
+
var languagesOf = (text) => [...new Set(Object.entries(text).filter(([, value]) => typeof value === "string").map(([language]) => LANGUAGES.has(language.toLowerCase()) ? language.toLowerCase() : /^\d+$/u.test(language) && Number(language) < LANGUAGES.size ? `(language ${language})` : /^[+-]?\d+$/u.test(language) ? language : void 0).filter((language) => language !== void 0))];
|
|
3425
|
+
function writtenValueOf(property, value, holder) {
|
|
3426
|
+
if ((property === "@id" || property === "type" && holder === "chargingConnectors") && (typeof value === "number" || typeof value === "boolean"))
|
|
3427
|
+
return String(value);
|
|
3428
|
+
if (typeof value === "string") {
|
|
3429
|
+
if (property === "@id" && holder === "chargingStationOperators")
|
|
3430
|
+
return trimmed(value).toUpperCase();
|
|
3431
|
+
if (TRIMMED.has(property) || property === "type" && holder === "chargingConnectors")
|
|
3432
|
+
return trimmed(value);
|
|
3433
|
+
if (URLS.has(property))
|
|
3434
|
+
return hermodURL(value)?.text;
|
|
3435
|
+
const names = NAMED_VALUES[property];
|
|
3436
|
+
if (names !== void 0)
|
|
3437
|
+
return names.find((name) => name.toLowerCase() === trimmed(value).toLowerCase()) ?? trimmed(value);
|
|
3438
|
+
}
|
|
3439
|
+
if (holder === "geoLocation" && (property === "lat" || property === "lng") && (typeof value === "number" || typeof value === "object") && value !== null && !isArray(value)) {
|
|
3440
|
+
const number = Number(canonicalJSON(value));
|
|
3441
|
+
return Number.isFinite(number) ? number : void 0;
|
|
3442
|
+
}
|
|
3443
|
+
return void 0;
|
|
3444
|
+
}
|
|
3445
|
+
var contentText = (value) => typeof value === "number" && !Number.isSafeInteger(value) ? String(value) : canonicalJSON(value);
|
|
3446
|
+
function asRead(value, kind) {
|
|
3447
|
+
if (isArray(value))
|
|
3448
|
+
return value.map((element) => asRead(element, kind));
|
|
3449
|
+
if (!isObject(value))
|
|
3450
|
+
return value;
|
|
3451
|
+
const known = PROPERTIES_OF[kind];
|
|
3452
|
+
return Object.fromEntries(Object.entries(value).filter(([key]) => known === void 0 || known.includes(key)).map(([key, element]) => [key, PROPERTIES_OF[key] === void 0 ? element : asRead(element, key)]));
|
|
3453
|
+
}
|
|
3454
|
+
function notWritten(value, property, path, of) {
|
|
3455
|
+
const eachOnce = of === "new value";
|
|
3456
|
+
const join = (at, key) => at === "" ? key : `${at}.${key}`;
|
|
3457
|
+
const holdsAs = (at, written) => ({ path: at, reason: `the content holds it as '${contentText(written)}'` });
|
|
3458
|
+
const leftOut = (key, element, kind, keepsEmptyName) => {
|
|
3459
|
+
if (element === null)
|
|
3460
|
+
return "a property without a value is left out";
|
|
3461
|
+
if (isArray(element) && element.length === 0 && LEFT_OUT_WHEN_EMPTY.has(key) && !(key === "identityKeys" && kind === "keyStatement"))
|
|
3462
|
+
return "a list without elements is left out";
|
|
3463
|
+
if (TEXTS_IN_LANGUAGES.has(key) && isObject(element) && languagesOf(element).length === 0 && !(key === "name" && keepsEmptyName))
|
|
3464
|
+
return "the content leaves it out";
|
|
3465
|
+
if (key === "dataLicenseIds")
|
|
3466
|
+
return "the content leaves it out";
|
|
3467
|
+
const known = kind === void 0 ? void 0 : PROPERTIES_OF[kind];
|
|
3468
|
+
if (known !== void 0 && !known.includes(key))
|
|
3469
|
+
return "the content leaves it out";
|
|
3470
|
+
return void 0;
|
|
3471
|
+
};
|
|
3472
|
+
const check2 = (item, name, holder, at, root = false) => {
|
|
3473
|
+
if (name === "customData")
|
|
3474
|
+
return void 0;
|
|
3475
|
+
if (isArray(item)) {
|
|
3476
|
+
if (name !== void 0 && ORDERED_TEXTS.has(name) && item.some((element) => typeof element === "string" && trimmed(element) !== element))
|
|
3477
|
+
return { path: at, reason: "the texts of its elements are trimmed" };
|
|
3478
|
+
const keys = orderKeys(item, name);
|
|
3479
|
+
if (keys?.some((key, index) => index > 0 && ordinal(keys[index - 1] ?? "", key) >= (eachOnce ? 0 : 1)) === true)
|
|
3480
|
+
return { path: at, reason: eachOnce ? "its elements are in the order the content holds them in, each once" : "its elements are in the order the content holds them in" };
|
|
3481
|
+
for (const [index, element] of item.entries()) {
|
|
3482
|
+
const elementAt = `${at}[${String(index)}]`;
|
|
3483
|
+
if (typeof element === "string" && name !== void 0 && NAMED_VALUES[name] !== void 0) {
|
|
3484
|
+
const written = writtenValueOf(name, element, holder);
|
|
3485
|
+
if (written !== void 0 && written !== element)
|
|
3486
|
+
return holdsAs(elementAt, written);
|
|
3487
|
+
}
|
|
3488
|
+
const found = check2(element, void 0, name, elementAt);
|
|
3489
|
+
if (found !== void 0)
|
|
3490
|
+
return found;
|
|
3491
|
+
}
|
|
3492
|
+
return void 0;
|
|
3493
|
+
}
|
|
3494
|
+
if (isObject(item)) {
|
|
3495
|
+
const kind = root ? "" : name ?? holder;
|
|
3496
|
+
const party = name === void 0 && holder !== void 0 ? PARTY_NAMES[holder] : void 0;
|
|
3497
|
+
const keepsEmptyName = name === void 0 && holder === "chargingStationOperators";
|
|
3498
|
+
if (name !== void 0 && TEXTS_IN_LANGUAGES.has(name) && [...Object.keys(item)].sort(ordinal).join("\0") !== languagesOf(item).sort(ordinal).join("\0"))
|
|
3499
|
+
return { path: at, reason: "a text in languages names each language as Styx writes it, in lower case, with a text" };
|
|
3500
|
+
for (const [key, element] of Object.entries(item)) {
|
|
3501
|
+
if (key === "@context") {
|
|
3502
|
+
if (root)
|
|
3503
|
+
continue;
|
|
3504
|
+
return { path: at, reason: "embedded, an object names no JSON-LD context" };
|
|
3505
|
+
}
|
|
3506
|
+
const elementAt = join(at, key);
|
|
3507
|
+
const omitted2 = leftOut(key, element, kind, keepsEmptyName);
|
|
3508
|
+
if (omitted2 !== void 0)
|
|
3509
|
+
return { path: elementAt, reason: omitted2 };
|
|
3510
|
+
if (typeof element === "string" && TIMESTAMP_PROPERTIES.has(key) && !TIMESTAMP3.test(element))
|
|
3511
|
+
return { path: elementAt, reason: "a timestamp is UTC to the millisecond, yyyy-MM-ddTHH:mm:ss.fffZ" };
|
|
3512
|
+
const written = key === "customData" ? void 0 : writtenValueOf(key, element, kind);
|
|
3513
|
+
if (written !== void 0 && contentText(written) !== contentText(element))
|
|
3514
|
+
return holdsAs(elementAt, written);
|
|
3515
|
+
const found = check2(element, key, kind, elementAt);
|
|
3516
|
+
if (found !== void 0)
|
|
3517
|
+
return found;
|
|
3518
|
+
}
|
|
3519
|
+
if (party !== void 0 && !("name" in item))
|
|
3520
|
+
return holdsAs(join(at, "name"), { en: `${party} '${asText(writtenValueOf("@id", item["@id"] ?? "", holder) ?? item["@id"])}'` });
|
|
3521
|
+
for (const list of name === void 0 && holder !== void 0 ? WRITTEN_ALSO_EMPTY[holder] ?? [] : [])
|
|
3522
|
+
if (!(list in item))
|
|
3523
|
+
return holdsAs(join(at, list), []);
|
|
3524
|
+
if (!eachOnce && typeof item["created"] === "string" && !("lastChange" in item))
|
|
3525
|
+
return holdsAs(join(at, "lastChange"), item["created"]);
|
|
3526
|
+
}
|
|
3527
|
+
return void 0;
|
|
3528
|
+
};
|
|
3529
|
+
const omitted = property === void 0 ? void 0 : leftOut(property, value, void 0, false);
|
|
3530
|
+
if (omitted !== void 0)
|
|
3531
|
+
return { path, reason: omitted };
|
|
3532
|
+
return check2(value, property, void 0, path, of === "version" && property === void 0);
|
|
3533
|
+
}
|
|
3534
|
+
function notWrittenAsHeld(content) {
|
|
3535
|
+
const unknownLicense = (value) => {
|
|
3536
|
+
if (isArray(value))
|
|
3537
|
+
return value.map(unknownLicense).find((found2) => found2 !== void 0);
|
|
3538
|
+
if (!isObject(value))
|
|
3539
|
+
return void 0;
|
|
3540
|
+
for (const [key, element] of Object.entries(value)) {
|
|
3541
|
+
if (key === "customData")
|
|
3542
|
+
continue;
|
|
3543
|
+
const unknown = key === "dataLicenseIds" && isArray(element) ? element.find((id) => typeof id === "string" && !KNOWN_DATA_LICENSES.has(id)) : void 0;
|
|
3544
|
+
if (unknown !== void 0)
|
|
3545
|
+
return `The data license '${asText(unknown)}' is not well-known, so it must be given completely!`;
|
|
3546
|
+
const found2 = unknownLicense(element);
|
|
3547
|
+
if (found2 !== void 0)
|
|
3548
|
+
return found2;
|
|
3549
|
+
}
|
|
3550
|
+
return void 0;
|
|
3551
|
+
};
|
|
3552
|
+
const license = unknownLicense(content);
|
|
3553
|
+
if (license !== void 0)
|
|
3554
|
+
return license;
|
|
3555
|
+
for (const manufacturer of isArray(content["transparencySoftwareManufacturers"]) ? content["transparencySoftwareManufacturers"].filter(isObject) : [])
|
|
3556
|
+
for (const release of isArray(manufacturer["transparencySoftware"]) ? manufacturer["transparencySoftware"].filter(isObject) : []) {
|
|
3557
|
+
const unknown = Object.keys(release).find((property) => !RELEASE_PROPERTIES.includes(property));
|
|
3558
|
+
if (unknown !== void 0)
|
|
3559
|
+
return `TransparencySoftware: Unknown property '${unknown}'.`;
|
|
3560
|
+
for (const [index, license2] of (isArray(release["openSourceLicenses"]) ? release["openSourceLicenses"] : []).entries()) {
|
|
3561
|
+
const unknownOfLicense = isObject(license2) ? Object.keys(license2).find((property) => !LICENSE_PROPERTIES.includes(property)) : void 0;
|
|
3562
|
+
if (unknownOfLicense !== void 0)
|
|
3563
|
+
return `TransparencySoftware: openSourceLicenses[${String(index)}]: Unknown property '${unknownOfLicense}'.`;
|
|
3564
|
+
}
|
|
3565
|
+
}
|
|
3566
|
+
const found = notWritten(content, void 0, "", "version");
|
|
3567
|
+
return found === void 0 ? void 0 : `'${found.path}' is not written as the content holds it: ${found.reason}!`;
|
|
3568
|
+
}
|
|
3569
|
+
|
|
2232
3570
|
// src/network/tree.ts
|
|
2233
3571
|
var CHILD_ARRAYS = {
|
|
2234
3572
|
roamingNetwork: {
|
|
@@ -2406,37 +3744,57 @@ var KeyStatement = class _KeyStatement {
|
|
|
2406
3744
|
validUntil;
|
|
2407
3745
|
signatures;
|
|
2408
3746
|
json;
|
|
2409
|
-
/**
|
|
3747
|
+
/**
|
|
3748
|
+
* Reads a key statement as `RoamingNetworkKeyStatement.TryParse` of WWCP_POI3 reads it, in its words and order: its
|
|
3749
|
+
* context, the roaming network and its operator, its identity keys, `signedAt` and `validUntil` as POI writes them,
|
|
3750
|
+
* `minConsensus`, its signatures. Then what this library refuses besides, as whatever is not signed is not taken: a
|
|
3751
|
+
* property it does not know, identity keys out of the order of their `@id`s, a `validUntil` before its `signedAt`.
|
|
3752
|
+
*/
|
|
2410
3753
|
static parse(value) {
|
|
2411
3754
|
const json = requireObject(value, "A key statement");
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
const roamingNetworkId =
|
|
2415
|
-
const roamingNetworkOperatorId =
|
|
2416
|
-
const
|
|
3755
|
+
if (get(json, "@context") !== void 0 && get(json, "@context") !== KEY_STATEMENT_CONTEXT)
|
|
3756
|
+
throw new POIError(`The JSON-LD context of the key statement must be '${KEY_STATEMENT_CONTEXT}'!`);
|
|
3757
|
+
const roamingNetworkId = trimmed(mandatoryText(json, "roamingNetworkId", "The roaming network of a key statement"));
|
|
3758
|
+
const roamingNetworkOperatorId = trimmed(mandatoryText(json, "roamingNetworkOperatorId", "The roaming network operator of a key statement"));
|
|
3759
|
+
const identityKeysJSON = get(json, "identityKeys");
|
|
3760
|
+
if (identityKeysJSON !== void 0 && !isArray(identityKeysJSON))
|
|
3761
|
+
throw new POIError("The identityKeys of a key statement must be a JSON array!");
|
|
3762
|
+
const identityKeys = (identityKeysJSON ?? []).map((item) => {
|
|
3763
|
+
try {
|
|
3764
|
+
return POIPublicKey.parse(item);
|
|
3765
|
+
} catch {
|
|
3766
|
+
throw new POIError("Invalid key in the identityKeys of a key statement!");
|
|
3767
|
+
}
|
|
3768
|
+
});
|
|
2417
3769
|
if (identityKeys.length === 0)
|
|
2418
3770
|
throw new POIError("A key statement requires its identityKeys!");
|
|
3771
|
+
const signedAt = timestampAt(json, "signedAt");
|
|
3772
|
+
const validUntil = timestampAt(json, "validUntil");
|
|
3773
|
+
if (signedAt === void 0 || validUntil === void 0)
|
|
3774
|
+
throw new POIError("The signedAt and validUntil of a key statement must be written as yyyy-MM-ddTHH:mm:ss.fffZ!");
|
|
3775
|
+
const minConsensus = get(json, "minConsensus");
|
|
3776
|
+
if (typeof minConsensus !== "number" || !Number.isInteger(minConsensus) || minConsensus < 1 || minConsensus > 255)
|
|
3777
|
+
throw new POIError("A key statement requires its minConsensus, a whole number from 1 to 255!");
|
|
3778
|
+
const signaturesJSON = get(json, "signatures");
|
|
3779
|
+
if (!isArray(signaturesJSON) || signaturesJSON.length === 0)
|
|
3780
|
+
throw new POIError("A key statement requires its signatures!");
|
|
3781
|
+
const signatures = signaturesJSON.map((item) => {
|
|
3782
|
+
const algorithm = isObject(item) ? nonemptyText(item, "algorithm") : void 0;
|
|
3783
|
+
const keyId = isObject(item) ? nonemptyText(item, "keyId") : void 0;
|
|
3784
|
+
const value2 = isObject(item) ? nonemptyText(item, "value") : void 0;
|
|
3785
|
+
if (!isObject(item) || algorithm === void 0 || keyId === void 0 || value2 === void 0)
|
|
3786
|
+
throw new POIError("Every signature of a key statement requires an algorithm, a key identification and a value!");
|
|
3787
|
+
onlyProperties(item, ["algorithm", "keyId", "value"], "A signature of a key statement");
|
|
3788
|
+
return { algorithm, keyId, value: value2 };
|
|
3789
|
+
});
|
|
3790
|
+
onlyProperties(json, ["@context", "roamingNetworkId", "roamingNetworkOperatorId", "identityKeys", "minConsensus", "signedAt", "validUntil", "signatures"], "A key statement");
|
|
2419
3791
|
if (identityKeys.some((key, index) => {
|
|
2420
3792
|
const before = identityKeys[index - 1];
|
|
2421
3793
|
return before !== void 0 && before.id >= key.id;
|
|
2422
3794
|
}))
|
|
2423
3795
|
throw new POIError("The identity keys of a key statement are written in the order of their @ids!");
|
|
2424
|
-
const minConsensus = requireInteger(json, "minConsensus", 1, 255, "The minConsensus of a key statement");
|
|
2425
|
-
const signedAt = requireTimestamp(json, "signedAt", "The signedAt of a key statement");
|
|
2426
|
-
const validUntil = requireTimestamp(json, "validUntil", "The validUntil of a key statement");
|
|
2427
3796
|
if (validUntil < signedAt)
|
|
2428
3797
|
throw new POIError("A key statement is not valid until before it was signed!");
|
|
2429
|
-
const signatures = requireArray(json["signatures"], "The signatures of a key statement").map((item) => {
|
|
2430
|
-
const signature = requireObject(item, "A signature of a key statement");
|
|
2431
|
-
onlyProperties(signature, ["algorithm", "keyId", "value"], "A signature of a key statement");
|
|
2432
|
-
return {
|
|
2433
|
-
algorithm: requireString(signature, "algorithm"),
|
|
2434
|
-
keyId: requireString(signature, "keyId"),
|
|
2435
|
-
value: requireString(signature, "value")
|
|
2436
|
-
};
|
|
2437
|
-
});
|
|
2438
|
-
if (signatures.length === 0)
|
|
2439
|
-
throw new POIError("A key statement requires its signatures!");
|
|
2440
3798
|
return new _KeyStatement(roamingNetworkId, roamingNetworkOperatorId, identityKeys, minConsensus, signedAt, validUntil, signatures, json);
|
|
2441
3799
|
}
|
|
2442
3800
|
/** The statement as it is signed: without `signatures`, with its `@context`, keys embedded without theirs. */
|
|
@@ -2546,7 +3904,7 @@ var KeyStatement = class _KeyStatement {
|
|
|
2546
3904
|
|
|
2547
3905
|
// src/proofs/signingKeyCertificate.ts
|
|
2548
3906
|
var SIGNING_KEY_CERTIFICATE_CONTEXT = CONTEXT_PREFIX + "roamingNetwork/signingKeyCertificate/v2";
|
|
2549
|
-
var describeHolder = (key) => key.holder !== void 0 ? `'${key.holder}'` : "no named holder";
|
|
3907
|
+
var describeHolder = (key) => key.holder !== void 0 ? `the holder '${key.holder}'` : "no named holder";
|
|
2550
3908
|
var SigningKeyCertificate = class _SigningKeyCertificate {
|
|
2551
3909
|
constructor(roamingNetworkOperatorId, signingKey, signedAt, algorithm, keyId, value, json) {
|
|
2552
3910
|
this.roamingNetworkOperatorId = roamingNetworkOperatorId;
|
|
@@ -2564,19 +3922,32 @@ var SigningKeyCertificate = class _SigningKeyCertificate {
|
|
|
2564
3922
|
keyId;
|
|
2565
3923
|
value;
|
|
2566
3924
|
json;
|
|
3925
|
+
/**
|
|
3926
|
+
* Reads a certificate as `RoamingNetworkSigningKeyCertificate.TryParse` of WWCP_POI3 reads it, in its words and order:
|
|
3927
|
+
* its context, the roaming network operator, the signing key it certifies, `signedAt` as POI writes it, the algorithm,
|
|
3928
|
+
* key identification and value of its signature; then a property it does not know, which is not signed.
|
|
3929
|
+
*/
|
|
2567
3930
|
static parse(value) {
|
|
2568
3931
|
const json = requireObject(value, "A certificate of a signing key");
|
|
2569
|
-
|
|
3932
|
+
if (get(json, "@context") !== void 0 && get(json, "@context") !== SIGNING_KEY_CERTIFICATE_CONTEXT)
|
|
3933
|
+
throw new POIError(`The JSON-LD context of a signing key certificate must be '${SIGNING_KEY_CERTIFICATE_CONTEXT}'!`);
|
|
3934
|
+
const roamingNetworkOperatorId = trimmed(mandatoryText(json, "roamingNetworkOperatorId", "The roaming network operator of a certificate"));
|
|
3935
|
+
let signingKey;
|
|
3936
|
+
try {
|
|
3937
|
+
signingKey = POIPublicKey.parse(isObject(json["signingKey"]) ? json["signingKey"] : void 0);
|
|
3938
|
+
} catch {
|
|
3939
|
+
throw new POIError("A signing key certificate requires the signingKey it certifies!");
|
|
3940
|
+
}
|
|
3941
|
+
const signedAt = timestampAt(json, "signedAt");
|
|
3942
|
+
if (signedAt === void 0)
|
|
3943
|
+
throw new POIError("The signedAt of a signing key certificate must be written as yyyy-MM-ddTHH:mm:ss.fffZ!");
|
|
3944
|
+
const algorithm = nonemptyText(json, "algorithm");
|
|
3945
|
+
const keyId = nonemptyText(json, "keyId");
|
|
3946
|
+
const signature = nonemptyText(json, "value");
|
|
3947
|
+
if (algorithm === void 0 || keyId === void 0 || signature === void 0)
|
|
3948
|
+
throw new POIError("A signing key certificate requires the algorithm, the key identification and the value of its signature!");
|
|
2570
3949
|
onlyProperties(json, ["@context", "roamingNetworkOperatorId", "signingKey", "signedAt", "algorithm", "keyId", "value"], "A certificate of a signing key");
|
|
2571
|
-
return new _SigningKeyCertificate(
|
|
2572
|
-
requireString(json, "roamingNetworkOperatorId", "The roaming network operator of a certificate"),
|
|
2573
|
-
POIPublicKey.parse(json["signingKey"], "The signing key of a certificate"),
|
|
2574
|
-
requireTimestamp(json, "signedAt", "The signedAt of a certificate"),
|
|
2575
|
-
requireString(json, "algorithm"),
|
|
2576
|
-
requireString(json, "keyId"),
|
|
2577
|
-
requireString(json, "value"),
|
|
2578
|
-
json
|
|
2579
|
-
);
|
|
3950
|
+
return new _SigningKeyCertificate(roamingNetworkOperatorId, signingKey, signedAt, algorithm, keyId, signature, json);
|
|
2580
3951
|
}
|
|
2581
3952
|
/** The signature input: the certificate without `value`, with its `@context`, its signing key embedded without its. */
|
|
2582
3953
|
signingBytes() {
|
|
@@ -2614,6 +3985,9 @@ var SigningKeyCertificate = class _SigningKeyCertificate {
|
|
|
2614
3985
|
|
|
2615
3986
|
// src/network/roamingNetwork.ts
|
|
2616
3987
|
var ROAMING_NETWORK_CONTEXT = CONTEXT_PREFIX + "roamingNetwork/v1";
|
|
3988
|
+
var KeyStatementError = class extends POIError {
|
|
3989
|
+
};
|
|
3990
|
+
var sameId2 = (left, right) => ignoringCase(trimmed(left)) === ignoringCase(trimmed(right));
|
|
2617
3991
|
var holdersOf = (keys) => new Set(keys.map((key) => key.holderOrUnnamed));
|
|
2618
3992
|
var RoamingNetworkOperator = class _RoamingNetworkOperator {
|
|
2619
3993
|
constructor(id, identityKeys, minConsensus, keyStatement, signingKeyCertificates, json) {
|
|
@@ -2647,68 +4021,72 @@ var RoamingNetworkOperator = class _RoamingNetworkOperator {
|
|
|
2647
4021
|
*/
|
|
2648
4022
|
static parse(value, roamingNetworkId) {
|
|
2649
4023
|
const json = requireObject(value, "The roaming network operator");
|
|
2650
|
-
const id =
|
|
4024
|
+
const id = mandatoryText(json, "@id", "The identification of the roaming network operator");
|
|
2651
4025
|
checkContext(json, CONTEXT_PREFIX + "roamingNetwork/operator/v1", `the roaming network operator '${id}'`);
|
|
2652
4026
|
if (get(json, "signingKeys") !== void 0)
|
|
2653
4027
|
throw new POIError("The signing keys of a roaming network operator are those of its signingKeyCertificates!");
|
|
2654
4028
|
const identityKeys = partyKeysOf(json, `the roaming network operator '${id}'`, "a roaming network operator").identityKeys;
|
|
2655
|
-
const minConsensus = get(json, "minConsensus") === void 0 ? 1 : requireInteger(json, "minConsensus", 1, 255,
|
|
2656
|
-
const keyStatement = get(json, "keyStatement") === void 0 ? void 0 : KeyStatement.parse(get(json, "keyStatement"));
|
|
4029
|
+
const minConsensus = get(json, "minConsensus") === void 0 ? 1 : requireInteger(json, "minConsensus", 1, 255, "The minConsensus of a roaming network operator");
|
|
4030
|
+
const keyStatement = get(json, "keyStatement") === void 0 ? void 0 : KeyStatement.parse(asRead(requireObject(get(json, "keyStatement"), "The key statement"), "keyStatement"));
|
|
2657
4031
|
const certificatesJSON = get(json, "signingKeyCertificates");
|
|
2658
4032
|
const certificates = certificatesJSON === void 0 ? [] : (() => {
|
|
2659
4033
|
if (!isArray(certificatesJSON) || certificatesJSON.length === 0)
|
|
2660
4034
|
throw new POIError("The signingKeyCertificates of a roaming network operator must be a nonempty array!");
|
|
2661
|
-
return certificatesJSON.map((certificate) => SigningKeyCertificate.parse(certificate));
|
|
4035
|
+
return certificatesJSON.map((certificate) => SigningKeyCertificate.parse(asRead(certificate, "signingKeyCertificates")));
|
|
2662
4036
|
})();
|
|
4037
|
+
const invalid = (error) => new POIError(`The given JSON representation of a roaming network operator is invalid: ${error}`);
|
|
4038
|
+
const certifications = certificates.map((certificate) => `${certificate.signingKey.id}/${certificate.keyId}`);
|
|
4039
|
+
if (new Set(certifications).size !== certifications.length)
|
|
4040
|
+
throw invalid(`An certificate of a signing key of the roaming network operator '${id}' must not be given twice!`);
|
|
2663
4041
|
const certified = /* @__PURE__ */ new Map();
|
|
2664
4042
|
for (const certificate of certificates) {
|
|
2665
4043
|
const before = certified.get(certificate.signingKey.id);
|
|
2666
|
-
if (before !== void 0 && !sameValue(without(before.json, "@context"), without(certificate.signingKey.json, "@context")))
|
|
2667
|
-
throw
|
|
4044
|
+
if (before !== void 0 && !sameValue(without(before.json, "@context"), without(asRead(certificate.signingKey.json, "signingKey"), "@context")))
|
|
4045
|
+
throw invalid(`An signing key of the roaming network operator '${id}' must not be given twice!`);
|
|
2668
4046
|
certified.set(certificate.signingKey.id, certificate.signingKey);
|
|
2669
4047
|
}
|
|
2670
4048
|
const signingKeys = [...certified.values()];
|
|
2671
|
-
const both = signingKeys.find((key) => identityKeys.some((identityKey) => identityKey.id === key.id));
|
|
4049
|
+
const both = [...signingKeys].sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0).find((key) => identityKeys.some((identityKey) => identityKey.id === key.id));
|
|
2672
4050
|
if (both !== void 0)
|
|
2673
|
-
throw
|
|
4051
|
+
throw invalid(`The key '${both.id}' of the roaming network operator '${id}' must not be both a signing and an identity key!`);
|
|
2674
4052
|
for (const [kind, keys] of [["signing", signingKeys], ["identity", identityKeys]]) {
|
|
2675
4053
|
const holders = holdersOf(keys).size;
|
|
2676
4054
|
if (holders === 0) {
|
|
2677
4055
|
if (minConsensus > 1)
|
|
2678
|
-
throw
|
|
4056
|
+
throw invalid(`The minConsensus ${minConsensus} of the roaming network operator '${id}' needs ${kind} keys of as many holders!`);
|
|
2679
4057
|
continue;
|
|
2680
4058
|
}
|
|
2681
4059
|
if (minConsensus > holders)
|
|
2682
|
-
throw
|
|
4060
|
+
throw invalid(`The minConsensus ${minConsensus} of the roaming network operator '${id}' needs ${kind} keys of as many holders, not of ${holders}!`);
|
|
2683
4061
|
if (2 * minConsensus <= holders)
|
|
2684
|
-
throw
|
|
4062
|
+
throw invalid(`The minConsensus ${minConsensus} of the roaming network operator '${id}' must be more than half of the ${holders} holders of its ${kind} keys!`);
|
|
2685
4063
|
}
|
|
4064
|
+
if (keyStatement !== void 0 && !sameId2(keyStatement.roamingNetworkId, roamingNetworkId))
|
|
4065
|
+
throw new KeyStatementError(`The key statement of the roaming network operator '${id}' is one of the roaming network '${keyStatement.roamingNetworkId}', not of '${roamingNetworkId}'!`);
|
|
2686
4066
|
for (const certificate of certificates) {
|
|
2687
|
-
if (certificate.roamingNetworkOperatorId
|
|
2688
|
-
throw new
|
|
4067
|
+
if (!sameId2(certificate.roamingNetworkOperatorId, id))
|
|
4068
|
+
throw new KeyStatementError(`The certificate of the signing key '${certificate.signingKey.id}' of the roaming network operator '${id}' is one of '${certificate.roamingNetworkOperatorId}'!`);
|
|
2689
4069
|
try {
|
|
2690
4070
|
certificate.verify(identityKeys);
|
|
2691
4071
|
} catch (e) {
|
|
2692
|
-
throw new
|
|
4072
|
+
throw new KeyStatementError(`The roaming network operator '${id}': ${e instanceof Error ? e.message : String(e)}`);
|
|
2693
4073
|
}
|
|
2694
4074
|
}
|
|
2695
4075
|
if (keyStatement !== void 0) {
|
|
2696
|
-
if (keyStatement.
|
|
2697
|
-
throw new
|
|
2698
|
-
|
|
2699
|
-
throw new POIError(`The key statement of the roaming network operator '${id}' is one of '${keyStatement.roamingNetworkOperatorId}'!`);
|
|
2700
|
-
const unknown = keyStatement.identityKeys.find((key) => !identityKeys.some((identityKey) => sameValue(without(identityKey.json, "@context"), without(key.json, "@context"))));
|
|
4076
|
+
if (!sameId2(keyStatement.roamingNetworkOperatorId, id))
|
|
4077
|
+
throw new KeyStatementError(`The key statement of the roaming network operator '${id}' is one of '${keyStatement.roamingNetworkOperatorId}'!`);
|
|
4078
|
+
const unknown = keyStatement.identityKeys.find((key) => !identityKeys.some((identityKey) => sameValue(without(asRead(identityKey.json, "identityKeys"), "@context"), without(key.json, "@context"))));
|
|
2701
4079
|
if (unknown !== void 0)
|
|
2702
|
-
throw new
|
|
4080
|
+
throw new KeyStatementError(`The key statement of the roaming network operator '${id}' names the identity key '${unknown.id}', which is not one of its identity keys!`);
|
|
2703
4081
|
if (keyStatement.minConsensus !== minConsensus)
|
|
2704
|
-
throw new
|
|
4082
|
+
throw new KeyStatementError(`The key statement of the roaming network operator '${id}' states the minConsensus ${keyStatement.minConsensus}, not its ${minConsensus}!`);
|
|
2705
4083
|
try {
|
|
2706
4084
|
const holders = /* @__PURE__ */ new Map();
|
|
2707
4085
|
for (const key of identityKeys)
|
|
2708
4086
|
holders.set(key.holderOrUnnamed, [...holders.get(key.holderOrUnnamed) ?? [], key.id]);
|
|
2709
4087
|
keyStatement.verifyHolders([...holders.values()], identityKeys, { minConsensus });
|
|
2710
4088
|
} catch (e) {
|
|
2711
|
-
throw new
|
|
4089
|
+
throw new KeyStatementError(minConsensus > 1 ? `The key statement of the roaming network operator '${id}' is not signed by identity keys of ${minConsensus} of its holders: ${e instanceof Error ? e.message : String(e)}` : `The key statement of the roaming network operator '${id}' is not signed by one of its identity keys: ${e instanceof Error ? e.message : String(e)}`);
|
|
2712
4090
|
}
|
|
2713
4091
|
}
|
|
2714
4092
|
return new _RoamingNetworkOperator(id, identityKeys, minConsensus, keyStatement, certificates, json);
|
|
@@ -2734,12 +4112,25 @@ var RoamingNetwork = class _RoamingNetwork {
|
|
|
2734
4112
|
* revision, firmware version or serial number WWCP_POI refuses (`invalidVersionText`), nor a certificate WWCP_POI
|
|
2735
4113
|
* refuses to read (`invalidCertificates`), nor an EV Taler merchant or payment options it refuses (`invalidEVTaler`),
|
|
2736
4114
|
* nor keys of a party it refuses (`invalidPartyKeys`),
|
|
4115
|
+
* nor what WWCP_POI takes and writes otherwise than the content holds it (`notWrittenAsHeld`),
|
|
2737
4116
|
* also the version a change set leads to. Its `eTags` may be left out: what binds a version is the commit whose ETags it
|
|
2738
4117
|
* has (`matchesCommitETags`).
|
|
2739
4118
|
*/
|
|
2740
4119
|
static parse(value) {
|
|
4120
|
+
return _RoamingNetwork.read(value, "version");
|
|
4121
|
+
}
|
|
4122
|
+
/**
|
|
4123
|
+
* Reads the version the given change set leads to, its content after the last change, and refuses it as `parse`
|
|
4124
|
+
* does, but in the words WWCP_POI3 names what it refuses of the network there (RoamingNetwork.ChangeSets.cs): its
|
|
4125
|
+
* operator and the identifications it keeps unique within the roaming network bare, not as arguments of its
|
|
4126
|
+
* constructor.
|
|
4127
|
+
*/
|
|
4128
|
+
static afterChangeSet(content) {
|
|
4129
|
+
return _RoamingNetwork.read(content, "change set");
|
|
4130
|
+
}
|
|
4131
|
+
static read(value, of) {
|
|
2741
4132
|
const json = requireObject(value, "A roaming network");
|
|
2742
|
-
const id =
|
|
4133
|
+
const id = mandatoryText(json, "@id", "The identification of a roaming network");
|
|
2743
4134
|
checkContext(json, ROAMING_NETWORK_CONTEXT, `the roaming network '${id}'`);
|
|
2744
4135
|
if (get(json, "signingKeys") !== void 0 || get(json, "identityKeys") !== void 0)
|
|
2745
4136
|
throw new POIError(`The roaming network '${id}' names no keys of its own: those of its operator are its operator's!`);
|
|
@@ -2748,13 +4139,26 @@ var RoamingNetwork = class _RoamingNetwork {
|
|
|
2748
4139
|
let treeHashAlgorithms = ["sha256"];
|
|
2749
4140
|
const treeHashAlgorithmsJSON = get(json, "treeHashAlgorithms");
|
|
2750
4141
|
if (treeHashAlgorithmsJSON !== void 0) {
|
|
2751
|
-
if (!isArray(treeHashAlgorithmsJSON)
|
|
2752
|
-
throw new POIError(
|
|
4142
|
+
if (!isArray(treeHashAlgorithmsJSON))
|
|
4143
|
+
throw new POIError("The 'treeHashAlgorithms' must be a JSON array of hash algorithms!");
|
|
4144
|
+
const unknown = treeHashAlgorithmsJSON.find((algorithm) => !isHashAlgorithm(algorithm));
|
|
4145
|
+
if (unknown !== void 0)
|
|
4146
|
+
throw new POIError(`Unknown tree hash algorithm '${asText(unknown)}': sha256, sha384 or sha512!`);
|
|
4147
|
+
if (treeHashAlgorithmsJSON.length === 0)
|
|
4148
|
+
throw new POIError("The 'treeHashAlgorithms' must name at least one hash algorithm!");
|
|
4149
|
+
if (new Set(treeHashAlgorithmsJSON).size !== treeHashAlgorithmsJSON.length)
|
|
4150
|
+
throw new POIError("The 'treeHashAlgorithms' must not name a hash algorithm twice!");
|
|
2753
4151
|
treeHashAlgorithms = treeHashAlgorithmsJSON;
|
|
2754
4152
|
}
|
|
2755
4153
|
const operatorJSON = get(json, "operator");
|
|
2756
|
-
const operator = operatorJSON === void 0 ? void 0 :
|
|
2757
|
-
|
|
4154
|
+
const operator = operatorJSON === void 0 ? void 0 : (() => {
|
|
4155
|
+
try {
|
|
4156
|
+
return RoamingNetworkOperator.parse(operatorJSON, id);
|
|
4157
|
+
} catch (e) {
|
|
4158
|
+
throw e instanceof KeyStatementError && of === "version" ? new POIError(inRoamingNetwork(e.message, "Operator")) : e;
|
|
4159
|
+
}
|
|
4160
|
+
})();
|
|
4161
|
+
const refusal = invalidIdentification(content) ?? invalidVersionText(content) ?? invalidCertificates(content) ?? invalidEVTaler(content) ?? invalidPartyKeys(content) ?? duplicateIdentification(content, of) ?? notWrittenAsHeld(content);
|
|
2758
4162
|
if (refusal !== void 0)
|
|
2759
4163
|
throw new POIError(refusal);
|
|
2760
4164
|
const network = new _RoamingNetwork(id, content, operator, treeHashAlgorithms);
|
|
@@ -3051,6 +4455,125 @@ function checkTrustAnchor(urls, holders, minConsensus) {
|
|
|
3051
4455
|
return required(networkId, "A trust anchor names at least one URL of its roaming network!");
|
|
3052
4456
|
}
|
|
3053
4457
|
|
|
4458
|
+
// src/proofs/trustContext.ts
|
|
4459
|
+
var TrustContext = class _TrustContext {
|
|
4460
|
+
constructor(anchor, holders, statement, evaluatedAt) {
|
|
4461
|
+
this.evaluatedAt = evaluatedAt;
|
|
4462
|
+
this.anchor = frozenAnchor(anchor);
|
|
4463
|
+
this.trustedHolders = Object.freeze(holders.map((holder) => Object.freeze([...holder])));
|
|
4464
|
+
this.authorizedAnchor = frozenAnchor(TrustAnchor.create(
|
|
4465
|
+
anchor.id,
|
|
4466
|
+
anchor.urls,
|
|
4467
|
+
holders.filter((holder) => holder.length > 0),
|
|
4468
|
+
anchor.minConsensus,
|
|
4469
|
+
anchor.name,
|
|
4470
|
+
anchor.description
|
|
4471
|
+
));
|
|
4472
|
+
this.roamingNetworkId = statement.roamingNetworkId;
|
|
4473
|
+
this.roamingNetworkOperatorId = statement.roamingNetworkOperatorId;
|
|
4474
|
+
this.keyStatementDigest = statementDigest(statement);
|
|
4475
|
+
this.requiredConsensus = Math.max(anchor.minConsensus, statement.minConsensus);
|
|
4476
|
+
this.validUntil = statement.validUntil;
|
|
4477
|
+
Object.freeze(this);
|
|
4478
|
+
}
|
|
4479
|
+
evaluatedAt;
|
|
4480
|
+
anchor;
|
|
4481
|
+
authorizedAnchor;
|
|
4482
|
+
trustedHolders;
|
|
4483
|
+
roamingNetworkId;
|
|
4484
|
+
roamingNetworkOperatorId;
|
|
4485
|
+
keyStatementDigest;
|
|
4486
|
+
requiredConsensus;
|
|
4487
|
+
validUntil;
|
|
4488
|
+
static create(anchor, statement, options) {
|
|
4489
|
+
const result = _TrustContext.evaluate(anchor, statement, options);
|
|
4490
|
+
if (result.context === void 0)
|
|
4491
|
+
throw new POIError(result.verificationError ?? "No locally authorized trust quorum");
|
|
4492
|
+
return result.context;
|
|
4493
|
+
}
|
|
4494
|
+
static evaluate(anchor, statement, options) {
|
|
4495
|
+
const at = timeOf(options.at);
|
|
4496
|
+
if (!Number.isFinite(at))
|
|
4497
|
+
throw new POIError("Invalid trust evaluation time");
|
|
4498
|
+
if (statement.roamingNetworkId !== anchor.id)
|
|
4499
|
+
throw new POIError("The key statement belongs to another roaming network");
|
|
4500
|
+
const trusted = new Set(options.trustedIdentityKeyIds);
|
|
4501
|
+
const holders = anchor.holders.map((holder) => holder.filter((id) => trusted.has(id)));
|
|
4502
|
+
const pool = [...statement.identityKeys, ...options.otherIdentityKeys ?? []];
|
|
4503
|
+
const signedBy = new Set(statement.signatures.map((signature) => signature.keyId));
|
|
4504
|
+
const trustedHolderCount = holders.filter((holder) => holder.some((id) => signedBy.has(id))).length;
|
|
4505
|
+
let signaturesValid = true;
|
|
4506
|
+
let keysValid = true;
|
|
4507
|
+
let verificationError;
|
|
4508
|
+
try {
|
|
4509
|
+
for (const signature of statement.signatures) {
|
|
4510
|
+
const key = pool.find((key2) => key2.id === signature.keyId);
|
|
4511
|
+
if (key === void 0)
|
|
4512
|
+
throw new POIError("The public key of a signer was not provided");
|
|
4513
|
+
statement.verifySignature(signature, key);
|
|
4514
|
+
if (!key.isValidAt(statement.signedAt))
|
|
4515
|
+
keysValid = false;
|
|
4516
|
+
}
|
|
4517
|
+
} catch (error) {
|
|
4518
|
+
signaturesValid = false;
|
|
4519
|
+
verificationError = error instanceof Error ? error.message : String(error);
|
|
4520
|
+
}
|
|
4521
|
+
let quorumValid = false;
|
|
4522
|
+
try {
|
|
4523
|
+
statement.verifyHolders(holders, options.otherIdentityKeys, { minConsensus: anchor.minConsensus, at });
|
|
4524
|
+
quorumValid = true;
|
|
4525
|
+
} catch (error) {
|
|
4526
|
+
verificationError ??= error instanceof Error ? error.message : String(error);
|
|
4527
|
+
}
|
|
4528
|
+
const validityValid = keysValid && statement.isValidAt(at);
|
|
4529
|
+
return Object.freeze({
|
|
4530
|
+
signatures: signaturesValid ? "valid" : "invalid",
|
|
4531
|
+
signers: trustedHolderCount > 0 ? "valid" : "invalid",
|
|
4532
|
+
quorum: quorumValid ? "valid" : "invalid",
|
|
4533
|
+
validity: validityValid ? "valid" : "invalid",
|
|
4534
|
+
trustedHolderCount,
|
|
4535
|
+
requiredConsensus: Math.max(anchor.minConsensus, statement.minConsensus),
|
|
4536
|
+
signatureCount: statement.signatures.length,
|
|
4537
|
+
canTrustKeys: signaturesValid && validityValid,
|
|
4538
|
+
...verificationError === void 0 ? {} : { verificationError },
|
|
4539
|
+
...signaturesValid && quorumValid && validityValid ? { context: new _TrustContext(anchor, holders, statement, at) } : {}
|
|
4540
|
+
});
|
|
4541
|
+
}
|
|
4542
|
+
/** The context represents exactly one evaluation time; a different time requires fresh local decisions. */
|
|
4543
|
+
evaluationTime(at) {
|
|
4544
|
+
if (at !== void 0 && timeOf(at) !== this.evaluatedAt)
|
|
4545
|
+
throw new POIError("Recreate the trust context for a different evaluation time");
|
|
4546
|
+
return this.evaluatedAt;
|
|
4547
|
+
}
|
|
4548
|
+
/** Rechecks supplied signatures and binds their signed content to the verified statement. */
|
|
4549
|
+
verifyStatement(statement, otherIdentityKeys = [], at) {
|
|
4550
|
+
const time = this.evaluationTime(at);
|
|
4551
|
+
if (statement.roamingNetworkId !== this.roamingNetworkId || statement.roamingNetworkOperatorId !== this.roamingNetworkOperatorId || statementDigest(statement) !== this.keyStatementDigest)
|
|
4552
|
+
throw new POIError("The operator or key statement differs from the authorized trust context");
|
|
4553
|
+
return statement.verifyHolders(
|
|
4554
|
+
this.trustedHolders,
|
|
4555
|
+
otherIdentityKeys,
|
|
4556
|
+
{ minConsensus: this.anchor.minConsensus, at: time }
|
|
4557
|
+
);
|
|
4558
|
+
}
|
|
4559
|
+
};
|
|
4560
|
+
function anchorOf(basis) {
|
|
4561
|
+
return basis instanceof TrustContext ? basis.authorizedAnchor : basis;
|
|
4562
|
+
}
|
|
4563
|
+
function statementDigest(statement) {
|
|
4564
|
+
return toHex(hash("sha256", canonicalJSONBytes(statement.content())));
|
|
4565
|
+
}
|
|
4566
|
+
function frozenAnchor(anchor) {
|
|
4567
|
+
const copy = TrustAnchor.parse(anchor.toQRCode());
|
|
4568
|
+
for (const holder of copy.holders)
|
|
4569
|
+
Object.freeze(holder);
|
|
4570
|
+
Object.freeze(copy.holders);
|
|
4571
|
+
Object.freeze(copy.urls);
|
|
4572
|
+
Object.freeze(copy.name);
|
|
4573
|
+
Object.freeze(copy.description);
|
|
4574
|
+
return Object.freeze(copy);
|
|
4575
|
+
}
|
|
4576
|
+
|
|
3054
4577
|
// src/proofs/attestation.ts
|
|
3055
4578
|
var ATTESTATION_CONTEXT = CONTEXT_PREFIX + "roamingNetwork/attestation/v1";
|
|
3056
4579
|
var MAX_ATTESTATION_VALIDITY = 24 * 60 * 60 * 1e3;
|
|
@@ -3212,13 +4735,14 @@ var ChargingStationProof = class _ChargingStationProof {
|
|
|
3212
4735
|
*
|
|
3213
4736
|
* Attestations of a subject (8.5) attest one entity, not the root: they do not count here.
|
|
3214
4737
|
*/
|
|
3215
|
-
verify(
|
|
3216
|
-
const
|
|
4738
|
+
verify(basis, at) {
|
|
4739
|
+
const anchor = anchorOf(basis);
|
|
4740
|
+
const time = basis instanceof TrustContext ? basis.evaluationTime(at) : timeOf(at);
|
|
3217
4741
|
const networkId = this.roamingNetwork["@id"];
|
|
3218
4742
|
if (networkId !== anchor.id)
|
|
3219
4743
|
throw new POIError(`The trust anchor is one of the roaming network '${anchor.id}'!`);
|
|
3220
4744
|
const { eTag, attested } = this.calculate();
|
|
3221
|
-
const { keyStatement, required: required2, signingKeyOf } = this.certifiedSigningKeys(
|
|
4745
|
+
const { keyStatement, required: required2, signingKeyOf } = this.certifiedSigningKeys(basis, time);
|
|
3222
4746
|
const certifiedSigningKeyOf = (attestation) => signingKeyOf(attestation.keyId, attestation.signedAt);
|
|
3223
4747
|
const counted = [];
|
|
3224
4748
|
const holders = /* @__PURE__ */ new Set();
|
|
@@ -3265,8 +4789,9 @@ var ChargingStationProof = class _ChargingStationProof {
|
|
|
3265
4789
|
* signed and at `at`, and allowed to sign for the party, as attestations are verified. Signatures that do not count are
|
|
3266
4790
|
* ignored, not refused; the other signatures, e.g. of witnesses, are not checked here. Returns the holders that signed.
|
|
3267
4791
|
*/
|
|
3268
|
-
verifyCheckpoint(checkpoint,
|
|
3269
|
-
const
|
|
4792
|
+
verifyCheckpoint(checkpoint, basis, at) {
|
|
4793
|
+
const anchor = anchorOf(basis);
|
|
4794
|
+
const time = basis instanceof TrustContext ? basis.evaluationTime(at) : timeOf(at);
|
|
3270
4795
|
if (this.roamingNetwork["@id"] !== anchor.id || checkpoint.roamingNetworkId !== anchor.id)
|
|
3271
4796
|
throw new POIError(`The trust anchor is one of the roaming network '${anchor.id}'!`);
|
|
3272
4797
|
if (checkpoint.commitId !== this.commitId)
|
|
@@ -3277,7 +4802,7 @@ var ChargingStationProof = class _ChargingStationProof {
|
|
|
3277
4802
|
const { eTag } = this.calculate();
|
|
3278
4803
|
if (!bytesEqual(eTag.digest, named.digest))
|
|
3279
4804
|
throw new POIError(`The proof leads to ${etagToText(eTag)}, not to ${etagToText(named)}!`);
|
|
3280
|
-
const { required: required2, signingKeyOf } = this.certifiedSigningKeys(
|
|
4805
|
+
const { required: required2, signingKeyOf } = this.certifiedSigningKeys(basis, time);
|
|
3281
4806
|
const holders = /* @__PURE__ */ new Set();
|
|
3282
4807
|
for (const signature of checkpoint.signatures) {
|
|
3283
4808
|
const certified = signature.role === "roamingNetworkOperator" ? signingKeyOf(signature.keyId, signature.signedAt) : void 0;
|
|
@@ -3301,7 +4826,8 @@ var ChargingStationProof = class _ChargingStationProof {
|
|
|
3301
4826
|
* and operator and their holders as the trust anchor does, and is valid at `time`; its identity keys are trusted then
|
|
3302
4827
|
* as well. A signing key counts where a trusted identity key of its holder certifies it for this operator.
|
|
3303
4828
|
*/
|
|
3304
|
-
certifiedSigningKeys(
|
|
4829
|
+
certifiedSigningKeys(basis, time) {
|
|
4830
|
+
const anchor = anchorOf(basis);
|
|
3305
4831
|
const networkId = this.roamingNetwork["@id"];
|
|
3306
4832
|
const operator = get(this.roamingNetwork, "operator");
|
|
3307
4833
|
if (!isObject(operator))
|
|
@@ -3316,7 +4842,7 @@ var ChargingStationProof = class _ChargingStationProof {
|
|
|
3316
4842
|
throw new POIError(`The key statement is one of the roaming network '${keyStatement.roamingNetworkId}'!`);
|
|
3317
4843
|
if (keyStatement.roamingNetworkOperatorId !== operatorId)
|
|
3318
4844
|
throw new POIError(`The key statement is one of the roaming network operator '${keyStatement.roamingNetworkOperatorId}', not of '${operatorId}'!`);
|
|
3319
|
-
const { holderOf } = keyStatement.verifyHolders(anchor.holders, operatorIdentityKeys, { minConsensus: anchor.minConsensus, at: time });
|
|
4845
|
+
const { holderOf } = basis instanceof TrustContext ? basis.verifyStatement(keyStatement, operatorIdentityKeys, time) : keyStatement.verifyHolders(anchor.holders, operatorIdentityKeys, { minConsensus: anchor.minConsensus, at: time });
|
|
3320
4846
|
const identityKeys = [...keyStatement.identityKeys, ...operatorIdentityKeys];
|
|
3321
4847
|
const trustedIds = new Set(holderOf.keys());
|
|
3322
4848
|
const signingKeyOf = (keyId, signedAt) => {
|
|
@@ -4142,9 +5668,10 @@ var PARTY_CHILD_TYPES = {
|
|
|
4142
5668
|
property: "transparencySoftware",
|
|
4143
5669
|
what: "transparency software release",
|
|
4144
5670
|
usage: KeyUsages.Software,
|
|
5671
|
+
// Not its version: a new version is a new release, so that a certificate naming a release names the version that
|
|
5672
|
+
// was assessed.
|
|
4145
5673
|
changeable: [
|
|
4146
5674
|
"name",
|
|
4147
|
-
"version",
|
|
4148
5675
|
"openSourceLicenses",
|
|
4149
5676
|
"logo",
|
|
4150
5677
|
"howToUse",
|
|
@@ -4153,7 +5680,8 @@ var PARTY_CHILD_TYPES = {
|
|
|
4153
5680
|
"supportUntil",
|
|
4154
5681
|
"declarationOfConformity",
|
|
4155
5682
|
"softwareBillOfMaterials"
|
|
4156
|
-
]
|
|
5683
|
+
],
|
|
5684
|
+
keepsVersion: true
|
|
4157
5685
|
},
|
|
4158
5686
|
ConformityCertificate: {
|
|
4159
5687
|
parentType: "ConformityAssessmentBody",
|
|
@@ -4206,7 +5734,7 @@ var ENERGY_METER_CHILD_TYPES = {
|
|
|
4206
5734
|
changeable: ["name", "description", "dataSource", "energyMeterIds", "customData"]
|
|
4207
5735
|
}
|
|
4208
5736
|
};
|
|
4209
|
-
var
|
|
5737
|
+
var sameId3 = (left, right) => left.toUpperCase() === right.toUpperCase();
|
|
4210
5738
|
var OPERATOR_CHILD_ARRAYS = {
|
|
4211
5739
|
ChargingTariff: "chargingTariffs",
|
|
4212
5740
|
EVSETemplate: "EVSETemplates",
|
|
@@ -4220,87 +5748,10 @@ var OPERATOR_CHILD_ARRAYS = {
|
|
|
4220
5748
|
};
|
|
4221
5749
|
var TARIFF_TYPES = /* @__PURE__ */ new Set(["ChargingTariff", "ChargingTariffTemplate", "ChargingTariffGroup", "ChargingTariffOffer"]);
|
|
4222
5750
|
var INFRASTRUCTURE_TYPES = /* @__PURE__ */ new Set([...Object.keys(OPERATOR_CHILD_ARRAYS), "ChargingPool", "ChargingStation", "EVSE"]);
|
|
4223
|
-
var idOf4 = (value) => isObject(value) && typeof value["@id"] === "string" ? value["@id"] : "";
|
|
4224
|
-
var ORDERED_TEXTS = /* @__PURE__ */ new Set([
|
|
4225
|
-
"facilities",
|
|
4226
|
-
"paymentOptions",
|
|
4227
|
-
"uiFeatures",
|
|
4228
|
-
"features",
|
|
4229
|
-
"parkingRestrictions",
|
|
4230
|
-
"services",
|
|
4231
|
-
"standards",
|
|
4232
|
-
"nutsCodes",
|
|
4233
|
-
"vehicleTypes",
|
|
4234
|
-
"euVehicleCategories",
|
|
4235
|
-
"parkingSpaceIds",
|
|
4236
|
-
"certificateIds",
|
|
4237
|
-
"chargingTariffIds",
|
|
4238
|
-
"acceptedEMobilityProviderIds",
|
|
4239
|
-
"paymentMeans",
|
|
4240
|
-
"paymentBrands",
|
|
4241
|
-
"signatureMethods",
|
|
4242
|
-
"connectorTypes",
|
|
4243
|
-
"EVSEIds",
|
|
4244
|
-
"chargingStationIds",
|
|
4245
|
-
"chargingPoolIds",
|
|
4246
|
-
"energyMeterIds",
|
|
4247
|
-
"EVSEGroupIds",
|
|
4248
|
-
"chargingStationGroupIds",
|
|
4249
|
-
"chargingPoolGroupIds",
|
|
4250
|
-
"chargingStationOperatorIds",
|
|
4251
|
-
"eMobilityProviderIds",
|
|
4252
|
-
"parkingSensorIds",
|
|
4253
|
-
"parkingProductIds",
|
|
4254
|
-
"measurands",
|
|
4255
|
-
"notifiedFor",
|
|
4256
|
-
"verifiedTransparencySoftwareIds",
|
|
4257
|
-
"compatibleTransparencySoftwareIds",
|
|
4258
|
-
"cardTypes",
|
|
4259
|
-
"dimensions",
|
|
4260
|
-
"usages"
|
|
4261
|
-
]);
|
|
4262
|
-
var DAYS_OF_WEEK = ["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY", "SUNDAY"];
|
|
4263
|
-
var TIMESTAMP_PROPERTIES = /* @__PURE__ */ new Set(["created", "lastChange", "validFrom", "validUntil", "notBefore", "notAfter", "signedAt", "supportUntil"]);
|
|
4264
|
-
var TIMESTAMP3 = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
|
|
4265
|
-
function orderKeys(items, property) {
|
|
4266
|
-
if (property === "signingKeyCertificates" && items.every(isObject))
|
|
4267
|
-
return items.map((item) => `${idOf4(isObject(item) ? item["signingKey"] : void 0)}\0${isObject(item) ? asText(item["keyId"]) : ""}`);
|
|
4268
|
-
if (property === "authenticationModes" && items.every(isObject))
|
|
4269
|
-
return items.map((item) => isObject(item) ? asText(item["type"]) : "");
|
|
4270
|
-
if (property === "transparencySoftwareStatus" && items.every(isObject))
|
|
4271
|
-
return items.map((item) => isObject(item) ? asText(item["transparencySoftwareId"]) : "");
|
|
4272
|
-
if (property === "exchanges" && items.every(isObject))
|
|
4273
|
-
return items.map((item) => isObject(item) ? asText(item["masterPublicKey"]) : "");
|
|
4274
|
-
if (property === "daysOfWeek")
|
|
4275
|
-
return items.map((item) => String(DAYS_OF_WEEK.indexOf(typeof item === "string" ? item : "")).padStart(2, "0"));
|
|
4276
|
-
if (items.length > 0 && items.every((item) => isObject(item) && typeof item["@id"] === "string"))
|
|
4277
|
-
return items.map(idOf4);
|
|
4278
|
-
if (property !== void 0 && ORDERED_TEXTS.has(property) && items.every((item) => typeof item === "string"))
|
|
4279
|
-
return items.map((item) => typeof item === "string" ? item : "");
|
|
4280
|
-
return void 0;
|
|
4281
|
-
}
|
|
4282
5751
|
function asGiven(value, property, where) {
|
|
4283
|
-
const
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
return;
|
|
4287
|
-
if (isArray(item)) {
|
|
4288
|
-
const keys = orderKeys(item, name);
|
|
4289
|
-
if (keys?.some((key, index) => index > 0 && ordinal(keys[index - 1] ?? "", key) >= 0) === true)
|
|
4290
|
-
throw notHeld(path, "its elements are in the order the content holds them in, each once");
|
|
4291
|
-
item.forEach((element, index) => {
|
|
4292
|
-
check2(element, void 0, `${path}[${String(index)}]`);
|
|
4293
|
-
});
|
|
4294
|
-
} else if (isObject(item)) {
|
|
4295
|
-
for (const [key, element] of Object.entries(item)) {
|
|
4296
|
-
if (key === "@context")
|
|
4297
|
-
throw notHeld(path, "embedded, an object names no JSON-LD context");
|
|
4298
|
-
check2(element, key, path === "" ? key : `${path}.${key}`);
|
|
4299
|
-
}
|
|
4300
|
-
} else if (typeof item === "string" && name !== void 0 && TIMESTAMP_PROPERTIES.has(name) && !TIMESTAMP3.test(item))
|
|
4301
|
-
throw notHeld(path, "a timestamp is UTC to the millisecond, yyyy-MM-ddTHH:mm:ss.fffZ");
|
|
4302
|
-
};
|
|
4303
|
-
check2(value, property, property ?? "");
|
|
5752
|
+
const found = notWritten(value, property, property ?? "", "new value");
|
|
5753
|
+
if (found !== void 0)
|
|
5754
|
+
throw new POIError(`${where}: ${found.path === "" ? "it" : `'${found.path}'`} is not given as the content holds it: ${found.reason}!`);
|
|
4304
5755
|
return clone(value);
|
|
4305
5756
|
}
|
|
4306
5757
|
function insertOrdered(array, entity) {
|
|
@@ -4505,7 +5956,7 @@ function applyNetworkArrayChange(content, change, index, createdAt) {
|
|
|
4505
5956
|
function partyChildOf(content, type, childId) {
|
|
4506
5957
|
for (const party of objectsOf4(get(content, type.parents))) {
|
|
4507
5958
|
const children = get(party, type.property);
|
|
4508
|
-
const child = objectsOf4(children).find((item) => typeof item["@id"] === "string" &&
|
|
5959
|
+
const child = objectsOf4(children).find((item) => typeof item["@id"] === "string" && sameId3(item["@id"], childId));
|
|
4509
5960
|
if (child !== void 0)
|
|
4510
5961
|
return { party, children, child };
|
|
4511
5962
|
}
|
|
@@ -4513,14 +5964,14 @@ function partyChildOf(content, type, childId) {
|
|
|
4513
5964
|
}
|
|
4514
5965
|
function partyNamed(content, type, id) {
|
|
4515
5966
|
const property = NETWORK_ARRAYS[type];
|
|
4516
|
-
return property === void 0 || id === void 0 ? void 0 : objectsOf4(get(content, property)).find((party) => typeof party["@id"] === "string" &&
|
|
5967
|
+
return property === void 0 || id === void 0 ? void 0 : objectsOf4(get(content, property)).find((party) => typeof party["@id"] === "string" && sameId3(party["@id"], id));
|
|
4517
5968
|
}
|
|
4518
5969
|
function partyChildIn(content, type, change, index) {
|
|
4519
5970
|
const party = change.parentEntityType === type.parentType ? partyNamed(content, type.parentType, change.parentEntityId) : void 0;
|
|
4520
5971
|
if (party === void 0)
|
|
4521
5972
|
throw new POIError(`Change ${index}: the ${type.what} '${change.entityId}' needs its ${type.parentType}, an existing one!`);
|
|
4522
5973
|
const children = get(party, type.property);
|
|
4523
|
-
const child = objectsOf4(children).find((item) => typeof item["@id"] === "string" &&
|
|
5974
|
+
const child = objectsOf4(children).find((item) => typeof item["@id"] === "string" && sameId3(item["@id"], change.entityId));
|
|
4524
5975
|
return { party, found: child === void 0 ? void 0 : { party, children, child } };
|
|
4525
5976
|
}
|
|
4526
5977
|
function applyPartyChildChange(content, change, index, createdAt) {
|
|
@@ -4547,7 +5998,7 @@ function applyPartyChildChange(content, change, index, createdAt) {
|
|
|
4547
5998
|
} else {
|
|
4548
5999
|
if (found === void 0)
|
|
4549
6000
|
throw new POIError(`Change ${index}: the ${what} does not exist!`);
|
|
4550
|
-
if (change.parentEntityType !== void 0 && (change.parentEntityType !== type.parentType || change.parentEntityId === void 0 || !
|
|
6001
|
+
if (change.parentEntityType !== void 0 && (change.parentEntityType !== type.parentType || change.parentEntityId === void 0 || !sameId3(change.parentEntityId, asText(found.party["@id"]))))
|
|
4551
6002
|
throw new POIError(`Change ${index}: the ${what} belongs to ${type.parentType} '${asText(found.party["@id"])}', not to ${change.parentEntityType} '${change.parentEntityId ?? ""}'!`);
|
|
4552
6003
|
party = found.party;
|
|
4553
6004
|
}
|
|
@@ -4564,7 +6015,7 @@ function applyPartyChild(type, party, found, change, index, what, createdAt) {
|
|
|
4564
6015
|
const property = change.propertyName ?? "";
|
|
4565
6016
|
const child = existing().child;
|
|
4566
6017
|
if (!type.changeable.includes(property))
|
|
4567
|
-
throw new POIError(`Change ${index}: the property '${property}' of a ${type.what} can not be changed!`);
|
|
6018
|
+
throw new POIError(type.keepsVersion === true && property === "version" ? `Change ${index}: the version of the ${what} can not be changed: a new version is a new release!` : `Change ${index}: the property '${property}' of a ${type.what} can not be changed!`);
|
|
4568
6019
|
if (change.kind === "RemoveProperty") {
|
|
4569
6020
|
if (get(child, property) === void 0)
|
|
4570
6021
|
throw new POIError(`Change ${index}: the property '${property}' of the ${what} does not exist!`);
|
|
@@ -4577,7 +6028,7 @@ function applyPartyChild(type, party, found, change, index, what, createdAt) {
|
|
|
4577
6028
|
break;
|
|
4578
6029
|
}
|
|
4579
6030
|
case "Add": {
|
|
4580
|
-
if (!isObject(change.newValue) || typeof change.newValue["@id"] !== "string" || !
|
|
6031
|
+
if (!isObject(change.newValue) || typeof change.newValue["@id"] !== "string" || !sameId3(change.newValue["@id"], change.entityId))
|
|
4581
6032
|
throw new POIError(`Change ${index}: the ${type.what} to add must be a JSON object with the identification '${change.entityId}'!`);
|
|
4582
6033
|
const added = asGiven(without(change.newValue, "lastChange"), void 0, `Change ${String(index)}, the ${what} to add`);
|
|
4583
6034
|
const children = get(party, type.property);
|
|
@@ -4605,7 +6056,7 @@ function energyMeterChildOf(content, type, childId) {
|
|
|
4605
6056
|
for (const [partyType, parties] of [["ChargingStationOperator", "chargingStationOperators"], ["GridOperator", "gridOperators"]])
|
|
4606
6057
|
for (const party of objectsOf4(get(content, parties))) {
|
|
4607
6058
|
const children = get(party, type.property);
|
|
4608
|
-
const child = objectsOf4(children).find((item) => typeof item["@id"] === "string" &&
|
|
6059
|
+
const child = objectsOf4(children).find((item) => typeof item["@id"] === "string" && sameId3(item["@id"], childId));
|
|
4609
6060
|
if (child !== void 0)
|
|
4610
6061
|
return { party, partyType, children, child };
|
|
4611
6062
|
}
|
|
@@ -4626,7 +6077,7 @@ function applyEnergyMeterChildChange(content, change, index, createdAt) {
|
|
|
4626
6077
|
} else {
|
|
4627
6078
|
if (found === void 0)
|
|
4628
6079
|
throw new POIError(`Change ${index}: the ${what} does not exist!`);
|
|
4629
|
-
if (change.parentEntityType !== void 0 && (change.parentEntityType !== found.partyType || change.parentEntityId === void 0 || !
|
|
6080
|
+
if (change.parentEntityType !== void 0 && (change.parentEntityType !== found.partyType || change.parentEntityId === void 0 || !sameId3(change.parentEntityId, asText(found.party["@id"]))))
|
|
4630
6081
|
throw new POIError(`Change ${index}: the ${what} belongs to ${found.partyType} '${asText(found.party["@id"])}', not to ${change.parentEntityType} '${change.parentEntityId ?? ""}'!`);
|
|
4631
6082
|
party = found.party;
|
|
4632
6083
|
}
|
|
@@ -4707,6 +6158,8 @@ function ownerOf(content, change, index, addedEnergyMeterChildren) {
|
|
|
4707
6158
|
if (PARTIES2.has(change.entityType)) {
|
|
4708
6159
|
if (change.kind === "Add" || change.kind === "Remove")
|
|
4709
6160
|
return { kind: "rno", keys: "signing" };
|
|
6161
|
+
if (change.entityType === "ConformityAssessmentBody" && (change.propertyName === "notifiedBodyNumber" || change.propertyName === "notifiedFor"))
|
|
6162
|
+
return { kind: "rno", keys: "signing" };
|
|
4710
6163
|
const id = asText(partyNamed(content, change.entityType, change.entityId)?.["@id"] ?? change.entityId);
|
|
4711
6164
|
return {
|
|
4712
6165
|
kind: "party",
|
|
@@ -4911,12 +6364,27 @@ function applyChangeSet(before, changeSet, options = {}) {
|
|
|
4911
6364
|
if (withoutMerchant2 !== void 0)
|
|
4912
6365
|
throw new POIError(withoutMerchant2);
|
|
4913
6366
|
checkStatedBy(before, content, changeSet);
|
|
6367
|
+
const changedVersion = changedReleaseVersion(before.content, content);
|
|
6368
|
+
if (changedVersion !== void 0)
|
|
6369
|
+
throw new POIError(changedVersion);
|
|
4914
6370
|
content["lastChange"] = createdAt;
|
|
4915
|
-
const after = RoamingNetwork.
|
|
6371
|
+
const after = RoamingNetwork.afterChangeSet(content);
|
|
4916
6372
|
matchETags(changeSet.afterETags, after, "The result does not match the change set");
|
|
4917
6373
|
checkKeyHolders(before, after);
|
|
4918
6374
|
return after;
|
|
4919
6375
|
}
|
|
6376
|
+
function changedReleaseVersion(before, after) {
|
|
6377
|
+
const releasesOf = (content) => objectsOf4(get(content, "transparencySoftwareManufacturers")).flatMap((manufacturer) => objectsOf4(get(manufacturer, "transparencySoftware")));
|
|
6378
|
+
const versionOf2 = (release) => trimmed(asText(get(release, "version") ?? ""));
|
|
6379
|
+
const versions = new Map(releasesOf(before).map((release) => [ignoringCase(asText(release["@id"])), versionOf2(release)]));
|
|
6380
|
+
for (const release of releasesOf(after)) {
|
|
6381
|
+
const was = versions.get(ignoringCase(asText(release["@id"])));
|
|
6382
|
+
const is = versionOf2(release);
|
|
6383
|
+
if (was !== void 0 && ignoringCase(was) !== ignoringCase(is))
|
|
6384
|
+
return `The version of the transparency software release '${asText(release["@id"])}' can not be changed from '${was}' to '${is}': a new version is a new release!`;
|
|
6385
|
+
}
|
|
6386
|
+
return void 0;
|
|
6387
|
+
}
|
|
4920
6388
|
function checkStatedBy(before, content, changeSet) {
|
|
4921
6389
|
const type = required(PARTY_CHILD_TYPES["ConformityCertificate"], "Certificates are children of their bodies!");
|
|
4922
6390
|
const keyless = objectsOf4(get(before.content, type.parents)).filter((body) => objectsOf4(get(body, "signingKeys")).length === 0).map((body) => asText(body["@id"]));
|
|
@@ -4929,7 +6397,7 @@ function checkStatedBy(before, content, changeSet) {
|
|
|
4929
6397
|
const statedBy = get(found.child, "statedBy");
|
|
4930
6398
|
if (statedBy !== void 0 && statedBy !== "roamingNetworkOperator")
|
|
4931
6399
|
throw new POIError(`The certificate '${certificateId}' is stated by its conformity assessment body, or by the roaming network operator in its place, 'roamingNetworkOperator', not by '${asText(statedBy)}'!`);
|
|
4932
|
-
const byOperator = keyless.some((id) =>
|
|
6400
|
+
const byOperator = keyless.some((id) => sameId3(id, bodyId));
|
|
4933
6401
|
if (byOperator !== (statedBy !== void 0))
|
|
4934
6402
|
throw new POIError(byOperator ? `The certificate '${certificateId}' of the conformity assessment body '${bodyId}' without signing keys is stated by the roaming network operator in its place: its statedBy is 'roamingNetworkOperator'!` : `The certificate '${certificateId}' of the conformity assessment body '${bodyId}' is stated by the body itself, with its keys: it names no statedBy!`);
|
|
4935
6403
|
}
|
|
@@ -6928,17 +8396,19 @@ var OperatorTrust = class _OperatorTrust {
|
|
|
6928
8396
|
* Verifies the key statement of the operator of the given version against the trust anchor (A1 step e) and returns the
|
|
6929
8397
|
* trust in its keys. `at` is when the statement must be valid, now by default.
|
|
6930
8398
|
*/
|
|
6931
|
-
static of(
|
|
8399
|
+
static of(basis, network, at) {
|
|
8400
|
+
const anchor = anchorOf(basis);
|
|
6932
8401
|
if (network.id !== anchor.id)
|
|
6933
8402
|
throw new POIError("this is not the roaming network of the trust anchor");
|
|
6934
|
-
return _OperatorTrust.ofOperator(
|
|
8403
|
+
return _OperatorTrust.ofOperator(basis, network.operator, at);
|
|
6935
8404
|
}
|
|
6936
8405
|
/**
|
|
6937
8406
|
* The same from the roaming network operator alone, e.g. as a proof of a charging station gives it (8.4): its key
|
|
6938
8407
|
* statement verified against the trust anchor at `at`.
|
|
6939
8408
|
*/
|
|
6940
|
-
static fromOperatorJSON(
|
|
6941
|
-
|
|
8409
|
+
static fromOperatorJSON(basis, operatorJSON, at) {
|
|
8410
|
+
const anchor = anchorOf(basis);
|
|
8411
|
+
return _OperatorTrust.ofOperator(basis, operatorJSON === void 0 ? void 0 : RoamingNetworkOperator.parse(operatorJSON, anchor.id), at);
|
|
6942
8412
|
}
|
|
6943
8413
|
/**
|
|
6944
8414
|
* The trust in the operator of a later version of a history this trust follows (8.6, *Succession*): its key statement
|
|
@@ -6968,11 +8438,12 @@ var OperatorTrust = class _OperatorTrust {
|
|
|
6968
8438
|
signedBy
|
|
6969
8439
|
);
|
|
6970
8440
|
}
|
|
6971
|
-
static ofOperator(
|
|
8441
|
+
static ofOperator(basis, operator, at) {
|
|
8442
|
+
const anchor = anchorOf(basis);
|
|
6972
8443
|
const statement = operator?.keyStatement;
|
|
6973
8444
|
if (operator === void 0 || statement === void 0)
|
|
6974
8445
|
throw new POIError("the roaming network operator states no keys");
|
|
6975
|
-
const { signedBy, holderOf } = statement.verifyHolders(anchor.holders, operator.identityKeys, { minConsensus: anchor.minConsensus, at: timeOf(at) });
|
|
8446
|
+
const { signedBy, holderOf } = basis instanceof TrustContext ? basis.verifyStatement(statement, operator.identityKeys, at) : statement.verifyHolders(anchor.holders, operator.identityKeys, { minConsensus: anchor.minConsensus, at: timeOf(at) });
|
|
6976
8447
|
return new _OperatorTrust(
|
|
6977
8448
|
anchor,
|
|
6978
8449
|
operator,
|
|
@@ -7051,14 +8522,15 @@ var OperatorTrust = class _OperatorTrust {
|
|
|
7051
8522
|
};
|
|
7052
8523
|
|
|
7053
8524
|
// src/verifier/version.ts
|
|
7054
|
-
function verifyVersion(
|
|
8525
|
+
function verifyVersion(basis, networkJSON, commitJSON, at) {
|
|
8526
|
+
const anchor = anchorOf(basis);
|
|
7055
8527
|
const network = RoamingNetwork.parse(networkJSON);
|
|
7056
8528
|
if (network.id !== anchor.id)
|
|
7057
8529
|
throw new POIError("this is not the roaming network of the trust anchor");
|
|
7058
8530
|
const commit = Commit.parse(commitJSON);
|
|
7059
8531
|
if (commit.roamingNetworkId !== network.id || !network.matchesCommitETags(commit.eTags))
|
|
7060
8532
|
throw new POIError("the commit does not lead to the roaming network");
|
|
7061
|
-
const trust = OperatorTrust.of(
|
|
8533
|
+
const trust = OperatorTrust.of(basis, network, at);
|
|
7062
8534
|
const signedBy = trust.verifyOperatorSignatures(commit.signatures, (signature, key) => {
|
|
7063
8535
|
commit.verifySignature(signature, key);
|
|
7064
8536
|
}, "the commit");
|
|
@@ -7155,6 +8627,7 @@ function verifyChargingStation(anchor, proof, options = {}) {
|
|
|
7155
8627
|
const verified = parsed.verify(anchor, options.at);
|
|
7156
8628
|
const attested = verified.attested;
|
|
7157
8629
|
const warnings = [];
|
|
8630
|
+
const shownAnchor = anchor instanceof TrustContext ? anchor.anchor : anchor;
|
|
7158
8631
|
const found = [];
|
|
7159
8632
|
for (const operator2 of objects2(get(attested, "chargingStationOperators")))
|
|
7160
8633
|
for (const pool2 of objects2(get(operator2, "chargingPools")))
|
|
@@ -7193,7 +8666,7 @@ function verifyChargingStation(anchor, proof, options = {}) {
|
|
|
7193
8666
|
energyMeterModels.set(asText(meter["@id"]), manufactured);
|
|
7194
8667
|
}
|
|
7195
8668
|
const certificates = certificatesOf(attested, station, energyMeters, warnings);
|
|
7196
|
-
for (const [kind, shown3, proven] of [["name",
|
|
8669
|
+
for (const [kind, shown3, proven] of [["name", shownAnchor.name, get(attested, "name")], ["description", shownAnchor.description, get(attested, "description")]])
|
|
7197
8670
|
for (const [language, text] of Object.entries(shown3))
|
|
7198
8671
|
if (!isObject(proven) || get(proven, language) !== text)
|
|
7199
8672
|
warnings.push(`the trust anchor shows the ${kind} '${text}' (${language}), not the one of the network in the proof`);
|
|
@@ -7550,6 +9023,6 @@ var RuntimeStatus = class _RuntimeStatus {
|
|
|
7550
9023
|
}
|
|
7551
9024
|
};
|
|
7552
9025
|
|
|
7553
|
-
export { ATTESTATION_CONTEXT, ArchiveSegment, Attestation, CHANGE_SET_CONTEXT, CHECKPOINT_CONTEXT2 as CHECKPOINT_CONTEXT, CHILD_ARRAYS, COMMIT_CONTEXT2 as COMMIT_CONTEXT, CONTEXT_PREFIX, ChangeSet, ChargingStationProof, Checkpoint, CheckpointProof, Commit, DCCMeasurementResult, DCCResult, DCCStatement, DCC_PERFORMANCE_LOCATIONS, DCOC_MODULES, DDoCNotifiedBody, Decimal, DigitalCalibrationCertificate, DigitalCertificateOfConformity, DigitalDeclarationOfConformity, EPOCH_CONTEXT, EPOCH_LINK_CONTEXT, EPOCH_PROFILES_CONTEXT, EV_TALER_EXCHANGE_CONTEXT, EV_TALER_MERCHANT_CONTEXT, EV_TALER_PAYMENT_MEANS, EV_TALER_PAYMENT_OPTION, EpochProfiles, FIRST_EPOCH, History, KEY_STATEMENT_CONTEXT, KeyStatement, KeyUsages, LIVE_TOPICS, MAX_DECIMAL_SCALE, MAX_PRICE_STATEMENT_SEQUENCE, MERGE_CHANGE_SET_ID_PREFIX, OperatorTrust, POIClient, POIError, POIPublicKey, PROOF_CONTEXT, PriceStatement, PriceStatementProof, QIDigitalDocument, QIDigitalItem, QIDigitalLegislation, QIDigitalManufacturer, QIDigitalModel, QIDigitalPerson, QIDigitalQuantity, QIDigitalSignature, QIDigitalStandard, QI_DIGITAL_CONFORMITIES, ROAMING_NETWORK_CONTEXT, RUNTIME_STATUS_KINDS, RoamingNetwork, RoamingNetworkOperator, RuntimeStatus, SIGNATURE_ALGORITHMS, SIGNING_KEY_CERTIFICATE_CONTEXT, STATUS_UPDATE_CONTEXT, STYX_CANONICAL_JSON, SignatureRoles, SigningKeyCertificate, TRUST_ANCHOR_CONTEXT, TRUST_ANCHOR_QR_PREFIX, TrustAnchor, applyChangeSet, approvesQualitySystem, auditPath, canonicalJSON, canonicalJSONBytes, canonicalString, cborETag, cborToJson, changeSetIdentification, check, checkOwnership, clone, commitsRoot, decodeDeterministicCbor, describeVersion, deterministicCbor, effectiveChargingStationOperator, effectiveContent, effectiveTreeETag, entityDigest, etagToJSON, etagToText, evTalerExchangesAt, evTalerMerchantOf, evTalerTariffOf, fromBase45, fromBase64, fromHex, fromJavaScript, get, hash, isArray, isObject, isTalerPublicKey, jsonETag, jsonToCbor, leafHash, liveRequest, merkleRoot, merkleRootOfLeafHashes, nodeHash, parseArchiveSegmentInfo, parseETag, parseETags, parseEpoch, parseEpochLink, parseEvidence, parseFrame, parseJSON, parseJSONBytes, parseJSONObject, parsePriceStatements, parseStatusUpdate, parseTimestamp, parseTrustedWitnesses, paymentOptionName, prettyJSON, priceStatementChainOf, priceStatementsRoot, prunedTree, qiDigitalContext, rootFromAuditPath, sameETag, sameETags, sameEpoch, sameValue, skeleton, subscribeRequest, toBase45, toBase64, toHex, toTimestamp, verifyChargingStation, verifyCheckpointLine, verifyCheckpointPriceStatements, verifyCheckpointSignatures, verifyEvidence, verifyPriceStatementChain, verifyPriceStatements, verifySegmentLine, verifySignature, verifyVersion };
|
|
9026
|
+
export { ATTESTATION_CONTEXT, ArchiveSegment, Attestation, CHANGE_SET_CONTEXT, CHECKPOINT_CONTEXT2 as CHECKPOINT_CONTEXT, CHILD_ARRAYS, COMMIT_CONTEXT2 as COMMIT_CONTEXT, CONTEXT_PREFIX, ChangeSet, ChargingStationProof, Checkpoint, CheckpointProof, Commit, DCCMeasurementResult, DCCResult, DCCStatement, DCC_PERFORMANCE_LOCATIONS, DCOC_MODULES, DDoCNotifiedBody, Decimal, DigitalCalibrationCertificate, DigitalCertificateOfConformity, DigitalDeclarationOfConformity, EPOCH_CONTEXT, EPOCH_LINK_CONTEXT, EPOCH_PROFILES_CONTEXT, EV_TALER_EXCHANGE_CONTEXT, EV_TALER_MERCHANT_CONTEXT, EV_TALER_PAYMENT_MEANS, EV_TALER_PAYMENT_OPTION, EpochProfiles, FIRST_EPOCH, History, KEY_STATEMENT_CONTEXT, KeyStatement, KeyUsages, LIVE_TOPICS, MAX_DECIMAL_SCALE, MAX_PRICE_STATEMENT_SEQUENCE, MERGE_CHANGE_SET_ID_PREFIX, OperatorTrust, POIClient, POIError, POIPublicKey, PROOF_CONTEXT, PriceStatement, PriceStatementProof, QIDigitalDocument, QIDigitalItem, QIDigitalLegislation, QIDigitalManufacturer, QIDigitalModel, QIDigitalPerson, QIDigitalQuantity, QIDigitalSignature, QIDigitalStandard, QI_DIGITAL_CONFORMITIES, ROAMING_NETWORK_CONTEXT, RUNTIME_STATUS_KINDS, RoamingNetwork, RoamingNetworkOperator, RuntimeStatus, SIGNATURE_ALGORITHMS, SIGNING_KEY_CERTIFICATE_CONTEXT, STATUS_UPDATE_CONTEXT, STYX_CANONICAL_JSON, SignatureRoles, SigningKeyCertificate, TRUST_ANCHOR_CONTEXT, TRUST_ANCHOR_QR_PREFIX, TrustAnchor, TrustContext, applyChangeSet, approvesQualitySystem, auditPath, canonicalJSON, canonicalJSONBytes, canonicalString, cborETag, cborToJson, changeSetIdentification, check, checkOwnership, clone, commitsRoot, decodeDeterministicCbor, describeVersion, deterministicCbor, effectiveChargingStationOperator, effectiveContent, effectiveTreeETag, entityDigest, etagToJSON, etagToText, evTalerExchangesAt, evTalerMerchantOf, evTalerTariffOf, fromBase45, fromBase64, fromHex, fromJavaScript, get, hash, isArray, isObject, isTalerPublicKey, jsonETag, jsonToCbor, leafHash, liveRequest, merkleRoot, merkleRootOfLeafHashes, nodeHash, parseArchiveSegmentInfo, parseETag, parseETags, parseEpoch, parseEpochLink, parseEvidence, parseFrame, parseJSON, parseJSONBytes, parseJSONObject, parsePriceStatements, parseStatusUpdate, parseTimestamp, parseTrustedWitnesses, paymentOptionName, prettyJSON, priceStatementChainOf, priceStatementsRoot, prunedTree, qiDigitalContext, rootFromAuditPath, sameETag, sameETags, sameEpoch, sameValue, skeleton, subscribeRequest, toBase45, toBase64, toHex, toTimestamp, verifyChargingStation, verifyCheckpointLine, verifyCheckpointPriceStatements, verifyCheckpointSignatures, verifyEvidence, verifyPriceStatementChain, verifyPriceStatements, verifySegmentLine, verifySignature, verifyVersion };
|
|
7554
9027
|
//# sourceMappingURL=index.js.map
|
|
7555
9028
|
//# sourceMappingURL=index.js.map
|