@open-charging-cloud/chargy-core 0.9.0 → 0.10.0

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.
@@ -2,6 +2,7 @@ import Decimal from 'decimal.js';
2
2
  import moment from 'moment';
3
3
  import { Buffer as Buffer$1 } from 'buffer';
4
4
  import { fileTypeFromBuffer } from 'file-type';
5
+ import isURL from 'is-url-superb';
5
6
  import jsQR from 'jsqr';
6
7
  import seekBzip from 'seek-bzip';
7
8
 
@@ -8078,11 +8079,16 @@ function CreateWarning(message, level = "low" /* low */) {
8078
8079
  message
8079
8080
  };
8080
8081
  }
8081
- function CreateError(message, level = "high" /* high */) {
8082
- return {
8082
+ function CreateError(message, level = "high" /* high */, code, details) {
8083
+ const error = {
8083
8084
  level,
8084
8085
  message
8085
8086
  };
8087
+ if (code !== void 0)
8088
+ error.code = code;
8089
+ if (details !== void 0)
8090
+ error.details = details;
8091
+ return error;
8086
8092
  }
8087
8093
  function isISessionCryptoResult1(obj) {
8088
8094
  return isObject(obj) && obj["status"] !== void 0;
@@ -9068,6 +9074,20 @@ var ACrypt = class {
9068
9074
  newText.classList.remove("overEntry");
9069
9075
  };
9070
9076
  }
9077
+ // Records why a verification step failed as structured data: a stable reason
9078
+ // key (localized via i18n.json and machine-switchable by the GUI) plus an
9079
+ // optional, language-neutral technical detail. Presentation is left to the GUI.
9080
+ AddVerificationError(cryptoResult, reasonKey, detail) {
9081
+ const details = detail instanceof Error ? detail.message : typeof detail === "string" ? detail : void 0;
9082
+ (cryptoResult.errors ??= []).push(
9083
+ CreateError(
9084
+ this.chargy.GetMultilanguageText(reasonKey),
9085
+ "high" /* high */,
9086
+ reasonKey,
9087
+ details
9088
+ )
9089
+ );
9090
+ }
9071
9091
  };
9072
9092
  var Alfen = class {
9073
9093
  chargy;
@@ -9482,9 +9502,15 @@ var AlfenCrypt01 = class extends ACrypt {
9482
9502
  cryptoResult.publicKey = meter.publicKeys[0]?.value;
9483
9503
  cryptoResult.publicKeyFormat = meter.publicKeys[0]?.format;
9484
9504
  cryptoResult.publicKeySignatures = meter.publicKeys[0]?.signatures;
9505
+ let publicKey;
9506
+ try {
9507
+ publicKey = buf2hex(this.chargy.base32Decode(cryptoResult.publicKey ?? "", "RFC4648"));
9508
+ } catch (exception) {
9509
+ this.AddVerificationError(cryptoResult, "Verification_PublicKeyDecodingFailed", exception);
9510
+ return setResult("InvalidPublicKey" /* InvalidPublicKey */);
9511
+ }
9512
+ let result = false;
9485
9513
  try {
9486
- const publicKey = buf2hex(this.chargy.base32Decode(cryptoResult.publicKey ?? "", "RFC4648"));
9487
- let result = false;
9488
9514
  switch (meter.publicKeys[0]?.algorithm ?? "") {
9489
9515
  case "secp192r1":
9490
9516
  cryptoResult.hashValue = await sha256(cryptoBuffer);
@@ -9529,25 +9555,29 @@ var AlfenCrypt01 = class extends ACrypt {
9529
9555
  );
9530
9556
  break;
9531
9557
  }
9532
- if (result) {
9533
- return setResult("ValidSignature" /* ValidSignature */);
9534
- }
9535
- return setResult("InvalidSignature" /* InvalidSignature */);
9536
- } catch {
9558
+ } catch (exception) {
9559
+ this.AddVerificationError(cryptoResult, "Verification_SignatureMalformed", exception);
9537
9560
  return setResult("InvalidSignature" /* InvalidSignature */);
9538
9561
  }
9539
- } catch {
9562
+ if (result)
9563
+ return setResult("ValidSignature" /* ValidSignature */);
9564
+ this.AddVerificationError(cryptoResult, "Verification_SignatureMismatch");
9565
+ return setResult("InvalidSignature" /* InvalidSignature */);
9566
+ } catch (exception) {
9567
+ this.AddVerificationError(cryptoResult, "Verification_PublicKeyDecodingFailed", exception);
9540
9568
  return setResult("InvalidPublicKey" /* InvalidPublicKey */);
9541
9569
  }
9542
9570
  } else
9543
9571
  return setResult("PublicKeyNotFound" /* PublicKeyNotFound */);
9544
9572
  } else
9545
9573
  return setResult("EnergyMeterNotFound" /* EnergyMeterNotFound */);
9546
- } catch {
9574
+ } catch (exception) {
9575
+ this.AddVerificationError(cryptoResult, "Verification_UnexpectedError", exception);
9547
9576
  return setResult("InvalidSignature" /* InvalidSignature */);
9548
9577
  }
9549
9578
  }
9550
- return {};
9579
+ this.AddVerificationError(cryptoResult, "Verification_SignatureMissing");
9580
+ return setResult("InvalidSignature" /* InvalidSignature */);
9551
9581
  }
