@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.
@@ -1,6 +1,7 @@
1
1
  import Decimal from 'decimal.js';
2
2
  import moment from 'moment';
3
3
  import { fileTypeFromBuffer } from 'file-type';
4
+ import isURL from 'is-url-superb';
4
5
  import jsQR from 'jsqr';
5
6
  import seekBzip from 'seek-bzip';
6
7
 
@@ -9841,11 +9842,16 @@ function CreateWarning(message, level = "low" /* low */) {
9841
9842
  message
9842
9843
  };
9843
9844
  }
9844
- function CreateError(message, level = "high" /* high */) {
9845
- return {
9845
+ function CreateError(message, level = "high" /* high */, code, details) {
9846
+ const error = {
9846
9847
  level,
9847
9848
  message
9848
9849
  };
9850
+ if (code !== void 0)
9851
+ error.code = code;
9852
+ if (details !== void 0)
9853
+ error.details = details;
9854
+ return error;
9849
9855
  }
9850
9856
  function isISessionCryptoResult1(obj) {
9851
9857
  return isObject(obj) && obj["status"] !== void 0;
@@ -10831,6 +10837,20 @@ var ACrypt = class {
10831
10837
  newText.classList.remove("overEntry");
10832
10838
  };
10833
10839
  }
10840
+ // Records why a verification step failed as structured data: a stable reason
10841
+ // key (localized via i18n.json and machine-switchable by the GUI) plus an
10842
+ // optional, language-neutral technical detail. Presentation is left to the GUI.
10843
+ AddVerificationError(cryptoResult, reasonKey, detail) {
10844
+ const details = detail instanceof Error ? detail.message : typeof detail === "string" ? detail : void 0;
10845
+ (cryptoResult.errors ??= []).push(
10846
+ CreateError(
10847
+ this.chargy.GetMultilanguageText(reasonKey),
10848
+ "high" /* high */,
10849
+ reasonKey,
10850
+ details
10851
+ )
10852
+ );
10853
+ }
10834
10854
  };
10835
10855
  var Alfen = class {
10836
10856
  chargy;
@@ -11245,9 +11265,15 @@ var AlfenCrypt01 = class extends ACrypt {
11245
11265
  cryptoResult.publicKey = meter.publicKeys[0]?.value;
11246
11266
  cryptoResult.publicKeyFormat = meter.publicKeys[0]?.format;
11247
11267
  cryptoResult.publicKeySignatures = meter.publicKeys[0]?.signatures;
11268
+ let publicKey;
11269
+ try {
11270
+ publicKey = buf2hex(this.chargy.base32Decode(cryptoResult.publicKey ?? "", "RFC4648"));
11271
+ } catch (exception) {
11272
+ this.AddVerificationError(cryptoResult, "Verification_PublicKeyDecodingFailed", exception);
11273
+ return setResult("InvalidPublicKey" /* InvalidPublicKey */);
11274
+ }
11275
+ let result = false;
11248
11276
  try {
11249
- const publicKey = buf2hex(this.chargy.base32Decode(cryptoResult.publicKey ?? "", "RFC4648"));
11250
- let result = false;
11251
11277
  switch (meter.publicKeys[0]?.algorithm ?? "") {
11252
11278
  case "secp192r1":
11253
11279
  cryptoResult.hashValue = await sha256(cryptoBuffer);
@@ -11292,25 +11318,29 @@ var AlfenCrypt01 = class extends ACrypt {
11292
11318
  );
11293
11319
  break;
11294
11320
  }
11295
- if (result) {
11296
- return setResult("ValidSignature" /* ValidSignature */);
11297
- }
11298
- return setResult("InvalidSignature" /* InvalidSignature */);
11299
- } catch {
11321
+ } catch (exception) {
11322
+ this.AddVerificationError(cryptoResult, "Verification_SignatureMalformed", exception);
11300
11323
  return setResult("InvalidSignature" /* InvalidSignature */);
11301
11324
  }
11302
- } catch {
11325
+ if (result)
11326
+ return setResult("ValidSignature" /* ValidSignature */);
11327
+ this.AddVerificationError(cryptoResult, "Verification_SignatureMismatch");
11328
+ return setResult("InvalidSignature" /* InvalidSignature */);
11329
+ } catch (exception) {
11330
+ this.AddVerificationError(cryptoResult, "Verification_PublicKeyDecodingFailed", exception);
11303
11331
  return setResult("InvalidPublicKey" /* InvalidPublicKey */);
11304
11332
  }
11305
11333
  } else
11306
11334
  return setResult("PublicKeyNotFound" /* PublicKeyNotFound */);
11307
11335
  } else