9552
9582
  async ViewMeasurement(measurementValue, _errorDiv, introDiv, infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
9553
9583
  const result = measurementValue.result;
@@ -10386,33 +10416,46 @@ var BSMCrypt01 = class extends ACrypt {
10386
10416
  const publicKeyDER = ASN1_PublicKey.decode(Buffer.from(meter.publicKeys[0]?.value ?? "", "hex"), "der");
10387
10417
  publicKey = buf2hex(publicKeyDER.publicKey.data).toLowerCase();
10388
10418
  }
10419
+ let keyPair;
10389
10420
  try {
10390
- if (this.curve.keyFromPublic(publicKey, "hex").verify(
10391
- cryptoResult.sha256value,
10392
- cryptoResult.signature
10393
- )) {
10394
- if (measurementValue.errors && measurementValue.errors.length > 0)
10395
- return setResult("ValidationError" /* ValidationError */);
10396
- return setResult("ValidSignature" /* ValidSignature */);
10397
- }
10398
- if (measurementValue.errors && measurementValue.errors.length > 0)
10399
- return setResult("ValidationError" /* ValidationError */);
10400
- return setResult("InvalidSignature" /* InvalidSignature */);
10401
- } catch {
10421
+ keyPair = this.curve.keyFromPublic(publicKey, "hex");
10422
+ } catch (exception) {
10423
+ this.AddVerificationError(cryptoResult, "Verification_PublicKeyDecodingFailed", exception);
10424
+ return setResult("InvalidPublicKey" /* InvalidPublicKey */);
10425
+ }
10426
+ const keyValidation = keyPair.validate();
10427
+ if (!keyValidation.result) {
10428
+ this.AddVerificationError(cryptoResult, "Verification_PublicKeyNotOnCurve", keyValidation.reason ?? void 0);
10429
+ return setResult("InvalidPublicKey" /* InvalidPublicKey */);
10430
+ }
10431
+ let signatureValid;
10432
+ try {
10433
+ signatureValid = keyPair.verify(cryptoResult.sha256value, cryptoResult.signature);
10434
+ } catch (exception) {
10435
+ this.AddVerificationError(cryptoResult, "Verification_SignatureMalformed", exception);
10402
10436
  return setResult("InvalidSignature" /* InvalidSignature */);
10403
10437
  }
10404
- } catch {
10438
+ if (measurementValue.errors && measurementValue.errors.length > 0)
10439
+ return setResult("ValidationError" /* ValidationError */);
10440
+ if (signatureValid)
10441
+ return setResult("ValidSignature" /* ValidSignature */);
10442
+ this.AddVerificationError(cryptoResult, "Verification_SignatureMismatch");
10443
+ return setResult("InvalidSignature" /* InvalidSignature */);
10444
+ } catch (exception) {
10445
+ this.AddVerificationError(cryptoResult, "Verification_PublicKeyDecodingFailed", exception);
10405
10446
  return setResult("InvalidPublicKey" /* InvalidPublicKey */);
10406
10447
  }
10407
10448
  } else
10408
10449
  return setResult("PublicKeyNotFound" /* PublicKeyNotFound */);
10409
10450
  } else
10410
10451
  return setResult("EnergyMeterNotFound" /* EnergyMeterNotFound */);
10411
- } catch {
10452
+ } catch (exception) {
10453
+ this.AddVerificationError(cryptoResult, "Verification_UnexpectedError", exception);
10412
10454
  return setResult("InvalidSignature" /* InvalidSignature */);
10413
10455
  }
10414
10456
  }
10415
- return {};
10457
+ this.AddVerificationError(cryptoResult, "Verification_SignatureMissing");
10458
+ return setResult("InvalidSignature" /* InvalidSignature */);
10416
10459
  }
10417
10460
  async ViewMeasurement(measurementValue, _errorDiv, introDiv, infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
10418
10461
  if (measurementValue.measurement === void 0)
@@ -10591,35 +10634,7 @@ var BSMCrypt01 = class extends ACrypt {
10591
10634
  if ((value & 1 << 29) != 0) events.push("OEM 15");
10592
10635
  return events;
10593
10636
  }
10594
- // private DecodeStatus(statusValue: string) : Array<string>
10595
- // {
10596
- // const statusArray:string[] = [];
10597
- // try
10598
- // {
10599
- // const status = parseInt(statusValue);
10600
- // if ((status & 1) == 1)
10601
- // statusArray.push("Fehler erkannt");
10602
- // if ((status & 2) == 2)
10603
- // statusArray.push("Synchrone Messwertübermittlung");
10604
- // // Bit 3 is reserved!
10605
- // if ((status & 8) == 8)
10606
- // statusArray.push("System-Uhr ist synchron");
10607
- // else
10608
- // statusArray.push("System-Uhr ist nicht synchron");
10609
- // if ((status & 16) == 16)
10610
- // statusArray.push("Rücklaufsperre aktiv");
10611
- // if ((status & 32) == 32)
10612
- // statusArray.push("Energierichtung -A");
10613
- // if ((status & 64) == 64)
10614
- // statusArray.push("Magnetfeld erkannt");
10615
- // }
10616
- // catch
10617
- // {
10618
- // statusArray.push("Invalid status!");
10619
- // }
10620
- // return statusArray;
10621
- // }
10622
- // //#endregion
10637
+ //#endregion
10623
10638
  };
10624
10639
 
10625
10640
  // src/interfaces/IPublicKeyInfo.ts