11308
11336
  return setResult("EnergyMeterNotFound" /* EnergyMeterNotFound */);
11309
- } catch {
11337
+ } catch (exception) {
11338
+ this.AddVerificationError(cryptoResult, "Verification_UnexpectedError", exception);
11310
11339
  return setResult("InvalidSignature" /* InvalidSignature */);
11311
11340
  }
11312
11341
  }
11313
- return {};
11342
+ this.AddVerificationError(cryptoResult, "Verification_SignatureMissing");
11343
+ return setResult("InvalidSignature" /* InvalidSignature */);
11314
11344
  }
11315
11345
  async ViewMeasurement(measurementValue, _errorDiv, introDiv, infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
11316
11346
  const result = measurementValue.result;
@@ -12149,33 +12179,46 @@ var BSMCrypt01 = class extends ACrypt {
12149
12179
  const publicKeyDER = ASN1_PublicKey.decode(Buffer.from(meter.publicKeys[0]?.value ?? "", "hex"), "der");
12150
12180
  publicKey = buf2hex(publicKeyDER.publicKey.data).toLowerCase();
12151
12181
  }
12182
+ let keyPair;
12152
12183
  try {
12153
- if (this.curve.keyFromPublic(publicKey, "hex").verify(
12154
- cryptoResult.sha256value,
12155
- cryptoResult.signature
12156
- )) {
12157
- if (measurementValue.errors && measurementValue.errors.length > 0)
12158
- return setResult("ValidationError" /* ValidationError */);
12159
- return setResult("ValidSignature" /* ValidSignature */);
12160
- }
12161
- if (measurementValue.errors && measurementValue.errors.length > 0)
12162
- return setResult("ValidationError" /* ValidationError */);
12163
- return setResult("InvalidSignature" /* InvalidSignature */);
12164
- } catch {
12184
+ keyPair = this.curve.keyFromPublic(publicKey, "hex");
12185
+ } catch (exception) {
12186
+ this.AddVerificationError(cryptoResult, "Verification_PublicKeyDecodingFailed", exception);
12187
+ return setResult("InvalidPublicKey" /* InvalidPublicKey */);
12188
+ }
12189
+ const keyValidation = keyPair.validate();
12190
+ if (!keyValidation.result) {
12191
+ this.AddVerificationError(cryptoResult, "Verification_PublicKeyNotOnCurve", keyValidation.reason ?? void 0);
12192
+ return setResult("InvalidPublicKey" /* InvalidPublicKey */);
12193
+ }
12194
+ let signatureValid;
12195
+ try {
12196
+ signatureValid = keyPair.verify(cryptoResult.sha256value, cryptoResult.signature);
12197
+ } catch (exception) {
12198
+ this.AddVerificationError(cryptoResult, "Verification_SignatureMalformed", exception);
12165
12199
  return setResult("InvalidSignature" /* InvalidSignature */);
12166
12200
  }
12167
- } catch {
12201
+ if (measurementValue.errors && measurementValue.errors.length > 0)
12202
+ return setResult("ValidationError" /* ValidationError */);
12203
+ if (signatureValid)
12204
+ return setResult("ValidSignature" /* ValidSignature */);
12205
+ this.AddVerificationError(cryptoResult, "Verification_SignatureMismatch");
12206
+ return setResult("InvalidSignature" /* InvalidSignature */);
12207
+ } catch (exception) {
12208
+ this.AddVerificationError(cryptoResult, "Verification_PublicKeyDecodingFailed", exception);
12168
12209
  return setResult("InvalidPublicKey" /* InvalidPublicKey */);
12169
12210
  }
12170
12211
  } else
12171
12212
  return setResult("PublicKeyNotFound" /* PublicKeyNotFound */);
12172
12213
  } else
12173
12214
  return setResult("EnergyMeterNotFound" /* EnergyMeterNotFound */);
12174
- } catch {
12215
+ } catch (exception) {
12216
+ this.AddVerificationError(cryptoResult, "Verification_UnexpectedError", exception);
12175
12217
  return setResult("InvalidSignature" /* InvalidSignature */);
12176
12218
  }
12177
12219
  }
12178
- return {};
12220
+ this.AddVerificationError(cryptoResult, "Verification_SignatureMissing");
12221
+ return setResult("InvalidSignature" /* InvalidSignature */);
12179
12222
  }
12180
12223
  async ViewMeasurement(measurementValue, _errorDiv, introDiv, infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
12181
12224
  if (measurementValue.measurement === void 0)
@@ -12354,35 +12397,7 @@ var BSMCrypt01 = class extends ACrypt {
12354
12397
  if ((value & 1 << 29) != 0) events.push("OEM 15");
12355
12398
  return events;
12356
12399
  }
12357
- // private DecodeStatus(statusValue: string) : Array<string>
12358
- // {
12359
- // const statusArray:string[] = [];
12360
- // try
12361
- // {
12362
- // const status = parseInt(statusValue);
12363
- // if ((status & 1) == 1)
12364
- // statusArray.push("Fehler erkannt");
12365
- // if ((status & 2) == 2)
12366
- // statusArray.push("Synchrone Messwertübermittlung");
12367
- // // Bit 3 is reserved!
12368
- // if ((status & 8) == 8)
12369
- // statusArray.push("System-Uhr ist synchron");
12370
- // else
12371
- // statusArray.push("System-Uhr ist nicht synchron");
12372
- // if ((status & 16) == 16)
12373
- // statusArray.push("Rücklaufsperre aktiv");
12374
- // if ((status & 32) == 32)
12375
- // statusArray.push("Energierichtung -A");
12376
- // if ((status & 64) == 64)
12377
- // statusArray.push("Magnetfeld erkannt");
12378
- // }
12379
- // catch
12380
- // {
12381
- // statusArray.push("Invalid status!");
12382
- // }
12383
- // return statusArray;
12384
- // }
12385
- // //#endregion
12400
+ //#endregion
12386
12401
  };
12387
12402
 
12388
12403
  // src/interfaces/IPublicKeyInfo.ts
@@ -13841,29 +13856,44 @@ var EMHCrypt01 = class extends ACrypt {
13841
13856
  cryptoResult.publicKey = publicKey?.value.toLowerCase();
13842
13857
  cryptoResult.publicKeyFormat = publicKey?.format;
13843
13858
  cryptoResult.publicKeySignatures = publicKey?.signatures;
13859
+ let keyPair;
13844
13860
  try {
13845
- if (this.curve.keyFromPublic(cryptoResult.publicKey ?? "", "hex").verify(
13846
- cryptoResult.sha256value,
13847
- cryptoResult.signature
13848
- )) {
13849
- return setResult("ValidSignature" /* ValidSignature */);
13850
- }
13851
- return setResult("InvalidSignature" /* InvalidSignature */);
13852
- } catch {
13861
+ keyPair = this.curve.keyFromPublic(cryptoResult.publicKey ?? "", "hex");
13862
+ } catch (exception) {
13863
+ this.AddVerificationError(cryptoResult, "Verification_PublicKeyDecodingFailed", exception);
13864
+ return setResult("InvalidPublicKey" /* InvalidPublicKey */);
13865
+ }
13866
+ const keyValidation = keyPair.validate();
13867
+ if (!keyValidation.result) {
13868
+ this.AddVerificationError(cryptoResult, "Verification_PublicKeyNotOnCurve", keyValidation.reason ?? void 0);
13869
+ return setResult("InvalidPublicKey" /* InvalidPublicKey */);
13870
+ }
13871
+ let signatureValid;
13872
+ try {
13873
+ signatureValid = keyPair.verify(cryptoResult.sha256value, cryptoResult.signature);
13874
+ } catch (exception) {
13875
+ this.AddVerificationError(cryptoResult, "Verification_SignatureMalformed", exception);
13853
13876
  return setResult("InvalidSignature" /* InvalidSignature */);
13854
13877
  }
13855
- } catch {
13878
+ if (signatureValid)
13879
+ return setResult("ValidSignature" /* ValidSignature */);
13880
+ this.AddVerificationError(cryptoResult, "Verification_SignatureMismatch");
13881
+ return setResult("InvalidSignature" /* InvalidSignature */);
13882
+ } catch (exception) {
13883
+ this.AddVerificationError(cryptoResult, "Verification_PublicKeyDecodingFailed", exception);
13856
13884
  return setResult("InvalidPublicKey" /* InvalidPublicKey */);
13857
13885
  }