@@ -12078,29 +12093,44 @@ var EMHCrypt01 = class extends ACrypt {
12078
12093
  cryptoResult.publicKey = publicKey?.value.toLowerCase();
12079
12094
  cryptoResult.publicKeyFormat = publicKey?.format;
12080
12095
  cryptoResult.publicKeySignatures = publicKey?.signatures;
12096
+ let keyPair;
12081
12097
  try {
12082
- if (this.curve.keyFromPublic(cryptoResult.publicKey ?? "", "hex").verify(
12083
- cryptoResult.sha256value,
12084
- cryptoResult.signature
12085
- )) {
12086
- return setResult("ValidSignature" /* ValidSignature */);
12087
- }
12088
- return setResult("InvalidSignature" /* InvalidSignature */);
12089
- } catch {
12098
+ keyPair = this.curve.keyFromPublic(cryptoResult.publicKey ?? "", "hex");
12099
+ } catch (exception) {
12100
+ this.AddVerificationError(cryptoResult, "Verification_PublicKeyDecodingFailed", exception);
12101
+ return setResult("InvalidPublicKey" /* InvalidPublicKey */);
12102
+ }
12103
+ const keyValidation = keyPair.validate();
12104
+ if (!keyValidation.result) {
12105
+ this.AddVerificationError(cryptoResult, "Verification_PublicKeyNotOnCurve", keyValidation.reason ?? void 0);
12106
+ return setResult("InvalidPublicKey" /* InvalidPublicKey */);
12107
+ }
12108
+ let signatureValid;
12109
+ try {
12110
+ signatureValid = keyPair.verify(cryptoResult.sha256value, cryptoResult.signature);
12111
+ } catch (exception) {
12112
+ this.AddVerificationError(cryptoResult, "Verification_SignatureMalformed", exception);
12090
12113
  return setResult("InvalidSignature" /* InvalidSignature */);
12091
12114
  }
12092
- } catch {
12115
+ if (signatureValid)
12116
+ return setResult("ValidSignature" /* ValidSignature */);
12117
+ this.AddVerificationError(cryptoResult, "Verification_SignatureMismatch");
12118
+ return setResult("InvalidSignature" /* InvalidSignature */);
12119
+ } catch (exception) {
12120
+ this.AddVerificationError(cryptoResult, "Verification_PublicKeyDecodingFailed", exception);
12093
12121
  return setResult("InvalidPublicKey" /* InvalidPublicKey */);
12094
12122
  }
12095
12123
  } else
12096
12124
  return setResult("PublicKeyNotFound" /* PublicKeyNotFound */);
12097
12125
  } else
12098
12126
  return setResult("EnergyMeterNotFound" /* EnergyMeterNotFound */);
12099
- } catch {
12127
+ } catch (exception) {
12128
+ this.AddVerificationError(cryptoResult, "Verification_UnexpectedError", exception);
12100
12129
  return setResult("InvalidSignature" /* InvalidSignature */);
12101
12130
  }
12102
12131
  }
12103
- return {};
12132
+ this.AddVerificationError(cryptoResult, "Verification_SignatureMissing");
12133
+ return setResult("InvalidSignature" /* InvalidSignature */);
12104
12134
  }
12105
12135
  async ViewMeasurement(measurementValue, _errorDiv, introDiv, infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
12106
12136
  if (measurementValue.measurement?.chargingSession?.authorizationStart?.timestamp === void 0) {
@@ -12208,7 +12238,7 @@ var EMHCrypt01 = class extends ACrypt {
12208
12238
  DecodeStatus(statusValue) {
12209
12239
  const statusArray = [];
12210
12240
  try {
12211
- const status = parseInt(statusValue);
12241
+ const status = parseInt(statusValue, 16);
12212
12242
  if ((status & 1) == 1)
12213
12243
  statusArray.push("Fehler erkannt");
12214
12244
  if ((status & 2) == 2)
@@ -12310,29 +12340,44 @@ var GDFCrypt01 = class extends ACrypt {
12310
12340
  cryptoResult.publicKey = publicKey?.value.toLowerCase();
12311
12341
  cryptoResult.publicKeyFormat = publicKey?.format;
12312
12342
  cryptoResult.publicKeySignatures = publicKey?.signatures;
12343
+ let keyPair;
12313
12344
  try {
12314
- if (this.curve.keyFromPublic(cryptoResult.publicKey ?? "", "hex").verify(
12315
- cryptoResult.sha256value,
12316
- cryptoResult.signature
12317
- )) {
12318
- return setResult("ValidSignature" /* ValidSignature */);
12319
- }
12320
- return setResult("InvalidSignature" /* InvalidSignature */);
12321
- } catch {
12345
+ keyPair = this.curve.keyFromPublic(cryptoResult.publicKey ?? "", "hex");
12346
+ } catch (exception) {
12347
+ this.AddVerificationError(cryptoResult, "Verification_PublicKeyDecodingFailed", exception);
12348
+ return setResult("InvalidPublicKey" /* InvalidPublicKey */);
12349
+ }
12350
+ const keyValidation = keyPair.validate();
12351
+ if (!keyValidation.result) {
12352
+ this.AddVerificationError(cryptoResult, "Verification_PublicKeyNotOnCurve", keyValidation.reason ?? void 0);
12353
+ return setResult("InvalidPublicKey" /* InvalidPublicKey */);
12354
+ }
12355
+ let signatureValid;
12356
+ try {
12357
+ signatureValid = keyPair.verify(cryptoResult.sha256value, cryptoResult.signature);
12358
+ } catch (exception) {
12359
+ this.AddVerificationError(cryptoResult, "Verification_SignatureMalformed", exception);
12322
12360
  return setResult("InvalidSignature" /* InvalidSignature */);
12323
12361
  }
12324
- } catch {
12362
+ if (signatureValid)
12363
+ return setResult("ValidSignature" /* ValidSignature */);
12364
+ this.AddVerificationError(cryptoResult, "Verification_SignatureMismatch");
12365
+ return setResult("InvalidSignature" /* InvalidSignature */);
12366
+ } catch (exception) {
12367
+ this.AddVerificationError(cryptoResult, "Verification_PublicKeyDecodingFailed", exception);
12325
12368
  return setResult("InvalidPublicKey" /* InvalidPublicKey */);
12326
12369
  }
12327
12370
  } else
12328
12371
  return setResult("PublicKeyNotFound" /* PublicKeyNotFound */);
12329
12372
  } else
12330
12373
  return setResult("EnergyMeterNotFound" /* EnergyMeterNotFound */);
12331
- } catch {
12374
+ } catch (exception) {
12375
+ this.AddVerificationError(cryptoResult, "Verification_UnexpectedError", exception);
12332
12376
  return setResult("InvalidSignature" /* InvalidSignature */);
12333
12377
  }
12334
12378
  }
12335
- return {};
12379
+ this.AddVerificationError(cryptoResult, "Verification_SignatureMissing");
12380
+ return setResult("InvalidSignature" /* InvalidSignature */);
12336
12381
  }