13858
13886
  } else
13859
13887
  return setResult("PublicKeyNotFound" /* PublicKeyNotFound */);
13860
13888
  } else
13861
13889
  return setResult("EnergyMeterNotFound" /* EnergyMeterNotFound */);
13862
- } catch {
13890
+ } catch (exception) {
13891
+ this.AddVerificationError(cryptoResult, "Verification_UnexpectedError", exception);
13863
13892
  return setResult("InvalidSignature" /* InvalidSignature */);
13864
13893
  }
13865
13894
  }
13866
- return {};
13895
+ this.AddVerificationError(cryptoResult, "Verification_SignatureMissing");
13896
+ return setResult("InvalidSignature" /* InvalidSignature */);
13867
13897
  }
13868
13898
  async ViewMeasurement(measurementValue, _errorDiv, introDiv, infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
13869
13899
  if (measurementValue.measurement?.chargingSession?.authorizationStart?.timestamp === void 0) {
@@ -13971,7 +14001,7 @@ var EMHCrypt01 = class extends ACrypt {
13971
14001
  DecodeStatus(statusValue) {
13972
14002
  const statusArray = [];
13973
14003
  try {
13974
- const status = parseInt(statusValue);
14004
+ const status = parseInt(statusValue, 16);
13975
14005
  if ((status & 1) == 1)
13976
14006
  statusArray.push("Fehler erkannt");
13977
14007
  if ((status & 2) == 2)
@@ -14073,29 +14103,44 @@ var GDFCrypt01 = class extends ACrypt {
14073
14103
  cryptoResult.publicKey = publicKey?.value.toLowerCase();
14074
14104
  cryptoResult.publicKeyFormat = publicKey?.format;
14075
14105
  cryptoResult.publicKeySignatures = publicKey?.signatures;
14106
+ let keyPair;
14076
14107
  try {
14077
- if (this.curve.keyFromPublic(cryptoResult.publicKey ?? "", "hex").verify(
14078
- cryptoResult.sha256value,
14079
- cryptoResult.signature
14080
- )) {
14081
- return setResult("ValidSignature" /* ValidSignature */);
14082
- }
14083
- return setResult("InvalidSignature" /* InvalidSignature */);
14084
- } catch {
14108
+ keyPair = this.curve.keyFromPublic(cryptoResult.publicKey ?? "", "hex");
14109
+ } catch (exception) {
14110
+ this.AddVerificationError(cryptoResult, "Verification_PublicKeyDecodingFailed", exception);
14111
+ return setResult("InvalidPublicKey" /* InvalidPublicKey */);
14112
+ }
14113
+ const keyValidation = keyPair.validate();
14114
+ if (!keyValidation.result) {
14115
+ this.AddVerificationError(cryptoResult, "Verification_PublicKeyNotOnCurve", keyValidation.reason ?? void 0);
14116
+ return setResult("InvalidPublicKey" /* InvalidPublicKey */);
14117
+ }
14118
+ let signatureValid;
14119
+ try {
14120
+ signatureValid = keyPair.verify(cryptoResult.sha256value, cryptoResult.signature);
14121
+ } catch (exception) {
14122
+ this.AddVerificationError(cryptoResult, "Verification_SignatureMalformed", exception);
14085
14123
  return setResult("InvalidSignature" /* InvalidSignature */);
14086
14124
  }
14087
- } catch {
14125
+ if (signatureValid)
14126
+ return setResult("ValidSignature" /* ValidSignature */);
14127
+ this.AddVerificationError(cryptoResult, "Verification_SignatureMismatch");
14128
+ return setResult("InvalidSignature" /* InvalidSignature */);
14129
+ } catch (exception) {
14130
+ this.AddVerificationError(cryptoResult, "Verification_PublicKeyDecodingFailed", exception);
14088
14131
  return setResult("InvalidPublicKey" /* InvalidPublicKey */);
14089
14132
  }
14090
14133
  } else
14091
14134
  return setResult("PublicKeyNotFound" /* PublicKeyNotFound */);
14092
14135
  } else
14093
14136
  return setResult("EnergyMeterNotFound" /* EnergyMeterNotFound */);
14094
- } catch {
14137
+ } catch (exception) {
14138
+ this.AddVerificationError(cryptoResult, "Verification_UnexpectedError", exception);
14095
14139
  return setResult("InvalidSignature" /* InvalidSignature */);
14096
14140
  }
14097
14141
  }
14098
- return {};
14142
+ this.AddVerificationError(cryptoResult, "Verification_SignatureMissing");
14143
+ return setResult("InvalidSignature" /* InvalidSignature */);
14099
14144
  }
14100
14145
  async ViewMeasurement(measurementValue, _errorDiv, introDiv, infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
14101
14146
  if (measurementValue.measurement?.chargingSession?.authorizationStart?.timestamp === void 0) {
@@ -14434,19 +14479,38 @@ var MennekesCrypt01 = class extends ACrypt {
14434
14479
  );
14435
14480
  cryptoResult.hashValue = (await sha256(new DataView(signedDataBuffer))).substring(0, 48);
14436
14481
  const publicKey = cleanHex(meter.publicKeys.at(0)?.value ?? measurement.publicKey);
14437
- if (publicKey.length !== 96)
14482
+ if (publicKey.length !== 96) {
14483
+ this.AddVerificationError(cryptoResult, "Verification_PublicKeyDecodingFailed");
14438
14484
  return setResult("InvalidPublicKey" /* InvalidPublicKey */);
14439
- const result = this.curve192r1.keyFromPublic("04" + publicKey, "hex").verify(
14440
- cryptoResult.hashValue.toUpperCase(),
14441
- {
14485
+ }
14486
+ let keyPair;
14487
+ try {
14488
+ keyPair = this.curve192r1.keyFromPublic("04" + publicKey, "hex");
14489
+ } catch (exception) {
14490
+ this.AddVerificationError(cryptoResult, "Verification_PublicKeyDecodingFailed", exception);
14491
+ return setResult("InvalidPublicKey" /* InvalidPublicKey */);
14492
+ }
14493
+ const keyValidation = keyPair.validate();
14494
+ if (!keyValidation.result) {
14495
+ this.AddVerificationError(cryptoResult, "Verification_PublicKeyNotOnCurve", keyValidation.reason ?? void 0);
14496
+ return setResult("InvalidPublicKey" /* InvalidPublicKey */);
14497
+ }
14498
+ let signatureValid;
14499
+ try {
14500
+ signatureValid = keyPair.verify(cryptoResult.hashValue.toUpperCase(), {
14442
14501
  r: signatureExpected.r,
14443
14502
  s: signatureExpected.s
14444
- }
14445
- );
14446
- return setResult(
14447
- result ? "ValidSignature" /* ValidSignature */ : "InvalidSignature" /* InvalidSignature */
14448
- );
14449
- } catch {
14503
+ });
14504
+ } catch (exception) {
14505
+ this.AddVerificationError(cryptoResult, "Verification_SignatureMalformed", exception);
14506
+ return setResult("InvalidSignature" /* InvalidSignature */);
14507
+ }
14508
+ if (signatureValid)
14509
+ return setResult("ValidSignature" /* ValidSignature */);
14510
+ this.AddVerificationError(cryptoResult, "Verification_SignatureMismatch");
14511
+ return setResult("InvalidSignature" /* InvalidSignature */);
14512
+ } catch (exception) {
14513
+ this.AddVerificationError(cryptoResult, "Verification_UnexpectedError", exception);
14450
14514
  return setResult("InvalidSignature" /* InvalidSignature */);
14451
14515
  }
14452
14516
  }