12337
12382
  async ViewMeasurement(measurementValue, _errorDiv, introDiv, infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
12338
12383
  if (measurementValue.measurement?.chargingSession?.authorizationStart?.timestamp === void 0) {
@@ -12671,19 +12716,38 @@ var MennekesCrypt01 = class extends ACrypt {
12671
12716
  );
12672
12717
  cryptoResult.hashValue = (await sha256(new DataView(signedDataBuffer))).substring(0, 48);
12673
12718
  const publicKey = cleanHex(meter.publicKeys.at(0)?.value ?? measurement.publicKey);
12674
- if (publicKey.length !== 96)
12719
+ if (publicKey.length !== 96) {
12720
+ this.AddVerificationError(cryptoResult, "Verification_PublicKeyDecodingFailed");
12675
12721
  return setResult("InvalidPublicKey" /* InvalidPublicKey */);
12676
- const result = this.curve192r1.keyFromPublic("04" + publicKey, "hex").verify(
12677
- cryptoResult.hashValue.toUpperCase(),
12678
- {
12722
+ }
12723
+ let keyPair;
12724
+ try {
12725
+ keyPair = this.curve192r1.keyFromPublic("04" + publicKey, "hex");
12726
+ } catch (exception) {
12727
+ this.AddVerificationError(cryptoResult, "Verification_PublicKeyDecodingFailed", exception);
12728
+ return setResult("InvalidPublicKey" /* InvalidPublicKey */);
12729
+ }
12730
+ const keyValidation = keyPair.validate();
12731
+ if (!keyValidation.result) {
12732
+ this.AddVerificationError(cryptoResult, "Verification_PublicKeyNotOnCurve", keyValidation.reason ?? void 0);
12733
+ return setResult("InvalidPublicKey" /* InvalidPublicKey */);
12734
+ }
12735
+ let signatureValid;
12736
+ try {
12737
+ signatureValid = keyPair.verify(cryptoResult.hashValue.toUpperCase(), {
12679
12738
  r: signatureExpected.r,
12680
12739
  s: signatureExpected.s
12681
- }
12682
- );
12683
- return setResult(
12684
- result ? "ValidSignature" /* ValidSignature */ : "InvalidSignature" /* InvalidSignature */
12685
- );
12686
- } catch {
12740
+ });
12741
+ } catch (exception) {
12742
+ this.AddVerificationError(cryptoResult, "Verification_SignatureMalformed", exception);
12743
+ return setResult("InvalidSignature" /* InvalidSignature */);
12744
+ }
12745
+ if (signatureValid)
12746
+ return setResult("ValidSignature" /* ValidSignature */);
12747
+ this.AddVerificationError(cryptoResult, "Verification_SignatureMismatch");
12748
+ return setResult("InvalidSignature" /* InvalidSignature */);
12749
+ } catch (exception) {
12750
+ this.AddVerificationError(cryptoResult, "Verification_UnexpectedError", exception);
12687
12751
  return setResult("InvalidSignature" /* InvalidSignature */);
12688
12752
  }
12689
12753
  }
@@ -13661,7 +13725,9 @@ var OCMF = class {
13661
13725
  // "value": ocmfJSONDocument.signature["SD"]
13662
13726
  // }],
13663
13727
  "result": {
13664
- "status": ocmfJSONDocument.validationStatus ?? "Unvalidated" /* Unvalidated */
13728
+ "status": ocmfJSONDocument.validationStatus ?? "Unvalidated" /* Unvalidated */,
13729
+ // Surface the per-document verification diagnostics on the measurement value.
13730
+ ...ocmfJSONDocument.validationErrors && ocmfJSONDocument.validationErrors.length > 0 ? { errors: ocmfJSONDocument.validationErrors } : {}
13665
13731
  },
13666
13732
  "ocmfDocument": ocmfJSONDocument
13667
13733
  });