@@ -15424,7 +15488,9 @@ var OCMF = class {
15424
15488
  // "value": ocmfJSONDocument.signature["SD"]
15425
15489
  // }],
15426
15490
  "result": {
15427
- "status": ocmfJSONDocument.validationStatus ?? "Unvalidated" /* Unvalidated */
15491
+ "status": ocmfJSONDocument.validationStatus ?? "Unvalidated" /* Unvalidated */,
15492
+ // Surface the per-document verification diagnostics on the measurement value.
15493
+ ...ocmfJSONDocument.validationErrors && ocmfJSONDocument.validationErrors.length > 0 ? { errors: ocmfJSONDocument.validationErrors } : {}
15428
15494
  },
15429
15495
  "ocmfDocument": ocmfJSONDocument
15430
15496
  });
@@ -15569,6 +15635,20 @@ var OCMF = class {
15569
15635
  // return mergedCTR;
15570
15636
  // }
15571
15637
  // //#endregion
15638
+ // Records why a verification step failed as structured data: a stable reason
15639
+ // key (localized via i18n.json and machine-switchable by the GUI) plus an
15640
+ // optional, language-neutral technical detail. Presentation is left to the GUI.
15641
+ AddValidationError(OCMFJSONDocument, reasonKey, detail) {
15642
+ const details = detail instanceof Error ? detail.message : typeof detail === "string" ? detail : void 0;
15643
+ (OCMFJSONDocument.validationErrors ??= []).push(
15644
+ CreateError(
15645
+ this.chargy.GetMultilanguageText(reasonKey),
15646
+ "high" /* high */,
15647
+ reasonKey,
15648
+ details
15649
+ )
15650
+ );
15651
+ }
15572
15652
  //#region (private) validateOCMFSignature(OCMFJSONDocument, PublicKey, PublicKeyEncoding?)
15573
15653
  async validateOCMFSignature(OCMFJSONDocument, PublicKey, PublicKeyEncoding) {
15574
15654
  try {
@@ -15608,7 +15688,8 @@ var OCMF = class {
15608
15688
  curve = new this.chargy.elliptic.ec("p256");
15609
15689
  break;
15610
15690
  }
15611
- } catch {
15691
+ } catch (exception) {
15692
+ this.AddValidationError(OCMFJSONDocument, "Verification_UnknownSignatureFormat", exception);
15612
15693
  OCMFJSONDocument.validationStatus = "UnknownSignatureFormat" /* UnknownSignatureFormat */;
15613
15694
  return OCMFJSONDocument.validationStatus;
15614
15695
  }
@@ -15685,20 +15766,26 @@ var OCMF = class {
15685
15766
  y: OCMFJSONDocument.publicKey.y
15686
15767
  }, "hex");
15687
15768
  }
15688
- } catch {
15769
+ } catch (exception) {
15770
+ this.AddValidationError(OCMFJSONDocument, "Verification_PublicKeyDecodingFailed", exception);
15689
15771
  OCMFJSONDocument.validationStatus = "InvalidPublicKey" /* InvalidPublicKey */;
15690
15772
  return OCMFJSONDocument.validationStatus;
15691
15773
  }
15692
15774
  try {
15693
15775
  if (publicKey === null)
15694
15776
  throw new Error("Missing public key!");
15695
- OCMFJSONDocument.validationStatus = publicKey.verify(OCMFJSONDocument.hashValue, OCMFJSONDocument.signatureRS) ? "ValidSignature" /* ValidSignature */ : "InvalidSignature" /* InvalidSignature */;
15777
+ const signatureValid = publicKey.verify(OCMFJSONDocument.hashValue, OCMFJSONDocument.signatureRS);
15778
+ if (!signatureValid)
15779
+ this.AddValidationError(OCMFJSONDocument, "Verification_SignatureMismatch");
15780
+ OCMFJSONDocument.validationStatus = signatureValid ? "ValidSignature" /* ValidSignature */ : "InvalidSignature" /* InvalidSignature */;
15696
15781
  return await Promise.resolve(OCMFJSONDocument.validationStatus);
15697
- } catch {
15782
+ } catch (exception) {
15783
+ this.AddValidationError(OCMFJSONDocument, "Verification_SignatureMalformed", exception);
15698
15784
  OCMFJSONDocument.validationStatus = "InvalidSignature" /* InvalidSignature */;
15699
15785
  return OCMFJSONDocument.validationStatus;
15700
15786
  }
15701
- } catch {
15787
+ } catch (exception) {
15788
+ this.AddValidationError(OCMFJSONDocument, "Verification_UnexpectedError", exception);
15702
15789
  OCMFJSONDocument.validationStatus = "InvalidSignature" /* InvalidSignature */;
15703
15790
  return OCMFJSONDocument.validationStatus;
15704
15791
  }
@@ -19305,6 +19392,26 @@ function isTOTPConfig(data) {
19305
19392
  return isObject(data) && typeof data["initialSharedSecret"] === "string" && typeof data["timeStep"] === "number";
19306
19393
  }
19307
19394
 
19395
+ // src/interfaces/IURL.ts
19396
+ var IURL_exports = {};
19397
+ __export(IURL_exports, {
19398
+ IsAURL: () => IsAURL,
19399
+ IsValidURL: () => IsValidURL,
19400
+ URLContext: () => URLContext
19401
+ });
19402
+ var URLContext = "https://open.charging.cloud/contexts/URL";
19403
+ function IsValidURL(value) {
19404
+ if (!isURL(value))
19405
+ return false;
19406
+ const protocol = new URL(value).protocol;
19407
+ return protocol === "http:" || protocol === "https:";
19408
+ }
19409
+ function IsAURL(data) {
19410
+ if (!isMandatoryJSONObject(data))
19411
+ return false;
19412
+ 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"]));
19413
+ }
19414
+
19308
19415
  // src/qrCodeReader.ts
19309
19416
  var import_buffer = __toESM(require_buffer2());