@@ -13806,6 +13872,20 @@ var OCMF = class {
13806
13872
  // return mergedCTR;
13807
13873
  // }
13808
13874
  // //#endregion
13875
+ // Records why a verification step failed as structured data: a stable reason
13876
+ // key (localized via i18n.json and machine-switchable by the GUI) plus an
13877
+ // optional, language-neutral technical detail. Presentation is left to the GUI.
13878
+ AddValidationError(OCMFJSONDocument, reasonKey, detail) {
13879
+ const details = detail instanceof Error ? detail.message : typeof detail === "string" ? detail : void 0;
13880
+ (OCMFJSONDocument.validationErrors ??= []).push(
13881
+ CreateError(
13882
+ this.chargy.GetMultilanguageText(reasonKey),
13883
+ "high" /* high */,
13884
+ reasonKey,
13885
+ details
13886
+ )
13887
+ );
13888
+ }
13809
13889
  //#region (private) validateOCMFSignature(OCMFJSONDocument, PublicKey, PublicKeyEncoding?)
13810
13890
  async validateOCMFSignature(OCMFJSONDocument, PublicKey, PublicKeyEncoding) {
13811
13891
  try {
@@ -13845,7 +13925,8 @@ var OCMF = class {
13845
13925
  curve = new this.chargy.elliptic.ec("p256");
13846
13926
  break;
13847
13927
  }
13848
- } catch {
13928
+ } catch (exception) {
13929
+ this.AddValidationError(OCMFJSONDocument, "Verification_UnknownSignatureFormat", exception);
13849
13930
  OCMFJSONDocument.validationStatus = "UnknownSignatureFormat" /* UnknownSignatureFormat */;
13850
13931
  return OCMFJSONDocument.validationStatus;
13851
13932
  }
@@ -13922,20 +14003,26 @@ var OCMF = class {
13922
14003
  y: OCMFJSONDocument.publicKey.y
13923
14004
  }, "hex");
13924
14005
  }
13925
- } catch {
14006
+ } catch (exception) {
14007
+ this.AddValidationError(OCMFJSONDocument, "Verification_PublicKeyDecodingFailed", exception);
13926
14008
  OCMFJSONDocument.validationStatus = "InvalidPublicKey" /* InvalidPublicKey */;
13927
14009
  return OCMFJSONDocument.validationStatus;
13928
14010
  }
13929
14011
  try {
13930
14012
  if (publicKey === null)
13931
14013
  throw new Error("Missing public key!");
13932
- OCMFJSONDocument.validationStatus = publicKey.verify(OCMFJSONDocument.hashValue, OCMFJSONDocument.signatureRS) ? "ValidSignature" /* ValidSignature */ : "InvalidSignature" /* InvalidSignature */;
14014
+ const signatureValid = publicKey.verify(OCMFJSONDocument.hashValue, OCMFJSONDocument.signatureRS);
14015
+ if (!signatureValid)
14016
+ this.AddValidationError(OCMFJSONDocument, "Verification_SignatureMismatch");
14017
+ OCMFJSONDocument.validationStatus = signatureValid ? "ValidSignature" /* ValidSignature */ : "InvalidSignature" /* InvalidSignature */;
13933
14018
  return await Promise.resolve(OCMFJSONDocument.validationStatus);
13934
- } catch {
14019
+ } catch (exception) {
14020
+ this.AddValidationError(OCMFJSONDocument, "Verification_SignatureMalformed", exception);
13935
14021
  OCMFJSONDocument.validationStatus = "InvalidSignature" /* InvalidSignature */;
13936
14022
  return OCMFJSONDocument.validationStatus;
13937
14023
  }
13938
- } catch {
14024
+ } catch (exception) {
14025
+ this.AddValidationError(OCMFJSONDocument, "Verification_UnexpectedError", exception);
13939
14026
  OCMFJSONDocument.validationStatus = "InvalidSignature" /* InvalidSignature */;
13940
14027
  return OCMFJSONDocument.validationStatus;
13941
14028
  }