19310
19417
  function isRecord(value) {
@@ -19538,6 +19645,8 @@ var Chargy = class {
19538
19645
  base32Decode;
19539
19646
  showPKIDetails;
19540
19647
  validationRules;
19648
+ resolveURLs;
19649
+ urlResolver;
19541
19650
  chargingStationOperators = new Array();
19542
19651
  chargingPools = new Array();
19543
19652
  chargingStations = new Array();
@@ -19547,7 +19656,7 @@ var Chargy = class {
19547
19656
  currentCTR = {};
19548
19657
  internalCTR = {};
19549
19658
  //#endregion
19550
- constructor(i18n, UILanguages, elliptic, moment2, asn1, base32Decode, ShowPKIDetails, validationRules = validationRules_default) {
19659
+ constructor(i18n, UILanguages, elliptic, moment2, asn1, base32Decode, ShowPKIDetails, validationRules = validationRules_default, resolveURLs = false, urlResolver) {
19551
19660
  this.i18n = i18n;
19552
19661
  this.uiLanguages = this.NormalizeUILanguages(UILanguages);
19553
19662
  this.elliptic = elliptic;
@@ -19556,6 +19665,38 @@ var Chargy = class {
19556
19665
  this.base32Decode = base32Decode;
19557
19666
  this.showPKIDetails = ShowPKIDetails;
19558
19667
  this.validationRules = validationRules;
19668
+ this.resolveURLs = resolveURLs;
19669
+ this.urlResolver = urlResolver;
19670
+ }
19671
+ async resolveURL(url) {
19672
+ if (!this.resolveURLs)
19673
+ return url;
19674
+ try {
19675
+ if (this.urlResolver != null)
19676
+ return await this.urlResolver(url);
19677
+ const response = await fetch(url.url, {
19678
+ method: "GET",
19679
+ headers: {
19680
+ "Accept": "application/chargy"
19681
+ }
19682
+ });
19683
+ if (!response.ok)
19684
+ return url;
19685
+ const resolvedURL = { ...url };
19686
+ const contentType = response.headers.get("Content-Type")?.split(";")[0]?.trim().toLowerCase();
19687
+ if (contentType === "application/chargy")
19688
+ resolvedURL.serviceTypes = ["chargy"];
19689
+ const responseBody = await response.text();
19690
+ try {
19691
+ const serviceData = JSON.parse(responseBody);
19692
+ if (isMandatoryJSONObject(serviceData))
19693
+ resolvedURL.serviceData = serviceData;
19694
+ } catch {
19695
+ }
19696
+ return resolvedURL;
19697
+ } catch {
19698
+ return url;
19699
+ }
19559
19700
  }
19560
19701
  fileNameWithoutExtension(fileName) {
19561
19702
  const lastSeparator = Math.max(fileName.lastIndexOf("/"), fileName.lastIndexOf("\\"));
@@ -19647,6 +19788,26 @@ var Chargy = class {
19647
19788
  return textContent.replace(/\s+/g, "");
19648
19789
  return void 0;
19649
19790
  }
19791
+ TryToCreatePublicKeyLookup(processedFiles) {
19792
+ if (processedFiles.length === 0)
19793
+ return void 0;
19794
+ const publicKeys = new Array();
19795
+ for (const processedFile of processedFiles) {
19796
+ if (IsAChargeTransparencyRecord(processedFile.result) || IsAChargeTransparencyLiveLink(processedFile.result)) {
19797
+ return void 0;
19798
+ }
19799
+ if (IsAPublicKey(processedFile.result))
19800
+ publicKeys.push(processedFile.result);
19801
+ else if (IsAPublicKeyLookup(processedFile.result))
19802
+ publicKeys.push(...processedFile.result.publicKeys);
19803
+ else
19804
+ return void 0;
19805
+ }
19806
+ if (processedFiles.length === 1 && IsAPublicKeyLookup(processedFiles[0]?.result)) {
19807
+ return processedFiles[0].result;
19808
+ }
19809
+ return { publicKeys };
19810
+ }
19650
19811
  //#endregion
19651
19812
  //#region QR code image files...
19652
19813
  normalizeMIMEType(mimeType) {
@@ -20402,21 +20563,26 @@ var Chargy = class {
20402
20563
  certainty: 0
20403
20564
  };
20404
20565
  }
20405
- }
20566
+ } else if (IsValidURL(textContent))
20567
+ processedFile.result = await this.resolveURL(
20568
+ {
20569
+ "@context": URLContext,
20570
+ "url": textContent
20571
+ }
20572
+ );
20406
20573
  processedFiles.push(processedFile);
20407
20574
  }
20575
+ const publicKeyLookup = this.TryToCreatePublicKeyLookup(processedFiles);
20576
+ if (publicKeyLookup != null)
20577
+ return publicKeyLookup;
20408
20578
  if (processedFiles.length == 1) {
20409
20579
  const processedFile = getFirstArrayElement(processedFiles, "Missing processed file");
20410
20580
  if (IsAChargeTransparencyRecord(processedFile.result))
20411
20581
  return this.processChargeTransparencyRecord(processedFile.result);
20412
20582
  if (IsAChargeTransparencyLiveLink(processedFile.result))
20413
20583
  return processedFile.result;
20414
- if (IsAPublicKeyLookup(processedFile.result))
20415
- return {
20416
- status: "InvalidSessionFormat" /* InvalidSessionFormat */,
20417
- message: this.GetMultilanguageText("UnknownOrInvalidChargeTransparencyRecord"),
20418
- certainty: 0
20419
- };
20584
+ if (IsAURL(processedFile.result))
20585
+ return processedFile.result;
20420
20586
  return processedFile.result;
20421
20587
  } else if (processedFiles.length > 1) {
20422
20588
  const mergedCTR = {
@@ -20838,6 +21004,6 @@ buffer/index.js:
20838
21004
  *)
20839
21005
  */
20840
21006
 
20841
- 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 };
21007
+ 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 };
20842
21008
  //# sourceMappingURL=index.js.map
20843
21009
  //# sourceMappingURL=index.js.map