@@ -17538,6 +17625,26 @@ function IsAChargeTransparencyLiveLink(data) {
17538
17625
  function isTOTPConfig(data) {
17539
17626
  return isObject(data) && typeof data["initialSharedSecret"] === "string" && typeof data["timeStep"] === "number";
17540
17627
  }
17628
+
17629
+ // src/interfaces/IURL.ts
17630
+ var IURL_exports = {};
17631
+ __export(IURL_exports, {
17632
+ IsAURL: () => IsAURL,
17633
+ IsValidURL: () => IsValidURL,
17634
+ URLContext: () => URLContext
17635
+ });
17636
+ var URLContext = "https://open.charging.cloud/contexts/URL";
17637
+ function IsValidURL(value) {
17638
+ if (!isURL(value))
17639
+ return false;
17640
+ const protocol = new URL(value).protocol;
17641
+ return protocol === "http:" || protocol === "https:";
17642
+ }
17643
+ function IsAURL(data) {
17644
+ if (!isMandatoryJSONObject(data))
17645
+ return false;
17646
+ return data["@context"] === URLContext && typeof data["url"] === "string" && IsValidURL(data["url"]) && (data["method"] === void 0 || typeof data["method"] === "string") && (data["acceptType"] === void 0 || typeof data["acceptType"] === "string") && (data["actions"] === void 0 || Array.isArray(data["actions"]) && data["actions"].every((action) => typeof action === "string")) && (data["serviceTypes"] === void 0 || Array.isArray(data["serviceTypes"]) && data["serviceTypes"].every((serviceType) => typeof serviceType === "string")) && (data["serviceData"] === void 0 || isMandatoryJSONObject(data["serviceData"]));
17647
+ }
17541
17648
  function isRecord(value) {
17542
17649
  return typeof value === "object" && value !== null;
17543
17650
  }
@@ -17769,6 +17876,8 @@ var Chargy = class {
17769
17876
  base32Decode;
17770
17877
  showPKIDetails;
17771
17878
  validationRules;
17879
+ resolveURLs;
17880
+ urlResolver;
17772
17881
  chargingStationOperators = new Array();
17773
17882
  chargingPools = new Array();
17774
17883
  chargingStations = new Array();
@@ -17778,7 +17887,7 @@ var Chargy = class {
17778
17887
  currentCTR = {};
17779
17888
  internalCTR = {};
17780
17889
  //#endregion
17781
- constructor(i18n, UILanguages, elliptic, moment2, asn1, base32Decode, ShowPKIDetails, validationRules = validationRules_default) {
17890
+ constructor(i18n, UILanguages, elliptic, moment2, asn1, base32Decode, ShowPKIDetails, validationRules = validationRules_default, resolveURLs = false, urlResolver) {
17782
17891
  this.i18n = i18n;
17783
17892
  this.uiLanguages = this.NormalizeUILanguages(UILanguages);
17784
17893
  this.elliptic = elliptic;
@@ -17787,6 +17896,38 @@ var Chargy = class {
17787
17896
  this.base32Decode = base32Decode;
17788
17897
  this.showPKIDetails = ShowPKIDetails;
17789
17898
  this.validationRules = validationRules;
17899
+ this.resolveURLs = resolveURLs;
17900
+ this.urlResolver = urlResolver;
17901
+ }
17902
+ async resolveURL(url) {
17903
+ if (!this.resolveURLs)
17904
+ return url;
17905
+ try {
17906
+ if (this.urlResolver != null)
17907
+ return await this.urlResolver(url);
17908
+ const response = await fetch(url.url, {
17909
+ method: "GET",
17910
+ headers: {
17911
+ "Accept": "application/chargy"
17912
+ }
17913
+ });
17914
+ if (!response.ok)
17915
+ return url;
17916
+ const resolvedURL = { ...url };
17917
+ const contentType = response.headers.get("Content-Type")?.split(";")[0]?.trim().toLowerCase();
17918
+ if (contentType === "application/chargy")
17919
+ resolvedURL.serviceTypes = ["chargy"];
17920
+ const responseBody = await response.text();
17921
+ try {
17922
+ const serviceData = JSON.parse(responseBody);
17923
+ if (isMandatoryJSONObject(serviceData))
17924
+ resolvedURL.serviceData = serviceData;
17925
+ } catch {
17926
+ }
17927
+ return resolvedURL;
17928
+ } catch {
17929
+ return url;
17930
+ }
17790
17931
  }
17791
17932
  fileNameWithoutExtension(fileName) {
17792
17933
  const lastSeparator = Math.max(fileName.lastIndexOf("/"), fileName.lastIndexOf("\\"));
@@ -17878,6 +18019,26 @@ var Chargy = class {
17878
18019
  return textContent.replace(/\s+/g, "");
17879
18020
  return void 0;
17880
18021
  }
18022
+ TryToCreatePublicKeyLookup(processedFiles) {
18023
+ if (processedFiles.length === 0)
18024
+ return void 0;
18025
+ const publicKeys = new Array();
18026
+ for (const processedFile of processedFiles) {
18027
+ if (IsAChargeTransparencyRecord(processedFile.result) || IsAChargeTransparencyLiveLink(processedFile.result)) {
18028
+ return void 0;
18029
+ }
18030
+ if (IsAPublicKey(processedFile.result))
18031
+ publicKeys.push(processedFile.result);
18032
+ else if (IsAPublicKeyLookup(processedFile.result))
18033
+ publicKeys.push(...processedFile.result.publicKeys);
18034
+ else
18035
+ return void 0;
18036
+ }
18037
+ if (processedFiles.length === 1 && IsAPublicKeyLookup(processedFiles[0]?.result)) {
18038
+ return processedFiles[0].result;
18039
+ }
18040
+ return { publicKeys };
18041
+ }
17881
18042
  //#endregion
17882
18043
  //#region QR code image files...
17883
18044
  normalizeMIMEType(mimeType) {
@@ -18633,21 +18794,26 @@ var Chargy = class {
18633
18794
  certainty: 0
18634
18795
  };
18635
18796
  }
18636
- }
18797
+ } else if (IsValidURL(textContent))
18798
+ processedFile.result = await this.resolveURL(
18799
+ {
18800
+ "@context": URLContext,
18801
+ "url": textContent
18802
+ }
18803
+ );
18637
18804
  processedFiles.push(processedFile);
18638
18805
  }
18806
+ const publicKeyLookup = this.TryToCreatePublicKeyLookup(processedFiles);
18807
+ if (publicKeyLookup != null)
18808
+ return publicKeyLookup;
18639
18809
  if (processedFiles.length == 1) {
18640
18810
  const processedFile = getFirstArrayElement(processedFiles, "Missing processed file");
18641
18811
  if (IsAChargeTransparencyRecord(processedFile.result))
18642
18812
  return this.processChargeTransparencyRecord(processedFile.result);
18643
18813
  if (IsAChargeTransparencyLiveLink(processedFile.result))
18644
18814
  return processedFile.result;
18645
- if (IsAPublicKeyLookup(processedFile.result))
18646
- return {
18647
- status: "InvalidSessionFormat" /* InvalidSessionFormat */,
18648
- message: this.GetMultilanguageText("UnknownOrInvalidChargeTransparencyRecord"),
18649
- certainty: 0
18650
- };
18815
+ if (IsAURL(processedFile.result))
18816
+ return processedFile.result;
18651
18817
  return processedFile.result;
18652
18818
  } else if (processedFiles.length > 1) {
18653
18819
  const mergedCTR = {
@@ -19056,6 +19222,6 @@ var Chargy = class {
19056
19222
  }
19057
19223
  };
19058
19224
 
19059
- export { ACrypt, Alfen, AlfenCrypt01, BSMCrypt01, CanonicalJSONError, ChargeIT, ChargePoint, ChargePointCrypt01, IChargeTransparencyLiveLink_exports as ChargeTransparencyLiveLink, ChargeTransparencyLiveLinkContext, IChargeTransparencyRecord_exports as ChargeTransparencyRecord, Chargy, chargyInterfaces_exports as ChargyInterfaces, Clone, CloneCTR, ConcatenateBuffers, CreateDiv, CreateDiv2, CreateError, CreateWarning, CryptoAlgorithms, CryptoHashAlgorithms, DayOfWeek, DisplayPrefixes, EDL40, EDL40Crypt01, EDL40ValidationError, EDL40_OBIS, EDL40_SESSION_CONTEXT, EDL40_SIGNATURE_CONTEXT, EMHCrypt01, ErrorLevel, GDFCrypt01, IECCurves, IEncoding, InformationRelevance, InformationRelevanceToString, IsAChargeTransparencyLiveLink, IsAChargeTransparencyRecord, IsAPublicKey, IsAPublicKeyLookup, IsAPublicKeySignature, IsAPublicKeyXY, IsASessionCryptoResult, IsNullOrEmpty, JSONSignatureVerificationStatus, MENNEKES_EDL40_OBIS, MENNEKES_EDL40_XMLNS, Mennekes, MennekesCrypt01, OBIS2Hex, OBIS2MeasurementName, OBIS_RegExpr, OCMF, OCMFBonnTariffParseError, OCMFTransactionTypes, OCMFv1_x, OCPI, OIDInfo, PCDF, PCDFCrypt01, PCDFParseError, PCDFValidationError, PCDF_FIELD_ORDER, PCDF_PREFIX, PTB, ParseJSON_LD, PublicKeyFormats, IPublicKeyInfo_exports as PublicKeyInfo, SAFEXML, SessionVerificationResult, SetHex, SetInt8, SetText, SetText_withLength, SetTimestamp, SetTimestamp32, SetUInt32, SetUInt32_withCode, SetUInt64, SetUInt64D, SignMessage, SignatureFormats, TimeStatusTypes, UTC2human, VerificationResult, VerifyJSONMessageSignatures, WarningLevel, WhenNullOrEmpty, XMLContainer, asJSONArray, asJSONObject, asNumber, asString, base64ToBytes, buf2hex, buildEDL40Signature, buildIsaSignature, buildMennekesSignatureData, bytesToBase64, bytesToHex, canParseEDL40, canonicalJSONBytes, canonicalJSONStringify, cleanHex, closeFullscreen, createHexString, dateToMennekesLocalEpochSeconds, decodeSmlMessages, extractMennekesChargingProcesses, findEntryByObis, findGetListRes, firstKey, firstValue, getArrayElement, getArrayLikeElement, getDirectChildByLocalName, getDirectChildrenByLocalName, getElementsByLocalName, getFirstArrayElement, getInt16Bytes, getInt32Bytes, getInt64Bytes, getInt8Bytes, getLastArrayElement, getTrimmedTextContent, hashFile, hex2bin, hex32, hexToArrayBuffer, hexToBytes, intFromBytes, isEncodedValue, isGeoLocation, isI18NString, isICryptoResult, isIFileInfo, isISessionCryptoResult1, isISessionCryptoResult2, isJSONLDObject, isMandatoryArrayOfStrings, isMandatoryBoolean, isMandatoryDecimal, isMandatoryJSONArray, isMandatoryJSONObject, isMandatoryNumber, isMandatoryString, isMandatoryURL, isOIDInfo, isObject, isOptionalArrayOfStrings, isOptionalDecimal, isOptionalJSONArray, isOptionalJSONArrayError, isOptionalJSONArrayOk, isOptionalJSONObject, isOptionalNumber, isOptionalString, isOptionalStringArray, isOptionalStringOrOIDInfo, isOptionalURL, isPCDFText, isPublicKeySubject, isString, isStringArray, isStringOrOIDInfo, isStringOrStringArray, isaListNameContext, jsonPrettyPrinter, measurementName2human, normalizePCDFPublicKeyHex, normalizeXMLText, ocmfBonnTariffToChargingTariff, openFullscreen, pad, parseAndVerifyJSONSignatures, parseDescription, parseEDL40, parseHexString, parseMennekesXMLDocument, parseNumber, parseOBIS, parseOCMFBonnTariffText, parsePCDFDocument, parsePCDFPublicKey, parsePCDFSignature, parseSmlTime, parseUTC, readQRCodeTextFromImage, readQRCodeTextFromImageData, readTLV, secp224k1, setUILocale, sha256, sha256____, sha384, sha384____, sha512, sha512____, signJSONMessage, signMessage, stripPCDFControlCharacters, stripTransport, time2human, toArrayBuffer, toSessionVerificationResults, toUint8Array, transformEDL40Status, tryParseOCMFBonnTariffText, unquotePCDFText, validatePCDFFields, verifyEDL40Document, verifyJSONMessageSignatureResults, verifyJSONMessageSignatures, verifyJSONSignature, verifyJSONSignatureResult, verifyPCDFDocument };
19225
+ export { ACrypt, Alfen, AlfenCrypt01, BSMCrypt01, CanonicalJSONError, ChargeIT, ChargePoint, ChargePointCrypt01, IChargeTransparencyLiveLink_exports as ChargeTransparencyLiveLink, ChargeTransparencyLiveLinkContext, IChargeTransparencyRecord_exports as ChargeTransparencyRecord, Chargy, chargyInterfaces_exports as ChargyInterfaces, Clone, CloneCTR, ConcatenateBuffers, CreateDiv, CreateDiv2, CreateError, CreateWarning, CryptoAlgorithms, CryptoHashAlgorithms, DayOfWeek, DisplayPrefixes, EDL40, EDL40Crypt01, EDL40ValidationError, EDL40_OBIS, EDL40_SESSION_CONTEXT, EDL40_SIGNATURE_CONTEXT, EMHCrypt01, ErrorLevel, GDFCrypt01, IECCurves, IEncoding, InformationRelevance, InformationRelevanceToString, IsAChargeTransparencyLiveLink, IsAChargeTransparencyRecord, IsAPublicKey, IsAPublicKeyLookup, IsAPublicKeySignature, IsAPublicKeyXY, IsASessionCryptoResult, IsAURL, IsNullOrEmpty, IsValidURL, JSONSignatureVerificationStatus, MENNEKES_EDL40_OBIS, MENNEKES_EDL40_XMLNS, Mennekes, MennekesCrypt01, OBIS2Hex, OBIS2MeasurementName, OBIS_RegExpr, OCMF, OCMFBonnTariffParseError, OCMFTransactionTypes, OCMFv1_x, OCPI, OIDInfo, PCDF, PCDFCrypt01, PCDFParseError, PCDFValidationError, PCDF_FIELD_ORDER, PCDF_PREFIX, PTB, ParseJSON_LD, PublicKeyFormats, IPublicKeyInfo_exports as PublicKeyInfo, SAFEXML, SessionVerificationResult, SetHex, SetInt8, SetText, SetText_withLength, SetTimestamp, SetTimestamp32, SetUInt32, SetUInt32_withCode, SetUInt64, SetUInt64D, SignMessage, SignatureFormats, IURL_exports as SimpleURL, TimeStatusTypes, URLContext, UTC2human, VerificationResult, VerifyJSONMessageSignatures, WarningLevel, WhenNullOrEmpty, XMLContainer, asJSONArray, asJSONObject, asNumber, asString, base64ToBytes, buf2hex, buildEDL40Signature, buildIsaSignature, buildMennekesSignatureData, bytesToBase64, bytesToHex, canParseEDL40, canonicalJSONBytes, canonicalJSONStringify, cleanHex, closeFullscreen, createHexString, dateToMennekesLocalEpochSeconds, decodeSmlMessages, extractMennekesChargingProcesses, findEntryByObis, findGetListRes, firstKey, firstValue, getArrayElement, getArrayLikeElement, getDirectChildByLocalName, getDirectChildrenByLocalName, getElementsByLocalName, getFirstArrayElement, getInt16Bytes, getInt32Bytes, getInt64Bytes, getInt8Bytes, getLastArrayElement, getTrimmedTextContent, hashFile, hex2bin, hex32, hexToArrayBuffer, hexToBytes, intFromBytes, isEncodedValue, isGeoLocation, isI18NString, isICryptoResult, isIFileInfo, isISessionCryptoResult1, isISessionCryptoResult2, isJSONLDObject, isMandatoryArrayOfStrings, isMandatoryBoolean, isMandatoryDecimal, isMandatoryJSONArray, isMandatoryJSONObject, isMandatoryNumber, isMandatoryString, isMandatoryURL, isOIDInfo, isObject, isOptionalArrayOfStrings, isOptionalDecimal, isOptionalJSONArray, isOptionalJSONArrayError, isOptionalJSONArrayOk, isOptionalJSONObject, isOptionalNumber, isOptionalString, isOptionalStringArray, isOptionalStringOrOIDInfo, isOptionalURL, isPCDFText, isPublicKeySubject, isString, isStringArray, isStringOrOIDInfo, isStringOrStringArray, isaListNameContext, jsonPrettyPrinter, measurementName2human, normalizePCDFPublicKeyHex, normalizeXMLText, ocmfBonnTariffToChargingTariff, openFullscreen, pad, parseAndVerifyJSONSignatures, parseDescription, parseEDL40, parseHexString, parseMennekesXMLDocument, parseNumber, parseOBIS, parseOCMFBonnTariffText, parsePCDFDocument, parsePCDFPublicKey, parsePCDFSignature, parseSmlTime, parseUTC, readQRCodeTextFromImage, readQRCodeTextFromImageData, readTLV, secp224k1, setUILocale, sha256, sha256____, sha384, sha384____, sha512, sha512____, signJSONMessage, signMessage, stripPCDFControlCharacters, stripTransport, time2human, toArrayBuffer, toSessionVerificationResults, toUint8Array, transformEDL40Status, tryParseOCMFBonnTariffText, unquotePCDFText, validatePCDFFields, verifyEDL40Document, verifyJSONMessageSignatureResults, verifyJSONMessageSignatures, verifyJSONSignature, verifyJSONSignatureResult, verifyPCDFDocument };
19060
19226
  //# sourceMappingURL=index.js.map
19061
19227
  //# sourceMappingURL=index.js.map