From 37e03d6cd28d0882984feceeeb475a5eec004e58 Mon Sep 17 00:00:00 2001 From: Achim Friedland Date: Sun, 18 Aug 2019 06:30:52 +0200 Subject: [PATCH 001/110] Add chargeIT Testdatensatz in Chargy's Charge Transparency Record data format --- .../chargeIT-Testdatensatz-02.chargy | 178 ++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 documentation/chargeIT-Testdatensatz-02.chargy diff --git a/documentation/chargeIT-Testdatensatz-02.chargy b/documentation/chargeIT-Testdatensatz-02.chargy new file mode 100644 index 0000000..09ac43d --- /dev/null +++ b/documentation/chargeIT-Testdatensatz-02.chargy @@ -0,0 +1,178 @@ +{ + "@id": "1554181214441:-1965658344385548683:2", + "@context": "https://open.charging.cloud/contexts/CTR+json", + "begin": "2019-04-02T05:00:19Z", + "end": "2019-04-02T05:13:52Z", + "description": { + "de": "Alle Ladevorgänge" + }, + "contract": { + "@id": "8057F5AA592904", + "type": "RFID_TAG_ID", + "username": "", + "email": "" + }, + "chargingStationOperators": [{ + "@id": "chargeITmobilityCSO", + "eMobilityIds": ["DE*BDO", "DE*LVF", "+49*822"], + "description": { + "de": "chargeIT mobility GmbH - Charging Station Operator Services" + }, + "contact": { + "email": "info@chargeit-mobility.com", + "web": "https://www.chargeit-mobility.com", + "logoUrl": "http://www.chargeit-mobility.com/fileadmin/BELECTRIC_Drive/templates/pics/chargeit_logo_408x70.png", + "publicKeys": [{ + "algorithm": "secp192r1", + "format": "DER", + "value": "042313b9e469612b4ca06981bfdecb226e234632b01d84b6a814f63a114b7762c34ddce2e6853395b7a0f87275f63ffe3c", + "signatures": [{ + "keyId": "...", + "algorithm": "secp192r1", + "format": "DER", + "value": "????" + }] + }, { + "algorithm": "secp256k1", + "format": "DER", + "value": "04a8ff0d82107922522e004a167cc658f0eef408c5020f98e7a2615be326e61852666877335f4f8d9a0a756c26f0c9fb3f401431416abb5317cc0f5d714d3026fe", + "signatures": [] + }] + }, + "support": { + "hotline": "+49 9321 / 2680 - 700", + "email": "service@chargeit-mobility.com", + "web": "https://cso.chargeit.charging.cloud/issues" + }, + "privacy": { + "contact": "Dr. iur. Christian Borchers, datenschutz süd GmbH", + "email": "datenschutz@chargeit-mobility.com", + "web": "http://www.chargeit-mobility.com/de/datenschutz/" + }, + "chargingStations": [{ + "@id": "DE*BDO*E8025334492", + "firmwareVersion": "3.0.25.2089", + "geoLocation": { + "lat": 48.035131, + "lng": 10.50635 + }, + "address": { + "street": "Breitenbergstr. 2", + "postalCode": "87719", + "city": "Mindelheim" + }, + "EVSEs": [{ + "@id": "DE*BDO*E8025334492*2", + "sockets": [{}], + "meters": [{ + "@id": "0901454D48000083E076", + "vendor": "EMH", + "vendorURL": "http://www.emh-metering.de", + "model": "eHZ IW8E EMH", + "hardwareVersion": "1.0", + "firmwareVersion": "123", + "signatureFormat": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/EMHCrypt01", + "publicKeys": [{ + "algorithm": "secp192r1", + "format": "DER", + "value": "049EA8697F5C3126E86A37295566D560DE8EA690325791C9CBA79D30612B8EA8E00908FBAD5374812D55DCC3D809C3A36C", + "signatures": [{ + "signer": "Open Charging Cloud", + "publicKey": "04a8ff0d82107922522e004a167cc658f0eef408c5020f98e7a2615be326e61852666877335f4f8d9a0a756c26f0c9fb3f401431416abb5317cc0f5d714d3026fe", + "timestamp": "2019-06-30T00:00:00Z", + "comment": { + "en": "Hello world!" + }, + "notBefore": "2018-11-04T16:47:01Z", + "notAfter": "2023-03-12T13:54:12Z", + "operations": { + "signCertificates": false, + "signMeterValues": true + }, + "revocationURIs": [], + "algorithm": "secp256k1", + "format": "DER", + "value": "303502181dce9223416d64e5362bc8eb46eddf23adcb74382b602e1f021900eca85b1a48bc1f64d25951e947c7e48fa0b070b82e2cae41" + }, { + "signer": "chargeIT mobility", + "publicKey": "04a8ff0d82107922522e004a167cc658f0eef408c5020f98e7a2615be326e61852666877335f4f8d9a0a756c26f0c9fb3f401431416abb5317cc0f5d714d3026fe", + "timestamp": "2019-06-30T00:00:00Z", + "comment": { + "en": "Hello world!" + }, + "notBefore": "2018-11-04T16:47:01Z", + "notAfter": "2023-03-12T13:54:12Z", + "operations": { + "signCertificates": false, + "signMeterValues": true + }, + "revocationURIs": [], + "algorithm": "secp256k1", + "format": "DER", + "value": "303502181dce9223416d64e5362bc8eb46eddf23adcb74382b602e1f021900eca85b1a48bc1f64d25951e947c7e48fa0b070b82e2cae41" + }] + }] + }] + }] + }] + }], + "chargingSessions": [{ + "@id": "1554181214441:-1965658344385548683:2", + "@context": "https://open.charging.cloud/contexts/SessionSignatureFormats/EMHCrypt01+json", + "begin": "2019-04-02T05:00:19Z", + "end": "2019-04-02T05:13:52Z", + "EVSEId": "DE*BDO*E8025334492*2", + "authorizationStart": { + "@id": "8057F5AA592904", + "type": "RFID_TAG_ID", + "timestamp": "2019-04-02T07:00:19+02:00" + }, + "signatureInfos": { + "hash": "SHA512", + "hashTruncation": "24", + "algorithm": "ECC", + "curve": "secp192r1", + "format": "rs" + }, + "measurements": [{ + "meterId": "0901454D48000083E076", + "@context": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/EMHCrypt01+json", + "name": "ENERGY_TOTAL", + "obis": "0100011100FF", + "unit": "WATT_HOUR", + "unitEncoded": 30, + "valueType": "Integer64", + "scale": -1, + "signatureInfos": { + "hash": "SHA512", + "hashTruncation": "24", + "algorithm": "ECC", + "curve": "secp192r1", + "format": "rs" + }, + "values": [{ + "timestamp": "2019-04-02T07:00:19+02:00", + "value": "66260", + "infoStatus": "08", + "secondsIndex": 65058, + "paginationId": "00000012", + "logBookIndex": "0006", + "signatures": [{ + "r": "71F76A80F170F87675AAEB19606BBD298355FDA7B0851700", + "s": "2FAD322FA073255BD8B971BD69BFF051BCA9330703172E3C" + }] + }, { + "timestamp": "2019-04-02T07:13:52+02:00", + "value": "67327", + "infoStatus": "08", + "secondsIndex": 65871, + "paginationId": "00000013", + "logBookIndex": "0006", + "signatures": [{ + "r": "6DF01D7603CB49BB76141F8E67B371351BF1F87C1F8D38AE", + "s": "B3600A9432B8CE0A378126D4FB9D9581457651A5D208AD9E" + }] + }] + }] + }] +} From b2d1e32aa9aaffa090fc14d57eb444ca976c99fc Mon Sep 17 00:00:00 2001 From: Achim Friedland Date: Sun, 18 Aug 2019 17:04:57 +0200 Subject: [PATCH 002/110] Adding first lines of support for SAFE XML, OCMF v0.1, OCMF v1.0 --- .../OCMF v1.0/OCMF-Testdatensatz-01.json | 1 + .../OCMF-Testdatensatz-01_publicKey.json | 1 + .../OCMF v1.0/SAFE-Testdatensatz-01.xml | 7 + ...AFE-Testdatensatz-02_emptyXMLNamespace.xml | 7 + ...SAFE-Testdatensatz-02_withXMLNamespace.xml | 7 + ...E-Testdatensatz-02_withoutXMLNamespace.xml | 7 + .../OCMF v1.0/SAFE-Testdatensatz-03.xml | 19 + .../OCMF v1.0/SAFE-TransparencySoftware.xsd | 41 ++ src/js/OCMFTypes.ts | 48 ++ src/js/chargy.ts | 449 +++++++++++++++++- src/main.js | 2 +- 11 files changed, 577 insertions(+), 12 deletions(-) create mode 100644 documentation/OCMF v1.0/OCMF-Testdatensatz-01.json create mode 100644 documentation/OCMF v1.0/OCMF-Testdatensatz-01_publicKey.json create mode 100644 documentation/OCMF v1.0/SAFE-Testdatensatz-01.xml create mode 100644 documentation/OCMF v1.0/SAFE-Testdatensatz-02_emptyXMLNamespace.xml create mode 100644 documentation/OCMF v1.0/SAFE-Testdatensatz-02_withXMLNamespace.xml create mode 100644 documentation/OCMF v1.0/SAFE-Testdatensatz-02_withoutXMLNamespace.xml create mode 100644 documentation/OCMF v1.0/SAFE-Testdatensatz-03.xml create mode 100644 documentation/OCMF v1.0/SAFE-TransparencySoftware.xsd create mode 100644 src/js/OCMFTypes.ts diff --git a/documentation/OCMF v1.0/OCMF-Testdatensatz-01.json b/documentation/OCMF v1.0/OCMF-Testdatensatz-01.json new file mode 100644 index 0000000..496d570 --- /dev/null +++ b/documentation/OCMF v1.0/OCMF-Testdatensatz-01.json @@ -0,0 +1 @@ +OCMF|{"FV":"1.0","GI":"SEAL AG","GS":"1850006a","GV":"1.34","PG":"T9289","MV":"Carlo Gavazzi","MM":"EM340-DIN.AV2.3.X.S1.PF","MS":"******240084S","MF":"B4","IS":true,"IL":"TRUSTED","IF":["OCCP_AUTH"],"IT":"ISO14443","ID":"56213C05","RD":[{"TM":"2019-06-26T08:57:44,337+0000 U","TX":"B","RV":268.978,"RI":"1-b:1.8.0","RU":"kWh","RT":"AC","EF":"","ST":"G"}]}|{"SD":"304402201455BF1082C9EB8B1272D7FA838EB44286B03AC96E8BAFC5E79E30C5B3E1B872022006286CA81AEE0FAFCB1D6A137FFB2C0DD014727E2AEC149F30CD5A7E87619139"} diff --git a/documentation/OCMF v1.0/OCMF-Testdatensatz-01_publicKey.json b/documentation/OCMF v1.0/OCMF-Testdatensatz-01_publicKey.json new file mode 100644 index 0000000..23b1750 --- /dev/null +++ b/documentation/OCMF v1.0/OCMF-Testdatensatz-01_publicKey.json @@ -0,0 +1 @@ +3059301306072A8648CE3D020106082A8648CE3D030107034200044171CAB628050A228DA1D33129696D9ECA50FD50AFF04ABA2CE1E5EBBB1F457963B06A6A2D39175AB7C5B25685BEA3072197D00444C9DCE194817C21F35A4AC3 diff --git a/documentation/OCMF v1.0/SAFE-Testdatensatz-01.xml b/documentation/OCMF v1.0/SAFE-Testdatensatz-01.xml new file mode 100644 index 0000000..7bafb0b --- /dev/null +++ b/documentation/OCMF v1.0/SAFE-Testdatensatz-01.xml @@ -0,0 +1,7 @@ + + + + ENCODED STRING + 887FABF407AC82782EEFFF2220C2F856AEB0BC22364BBCC6B55761911ED651D1A922BADA88818C9671AFEE7094D7F536 + + diff --git a/documentation/OCMF v1.0/SAFE-Testdatensatz-02_emptyXMLNamespace.xml b/documentation/OCMF v1.0/SAFE-Testdatensatz-02_emptyXMLNamespace.xml new file mode 100644 index 0000000..2d1a686 --- /dev/null +++ b/documentation/OCMF v1.0/SAFE-Testdatensatz-02_emptyXMLNamespace.xml @@ -0,0 +1,7 @@ + + + + OCMF|{"FV":"0.1","VI":"ABL","VV":"1.4p3","PG":"T12345","MV":"Phoenix Contact","MM":"EEM-350-D-MCB","MS":"BQ27400330016","MF":"1.0","IS":"VERIFIED","IF":["RFID_PLAIN","OCPP_RS_TLS"],"IT":"ISO14443","ID":"1F2D3A4F5506C7","RD":[{"TM":"2018-07-24T13:22:04,000+0200 S","TX":"B","RV":2935.6,"RI":"1-b:1.8.e","RU":"kWh","EI":567,"ST":"G"}]}|{"SA":"ECDSA-secp256k1-SHA256","SD":"3046022100A7F1FD39278A88432E1AB81229C34CE1066885D0EAD8810DB900018A4960888302210089004420623749BF75561F29685CD87D6853EC08E83BD1A15C5DAFF9F03F4115"} + 3056301006072A8648CE3D020106052B8104000A034200044E4970098EEFF5E0E286E3A38552679771B89315A49DDDF66EBAC6F176FB02DF9841091010E6850510540DAD0CF967FD8DE0AB25198282B39597DDCE09EDF459 + + \ No newline at end of file diff --git a/documentation/OCMF v1.0/SAFE-Testdatensatz-02_withXMLNamespace.xml b/documentation/OCMF v1.0/SAFE-Testdatensatz-02_withXMLNamespace.xml new file mode 100644 index 0000000..9ba8ad1 --- /dev/null +++ b/documentation/OCMF v1.0/SAFE-Testdatensatz-02_withXMLNamespace.xml @@ -0,0 +1,7 @@ + + + + OCMF|{"FV":"0.1","VI":"ABL","VV":"1.4p3","PG":"T12345","MV":"Phoenix Contact","MM":"EEM-350-D-MCB","MS":"BQ27400330016","MF":"1.0","IS":"VERIFIED","IF":["RFID_PLAIN","OCPP_RS_TLS"],"IT":"ISO14443","ID":"1F2D3A4F5506C7","RD":[{"TM":"2018-07-24T13:22:04,000+0200 S","TX":"B","RV":2935.6,"RI":"1-b:1.8.e","RU":"kWh","EI":567,"ST":"G"}]}|{"SA":"ECDSA-secp256k1-SHA256","SD":"3046022100A7F1FD39278A88432E1AB81229C34CE1066885D0EAD8810DB900018A4960888302210089004420623749BF75561F29685CD87D6853EC08E83BD1A15C5DAFF9F03F4115"} + 3056301006072A8648CE3D020106052B8104000A034200044E4970098EEFF5E0E286E3A38552679771B89315A49DDDF66EBAC6F176FB02DF9841091010E6850510540DAD0CF967FD8DE0AB25198282B39597DDCE09EDF459 + + \ No newline at end of file diff --git a/documentation/OCMF v1.0/SAFE-Testdatensatz-02_withoutXMLNamespace.xml b/documentation/OCMF v1.0/SAFE-Testdatensatz-02_withoutXMLNamespace.xml new file mode 100644 index 0000000..edb9711 --- /dev/null +++ b/documentation/OCMF v1.0/SAFE-Testdatensatz-02_withoutXMLNamespace.xml @@ -0,0 +1,7 @@ + + + + OCMF|{"FV":"0.1","VI":"ABL","VV":"1.4p3","PG":"T12345","MV":"Phoenix Contact","MM":"EEM-350-D-MCB","MS":"BQ27400330016","MF":"1.0","IS":"VERIFIED","IF":["RFID_PLAIN","OCPP_RS_TLS"],"IT":"ISO14443","ID":"1F2D3A4F5506C7","RD":[{"TM":"2018-07-24T13:22:04,000+0200 S","TX":"B","RV":2935.6,"RI":"1-b:1.8.e","RU":"kWh","EI":567,"ST":"G"}]}|{"SA":"ECDSA-secp256k1-SHA256","SD":"3046022100A7F1FD39278A88432E1AB81229C34CE1066885D0EAD8810DB900018A4960888302210089004420623749BF75561F29685CD87D6853EC08E83BD1A15C5DAFF9F03F4115"} + 3056301006072A8648CE3D020106052B8104000A034200044E4970098EEFF5E0E286E3A38552679771B89315A49DDDF66EBAC6F176FB02DF9841091010E6850510540DAD0CF967FD8DE0AB25198282B39597DDCE09EDF459 + + \ No newline at end of file diff --git a/documentation/OCMF v1.0/SAFE-Testdatensatz-03.xml b/documentation/OCMF v1.0/SAFE-Testdatensatz-03.xml new file mode 100644 index 0000000..6b39ccf --- /dev/null +++ b/documentation/OCMF v1.0/SAFE-Testdatensatz-03.xml @@ -0,0 +1,19 @@ + + + + + T0NNRnx7IkZWIjoiMS4wIiwiR0kiOiJTRUFMIEFHIiwiR1MiOiIxODUwMDA2YSIsIkdWIjoiMS4zNCIsIlBHIjoiVDkyODkiLCJNViI6IkNhcmxvIEdhdmF6emkiLCJNTSI6IkVNMzQwLURJTi5BVjIuMy5YLlMxLlBGIiwiTVMiOiIqKioqKioyNDAwODRTIiwiTUYiOiJCNCIsIklTIjp0cnVlLCJJTCI6IlRSVVNURUQiLCJJRiI6WyJPQ0NQX0FVVEgiXSwiSVQiOiJJU08xNDQ0MyIsIklEIjoiNTYyMTNDMDUiLCJSRCI6W3siVE0iOiIyMDE5LTA2LTI2VDA4OjU3OjQ0LDMzNyswMDAwIFUiLCJUWCI6IkIiLCJSViI6MjY4Ljk3OCwiUkkiOiIxLWI6MS44LjAiLCJSVSI6ImtXaCIsIlJUIjoiQUMiLCJFRiI6IiIsIlNUIjoiRyJ9XX18eyJTRCI6IjMwNDQwMjIwMTQ1NUJGMTA4MkM5RUI4QjEyNzJEN0ZBODM4RUI0NDI4NkIwM0FDOTZFOEJBRkM1RTc5RTMwQzVCM0UxQjg3MjAyMjAwNjI4NkNBODFBRUUwRkFGQ0IxRDZBMTM3RkZCMkMwREQwMTQ3MjdFMkFFQzE0OUYzMENENUE3RTg3NjE5MTM5In0 + 3059301306072A8648CE3D020106082A8648CE3D030107034200044171CAB628050A228DA1D33129696D9ECA50FD50AFF04ABA2CE1E5EBBB1F457963B06A6A2D39175AB7C5B25685BEA3072197D00444C9DCE194817C21F35A4AC3 + + + + T0NNRnx7IkZWIjoiMS4wIiwiR0kiOiJTRUFMIEFHIiwiR1MiOiIxODUwMDA2YSIsIkdWIjoiMS4zNCIsIlBHIjoiVDkyOTAiLCJNViI6IkNhcmxvIEdhdmF6emkiLCJNTSI6IkVNMzQwLURJTi5BVjIuMy5YLlMxLlBGIiwiTVMiOiIqKioqKioyNDAwODRTIiwiTUYiOiJCNCIsIklTIjp0cnVlLCJJTCI6IlRSVVNURUQiLCJJRiI6WyJPQ0NQX0FVVEgiXSwiSVQiOiJJU08xNDQ0MyIsIklEIjoiNTYyMTNDMDUiLCJSRCI6W3siVE0iOiIyMDE5LTA2LTI2VDA4OjU3OjU0LDM0NCswMDAwIFUiLCJUWCI6IkMiLCJSViI6MjY4Ljk3OCwiUkkiOiIxLWI6MS44LjAiLCJSVSI6ImtXaCIsIlJUIjoiQUMiLCJFRiI6IiIsIlNUIjoiRyJ9XX18eyJTRCI6IjMwNDUwMjIxMDBBOEU4QTE3QTYxNzNDMUZEQkUxM0E3Q0YwNzNBOTlFRUZGNjdDNzJGNkM2OUY5NTEwQTc1RjRCQjYwOThFQzU2MDIyMDcyNUQyMERDREEyNzc1QTRCNTE4MUJCN0MwOEY3NzA1RUNBNzdCQjhGRDFBRUIyMDZCOEY2RDlCQzUwRjI2ODEifQ== + 3059301306072A8648CE3D020106082A8648CE3D030107034200044171CAB628050A228DA1D33129696D9ECA50FD50AFF04ABA2CE1E5EBBB1F457963B06A6A2D39175AB7C5B25685BEA3072197D00444C9DCE194817C21F35A4AC3 + + + + T0NNRnx7IkZWIjoiMS4wIiwiR0kiOiJTRUFMIEFHIiwiR1MiOiIxODUwMDA2YSIsIkdWIjoiMS4zNCIsIlBHIjoiVDkyOTEiLCJNViI6IkNhcmxvIEdhdmF6emkiLCJNTSI6IkVNMzQwLURJTi5BVjIuMy5YLlMxLlBGIiwiTVMiOiIqKioqKioyNDAwODRTIiwiTUYiOiJCNCIsIklTIjp0cnVlLCJJTCI6IlRSVVNURUQiLCJJRiI6WyJPQ0NQX0FVVEgiXSwiSVQiOiJJU08xNDQ0MyIsIklEIjoiNTYyMTNDMDUiLCJSRCI6W3siVE0iOiIyMDE5LTA2LTI2VDA4OjU3OjU4LDMxMCswMDAwIFUiLCJUWCI6IkUiLCJSViI6MjY4Ljk3OCwiUkkiOiIxLWI6MS44LjAiLCJSVSI6ImtXaCIsIlJUIjoiQUMiLCJFRiI6IiIsIlNUIjoiRyJ9XX18eyJTRCI6IjMwNDUwMjIxMDBGOTczOTgxQTQ5MTRBMTZGNjVCQzU4QkIxNUI4NTA1NEFFRDRERTM4MzREODlBQTkwQkUxQzEyQTJBMTVFNTJGMDIyMDI5Njk3OTZFMkQ0RDczNzAwMDgxOUI4RTI1RDgxNDY3NUZFRTg1MEI5QTdBNTQwNTE1MzczRDQxRERCNTM0MUIifQ== + 3059301306072A8648CE3D020106082A8648CE3D030107034200044171CAB628050A228DA1D33129696D9ECA50FD50AFF04ABA2CE1E5EBBB1F457963B06A6A2D39175AB7C5B25685BEA3072197D00444C9DCE194817C21F35A4AC3 + + + diff --git a/documentation/OCMF v1.0/SAFE-TransparencySoftware.xsd b/documentation/OCMF v1.0/SAFE-TransparencySoftware.xsd new file mode 100644 index 0000000..0448293 --- /dev/null +++ b/documentation/OCMF v1.0/SAFE-TransparencySoftware.xsd @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/js/OCMFTypes.ts b/src/js/OCMFTypes.ts new file mode 100644 index 0000000..afb79b7 --- /dev/null +++ b/src/js/OCMFTypes.ts @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2018-2019 GraphDefined GmbH + * This file is part of Chargy Desktop App + * + * Licensed under the Affero GPL license, Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.gnu.org/licenses/agpl.html + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const enum OCMFTransactionTypes +{ + undefined, + fiscal, + transaction +} + +interface IOCMFData { + + FV: string, + + PG: string, + + MV: string, + MM: string, + MS: string, + MF: string, + +} + +interface IOCMFData_v0_1 extends IOCMFData { + VI: string, + VV: string, +} + +interface IOCMFData_v1_0 extends IOCMFData { + GI: string, + GS: string, + GV: string, +} + diff --git a/src/js/chargy.ts b/src/js/chargy.ts index 5b6dc05..9b475b5 100644 --- a/src/js/chargy.ts +++ b/src/js/chargy.ts @@ -21,6 +21,8 @@ /// /// +/// + // import { debug } from "util"; // import * as crypto from "crypto"; // import { readSync } from "fs"; @@ -2293,9 +2295,335 @@ class ChargyApplication { //#endregion + //#region tryToParseTransparenzSoftwareXML(XMLDocument) + + private tryToParseTransparenzSoftwareXML(XMLDocument: Document) : boolean + { + + // The SAFE transparency software v1.0 does not understand its own + // XML namespace. Therefore we have to guess the format. + + try + { + + let values = XMLDocument.querySelectorAll("values"); + if (values.length == 1) + { + let valueList = values[0].querySelectorAll("value"); + if (valueList.length >= 1) + { + for (var i in valueList) + { + + //#region Parse XML... + + let signedDataEncoding = ""; + let signedDataFormat = ""; + let signedDataValue = ""; + let publicKeyEncoding = ""; + let publicKeyValue = ""; + + var signedData = valueList[i].querySelector("signedData"); + if (signedData != null) + { + + signedDataEncoding = signedData.attributes.getNamedItem("encoding") !== null ? signedData.attributes.getNamedItem("encoding")!.value.trim().toLowerCase() : ""; + signedDataFormat = signedData.attributes.getNamedItem("format") !== null ? signedData.attributes.getNamedItem("format")!.value.trim().toLowerCase() : ""; + signedDataValue = signedData.textContent !== null ? signedData.textContent.trim() : ""; + + switch (signedDataEncoding) + { + + //case "base32": + + case "base64": + signedDataValue = Buffer.from(signedDataValue, 'base64').toString(); + break; + + //case "hex": + + } + + } + + // Note: The public key is optional! + var publicKey = valueList[i].querySelector("publicKey"); + if (publicKey != null) + { + + publicKeyEncoding = publicKey.attributes.getNamedItem("encoding") !== null ? publicKey.attributes.getNamedItem("encoding")!.value.trim().toLowerCase() : ""; + publicKeyValue = publicKey.textContent !== null ? publicKey.textContent.trim() : ""; + + switch (publicKeyEncoding) + { + + //case "base32": + + case "base64": + publicKeyValue = Buffer.from(publicKeyValue, 'base64').toString(); + break; + + //case "hex": + + } + + } + + //#endregion + + if (signedDataValue !== "") + { + switch (signedDataFormat) + { + + case "ocmf": + this.tryToParseOCMF(signedDataValue, publicKeyValue); + break; + + } + } + + } + } + } + + } + catch (exception) + { } + + return false; + + } + + //#endregion + + //#region tryToParseOCMF(OCMF, PublicKey?) + + //#region tryToParseOCMFv0_1(OCMFData, PublicKey?) + + private tryToParseOCMFv0_1(OCMFData: IOCMFData_v0_1, + PublicKey?: string) : boolean + { + + // { + // "FV": "0.1", + // "VI": "ABL", + // "VV": "1.4p3", + // + // "PG": "T12345", + // + // "MV": "Phoenix Contact", + // "MM": "EEM-350-D-MCB", + // "MS": "BQ27400330016", + // "MF": "1.0", + // + // "IS": "VERIFIED", + // "IF": ["RFID_PLAIN", "OCPP_RS_TLS"], + // "IT": "ISO14443", + // "ID": "1F2D3A4F5506C7", + // + // "RD": [{ + // "TM": "2018-07-24T13:22:04,000+0200 S", + // "TX": "B", + // "RV": 2935.6, + // "RI": "1-b:1.8.e", + // "RU": "kWh", + // "EI": 567, + // "ST": "G" + // }] + // } + + try + { + + let VendorInformation :string = OCMFData.VI != null ? OCMFData.VI.trim() : ""; // Some text about the manufacturer, model, variant, ... of e.g. the vendor. + let VendorVersion :string = OCMFData.VV != null ? OCMFData.VV.trim() : ""; // Software version of the vendor. + + let paging :string = OCMFData.PG != null ? OCMFData.PG.trim() : ""; // Paging, as this data might be part of a larger context. + let transactionType = OCMFTransactionTypes.undefined; + switch (paging[0].toLowerCase()) + { + + case 't': + transactionType = OCMFTransactionTypes.transaction; + break; + + case 'f': + transactionType = OCMFTransactionTypes.fiscal; + break + + } + let pagingId = paging.substring(1); + + let MeterVendor :string = OCMFData.MV != null ? OCMFData.MV.trim() : ""; // Vendor of the device, optional. + let MeterModel :string = OCMFData.MM != null ? OCMFData.MM.trim() : ""; // Model of the device, optional. + let MeterSerial :string = OCMFData.MS != null ? OCMFData.MS.trim() : ""; // Serialnumber of the device, might be optional. + let MeterFirmware :string = OCMFData.MF != null ? OCMFData.MF.trim() : ""; // Software version of the device. + + } catch (exception) + { } + + return false; + + } + + //#endregion + + //#region tryToParseOCMFv1_0(OCMFData, PublicKey?) + + private tryToParseOCMFv1_0(OCMFData: IOCMFData_v1_0, + PublicKey?: string) : boolean + { + + // { + // "FV": "1.0", + // "GI": "SEAL AG", + // "GS": "1850006a", + // "GV": "1.34", + // + // "PG": "T9289", + // + // "MV": "Carlo Gavazzi", + // "MM": "EM340-DIN.AV2.3.X.S1.PF", + // "MS": "******240084S", + // "MF": "B4", + // + // "IS": true, + // "IL": "TRUSTED", + // "IF": ["OCCP_AUTH"], + // "IT": "ISO14443", + // "ID": "56213C05", + // + // "RD": [{ + // "TM": "2019-06-26T08:57:44,337+0000 U", + // "TX": "B", + // "RV": 268.978, + // "RI": "1-b:1.8.0", + // "RU": "kWh", + // "RT": "AC", + // "EF": "", + // "ST": "G" + // }] + // } + + try + { + + let GatewayInformation :string = OCMFData.GI != null ? OCMFData.GI.trim() : ""; // Some text about the manufacturer, model, variant, ... of e.g. the gateway. + let GatewaySerial :string = OCMFData.GS != null ? OCMFData.GS.trim() : ""; // Serial number of the gateway, might be mandatory. + let GatewayVersion :string = OCMFData.GV != null ? OCMFData.GV.trim() : ""; // Software version of the gateway. + + let paging :string = OCMFData.PG != null ? OCMFData.PG.trim() : ""; // Paging, as this data might be part of a larger context. + let transactionType = OCMFTransactionTypes.undefined; + switch (paging[0].toLowerCase()) + { + + case 't': + transactionType = OCMFTransactionTypes.transaction; + break; + + case 'f': + transactionType = OCMFTransactionTypes.fiscal; + break + + } + let pagingId = paging.substring(1); + + let MeterVendor :string = OCMFData.MV != null ? OCMFData.MV.trim() : ""; // Vendor of the device, optional. + let MeterModel :string = OCMFData.MM != null ? OCMFData.MM.trim() : ""; // Model of the device, optional. + let MeterSerial :string = OCMFData.MS != null ? OCMFData.MS.trim() : ""; // Serialnumber of the device, might be optional. + let MeterFirmware :string = OCMFData.MF != null ? OCMFData.MF.trim() : ""; // Software version of the device. + + } catch (exception) + { } + + return false; + + } + + //#endregion + + private tryToParseOCMF(OCMF: string, + PublicKey?: string) : boolean + { + + // OCMF|{"FV":"1.0","GI":"SEAL AG","GS":"1850006a","GV":"1.34","PG":"T9289","MV":"Carlo Gavazzi","MM":"EM340-DIN.AV2.3.X.S1.PF","MS":"******240084S","MF":"B4","IS":true,"IL":"TRUSTED","IF":["OCCP_AUTH"],"IT":"ISO14443","ID":"56213C05","RD":[{"TM":"2019-06-26T08:57:44,337+0000 U","TX":"B","RV":268.978,"RI":"1-b:1.8.0","RU":"kWh","RT":"AC","EF":"","ST":"G"}]}|{"SD":"304402201455BF1082C9EB8B1272D7FA838EB44286B03AC96E8BAFC5E79E30C5B3E1B872022006286CA81AEE0FAFCB1D6A137FFB2C0DD014727E2AEC149F30CD5A7E87619139"} + let elements = OCMF.split('|'); + + if (elements.length == 3) + { + + try + { + + let OCMFData = JSON.parse(elements[1]); + let OCMFSignature = JSON.parse(elements[2]); + + + // http://hers.abl.de/SAFE/Datenformat_OCMF/Datenformat_OCMF_v1.0.pdf + // Ein Darstellungsformat, JSON-basiert (nachvollziehbar) + // Ein Übertragungsformat, JSON-basiert (vereinheitlicht) + // + // { + // "FV": "1.0", + // "GI": "SEAL AG", + // "GS": "1850006a", + // "GV": "1.34", + // + // "PG": "T9289", + // + // "MV": "Carlo Gavazzi", + // "MM": "EM340-DIN.AV2.3.X.S1.PF", + // "MS": "******240084S", + // "MF": "B4", + // + // "IS": true, + // "IL": "TRUSTED", + // "IF": ["OCCP_AUTH"], + // "IT": "ISO14443", + // "ID": "56213C05", + // + // "RD": [{ + // "TM": "2019-06-26T08:57:44,337+0000 U", + // "TX": "B", + // "RV": 268.978, + // "RI": "1-b:1.8.0", + // "RU": "kWh", + // "RT": "AC", + // "EF": "", + // "ST": "G" + // }] + // } + + // Protocol version: major.minor + let FormatVersion:string = OCMFData["FV"] != null ? OCMFData["FV"].trim() : ""; + + switch (FormatVersion) + { + + case "0.1": + return this.tryToParseOCMFv0_1(OCMFData as IOCMFData_v0_1, PublicKey); + + case "1.0": + return this.tryToParseOCMFv1_0(OCMFData as IOCMFData_v1_0, PublicKey); + + } + + } + catch (exception) + { } + + } + + return false; + + } + + //#endregion + //#region detectContentFormat(Content) - private detectContentFormat(Content: IChargeTransparencyRecord) { + private detectContentFormat(Content: string) { if (Content == null) return; @@ -2303,21 +2631,120 @@ class ChargyApplication { this.inputInfosDiv.style.display = 'none'; this.errorTextDiv.style.display = 'none'; - switch (Content["@context"]) + //#region Clean data + + Content = Content.trim(); + + // Catches EFBBBF (UTF-8 BOM) because the buffer-to-string + // conversion translates it to FEFF (UTF-16 BOM) + if (Content.charCodeAt(0) === 0xFEFF) + Content = Content.substr(1); + + //#endregion + + //#region XML processing... + + if (Content.startsWith(" { try { - this.detectContentFormat(JSON.parse((event.target as any).result)); + this.detectContentFormat((event.target as any).result); } catch (exception) { this.doGlobalError("Fehlerhafter Transparenzdatensatz!", exception); diff --git a/src/main.js b/src/main.js index 175a7f7..435d122 100644 --- a/src/main.js +++ b/src/main.js @@ -25,7 +25,7 @@ function createWindow () { mainWindow.loadFile('src/index.html') // Open the DevTools. - // mainWindow.webContents.openDevTools() + mainWindow.webContents.openDevTools() // Emitted when the window is closed. mainWindow.on('closed', function () { From dbe922192fa87b898a76bce98403f2fe09d581c6 Mon Sep 17 00:00:00 2001 From: Achim Friedland Date: Sun, 18 Aug 2019 18:23:58 +0200 Subject: [PATCH 003/110] Update test files to OCMF v1.0 --- ...AFE-Testdatensatz-02_emptyXMLNamespace.xml | 6 +++--- ...SAFE-Testdatensatz-02_withXMLNamespace.xml | 6 +++--- ...E-Testdatensatz-02_withoutXMLNamespace.xml | 6 +++--- .../OCMF v1.0/SAFE-Testdatensatz-03.xml | 19 ------------------- ...tdatensatz-03_multipleOCMFMeasurements.xml | 19 +++++++++++++++++++ 5 files changed, 28 insertions(+), 28 deletions(-) delete mode 100644 documentation/OCMF v1.0/SAFE-Testdatensatz-03.xml create mode 100644 documentation/OCMF v1.0/SAFE-Testdatensatz-03_multipleOCMFMeasurements.xml diff --git a/documentation/OCMF v1.0/SAFE-Testdatensatz-02_emptyXMLNamespace.xml b/documentation/OCMF v1.0/SAFE-Testdatensatz-02_emptyXMLNamespace.xml index 2d1a686..e6d28df 100644 --- a/documentation/OCMF v1.0/SAFE-Testdatensatz-02_emptyXMLNamespace.xml +++ b/documentation/OCMF v1.0/SAFE-Testdatensatz-02_emptyXMLNamespace.xml @@ -1,7 +1,7 @@ - OCMF|{"FV":"0.1","VI":"ABL","VV":"1.4p3","PG":"T12345","MV":"Phoenix Contact","MM":"EEM-350-D-MCB","MS":"BQ27400330016","MF":"1.0","IS":"VERIFIED","IF":["RFID_PLAIN","OCPP_RS_TLS"],"IT":"ISO14443","ID":"1F2D3A4F5506C7","RD":[{"TM":"2018-07-24T13:22:04,000+0200 S","TX":"B","RV":2935.6,"RI":"1-b:1.8.e","RU":"kWh","EI":567,"ST":"G"}]}|{"SA":"ECDSA-secp256k1-SHA256","SD":"3046022100A7F1FD39278A88432E1AB81229C34CE1066885D0EAD8810DB900018A4960888302210089004420623749BF75561F29685CD87D6853EC08E83BD1A15C5DAFF9F03F4115"} - 3056301006072A8648CE3D020106052B8104000A034200044E4970098EEFF5E0E286E3A38552679771B89315A49DDDF66EBAC6F176FB02DF9841091010E6850510540DAD0CF967FD8DE0AB25198282B39597DDCE09EDF459 + OCMF|{"FV":"1.0","GI":"SEAL AG","GS":"1850006a","GV":"1.34","PG":"T9289","MV":"Carlo Gavazzi","MM":"EM340-DIN.AV2.3.X.S1.PF","MS":"******240084S","MF":"B4","IS":true,"IL":"TRUSTED","IF":["OCCP_AUTH"],"IT":"ISO14443","ID":"56213C05","RD":[{"TM":"2019-06-26T08:57:44,337+0000 U","TX":"B","RV":268.978,"RI":"1-b:1.8.0","RU":"kWh","RT":"AC","EF":"","ST":"G"}]}|{"SD":"304402201455BF1082C9EB8B1272D7FA838EB44286B03AC96E8BAFC5E79E30C5B3E1B872022006286CA81AEE0FAFCB1D6A137FFB2C0DD014727E2AEC149F30CD5A7E87619139"} + 3059301306072A8648CE3D020106082A8648CE3D030107034200044171CAB628050A228DA1D33129696D9ECA50FD50AFF04ABA2CE1E5EBBB1F457963B06A6A2D39175AB7C5B25685BEA3072197D00444C9DCE194817C21F35A4AC3 - \ No newline at end of file + diff --git a/documentation/OCMF v1.0/SAFE-Testdatensatz-02_withXMLNamespace.xml b/documentation/OCMF v1.0/SAFE-Testdatensatz-02_withXMLNamespace.xml index 9ba8ad1..a848a1e 100644 --- a/documentation/OCMF v1.0/SAFE-Testdatensatz-02_withXMLNamespace.xml +++ b/documentation/OCMF v1.0/SAFE-Testdatensatz-02_withXMLNamespace.xml @@ -1,7 +1,7 @@ - OCMF|{"FV":"0.1","VI":"ABL","VV":"1.4p3","PG":"T12345","MV":"Phoenix Contact","MM":"EEM-350-D-MCB","MS":"BQ27400330016","MF":"1.0","IS":"VERIFIED","IF":["RFID_PLAIN","OCPP_RS_TLS"],"IT":"ISO14443","ID":"1F2D3A4F5506C7","RD":[{"TM":"2018-07-24T13:22:04,000+0200 S","TX":"B","RV":2935.6,"RI":"1-b:1.8.e","RU":"kWh","EI":567,"ST":"G"}]}|{"SA":"ECDSA-secp256k1-SHA256","SD":"3046022100A7F1FD39278A88432E1AB81229C34CE1066885D0EAD8810DB900018A4960888302210089004420623749BF75561F29685CD87D6853EC08E83BD1A15C5DAFF9F03F4115"} - 3056301006072A8648CE3D020106052B8104000A034200044E4970098EEFF5E0E286E3A38552679771B89315A49DDDF66EBAC6F176FB02DF9841091010E6850510540DAD0CF967FD8DE0AB25198282B39597DDCE09EDF459 + OCMF|{"FV":"1.0","GI":"SEAL AG","GS":"1850006a","GV":"1.34","PG":"T9289","MV":"Carlo Gavazzi","MM":"EM340-DIN.AV2.3.X.S1.PF","MS":"******240084S","MF":"B4","IS":true,"IL":"TRUSTED","IF":["OCCP_AUTH"],"IT":"ISO14443","ID":"56213C05","RD":[{"TM":"2019-06-26T08:57:44,337+0000 U","TX":"B","RV":268.978,"RI":"1-b:1.8.0","RU":"kWh","RT":"AC","EF":"","ST":"G"}]}|{"SD":"304402201455BF1082C9EB8B1272D7FA838EB44286B03AC96E8BAFC5E79E30C5B3E1B872022006286CA81AEE0FAFCB1D6A137FFB2C0DD014727E2AEC149F30CD5A7E87619139"} + 3059301306072A8648CE3D020106082A8648CE3D030107034200044171CAB628050A228DA1D33129696D9ECA50FD50AFF04ABA2CE1E5EBBB1F457963B06A6A2D39175AB7C5B25685BEA3072197D00444C9DCE194817C21F35A4AC3 - \ No newline at end of file + diff --git a/documentation/OCMF v1.0/SAFE-Testdatensatz-02_withoutXMLNamespace.xml b/documentation/OCMF v1.0/SAFE-Testdatensatz-02_withoutXMLNamespace.xml index edb9711..8a75a04 100644 --- a/documentation/OCMF v1.0/SAFE-Testdatensatz-02_withoutXMLNamespace.xml +++ b/documentation/OCMF v1.0/SAFE-Testdatensatz-02_withoutXMLNamespace.xml @@ -1,7 +1,7 @@ - OCMF|{"FV":"0.1","VI":"ABL","VV":"1.4p3","PG":"T12345","MV":"Phoenix Contact","MM":"EEM-350-D-MCB","MS":"BQ27400330016","MF":"1.0","IS":"VERIFIED","IF":["RFID_PLAIN","OCPP_RS_TLS"],"IT":"ISO14443","ID":"1F2D3A4F5506C7","RD":[{"TM":"2018-07-24T13:22:04,000+0200 S","TX":"B","RV":2935.6,"RI":"1-b:1.8.e","RU":"kWh","EI":567,"ST":"G"}]}|{"SA":"ECDSA-secp256k1-SHA256","SD":"3046022100A7F1FD39278A88432E1AB81229C34CE1066885D0EAD8810DB900018A4960888302210089004420623749BF75561F29685CD87D6853EC08E83BD1A15C5DAFF9F03F4115"} - 3056301006072A8648CE3D020106052B8104000A034200044E4970098EEFF5E0E286E3A38552679771B89315A49DDDF66EBAC6F176FB02DF9841091010E6850510540DAD0CF967FD8DE0AB25198282B39597DDCE09EDF459 + OCMF|{"FV":"1.0","GI":"SEAL AG","GS":"1850006a","GV":"1.34","PG":"T9289","MV":"Carlo Gavazzi","MM":"EM340-DIN.AV2.3.X.S1.PF","MS":"******240084S","MF":"B4","IS":true,"IL":"TRUSTED","IF":["OCCP_AUTH"],"IT":"ISO14443","ID":"56213C05","RD":[{"TM":"2019-06-26T08:57:44,337+0000 U","TX":"B","RV":268.978,"RI":"1-b:1.8.0","RU":"kWh","RT":"AC","EF":"","ST":"G"}]}|{"SD":"304402201455BF1082C9EB8B1272D7FA838EB44286B03AC96E8BAFC5E79E30C5B3E1B872022006286CA81AEE0FAFCB1D6A137FFB2C0DD014727E2AEC149F30CD5A7E87619139"} + 3059301306072A8648CE3D020106082A8648CE3D030107034200044171CAB628050A228DA1D33129696D9ECA50FD50AFF04ABA2CE1E5EBBB1F457963B06A6A2D39175AB7C5B25685BEA3072197D00444C9DCE194817C21F35A4AC3 - \ No newline at end of file + diff --git a/documentation/OCMF v1.0/SAFE-Testdatensatz-03.xml b/documentation/OCMF v1.0/SAFE-Testdatensatz-03.xml deleted file mode 100644 index 6b39ccf..0000000 --- a/documentation/OCMF v1.0/SAFE-Testdatensatz-03.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - T0NNRnx7IkZWIjoiMS4wIiwiR0kiOiJTRUFMIEFHIiwiR1MiOiIxODUwMDA2YSIsIkdWIjoiMS4zNCIsIlBHIjoiVDkyODkiLCJNViI6IkNhcmxvIEdhdmF6emkiLCJNTSI6IkVNMzQwLURJTi5BVjIuMy5YLlMxLlBGIiwiTVMiOiIqKioqKioyNDAwODRTIiwiTUYiOiJCNCIsIklTIjp0cnVlLCJJTCI6IlRSVVNURUQiLCJJRiI6WyJPQ0NQX0FVVEgiXSwiSVQiOiJJU08xNDQ0MyIsIklEIjoiNTYyMTNDMDUiLCJSRCI6W3siVE0iOiIyMDE5LTA2LTI2VDA4OjU3OjQ0LDMzNyswMDAwIFUiLCJUWCI6IkIiLCJSViI6MjY4Ljk3OCwiUkkiOiIxLWI6MS44LjAiLCJSVSI6ImtXaCIsIlJUIjoiQUMiLCJFRiI6IiIsIlNUIjoiRyJ9XX18eyJTRCI6IjMwNDQwMjIwMTQ1NUJGMTA4MkM5RUI4QjEyNzJEN0ZBODM4RUI0NDI4NkIwM0FDOTZFOEJBRkM1RTc5RTMwQzVCM0UxQjg3MjAyMjAwNjI4NkNBODFBRUUwRkFGQ0IxRDZBMTM3RkZCMkMwREQwMTQ3MjdFMkFFQzE0OUYzMENENUE3RTg3NjE5MTM5In0 - 3059301306072A8648CE3D020106082A8648CE3D030107034200044171CAB628050A228DA1D33129696D9ECA50FD50AFF04ABA2CE1E5EBBB1F457963B06A6A2D39175AB7C5B25685BEA3072197D00444C9DCE194817C21F35A4AC3 - - - - T0NNRnx7IkZWIjoiMS4wIiwiR0kiOiJTRUFMIEFHIiwiR1MiOiIxODUwMDA2YSIsIkdWIjoiMS4zNCIsIlBHIjoiVDkyOTAiLCJNViI6IkNhcmxvIEdhdmF6emkiLCJNTSI6IkVNMzQwLURJTi5BVjIuMy5YLlMxLlBGIiwiTVMiOiIqKioqKioyNDAwODRTIiwiTUYiOiJCNCIsIklTIjp0cnVlLCJJTCI6IlRSVVNURUQiLCJJRiI6WyJPQ0NQX0FVVEgiXSwiSVQiOiJJU08xNDQ0MyIsIklEIjoiNTYyMTNDMDUiLCJSRCI6W3siVE0iOiIyMDE5LTA2LTI2VDA4OjU3OjU0LDM0NCswMDAwIFUiLCJUWCI6IkMiLCJSViI6MjY4Ljk3OCwiUkkiOiIxLWI6MS44LjAiLCJSVSI6ImtXaCIsIlJUIjoiQUMiLCJFRiI6IiIsIlNUIjoiRyJ9XX18eyJTRCI6IjMwNDUwMjIxMDBBOEU4QTE3QTYxNzNDMUZEQkUxM0E3Q0YwNzNBOTlFRUZGNjdDNzJGNkM2OUY5NTEwQTc1RjRCQjYwOThFQzU2MDIyMDcyNUQyMERDREEyNzc1QTRCNTE4MUJCN0MwOEY3NzA1RUNBNzdCQjhGRDFBRUIyMDZCOEY2RDlCQzUwRjI2ODEifQ== - 3059301306072A8648CE3D020106082A8648CE3D030107034200044171CAB628050A228DA1D33129696D9ECA50FD50AFF04ABA2CE1E5EBBB1F457963B06A6A2D39175AB7C5B25685BEA3072197D00444C9DCE194817C21F35A4AC3 - - - - T0NNRnx7IkZWIjoiMS4wIiwiR0kiOiJTRUFMIEFHIiwiR1MiOiIxODUwMDA2YSIsIkdWIjoiMS4zNCIsIlBHIjoiVDkyOTEiLCJNViI6IkNhcmxvIEdhdmF6emkiLCJNTSI6IkVNMzQwLURJTi5BVjIuMy5YLlMxLlBGIiwiTVMiOiIqKioqKioyNDAwODRTIiwiTUYiOiJCNCIsIklTIjp0cnVlLCJJTCI6IlRSVVNURUQiLCJJRiI6WyJPQ0NQX0FVVEgiXSwiSVQiOiJJU08xNDQ0MyIsIklEIjoiNTYyMTNDMDUiLCJSRCI6W3siVE0iOiIyMDE5LTA2LTI2VDA4OjU3OjU4LDMxMCswMDAwIFUiLCJUWCI6IkUiLCJSViI6MjY4Ljk3OCwiUkkiOiIxLWI6MS44LjAiLCJSVSI6ImtXaCIsIlJUIjoiQUMiLCJFRiI6IiIsIlNUIjoiRyJ9XX18eyJTRCI6IjMwNDUwMjIxMDBGOTczOTgxQTQ5MTRBMTZGNjVCQzU4QkIxNUI4NTA1NEFFRDRERTM4MzREODlBQTkwQkUxQzEyQTJBMTVFNTJGMDIyMDI5Njk3OTZFMkQ0RDczNzAwMDgxOUI4RTI1RDgxNDY3NUZFRTg1MEI5QTdBNTQwNTE1MzczRDQxRERCNTM0MUIifQ== - 3059301306072A8648CE3D020106082A8648CE3D030107034200044171CAB628050A228DA1D33129696D9ECA50FD50AFF04ABA2CE1E5EBBB1F457963B06A6A2D39175AB7C5B25685BEA3072197D00444C9DCE194817C21F35A4AC3 - - - diff --git a/documentation/OCMF v1.0/SAFE-Testdatensatz-03_multipleOCMFMeasurements.xml b/documentation/OCMF v1.0/SAFE-Testdatensatz-03_multipleOCMFMeasurements.xml new file mode 100644 index 0000000..45e516b --- /dev/null +++ b/documentation/OCMF v1.0/SAFE-Testdatensatz-03_multipleOCMFMeasurements.xml @@ -0,0 +1,19 @@ + + + + + OCMF|{"FV":"1.0","GI":"SEAL AG","GS":"1850006a","GV":"1.34","PG":"T9289","MV":"Carlo Gavazzi","MM":"EM340-DIN.AV2.3.X.S1.PF","MS":"******240084S","MF":"B4","IS":true,"IL":"TRUSTED","IF":["OCCP_AUTH"],"IT":"ISO14443","ID":"56213C05","RD":[{"TM":"2019-06-26T08:57:44,337+0000 U","TX":"B","RV":268.978,"RI":"1-b:1.8.0","RU":"kWh","RT":"AC","EF":"","ST":"G"}]}|{"SD":"304402201455BF1082C9EB8B1272D7FA838EB44286B03AC96E8BAFC5E79E30C5B3E1B872022006286CA81AEE0FAFCB1D6A137FFB2C0DD014727E2AEC149F30CD5A7E87619139"} + 3059301306072A8648CE3D020106082A8648CE3D030107034200044171CAB628050A228DA1D33129696D9ECA50FD50AFF04ABA2CE1E5EBBB1F457963B06A6A2D39175AB7C5B25685BEA3072197D00444C9DCE194817C21F35A4AC3 + + + + OCMF|{"FV":"1.0","GI":"SEAL AG","GS":"1850006a","GV":"1.34","PG":"T9290","MV":"Carlo Gavazzi","MM":"EM340-DIN.AV2.3.X.S1.PF","MS":"******240084S","MF":"B4","IS":true,"IL":"TRUSTED","IF":["OCCP_AUTH"],"IT":"ISO14443","ID":"56213C05","RD":[{"TM":"2019-06-26T08:57:54,344+0000 U","TX":"C","RV":268.978,"RI":"1-b:1.8.0","RU":"kWh","RT":"AC","EF":"","ST":"G"}]}|{"SD":"3045022100A8E8A17A6173C1FDBE13A7CF073A99EEFF67C72F6C69F9510A75F4BB6098EC560220725D20DCDA2775A4B5181BB7C08F7705ECA77BB8FD1AEB206B8F6D9BC50F2681"} + 3059301306072A8648CE3D020106082A8648CE3D030107034200044171CAB628050A228DA1D33129696D9ECA50FD50AFF04ABA2CE1E5EBBB1F457963B06A6A2D39175AB7C5B25685BEA3072197D00444C9DCE194817C21F35A4AC3 + + + + OCMF|{"FV":"1.0","GI":"SEAL AG","GS":"1850006a","GV":"1.34","PG":"T9291","MV":"Carlo Gavazzi","MM":"EM340-DIN.AV2.3.X.S1.PF","MS":"******240084S","MF":"B4","IS":true,"IL":"TRUSTED","IF":["OCCP_AUTH"],"IT":"ISO14443","ID":"56213C05","RD":[{"TM":"2019-06-26T08:57:58,310+0000 U","TX":"E","RV":268.978,"RI":"1-b:1.8.0","RU":"kWh","RT":"AC","EF":"","ST":"G"}]}|{"SD":"3045022100F973981A4914A16F65BC58BB15B85054AED4DE3834D89AA90BE1C12A2A15E52F02202969796E2D4D737000819B8E25D814675FEE850B9A7A540515373D41DDB5341B"} + 3059301306072A8648CE3D020106082A8648CE3D030107034200044171CAB628050A228DA1D33129696D9ECA50FD50AFF04ABA2CE1E5EBBB1F457963B06A6A2D39175AB7C5B25685BEA3072197D00444C9DCE194817C21F35A4AC3 + + + From 8ea72a7ae888fd165ca7fcc625c1113e44cce9ba Mon Sep 17 00:00:00 2001 From: Achim Friedland Date: Sun, 18 Aug 2019 18:40:57 +0200 Subject: [PATCH 004/110] Update test files to OCMF v0.1 --- documentation/OCMF v1.0/SAFE-Testdatensatz-01.xml | 7 ------- documentation/OCMF v1.0/SAFE-Testdatensatz-01_OCMFv0.1.xml | 7 +++++++ 2 files changed, 7 insertions(+), 7 deletions(-) delete mode 100644 documentation/OCMF v1.0/SAFE-Testdatensatz-01.xml create mode 100644 documentation/OCMF v1.0/SAFE-Testdatensatz-01_OCMFv0.1.xml diff --git a/documentation/OCMF v1.0/SAFE-Testdatensatz-01.xml b/documentation/OCMF v1.0/SAFE-Testdatensatz-01.xml deleted file mode 100644 index 7bafb0b..0000000 --- a/documentation/OCMF v1.0/SAFE-Testdatensatz-01.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - ENCODED STRING - 887FABF407AC82782EEFFF2220C2F856AEB0BC22364BBCC6B55761911ED651D1A922BADA88818C9671AFEE7094D7F536 - - diff --git a/documentation/OCMF v1.0/SAFE-Testdatensatz-01_OCMFv0.1.xml b/documentation/OCMF v1.0/SAFE-Testdatensatz-01_OCMFv0.1.xml new file mode 100644 index 0000000..edb9711 --- /dev/null +++ b/documentation/OCMF v1.0/SAFE-Testdatensatz-01_OCMFv0.1.xml @@ -0,0 +1,7 @@ + + + + OCMF|{"FV":"0.1","VI":"ABL","VV":"1.4p3","PG":"T12345","MV":"Phoenix Contact","MM":"EEM-350-D-MCB","MS":"BQ27400330016","MF":"1.0","IS":"VERIFIED","IF":["RFID_PLAIN","OCPP_RS_TLS"],"IT":"ISO14443","ID":"1F2D3A4F5506C7","RD":[{"TM":"2018-07-24T13:22:04,000+0200 S","TX":"B","RV":2935.6,"RI":"1-b:1.8.e","RU":"kWh","EI":567,"ST":"G"}]}|{"SA":"ECDSA-secp256k1-SHA256","SD":"3046022100A7F1FD39278A88432E1AB81229C34CE1066885D0EAD8810DB900018A4960888302210089004420623749BF75561F29685CD87D6853EC08E83BD1A15C5DAFF9F03F4115"} + 3056301006072A8648CE3D020106052B8104000A034200044E4970098EEFF5E0E286E3A38552679771B89315A49DDDF66EBAC6F176FB02DF9841091010E6850510540DAD0CF967FD8DE0AB25198282B39597DDCE09EDF459 + + \ No newline at end of file From b901bd0e6d2711ec8a8c226628dd8532a317d642 Mon Sep 17 00:00:00 2001 From: Achim Friedland Date: Sun, 25 Aug 2019 17:39:44 +0200 Subject: [PATCH 005/110] Merge with async/await SHA256 methods from the ChargyMobileApp --- .../chargeIT-Testdatensatz-01.chargy | 2 +- .../chargeIT-Testdatensatz-02.chargy | 2 +- src/js/ACrypt.ts | 10 ++- src/js/EMHCrypt01.ts | 63 ++++++++----------- src/js/GDFCrypt01.ts | 43 +++++-------- src/js/chargy.ts | 42 ++++++------- src/js/chargyInterfaces.ts | 2 +- 7 files changed, 70 insertions(+), 94 deletions(-) diff --git a/documentation/chargeIT-Testdatensatz-01.chargy b/documentation/chargeIT-Testdatensatz-01.chargy index 56a4670..d46b545 100644 --- a/documentation/chargeIT-Testdatensatz-01.chargy +++ b/documentation/chargeIT-Testdatensatz-01.chargy @@ -145,4 +145,4 @@ "signature": "6DF01D7603CB49BB76141F8E67B371351BF1F87C1F8D38AEB3600A9432B8CE0A378126D4FB9D9581457651A5D208AD9E" } ] -} \ No newline at end of file +} diff --git a/documentation/chargeIT-Testdatensatz-02.chargy b/documentation/chargeIT-Testdatensatz-02.chargy index 09ac43d..78aea7d 100644 --- a/documentation/chargeIT-Testdatensatz-02.chargy +++ b/documentation/chargeIT-Testdatensatz-02.chargy @@ -135,7 +135,7 @@ "format": "rs" }, "measurements": [{ - "meterId": "0901454D48000083E076", + "energyMeterId": "0901454D48000083E076", "@context": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/EMHCrypt01+json", "name": "ENERGY_TOTAL", "obis": "0100011100FF", diff --git a/src/js/ACrypt.ts b/src/js/ACrypt.ts index 890f43a..364370a 100644 --- a/src/js/ACrypt.ts +++ b/src/js/ACrypt.ts @@ -26,8 +26,6 @@ abstract class ACrypt { readonly elliptic: any; readonly moment: any; - // variable 'crypto' is already defined differently in Google Chrome! - readonly crypt = require('electron').remote.require('crypto'); constructor(description: string, GetMeter: GetMeterFunc, @@ -96,19 +94,19 @@ abstract class ACrypt { } async sha256(message: DataView) { - const hashBuffer = await crypto.subtle.digest('SHA-256', message);// new TextEncoder().encode(message)); + const hashBuffer = await crypto.subtle.digest('SHA-256', message); const hashArray = Array.from(new Uint8Array(hashBuffer)); // convert hash to byte array const hashHex = hashArray.map(b => ('00' + b.toString(16)).slice(-2)).join('').toLowerCase(); // convert bytes to hex string return hashHex; } - abstract VerifyChargingSession(chargingSession: IChargingSession): ISessionCryptoResult; + abstract VerifyChargingSession(chargingSession: IChargingSession): Promise; abstract SignMeasurement(measurementValue: IMeasurementValue, privateKey: any, - publicKey: any): ICryptoResult; + publicKey: any): Promise; - abstract VerifyMeasurement(measurementValue: IMeasurementValue): ICryptoResult; + abstract VerifyMeasurement(measurementValue: IMeasurementValue): Promise; abstract ViewMeasurement(measurementValue: IMeasurementValue, introDiv: HTMLDivElement, diff --git a/src/js/EMHCrypt01.ts b/src/js/EMHCrypt01.ts index 1802aed..1f1012d 100644 --- a/src/js/EMHCrypt01.ts +++ b/src/js/EMHCrypt01.ts @@ -75,17 +75,11 @@ class EMHCrypt01 extends ACrypt { // publicKeyHEX = publicKey.encode('hex').toLowerCase(); } - SignMeasurement(measurementValue: IEMHMeasurementValue, - privateKey: any, - publicKey: any): IEMHCrypt01Result + async SignMeasurement(measurementValue: IEMHMeasurementValue, + privateKey: any, + publicKey: any): Promise { - // var keypair = this.curve.genKeyPair(); - // privateKey = keypair.getPrivate(); - // publicKey = keypair.getPublic(); - // var privateKeyHEX = privateKey.toString('hex').toLowerCase(); - // var publicKeyHEX = publicKey.encode('hex').toLowerCase(); - var buffer = new ArrayBuffer(320); var cryptoBuffer = new DataView(buffer); @@ -106,11 +100,7 @@ class EMHCrypt01 extends ACrypt { }; // Only the first 24 bytes/192 bits are used! - cryptoResult.sha256value = this.crypt.createHash ('sha256'). - update (cryptoBuffer). - digest ('hex'). - toLowerCase(). - substring (0, 48); + cryptoResult.sha256value = (await this.sha256(cryptoBuffer)).substring(0, 48); cryptoResult.publicKey = publicKey.encode('hex'). toLowerCase(); @@ -155,7 +145,7 @@ class EMHCrypt01 extends ACrypt { } - VerifyChargingSession(chargingSession: IChargingSession): ISessionCryptoResult + async VerifyChargingSession(chargingSession: IChargingSession): Promise { var sessionResult = SessionVerificationResult.UnknownSessionFormat; @@ -175,7 +165,7 @@ class EMHCrypt01 extends ACrypt { for (var measurementValue of measurement.values) { measurementValue.measurement = measurement; - this.VerifyMeasurement(measurementValue as IEMHMeasurementValue); + await this.VerifyMeasurement(measurementValue as IEMHMeasurementValue); } @@ -206,7 +196,7 @@ class EMHCrypt01 extends ACrypt { } - VerifyMeasurement(measurementValue: IEMHMeasurementValue): IEMHCrypt01Result + async VerifyMeasurement(measurementValue: IEMHMeasurementValue): Promise { function setResult(verificationResult: VerificationResult) @@ -250,10 +240,7 @@ class EMHCrypt01 extends ACrypt { }; // Only the first 24 bytes/192 bits are used! - cryptoResult.sha256value = this.crypt.createHash('sha256'). - update(cryptoBuffer). - digest('hex'). - substring(0, 48); + cryptoResult.sha256value = (await this.sha256(cryptoBuffer)).substring(0, 48); const meter = this.GetMeter(measurementValue.measurement.energyMeterId); @@ -319,7 +306,7 @@ class EMHCrypt01 extends ACrypt { } - + private DecodeStatus(statusValue: string) : Array { @@ -362,14 +349,15 @@ class EMHCrypt01 extends ACrypt { } - ViewMeasurement(measurementValue: IEMHMeasurementValue, - introDiv: HTMLDivElement, - infoDiv: HTMLDivElement, - bufferValue: HTMLDivElement, - hashedBufferValue: HTMLDivElement, - publicKeyValue: HTMLDivElement, - signatureExpectedValue: HTMLDivElement, - signatureCheckValue: HTMLDivElement) + + async ViewMeasurement(measurementValue: IEMHMeasurementValue, + introDiv: HTMLDivElement, + infoDiv: HTMLDivElement, + bufferValue: HTMLDivElement, + hashedBufferValue: HTMLDivElement, + publicKeyValue: HTMLDivElement, + signatureExpectedValue: HTMLDivElement, + signatureCheckValue: HTMLDivElement) { const result = measurementValue.result as IEMHCrypt01Result; @@ -391,6 +379,7 @@ class EMHCrypt01 extends ACrypt { this.CreateLine("Autorisierung", measurementValue.measurement.chargingSession.authorizationStart["@id"] + " hex", this.pad(result.authorizationStart, 128) || "", infoDiv, bufferValue); this.CreateLine("Autorisierungszeitpunkt", parseUTC(measurementValue.measurement.chargingSession.authorizationStart.timestamp), this.pad(result.authorizationStartTimestamp, 151) || "", infoDiv, bufferValue); + // Buffer bufferValue.parentElement!.children[0].innerHTML = "Puffer (320 Bytes, hex)"; @@ -427,13 +416,13 @@ class EMHCrypt01 extends ACrypt { { let signatureDiv = publicKeyValue.parentElement!.children[3].appendChild(document.createElement('div')); - signatureDiv.innerHTML = this.CheckMeterPublicKeySignature(measurementValue.measurement.chargingSession.chargingStation, - measurementValue.measurement.chargingSession.EVSE, - //@ts-ignore - measurementValue.measurement.chargingSession.EVSE.meters[0], - //@ts-ignore - measurementValue.measurement.chargingSession.EVSE.meters[0].publicKeys[0], - signature); + signatureDiv.innerHTML = await this.CheckMeterPublicKeySignature(measurementValue.measurement.chargingSession.chargingStation, + measurementValue.measurement.chargingSession.EVSE, + //@ts-ignore + measurementValue.measurement.chargingSession.EVSE.meters[0], + //@ts-ignore + measurementValue.measurement.chargingSession.EVSE.meters[0].publicKeys[0], + signature); } catch (exception) diff --git a/src/js/GDFCrypt01.ts b/src/js/GDFCrypt01.ts index 75a8db4..2ecd028 100644 --- a/src/js/GDFCrypt01.ts +++ b/src/js/GDFCrypt01.ts @@ -66,17 +66,11 @@ class GDFCrypt01 extends ACrypt { // publicKeyHEX = publicKey.encode('hex').toLowerCase(); } - SignMeasurement(measurementValue: IGDFMeasurementValue, - privateKey: any, - publicKey: any): IGDFCrypt01Result + async SignMeasurement(measurementValue: IGDFMeasurementValue, + privateKey: any, + publicKey: any): Promise { - // var keypair = this.curve.genKeyPair(); - // privateKey = keypair.getPrivate(); - // publicKey = keypair.getPublic(); - // var privateKeyHEX = privateKey.toString('hex').toLowerCase(); - // var publicKeyHEX = publicKey.encode('hex').toLowerCase(); - var buffer = new ArrayBuffer(320); var cryptoBuffer = new DataView(buffer); @@ -92,10 +86,7 @@ class GDFCrypt01 extends ACrypt { authorizationStartTimestamp: SetTimestamp(cryptoBuffer, measurementValue.measurement.chargingSession.authorizationStart.timestamp, 169) }; - cryptoResult.sha256value = this.crypt.createHash ('sha256'). - update (cryptoBuffer). - digest ('hex'). - toLowerCase(); + cryptoResult.sha256value = await this.sha256(cryptoBuffer); cryptoResult.publicKey = publicKey.encode('hex'). toLowerCase(); @@ -140,7 +131,7 @@ class GDFCrypt01 extends ACrypt { } - VerifyChargingSession(chargingSession: IChargingSession): ISessionCryptoResult + async VerifyChargingSession(chargingSession: IChargingSession): Promise { var sessionResult = SessionVerificationResult.UnknownSessionFormat; @@ -160,7 +151,7 @@ class GDFCrypt01 extends ACrypt { for (var measurementValue of measurement.values) { measurementValue.measurement = measurement; - this.VerifyMeasurement(measurementValue as IGDFMeasurementValue); + await this.VerifyMeasurement(measurementValue as IGDFMeasurementValue); } @@ -191,7 +182,7 @@ class GDFCrypt01 extends ACrypt { } - VerifyMeasurement(measurementValue: IGDFMeasurementValue): IGDFCrypt01Result + async VerifyMeasurement(measurementValue: IGDFMeasurementValue): Promise { function setResult(vr: VerificationResult) @@ -230,9 +221,7 @@ class GDFCrypt01 extends ACrypt { s: signatureExpected.s }; - cryptoResult.sha256value = this.crypt.createHash('sha256'). - update(cryptoBuffer). - digest('hex'); + cryptoResult.sha256value = await this.sha256(cryptoBuffer); const meter = this.GetMeter(measurementValue.measurement.energyMeterId); @@ -298,14 +287,14 @@ class GDFCrypt01 extends ACrypt { } - ViewMeasurement(measurementValue: IMeasurementValue, - introDiv: HTMLDivElement, - infoDiv: HTMLDivElement, - bufferValue: HTMLDivElement, - hashedBufferValue: HTMLDivElement, - publicKeyValue: HTMLDivElement, - signatureExpectedValue: HTMLDivElement, - signatureCheckValue: HTMLDivElement) + async ViewMeasurement(measurementValue: IMeasurementValue, + introDiv: HTMLDivElement, + infoDiv: HTMLDivElement, + bufferValue: HTMLDivElement, + hashedBufferValue: HTMLDivElement, + publicKeyValue: HTMLDivElement, + signatureExpectedValue: HTMLDivElement, + signatureCheckValue: HTMLDivElement) { const result = measurementValue.result as IGDFCrypt01Result; diff --git a/src/js/chargy.ts b/src/js/chargy.ts index 973e6a1..88bc6dd 100644 --- a/src/js/chargy.ts +++ b/src/js/chargy.ts @@ -527,7 +527,7 @@ class ChargyApplication { (navigator as any).clipboard.readText().then((clipText: string) => { try { - this.detectContentFormat(JSON.parse(clipText)); + this.detectContentFormat(clipText); } catch (exception) { this.doGlobalError("Fehlerhafter Transparenzdatensatz!", exception); @@ -809,11 +809,11 @@ class ChargyApplication { //#region CheckMeterPublicKeySignature(...) - private CheckMeterPublicKeySignature(chargingStation: any, - evse: any, - meter: any, - publicKey: any, - signature: any): string + private async CheckMeterPublicKeySignature(chargingStation: any, + evse: any, + meter: any, + publicKey: any, + signature: any): Promise { // For now: Do not enforce this feature! @@ -946,10 +946,10 @@ class ChargyApplication { //#region detectContentFormat - private checkSessionCrypto(chargingSession: IChargingSession) + private async checkSessionCrypto(chargingSession: IChargingSession) { - var result = this.verifySessionCryptoDetails(chargingSession); + var result = await this.verifySessionCryptoDetails(chargingSession); //#region Add marker to map @@ -1069,7 +1069,7 @@ class ChargyApplication { //#region processChargeTransparencyRecord(CTR) - private processChargeTransparencyRecord(CTR: IChargeTransparencyRecord) + private async processChargeTransparencyRecord(CTR: IChargeTransparencyRecord) { this.chargingStationOperators = []; @@ -1686,7 +1686,7 @@ class ChargyApplication { let verificationStatusDiv = chargingSessionDiv.appendChild(document.createElement('div')); verificationStatusDiv.className = "verificationStatus"; - verificationStatusDiv.innerHTML = this.checkSessionCrypto(chargingSession); + verificationStatusDiv.innerHTML = await this.checkSessionCrypto(chargingSession); //#endregion @@ -2742,10 +2742,10 @@ class ChargyApplication { //#region checkMeasurementCrypto(measurementValue) - private checkMeasurementCrypto(measurementValue: IMeasurementValue) + private async checkMeasurementCrypto(measurementValue: IMeasurementValue) { - var result = this.verifyMeasurementCryptoDetails(measurementValue); + var result = await this.verifyMeasurementCryptoDetails(measurementValue); switch (result.status) { @@ -2772,7 +2772,7 @@ class ChargyApplication { default: return ' Ungültige Signatur'; - } + } } @@ -2780,7 +2780,7 @@ class ChargyApplication { //#region showChargingSessionDetails - private showChargingSessionDetails(chargingSession: IChargingSession) + private async showChargingSessionDetails(chargingSession: IChargingSession) { try @@ -2994,7 +2994,7 @@ class ChargyApplication { // Show signature status let verificationStatusDiv = CreateDiv(MeasurementValueDiv, "verificationStatus", - this.checkMeasurementCrypto(measurementValue)); + await this.checkMeasurementCrypto(measurementValue)); previousValue = currentValue; @@ -3020,7 +3020,7 @@ class ChargyApplication { //#region verifySessionCryptoDetails - private verifySessionCryptoDetails(chargingSession: IChargingSession) : ISessionCryptoResult + private async verifySessionCryptoDetails(chargingSession: IChargingSession) : Promise { var result: ISessionCryptoResult = { @@ -3037,12 +3037,12 @@ class ChargyApplication { { case "https://open.charging.cloud/contexts/SessionSignatureFormats/GDFCrypt01+json": - chargingSession.method = new GDFCrypt01(this.GetMeter, this.CheckMeterPublicKeySignature); - return chargingSession.method.VerifyChargingSession(chargingSession); + chargingSession.method = new GDFCrypt01(this.GetMeter, await this.CheckMeterPublicKeySignature); + return await chargingSession.method.VerifyChargingSession(chargingSession); case "https://open.charging.cloud/contexts/SessionSignatureFormats/EMHCrypt01+json": - chargingSession.method = new EMHCrypt01(this.GetMeter, this.CheckMeterPublicKeySignature); - return chargingSession.method.VerifyChargingSession(chargingSession); + chargingSession.method = new EMHCrypt01(this.GetMeter, await this.CheckMeterPublicKeySignature); + return await chargingSession.method.VerifyChargingSession(chargingSession); default: return result; @@ -3055,7 +3055,7 @@ class ChargyApplication { //#region verifyMeasurementCryptoDetails - private verifyMeasurementCryptoDetails(measurementValue: IMeasurementValue) : ICryptoResult + private async verifyMeasurementCryptoDetails(measurementValue: IMeasurementValue) : Promise { var result: ICryptoResult = { diff --git a/src/js/chargyInterfaces.ts b/src/js/chargyInterfaces.ts index 2ed988e..21aef92 100644 --- a/src/js/chargyInterfaces.ts +++ b/src/js/chargyInterfaces.ts @@ -38,7 +38,7 @@ interface CheckMeterPublicKeySignatureFunc { evse: any|null, meter: any|null, publicKey: any|null, - signature: any|null): string; + signature: any|null): Promise; } From f878a7ba12f8112b6e682f9ed2b9aa3d7e9ad1c6 Mon Sep 17 00:00:00 2001 From: Achim Friedland Date: Sun, 25 Aug 2019 19:57:08 +0200 Subject: [PATCH 006/110] Bugfixes --- src/css/chargy.scss | 10 +++++----- src/js/chargy.ts | 6 ++++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/css/chargy.scss b/src/css/chargy.scss index 56d9e78..57ec7a0 100644 --- a/src/css/chargy.scss +++ b/src/css/chargy.scss @@ -1118,18 +1118,18 @@ body { .statusInfos { font-style: italic; font-size: 90%; - } + } } } .row:hover { - background-color: orange; + background-color: orange; } .overEntry { - background-color: orange; + background-color: orange; } } @@ -1173,11 +1173,11 @@ body { } .entry:hover { - background-color: orange; + background-color: orange; } .overEntry { - background-color: orange; + background-color: orange; } } diff --git a/src/js/chargy.ts b/src/js/chargy.ts index 88bc6dd..bb053cf 100644 --- a/src/js/chargy.ts +++ b/src/js/chargy.ts @@ -2390,6 +2390,7 @@ class ChargyApplication { //#region tryToParseOCMF(OCMF, PublicKey?) + //#region tryToParseOCMFv0_1(OCMFData, PublicKey?) private tryToParseOCMFv0_1(OCMFData: IOCMFData_v0_1, @@ -2534,6 +2535,7 @@ class ChargyApplication { //#endregion + private tryToParseOCMF(OCMF: string, PublicKey?: string) : boolean { @@ -2550,7 +2552,6 @@ class ChargyApplication { let OCMFData = JSON.parse(elements[1]); let OCMFSignature = JSON.parse(elements[2]); - // http://hers.abl.de/SAFE/Datenformat_OCMF/Datenformat_OCMF_v1.0.pdf // Ein Darstellungsformat, JSON-basiert (nachvollziehbar) // Ein Übertragungsformat, JSON-basiert (vereinheitlicht) @@ -2627,7 +2628,7 @@ class ChargyApplication { Content = Content.trim(); // Catches EFBBBF (UTF-8 BOM) because the buffer-to-string - // conversion translates it to FEFF (UTF-16 BOM) + // conversion translates it to FEFF (UTF-16 BOM) if (Content.charCodeAt(0) === 0xFEFF) Content = Content.substr(1); @@ -2740,6 +2741,7 @@ class ChargyApplication { //#endregion + //#region checkMeasurementCrypto(measurementValue) private async checkMeasurementCrypto(measurementValue: IMeasurementValue) From 14e598c6119f249b6d6f23597d9f127679e08126 Mon Sep 17 00:00:00 2001 From: Achim Friedland Date: Mon, 26 Aug 2019 05:49:19 +0200 Subject: [PATCH 007/110] More on OCMF v1.0 verification --- src/index.html | 2 + src/js/EMHCrypt01.ts | 2 +- src/js/OCMFTypes.ts | 40 ++- src/js/OCMFv1_0.ts | 517 +++++++++++++++++++++++++++++++++++++ src/js/chargy.ts | 596 +++++++++++++++++++++++++++++++++---------- src/js/chargyLib.ts | 16 +- 6 files changed, 1032 insertions(+), 141 deletions(-) create mode 100644 src/js/OCMFv1_0.ts diff --git a/src/index.html b/src/index.html index ab179e2..e35912e 100644 --- a/src/index.html +++ b/src/index.html @@ -41,6 +41,8 @@ + + diff --git a/src/js/EMHCrypt01.ts b/src/js/EMHCrypt01.ts index 1f1012d..b19a40b 100644 --- a/src/js/EMHCrypt01.ts +++ b/src/js/EMHCrypt01.ts @@ -73,7 +73,7 @@ class EMHCrypt01 extends ACrypt { // publicKey = keypair.getPublic(); // privateKeyHEX = privateKey.toString('hex').toLowerCase(); // publicKeyHEX = publicKey.encode('hex').toLowerCase(); - } + } async SignMeasurement(measurementValue: IEMHMeasurementValue, privateKey: any, diff --git a/src/js/OCMFTypes.ts b/src/js/OCMFTypes.ts index afb79b7..fae60d2 100644 --- a/src/js/OCMFTypes.ts +++ b/src/js/OCMFTypes.ts @@ -22,6 +22,31 @@ const enum OCMFTransactionTypes transaction } +const enum TimeStatusTypes { + unknown, + informative, + syncronized, + relative +} + +interface IOCMFReading { + TM: string, // Timestamp + TX?: string, // Transaction + RV?: string, // typeof RV == 'number', but MUST NOT be rounded! + RI?: string, // Reading-Identification == OBIS-Code + RU?: string, // Reading-Unit: kWh, ... + RT?: string, // Reading-Current-Type + EF?: string, // Error-Flags + ST: string // Status +} + +interface IOCMFSignature { + SA?: string, + SE?: string, + SM?: string, + SD: string +} + interface IOCMFData { FV: string, @@ -33,6 +58,20 @@ interface IOCMFData { MS: string, MF: string, + IS: boolean, + IL?: string, + IF?: string[], + IT: string, + ID: string, + + CT?: string, + CI?: string, + C2I?: string, + + RD: Array, + + signature: IOCMFSignature + } interface IOCMFData_v0_1 extends IOCMFData { @@ -45,4 +84,3 @@ interface IOCMFData_v1_0 extends IOCMFData { GS: string, GV: string, } - diff --git a/src/js/OCMFv1_0.ts b/src/js/OCMFv1_0.ts new file mode 100644 index 0000000..c7abad3 --- /dev/null +++ b/src/js/OCMFv1_0.ts @@ -0,0 +1,517 @@ +/* + * Copyright (c) 2018-2019 GraphDefined GmbH + * This file is part of Chargy Desktop App + * + * Licensed under the Affero GPL license, Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.gnu.org/licenses/agpl.html + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/// +/// +/// +/// + + +interface IOCMFv1_0MeasurementValue extends IMeasurementValue +{ + infoStatus: string, + secondsIndex: number, + paginationId: string, + logBookIndex: string +} + +interface IOCMFv1_0Result extends ICryptoResult +{ + sha256value?: any, + meterId?: string, + meter?: IMeter, + timestamp?: string, + infoStatus?: string, + secondsIndex?: string, + paginationId?: string, + obis?: string, + unitEncoded?: string, + scale?: string, + value?: string, + logBookIndex?: string, + authorizationStart?: string, + authorizationStop?: string, + authorizationStartTimestamp?: string, + publicKey?: string, + publicKeyFormat?: string, + publicKeySignatures?: any, + signature?: IECCSignature +} + + +class OCMFv1_0 extends ACrypt { + + readonly curve = new this.elliptic.ec('p256'); + + constructor(GetMeter: GetMeterFunc, + CheckMeterPublicKeySignature: CheckMeterPublicKeySignatureFunc) { + + super("ECC secp192r1", + GetMeter, + CheckMeterPublicKeySignature); + + } + + + GenerateKeyPair()//options?: elliptic.ec.GenKeyPairOptions) + { + return this.curve.genKeyPair(); + // privateKey = keypair.getPrivate(); + // publicKey = keypair.getPublic(); + // privateKeyHEX = privateKey.toString('hex').toLowerCase(); + // publicKeyHEX = publicKey.encode('hex').toLowerCase(); + } + + async SignMeasurement(measurementValue: IOCMFv1_0MeasurementValue, + privateKey: any, + publicKey: any): Promise + { + + var buffer = new ArrayBuffer(320); + var cryptoBuffer = new DataView(buffer); + + var cryptoResult:IOCMFv1_0Result = { + status: VerificationResult.InvalidSignature, + meterId: SetHex (cryptoBuffer, measurementValue.measurement.energyMeterId, 0), + timestamp: SetTimestamp32(cryptoBuffer, measurementValue.timestamp, 10), + infoStatus: SetHex (cryptoBuffer, measurementValue.infoStatus, 14, false), + secondsIndex: SetUInt32 (cryptoBuffer, measurementValue.secondsIndex, 15, true), + paginationId: SetHex (cryptoBuffer, measurementValue.paginationId, 19, true), + obis: SetHex (cryptoBuffer, measurementValue.measurement.obis, 23, false), + unitEncoded: SetInt8 (cryptoBuffer, measurementValue.measurement.unitEncoded, 29), + scale: SetInt8 (cryptoBuffer, measurementValue.measurement.scale, 30), + value: SetUInt64 (cryptoBuffer, measurementValue.value, 31, true), + logBookIndex: SetHex (cryptoBuffer, measurementValue.logBookIndex, 39, false), + authorizationStart: SetText (cryptoBuffer, measurementValue.measurement.chargingSession.authorizationStart["@id"], 41), + authorizationStartTimestamp: SetTimestamp32(cryptoBuffer, measurementValue.measurement.chargingSession.authorizationStart.timestamp, 169) + }; + + // Only the first 24 bytes/192 bits are used! + cryptoResult.sha256value = (await this.sha256(cryptoBuffer)).substring(0, 48); + + cryptoResult.publicKey = publicKey.encode('hex'). + toLowerCase(); + + const signature = this.curve.keyFromPrivate(privateKey.toString('hex')). + sign(cryptoResult.sha256value); + + switch (measurementValue.measurement.signatureInfos.format) + { + + case SignatureFormats.DER: + + cryptoResult.signature = { + algorithm: measurementValue.measurement.signatureInfos.algorithm, + format: measurementValue.measurement.signatureInfos.format, + value: signature.toDER('hex') + }; + + return cryptoResult; + + + case SignatureFormats.rs: + + cryptoResult.signature = { + algorithm: measurementValue.measurement.signatureInfos.algorithm, + format: measurementValue.measurement.signatureInfos.format, + r: signature.r, + s: signature.s + }; + + return cryptoResult; + + + //default: + + + } + + cryptoResult.status = VerificationResult.ValidSignature; + return cryptoResult; + + } + + + async VerifyChargingSession(chargingSession: IChargingSession): Promise + { + + var sessionResult = SessionVerificationResult.UnknownSessionFormat; + + if (chargingSession.measurements) + { + for (var measurement of chargingSession.measurements) + { + + measurement.chargingSession = chargingSession; + + // Must include at least two measurements (start & stop) + if (measurement.values && measurement.values.length > 1) + { + + // Validate... + for (var measurementValue of measurement.values) + { + measurementValue.measurement = measurement; + await this.VerifyMeasurement(measurementValue as IOCMFv1_0MeasurementValue); + } + + + // Find an overall result... + sessionResult = SessionVerificationResult.ValidSignature; + + for (var measurementValue of measurement.values) + { + if (sessionResult == SessionVerificationResult.ValidSignature && + measurementValue.result.status != VerificationResult.ValidSignature) + { + sessionResult = SessionVerificationResult.InvalidSignature; + } + } + + } + + else + sessionResult = SessionVerificationResult.AtLeastTwoMeasurementsExpected; + + } + } + + return { + status: sessionResult + } ; + + } + + + async VerifyMeasurement(measurementValue: IOCMFv1_0MeasurementValue): Promise + { + + function setResult(verificationResult: VerificationResult) + { + cryptoResult.status = verificationResult; + measurementValue.result = cryptoResult; + return cryptoResult; + } + + // { + // + // "FV": "1.0", + // "GI": "SEAL AG", + // "GS": "1850006a", + // "GV": "1.34", + // + // "PG": "T9289", + // + // "MV": "Carlo Gavazzi", + // "MM": "EM340-DIN.AV2.3.X.S1.PF", + // "MS": "******240084S", + // "MF": "B4", + // + // "IS": true, + // "IL": "TRUSTED", + // "IF": ["OCCP_AUTH"], + // "IT": "ISO14443", + // "ID": "56213C05", + // + // "RD": [{ + // "TM": "2019-06-26T08:57:44,337+0000 U", + // "TX": "B", + // "RV": 268.978, + // "RI": "1-b:1.8.0", + // "RU": "kWh", + // "RT": "AC", + // "EF": "", + // "ST": "G" + // }] + // + // } + + var reading = { + + "FV": "1.0", + "GI": "SEAL AG", + "GS": "1850006a", + "GV": "1.34", + + "PG": "T9289", + + "MV": "Carlo Gavazzi", + "MM": "EM340-DIN.AV2.3.X.S1.PF", + "MS": "******240084S", + "MF": "B4", + + "IS": true, + "IL": "TRUSTED", + "IF": ["OCCP_AUTH"], + "IT": "ISO14443", + "ID": "56213C05", + + "RD": [{ + "TM": "2019-06-26T08:57:44,337+0000 U", + "TX": "B", + "RV": 268.978, + "RI": "1-b:1.8.0", + "RU": "kWh", + "RT": "AC", + "EF": "", + "ST": "G" + }] + + }; + + + var serialized = JSON.stringify(reading); + + var cryptoResult:IOCMFv1_0Result = { + status: VerificationResult.ValidSignature, + }; + + return setResult(VerificationResult.ValidSignature); + + // var buffer = new ArrayBuffer(320); + // var cryptoBuffer = new DataView(buffer); + + // var cryptoResult:IOCMFv1_0Result = { + // status: VerificationResult.InvalidSignature, + // meterId: SetHex (cryptoBuffer, measurementValue.measurement.energyMeterId, 0), + // timestamp: SetTimestamp32(cryptoBuffer, measurementValue.timestamp, 10), + // infoStatus: SetHex (cryptoBuffer, measurementValue.infoStatus, 14, false), + // secondsIndex: SetUInt32 (cryptoBuffer, measurementValue.secondsIndex, 15, true), + // paginationId: SetHex (cryptoBuffer, measurementValue.paginationId, 19, true), + // obis: SetHex (cryptoBuffer, measurementValue.measurement.obis, 23, false), + // unitEncoded: SetInt8 (cryptoBuffer, measurementValue.measurement.unitEncoded, 29), + // scale: SetInt8 (cryptoBuffer, measurementValue.measurement.scale, 30), + // value: SetUInt64 (cryptoBuffer, measurementValue.value, 31, true), + // logBookIndex: SetHex (cryptoBuffer, measurementValue.logBookIndex, 39, false), + // authorizationStart: SetText (cryptoBuffer, measurementValue.measurement.chargingSession.authorizationStart["@id"], 41), + // authorizationStartTimestamp: SetTimestamp32(cryptoBuffer, measurementValue.measurement.chargingSession.authorizationStart.timestamp, 169) + // }; + + // var signatureExpected = measurementValue.signatures[0] as IECCSignature; + // if (signatureExpected != null) + // { + + // try + // { + + // cryptoResult.signature = { + // algorithm: measurementValue.measurement.signatureInfos.algorithm, + // format: measurementValue.measurement.signatureInfos.format, + // r: signatureExpected.r, + // s: signatureExpected.s + // }; + + // // Only the first 24 bytes/192 bits are used! + // cryptoResult.sha256value = (await this.sha256(cryptoBuffer)).substring(0, 48); + + + // const meter = this.GetMeter(measurementValue.measurement.energyMeterId); + // if (meter != null) + // { + + // cryptoResult.meter = meter; + + // var iPublicKey = meter.publicKeys[0] as IPublicKey; + // if (iPublicKey != null) + // { + + // try + // { + + // cryptoResult.publicKey = iPublicKey.value.toLowerCase(); + // cryptoResult.publicKeyFormat = iPublicKey.format; + // cryptoResult.publicKeySignatures = iPublicKey.signatures; + + // try + // { + + // if (this.curve.keyFromPublic(cryptoResult.publicKey, 'hex'). + // verify (cryptoResult.sha256value, + // cryptoResult.signature)) + // { + // return setResult(VerificationResult.ValidSignature); + // } + + // return setResult(VerificationResult.InvalidSignature); + + // } + // catch (exception) + // { + // return setResult(VerificationResult.InvalidSignature); + // } + + // } + // catch (exception) + // { + // return setResult(VerificationResult.InvalidPublicKey); + // } + + // } + + // else + // return setResult(VerificationResult.PublicKeyNotFound); + + // } + + // else + // return setResult(VerificationResult.EnergyMeterNotFound); + + // } + // catch (exception) + // { + // return setResult(VerificationResult.InvalidSignature); + // } + + // } + + // return {} as IOCMFv1_0Result; + + } + + + async ViewMeasurement(measurementValue: IOCMFv1_0MeasurementValue, + introDiv: HTMLDivElement, + infoDiv: HTMLDivElement, + bufferValue: HTMLDivElement, + hashedBufferValue: HTMLDivElement, + publicKeyValue: HTMLDivElement, + signatureExpectedValue: HTMLDivElement, + signatureCheckValue: HTMLDivElement) + { + + const result = measurementValue.result as IOCMFv1_0Result; + + const cryptoSpan = introDiv.querySelector('#cryptoAlgorithm') as HTMLSpanElement; + cryptoSpan.innerHTML = "EMHCrypt01 (" + this.description + ")"; + + this.CreateLine("Zählernummer", measurementValue.measurement.energyMeterId, result.meterId || "", infoDiv, bufferValue); + this.CreateLine("Zeitstempel", parseUTC(measurementValue.timestamp), result.timestamp || "", infoDiv, bufferValue); + this.CreateLine("Status", hex2bin(measurementValue.infoStatus) + " (" + measurementValue.infoStatus + " hex)", result.infoStatus || "", infoDiv, bufferValue); + this.CreateLine("Sekundenindex", measurementValue.secondsIndex, result.secondsIndex || "", infoDiv, bufferValue); + this.CreateLine("Paginierungszähler", parseInt(measurementValue.paginationId, 16), result.paginationId || "", infoDiv, bufferValue); + this.CreateLine("OBIS-Kennzahl", parseOBIS(measurementValue.measurement.obis), result.obis || "", infoDiv, bufferValue); + this.CreateLine("Einheit (codiert)", measurementValue.measurement.unitEncoded, result.unitEncoded || "", infoDiv, bufferValue); + this.CreateLine("Skalierung", measurementValue.measurement.scale, result.scale || "", infoDiv, bufferValue); + this.CreateLine("Messwert", measurementValue.value + " Wh", result.value || "", infoDiv, bufferValue); + this.CreateLine("Logbuchindex", measurementValue.logBookIndex + " hex", result.logBookIndex || "", infoDiv, bufferValue); + this.CreateLine("Autorisierung", measurementValue.measurement.chargingSession.authorizationStart["@id"] + " hex", this.pad(result.authorizationStart, 128) || "", infoDiv, bufferValue); + this.CreateLine("Autorisierungszeitpunkt", parseUTC(measurementValue.measurement.chargingSession.authorizationStart.timestamp), this.pad(result.authorizationStartTimestamp, 151) || "", infoDiv, bufferValue); + + + // Buffer + bufferValue.parentElement!.children[0].innerHTML = "Puffer (320 Bytes, hex)"; + + // Hashed Buffer + hashedBufferValue.parentElement!.children[0].innerHTML = "Hashed Puffer (SHA256, 24 bytes, hex)"; + hashedBufferValue.innerHTML = result.sha256value.match(/.{1,8}/g).join(" ");; + + + // Public Key + publicKeyValue.parentElement!.children[0].innerHTML = "Public Key (" + + (result.publicKeyFormat + ? result.publicKeyFormat + ", " + : "") + + "hex)"; + + var pubKey = WhenNullOrEmpty(result.publicKey, ""); + + if (!IsNullOrEmpty(result.publicKey)) + publicKeyValue.innerHTML = pubKey.startsWith("04") // Add some space after '04' to avoid confused customers + ? "04 " + + pubKey.substring(2).match(/.{1,8}/g)!.join(" ") + : pubKey.match(/.{1,8}/g)!.join(" "); + + + if (!IsNullOrEmpty(result.publicKeySignatures)) { + +// publicKeyValue.parentElement!.children[2].innerHTML = "Bestätigt durch..."; + publicKeyValue.parentElement!.children[3].innerHTML = ""; + + for (let signature of result.publicKeySignatures) + { + + try + { + + let signatureDiv = publicKeyValue.parentElement!.children[3].appendChild(document.createElement('div')); + signatureDiv.innerHTML = await this.CheckMeterPublicKeySignature(measurementValue.measurement.chargingSession.chargingStation, + measurementValue.measurement.chargingSession.EVSE, + //@ts-ignore + measurementValue.measurement.chargingSession.EVSE.meters[0], + //@ts-ignore + measurementValue.measurement.chargingSession.EVSE.meters[0].publicKeys[0], + signature); + + } + catch (exception) + { } + + } + + } + + + // Signature + signatureExpectedValue.parentElement!.children[0].innerHTML = "Erwartete Signatur (" + (result.signature!.format || "") + ", hex)"; + + if (result.signature!.r && result.signature!.s) + signatureExpectedValue.innerHTML = "r: " + result.signature!.r!.toLowerCase().match(/.{1,8}/g)!.join(" ") + "
" + + "s: " + result.signature!.s!.toLowerCase().match(/.{1,8}/g)!.join(" "); + + else if (result.signature!.value) + signatureExpectedValue.innerHTML = result.signature!.value!.toLowerCase().match(/.{1,8}/g)!.join(" "); + + + // Result + switch (result.status) + { + + case VerificationResult.UnknownCTRFormat: + signatureCheckValue.innerHTML = '
Unbekanntes Transparenzdatenformat
'; + break; + + case VerificationResult.EnergyMeterNotFound: + signatureCheckValue.innerHTML = '
Ungültiger Energiezähler
'; + break; + + case VerificationResult.PublicKeyNotFound: + signatureCheckValue.innerHTML = '
Ungültiger Public Key
'; + break; + + case VerificationResult.InvalidPublicKey: + signatureCheckValue.innerHTML = '
Ungültiger Public Key
'; + break; + + case VerificationResult.InvalidSignature: + signatureCheckValue.innerHTML = '
Ungültige Signatur
'; + break; + + case VerificationResult.ValidSignature: + signatureCheckValue.innerHTML = '
Gültige Signatur
'; + break; + + + default: + signatureCheckValue.innerHTML = '
Ungültige Signatur
'; + break; + + } + + + } + +} \ No newline at end of file diff --git a/src/js/chargy.ts b/src/js/chargy.ts index bb053cf..828617b 100644 --- a/src/js/chargy.ts +++ b/src/js/chargy.ts @@ -20,8 +20,7 @@ /// /// /// - -/// +/// // import { debug } from "util"; // import * as crypto from "crypto"; @@ -1603,13 +1602,20 @@ class ChargyApplication { ? chargingSession.EVSEId : chargingSession.EVSE!["@id"]); - chargingSession.chargingStation = chargingSession.EVSE!.chargingStation; - chargingSession.chargingStationId = chargingSession.EVSE!.chargingStationId; + if (chargingSession.EVSE) + { + + chargingSession.chargingStation = chargingSession.EVSE.chargingStation; + chargingSession.chargingStationId = chargingSession.EVSE.chargingStationId; - chargingSession.chargingPool = chargingSession.EVSE!.chargingStation.chargingPool; - chargingSession.chargingPoolId = chargingSession.EVSE!.chargingStation.chargingPoolId; + if (chargingSession.EVSE.chargingStation) + { + chargingSession.chargingPool = chargingSession.EVSE.chargingStation.chargingPool; + chargingSession.chargingPoolId = chargingSession.EVSE.chargingStation.chargingPoolId; + address = chargingSession.EVSE.chargingStation.address; + } - address = chargingSession.EVSE!.chargingStation.address; + } } @@ -1715,7 +1721,7 @@ class ChargyApplication { //#region tryToParseAnonymousFormat(...) // e.g. the current chargeIT mobility does not provide any format identifiers - private tryToParseAnonymousFormat(SomeJSON: { signedMeterValues: any[]; placeInfo: any; }) : boolean + private async tryToParseAnonymousFormat(SomeJSON: { signedMeterValues: any[]; placeInfo: any; }) : Promise { if (!Array.isArray(SomeJSON)) @@ -2269,7 +2275,7 @@ class ChargyApplication { } - this.processChargeTransparencyRecord(_CTR); + await this.processChargeTransparencyRecord(_CTR); return true; } @@ -2288,7 +2294,7 @@ class ChargyApplication { //#region tryToParseTransparenzSoftwareXML(XMLDocument) - private tryToParseTransparenzSoftwareXML(XMLDocument: Document) : boolean + private async tryToParseTransparenzSoftwareXML(XMLDocument: Document) : Promise { // The SAFE transparency software v1.0 does not understand its own @@ -2297,23 +2303,27 @@ class ChargyApplication { try { + let commonFormat = ""; + let commonPublicKey = ""; + let signedValues:string[] = []; + let values = XMLDocument.querySelectorAll("values"); if (values.length == 1) { let valueList = values[0].querySelectorAll("value"); if (valueList.length >= 1) { - for (var i in valueList) + for (let i=0; i... + var signedData = valueList[i].querySelector("signedData"); if (signedData != null) { @@ -2325,17 +2335,50 @@ class ChargyApplication { switch (signedDataEncoding) { + case "": + case "plain": + break; + //case "base32": case "base64": - signedDataValue = Buffer.from(signedDataValue, 'base64').toString(); + signedDataValue = Buffer.from(signedDataValue, 'base64').toString().trim(); break; //case "hex": + default: + throw "Unkown signed data encoding within the given SAFE XML!"; + } + switch (signedDataFormat) + { + + case "ocmf": + if (commonFormat == "") + commonFormat = "ocmf"; + else if (commonFormat != "ocmf") + throw "Invalid mixture of different signed data formats within the given SAFE XML!"; + break; + + default: + throw "Unkown signed data formats within the given SAFE XML!"; + + } + + if (signedDataValue.isNullOrEmpty()) + throw "The signed data value within the given SAFE XML must not be empty!"; + + signedValues.push(signedDataValue); + } + else + throw "The signed data tag within the given SAFE XML must not be empty!"; + + //#endregion + + //#region ... // Note: The public key is optional! var publicKey = valueList[i].querySelector("publicKey"); @@ -2348,36 +2391,48 @@ class ChargyApplication { switch (publicKeyEncoding) { + case "": + case "plain": + break; + //case "base32": case "base64": - publicKeyValue = Buffer.from(publicKeyValue, 'base64').toString(); + publicKeyValue = Buffer.from(publicKeyValue, 'base64').toString().trim(); break; //case "hex": + default: + throw "Unkown public key encoding within the given SAFE XML!"; + } - } + if (publicKeyValue.isNullOrEmpty()) + throw "The public key within the given SAFE XML must not be empty!"; - //#endregion + else if (commonPublicKey == "") + commonPublicKey = publicKeyValue; - if (signedDataValue !== "") - { - switch (signedDataFormat) - { + else if (publicKeyValue != commonPublicKey) + throw "Invalid mixture of different public keys within the given SAFE XML!"; - case "ocmf": - this.tryToParseOCMF(signedDataValue, publicKeyValue); - break; - - } } + //#endregion + } } } + switch (commonFormat) + { + + case "ocmf": + return await this.tryToParseOCMF(signedValues, commonPublicKey); + + } + } catch (exception) { } @@ -2393,8 +2448,8 @@ class ChargyApplication { //#region tryToParseOCMFv0_1(OCMFData, PublicKey?) - private tryToParseOCMFv0_1(OCMFData: IOCMFData_v0_1, - PublicKey?: string) : boolean + private async tryToParseOCMFv0_1(OCMFData: IOCMFData_v0_1, + PublicKey?: string) : Promise { // { @@ -2463,68 +2518,262 @@ class ChargyApplication { //#region tryToParseOCMFv1_0(OCMFData, PublicKey?) - private tryToParseOCMFv1_0(OCMFData: IOCMFData_v1_0, - PublicKey?: string) : boolean + private async tryToParseOCMFv1_0(OCMFValues: IOCMFData_v1_0[], + PublicKey?: string) : Promise { - // { - // "FV": "1.0", - // "GI": "SEAL AG", - // "GS": "1850006a", - // "GV": "1.34", + var CTR:any = { + + "@id": "1554181214441:-1965658344385548683:2", + "@context": "https://open.charging.cloud/contexts/CTR+json", + "begin": "2019-04-02T05:00:19Z", + "end": "2019-04-02T05:13:52Z", + "description": { + "de": "Alle OCMF-Ladevorgänge" + }, + "contract": { + "@id": "8057F5AA592904", + "type": "RFID_TAG_ID", + "username": "", + "email": "" + }, + + "EVSEs": [{ + "@id": "DE*BDO*E8025334492*2", + "meters": [{ + "@id": "0901454D48000083E076", + "vendor": "EMH", + "vendorURL": "http://www.emh-metering.de", + "model": "eHZ IW8E EMH", + "hardwareVersion": "1.0", + "firmwareVersion": "123", + "signatureFormat": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/OCMFv1.0+json", + "publicKeys": [{ + "algorithm": "secp192r1", + "format": "DER", + "value": "049EA8697F5C3126E86A37295566D560DE8EA690325791C9CBA79D30612B8EA8E00908FBAD5374812D55DCC3D809C3A36C", + }] + }] + + }], + + "chargingSessions": [{ + + "@id": "1554181214441:-1965658344385548683:2", + "@context": "https://open.charging.cloud/contexts/SessionSignatureFormats/OCMFv1.0+json", + "begin": null, + "end": null, + "EVSEId": "DE*BDO*E8025334492*2", + + "authorizationStart": { + "@id": "8057F5AA592904", + "type": "RFID_TAG_ID" + }, + + "signatureInfos": { + "hash": "SHA512", + "hashTruncation": "24", + "algorithm": "ECC", + "curve": "secp192r1", + "format": "rs" + }, + + "measurements": [//{ + + // "energyMeterId": "0901454D48000083E076", + // "@context": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/OCMFv1.0+json", + // "name": "ENERGY_TOTAL", + // "obis": "0100011100FF", + // "unit": "WATT_HOUR", + // "unitEncoded": 30, + // "valueType": "Integer64", + // "scale": -1, + + // "signatureInfos": { + // "hash": "SHA512", + // "hashTruncation": "24", + // "algorithm": "ECC", + // "curve": "secp192r1", + // "format": "rs" + // }, + + // "values": [ + // { + // "timestamp": "2019-04-02T07:00:19+02:00", + // "value": "66260", + // "infoStatus": "08", + // "secondsIndex": 65058, + // "paginationId": "00000012", + // "logBookIndex": "0006", + // "signatures": [{ + // "r": "71F76A80F170F87675AAEB19606BBD298355FDA7B0851700", + // "s": "2FAD322FA073255BD8B971BD69BFF051BCA9330703172E3C" + // }] + // }, + // { + // "timestamp": "2019-04-02T07:13:52+02:00", + // "value": "67327", + // "infoStatus": "08", + // "secondsIndex": 65871, + // "paginationId": "00000013", + // "logBookIndex": "0006", + // "signatures": [{ + // "r": "6DF01D7603CB49BB76141F8E67B371351BF1F87C1F8D38AE", + // "s": "B3600A9432B8CE0A378126D4FB9D9581457651A5D208AD9E" + // }] + // } + ] + + }] + + // }] + }; + + + // [ // Not standard compliant use of an array! // - // "PG": "T9289", + // { // - // "MV": "Carlo Gavazzi", - // "MM": "EM340-DIN.AV2.3.X.S1.PF", - // "MS": "******240084S", - // "MF": "B4", + // "FV": "1.0", + // "GI": "SEAL AG", + // "GS": "1850006a", + // "GV": "1.34", // - // "IS": true, - // "IL": "TRUSTED", - // "IF": ["OCCP_AUTH"], - // "IT": "ISO14443", - // "ID": "56213C05", + // "PG": "T9289", // - // "RD": [{ - // "TM": "2019-06-26T08:57:44,337+0000 U", - // "TX": "B", - // "RV": 268.978, - // "RI": "1-b:1.8.0", - // "RU": "kWh", - // "RT": "AC", - // "EF": "", - // "ST": "G" - // }] - // } + // "MV": "Carlo Gavazzi", + // "MM": "EM340-DIN.AV2.3.X.S1.PF", + // "MS": "******240084S", + // "MF": "B4", + // + // "IS": true, + // "IL": "TRUSTED", + // "IF": ["OCCP_AUTH"], + // "IT": "ISO14443", + // "ID": "56213C05", + // + // "RD": [{ + // "TM": "2019-06-26T08:57:44,337+0000 U", + // "TX": "B", + // "RV": 268.978, + // "RI": "1-b:1.8.0", + // "RU": "kWh", + // "RT": "AC", + // "EF": "", + // "ST": "G" + // }], + // + // "__signature": { // Not standard compliant property key! + // "SD": "304402201455BF1082C9EB8B1272D7FA838EB44286B03AC96E8BAFC5E79E30C5B3E1B872022006286CA81AEE0FAFCB1D6A137FFB2C0DD014727E2AEC149F30CD5A7E87619139" + // } + // + // }, + // + // [...] + // + // ] try { - let GatewayInformation :string = OCMFData.GI != null ? OCMFData.GI.trim() : ""; // Some text about the manufacturer, model, variant, ... of e.g. the gateway. - let GatewaySerial :string = OCMFData.GS != null ? OCMFData.GS.trim() : ""; // Serial number of the gateway, might be mandatory. - let GatewayVersion :string = OCMFData.GV != null ? OCMFData.GV.trim() : ""; // Software version of the gateway. - - let paging :string = OCMFData.PG != null ? OCMFData.PG.trim() : ""; // Paging, as this data might be part of a larger context. - let transactionType = OCMFTransactionTypes.undefined; - switch (paging[0].toLowerCase()) + for (let OCMFData of OCMFValues) { - case 't': - transactionType = OCMFTransactionTypes.transaction; - break; + let GatewayInformation :string = OCMFData.GI != null ? OCMFData.GI.trim() : ""; // Some text about the manufacturer, model, variant, ... of e.g. the gateway. + let GatewaySerial :string = OCMFData.GS != null ? OCMFData.GS.trim() : ""; // Serial number of the gateway, might be mandatory. + let GatewayVersion :string = OCMFData.GV != null ? OCMFData.GV.trim() : ""; // Software version of the gateway. - case 'f': - transactionType = OCMFTransactionTypes.fiscal; - break + let paging :string = OCMFData.PG != null ? OCMFData.PG.trim() : ""; // Paging, as this data might be part of a larger context. + let TransactionType = OCMFTransactionTypes.undefined; + switch (paging[0].toLowerCase()) + { + + case 't': + TransactionType = OCMFTransactionTypes.transaction; + break; + + case 'f': + TransactionType = OCMFTransactionTypes.fiscal; + break + + } + let Pagination = paging.substring(1); + + let MeterVendor :string = OCMFData.MV != null ? OCMFData.MV.trim() : ""; // Vendor of the device, optional. + let MeterModel :string = OCMFData.MM != null ? OCMFData.MM.trim() : ""; // Model of the device, optional. + let MeterSerial :string = OCMFData.MS != null ? OCMFData.MS.trim() : ""; // Serialnumber of the device, might be optional. + let MeterFirmware :string = OCMFData.MF != null ? OCMFData.MF.trim() : ""; // Software version of the device. + + let IdentificationStatus:boolean = OCMFData.IS != null ? OCMFData.IS : false; // true, if user is assigned, else false. + let IdentificationLevel :string = OCMFData.IL != null ? OCMFData.IL.trim() : ""; // optional + let IdentificationFlags :string[] = OCMFData.IF != null ? OCMFData.IF : []; // optional + let IdentificationType :string = OCMFData.IT != null ? OCMFData.IT.trim() : ""; // The type of the authentication data. + let IdentificationData :string = OCMFData.ID != null ? OCMFData.ID.trim() : ""; // The authentication data. + + let ChargePointIdType :string = OCMFData.CT != null ? OCMFData.CT.trim() : ""; // Type of the following ChargePointId: EVSEId|ChargingStationId|... + let ChargePointId :string = OCMFData.CI != null ? OCMFData.CI.trim() : ""; // The identification of the charge point + + if (!OCMFData.RD || OCMFData.RD.length == 0) + throw "Each OCMF data set must have at least one meter reading!"; + + for (let reading of OCMFData.RD) + { + + let metaTimestamp = reading.TM.split(' '); + let Timestamp = metaTimestamp[0]; + let TimeStatus = metaTimestamp[1]; + let Transaction = reading.TX; // B|C,X|E,L,R,A,P|S|T | null + let Value = reading.RV; // typeof RV == 'number', but MUST NOT be rounded! + let OBIS = reading.RI; // OBIS-Code + let Unit = reading.RU; // Reading-Unit: kWh, ... + let CurrentType = reading.RT; // Reading-Current-Type + let ErrorFlags = reading.EF; // Error-Flags + let Status = reading.ST; // Status + + if (CTR.chargingSessions[0].begin == null) + CTR.chargingSessions[0].begin = Timestamp; + + CTR.chargingSessions[0].end = Timestamp; + + if (CTR.chargingSessions[0].measurements.length == 0) + CTR.chargingSessions[0].measurements.push({ + "energyMeterId": MeterSerial, + "@context": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/OCMFv1.0+json", + "obis": OBIS, // "1-b:1.8.0" + "unit": Unit, // "kWh" + "currentType": CurrentType, // "AC" + "values": [] + }); + + CTR.chargingSessions[0].measurements[0].values.push({ + "timestamp": Timestamp, // "2019-06-26T08:57:44,337+0000" + "timeStatus": TimeStatus, // "U" + "transaction": Transaction, // "B" + "value": Value, // 2935.6 + "transactionType": TransactionType, // "T" + "pagination": Pagination, // "9289" + "errorFlags": ErrorFlags, // "" + "status": Status, // "G" + "signatures": [{ + "value": OCMFData["__signature"]["SD"] + }] + }); + + } + + CTR.begin = CTR.chargingSessions[0].begin; + CTR.end = CTR.chargingSessions[0].end; + + CTR.chargingSessions[0].authorizationStart["@id"] = OCMFData.ID; + CTR.chargingSessions[0].authorizationStart["type"] = OCMFData.IT; + CTR.chargingSessions[0].authorizationStart["IS"] = OCMFData.IS; + CTR.chargingSessions[0].authorizationStart["IL"] = OCMFData.IL; + CTR.chargingSessions[0].authorizationStart["IF"] = OCMFData.IF; } - let pagingId = paging.substring(1); - let MeterVendor :string = OCMFData.MV != null ? OCMFData.MV.trim() : ""; // Vendor of the device, optional. - let MeterModel :string = OCMFData.MM != null ? OCMFData.MM.trim() : ""; // Model of the device, optional. - let MeterSerial :string = OCMFData.MS != null ? OCMFData.MS.trim() : ""; // Serialnumber of the device, might be optional. - let MeterFirmware :string = OCMFData.MF != null ? OCMFData.MF.trim() : ""; // Software version of the device. + await this.processChargeTransparencyRecord(CTR); + return true; } catch (exception) { } @@ -2536,75 +2785,126 @@ class ChargyApplication { //#endregion - private tryToParseOCMF(OCMF: string, - PublicKey?: string) : boolean + private async tryToParseOCMF(OCMFValues: string|string[], + PublicKey?: string) : Promise { - // OCMF|{"FV":"1.0","GI":"SEAL AG","GS":"1850006a","GV":"1.34","PG":"T9289","MV":"Carlo Gavazzi","MM":"EM340-DIN.AV2.3.X.S1.PF","MS":"******240084S","MF":"B4","IS":true,"IL":"TRUSTED","IF":["OCCP_AUTH"],"IT":"ISO14443","ID":"56213C05","RD":[{"TM":"2019-06-26T08:57:44,337+0000 U","TX":"B","RV":268.978,"RI":"1-b:1.8.0","RU":"kWh","RT":"AC","EF":"","ST":"G"}]}|{"SD":"304402201455BF1082C9EB8B1272D7FA838EB44286B03AC96E8BAFC5E79E30C5B3E1B872022006286CA81AEE0FAFCB1D6A137FFB2C0DD014727E2AEC149F30CD5A7E87619139"} - let elements = OCMF.split('|'); + let commonVersion = ""; + let OCMFDataList:Object[] = []; + + if (typeof OCMFValues === 'string') + OCMFValues = [ OCMFValues ]; - if (elements.length == 3) + for (let OCMFValue of OCMFValues) { - try + // OCMF|{"FV":"1.0","GI":"SEAL AG","GS":"1850006a","GV":"1.34","PG":"T9289","MV":"Carlo Gavazzi","MM":"EM340-DIN.AV2.3.X.S1.PF","MS":"******240084S","MF":"B4","IS":true,"IL":"TRUSTED","IF":["OCCP_AUTH"],"IT":"ISO14443","ID":"56213C05","RD":[{"TM":"2019-06-26T08:57:44,337+0000 U","TX":"B","RV":268.978,"RI":"1-b:1.8.0","RU":"kWh","RT":"AC","EF":"","ST":"G"}]}|{"SD":"304402201455BF1082C9EB8B1272D7FA838EB44286B03AC96E8BAFC5E79E30C5B3E1B872022006286CA81AEE0FAFCB1D6A137FFB2C0DD014727E2AEC149F30CD5A7E87619139"} + let OCMFSections = OCMFValue.split('|'); + + if (OCMFSections.length == 3) { - let OCMFData = JSON.parse(elements[1]); - let OCMFSignature = JSON.parse(elements[2]); - - // http://hers.abl.de/SAFE/Datenformat_OCMF/Datenformat_OCMF_v1.0.pdf - // Ein Darstellungsformat, JSON-basiert (nachvollziehbar) - // Ein Übertragungsformat, JSON-basiert (vereinheitlicht) - // - // { - // "FV": "1.0", - // "GI": "SEAL AG", - // "GS": "1850006a", - // "GV": "1.34", - // - // "PG": "T9289", - // - // "MV": "Carlo Gavazzi", - // "MM": "EM340-DIN.AV2.3.X.S1.PF", - // "MS": "******240084S", - // "MF": "B4", - // - // "IS": true, - // "IL": "TRUSTED", - // "IF": ["OCCP_AUTH"], - // "IT": "ISO14443", - // "ID": "56213C05", - // - // "RD": [{ - // "TM": "2019-06-26T08:57:44,337+0000 U", - // "TX": "B", - // "RV": 268.978, - // "RI": "1-b:1.8.0", - // "RU": "kWh", - // "RT": "AC", - // "EF": "", - // "ST": "G" - // }] - // } - - // Protocol version: major.minor - let FormatVersion:string = OCMFData["FV"] != null ? OCMFData["FV"].trim() : ""; - - switch (FormatVersion) - { + if (OCMFSections[0] !== "OCMF") + throw "The given data does not have a valid OCMF header!" - case "0.1": - return this.tryToParseOCMFv0_1(OCMFData as IOCMFData_v0_1, PublicKey); + let OCMFVersion = ""; + let OCMFData:Object = {}; + let OCMFSignature:Object = {}; - case "1.0": - return this.tryToParseOCMFv1_0(OCMFData as IOCMFData_v1_0, PublicKey); + try + { + // http://hers.abl.de/SAFE/Datenformat_OCMF/Datenformat_OCMF_v1.0.pdf + // Ein Darstellungsformat, JSON-basiert (nachvollziehbar) + // Ein Übertragungsformat, JSON-basiert (vereinheitlicht) + // + // { + // "FV": "1.0", + // "GI": "SEAL AG", + // "GS": "1850006a", + // "GV": "1.34", + // + // "PG": "T9289", + // + // "MV": "Carlo Gavazzi", + // "MM": "EM340-DIN.AV2.3.X.S1.PF", + // "MS": "******240084S", + // "MF": "B4", + // + // "IS": true, + // "IL": "TRUSTED", + // "IF": ["OCCP_AUTH"], + // "IT": "ISO14443", + // "ID": "56213C05", + // + // "RD": [{ + // "TM": "2019-06-26T08:57:44,337+0000 U", + // "TX": "B", + // "RV": 268.978, + // "RI": "1-b:1.8.0", + // "RU": "kWh", + // "RT": "AC", + // "EF": "", + // "ST": "G" + // }] + // } + // { + // "SD": "304402201455BF1082C9EB8B1272D7FA838EB44286B03AC96E8BAFC5E79E30C5B3E1B872022006286CA81AEE0FAFCB1D6A137FFB2C0DD014727E2AEC149F30CD5A7E87619139" + // } + + OCMFData = JSON.parse(OCMFSections[1]); + OCMFSignature = JSON.parse(OCMFSections[2]); + OCMFVersion = OCMFData["FV"] != null ? OCMFData["FV"].trim() : ""; + + } + catch (exception) + { + throw "Could not parse the given OCMF data!"; } + if (OCMFData == null || OCMFData == {}) + throw "Could not parse the given OCMF data!"; + + if (OCMFSignature == null || OCMFSignature == {}) + throw "Could not parse the given OCMF signature!"; + + if (commonVersion == "") + commonVersion = OCMFVersion; + else + if (OCMFVersion != commonVersion) + "Invalid mixture of different OCMF versions within the given SAFE XML!"; + + OCMFData["__signature"] = OCMFSignature; + + OCMFDataList.push(OCMFData); + } - catch (exception) - { } + else + throw "The given data is not valid OCMF!" + + } + + if (OCMFDataList.length == 1) + throw "The given data is not valid OCMF!"; + + if (OCMFDataList.length >= 2) + { + switch (commonVersion) + { + + case "0.1": + //@ts-ignore + return await this.tryToParseOCMFv0_1(OCMFDataList as IOCMFData_v0_1[], PublicKey); + + case "1.0": + //@ts-ignore + return await this.tryToParseOCMFv1_0(OCMFDataList as IOCMFData_v1_0[], PublicKey); + + default: + throw "Unknown OCMF version!"; + + } } return false; @@ -2615,7 +2915,7 @@ class ChargyApplication { //#region detectContentFormat(Content) - private detectContentFormat(Content: string) { + private async detectContentFormat(Content: string) { if (Content == null) return; @@ -2653,14 +2953,14 @@ class ChargyApplication { { case "http://transparenz.software/schema/2018/07": - if (!this.tryToParseTransparenzSoftwareXML(XMLDocument)) + if (! await this.tryToParseTransparenzSoftwareXML(XMLDocument)) this.doGlobalError("Unbekanntes Transparenzdatensatzformat!"); break; // The SAFE transparency software v1.0 does not understand its own // XML namespace. Therefore we have to guess the format. case "": - if (!this.tryToParseTransparenzSoftwareXML(XMLDocument)) + if (! await this.tryToParseTransparenzSoftwareXML(XMLDocument)) this.doGlobalError("Unbekanntes Transparenzdatensatzformat!"); break; @@ -2677,7 +2977,7 @@ class ChargyApplication { // The SAFE transparency software v1.0 does not understand its own // XML namespace. Therefore we have to guess the format. - if (!this.tryToParseTransparenzSoftwareXML(XMLDocument)) + if (! await this.tryToParseTransparenzSoftwareXML(XMLDocument)) this.doGlobalError("Unbekanntes Transparenzdatensatzformat!"); } @@ -2697,7 +2997,7 @@ class ChargyApplication { else if (Content.startsWith("OCMF|{")) { - if (!this.tryToParseOCMF(Content)) + if (! await this.tryToParseOCMF(Content)) this.doGlobalError("Unbekanntes Transparenzdatensatzformat!"); } @@ -2717,12 +3017,12 @@ class ChargyApplication { { case "https://open.charging.cloud/contexts/CTR+json": - this.processChargeTransparencyRecord(JSONContent); + await this.processChargeTransparencyRecord(JSONContent); break; default: //@ts-ignore - if (!this.tryToParseAnonymousFormat(JSONContent)) + if (! await this.tryToParseAnonymousFormat(JSONContent)) this.doGlobalError("Unbekanntes Transparenzdatensatzformat!"); break; @@ -2887,9 +3187,9 @@ class ChargyApplication { else { - let meterIdDiv = CreateDiv(meterDiv, "meter"); + let meterIdDiv = CreateDiv(meterDiv, "meterId"); - let meterIdIdDiv = CreateDiv(meterIdDiv, "meterId", + let meterIdIdDiv = CreateDiv(meterIdDiv, "meterIdId", "Zählerseriennummer"); let meterIdValueDiv = CreateDiv(meterIdDiv, "meterIdValue", @@ -3046,6 +3346,10 @@ class ChargyApplication { chargingSession.method = new EMHCrypt01(this.GetMeter, await this.CheckMeterPublicKeySignature); return await chargingSession.method.VerifyChargingSession(chargingSession); + case "https://open.charging.cloud/contexts/SessionSignatureFormats/OCMFv1.0+json": + chargingSession.method = new OCMFv1_0 (this.GetMeter, await this.CheckMeterPublicKeySignature); + return await chargingSession.method.VerifyChargingSession(chargingSession); + default: return result; @@ -3093,6 +3397,22 @@ class ChargyApplication { measurementValue.method = new EMHCrypt01(this.GetMeter, this.CheckMeterPublicKeySignature); return measurementValue.method.VerifyMeasurement(measurementValue); + case "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/OCMFv1.0+json": + if (measurementValue.measurement.chargingSession.method != null) + { + + measurementValue.method = measurementValue.measurement.chargingSession.method; + + if (measurementValue.result == null) + return measurementValue.method.VerifyMeasurement(measurementValue); + + return measurementValue.result; + + } + + measurementValue.method = new OCMFv1_0(this.GetMeter, this.CheckMeterPublicKeySignature); + return measurementValue.method.VerifyMeasurement(measurementValue); + default: return result; diff --git a/src/js/chargyLib.ts b/src/js/chargyLib.ts index 42e20ca..de8851e 100644 --- a/src/js/chargyLib.ts +++ b/src/js/chargyLib.ts @@ -387,4 +387,18 @@ function OpenExternal(URL: string) shell.openExternal(URL); -} \ No newline at end of file +} + + +interface String { + isNullOrEmpty(): boolean; + isNotNullOrEmpty(): boolean; +} + +String.prototype.isNullOrEmpty = function() { + return !(typeof this === "string" && this.length > 0); +} + +String.prototype.isNotNullOrEmpty = function() { + return typeof this === "string" && this.length > 0; +} From 4291b3b579d9b7597608a85ce2328349a2d58532 Mon Sep 17 00:00:00 2001 From: Achim Friedland Date: Tue, 3 Sep 2019 21:11:14 +0200 Subject: [PATCH 008/110] Add support for ALFEN charge transparency records --- documentation/REBUILD.md | 6 +- package-lock.json | 5 + package.json | 1 + src/js/chargy.ts | 419 +++++++++++++++++++++++++++++++++++++-- src/js/chargyLib.ts | 16 ++ 5 files changed, 422 insertions(+), 25 deletions(-) diff --git a/documentation/REBUILD.md b/documentation/REBUILD.md index 50d0e6a..1c86bf1 100644 --- a/documentation/REBUILD.md +++ b/documentation/REBUILD.md @@ -32,10 +32,10 @@ $ npm install @types/elliptic@latest --save-dev $ npm install moment@latest + moment@2.24.0 -``` - - +$ npm install base32-decode ++ base32-decode@1.0.0 +``` diff --git a/package-lock.json b/package-lock.json index 28f2c4a..11ad054 100644 --- a/package-lock.json +++ b/package-lock.json @@ -294,6 +294,11 @@ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, + "base32-decode": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base32-decode/-/base32-decode-1.0.0.tgz", + "integrity": "sha512-KNWUX/R7wKenwE/G/qFMzGScOgVntOmbE27vvc6GrniDGYb6a5+qWcuoXl8WIOQL7q0TpK7nZDm1Y04Yi3Yn5g==" + }, "base64-js": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", diff --git a/package.json b/package.json index 80b3f0a..db27c19 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "@types/chart.js": "^2.7.54", "@types/elliptic": "^6.4.9", "@types/leaflet": "^1.4.4", + "base32-decode": "^1.0.0", "chart.js": "^2.8.0", "elliptic": "^6.5.0", "leaflet": "^1.5.1", diff --git a/src/js/chargy.ts b/src/js/chargy.ts index 828617b..2241239 100644 --- a/src/js/chargy.ts +++ b/src/js/chargy.ts @@ -1731,6 +1731,19 @@ class ChargyApplication { var placeInfo = SomeJSON.placeInfo; // { + // "placeInfo": { + // "evseId": "DE*BDO*74778874*1", + // "address": { + // "street": "Musterstraße 12", + // "zipCode": "74789", + // "town": "Stadt" + // }, + // "geoLocation": { + // "lat": 12.3774, + // "lon": 1.3774 + // } + // }, + // // "signedMeterValues":[{ // "timestamp": 1550533285, // "meterInfo": { @@ -1777,20 +1790,8 @@ class ChargyApplication { // "status": "88" // }, // "signature": "13493BBB43DA1E26C88B21ADB7AA53A7AE4FC7F6F6B916E67AD3E168421D180F021D6DD458612C53FF167781892A9DF3" - // }], + // }] // - // "placeInfo": { - // "evseId": "DE*BDO*74778874*1", - // "address": { - // "street": "Musterstraße 12", - // "zipCode": "74789", - // "town": "Stadt" - // }, - // "geoLocation": { - // "lat": 12.3774, - // "lon": 1.3774 - // } - // } // } try { @@ -2199,7 +2200,7 @@ class ChargyApplication { "begin": this.moment.unix(CTRArray[0]["measuredValue"]["timestampLocal"]["timestamp"]).utc().format(), "end": this.moment.unix(CTRArray[n]["measuredValue"]["timestampLocal"]["timestamp"]).utc().format(), "EVSEId": evseId, - + "authorizationStart": { "@id": CTRArray[0]["contract"]["id"], "type": CTRArray[0]["contract"]["type"], @@ -2297,6 +2298,8 @@ class ChargyApplication { private async tryToParseTransparenzSoftwareXML(XMLDocument: Document) : Promise { + const base32Decode = require('base32-decode'); + // The SAFE transparency software v1.0 does not understand its own // XML namespace. Therefore we have to guess the format. @@ -2337,15 +2340,20 @@ class ChargyApplication { case "": case "plain": + signedDataValue = Buffer.from(signedDataValue, 'utf8').toString().trim(); break; - //case "base32": + case "base32": + signedDataValue = Buffer.from(base32Decode(signedDataValue, 'RFC4648')).toString().trim(); + break; case "base64": signedDataValue = Buffer.from(signedDataValue, 'base64').toString().trim(); break; - //case "hex": + case "hex": + signedDataValue = Buffer.from(signedDataValue, 'hex').toString().trim(); + break; default: throw "Unkown signed data encoding within the given SAFE XML!"; @@ -2355,6 +2363,13 @@ class ChargyApplication { switch (signedDataFormat) { + case "alfen": + if (commonFormat == "") + commonFormat = "alfen"; + else if (commonFormat != "alfen") + throw "Invalid mixture of different signed data formats within the given SAFE XML!"; + break; + case "ocmf": if (commonFormat == "") commonFormat = "ocmf"; @@ -2393,15 +2408,20 @@ class ChargyApplication { case "": case "plain": + publicKeyValue = Buffer.from(publicKeyValue, 'utf8').toString().trim(); break; - //case "base32": + case "base32": + publicKeyValue = Buffer.from(base32Decode(publicKeyValue, 'RFC4648')).toString().trim(); + break; case "base64": publicKeyValue = Buffer.from(publicKeyValue, 'base64').toString().trim(); break; - //case "hex": + case "hex": + publicKeyValue = Buffer.from(publicKeyValue, 'hex').toString().trim(); + break; default: throw "Unkown public key encoding within the given SAFE XML!"; @@ -2428,6 +2448,9 @@ class ChargyApplication { switch (commonFormat) { + case "alfen": + return await this.tryToParseALFENFormat(signedValues); + case "ocmf": return await this.tryToParseOCMF(signedValues, commonPublicKey); @@ -2913,6 +2936,346 @@ class ChargyApplication { //#endregion + //#region tryToParseALFENFormat(Content) + + private bufferToHex (buffer: ArrayBuffer) : string { + return Array + .from (new Uint8Array (buffer)) + .map (b => b.toString (16).padStart (2, "0")) + .join (""); + } + + private async tryToParseALFENFormat(Content: string|string[]) : Promise + { + + const base32Decode = require('base32-decode'); + + // AP; + // 0; + // 3; + // AJ2J7LYMGCIWT4AHUJPPFIIVB3FGRV2JQ2HVZG2I; + // BIHEIWSHAAA2WZUZOYYDCNWTWAFACRC2I4ADGAEDQ4AAAABASMBFSAHY2JWF2AIAAEEAB7Y6ABUVEAAAAAAAAABQGQ2EMNCFIVATANRVII4DAAAAAAAAAAADAAAAABIAAAAA====; + // S27J5BHL22ZBNFYTHTK433G7VU7Z6NN4JKO5DNPE7FNMT3SM3ZJGVWJ6ZKUOKE2LK4W63JYP4E6CY===; + + // AP; + // 1; + // 3; + // AJ2J7LYMGCIWT4AHUJPPFIIVB3FGRV2JQ2HVZG2I; + // BIHEIWSHAAA2WZUZOYYDCNWTWAFACRC2I4ADGAEDQ4AAAAAQEMWVSAASAAAAAAIAAEEAB7Y6ABXFEAAAAAAAAABQGQ2EMNCFIVATANRVII4DAAAAAAAAAAADAAAAABQAAAAA====; + // MVYFHY24SFHI35DSXBSXRFMQP4OLYVO77TIQ6REROGCPWHY36AXIU4FD4W4Q2AHBZSNJXWCIRXAGS===; + + try + { + + var common = { + PublicKey: "", + AdapterId: "", + AdapterFWVersion: "", + AdapterFWChecksum: "", + MeterId: "", + ObisId: "", + Unit: "", + Scalar: "", + UID: "", + SessionId: 0, + dataSets: [] as any[] + }; + + let signedValues:string[] = []; + if (typeof (Content) === 'string') + signedValues = Content.split(/\r\n|\r|\n/g); + else + signedValues = Content; + + for (let i=0; i 43675944 dec + let Timestamp = DataSet.slice(34, 38); // UNIX timestamp: 91 91 3D 5C => 1547538833 => 2019-01-15T07:53:53Z + let ObisId = DataSet.slice(38, 44); // 01 00 01 08 00 ff + let Unit = DataSet.slice(44, 45); // 1e == Wh + let Scalar = DataSet.slice(45, 46); // 00 + let Value = DataSet.slice(46, 54); // 73 29 00 00 00 00 00 00 => 10611 Wh so 10,611 KWh + let UID = DataSet.slice(54, 74); // ASCII: 30 35 38 39 38 41 42 42 00 00 00 00 00 00 00 00 00 00 00 00 => UID: 05 89 8A BB + let SessionId = DataSet.slice(74, 78); // 81 01 00 00 => 385(dec) + let Paging = DataSet.slice(78, 82); // 47 02 00 00 => 583(dec) + + let _AdapterId = this.bufferToHex(AdapterId); + let _AdapterFWVersion = String.fromCharCode.apply(null, new Uint8Array(AdapterFWVersion) as any); + let _AdapterFWChecksum = this.bufferToHex(AdapterFWChecksum); + let _MeterId = this.bufferToHex(MeterId); + let _Status = this.bufferToHex(Status); + let _SecondIndex = new DataView(SecondIndex, 0).getInt32 (0, true); + let _Timestamp = new Date(new DataView(Timestamp, 0).getInt32(0, true) * 1000).toISOString(); // this.moment.unix(timestamp).utc().format(), + let _ObisId = this.bufferToHex(ObisId); + let _Unit = this.bufferToHex(Unit); + let _Scalar = this.bufferToHex(Scalar); + let _Value = new DataView(Value, 0).getBigInt64(0, true); + let _UID = String.fromCharCode.apply(null, new Uint8Array(UID) as any).replace(/\0.*$/g, ''); + let _SessionId = new DataView(SessionId, 0).getInt32 (0, true); + let _Paging = new DataView(Paging, 0).getInt32 (0, true); + + + if (common.AdapterId === "") + common.AdapterId = _AdapterId; + else if (_AdapterId !== common.AdapterId) + return false; + + if (common.AdapterFWVersion === "") + common.AdapterFWVersion = _AdapterFWVersion; + else if (_AdapterFWVersion !== common.AdapterFWVersion) + return false; + + if (common.AdapterFWChecksum === "") + common.AdapterFWChecksum = _AdapterFWChecksum; + else if (_AdapterFWChecksum !== common.AdapterFWChecksum) + return false; + + if (common.MeterId === "") + common.MeterId = _MeterId; + else if (_MeterId !== common.MeterId) + return false; + + if (common.ObisId === "") + common.ObisId = _ObisId; + else if (_ObisId !== common.ObisId) + return false; + + if (common.Unit === "") + common.Unit = _Unit; + else if (_Unit !== common.Unit) + return false; + + if (common.Scalar === "") + common.Scalar = _Scalar; + else if (_Scalar !== common.Scalar) + return false; + + if (common.UID === "") + common.UID = _UID; + else if (_UID !== common.UID) + return false; + + if (common.SessionId === 0) + common.SessionId = _SessionId; + else if (_SessionId !== common.SessionId) + return false; + + + common.dataSets.push({ + //@ts-ignore + "Status": _Status, + //@ts-ignore + "SecondIndex": _SecondIndex, + //@ts-ignore + "Timestamp": _Timestamp, + //@ts-ignore + "Value": _Value, + //@ts-ignore + "Paging": _Paging, + //@ts-ignore + "Signature": this.bufferToHex(Signature) + }); + + } + + + var n = common.dataSets.length-1; + var _CTR: any = { //IChargeTransparencyRecord = { + + "@id": common.SessionId, + "@context": "https://open.charging.cloud/contexts/CTR+json", + + "begin": common.dataSets[0]["Timestamp"], + "end": common.dataSets[n]["Timestamp"], + + "description": { + "de": "Alle Ladevorgänge" + }, + + "contract": { + "@id": common.UID, + //"type": CTRArray[0]["contract"]["type"], + "username": "", + "email": "" + }, + + // "chargingStations": [ + // { + // "@id": evseId.substring(0, evseId.lastIndexOf("*")), + // // "description": { + // // "de": "GraphDefined Charging Station - CI-Tests Pool 3 / Station A" + // // }, + // "firmwareVersion": CTRArray[0]["chargePoint"]["softwareVersion"], + // "geoLocation": { "lat": geoLocation_lat, "lng": geoLocation_lon }, + // "address": { + // "street": address_street, + // "postalCode": address_zipCode, + // "city": address_town + // }, + // "EVSEs": [ + // { + // "@id": evseId, + // // "description": { + // // "de": "GraphDefined EVSE - CI-Tests Pool 3 / Station A / EVSE 1" + // // }, + // "sockets": [ { } ], + // "meters": [ + // { + // "@id": CTRArray[0]["meterInfo"]["meterId"], + // "vendor": CTRArray[0]["meterInfo"]["manufacturer"], + // "vendorURL": "http://www.emh-metering.de", + // "model": CTRArray[0]["meterInfo"]["type"], + // "hardwareVersion": "1.0", + // "firmwareVersion": CTRArray[0]["meterInfo"]["firmwareVersion"], + // "signatureFormat": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/EMHCrypt01", + // "publicKeys": [ + // { + // "algorithm": "secp192r1", + // "format": "DER", + // "value": CTRArray[0]["meterInfo"]["publicKey"].startsWith("04") + // ? CTRArray[0]["meterInfo"]["publicKey"] + // : "04" + CTRArray[0]["meterInfo"]["publicKey"], + // "signatures": CTRArray[0]["meterInfo"]["publicKeySignatures"] + // } + // ] + // } + // ] + // } + // ] + // } + + "chargingSessions": [ + + { + + "@id": common.SessionId, + "@context": "https://open.charging.cloud/contexts/SessionSignatureFormats/AlfenCrypt03+json", + "begin": common.dataSets[0]["Timestamp"], + "end": common.dataSets[n]["Timestamp"], + // "EVSEId": evseId, + + "authorizationStart": { + "@id": common.UID, + // "type": CTRArray[0]["contract"]["type"], + // "timestamp": this.moment.unix(CTRArray[0]["contract"]["timestampLocal"]["timestamp"]).utc().utcOffset( + // CTRArray[0]["contract"]["timestampLocal"]["localOffset"] + + // CTRArray[0]["contract"]["timestampLocal"]["seasonOffset"]).format(), + }, + + // "signatureInfos": { + // "hash": "SHA256", + // "hashTruncation": "24", + // "algorithm": "ECC", + // "curve": "secp192r1", + // "format": "rs" + // }, + + "measurements": [ + + { + + "energyMeterId": common.MeterId, + "@context": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/AlfenCrypt03+json", + // "name": CTRArray[0]["measurand"]["name"], + "obis": common.ObisId, + // "unit": CTRArray[0]["measuredValue"]["unit"], + "unitEncoded": common.Unit, + // "valueType": CTRArray[0]["measuredValue"]["valueType"], + "scale": common.Scalar, + + // "signatureInfos": { + // "hash": "SHA512", + // "hashTruncation": "24", + // "algorithm": "ECC", + // "curve": "secp192r1", + // "format": "rs" + // }, + + "values": [ ] + + } + + ] + + } + + ] + + }; + + for (var dataSet of common.dataSets) + { + + _CTR["chargingSessions"][0]["measurements"][0]["values"].push( + + { + "timestamp": dataSet["Timestamp"], + "value": dataSet["Value"], + "infoStatus": dataSet["Status"], + "secondsIndex": dataSet["SecondIndex"], + "paginationId": dataSet["Paging"], + // "logBookIndex": _measurement["additionalInfo"]["indexes"]["logBook"], + "signatures": [ + { + "r": dataSet["Signature"].substring(0, 48), + "s": dataSet["Signature"].substring(48) + } + ] + } + + ); + + } + + await this.processChargeTransparencyRecord(_CTR); + return true; + + } + catch (exception) + { } + + return false; + + } + + //#endregion + //#region detectContentFormat(Content) private async detectContentFormat(Content: string) { @@ -2953,14 +3316,14 @@ class ChargyApplication { { case "http://transparenz.software/schema/2018/07": - if (! await this.tryToParseTransparenzSoftwareXML(XMLDocument)) + if (!await this.tryToParseTransparenzSoftwareXML(XMLDocument)) this.doGlobalError("Unbekanntes Transparenzdatensatzformat!"); break; // The SAFE transparency software v1.0 does not understand its own // XML namespace. Therefore we have to guess the format. case "": - if (! await this.tryToParseTransparenzSoftwareXML(XMLDocument)) + if (!await this.tryToParseTransparenzSoftwareXML(XMLDocument)) this.doGlobalError("Unbekanntes Transparenzdatensatzformat!"); break; @@ -2997,7 +3360,19 @@ class ChargyApplication { else if (Content.startsWith("OCMF|{")) { - if (! await this.tryToParseOCMF(Content)) + if (!await this.tryToParseOCMF(Content)) + this.doGlobalError("Unbekanntes Transparenzdatensatzformat!"); + + } + + //#endregion + + //#region ALFEN processing + + else if (Content.startsWith("AP;")) + { + + if (!await this.tryToParseALFENFormat(Content)) this.doGlobalError("Unbekanntes Transparenzdatensatzformat!"); } @@ -3022,7 +3397,7 @@ class ChargyApplication { default: //@ts-ignore - if (! await this.tryToParseAnonymousFormat(JSONContent)) + if (!await this.tryToParseAnonymousFormat(JSONContent)) this.doGlobalError("Unbekanntes Transparenzdatensatzformat!"); break; diff --git a/src/js/chargyLib.ts b/src/js/chargyLib.ts index de8851e..87680e0 100644 --- a/src/js/chargyLib.ts +++ b/src/js/chargyLib.ts @@ -141,6 +141,22 @@ function buf2hex(buffer: ArrayBuffer) { return Array.prototype.map.call(new Uint8Array(buffer), (x:number) => ('00' + x.toString(16)).slice(-2)).join(''); } +function hexToArrayBuffer(hex: string): ArrayBuffer { + + if ((hex.length % 2) !== 0) { + throw new RangeError('Expected string to be an even number of characters') + } + + var view = new Uint8Array(hex.length / 2) + + for (var i = 0; i < hex.length; i += 2) { + view[i / 2] = parseInt(hex.substring(i, i + 2), 16) + } + + return view.buffer + +} + function intFromBytes(x: number[]){ var val = 0; for (var i = 0; i < x.length; ++i) { From 2456417533b22efce2830143f25611d63c72725f Mon Sep 17 00:00:00 2001 From: Achim 'ahzf' Friedland Date: Fri, 13 Sep 2019 03:23:25 +0200 Subject: [PATCH 009/110] Reorg. ALFEN Testdatensatz 01 added. --- documentation/Alfen/ALFEN-Testdatensatz-01.xml | 12 ++++++++++++ .../{ => GraphDefined}/GDF-ChargingSession-01.chargy | 0 .../GDF-TestChargingSessions-01.chargy | 0 .../{ => chargeIT}/chargeIT-Testdatensatz-01.chargy | 0 .../{ => chargeIT}/chargeIT-Testdatensatz-02.chargy | 0 5 files changed, 12 insertions(+) create mode 100644 documentation/Alfen/ALFEN-Testdatensatz-01.xml rename documentation/{ => GraphDefined}/GDF-ChargingSession-01.chargy (100%) rename documentation/{ => GraphDefined}/GDF-TestChargingSessions-01.chargy (100%) rename documentation/{ => chargeIT}/chargeIT-Testdatensatz-01.chargy (100%) rename documentation/{ => chargeIT}/chargeIT-Testdatensatz-02.chargy (100%) diff --git a/documentation/Alfen/ALFEN-Testdatensatz-01.xml b/documentation/Alfen/ALFEN-Testdatensatz-01.xml new file mode 100644 index 0000000..d47092f --- /dev/null +++ b/documentation/Alfen/ALFEN-Testdatensatz-01.xml @@ -0,0 +1,12 @@ + + + + + AP;0;3;AJ2J7LYMGCIWT4AHUJPPFIIVB3FGRV2JQ2HVZG2I;BIHEIWSHAAA2WZUZOYYDCNWTWAFACRC2I4ADGAEDQ4AAAABASMBFSAHY2JWF2AIAAEEAB7Y6ABUVEAAAAAAAAABQGQ2EMNCFIVATANRVII4DAAAAAAAAAAADAAAAABIAAAAA====;S27J5BHL22ZBNFYTHTK433G7VU7Z6NN4JKO5DNPE7FNMT3SM3ZJGVWJ6ZKUOKE2LK4W63JYP4E6CY===; + + + + AP;1;3;AJ2J7LYMGCIWT4AHUJPPFIIVB3FGRV2JQ2HVZG2I;BIHEIWSHAAA2WZUZOYYDCNWTWAFACRC2I4ADGAEDQ4AAAAAQEMWVSAASAAAAAAIAAEEAB7Y6ABXFEAAAAAAAAABQGQ2EMNCFIVATANRVII4DAAAAAAAAAAADAAAAABQAAAAA====;MVYFHY24SFHI35DSXBSXRFMQP4OLYVO77TIQ6REROGCPWHY36AXIU4FD4W4Q2AHBZSNJXWCIRXAGS===; + + + diff --git a/documentation/GDF-ChargingSession-01.chargy b/documentation/GraphDefined/GDF-ChargingSession-01.chargy similarity index 100% rename from documentation/GDF-ChargingSession-01.chargy rename to documentation/GraphDefined/GDF-ChargingSession-01.chargy diff --git a/documentation/GDF-TestChargingSessions-01.chargy b/documentation/GraphDefined/GDF-TestChargingSessions-01.chargy similarity index 100% rename from documentation/GDF-TestChargingSessions-01.chargy rename to documentation/GraphDefined/GDF-TestChargingSessions-01.chargy diff --git a/documentation/chargeIT-Testdatensatz-01.chargy b/documentation/chargeIT/chargeIT-Testdatensatz-01.chargy similarity index 100% rename from documentation/chargeIT-Testdatensatz-01.chargy rename to documentation/chargeIT/chargeIT-Testdatensatz-01.chargy diff --git a/documentation/chargeIT-Testdatensatz-02.chargy b/documentation/chargeIT/chargeIT-Testdatensatz-02.chargy similarity index 100% rename from documentation/chargeIT-Testdatensatz-02.chargy rename to documentation/chargeIT/chargeIT-Testdatensatz-02.chargy From 7df6532efed31848a340fc800a29865b95af1757 Mon Sep 17 00:00:00 2001 From: Achim 'ahzf' Friedland Date: Fri, 13 Sep 2019 03:25:12 +0200 Subject: [PATCH 010/110] Reorg. --- documentation/{OCMF v1.0 => OCMF}/OCMF-Testdatensatz-01.json | 0 .../{OCMF v1.0 => OCMF}/OCMF-Testdatensatz-01_publicKey.json | 0 .../{OCMF v1.0 => OCMF}/SAFE-Testdatensatz-01_OCMFv0.1.xml | 0 .../SAFE-Testdatensatz-02_emptyXMLNamespace.xml | 0 .../SAFE-Testdatensatz-02_withXMLNamespace.xml | 0 .../SAFE-Testdatensatz-02_withoutXMLNamespace.xml | 0 .../SAFE-Testdatensatz-03_multipleOCMFMeasurements.xml | 0 documentation/{OCMF v1.0 => OCMF}/SAFE-TransparencySoftware.xsd | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename documentation/{OCMF v1.0 => OCMF}/OCMF-Testdatensatz-01.json (100%) rename documentation/{OCMF v1.0 => OCMF}/OCMF-Testdatensatz-01_publicKey.json (100%) rename documentation/{OCMF v1.0 => OCMF}/SAFE-Testdatensatz-01_OCMFv0.1.xml (100%) rename documentation/{OCMF v1.0 => OCMF}/SAFE-Testdatensatz-02_emptyXMLNamespace.xml (100%) rename documentation/{OCMF v1.0 => OCMF}/SAFE-Testdatensatz-02_withXMLNamespace.xml (100%) rename documentation/{OCMF v1.0 => OCMF}/SAFE-Testdatensatz-02_withoutXMLNamespace.xml (100%) rename documentation/{OCMF v1.0 => OCMF}/SAFE-Testdatensatz-03_multipleOCMFMeasurements.xml (100%) rename documentation/{OCMF v1.0 => OCMF}/SAFE-TransparencySoftware.xsd (100%) diff --git a/documentation/OCMF v1.0/OCMF-Testdatensatz-01.json b/documentation/OCMF/OCMF-Testdatensatz-01.json similarity index 100% rename from documentation/OCMF v1.0/OCMF-Testdatensatz-01.json rename to documentation/OCMF/OCMF-Testdatensatz-01.json diff --git a/documentation/OCMF v1.0/OCMF-Testdatensatz-01_publicKey.json b/documentation/OCMF/OCMF-Testdatensatz-01_publicKey.json similarity index 100% rename from documentation/OCMF v1.0/OCMF-Testdatensatz-01_publicKey.json rename to documentation/OCMF/OCMF-Testdatensatz-01_publicKey.json diff --git a/documentation/OCMF v1.0/SAFE-Testdatensatz-01_OCMFv0.1.xml b/documentation/OCMF/SAFE-Testdatensatz-01_OCMFv0.1.xml similarity index 100% rename from documentation/OCMF v1.0/SAFE-Testdatensatz-01_OCMFv0.1.xml rename to documentation/OCMF/SAFE-Testdatensatz-01_OCMFv0.1.xml diff --git a/documentation/OCMF v1.0/SAFE-Testdatensatz-02_emptyXMLNamespace.xml b/documentation/OCMF/SAFE-Testdatensatz-02_emptyXMLNamespace.xml similarity index 100% rename from documentation/OCMF v1.0/SAFE-Testdatensatz-02_emptyXMLNamespace.xml rename to documentation/OCMF/SAFE-Testdatensatz-02_emptyXMLNamespace.xml diff --git a/documentation/OCMF v1.0/SAFE-Testdatensatz-02_withXMLNamespace.xml b/documentation/OCMF/SAFE-Testdatensatz-02_withXMLNamespace.xml similarity index 100% rename from documentation/OCMF v1.0/SAFE-Testdatensatz-02_withXMLNamespace.xml rename to documentation/OCMF/SAFE-Testdatensatz-02_withXMLNamespace.xml diff --git a/documentation/OCMF v1.0/SAFE-Testdatensatz-02_withoutXMLNamespace.xml b/documentation/OCMF/SAFE-Testdatensatz-02_withoutXMLNamespace.xml similarity index 100% rename from documentation/OCMF v1.0/SAFE-Testdatensatz-02_withoutXMLNamespace.xml rename to documentation/OCMF/SAFE-Testdatensatz-02_withoutXMLNamespace.xml diff --git a/documentation/OCMF v1.0/SAFE-Testdatensatz-03_multipleOCMFMeasurements.xml b/documentation/OCMF/SAFE-Testdatensatz-03_multipleOCMFMeasurements.xml similarity index 100% rename from documentation/OCMF v1.0/SAFE-Testdatensatz-03_multipleOCMFMeasurements.xml rename to documentation/OCMF/SAFE-Testdatensatz-03_multipleOCMFMeasurements.xml diff --git a/documentation/OCMF v1.0/SAFE-TransparencySoftware.xsd b/documentation/OCMF/SAFE-TransparencySoftware.xsd similarity index 100% rename from documentation/OCMF v1.0/SAFE-TransparencySoftware.xsd rename to documentation/OCMF/SAFE-TransparencySoftware.xsd From 068370e0c2d93133b4d7e7c94294221ede3548fe Mon Sep 17 00:00:00 2001 From: Achim 'ahzf' Friedland Date: Fri, 13 Sep 2019 03:28:21 +0200 Subject: [PATCH 011/110] Fix typo --- src/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.html b/src/index.html index e35912e..19abb43 100644 --- a/src/index.html +++ b/src/index.html @@ -68,7 +68,7 @@
Sie können den Transparenzdatensatz zu Ihren Ladevorgängen entweder aus - einer Datei laden, über die Zwischenablage einfügen oder Drap'n'Drop + einer Datei laden, über die Zwischenablage einfügen oder Drag'n'Drop verwenden...
From 86b31c17163631d43c43818d49e1883f12e46995 Mon Sep 17 00:00:00 2001 From: Achim 'ahzf' Friedland Date: Fri, 20 Sep 2019 04:59:18 +0200 Subject: [PATCH 012/110] Reafctorings to seperate GUI and logic. Add stubs for additional charge transparency formats. --- src/index.html | 9 +- src/js/Alfen.ts | 405 ++++ src/js/Mennekes.ts | 49 + src/js/OCMF.ts | 535 +++++ src/js/SAFE_XML.ts | 231 +++ src/js/chargeIT.ts | 610 ++++++ src/js/chargepoint.ts | 49 + src/js/chargy.ts | 3975 ++++-------------------------------- src/js/chargyApp.ts | 1770 ++++++++++++++++ src/js/chargyInterfaces.ts | 32 +- tsconfig.json | 2 +- 11 files changed, 4111 insertions(+), 3556 deletions(-) create mode 100644 src/js/Alfen.ts create mode 100644 src/js/Mennekes.ts create mode 100644 src/js/OCMF.ts create mode 100644 src/js/SAFE_XML.ts create mode 100644 src/js/chargeIT.ts create mode 100644 src/js/chargepoint.ts create mode 100644 src/js/chargyApp.ts diff --git a/src/index.html b/src/index.html index 19abb43..72361f8 100644 --- a/src/index.html +++ b/src/index.html @@ -41,9 +41,16 @@ + + + + + + + @@ -393,7 +400,7 @@

Datenschutzerklärung für diesen Mängelmelder

id: 'ahzf.nc811hb2' }).addTo(map); - var chargyApplication = new ChargyApplication(); + var chargyApp = new ChargyApp(); diff --git a/src/js/Alfen.ts b/src/js/Alfen.ts new file mode 100644 index 0000000..3778359 --- /dev/null +++ b/src/js/Alfen.ts @@ -0,0 +1,405 @@ +/* + * Copyright (c) 2018-2019 GraphDefined GmbH + * This file is part of Chargy Desktop App + * + * Licensed under the Affero GPL license, Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.gnu.org/licenses/agpl.html + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/// +/// +/// + +class Alfen { + + + private bufferToHex (buffer: ArrayBuffer) : string { + return Array + .from (new Uint8Array (buffer)) + .map (b => b.toString (16).padStart (2, "0")) + .join (""); + } + + //#region tryToParseALFENFormat(Content) + + public async tryToParseALFENFormat(Content: string|string[]) : Promise + { + + const base32Decode = require('base32-decode'); + + // AP; + // 0; + // 3; + // AJ2J7LYMGCIWT4AHUJPPFIIVB3FGRV2JQ2HVZG2I; + // BIHEIWSHAAA2WZUZOYYDCNWTWAFACRC2I4ADGAEDQ4AAAABASMBFSAHY2JWF2AIAAEEAB7Y6ABUVEAAAAAAAAABQGQ2EMNCFIVATANRVII4DAAAAAAAAAAADAAAAABIAAAAA====; + // S27J5BHL22ZBNFYTHTK433G7VU7Z6NN4JKO5DNPE7FNMT3SM3ZJGVWJ6ZKUOKE2LK4W63JYP4E6CY===; + + // AP; + // 1; + // 3; + // AJ2J7LYMGCIWT4AHUJPPFIIVB3FGRV2JQ2HVZG2I; + // BIHEIWSHAAA2WZUZOYYDCNWTWAFACRC2I4ADGAEDQ4AAAAAQEMWVSAASAAAAAAIAAEEAB7Y6ABXFEAAAAAAAAABQGQ2EMNCFIVATANRVII4DAAAAAAAAAAADAAAAABQAAAAA====; + // MVYFHY24SFHI35DSXBSXRFMQP4OLYVO77TIQ6REROGCPWHY36AXIU4FD4W4Q2AHBZSNJXWCIRXAGS===; + + try + { + + var common = { + PublicKey: "", + AdapterId: "", + AdapterFWVersion: "", + AdapterFWChecksum: "", + MeterId: "", + ObisId: "", + Unit: "", + Scalar: "", + UID: "", + SessionId: 0, + dataSets: [] as any[] + }; + + let signedValues:string[] = []; + if (typeof (Content) === 'string') + signedValues = Content.split(/\r\n|\r|\n/g); + else + signedValues = Content; + + for (let i=0; i 43675944 dec + let Timestamp = DataSet.slice(34, 38); // UNIX timestamp: 91 91 3D 5C => 1547538833 => 2019-01-15T07:53:53Z + let ObisId = DataSet.slice(38, 44); // 01 00 01 08 00 ff + let Unit = DataSet.slice(44, 45); // 1e == Wh + let Scalar = DataSet.slice(45, 46); // 00 + let Value = DataSet.slice(46, 54); // 73 29 00 00 00 00 00 00 => 10611 Wh so 10,611 KWh + let UID = DataSet.slice(54, 74); // ASCII: 30 35 38 39 38 41 42 42 00 00 00 00 00 00 00 00 00 00 00 00 => UID: 05 89 8A BB + let SessionId = DataSet.slice(74, 78); // 81 01 00 00 => 385(dec) + let Paging = DataSet.slice(78, 82); // 47 02 00 00 => 583(dec) + + let _AdapterId = this.bufferToHex(AdapterId); + let _AdapterFWVersion = String.fromCharCode.apply(null, new Uint8Array(AdapterFWVersion) as any); + let _AdapterFWChecksum = this.bufferToHex(AdapterFWChecksum); + let _MeterId = this.bufferToHex(MeterId); + let _Status = this.bufferToHex(Status); + let _SecondIndex = new DataView(SecondIndex, 0).getInt32 (0, true); + let _Timestamp = new Date(new DataView(Timestamp, 0).getInt32(0, true) * 1000).toISOString(); // this.moment.unix(timestamp).utc().format(), + let _ObisId = this.bufferToHex(ObisId); + let _Unit = this.bufferToHex(Unit); + let _Scalar = this.bufferToHex(Scalar); + let _Value = new DataView(Value, 0).getBigInt64(0, true); + let _UID = String.fromCharCode.apply(null, new Uint8Array(UID) as any).replace(/\0.*$/g, ''); + let _SessionId = new DataView(SessionId, 0).getInt32 (0, true); + let _Paging = new DataView(Paging, 0).getInt32 (0, true); + + + if (common.AdapterId === "") + common.AdapterId = _AdapterId; + else if (_AdapterId !== common.AdapterId) + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Inconsistent adapter identification!" + }; + + if (common.AdapterFWVersion === "") + common.AdapterFWVersion = _AdapterFWVersion; + else if (_AdapterFWVersion !== common.AdapterFWVersion) + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Inconsistent adapter firmware version!" + }; + + if (common.AdapterFWChecksum === "") + common.AdapterFWChecksum = _AdapterFWChecksum; + else if (_AdapterFWChecksum !== common.AdapterFWChecksum) + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Inconsistent adapter firmware checksum!" + }; + + if (common.MeterId === "") + common.MeterId = _MeterId; + else if (_MeterId !== common.MeterId) + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Inconsistent meter identification!" + }; + + if (common.ObisId === "") + common.ObisId = _ObisId; + else if (_ObisId !== common.ObisId) + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Inconsistent OBIS identification!" + }; + + if (common.Unit === "") + common.Unit = _Unit; + else if (_Unit !== common.Unit) + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Inconsistent unit value!" + }; + + if (common.Scalar === "") + common.Scalar = _Scalar; + else if (_Scalar !== common.Scalar) + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Inconsistent measurement scaler!" + }; + + if (common.UID === "") + common.UID = _UID; + else if (_UID !== common.UID) + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Inconsistent user identification!" + }; + + if (common.SessionId === 0) + common.SessionId = _SessionId; + else if (_SessionId !== common.SessionId) + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Inconsistent charging session identification!" + }; + + + common.dataSets.push({ + //@ts-ignore + "Status": _Status, + //@ts-ignore + "SecondIndex": _SecondIndex, + //@ts-ignore + "Timestamp": _Timestamp, + //@ts-ignore + "Value": _Value, + //@ts-ignore + "Paging": _Paging, + //@ts-ignore + "Signature": this.bufferToHex(Signature) + }); + + } + + + var n = common.dataSets.length-1; + var _CTR: any = { //IChargeTransparencyRecord = { + + "@id": common.SessionId, + "@context": "https://open.charging.cloud/contexts/CTR+json", + + "begin": common.dataSets[0]["Timestamp"], + "end": common.dataSets[n]["Timestamp"], + + "description": { + "de": "Alle Ladevorgänge" + }, + + "contract": { + "@id": common.UID, + //"type": CTRArray[0]["contract"]["type"], + "username": "", + "email": "" + }, + + // "chargingStations": [ + // { + // "@id": evseId.substring(0, evseId.lastIndexOf("*")), + // // "description": { + // // "de": "GraphDefined Charging Station - CI-Tests Pool 3 / Station A" + // // }, + // "firmwareVersion": CTRArray[0]["chargePoint"]["softwareVersion"], + // "geoLocation": { "lat": geoLocation_lat, "lng": geoLocation_lon }, + // "address": { + // "street": address_street, + // "postalCode": address_zipCode, + // "city": address_town + // }, + // "EVSEs": [ + // { + // "@id": evseId, + // // "description": { + // // "de": "GraphDefined EVSE - CI-Tests Pool 3 / Station A / EVSE 1" + // // }, + // "sockets": [ { } ], + // "meters": [ + // { + // "@id": CTRArray[0]["meterInfo"]["meterId"], + // "vendor": CTRArray[0]["meterInfo"]["manufacturer"], + // "vendorURL": "http://www.emh-metering.de", + // "model": CTRArray[0]["meterInfo"]["type"], + // "hardwareVersion": "1.0", + // "firmwareVersion": CTRArray[0]["meterInfo"]["firmwareVersion"], + // "signatureFormat": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/EMHCrypt01", + // "publicKeys": [ + // { + // "algorithm": "secp192r1", + // "format": "DER", + // "value": CTRArray[0]["meterInfo"]["publicKey"].startsWith("04") + // ? CTRArray[0]["meterInfo"]["publicKey"] + // : "04" + CTRArray[0]["meterInfo"]["publicKey"], + // "signatures": CTRArray[0]["meterInfo"]["publicKeySignatures"] + // } + // ] + // } + // ] + // } + // ] + // } + + "chargingSessions": [ + + { + + "@id": common.SessionId, + "@context": "https://open.charging.cloud/contexts/SessionSignatureFormats/AlfenCrypt03+json", + "begin": common.dataSets[0]["Timestamp"], + "end": common.dataSets[n]["Timestamp"], + // "EVSEId": evseId, + + "authorizationStart": { + "@id": common.UID, + // "type": CTRArray[0]["contract"]["type"], + // "timestamp": this.moment.unix(CTRArray[0]["contract"]["timestampLocal"]["timestamp"]).utc().utcOffset( + // CTRArray[0]["contract"]["timestampLocal"]["localOffset"] + + // CTRArray[0]["contract"]["timestampLocal"]["seasonOffset"]).format(), + }, + + // "signatureInfos": { + // "hash": "SHA256", + // "hashTruncation": "24", + // "algorithm": "ECC", + // "curve": "secp192r1", + // "format": "rs" + // }, + + "measurements": [ + + { + + "energyMeterId": common.MeterId, + "@context": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/AlfenCrypt03+json", + // "name": CTRArray[0]["measurand"]["name"], + "obis": common.ObisId, + // "unit": CTRArray[0]["measuredValue"]["unit"], + "unitEncoded": common.Unit, + // "valueType": CTRArray[0]["measuredValue"]["valueType"], + "scale": common.Scalar, + + // "signatureInfos": { + // "hash": "SHA512", + // "hashTruncation": "24", + // "algorithm": "ECC", + // "curve": "secp192r1", + // "format": "rs" + // }, + + "values": [ ] + + } + + ] + + } + + ] + + }; + + for (var dataSet of common.dataSets) + { + + _CTR["chargingSessions"][0]["measurements"][0]["values"].push( + + { + "timestamp": dataSet["Timestamp"], + "value": dataSet["Value"], + "infoStatus": dataSet["Status"], + "secondsIndex": dataSet["SecondIndex"], + "paginationId": dataSet["Paging"], + // "logBookIndex": _measurement["additionalInfo"]["indexes"]["logBook"], + "signatures": [ + { + "r": dataSet["Signature"].substring(0, 48), + "s": dataSet["Signature"].substring(48) + } + ] + } + + ); + + } + + //await this.processChargeTransparencyRecord(_CTR); + return _CTR as IChargeTransparencyRecord; + + } + catch (exception) + { + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Exception occured: " + exception.message + } + } + + } + + //#endregion + + +} diff --git a/src/js/Mennekes.ts b/src/js/Mennekes.ts new file mode 100644 index 0000000..d43db42 --- /dev/null +++ b/src/js/Mennekes.ts @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018-2019 GraphDefined GmbH + * This file is part of Chargy Desktop App + * + * Licensed under the Affero GPL license, Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.gnu.org/licenses/agpl.html + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/// +/// +/// + +class Mennekes { + + //#region tryToParseMennekesXML(XMLDocument) + + public async tryToParseMennekesXML(XMLDocument: Document) : Promise + { + + try + { + + return { + status: SessionVerificationResult.InvalidSessionFormat + } + + } + catch (exception) + { + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Exception occured: " + exception.message + } + } + + } + + //#endregion + +} diff --git a/src/js/OCMF.ts b/src/js/OCMF.ts new file mode 100644 index 0000000..e6d18a8 --- /dev/null +++ b/src/js/OCMF.ts @@ -0,0 +1,535 @@ +/* + * Copyright (c) 2018-2019 GraphDefined GmbH + * This file is part of Chargy Desktop App + * + * Licensed under the Affero GPL license, Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.gnu.org/licenses/agpl.html + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/// +/// +/// +/// +/// +/// + +class OCMF { + + //#region tryToParseOCMFv0_1(OCMFData, PublicKey?) + + private async tryToParseOCMFv0_1(OCMFData: IOCMFData_v0_1, + PublicKey?: string) : Promise + { + + // { + // "FV": "0.1", + // "VI": "ABL", + // "VV": "1.4p3", + // + // "PG": "T12345", + // + // "MV": "Phoenix Contact", + // "MM": "EEM-350-D-MCB", + // "MS": "BQ27400330016", + // "MF": "1.0", + // + // "IS": "VERIFIED", + // "IF": ["RFID_PLAIN", "OCPP_RS_TLS"], + // "IT": "ISO14443", + // "ID": "1F2D3A4F5506C7", + // + // "RD": [{ + // "TM": "2018-07-24T13:22:04,000+0200 S", + // "TX": "B", + // "RV": 2935.6, + // "RI": "1-b:1.8.e", + // "RU": "kWh", + // "EI": 567, + // "ST": "G" + // }] + // } + + try + { + + let VendorInformation :string = OCMFData.VI != null ? OCMFData.VI.trim() : ""; // Some text about the manufacturer, model, variant, ... of e.g. the vendor. + let VendorVersion :string = OCMFData.VV != null ? OCMFData.VV.trim() : ""; // Software version of the vendor. + + let paging :string = OCMFData.PG != null ? OCMFData.PG.trim() : ""; // Paging, as this data might be part of a larger context. + let transactionType = OCMFTransactionTypes.undefined; + switch (paging[0].toLowerCase()) + { + + case 't': + transactionType = OCMFTransactionTypes.transaction; + break; + + case 'f': + transactionType = OCMFTransactionTypes.fiscal; + break + + } + let pagingId = paging.substring(1); + + let MeterVendor :string = OCMFData.MV != null ? OCMFData.MV.trim() : ""; // Vendor of the device, optional. + let MeterModel :string = OCMFData.MM != null ? OCMFData.MM.trim() : ""; // Model of the device, optional. + let MeterSerial :string = OCMFData.MS != null ? OCMFData.MS.trim() : ""; // Serialnumber of the device, might be optional. + let MeterFirmware :string = OCMFData.MF != null ? OCMFData.MF.trim() : ""; // Software version of the device. + + return { + status: SessionVerificationResult.InvalidSessionFormat + } + + } catch (exception) + { + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Exception occured: " + exception.message + } + } + + } + + //#endregion + + //#region tryToParseOCMFv1_0(OCMFData, PublicKey?) + + public async tryToParseOCMF(OCMFValues: IOCMFData_v1_0[], + PublicKey?: string) : Promise + { + + try + { + + var CTR:any = { + + "@id": "1554181214441:-1965658344385548683:2", + "@context": "https://open.charging.cloud/contexts/CTR+json", + "begin": "2019-04-02T05:00:19Z", + "end": "2019-04-02T05:13:52Z", + "description": { + "de": "Alle OCMF-Ladevorgänge" + }, + "contract": { + "@id": "8057F5AA592904", + "type": "RFID_TAG_ID", + "username": "", + "email": "" + }, + + "EVSEs": [{ + "@id": "DE*BDO*E8025334492*2", + "meters": [{ + "@id": "0901454D48000083E076", + "vendor": "EMH", + "vendorURL": "http://www.emh-metering.de", + "model": "eHZ IW8E EMH", + "hardwareVersion": "1.0", + "firmwareVersion": "123", + "signatureFormat": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/OCMFv1.0+json", + "publicKeys": [{ + "algorithm": "secp192r1", + "format": "DER", + "value": "049EA8697F5C3126E86A37295566D560DE8EA690325791C9CBA79D30612B8EA8E00908FBAD5374812D55DCC3D809C3A36C", + }] + }] + + }], + + "chargingSessions": [{ + + "@id": "1554181214441:-1965658344385548683:2", + "@context": "https://open.charging.cloud/contexts/SessionSignatureFormats/OCMFv1.0+json", + "begin": null, + "end": null, + "EVSEId": "DE*BDO*E8025334492*2", + + "authorizationStart": { + "@id": "8057F5AA592904", + "type": "RFID_TAG_ID" + }, + + "signatureInfos": { + "hash": "SHA512", + "hashTruncation": "24", + "algorithm": "ECC", + "curve": "secp192r1", + "format": "rs" + }, + + "measurements": [//{ + + // "energyMeterId": "0901454D48000083E076", + // "@context": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/OCMFv1.0+json", + // "name": "ENERGY_TOTAL", + // "obis": "0100011100FF", + // "unit": "WATT_HOUR", + // "unitEncoded": 30, + // "valueType": "Integer64", + // "scale": -1, + + // "signatureInfos": { + // "hash": "SHA512", + // "hashTruncation": "24", + // "algorithm": "ECC", + // "curve": "secp192r1", + // "format": "rs" + // }, + + // "values": [ + // { + // "timestamp": "2019-04-02T07:00:19+02:00", + // "value": "66260", + // "infoStatus": "08", + // "secondsIndex": 65058, + // "paginationId": "00000012", + // "logBookIndex": "0006", + // "signatures": [{ + // "r": "71F76A80F170F87675AAEB19606BBD298355FDA7B0851700", + // "s": "2FAD322FA073255BD8B971BD69BFF051BCA9330703172E3C" + // }] + // }, + // { + // "timestamp": "2019-04-02T07:13:52+02:00", + // "value": "67327", + // "infoStatus": "08", + // "secondsIndex": 65871, + // "paginationId": "00000013", + // "logBookIndex": "0006", + // "signatures": [{ + // "r": "6DF01D7603CB49BB76141F8E67B371351BF1F87C1F8D38AE", + // "s": "B3600A9432B8CE0A378126D4FB9D9581457651A5D208AD9E" + // }] + // } + ] + + }] + + // }] + }; + + // [ // Not standard compliant use of an array! + // + // { + // + // "FV": "1.0", + // "GI": "SEAL AG", + // "GS": "1850006a", + // "GV": "1.34", + // + // "PG": "T9289", + // + // "MV": "Carlo Gavazzi", + // "MM": "EM340-DIN.AV2.3.X.S1.PF", + // "MS": "******240084S", + // "MF": "B4", + // + // "IS": true, + // "IL": "TRUSTED", + // "IF": ["OCCP_AUTH"], + // "IT": "ISO14443", + // "ID": "56213C05", + // + // "RD": [{ + // "TM": "2019-06-26T08:57:44,337+0000 U", + // "TX": "B", + // "RV": 268.978, + // "RI": "1-b:1.8.0", + // "RU": "kWh", + // "RT": "AC", + // "EF": "", + // "ST": "G" + // }], + // + // "__signature": { // Not standard compliant property key! + // "SD": "304402201455BF1082C9EB8B1272D7FA838EB44286B03AC96E8BAFC5E79E30C5B3E1B872022006286CA81AEE0FAFCB1D6A137FFB2C0DD014727E2AEC149F30CD5A7E87619139" + // } + // + // }, + // + // [...] + // + // ] + + for (let OCMFData of OCMFValues) + { + + let GatewayInformation :string = OCMFData.GI != null ? OCMFData.GI.trim() : ""; // Some text about the manufacturer, model, variant, ... of e.g. the gateway. + let GatewaySerial :string = OCMFData.GS != null ? OCMFData.GS.trim() : ""; // Serial number of the gateway, might be mandatory. + let GatewayVersion :string = OCMFData.GV != null ? OCMFData.GV.trim() : ""; // Software version of the gateway. + + let paging :string = OCMFData.PG != null ? OCMFData.PG.trim() : ""; // Paging, as this data might be part of a larger context. + let TransactionType = OCMFTransactionTypes.undefined; + switch (paging[0].toLowerCase()) + { + + case 't': + TransactionType = OCMFTransactionTypes.transaction; + break; + + case 'f': + TransactionType = OCMFTransactionTypes.fiscal; + break + + } + let Pagination = paging.substring(1); + + let MeterVendor :string = OCMFData.MV != null ? OCMFData.MV.trim() : ""; // Vendor of the device, optional. + let MeterModel :string = OCMFData.MM != null ? OCMFData.MM.trim() : ""; // Model of the device, optional. + let MeterSerial :string = OCMFData.MS != null ? OCMFData.MS.trim() : ""; // Serialnumber of the device, might be optional. + let MeterFirmware :string = OCMFData.MF != null ? OCMFData.MF.trim() : ""; // Software version of the device. + + let IdentificationStatus:boolean = OCMFData.IS != null ? OCMFData.IS : false; // true, if user is assigned, else false. + let IdentificationLevel :string = OCMFData.IL != null ? OCMFData.IL.trim() : ""; // optional + let IdentificationFlags :string[] = OCMFData.IF != null ? OCMFData.IF : []; // optional + let IdentificationType :string = OCMFData.IT != null ? OCMFData.IT.trim() : ""; // The type of the authentication data. + let IdentificationData :string = OCMFData.ID != null ? OCMFData.ID.trim() : ""; // The authentication data. + + let ChargePointIdType :string = OCMFData.CT != null ? OCMFData.CT.trim() : ""; // Type of the following ChargePointId: EVSEId|ChargingStationId|... + let ChargePointId :string = OCMFData.CI != null ? OCMFData.CI.trim() : ""; // The identification of the charge point + + if (!OCMFData.RD || OCMFData.RD.length == 0) + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Each OCMF data set must have at least one meter reading!" + } + + for (let reading of OCMFData.RD) + { + + let metaTimestamp = reading.TM.split(' '); + let Timestamp = metaTimestamp[0]; + let TimeStatus = metaTimestamp[1]; + let Transaction = reading.TX; // B|C,X|E,L,R,A,P|S|T | null + let Value = reading.RV; // typeof RV == 'number', but MUST NOT be rounded! + let OBIS = reading.RI; // OBIS-Code + let Unit = reading.RU; // Reading-Unit: kWh, ... + let CurrentType = reading.RT; // Reading-Current-Type + let ErrorFlags = reading.EF; // Error-Flags + let Status = reading.ST; // Status + + if (CTR.chargingSessions[0].begin == null) + CTR.chargingSessions[0].begin = Timestamp; + + CTR.chargingSessions[0].end = Timestamp; + + if (CTR.chargingSessions[0].measurements.length == 0) + CTR.chargingSessions[0].measurements.push({ + "energyMeterId": MeterSerial, + "@context": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/OCMFv1.0+json", + "obis": OBIS, // "1-b:1.8.0" + "unit": Unit, // "kWh" + "currentType": CurrentType, // "AC" + "values": [] + }); + + CTR.chargingSessions[0].measurements[0].values.push({ + "timestamp": Timestamp, // "2019-06-26T08:57:44,337+0000" + "timeStatus": TimeStatus, // "U" + "transaction": Transaction, // "B" + "value": Value, // 2935.6 + "transactionType": TransactionType, // "T" + "pagination": Pagination, // "9289" + "errorFlags": ErrorFlags, // "" + "status": Status, // "G" + "signatures": [{ + "value": OCMFData["__signature"]["SD"] + }] + }); + + } + + CTR.begin = CTR.chargingSessions[0].begin; + CTR.end = CTR.chargingSessions[0].end; + + CTR.chargingSessions[0].authorizationStart["@id"] = OCMFData.ID; + CTR.chargingSessions[0].authorizationStart["type"] = OCMFData.IT; + CTR.chargingSessions[0].authorizationStart["IS"] = OCMFData.IS; + CTR.chargingSessions[0].authorizationStart["IL"] = OCMFData.IL; + CTR.chargingSessions[0].authorizationStart["IF"] = OCMFData.IF; + + } + + return { + status: SessionVerificationResult.InvalidSessionFormat + } + + } + catch (exception) + { + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Exception occured: " + exception.message + } + } + + } + + //#endregion + + + //#region Try + + public async tryToParseOCMF2(OCMFValues: string|string[], + PublicKey?: string) : Promise + { + + let commonVersion = ""; + let OCMFDataList:Object[] = []; + + if (typeof OCMFValues === 'string') + OCMFValues = [ OCMFValues ]; + + for (let OCMFValue of OCMFValues) + { + + // OCMF|{"FV":"1.0","GI":"SEAL AG","GS":"1850006a","GV":"1.34","PG":"T9289","MV":"Carlo Gavazzi","MM":"EM340-DIN.AV2.3.X.S1.PF","MS":"******240084S","MF":"B4","IS":true,"IL":"TRUSTED","IF":["OCCP_AUTH"],"IT":"ISO14443","ID":"56213C05","RD":[{"TM":"2019-06-26T08:57:44,337+0000 U","TX":"B","RV":268.978,"RI":"1-b:1.8.0","RU":"kWh","RT":"AC","EF":"","ST":"G"}]}|{"SD":"304402201455BF1082C9EB8B1272D7FA838EB44286B03AC96E8BAFC5E79E30C5B3E1B872022006286CA81AEE0FAFCB1D6A137FFB2C0DD014727E2AEC149F30CD5A7E87619139"} + let OCMFSections = OCMFValue.split('|'); + + if (OCMFSections.length == 3) + { + + if (OCMFSections[0] !== "OCMF") + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "The given data does not have a valid OCMF header!" + } + + let OCMFVersion = ""; + let OCMFData:Object = {}; + let OCMFSignature:Object = {}; + + try + { + + // http://hers.abl.de/SAFE/Datenformat_OCMF/Datenformat_OCMF_v1.0.pdf + // Ein Darstellungsformat, JSON-basiert (nachvollziehbar) + // Ein Übertragungsformat, JSON-basiert (vereinheitlicht) + // + // { + // "FV": "1.0", + // "GI": "SEAL AG", + // "GS": "1850006a", + // "GV": "1.34", + // + // "PG": "T9289", + // + // "MV": "Carlo Gavazzi", + // "MM": "EM340-DIN.AV2.3.X.S1.PF", + // "MS": "******240084S", + // "MF": "B4", + // + // "IS": true, + // "IL": "TRUSTED", + // "IF": ["OCCP_AUTH"], + // "IT": "ISO14443", + // "ID": "56213C05", + // + // "RD": [{ + // "TM": "2019-06-26T08:57:44,337+0000 U", + // "TX": "B", + // "RV": 268.978, + // "RI": "1-b:1.8.0", + // "RU": "kWh", + // "RT": "AC", + // "EF": "", + // "ST": "G" + // }] + // } + // { + // "SD": "304402201455BF1082C9EB8B1272D7FA838EB44286B03AC96E8BAFC5E79E30C5B3E1B872022006286CA81AEE0FAFCB1D6A137FFB2C0DD014727E2AEC149F30CD5A7E87619139" + // } + + OCMFData = JSON.parse(OCMFSections[1]); + OCMFSignature = JSON.parse(OCMFSections[2]); + OCMFVersion = OCMFData["FV"] != null ? OCMFData["FV"].trim() : ""; + + } + catch (exception) + { + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Could not parse the given OCMF data!" + } + } + + if (OCMFData == null || OCMFData == {}) + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Could not parse the given OCMF data!" + } + + if (OCMFSignature == null || OCMFSignature == {}) + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Could not parse the given OCMF signature!" + } + + if (commonVersion == "") + commonVersion = OCMFVersion; + else + if (OCMFVersion != commonVersion) + "Invalid mixture of different OCMF versions within the given SAFE XML!"; + + OCMFData["__signature"] = OCMFSignature; + + OCMFDataList.push(OCMFData); + + } + + else + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "The given data is not valid OCMF!" + } + + } + + if (OCMFDataList.length == 1) + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "The given data is not valid OCMF!" + } + + if (OCMFDataList.length >= 2) + { + switch (commonVersion) + { + + case "0.1": + //@ts-ignore + return await this.tryToParseOCMFv0_1(OCMFDataList as IOCMFData_v0_1[], PublicKey); + + case "1.0": + //@ts-ignore + return await this.tryToParseOCMFv1_0(OCMFDataList as IOCMFData_v1_0[], PublicKey); + + default: + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Unknown OCMF version!" + } + + } + } + + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Unknown OCMF version!" + } + + } + + //#endregion + + +} diff --git a/src/js/SAFE_XML.ts b/src/js/SAFE_XML.ts new file mode 100644 index 0000000..c8cc459 --- /dev/null +++ b/src/js/SAFE_XML.ts @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2018-2019 GraphDefined GmbH + * This file is part of Chargy Desktop App + * + * Licensed under the Affero GPL license, Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.gnu.org/licenses/agpl.html + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/// +/// +/// + +class SAFEXML { + + //#region tryToParseSAFEXML(XMLDocument) + + public async tryToParseSAFEXML(XMLDocument: Document) : Promise + { + + const base32Decode = require('base32-decode'); + + // The SAFE transparency software v1.0 does not understand its own + // XML namespace. Therefore we have to guess the format. + + try + { + + let commonFormat = ""; + let commonPublicKey = ""; + let signedValues:string[] = []; + + let values = XMLDocument.querySelectorAll("values"); + if (values.length == 1) + { + let valueList = values[0].querySelectorAll("value"); + if (valueList.length >= 1) + { + for (let i=0; i... + + var signedData = valueList[i].querySelector("signedData"); + if (signedData != null) + { + + signedDataEncoding = signedData.attributes.getNamedItem("encoding") !== null ? signedData.attributes.getNamedItem("encoding")!.value.trim().toLowerCase() : ""; + signedDataFormat = signedData.attributes.getNamedItem("format") !== null ? signedData.attributes.getNamedItem("format")!.value.trim().toLowerCase() : ""; + signedDataValue = signedData.textContent !== null ? signedData.textContent.trim() : ""; + + switch (signedDataEncoding) + { + + case "": + case "plain": + signedDataValue = Buffer.from(signedDataValue, 'utf8').toString().trim(); + break; + + case "base32": + signedDataValue = Buffer.from(base32Decode(signedDataValue, 'RFC4648')).toString().trim(); + break; + + case "base64": + signedDataValue = Buffer.from(signedDataValue, 'base64').toString().trim(); + break; + + case "hex": + signedDataValue = Buffer.from(signedDataValue, 'hex').toString().trim(); + break; + + default: + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Unkown signed data encoding within the given SAFE XML!" + } + + } + + switch (signedDataFormat) + { + + case "alfen": + if (commonFormat == "") + commonFormat = "alfen"; + else if (commonFormat != "alfen") + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Invalid mixture of different signed data formats within the given SAFE XML!" + } + break; + + case "ocmf": + if (commonFormat == "") + commonFormat = "ocmf"; + else if (commonFormat != "ocmf") + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Invalid mixture of different signed data formats within the given SAFE XML!" + } + break; + + default: + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Unkown signed data formats within the given SAFE XML!" + } + + } + + if (signedDataValue.isNullOrEmpty()) + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "The signed data value within the given SAFE XML must not be empty!" + } + + signedValues.push(signedDataValue); + + } + else + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "The signed data tag within the given SAFE XML must not be empty!" + } + + //#endregion + + //#region ... + + // Note: The public key is optional! + var publicKey = valueList[i].querySelector("publicKey"); + if (publicKey != null) + { + + publicKeyEncoding = publicKey.attributes.getNamedItem("encoding") !== null ? publicKey.attributes.getNamedItem("encoding")!.value.trim().toLowerCase() : ""; + publicKeyValue = publicKey.textContent !== null ? publicKey.textContent.trim() : ""; + + switch (publicKeyEncoding) + { + + case "": + case "plain": + publicKeyValue = Buffer.from(publicKeyValue, 'utf8').toString().trim(); + break; + + case "base32": + publicKeyValue = Buffer.from(base32Decode(publicKeyValue, 'RFC4648')).toString().trim(); + break; + + case "base64": + publicKeyValue = Buffer.from(publicKeyValue, 'base64').toString().trim(); + break; + + case "hex": + publicKeyValue = Buffer.from(publicKeyValue, 'hex').toString().trim(); + break; + + default: + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Unkown public key encoding within the given SAFE XML!" + } + + } + + if (publicKeyValue.isNullOrEmpty()) + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "The public key within the given SAFE XML must not be empty!" + } + + else if (commonPublicKey == "") + commonPublicKey = publicKeyValue; + + else if (publicKeyValue != commonPublicKey) + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Invalid mixture of different public keys within the given SAFE XML!" + } + + } + + //#endregion + + } + } + } + + switch (commonFormat) + { + + case "alfen": + return await new Alfen().tryToParseALFENFormat(signedValues); + + case "ocmf": + return await new OCMF().tryToParseOCMF2(signedValues, commonPublicKey); + + } + + return { + status: SessionVerificationResult.InvalidSessionFormat + } + + } + catch (exception) + { + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Exception occured: " + exception.message + } + } + + } + + //#endregion + +} diff --git a/src/js/chargeIT.ts b/src/js/chargeIT.ts new file mode 100644 index 0000000..b96e97a --- /dev/null +++ b/src/js/chargeIT.ts @@ -0,0 +1,610 @@ +/* + * Copyright (c) 2018-2019 GraphDefined GmbH + * This file is part of Chargy Desktop App + * + * Licensed under the Affero GPL license, Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.gnu.org/licenses/agpl.html + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/// +/// +/// + +class ChargeIT { + + private moment: any; + + constructor() { + this.moment = require('moment'); + } + + //#region tryToParseChargeITJSON(SomeJSON) + + //private async tryToParseAnonymousFormat(SomeJSON: { signedMeterValues: any[]; placeInfo: any; }) : Promise + + // The current chargeIT mobility does not provide any context or format identifiers + public async tryToParseChargeITJSON(SomeJSON: any) : Promise + { + + if (Array.isArray(SomeJSON)) + return { + status: SessionVerificationResult.InvalidSessionFormat + } + + try + { + + var signedMeterValues = SomeJSON.signedMeterValues as Array; + var placeInfo = SomeJSON.placeInfo; + + // { + // "placeInfo": { + // "evseId": "DE*BDO*74778874*1", + // "address": { + // "street": "Musterstraße 12", + // "zipCode": "74789", + // "town": "Stadt" + // }, + // "geoLocation": { + // "lat": 12.3774, + // "lon": 1.3774 + // } + // }, + // + // "signedMeterValues":[{ + // "timestamp": 1550533285, + // "meterInfo": { + // "firmwareVersion": "123", + // "publicKey": "08A56CF3B51DABA44F38607BB884F62FB8BE84B4EF39D09624AB9E0910354398590DC59A5B40F43FE68A9F416F65EC76", + // "publicKeySignatures": [], + // "meterId": "0901454D4800007F9F3E", + // "type": "eHZ IW8E EMH", + // "manufacturer": "EMH" + // }, + // "transactionId": "1546933282548:-7209653592192971037:1", + // "contract": { + // "type": "RFID_TAG_ID", + // "timestampLocal": { + // "timestamp": 1546933284, + // "localOffset": 60, + // "seasonOffset": 0 + // }, + // "timestamp": 1550533284, + // "id": "235DD5BB" + // }, + // "measurementId": "00000007", + // "measuredValue": { + // "timestampLocal": { + // "timestamp": 1546933285, + // "localOffset": 60, + // "seasonOffset": 0 + // }, + // "value": "60077", + // "unit": "WATT_HOUR", + // "scale": -1, + // "valueType": "Integer64", + // "unitEncoded": 30 + // }, + // "measurand": { + // "id": "0100011100FF", + // "name": "ENERGY_TOTAL" + // }, + // "additionalInfo": { + // "indexes": { + // "timer": 1730275, + // "logBook": "0004" + // }, + // "status": "88" + // }, + // "signature": "13493BBB43DA1E26C88B21ADB7AA53A7AE4FC7F6F6B916E67AD3E168421D180F021D6DD458612C53FF167781892A9DF3" + // }] + // + // } + + let CTRArray = []; + + for (let i = 0; i < signedMeterValues.length; i++) { + + let signedMeterValue = signedMeterValues[i]; + + let _timestamp = signedMeterValue["timestamp"] as number; + if (_timestamp == null || typeof _timestamp !== 'number') + throw "Missing or invalid timestamp[" + i + "]!" + let timestamp = parseUTC(_timestamp); + + let _meterInfo = signedMeterValue["meterInfo"] as string; + if (_meterInfo == null || typeof _meterInfo !== 'object') + throw "Missing or invalid meterInfo[" + i + "]!" + + let _meterInfo_firmwareVersion = _meterInfo["firmwareVersion"] as string; + if (_meterInfo_firmwareVersion == null || typeof _meterInfo_firmwareVersion !== 'string') + throw "Missing or invalid meterInfo firmwareVersion[" + i + "]!" + + let _meterInfo_publicKey = _meterInfo["publicKey"] as string; + if (_meterInfo_publicKey == null || typeof _meterInfo_publicKey !== 'string') + throw "Missing or invalid meterInfo publicKey[" + i + "]!" + + let _meterInfo_publicKeySignatures = _meterInfo["publicKeySignatures"]; + + let _meterInfo_meterId = _meterInfo["meterId"] as string; + if (_meterInfo_meterId == null || typeof _meterInfo_meterId !== 'string') + throw "Missing or invalid meterInfo meterId[" + i + "]!" + + let _meterInfo_type = _meterInfo["type"] as string; + if (_meterInfo_type == null || typeof _meterInfo_type !== 'string') + throw "Missing or invalid meterInfo type[" + i + "]!" + + let _meterInfo_manufacturer = _meterInfo["manufacturer"] as string; + if (_meterInfo_manufacturer == null || typeof _meterInfo_manufacturer !== 'string') + throw "Missing or invalid meterInfo manufacturer[" + i + "]!" + + + let _transactionId = signedMeterValue["transactionId"] as string; + if (_transactionId == null || typeof _transactionId !== 'string') + throw "Missing or invalid transactionId[" + i + "]!" + + + let _contract = signedMeterValue["contract"]; + if (_contract == null || typeof _contract !== 'object') + throw "Missing or invalid contract[" + i + "]!" + + let _contract_type = _contract["type"] as string; + if (_contract_type == null || typeof _contract_type !== 'string') + throw "Missing or invalid contract type[" + i + "]!" + + let _contract_timestampLocal = _contract["timestampLocal"]; + if (_contract_timestampLocal == null || typeof _contract_timestampLocal !== 'object') + throw "Missing or invalid contract timestampLocal[" + i + "]!" + + let _contract_timestampLocal_timestamp = _contract_timestampLocal["timestamp"] as number; + if (_contract_timestampLocal_timestamp == null || typeof _contract_timestampLocal_timestamp !== 'number') + throw "Missing or invalid contract timestampLocal timestamp[" + i + "]!" + + let _contract_timestampLocal_localOffset = _contract_timestampLocal["localOffset"] as number; + if (_contract_timestampLocal_localOffset == null || typeof _contract_timestampLocal_localOffset !== 'number') + throw "Missing or invalid contract timestampLocal localOffset[" + i + "]!" + + let _contract_timestampLocal_seasonOffset = _contract_timestampLocal["seasonOffset"] as number; + if (_contract_timestampLocal_seasonOffset == null || typeof _contract_timestampLocal_seasonOffset !== 'number') + throw "Missing or invalid contract timestampLocal seasonOffset[" + i + "]!" + + let _contract_timestamp = _contract["timestamp"] as number; + if (_contract_timestamp == null || typeof _contract_timestamp !== 'number') + throw "Missing or invalid contract timestamp[" + i + "]!" + + let _contract_id = _contract["id"] as string; + if (_contract_id == null || typeof _contract_id !== 'string') + throw "Missing or invalid contract type[" + i + "]!" + + + let _measurementId = signedMeterValue["measurementId"] as string; + if (_measurementId == null || typeof _measurementId !== 'string') + throw "Missing or invalid measurementId[" + i + "]!" + + + let _measuredValue = signedMeterValue["measuredValue"]; + if (_measuredValue == null || typeof _measuredValue !== 'object') + throw "Missing or invalid measuredValue[" + i + "]!" + + let _measuredValue_timestampLocal = _measuredValue["timestampLocal"]; + if (_measuredValue_timestampLocal == null || typeof _measuredValue_timestampLocal !== 'object') + throw "Missing or invalid measuredValue timestampLocal[" + i + "]!" + + let _measuredValue_timestampLocal_timestamp = _measuredValue_timestampLocal["timestamp"] as number; + if (_measuredValue_timestampLocal_timestamp == null || typeof _measuredValue_timestampLocal_timestamp !== 'number') + throw "Missing or invalid measuredValue timestampLocal timestamp[" + i + "]!" + + let _measuredValue_timestampLocal_localOffset = _measuredValue_timestampLocal["localOffset"] as number; + if (_measuredValue_timestampLocal_localOffset == null || typeof _measuredValue_timestampLocal_localOffset !== 'number') + throw "Missing or invalid measuredValue timestampLocal localOffset[" + i + "]!" + + let _measuredValue_timestampLocal_seasonOffset = _measuredValue_timestampLocal["seasonOffset"] as number; + if (_measuredValue_timestampLocal_seasonOffset == null || typeof _measuredValue_timestampLocal_seasonOffset !== 'number') + throw "Missing or invalid measuredValue timestampLocal seasonOffset[" + i + "]!" + + let _measuredValue_value = _measuredValue["value"] as string; + if (_measuredValue_value == null || typeof _measuredValue_value !== 'string') + throw "Missing or invalid measuredValue value[" + i + "]!" + + let _measuredValue_unit = _measuredValue["unit"] as string; + if (_measuredValue_unit == null || typeof _measuredValue_unit !== 'string') + throw "Missing or invalid measuredValue unit[" + i + "]!" + + let _measuredValue_scale = _measuredValue["scale"] as number; + if (_measuredValue_scale == null || typeof _measuredValue_scale !== 'number') + throw "Missing or invalid measuredValue scale[" + i + "]!" + + let _measuredValue_valueType = _measuredValue["valueType"] as string; + if (_measuredValue_valueType == null || typeof _measuredValue_valueType !== 'string') + throw "Missing or invalid measuredValue valueType[" + i + "]!" + + let _measuredValue_unitEncoded = _measuredValue["unitEncoded"] as number; + if (_measuredValue_unitEncoded == null || typeof _measuredValue_unitEncoded !== 'number') + throw "Missing or invalid measuredValue unitEncoded[" + i + "]!" + + + let _measurand = signedMeterValue["measurand"]; + if (_measurand == null || typeof _measurand !== 'object') + throw "Missing or invalid measurand[" + i + "]!" + + let _measurand_id = _measurand["id"] as string; + if (_measurand_id == null || typeof _measurand_id !== 'string') + throw "Missing or invalid measurand id[" + i + "]!" + + let _measurand_name = _measurand["name"] as string; + if (_measurand_name == null || typeof _measurand_name !== 'string') + throw "Missing or invalid measurand name[" + i + "]!" + + + let _additionalInfo = signedMeterValue["additionalInfo"]; + if (_additionalInfo == null || typeof _additionalInfo !== 'object') + throw "Missing or invalid additionalInfo[" + i + "]!" + + let _additionalInfo_indexes = _additionalInfo["indexes"]; + if (_additionalInfo_indexes == null || typeof _additionalInfo_indexes !== 'object') + throw "Missing or invalid additionalInfo indexes[" + i + "]!" + + let _additionalInfo_indexes_timer = _additionalInfo_indexes["timer"] as number; + if (_additionalInfo_indexes_timer == null || typeof _additionalInfo_indexes_timer !== 'number') + throw "Missing or invalid additionalInfo indexes timer[" + i + "]!" + + let _additionalInfo_indexes_logBook = _additionalInfo_indexes["logBook"] as string; + if (_additionalInfo_indexes_logBook == null || typeof _additionalInfo_indexes_logBook !== 'string') + throw "Missing or invalid additionalInfo indexes logBook[" + i + "]!" + + let _additionalInfo_status = _additionalInfo["status"] as string; + if (_additionalInfo_status == null || typeof _additionalInfo_status !== 'string') + throw "Missing or invalid additionalInfo status[" + i + "]!" + + + let _chargePoint = signedMeterValue["chargePoint"]; + if (_chargePoint == null || typeof _chargePoint !== 'object') + throw "Missing or invalid chargePoint[" + i + "] information!" + + let _chargePointSoftwareVersion = _chargePoint["softwareVersion"]; + if (_chargePointSoftwareVersion == null || typeof _chargePointSoftwareVersion !== 'string') + throw "Missing or invalid chargePoint softwareVersion[" + i + "]!" + + + let _signature = signedMeterValue["signature"] as string; + if (_signature == null || typeof _signature !== 'string') + throw "Missing or invalid signature[" + i + "]!" + + + //let aaa = moment.unix(_contract_timestampLocal_timestamp).utc(); + + CTRArray.push({ + "timestamp": _timestamp, + "meterInfo": { + "firmwareVersion": _meterInfo_firmwareVersion, + "publicKey": _meterInfo_publicKey, + "publicKeySignatures": _meterInfo_publicKeySignatures, + "meterId": _meterInfo_meterId, + "type": _meterInfo_type, + "manufacturer": _meterInfo_manufacturer + }, + "transactionId": _transactionId, + "contract": { + "type": _contract_type, + "timestampLocal": { + "timestamp": _contract_timestampLocal_timestamp, + "localOffset": _contract_timestampLocal_localOffset, + "seasonOffset": _contract_timestampLocal_seasonOffset + }, + "timestamp": _contract_timestamp, + "id": _contract_id + }, + "measurementId": _measurementId, + "measuredValue": { + "timestampLocal": { + "timestamp": _measuredValue_timestampLocal_timestamp, + "localOffset": _measuredValue_timestampLocal_localOffset, + "seasonOffset": _measuredValue_timestampLocal_seasonOffset + }, + "value": _measuredValue_value, + "unit": _measuredValue_unit, + "scale": _measuredValue_scale, + "valueType": _measuredValue_valueType, + "unitEncoded": _measuredValue_unitEncoded + }, + "measurand": { + "id": _measurand_id, + "name": _measurand_name + }, + "additionalInfo": { + "indexes": { + "timer": _additionalInfo_indexes_timer, + "logBook": _additionalInfo_indexes_logBook + }, + "status": _additionalInfo_status + }, + "chargePoint": { + "softwareVersion": _chargePointSoftwareVersion + }, + "signature": _signature + }); + + } + + + var evseId = placeInfo["evseId"] as string; + if (evseId == null || typeof evseId !== 'string') + throw "Missing or invalid EVSE Id!" + + + var address = placeInfo["address"]; + if (address == null) + throw "Missing or invalid address!" + + var address_street = address["street"]; + if (address_street == null || typeof address_street !== 'string') + throw "Missing or invalid address street!" + + var address_zipCode = address["zipCode"]; + if (address_zipCode == null || typeof address_zipCode !== 'string') + throw "Missing or invalid address zipCode!" + + var address_town = address["town"]; + if (address_town == null || typeof address_town !== 'string') + throw "Missing or invalid address town!" + + + var geoLocation = placeInfo["geoLocation"]; + if (geoLocation == null) + throw "Missing or invalid geoLocation!" + + var geoLocation_lat = geoLocation["lat"]; + if (geoLocation_lat == null || typeof geoLocation_lat !== 'number') + throw "Missing or invalid geoLocation latitude!" + + var geoLocation_lon = geoLocation["lon"]; + if (geoLocation_lon == null || typeof geoLocation_lon !== 'number') + throw "Missing or invalid geoLocation longitude!" + + + var n = CTRArray.length-1; + var _CTR: any = { //IChargeTransparencyRecord = { + + "@id": CTRArray[n]["transactionId"], + "@context": "https://open.charging.cloud/contexts/CTR+json", + + "begin": this.moment.unix(CTRArray[0]["measuredValue"]["timestampLocal"]["timestamp"]).utc().format(), + "end": this.moment.unix(CTRArray[n]["measuredValue"]["timestampLocal"]["timestamp"]).utc().format(), + + "description": { + "de": "Alle Ladevorgänge" + }, + + "contract": { + "@id": CTRArray[0]["contract"]["id"], + "type": CTRArray[0]["contract"]["type"], + "username": "", + "email": "" + }, + + "chargingStationOperators": [ + { + + "@id": "chargeITmobilityCSO", + "eMobilityIds": [ "DE*BDO", "DE*LVF", "+49*822" ], + "description": { + "de": "chargeIT mobility GmbH - Charging Station Operator Services" + }, + + "contact": { + "email": "info@chargeit-mobility.com", + "web": "https://www.chargeit-mobility.com", + "logoUrl": "http://www.chargeit-mobility.com/fileadmin/BELECTRIC_Drive/templates/pics/chargeit_logo_408x70.png", + "publicKeys": [ + { + "algorithm": "secp192r1", + "format": "DER", + "value": "042313b9e469612b4ca06981bfdecb226e234632b01d84b6a814f63a114b7762c34ddce2e6853395b7a0f87275f63ffe3c", + "signatures": [ + { + "keyId": "...", + "algorithm": "secp192r1", + "format": "DER", + "value": "????" + } + ] + }, + { + "algorithm": "secp256k1", + "format": "DER", + "value": "04a8ff0d82107922522e004a167cc658f0eef408c5020f98e7a2615be326e61852666877335f4f8d9a0a756c26f0c9fb3f401431416abb5317cc0f5d714d3026fe", + "signatures": [ ] + } + ] + }, + + "support": { + "hotline": "+49 9321 / 2680 - 700", + "email": "service@chargeit-mobility.com", + "web": "https://cso.chargeit.charging.cloud/issues" + // "mediationServices": [ "GraphDefined Mediation" ], + // "publicKeys": [ + // { + // "algorithm": "secp256k1", + // "format": "DER", + // "value": "04a8ff0d82107922522e004a167cc658f0eef408c5020f98e7a2615be326e61852666877335f4f8d9a0a756c26f0c9fb3f401431416abb5317cc0f5d714d3026fe", + // "signatures": [ ] + // } + // ] + }, + + "privacy": { + "contact": "Dr. iur. Christian Borchers, datenschutz süd GmbH", + "email": "datenschutz@chargeit-mobility.com", + "web": "http://www.chargeit-mobility.com/de/datenschutz/" + // "publicKeys": [ + // { + // "algorithm": "secp256k1", + // "format": "DER", + // "value": "04a8ff0d82107922522e004a167cc658f0eef408c5020f98e7a2615be326e61852666877335f4f8d9a0a756c26f0c9fb3f401431416abb5317cc0f5d714d3026fe", + // "signatures": [ ] + // } + // ] + }, + + "chargingStations": [ + { + "@id": evseId.substring(0, evseId.lastIndexOf("*")), + // "description": { + // "de": "GraphDefined Charging Station - CI-Tests Pool 3 / Station A" + // }, + "firmwareVersion": CTRArray[0]["chargePoint"]["softwareVersion"], + "geoLocation": { "lat": geoLocation_lat, "lng": geoLocation_lon }, + "address": { + "street": address_street, + "postalCode": address_zipCode, + "city": address_town + }, + "EVSEs": [ + { + "@id": evseId, + // "description": { + // "de": "GraphDefined EVSE - CI-Tests Pool 3 / Station A / EVSE 1" + // }, + "sockets": [ { } ], + "meters": [ + { + "@id": CTRArray[0]["meterInfo"]["meterId"], + "vendor": CTRArray[0]["meterInfo"]["manufacturer"], + "vendorURL": "http://www.emh-metering.de", + "model": CTRArray[0]["meterInfo"]["type"], + "hardwareVersion": "1.0", + "firmwareVersion": CTRArray[0]["meterInfo"]["firmwareVersion"], + "signatureFormat": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/EMHCrypt01", + "publicKeys": [ + { + "algorithm": "secp192r1", + "format": "DER", + "value": CTRArray[0]["meterInfo"]["publicKey"].startsWith("04") + ? CTRArray[0]["meterInfo"]["publicKey"] + : "04" + CTRArray[0]["meterInfo"]["publicKey"], + "signatures": CTRArray[0]["meterInfo"]["publicKeySignatures"] + } + ] + } + ] + } + ] + } + ] + + } + ], + + "chargingSessions": [ + + { + + "@id": CTRArray[n]["transactionId"], + "@context": "https://open.charging.cloud/contexts/SessionSignatureFormats/EMHCrypt01+json", + "begin": this.moment.unix(CTRArray[0]["measuredValue"]["timestampLocal"]["timestamp"]).utc().format(), + "end": this.moment.unix(CTRArray[n]["measuredValue"]["timestampLocal"]["timestamp"]).utc().format(), + "EVSEId": evseId, + + "authorizationStart": { + "@id": CTRArray[0]["contract"]["id"], + "type": CTRArray[0]["contract"]["type"], + "timestamp": this.moment.unix(CTRArray[0]["contract"]["timestampLocal"]["timestamp"]).utc().utcOffset( + CTRArray[0]["contract"]["timestampLocal"]["localOffset"] + + CTRArray[0]["contract"]["timestampLocal"]["seasonOffset"]).format(), + }, + + "signatureInfos": { + "hash": "SHA512", + "hashTruncation": "24", + "algorithm": "ECC", + "curve": "secp192r1", + "format": "rs" + }, + + "measurements": [ + + { + + "energyMeterId": CTRArray[0]["meterInfo"]["meterId"], + "@context": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/EMHCrypt01+json", + "name": CTRArray[0]["measurand"]["name"], + "obis": CTRArray[0]["measurand"]["id"], + "unit": CTRArray[0]["measuredValue"]["unit"], + "unitEncoded": CTRArray[0]["measuredValue"]["unitEncoded"], + "valueType": CTRArray[0]["measuredValue"]["valueType"], + "scale": CTRArray[0]["measuredValue"]["scale"], + + "signatureInfos": { + "hash": "SHA512", + "hashTruncation": "24", + "algorithm": "ECC", + "curve": "secp192r1", + "format": "rs" + }, + + "values": [ ] + + } + + ] + + } + + ] + + }; + + for (var _measurement of CTRArray) + { + + _CTR["chargingSessions"][0]["measurements"][0]["values"].push( + + { + "timestamp": this.moment.unix(_measurement["measuredValue"]["timestampLocal"]["timestamp"]).utc().utcOffset( + _measurement["measuredValue"]["timestampLocal"]["localOffset"] + + _measurement["measuredValue"]["timestampLocal"]["seasonOffset"]).format(), + "value": _measurement["measuredValue"]["value"], + "infoStatus": _measurement["additionalInfo"]["status"], + "secondsIndex": _measurement["additionalInfo"]["indexes"]["timer"], + "paginationId": _measurement["measurementId"], + "logBookIndex": _measurement["additionalInfo"]["indexes"]["logBook"], + "signatures": [ + { + "r": _measurement["signature"].substring(0, 48), + "s": _measurement["signature"].substring(48) + } + ] + } + + ); + + } + + // await this.processChargeTransparencyRecord(_CTR); + // return true; + return _CTR as IChargeTransparencyRecord; + + } + catch (exception) + { + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Exception occured: " + exception.message + } + } + + } + + //#endregion + +} diff --git a/src/js/chargepoint.ts b/src/js/chargepoint.ts new file mode 100644 index 0000000..3ac464a --- /dev/null +++ b/src/js/chargepoint.ts @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018-2019 GraphDefined GmbH + * This file is part of Chargy Desktop App + * + * Licensed under the Affero GPL license, Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.gnu.org/licenses/agpl.html + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/// +/// +/// + +class Chargepoint { + + //#region tryToParseChargepointXML(XMLDocument) + + public async tryToParseChargepointXML(XMLDocument: Document) : Promise + { + + try + { + + return { + status: SessionVerificationResult.InvalidSessionFormat + } + + } + catch (exception) + { + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Exception occured: " + exception.message + } + } + + } + + //#endregion + +} diff --git a/src/js/chargy.ts b/src/js/chargy.ts index 2241239..f215ba1 100644 --- a/src/js/chargy.ts +++ b/src/js/chargy.ts @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) 2018-2019 GraphDefined GmbH * This file is part of Chargy Desktop App * @@ -18,40 +18,14 @@ /// /// /// -/// -/// -/// - -// import { debug } from "util"; -// import * as crypto from "crypto"; -// import { readSync } from "fs"; -// import { version } from "punycode"; - -var map: any = ""; -var leaflet: any = ""; - -function OpenLink(url: string) -{ - if (url.startsWith("https://")) - require('electron').shell.openExternal(url); -} -class ChargyApplication { +class Chargy { + + //#region Data private elliptic: any; private moment: any; - // variable 'crypto' is already defined differently in Google Chrome! - private crypt = require('electron').remote.require('crypto'); - public appVersion = require('electron').remote.app.getVersion().split('.') as string[]; - private ipcRenderer = require('electron').ipcRenderer; - private path = require('path'); - - private exe_hash = ""; - private app_asar_hash = ""; - private electron_asar_hash = ""; - private complete_hash = ""; - private chargingStationOperators = new Array(); private chargingPools = new Array(); private chargingStations = new Array(); @@ -61,3233 +35,186 @@ class ChargyApplication { private mediationServices = new Array(); private chargingSessions = new Array(); - private input: HTMLDivElement; - private updateAvailableButton: HTMLButtonElement; - private aboutButton: HTMLButtonElement; - private fullScreenButton: HTMLButtonElement; + public currentCTR = {} as IChargeTransparencyRecord; - private updateAvailableScreen: HTMLDivElement; - private inputInfosDiv: HTMLDivElement; - private aboutScreenDiv: HTMLDivElement; - private chargySHA512Div: HTMLDivElement; - private chargingSessionScreenDiv: HTMLDivElement; - private backButtonDiv: HTMLDivElement; - private fileInputButton: HTMLButtonElement; - private fileInput: HTMLInputElement; - private evseTarifInfosDiv: HTMLDivElement; - private errorTextDiv: HTMLDivElement; - private overlayDiv: HTMLDivElement; - private overlayOkButton: HTMLButtonElement; - - private currentCTR = {} as IChargeTransparencyRecord; - private markers: any = []; - private minlat: number = +1000; - private maxlat: number = -1000; - private minlng: number = +1000; - private maxlng: number = -1000; + //#endregion - private currentAppInfos: any = null; - private currentVersionInfos: any = null; - private currentPackage: any = null; + constructor(elliptic: any, + moment: any) { - constructor() { + this.elliptic = elliptic; + this.moment = moment; - this.elliptic = require('elliptic'); - this.moment = require('moment'); + } + //#region GetMethods... - //#region Calculate application hash + public GetChargingPool: GetChargingPoolFunc = (Id: string) => { - switch (process.platform) + for (var chargingPool of this.chargingPools) { - - case "win32": - this.calcSHA512Hash('Chargy Transparenzsoftware.exe', hash => this.exe_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); - this.calcSHA512Hash(this.path.join('resources', 'app.asar'), hash => this.app_asar_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); - this.calcSHA512Hash(this.path.join('resources', 'electron.asar'), hash => this.electron_asar_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); - break; - - case "linux": - case "freebsd": - case "openbsd": - this.calcSHA512Hash('/opt/Chargy\ Transparenzsoftware/chargytransparenzsoftware', hash => this.exe_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); - this.calcSHA512Hash('/opt/Chargy\ Transparenzsoftware/resources/app.asar', hash => this.app_asar_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); - this.calcSHA512Hash('/opt/Chargy\ Transparenzsoftware/resources/electron.asar', hash => this.electron_asar_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); - break; - - case "darwin": - this.calcSHA512Hash('/Applications/Chargy\ Transparenzsoftware.app/Contents/MacOS/Chargy Transparenzsoftware', hash => this.exe_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); - this.calcSHA512Hash('/Applications/Chargy\ Transparenzsoftware.app/Contents/Resources/app.asar', hash => this.app_asar_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); - this.calcSHA512Hash('/Applications/Chargy\ Transparenzsoftware.app/Contents/Resources/electron.asar', hash => this.electron_asar_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); - break; - - default: - document.getElementById('chargySHA512')!.children[1].innerHTML = "Kann nicht berechnet werden!" - break; - - } - - //#endregion - - //#region Get list of Chargy versions from GitHub - - let GetListOfVersionsFromGitHub = new XMLHttpRequest(); - GetListOfVersionsFromGitHub.open("GET", - "https://raw.githubusercontent.com/OpenChargingCloud/ChargyDesktopApp/master/versions/versions.json", - true); - - GetListOfVersionsFromGitHub.onreadystatechange = () => { - - // 0 UNSENT | 1 OPENED | 2 HEADERS_RECEIVED | 3 LOADING | 4 DONE - if (GetListOfVersionsFromGitHub.readyState == 4) { - if (GetListOfVersionsFromGitHub.status == 200) { // HTTP 200 - OK - - try { - - var versionsDiv = this.updateAvailableScreen.querySelector("#versions") as HTMLDivElement; - if (versionsDiv != null) - { - - this.currentAppInfos = JSON.parse(GetListOfVersionsFromGitHub.responseText) as IVersions; - - for (let version of this.currentAppInfos.versions) - { - - var versionElements = version.version.split('.'); - - //#region Find current version package - - if (versionElements[0] == this.appVersion[0] && versionElements[1] == this.appVersion[1] && versionElements[2] == this.appVersion[2]) - { - - this.currentVersionInfos = version; - - if (this.currentVersionInfos.packages && this.currentVersionInfos.packages.length > 0) - { - for (let _package of this.currentVersionInfos.packages) - { - if (_package.isInstaller == null && - (_package.platform === process.platform || - (_package.platforms != null && Array.isArray(_package.platforms) && _package.platforms.indexOf(process.platform) > -1))) - { - this.currentPackage = _package; - } - } - } - - } - - //#endregion - - //#region Find newer/updated version - - else if (versionElements[0] > this.appVersion[0] || - (versionElements[0] >= this.appVersion[0] && versionElements[1] > this.appVersion[1]) || - (versionElements[0] >= this.appVersion[0] && versionElements[1] >= this.appVersion[1] && versionElements[2] > this.appVersion[2])) - { - - this.updateAvailableButton.style.display = "block"; - - let versionDiv = versionsDiv.appendChild(document.createElement('div')); - versionDiv.className = "version"; - - let headlineDiv = versionDiv.appendChild(document.createElement('div')); - headlineDiv.className = "headline"; - - let versionnumberDiv = headlineDiv.appendChild(document.createElement('div')); - versionnumberDiv.className = "versionnumber"; - versionnumberDiv.innerHTML = "Version " + version.version; - - let releaseDateDiv = headlineDiv.appendChild(document.createElement('div')); - releaseDateDiv.className = "releaseDate"; - releaseDateDiv.innerHTML = parseUTC(version.releaseDate).format("ll"); - - let descriptionDiv = versionDiv.appendChild(document.createElement('div')); - descriptionDiv.className = "description"; - descriptionDiv.innerHTML = version.description["de"]; - - let tagsDiv = versionDiv.appendChild(document.createElement('div')); - tagsDiv.className = "tags"; - - for (let tag of version.tags) - { - let tagDiv = tagsDiv.appendChild(document.createElement('div')); - tagDiv.className = "tag"; - tagDiv.innerHTML = tag; - } - - let packagesDiv = versionDiv.appendChild(document.createElement('div')); - packagesDiv.className = "packages"; - - for (let versionpackage of version.packages) - { - - let packageDiv = packagesDiv.appendChild(document.createElement('div')); - packageDiv.className = "package"; - - let nameDiv = packageDiv.appendChild(document.createElement('div')); - nameDiv.className = "name"; - nameDiv.innerHTML = versionpackage.name; - - if (versionpackage.description && - versionpackage.description["de"]) - { - let descriptionDiv = packageDiv.appendChild(document.createElement('div')); - descriptionDiv.className = "description"; - descriptionDiv.innerHTML = versionpackage.description["de"]; - } - - if (versionpackage.additionalInfo && - versionpackage.additionalInfo["de"]) - { - let additionalInfoDiv = packageDiv.appendChild(document.createElement('div')); - additionalInfoDiv.className = "additionalInfo"; - additionalInfoDiv.innerHTML = versionpackage.additionalInfo["de"]; - } - - - let cryptoHashesDiv = packageDiv.appendChild(document.createElement('div')); - cryptoHashesDiv.className = "cryptoHashes"; - - for (let cryptoHash in versionpackage.cryptoHashes) - { - - let cryptoHashDiv = cryptoHashesDiv.appendChild(document.createElement('div')); - cryptoHashDiv.className = "cryptoHash"; - - let cryptoHashNameDiv = cryptoHashDiv.appendChild(document.createElement('div')); - cryptoHashNameDiv.className = "name"; - cryptoHashNameDiv.innerHTML = cryptoHash; - - let value = versionpackage.cryptoHashes[cryptoHash].replace(/\s+/g, ''); - - if (value.startsWith("0x")) - value = value.substring(2); - - let cryptoHashValueDiv = cryptoHashDiv.appendChild(document.createElement('div')); - cryptoHashValueDiv.className = "value"; - cryptoHashValueDiv.innerHTML = value.match(/.{1,8}/g).join(" "); - - } - - - let signaturesTextDiv = packageDiv.appendChild(document.createElement('div')); - signaturesTextDiv.className = "signaturesText"; - signaturesTextDiv.innerHTML = "Die Authentizität diese Software wurde durch folgende digitale Signaturen bestätigt"; - - let signaturesDiv = packageDiv.appendChild(document.createElement('div')); - signaturesDiv.className = "signatures"; - - for (let signature of versionpackage.signatures) - { - - let signatureDiv = signaturesDiv.appendChild(document.createElement('div')); - signatureDiv.className = "signature"; - - let signatureCheckDiv = signatureDiv.appendChild(document.createElement('div')); - signatureCheckDiv.className = "signatureCheck"; - signatureCheckDiv.innerHTML = ""; - - let authorDiv = signatureDiv.appendChild(document.createElement('div')); - authorDiv.className = "signer"; - authorDiv.innerHTML = signature.signer; - - } - - - if (versionpackage.downloadURLs) - { - - let downloadURLsTextDiv = packageDiv.appendChild(document.createElement('div')); - downloadURLsTextDiv.className = "downloadURLsText"; - downloadURLsTextDiv.innerHTML = "Diese Software kann über folgende Weblinks runtergeladen werden"; - - let downloadURLsDiv = packageDiv.appendChild(document.createElement('div')); - downloadURLsDiv.className = "downloadURLs"; - - for (let downloadURLName in versionpackage.downloadURLs) - { - let downloadURLDiv = downloadURLsDiv.appendChild(document.createElement('div')); - downloadURLDiv.className = "downloadURL"; - downloadURLDiv.innerHTML = "" + downloadURLName + ""; - } - - } - - } - - } - - //#endregion - - } - - } - - } - catch (exception) - { - // Just do nothing! - } - - } - } - - } - - GetListOfVersionsFromGitHub.send(); - - //#endregion - - - this.updateAvailableScreen = document.getElementById('updateAvailableScreen'); - this.aboutScreenDiv = document.getElementById('aboutScreen'); - this.chargySHA512Div = document.getElementById('chargySHA512'); - this.chargingSessionScreenDiv = document.getElementById('chargingSessionScreen'); - this.evseTarifInfosDiv = document.getElementById('evseTarifInfos'); - this.inputInfosDiv = document.getElementById('inputInfos'); - this.errorTextDiv = document.getElementById('errorText'); - - - //#region Handle Drag'n'Drop of charge transparency files - - this.input = document.getElementById('input'); - - this.input.addEventListener('dragenter', (event: DragEvent) => { - event.preventDefault(); - (event.currentTarget as HTMLDivElement)!.classList.add('over'); - }, false); - - this.input.addEventListener('dragover', (event: DragEvent) => { - event.stopPropagation(); - event.preventDefault(); - event.dataTransfer!.dropEffect = 'copy'; - (event.currentTarget as HTMLDivElement)!.classList.add('over'); - }, false); - - this.input.addEventListener('dragleave', (event: DragEvent) => { - (event.currentTarget as HTMLDivElement)!.classList.remove('over'); - }, false); - - this.input.addEventListener('drop', (event: DragEvent) => { - event.stopPropagation(); - event.preventDefault(); - (event.currentTarget as HTMLDivElement)!.classList.remove('over'); - this.readAndParseFile(event.dataTransfer!.files[0]); - }, false); - - //#endregion - - //#region Handle the 'Update available'-button - - this.updateAvailableButton = document.getElementById('updateAvailableButton'); - this.updateAvailableButton.onclick = (ev: MouseEvent) => { - this.updateAvailableScreen.style.display = "block"; - this.inputInfosDiv.style.display = "none"; - this.aboutScreenDiv.style.display = "none"; - this.chargingSessionScreenDiv.style.display = "none"; - this.backButtonDiv.style.display = "block"; + if (chargingPool["@id"] === Id) + return chargingPool; } - //#endregion - - //#region Handle the 'About'-button - - this.aboutButton = document.getElementById('aboutButton'); - this.aboutButton.onclick = (ev: MouseEvent) => { - - this.updateAvailableScreen.style.display = "none"; - this.inputInfosDiv.style.display = "none"; - this.aboutScreenDiv.style.display = "block"; - this.chargingSessionScreenDiv.style.display = "none"; - this.backButtonDiv.style.display = "block"; - - //#region Calculate the over-all application hash - - if (this.complete_hash == "" && - this.exe_hash != "" && - this.app_asar_hash != "" && - this.electron_asar_hash != "") - { - - var sha512hash = this.crypt.createHash('sha512'); - sha512hash.update(this.exe_hash); - sha512hash.update(this.app_asar_hash); - sha512hash.update(this.electron_asar_hash); - - this.complete_hash = this.chargySHA512Div.children[1].innerHTML = sha512hash.digest('hex').match(/.{1,8}/g).join(" "); - - //#region Check application hash signatures, when given... - - if (this.currentAppInfos != null && - this.currentVersionInfos != null && - this.currentPackage != null) - { - - let sigHeadDiv = this.chargySHA512Div.children[2]; - let signaturesDiv = this.chargySHA512Div.children[3]; - - // Bad hash value - if (this.currentPackage.cryptoHashes.SHA512.replace("0x", "") !== this.complete_hash) - sigHeadDiv.innerHTML = " Ungültiger Hashwert!"; - - // At least the same hash value... - else - { - - if (this.currentPackage.signatures == null || this.currentPackage.signatures.length == 0) - { - sigHeadDiv.innerHTML = " Gültiger Hashwert"; - } - - // Some crypto signatures found... - else - { - - sigHeadDiv.innerHTML = "Bestätigt durch..."; - - for (let signature of this.currentPackage.signatures) - { - let signatureDiv = signaturesDiv.appendChild(document.createElement('div')); - signatureDiv.innerHTML = this.CheckApplicationHashSignature(this.currentAppInfos, - this.currentVersionInfos, - this.currentPackage, - signature); - } - - } - - } - - } - - //#endregion - - } - - //#endregion - - } + return null; - //#endregion + } - //#region Handle the 'fullScreen'-button + public GetChargingStation: GetChargingStationFunc = (Id: string) => { - var d = document as any; - this.fullScreenButton = document.getElementById('fullScreenButton'); - this.fullScreenButton.onclick = (ev: MouseEvent) => { - if (d.fullScreen || d.mozFullScreen || d.webkitIsFullScreen) - { - this.overlayDiv.classList.remove("fullScreen"); - closeFullscreen(); - this.fullScreenButton.innerHTML = ''; - } - else - { - this.overlayDiv.classList.add("fullScreen"); - openFullscreen(); - this.fullScreenButton.innerHTML = ''; - } + for (var chargingStation of this.chargingStations) + { + if (chargingStation["@id"] === Id) + return chargingStation; } - //#endregion - - //#region Handle the 'Overlay Ok'-button - - this.overlayDiv = document.getElementById('overlay'); - this.overlayOkButton = document.getElementById('overlayOkButton'); - this.overlayOkButton.onclick = (ev: MouseEvent) => { - this.overlayDiv.style.display = 'none'; - } + return null; - //#endregion + } - //#region Handle the 'fileInput'-button + public GetEVSE: GetEVSEFunc = (Id: string) => { - this.fileInputButton = document.getElementById('fileInputButton'); - this.fileInput = document.getElementById('fileInput'); - this.fileInputButton.onclick = (ev: MouseEvent) => { - this.fileInput.value = ''; - this.fileInput.click(); - } - //@ts-ignokjre - this.fileInput.onchange = (ev: Event) => { - var files = ev!.target!["files"]; - if (files != null) - this.readAndParseFile(files[0]); + for (var evse of this.EVSEs) + { + if (evse["@id"] === Id) + return evse; } - //#endregion - - //#region Handle the 'paste'-button - - var pasteButton = document.getElementById('pasteButton'); - pasteButton.onclick = (ev: MouseEvent) => { - (navigator as any).clipboard.readText().then((clipText: string) => { - try - { - this.detectContentFormat(clipText); - } - catch (exception) { - this.doGlobalError("Fehlerhafter Transparenzdatensatz!", exception); - } - }); - } + return null; - //#endregion + } - //#region The Issue tracker + public GetMeter: GetMeterFunc = (Id: string) => { - var issueTracker = document.getElementById('issueTracker'); - var showIssueTrackerButton = document.getElementById('showIssueTracker'); - showIssueTrackerButton.onclick = function (this: GlobalEventHandlers, ev: MouseEvent) { - issueTracker.style.display = 'block'; - privacyStatement.style.display = "none"; - issueTrackerText.scrollTop = 0; - } - var newIssueForm = document.getElementById('newIssueForm'); - var issueTrackerText = document.getElementById('issueTrackerText'); - var privacyStatement = document.getElementById('privacyStatement'); - var showPrivacyStatement = document.getElementById('showPrivacyStatement'); - showPrivacyStatement.onclick = function(this: GlobalEventHandlers, ev: MouseEvent) { - ev.preventDefault(); - privacyStatement.style.display = "block"; - issueTrackerText.scrollTop = issueTrackerText.scrollHeight; - } - var privacyStatementAccepted = document.getElementById('privacyStatementAccepted'); - privacyStatementAccepted.onchange = function(this: GlobalEventHandlers, ev: Event) { - sendIssueButton.disabled = !privacyStatementAccepted.checked; + for (var meter of this.meters) + { + if (meter["@id"] === Id) + return meter; } - var sendIssueButton = document.getElementById('sendIssueButton'); - sendIssueButton.onclick = (ev: MouseEvent) => { // function (this: GlobalEventHandlers, ev: MouseEvent) { - - ev.preventDefault(); - - try - { - - //#region Collect issue data... - - var data = {}; - - data["timestamp"] = new Date().toISOString(); - data["chargyVersion"] = this.appVersion.join("."); - data["platform"] = process.platform; - - data["invalidCTR"] = (newIssueForm.querySelector("#invalidCTR") as HTMLInputElement).checked; - data["InvalidStationData"] = (newIssueForm.querySelector("#InvalidStationData") as HTMLInputElement).checked; - data["invalidSignatures"] = (newIssueForm.querySelector("#invalidSignatures") as HTMLInputElement).checked; - data["invalidCertificates"] = (newIssueForm.querySelector("#invalidCertificates") as HTMLInputElement).checked; - data["transparencenySoftwareBug"] = (newIssueForm.querySelector("#transparencenySoftwareBug") as HTMLInputElement).checked; - data["DSGVO"] = (newIssueForm.querySelector("#DSGVO") as HTMLInputElement).checked; - data["BITV"] = (newIssueForm.querySelector("#BITV") as HTMLInputElement).checked; - - data["description"] = (newIssueForm.querySelector("#issueDescription") as HTMLTextAreaElement).value; - - if ((newIssueForm.querySelector("#includeCTR") as HTMLSelectElement).value == "yes") - data["chargeTransparencyRecord"] = this.currentCTR; - - data["name"] = (newIssueForm.querySelector("#issueName") as HTMLInputElement).value; - data["phone"] = (newIssueForm.querySelector("#issuePhone") as HTMLInputElement).value; - data["eMail"] = (newIssueForm.querySelector("#issueEMail") as HTMLInputElement).value; - - //#endregion - //#region Send issue to API - - let sendIssue = new XMLHttpRequest(); - - sendIssue.open("ADD", - "https://chargeit.charging.cloud/chargy/issues", - true); - sendIssue.setRequestHeader('Content-type', 'application/json'); - - sendIssue.onreadystatechange = function () { - - // 0 UNSENT | 1 OPENED | 2 HEADERS_RECEIVED | 3 LOADING | 4 DONE - if (this.readyState == 4) { - - if (this.status == 201) { // HTTP 201 - Created - issueTracker.style.display = 'none'; - // Show thank you for your issue - } - - else - { - alert("Leider ist ein Fehler bei der Datenübertragung aufgetreten. Bitte probieren Sie es erneut..."); - } - - } + return null; - } + } - sendIssue.send(JSON.stringify(data)); + //#endregion - //#endregion + async sha256(message: string|DataView) { - } - catch (exception) - { - // Just do nothing! - } + let hashBuffer = null; - } - var issueBackButton = document.getElementById('issueBackButton'); - issueBackButton.onclick = function (this: GlobalEventHandlers, ev: MouseEvent) { - issueTracker.style.display = 'none'; - } + if (typeof message === 'string') + hashBuffer = await crypto.subtle.digest('SHA-256', Buffer.from(message, 'utf8')); + else + hashBuffer = await crypto.subtle.digest('SHA-256', message); - //#endregion + const hashArray = Array.from(new Uint8Array(hashBuffer)); // convert hash to byte array + const hashHex = hashArray.map(b => ('00' + b.toString(16)).slice(-2)).join('').toLowerCase(); // convert bytes to hex string - //#region Handle the 'Back'-button + return hashHex; - this.backButtonDiv = document.getElementById('backButtonDiv'); - this.backButtonDiv.onclick = (ev: MouseEvent) => { + } - this.updateAvailableScreen.style.display = "none"; - this.inputInfosDiv.style.display = 'flex'; - this.aboutScreenDiv.style.display = "none"; - this.chargingSessionScreenDiv.style.display = "none"; - this.backButtonDiv.style.display = "none"; - this.fileInput.value = ""; - this.evseTarifInfosDiv.innerHTML = ""; + //#region CheckMeterPublicKeySignature(...) - // Clear the map and reset zoom bounds... - while(this.markers.length > 0) - map.removeLayer(this.markers.pop()); + public async CheckMeterPublicKeySignature(chargingStation: any, + evse: any, + meter: any, + publicKey: any, + signature: any): Promise + { - this.minlat = +1000; - this.maxlat = -1000; - this.minlng = +1000; - this.maxlng = -1000; + // For now: Do not enforce this feature! + if (chargingStation == null || evse == null || meter == null || publicKey == null || signature == null) + return "";// " Unbekannter Public Key!"; - } + try + { - //#endregion + var toCheck = { - //#region Modify external links to be opened in the external web browser + "@id": chargingStation["@id"], + "description": chargingStation.description, + "geoLocation": chargingStation.geoLocation, + "address": chargingStation.address, + "softwareVersion": chargingStation.softwareVersion, - var shell = require('electron').shell; - let linkButtons = document.getElementsByClassName('linkButton') as HTMLCollectionOf; - for (var i = 0; i < linkButtons.length; i++) { + "EVSE": { + "@id": evse["@id"], + "description": evse.description, + "sockets": evse.sockets, - let linkButton = linkButtons[i]; - - linkButton.onclick = function (this: GlobalEventHandlers, ev: MouseEvent) { - ev.preventDefault(); - var link = linkButton.attributes["href"].nodeValue; - if (link.startsWith("http://") || link.startsWith("https://")) { - shell.openExternal(link); - } - } - - } - - //#endregion - - //#region Handle 'Open this file with Chargy'-events... - - // Note: The following is synchronous, therefore must be at the end of the file... - - // Windows and Linux - var cliArguments = require('electron').remote.process.argv; - if (cliArguments.length >= 2) - this.readFileFromDisk(cliArguments[1]); - - // Mac OS X - first file to open - this.readFileFromDisk(this.ipcRenderer.sendSync('get-chargy-filename')); - - // Mac OS X - when app is running - this.ipcRenderer.on('send-chargy-filename', (event:any, filename:string) => { - this.readFileFromDisk(filename); - }); - - //#endregion - - } - - - //#region calcSHA512Hash(...) - - private calcSHA512Hash(filename: string, - OnSuccess: { (hash: string): any; }, - OnFailed: { (errorMessage: string): any; }) - { - - const fs = require('original-fs'); - let sha512 = require('electron').remote. - require('crypto').createHash('sha512'); - let stream = fs.createReadStream(filename); - - stream.on('data', function(data: any) { - sha512.update(data) - }) - - stream.on('error', function() { - OnFailed("File not found!"); - }) - - stream.on('end', function() { - OnSuccess(sha512.digest('hex')); - }) - - } - - //#endregion - - //#region CheckApplicationHashSignature(...) - - private CheckApplicationHashSignature(app: any, - version: any, - _package: any, - signature: any): string - { - - if (app == null || version == null || _package == null || signature == null) - return "Ungültige Signatur!"; - - try { - - var toCheck = { - "name": app.name, - "description": app.description, - - "version": { - "version": this.appVersion.join("."), - "releaseDate": version.releaseDate, - "description": version.description, - "tags": version.tags, - - "package": { - "name": _package.name, - "description": _package.description, - "additionalInfo": _package.additonalInfo, - "platform": _package.platform, - "isInstaller": _package.isInstaller, // Note: Might be null! Keep null values! - "cryptoHashValue": this.complete_hash, - - "signature": { - "signer": signature.signer, - "timestamp": signature.timestamp, - "comment": signature.comment, - "algorithm": signature.algorithm, - "format": signature.format - } - - } - - } - - }; - - //ToDo: Checking the timestamp might be usefull! - - var Input = JSON.stringify(toCheck); - var sha256value = this.crypt.createHash('sha256'). - update(Input, 'utf8'). - digest('hex'); - - var result = new this.elliptic.ec('secp256k1'). - keyFromPublic(signature.publicKey, 'hex'). - verify (sha256value, - signature.signature); - - if (result) - return "" + signature.signer; - - - } - catch (exception) - { } - - return "" + signature.signer; - - } - - //#endregion - - //#region CheckMeterPublicKeySignature(...) - - private async CheckMeterPublicKeySignature(chargingStation: any, - evse: any, - meter: any, - publicKey: any, - signature: any): Promise - { - - // For now: Do not enforce this feature! - if (chargingStation == null || evse == null || meter == null || publicKey == null || signature == null) - return "";// " Unbekannter Public Key!"; - - try { - - var toCheck = { - - "@id": chargingStation["@id"], - "description": chargingStation.description, - "geoLocation": chargingStation.geoLocation, - "address": chargingStation.address, - "softwareVersion": chargingStation.softwareVersion, - - "EVSE": { - "@id": evse["@id"], - "description": evse.description, - "sockets": evse.sockets, - - "meter": { - "@id": meter["@id"], - "vendor": meter.vendor, - "model": meter.model, - "firmwareVersion": meter.firmwareVersion, - "signatureFormat": meter.signatureFormat, + "meter": { + "@id": meter["@id"], + "vendor": meter.vendor, + "model": meter.model, + "firmwareVersion": meter.firmwareVersion, + "signatureFormat": meter.signatureFormat, "publicKey": { "algorithm": publicKey.algorithm, "format": publicKey.format, - "value": publicKey.value, - - "signature": { - "signer": signature.signer, - "timestamp": signature.timestamp, - "comment": signature.comment, - "algorithm": signature.algorithm, - "format": signature.format - } - - } - - } - - } - - }; - - //ToDo: Checking the timestamp might be usefull! - - var Input = JSON.stringify(toCheck); - var sha256value = this.crypt.createHash('sha256'). - update(Input, 'utf8'). - digest('hex'); - - var result = new this.elliptic.ec('secp256k1'). - keyFromPublic(signature.publicKey, 'hex'). - verify (sha256value, - signature.signature); - - - if (result) - return "" + signature.signer; - - - } - catch (exception) - { } - - return "" + signature.signer; - - } - - //#endregion - - - //#region GetMethods... - - private GetChargingPool: GetChargingPoolFunc = (Id: string) => { - - for (var chargingPool of this.chargingPools) - { - if (chargingPool["@id"] === Id) - return chargingPool; - } - - return null; - - } - - private GetChargingStation: GetChargingStationFunc = (Id: string) => { - - for (var chargingStation of this.chargingStations) - { - if (chargingStation["@id"] === Id) - return chargingStation; - } - - return null; - - } - - private GetEVSE: GetEVSEFunc = (Id: string) => { - - for (var evse of this.EVSEs) - { - if (evse["@id"] === Id) - return evse; - } - - return null; - - } - - private GetMeter: GetMeterFunc = (Id: string) => { - - for (var meter of this.meters) - { - if (meter["@id"] === Id) - return meter; - } - - return null; - - } - - //#endregion - - - //#region detectContentFormat - - private async checkSessionCrypto(chargingSession: IChargingSession) - { - - var result = await this.verifySessionCryptoDetails(chargingSession); - - //#region Add marker to map - - var redMarker = leaflet.AwesomeMarkers.icon({ - prefix: 'fa', - icon: 'exclamation', - markerColor: 'red', - iconColor: '#ecc8c3' - }); - - var greenMarker = leaflet.AwesomeMarkers.icon({ - prefix: 'fa', - icon: 'charging-station', - markerColor: 'green', - iconColor: '#c2ec8e' - }); - - var markerIcon = redMarker; - - switch (result.status) - { - - case SessionVerificationResult.UnknownSessionFormat: - case SessionVerificationResult.PublicKeyNotFound: - case SessionVerificationResult.InvalidPublicKey: - case SessionVerificationResult.InvalidSignature: - markerIcon = redMarker; - break; - - case SessionVerificationResult.ValidSignature: - markerIcon = greenMarker; - break; - - - default: - markerIcon = redMarker; - - } - - var geoLocation = null; - - if (chargingSession.chargingPool != null && - chargingSession.chargingPool.geoLocation != null) - { - geoLocation = chargingSession.chargingPool.geoLocation; - } - - if (chargingSession.chargingStation != null && - chargingSession.chargingStation.geoLocation != null) - { - geoLocation = chargingSession.chargingStation.geoLocation; - } - - if (geoLocation != null) - { - - var marker = leaflet.marker([geoLocation.lat, geoLocation.lng], { icon: markerIcon }).addTo(map); - this.markers.push(marker); - - if (this.minlat > geoLocation.lat) - this.minlat = geoLocation.lat; - - if (this.maxlat < geoLocation.lat) - this.maxlat = geoLocation.lat; - - if (this.minlng > geoLocation.lng) - this.minlng = geoLocation.lng; - - if (this.maxlng < geoLocation.lng) - this.maxlng = geoLocation.lng; - - switch (result.status) - { - - case SessionVerificationResult.UnknownSessionFormat: - case SessionVerificationResult.PublicKeyNotFound: - case SessionVerificationResult.InvalidPublicKey: - case SessionVerificationResult.InvalidSignature: - marker.bindPopup("Ungültiger Ladevorgang!"); - break; - - case SessionVerificationResult.ValidSignature: - marker.bindPopup("Gültiger Ladevorgang!"); - break; - - - default: - markerIcon = redMarker; - - } - - } - - //#endregion - - switch (result.status) - { - - case SessionVerificationResult.UnknownSessionFormat: - case SessionVerificationResult.PublicKeyNotFound: - case SessionVerificationResult.InvalidPublicKey: - case SessionVerificationResult.InvalidSignature: - return ' Ungültig'; - - case SessionVerificationResult.ValidSignature: - return ' Gültig'; - - - default: - return ' Ungültig'; - - } - - } - - //#endregion - - //#region processChargeTransparencyRecord(CTR) - - private async processChargeTransparencyRecord(CTR: IChargeTransparencyRecord) - { - - this.chargingStationOperators = []; - this.chargingPools = []; - this.chargingStations = []; - this.EVSEs = []; - this.meters = []; - this.eMobilityProviders = []; - this.mediationServices = []; - this.chargingSessions = []; - - this.currentCTR = {} as IChargeTransparencyRecord; - - //#region Prepare View - - this.chargingSessionScreenDiv.style.display = "flex"; - this.chargingSessionScreenDiv.innerText = ""; - this.backButtonDiv.style.display = "block"; - - //#endregion - - //#region Show CTR infos - - if (CTR.description) { - let descriptionDiv = this.chargingSessionScreenDiv.appendChild(document.createElement('div')); - descriptionDiv.id = "description"; - descriptionDiv.innerText = firstValue(CTR.description); - } - - if (CTR.begin) { - let beginDiv = this.chargingSessionScreenDiv.appendChild(document.createElement('div')); - beginDiv.id = "begin"; - beginDiv.className = "defi"; - beginDiv.innerHTML = "von " + parseUTC(CTR.begin).format('dddd, D. MMMM YYYY'); - } - - if (CTR.end) { - let endDiv = this.chargingSessionScreenDiv.appendChild(document.createElement('div')); - endDiv.id = "begin"; - endDiv.className = "defi"; - endDiv.innerHTML = "bis " + parseUTC(CTR.end).format('dddd, D. MMMM YYYY'); - } - - //#endregion - - //#region Show contract infos - - if (CTR.contract) - { - } - - //#endregion - - //#region Process CSOs, pools, stations, ... - - if (CTR.chargingStationOperators) - { - - for (var chargingStationOperator of CTR.chargingStationOperators) - { - - this.chargingStationOperators.push(chargingStationOperator); - - if (chargingStationOperator.chargingPools) { - - for (var chargingPool of chargingStationOperator.chargingPools) - { - - this.chargingPools.push(chargingPool); - - if (chargingPool.chargingStations) - { - - for (var chargingStation of chargingPool.chargingStations) - { - - this.chargingStations.push(chargingStation); - - if (chargingStation.EVSEs) { - - for (var EVSE of chargingStation.EVSEs) - { - - EVSE.chargingStation = chargingStation; - EVSE.chargingStationId = chargingStation["@id"]; - - this.EVSEs.push(EVSE); - - if (EVSE.meters) { - - for (var meter of EVSE.meters) - { - - meter.EVSE = EVSE; - meter.EVSEId = EVSE["@id"]; - - meter.chargingStation = chargingStation; - meter.chargingStationId = chargingStation["@id"]; - - this.meters.push(meter); - - } - - } - - } - - } - - } - - } - - } - - } - - if (chargingStationOperator.chargingStations) - { - - for (var chargingStation of chargingStationOperator.chargingStations) - { - - this.chargingStations.push(chargingStation); - - if (chargingStation.EVSEs) { - - for (var EVSE of chargingStation.EVSEs) - { - - EVSE.chargingStation = chargingStation; - EVSE.chargingStationId = chargingStation["@id"]; - - this.EVSEs.push(EVSE); - - if (EVSE.meters) { - - for (var meter of EVSE.meters) - { - - meter.EVSE = EVSE; - meter.EVSEId = EVSE["@id"]; - - meter.chargingStation = chargingStation; - meter.chargingStationId = chargingStation["@id"]; - - this.meters.push(meter); - - } - - } - - } - - } - - } - - } - - if (chargingStationOperator.EVSEs) { - - for (var EVSE of chargingStationOperator.EVSEs) - { - - // EVSE.chargingStation = chargingStation; - // EVSE.chargingStationId = chargingStation["@id"]; - - this.EVSEs.push(EVSE); - - if (EVSE.meters) { - - for (var meter of EVSE.meters) - { - - meter.EVSE = EVSE; - meter.EVSEId = EVSE["@id"]; - - // meter.chargingStation = chargingStation; - // meter.chargingStationId = chargingStation["@id"]; - - this.meters.push(meter); - - } - - } - - } - - } - - } - - } - - if (CTR.chargingPools) { - - for (var chargingPool of CTR.chargingPools) - { - - this.chargingPools.push(chargingPool); - - if (chargingPool.chargingStations) - { - - for (var chargingStation of chargingPool.chargingStations) - { - - this.chargingStations.push(chargingStation); - - if (chargingStation.EVSEs) { - - for (var EVSE of chargingStation.EVSEs) - { - - EVSE.chargingStation = chargingStation; - EVSE.chargingStationId = chargingStation["@id"]; - - this.EVSEs.push(EVSE); - - } - - } - - } - - } - - } - - } - - if (CTR.chargingStations) { - - for (var chargingStation of CTR.chargingStations) - { - - this.chargingStations.push(chargingStation); - - if (chargingStation.EVSEs) { - - for (var EVSE of chargingStation.EVSEs) - { - - EVSE.chargingStation = chargingStation; - EVSE.chargingStationId = chargingStation["@id"]; - - this.EVSEs.push(EVSE); - - if (EVSE.meters) { - - for (var meter of EVSE.meters) - { - - meter.EVSE = EVSE; - meter.EVSEId = EVSE["@id"]; - - meter.chargingStation = chargingStation; - meter.chargingStationId = chargingStation["@id"]; - - this.meters.push(meter); - - } - - } - - } - - } - - if (chargingStation.meters) { - - for (var meter of chargingStation.meters) - { - - meter.chargingStation = chargingStation; - meter.chargingStationId = chargingStation["@id"]; - - this.meters.push(meter); - - } - - } - - } - - } - - //#endregion - - - //#region Show all charging sessions... - - if (CTR.chargingSessions) { - - let chargingSessionsDiv = this.chargingSessionScreenDiv.appendChild(document.createElement('div')); - chargingSessionsDiv.id = "chargingSessions"; - - for (let chargingSession of CTR.chargingSessions) - { - - let chargingSessionDiv = CreateDiv(chargingSessionsDiv, "chargingSessions"); - chargingSession.GUI = chargingSessionDiv; - chargingSessionDiv.onclick = (ev: MouseEvent) => { - - //#region Highlight the selected charging session... - - var AllChargingSessionsDivs = document.getElementsByClassName("chargingSessions"); - for(var i=0; i Nov - replace(";", ".") + // 14; -> 14. - " Uhr"; - - if (chargingSession.end) - { - - var endUTC = parseUTC(chargingSession.end); - var duration = this.moment.duration(endUTC - beginUTC); - - dateDiv.innerHTML += " - " + - (Math.floor(duration.asDays()) > 0 ? endUTC.format("dddd") + " " : "") + - endUTC.format('HH:mm:ss') + - " Uhr"; - - } - - } - - } - catch (exception) - { - console.log("Could not show session time infos of charging session '" + chargingSession["@id"] + "':" + exception); - } - - //#endregion - - var tableDiv = chargingSessionDiv.appendChild(document.createElement('div')); - tableDiv.className = "table"; - - //#region Show energy infos - - try { - - var productInfoDiv = tableDiv.appendChild(document.createElement('div')); - productInfoDiv.className = "productInfos"; - - var productIconDiv = productInfoDiv.appendChild(document.createElement('div')); - productIconDiv.className = "icon"; - productIconDiv.innerHTML = ''; - - var productDiv = productInfoDiv.appendChild(document.createElement('div')); - productDiv.className = "text"; - productDiv.innerHTML = chargingSession.product != null ? chargingSession.product["@id"] + "
" : ""; - - productDiv.innerHTML += "Ladedauer "; - if (Math.floor(duration.asDays()) > 1) productDiv.innerHTML += duration.days() + " Tage " + duration.hours() + " Std. " + duration.minutes() + " Min. " + duration.seconds() + " Sek."; - else if (Math.floor(duration.asDays()) > 0) productDiv.innerHTML += duration.days() + " Tag " + duration.hours() + " Std. " + duration.minutes() + " Min. " + duration.seconds() + " Sek."; - else if (Math.floor(duration.asHours()) > 0) productDiv.innerHTML += duration.hours() + " Std. " + duration.minutes() + " Min. " + duration.seconds() + " Sek."; - else if (Math.floor(duration.asMinutes()) > 0) productDiv.innerHTML += duration.minutes() + " Min. " + duration.seconds() + " Sek."; - else if (Math.floor(duration.asSeconds()) > 0) productDiv.innerHTML += duration.seconds(); - - if (chargingSession.measurements) - { - for (var measurement of chargingSession.measurements) - { - // - if (measurement.values && measurement.values.length > 0) - { - - var first = measurement.values[0].value; - var last = measurement.values[measurement.values.length-1].value; - var amount = parseFloat(((last - first) * Math.pow(10, measurement.scale)).toFixed(10)); - - switch (measurement.unit) - { - - case "KILO_WATT_HOURS": - break; - - // "WATT_HOURS" - default: - amount = parseFloat((amount / 1000).toFixed(10)); - break; - - } - - productDiv.innerHTML += "
" + translateMeasurementName(measurement.name) + " " + amount.toString() + " kWh (" + measurement.values.length + " Messwerte)"; - - } - - } - } - - } - catch (exception) - { - console.log("Could not show energy infos of charging session '" + chargingSession["@id"] + "':" + exception); - } - - //#endregion - - //#region Show authorization start/stop information - - try { - - if (chargingSession.authorizationStart != null) - { - - var authorizationStartDiv = tableDiv.appendChild(document.createElement('div')); - authorizationStartDiv.className = "authorizationStart"; - - var authorizationStartIconDiv = authorizationStartDiv.appendChild(document.createElement('div')); - authorizationStartIconDiv.className = "icon"; - switch (chargingSession.authorizationStart.type) - { - - case "cryptoKey": - authorizationStartIconDiv.innerHTML = ''; - break; - - case "eMAId": - case "EVCOId": - authorizationStartIconDiv.innerHTML = ''; - break; - - default: - authorizationStartIconDiv.innerHTML = ''; - break; - - } - - var authorizationStartIdDiv = authorizationStartDiv.appendChild(document.createElement('div')); - authorizationStartIdDiv.className = "id"; - authorizationStartIdDiv.innerHTML = chargingSession.authorizationStart["@id"]; - - } - - if (chargingSession.authorizationStop != null) - { - - var authorizationStopDiv = tableDiv.appendChild(document.createElement('div')); - authorizationStopDiv.className = "authorizationStop"; - - var authorizationStopIconDiv = authorizationStopDiv.appendChild(document.createElement('div')); - authorizationStopIconDiv.className = "icon"; - switch (chargingSession.authorizationStop.type) - { - - case "cryptoKey": - authorizationStopIconDiv.innerHTML = ''; - break; - - case "eMAId": - case "EVCOId": - authorizationStopIconDiv.innerHTML = ''; - break; - - default: - authorizationStopIconDiv.innerHTML = ''; - break; - - } - - var authorizationStopIdDiv = authorizationStopDiv.appendChild(document.createElement('div')); - authorizationStopIdDiv.className = "id"; - authorizationStopIdDiv.innerHTML = chargingSession.authorizationStop["@id"]; - - } - - } catch (exception) - { - console.log("Could not show authorization start/stop infos of charging session '" + chargingSession["@id"] + "':" + exception); - } - - //#endregion - - //#region Show location infos... - - try - { - - if (chargingSession.EVSEId || chargingSession.EVSE || - chargingSession.chargingStationId || chargingSession.chargingStation || - chargingSession.chargingPoolId || chargingSession.chargingPool) { - - var address:IAddress|null = null; - - var locationInfoDiv = tableDiv.appendChild(document.createElement('div')); - locationInfoDiv.className = "locationInfos"; - - var locationIconDiv = locationInfoDiv.appendChild(document.createElement('div')); - locationIconDiv.className = "icon"; - locationIconDiv.innerHTML = ''; - - var locationDiv = locationInfoDiv.appendChild(document.createElement('div')); - locationDiv.classList.add("text"); - - if (chargingSession.EVSEId || chargingSession.EVSE) { - - if (chargingSession.EVSE == null || typeof chargingSession.EVSE !== 'object') - chargingSession.EVSE = this.GetEVSE(chargingSession.EVSEId); - - locationDiv.classList.add("EVSE"); - locationDiv.innerHTML = (chargingSession.EVSE != null && chargingSession.EVSE.description != null - ? firstValue(chargingSession.EVSE.description) + "
" - : "") + - (chargingSession.EVSEId != null - ? chargingSession.EVSEId - : chargingSession.EVSE!["@id"]); - - if (chargingSession.EVSE) - { - - chargingSession.chargingStation = chargingSession.EVSE.chargingStation; - chargingSession.chargingStationId = chargingSession.EVSE.chargingStationId; - - if (chargingSession.EVSE.chargingStation) - { - chargingSession.chargingPool = chargingSession.EVSE.chargingStation.chargingPool; - chargingSession.chargingPoolId = chargingSession.EVSE.chargingStation.chargingPoolId; - address = chargingSession.EVSE.chargingStation.address; - } - - } - - } - - else if (chargingSession.chargingStationId || chargingSession.chargingStation) { - - if (chargingSession.chargingStation == null || typeof chargingSession.chargingStation !== 'object') - chargingSession.chargingStation = this.GetChargingStation(chargingSession.chargingStationId); - - if (chargingSession.chargingStation != null) - { - - locationDiv.classList.add("chargingStation"); - locationDiv.innerHTML = (chargingSession.chargingStation != null && chargingSession.chargingStation.description != null - ? firstValue(chargingSession.chargingStation.description) + "
" - : "") + - (chargingSession.chargingStationId != null - ? chargingSession.chargingStationId - : chargingSession.chargingStation["@id"]); - - chargingSession.chargingPool = chargingSession.chargingStation.chargingPool; - chargingSession.chargingPoolId = chargingSession.chargingStation.chargingPoolId; - - address = chargingSession.chargingStation.address; - - } - else - locationInfoDiv.remove(); - - } - - else if (chargingSession.chargingPoolId || chargingSession.chargingPool) { - - if (chargingSession.chargingPool == null || typeof chargingSession.chargingPool !== 'object') - chargingSession.chargingPool = this.GetChargingPool(chargingSession.chargingPoolId); - - if (chargingSession.chargingPool != null) - { - - locationDiv.classList.add("chargingPool"); - locationDiv.innerHTML = (chargingSession.chargingPool != null && chargingSession.chargingPool.description != null - ? firstValue(chargingSession.chargingPool.description) + "
" - : "") + - (chargingSession.chargingPoolId != null - ? chargingSession.chargingPoolId - : chargingSession.chargingPool["@id"]); - - address = this.GetChargingPool(chargingSession.chargingPool["@id"])!.address; - - } - else - locationInfoDiv.remove(); - - } - - if (address != null) - locationDiv.innerHTML += "
" + - (address.street != null ? " " + address.street : "") + - (address.houseNumber != null ? " " + address.houseNumber : "") + - - (address.postalCode != null || address.city != null ? "," : "") + - (address.postalCode != null ? " " + address.postalCode : "") + - (address.city != null ? " " + address.city : ""); - - } - - } catch (exception) - { - console.log("Could not show location infos of charging session '" + chargingSession["@id"] + "':" + exception); - } - - //#endregion - - //#region Show verification status - - let verificationStatusDiv = chargingSessionDiv.appendChild(document.createElement('div')); - verificationStatusDiv.className = "verificationStatus"; - verificationStatusDiv.innerHTML = await this.checkSessionCrypto(chargingSession); - - //#endregion - - - this.chargingSessions.push(chargingSession); - - } - - // If there is only one charging session show its details at once... - if (this.chargingSessions.length == 1) - this.chargingSessions[0].GUI.click(); - - map.fitBounds([[this.minlat, this.minlng], [this.maxlat, this.maxlng]], - { padding: [40, 40] }); - - } - - //#endregion - - this.currentCTR = CTR; - - } - - //#endregion - - //#region tryToParseAnonymousFormat(...) - - // e.g. the current chargeIT mobility does not provide any format identifiers - private async tryToParseAnonymousFormat(SomeJSON: { signedMeterValues: any[]; placeInfo: any; }) : Promise - { - - if (!Array.isArray(SomeJSON)) - { - - var signedMeterValues = SomeJSON.signedMeterValues as Array; - var placeInfo = SomeJSON.placeInfo; - - // { - // "placeInfo": { - // "evseId": "DE*BDO*74778874*1", - // "address": { - // "street": "Musterstraße 12", - // "zipCode": "74789", - // "town": "Stadt" - // }, - // "geoLocation": { - // "lat": 12.3774, - // "lon": 1.3774 - // } - // }, - // - // "signedMeterValues":[{ - // "timestamp": 1550533285, - // "meterInfo": { - // "firmwareVersion": "123", - // "publicKey": "08A56CF3B51DABA44F38607BB884F62FB8BE84B4EF39D09624AB9E0910354398590DC59A5B40F43FE68A9F416F65EC76", - // "publicKeySignatures": [], - // "meterId": "0901454D4800007F9F3E", - // "type": "eHZ IW8E EMH", - // "manufacturer": "EMH" - // }, - // "transactionId": "1546933282548:-7209653592192971037:1", - // "contract": { - // "type": "RFID_TAG_ID", - // "timestampLocal": { - // "timestamp": 1546933284, - // "localOffset": 60, - // "seasonOffset": 0 - // }, - // "timestamp": 1550533284, - // "id": "235DD5BB" - // }, - // "measurementId": "00000007", - // "measuredValue": { - // "timestampLocal": { - // "timestamp": 1546933285, - // "localOffset": 60, - // "seasonOffset": 0 - // }, - // "value": "60077", - // "unit": "WATT_HOUR", - // "scale": -1, - // "valueType": "Integer64", - // "unitEncoded": 30 - // }, - // "measurand": { - // "id": "0100011100FF", - // "name": "ENERGY_TOTAL" - // }, - // "additionalInfo": { - // "indexes": { - // "timer": 1730275, - // "logBook": "0004" - // }, - // "status": "88" - // }, - // "signature": "13493BBB43DA1E26C88B21ADB7AA53A7AE4FC7F6F6B916E67AD3E168421D180F021D6DD458612C53FF167781892A9DF3" - // }] - // - // } - - try { - - let CTRArray = []; - - for (let i = 0; i < signedMeterValues.length; i++) { - - let signedMeterValue = signedMeterValues[i]; - - let _timestamp = signedMeterValue["timestamp"] as number; - if (_timestamp == null || typeof _timestamp !== 'number') - throw "Missing or invalid timestamp[" + i + "]!" - let timestamp = parseUTC(_timestamp); - - let _meterInfo = signedMeterValue["meterInfo"] as string; - if (_meterInfo == null || typeof _meterInfo !== 'object') - throw "Missing or invalid meterInfo[" + i + "]!" - - let _meterInfo_firmwareVersion = _meterInfo["firmwareVersion"] as string; - if (_meterInfo_firmwareVersion == null || typeof _meterInfo_firmwareVersion !== 'string') - throw "Missing or invalid meterInfo firmwareVersion[" + i + "]!" - - let _meterInfo_publicKey = _meterInfo["publicKey"] as string; - if (_meterInfo_publicKey == null || typeof _meterInfo_publicKey !== 'string') - throw "Missing or invalid meterInfo publicKey[" + i + "]!" - - let _meterInfo_publicKeySignatures = _meterInfo["publicKeySignatures"]; - - let _meterInfo_meterId = _meterInfo["meterId"] as string; - if (_meterInfo_meterId == null || typeof _meterInfo_meterId !== 'string') - throw "Missing or invalid meterInfo meterId[" + i + "]!" - - let _meterInfo_type = _meterInfo["type"] as string; - if (_meterInfo_type == null || typeof _meterInfo_type !== 'string') - throw "Missing or invalid meterInfo type[" + i + "]!" - - let _meterInfo_manufacturer = _meterInfo["manufacturer"] as string; - if (_meterInfo_manufacturer == null || typeof _meterInfo_manufacturer !== 'string') - throw "Missing or invalid meterInfo manufacturer[" + i + "]!" - - - let _transactionId = signedMeterValue["transactionId"] as string; - if (_transactionId == null || typeof _transactionId !== 'string') - throw "Missing or invalid transactionId[" + i + "]!" - - - let _contract = signedMeterValue["contract"]; - if (_contract == null || typeof _contract !== 'object') - throw "Missing or invalid contract[" + i + "]!" - - let _contract_type = _contract["type"] as string; - if (_contract_type == null || typeof _contract_type !== 'string') - throw "Missing or invalid contract type[" + i + "]!" - - let _contract_timestampLocal = _contract["timestampLocal"]; - if (_contract_timestampLocal == null || typeof _contract_timestampLocal !== 'object') - throw "Missing or invalid contract timestampLocal[" + i + "]!" - - let _contract_timestampLocal_timestamp = _contract_timestampLocal["timestamp"] as number; - if (_contract_timestampLocal_timestamp == null || typeof _contract_timestampLocal_timestamp !== 'number') - throw "Missing or invalid contract timestampLocal timestamp[" + i + "]!" - - let _contract_timestampLocal_localOffset = _contract_timestampLocal["localOffset"] as number; - if (_contract_timestampLocal_localOffset == null || typeof _contract_timestampLocal_localOffset !== 'number') - throw "Missing or invalid contract timestampLocal localOffset[" + i + "]!" - - let _contract_timestampLocal_seasonOffset = _contract_timestampLocal["seasonOffset"] as number; - if (_contract_timestampLocal_seasonOffset == null || typeof _contract_timestampLocal_seasonOffset !== 'number') - throw "Missing or invalid contract timestampLocal seasonOffset[" + i + "]!" - - let _contract_timestamp = _contract["timestamp"] as number; - if (_contract_timestamp == null || typeof _contract_timestamp !== 'number') - throw "Missing or invalid contract timestamp[" + i + "]!" - - let _contract_id = _contract["id"] as string; - if (_contract_id == null || typeof _contract_id !== 'string') - throw "Missing or invalid contract type[" + i + "]!" - - - let _measurementId = signedMeterValue["measurementId"] as string; - if (_measurementId == null || typeof _measurementId !== 'string') - throw "Missing or invalid measurementId[" + i + "]!" - - - let _measuredValue = signedMeterValue["measuredValue"]; - if (_measuredValue == null || typeof _measuredValue !== 'object') - throw "Missing or invalid measuredValue[" + i + "]!" - - let _measuredValue_timestampLocal = _measuredValue["timestampLocal"]; - if (_measuredValue_timestampLocal == null || typeof _measuredValue_timestampLocal !== 'object') - throw "Missing or invalid measuredValue timestampLocal[" + i + "]!" - - let _measuredValue_timestampLocal_timestamp = _measuredValue_timestampLocal["timestamp"] as number; - if (_measuredValue_timestampLocal_timestamp == null || typeof _measuredValue_timestampLocal_timestamp !== 'number') - throw "Missing or invalid measuredValue timestampLocal timestamp[" + i + "]!" - - let _measuredValue_timestampLocal_localOffset = _measuredValue_timestampLocal["localOffset"] as number; - if (_measuredValue_timestampLocal_localOffset == null || typeof _measuredValue_timestampLocal_localOffset !== 'number') - throw "Missing or invalid measuredValue timestampLocal localOffset[" + i + "]!" - - let _measuredValue_timestampLocal_seasonOffset = _measuredValue_timestampLocal["seasonOffset"] as number; - if (_measuredValue_timestampLocal_seasonOffset == null || typeof _measuredValue_timestampLocal_seasonOffset !== 'number') - throw "Missing or invalid measuredValue timestampLocal seasonOffset[" + i + "]!" - - let _measuredValue_value = _measuredValue["value"] as string; - if (_measuredValue_value == null || typeof _measuredValue_value !== 'string') - throw "Missing or invalid measuredValue value[" + i + "]!" - - let _measuredValue_unit = _measuredValue["unit"] as string; - if (_measuredValue_unit == null || typeof _measuredValue_unit !== 'string') - throw "Missing or invalid measuredValue unit[" + i + "]!" - - let _measuredValue_scale = _measuredValue["scale"] as number; - if (_measuredValue_scale == null || typeof _measuredValue_scale !== 'number') - throw "Missing or invalid measuredValue scale[" + i + "]!" - - let _measuredValue_valueType = _measuredValue["valueType"] as string; - if (_measuredValue_valueType == null || typeof _measuredValue_valueType !== 'string') - throw "Missing or invalid measuredValue valueType[" + i + "]!" - - let _measuredValue_unitEncoded = _measuredValue["unitEncoded"] as number; - if (_measuredValue_unitEncoded == null || typeof _measuredValue_unitEncoded !== 'number') - throw "Missing or invalid measuredValue unitEncoded[" + i + "]!" - - - let _measurand = signedMeterValue["measurand"]; - if (_measurand == null || typeof _measurand !== 'object') - throw "Missing or invalid measurand[" + i + "]!" - - let _measurand_id = _measurand["id"] as string; - if (_measurand_id == null || typeof _measurand_id !== 'string') - throw "Missing or invalid measurand id[" + i + "]!" - - let _measurand_name = _measurand["name"] as string; - if (_measurand_name == null || typeof _measurand_name !== 'string') - throw "Missing or invalid measurand name[" + i + "]!" - - - let _additionalInfo = signedMeterValue["additionalInfo"]; - if (_additionalInfo == null || typeof _additionalInfo !== 'object') - throw "Missing or invalid additionalInfo[" + i + "]!" - - let _additionalInfo_indexes = _additionalInfo["indexes"]; - if (_additionalInfo_indexes == null || typeof _additionalInfo_indexes !== 'object') - throw "Missing or invalid additionalInfo indexes[" + i + "]!" - - let _additionalInfo_indexes_timer = _additionalInfo_indexes["timer"] as number; - if (_additionalInfo_indexes_timer == null || typeof _additionalInfo_indexes_timer !== 'number') - throw "Missing or invalid additionalInfo indexes timer[" + i + "]!" - - let _additionalInfo_indexes_logBook = _additionalInfo_indexes["logBook"] as string; - if (_additionalInfo_indexes_logBook == null || typeof _additionalInfo_indexes_logBook !== 'string') - throw "Missing or invalid additionalInfo indexes logBook[" + i + "]!" - - let _additionalInfo_status = _additionalInfo["status"] as string; - if (_additionalInfo_status == null || typeof _additionalInfo_status !== 'string') - throw "Missing or invalid additionalInfo status[" + i + "]!" - - - let _chargePoint = signedMeterValue["chargePoint"]; - if (_chargePoint == null || typeof _chargePoint !== 'object') - throw "Missing or invalid chargePoint[" + i + "] information!" - - let _chargePointSoftwareVersion = _chargePoint["softwareVersion"]; - if (_chargePointSoftwareVersion == null || typeof _chargePointSoftwareVersion !== 'string') - throw "Missing or invalid chargePoint softwareVersion[" + i + "]!" - - - let _signature = signedMeterValue["signature"] as string; - if (_signature == null || typeof _signature !== 'string') - throw "Missing or invalid signature[" + i + "]!" - - - //let aaa = moment.unix(_contract_timestampLocal_timestamp).utc(); - - CTRArray.push({ - "timestamp": _timestamp, - "meterInfo": { - "firmwareVersion": _meterInfo_firmwareVersion, - "publicKey": _meterInfo_publicKey, - "publicKeySignatures": _meterInfo_publicKeySignatures, - "meterId": _meterInfo_meterId, - "type": _meterInfo_type, - "manufacturer": _meterInfo_manufacturer - }, - "transactionId": _transactionId, - "contract": { - "type": _contract_type, - "timestampLocal": { - "timestamp": _contract_timestampLocal_timestamp, - "localOffset": _contract_timestampLocal_localOffset, - "seasonOffset": _contract_timestampLocal_seasonOffset - }, - "timestamp": _contract_timestamp, - "id": _contract_id - }, - "measurementId": _measurementId, - "measuredValue": { - "timestampLocal": { - "timestamp": _measuredValue_timestampLocal_timestamp, - "localOffset": _measuredValue_timestampLocal_localOffset, - "seasonOffset": _measuredValue_timestampLocal_seasonOffset - }, - "value": _measuredValue_value, - "unit": _measuredValue_unit, - "scale": _measuredValue_scale, - "valueType": _measuredValue_valueType, - "unitEncoded": _measuredValue_unitEncoded - }, - "measurand": { - "id": _measurand_id, - "name": _measurand_name - }, - "additionalInfo": { - "indexes": { - "timer": _additionalInfo_indexes_timer, - "logBook": _additionalInfo_indexes_logBook - }, - "status": _additionalInfo_status - }, - "chargePoint": { - "softwareVersion": _chargePointSoftwareVersion - }, - "signature": _signature - }); - - } - - - var evseId = placeInfo["evseId"] as string; - if (evseId == null || typeof evseId !== 'string') - throw "Missing or invalid EVSE Id!" - - - var address = placeInfo["address"]; - if (address == null) - throw "Missing or invalid address!" - - var address_street = address["street"]; - if (address_street == null || typeof address_street !== 'string') - throw "Missing or invalid address street!" - - var address_zipCode = address["zipCode"]; - if (address_zipCode == null || typeof address_zipCode !== 'string') - throw "Missing or invalid address zipCode!" - - var address_town = address["town"]; - if (address_town == null || typeof address_town !== 'string') - throw "Missing or invalid address town!" - - - var geoLocation = placeInfo["geoLocation"]; - if (geoLocation == null) - throw "Missing or invalid geoLocation!" - - var geoLocation_lat = geoLocation["lat"]; - if (geoLocation_lat == null || typeof geoLocation_lat !== 'number') - throw "Missing or invalid geoLocation latitude!" - - var geoLocation_lon = geoLocation["lon"]; - if (geoLocation_lon == null || typeof geoLocation_lon !== 'number') - throw "Missing or invalid geoLocation longitude!" - - - var n = CTRArray.length-1; - var _CTR: any = { //IChargeTransparencyRecord = { - - "@id": CTRArray[n]["transactionId"], - "@context": "https://open.charging.cloud/contexts/CTR+json", - - "begin": this.moment.unix(CTRArray[0]["measuredValue"]["timestampLocal"]["timestamp"]).utc().format(), - "end": this.moment.unix(CTRArray[n]["measuredValue"]["timestampLocal"]["timestamp"]).utc().format(), - - "description": { - "de": "Alle Ladevorgänge" - }, - - "contract": { - "@id": CTRArray[0]["contract"]["id"], - "type": CTRArray[0]["contract"]["type"], - "username": "", - "email": "" - }, - - "chargingStationOperators": [ - { - - "@id": "chargeITmobilityCSO", - "eMobilityIds": [ "DE*BDO", "DE*LVF", "+49*822" ], - "description": { - "de": "chargeIT mobility GmbH - Charging Station Operator Services" - }, - - "contact": { - "email": "info@chargeit-mobility.com", - "web": "https://www.chargeit-mobility.com", - "logoUrl": "http://www.chargeit-mobility.com/fileadmin/BELECTRIC_Drive/templates/pics/chargeit_logo_408x70.png", - "publicKeys": [ - { - "algorithm": "secp192r1", - "format": "DER", - "value": "042313b9e469612b4ca06981bfdecb226e234632b01d84b6a814f63a114b7762c34ddce2e6853395b7a0f87275f63ffe3c", - "signatures": [ - { - "keyId": "...", - "algorithm": "secp192r1", - "format": "DER", - "value": "????" - } - ] - }, - { - "algorithm": "secp256k1", - "format": "DER", - "value": "04a8ff0d82107922522e004a167cc658f0eef408c5020f98e7a2615be326e61852666877335f4f8d9a0a756c26f0c9fb3f401431416abb5317cc0f5d714d3026fe", - "signatures": [ ] - } - ] - }, - - "support": { - "hotline": "+49 9321 / 2680 - 700", - "email": "service@chargeit-mobility.com", - "web": "https://cso.chargeit.charging.cloud/issues" - // "mediationServices": [ "GraphDefined Mediation" ], - // "publicKeys": [ - // { - // "algorithm": "secp256k1", - // "format": "DER", - // "value": "04a8ff0d82107922522e004a167cc658f0eef408c5020f98e7a2615be326e61852666877335f4f8d9a0a756c26f0c9fb3f401431416abb5317cc0f5d714d3026fe", - // "signatures": [ ] - // } - // ] - }, - - "privacy": { - "contact": "Dr. iur. Christian Borchers, datenschutz süd GmbH", - "email": "datenschutz@chargeit-mobility.com", - "web": "http://www.chargeit-mobility.com/de/datenschutz/" - // "publicKeys": [ - // { - // "algorithm": "secp256k1", - // "format": "DER", - // "value": "04a8ff0d82107922522e004a167cc658f0eef408c5020f98e7a2615be326e61852666877335f4f8d9a0a756c26f0c9fb3f401431416abb5317cc0f5d714d3026fe", - // "signatures": [ ] - // } - // ] - }, - - "chargingStations": [ - { - "@id": evseId.substring(0, evseId.lastIndexOf("*")), - // "description": { - // "de": "GraphDefined Charging Station - CI-Tests Pool 3 / Station A" - // }, - "firmwareVersion": CTRArray[0]["chargePoint"]["softwareVersion"], - "geoLocation": { "lat": geoLocation_lat, "lng": geoLocation_lon }, - "address": { - "street": address_street, - "postalCode": address_zipCode, - "city": address_town - }, - "EVSEs": [ - { - "@id": evseId, - // "description": { - // "de": "GraphDefined EVSE - CI-Tests Pool 3 / Station A / EVSE 1" - // }, - "sockets": [ { } ], - "meters": [ - { - "@id": CTRArray[0]["meterInfo"]["meterId"], - "vendor": CTRArray[0]["meterInfo"]["manufacturer"], - "vendorURL": "http://www.emh-metering.de", - "model": CTRArray[0]["meterInfo"]["type"], - "hardwareVersion": "1.0", - "firmwareVersion": CTRArray[0]["meterInfo"]["firmwareVersion"], - "signatureFormat": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/EMHCrypt01", - "publicKeys": [ - { - "algorithm": "secp192r1", - "format": "DER", - "value": CTRArray[0]["meterInfo"]["publicKey"].startsWith("04") - ? CTRArray[0]["meterInfo"]["publicKey"] - : "04" + CTRArray[0]["meterInfo"]["publicKey"], - "signatures": CTRArray[0]["meterInfo"]["publicKeySignatures"] - } - ] - } - ] - } - ] - } - ] - - } - ], - - "chargingSessions": [ - - { - - "@id": CTRArray[n]["transactionId"], - "@context": "https://open.charging.cloud/contexts/SessionSignatureFormats/EMHCrypt01+json", - "begin": this.moment.unix(CTRArray[0]["measuredValue"]["timestampLocal"]["timestamp"]).utc().format(), - "end": this.moment.unix(CTRArray[n]["measuredValue"]["timestampLocal"]["timestamp"]).utc().format(), - "EVSEId": evseId, - - "authorizationStart": { - "@id": CTRArray[0]["contract"]["id"], - "type": CTRArray[0]["contract"]["type"], - "timestamp": this.moment.unix(CTRArray[0]["contract"]["timestampLocal"]["timestamp"]).utc().utcOffset( - CTRArray[0]["contract"]["timestampLocal"]["localOffset"] + - CTRArray[0]["contract"]["timestampLocal"]["seasonOffset"]).format(), - }, - - "signatureInfos": { - "hash": "SHA512", - "hashTruncation": "24", - "algorithm": "ECC", - "curve": "secp192r1", - "format": "rs" - }, - - "measurements": [ - - { - - "energyMeterId": CTRArray[0]["meterInfo"]["meterId"], - "@context": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/EMHCrypt01+json", - "name": CTRArray[0]["measurand"]["name"], - "obis": CTRArray[0]["measurand"]["id"], - "unit": CTRArray[0]["measuredValue"]["unit"], - "unitEncoded": CTRArray[0]["measuredValue"]["unitEncoded"], - "valueType": CTRArray[0]["measuredValue"]["valueType"], - "scale": CTRArray[0]["measuredValue"]["scale"], - - "signatureInfos": { - "hash": "SHA512", - "hashTruncation": "24", - "algorithm": "ECC", - "curve": "secp192r1", - "format": "rs" - }, - - "values": [ ] - - } - - ] - - } - - ] - - }; - - for (var _measurement of CTRArray) - { - - _CTR["chargingSessions"][0]["measurements"][0]["values"].push( - - { - "timestamp": this.moment.unix(_measurement["measuredValue"]["timestampLocal"]["timestamp"]).utc().utcOffset( - _measurement["measuredValue"]["timestampLocal"]["localOffset"] + - _measurement["measuredValue"]["timestampLocal"]["seasonOffset"]).format(), - "value": _measurement["measuredValue"]["value"], - "infoStatus": _measurement["additionalInfo"]["status"], - "secondsIndex": _measurement["additionalInfo"]["indexes"]["timer"], - "paginationId": _measurement["measurementId"], - "logBookIndex": _measurement["additionalInfo"]["indexes"]["logBook"], - "signatures": [ - { - "r": _measurement["signature"].substring(0, 48), - "s": _measurement["signature"].substring(48) - } - ] - } - - ); - - } - - await this.processChargeTransparencyRecord(_CTR); - return true; - - } - catch (exception) - { - console.log("chargeIT mobility legacy CTR format: " + exception); - } - - } - - return false; - - } - - //#endregion - - //#region tryToParseTransparenzSoftwareXML(XMLDocument) - - private async tryToParseTransparenzSoftwareXML(XMLDocument: Document) : Promise - { - - const base32Decode = require('base32-decode'); - - // The SAFE transparency software v1.0 does not understand its own - // XML namespace. Therefore we have to guess the format. - - try - { - - let commonFormat = ""; - let commonPublicKey = ""; - let signedValues:string[] = []; - - let values = XMLDocument.querySelectorAll("values"); - if (values.length == 1) - { - let valueList = values[0].querySelectorAll("value"); - if (valueList.length >= 1) - { - for (let i=0; i... - - var signedData = valueList[i].querySelector("signedData"); - if (signedData != null) - { - - signedDataEncoding = signedData.attributes.getNamedItem("encoding") !== null ? signedData.attributes.getNamedItem("encoding")!.value.trim().toLowerCase() : ""; - signedDataFormat = signedData.attributes.getNamedItem("format") !== null ? signedData.attributes.getNamedItem("format")!.value.trim().toLowerCase() : ""; - signedDataValue = signedData.textContent !== null ? signedData.textContent.trim() : ""; - - switch (signedDataEncoding) - { - - case "": - case "plain": - signedDataValue = Buffer.from(signedDataValue, 'utf8').toString().trim(); - break; - - case "base32": - signedDataValue = Buffer.from(base32Decode(signedDataValue, 'RFC4648')).toString().trim(); - break; - - case "base64": - signedDataValue = Buffer.from(signedDataValue, 'base64').toString().trim(); - break; - - case "hex": - signedDataValue = Buffer.from(signedDataValue, 'hex').toString().trim(); - break; - - default: - throw "Unkown signed data encoding within the given SAFE XML!"; - - } - - switch (signedDataFormat) - { - - case "alfen": - if (commonFormat == "") - commonFormat = "alfen"; - else if (commonFormat != "alfen") - throw "Invalid mixture of different signed data formats within the given SAFE XML!"; - break; - - case "ocmf": - if (commonFormat == "") - commonFormat = "ocmf"; - else if (commonFormat != "ocmf") - throw "Invalid mixture of different signed data formats within the given SAFE XML!"; - break; - - default: - throw "Unkown signed data formats within the given SAFE XML!"; - - } - - if (signedDataValue.isNullOrEmpty()) - throw "The signed data value within the given SAFE XML must not be empty!"; - - signedValues.push(signedDataValue); - - } - else - throw "The signed data tag within the given SAFE XML must not be empty!"; - - //#endregion - - //#region ... - - // Note: The public key is optional! - var publicKey = valueList[i].querySelector("publicKey"); - if (publicKey != null) - { - - publicKeyEncoding = publicKey.attributes.getNamedItem("encoding") !== null ? publicKey.attributes.getNamedItem("encoding")!.value.trim().toLowerCase() : ""; - publicKeyValue = publicKey.textContent !== null ? publicKey.textContent.trim() : ""; - - switch (publicKeyEncoding) - { - - case "": - case "plain": - publicKeyValue = Buffer.from(publicKeyValue, 'utf8').toString().trim(); - break; - - case "base32": - publicKeyValue = Buffer.from(base32Decode(publicKeyValue, 'RFC4648')).toString().trim(); - break; - - case "base64": - publicKeyValue = Buffer.from(publicKeyValue, 'base64').toString().trim(); - break; - - case "hex": - publicKeyValue = Buffer.from(publicKeyValue, 'hex').toString().trim(); - break; - - default: - throw "Unkown public key encoding within the given SAFE XML!"; - - } - - if (publicKeyValue.isNullOrEmpty()) - throw "The public key within the given SAFE XML must not be empty!"; - - else if (commonPublicKey == "") - commonPublicKey = publicKeyValue; - - else if (publicKeyValue != commonPublicKey) - throw "Invalid mixture of different public keys within the given SAFE XML!"; - - } - - //#endregion - - } - } - } - - switch (commonFormat) - { - - case "alfen": - return await this.tryToParseALFENFormat(signedValues); - - case "ocmf": - return await this.tryToParseOCMF(signedValues, commonPublicKey); - - } - - } - catch (exception) - { } - - return false; - - } - - //#endregion - - //#region tryToParseOCMF(OCMF, PublicKey?) - - - //#region tryToParseOCMFv0_1(OCMFData, PublicKey?) - - private async tryToParseOCMFv0_1(OCMFData: IOCMFData_v0_1, - PublicKey?: string) : Promise - { - - // { - // "FV": "0.1", - // "VI": "ABL", - // "VV": "1.4p3", - // - // "PG": "T12345", - // - // "MV": "Phoenix Contact", - // "MM": "EEM-350-D-MCB", - // "MS": "BQ27400330016", - // "MF": "1.0", - // - // "IS": "VERIFIED", - // "IF": ["RFID_PLAIN", "OCPP_RS_TLS"], - // "IT": "ISO14443", - // "ID": "1F2D3A4F5506C7", - // - // "RD": [{ - // "TM": "2018-07-24T13:22:04,000+0200 S", - // "TX": "B", - // "RV": 2935.6, - // "RI": "1-b:1.8.e", - // "RU": "kWh", - // "EI": 567, - // "ST": "G" - // }] - // } - - try - { - - let VendorInformation :string = OCMFData.VI != null ? OCMFData.VI.trim() : ""; // Some text about the manufacturer, model, variant, ... of e.g. the vendor. - let VendorVersion :string = OCMFData.VV != null ? OCMFData.VV.trim() : ""; // Software version of the vendor. - - let paging :string = OCMFData.PG != null ? OCMFData.PG.trim() : ""; // Paging, as this data might be part of a larger context. - let transactionType = OCMFTransactionTypes.undefined; - switch (paging[0].toLowerCase()) - { - - case 't': - transactionType = OCMFTransactionTypes.transaction; - break; - - case 'f': - transactionType = OCMFTransactionTypes.fiscal; - break - - } - let pagingId = paging.substring(1); - - let MeterVendor :string = OCMFData.MV != null ? OCMFData.MV.trim() : ""; // Vendor of the device, optional. - let MeterModel :string = OCMFData.MM != null ? OCMFData.MM.trim() : ""; // Model of the device, optional. - let MeterSerial :string = OCMFData.MS != null ? OCMFData.MS.trim() : ""; // Serialnumber of the device, might be optional. - let MeterFirmware :string = OCMFData.MF != null ? OCMFData.MF.trim() : ""; // Software version of the device. - - } catch (exception) - { } - - return false; - - } - - //#endregion - - //#region tryToParseOCMFv1_0(OCMFData, PublicKey?) - - private async tryToParseOCMFv1_0(OCMFValues: IOCMFData_v1_0[], - PublicKey?: string) : Promise - { - - var CTR:any = { - - "@id": "1554181214441:-1965658344385548683:2", - "@context": "https://open.charging.cloud/contexts/CTR+json", - "begin": "2019-04-02T05:00:19Z", - "end": "2019-04-02T05:13:52Z", - "description": { - "de": "Alle OCMF-Ladevorgänge" - }, - "contract": { - "@id": "8057F5AA592904", - "type": "RFID_TAG_ID", - "username": "", - "email": "" - }, - - "EVSEs": [{ - "@id": "DE*BDO*E8025334492*2", - "meters": [{ - "@id": "0901454D48000083E076", - "vendor": "EMH", - "vendorURL": "http://www.emh-metering.de", - "model": "eHZ IW8E EMH", - "hardwareVersion": "1.0", - "firmwareVersion": "123", - "signatureFormat": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/OCMFv1.0+json", - "publicKeys": [{ - "algorithm": "secp192r1", - "format": "DER", - "value": "049EA8697F5C3126E86A37295566D560DE8EA690325791C9CBA79D30612B8EA8E00908FBAD5374812D55DCC3D809C3A36C", - }] - }] - - }], - - "chargingSessions": [{ - - "@id": "1554181214441:-1965658344385548683:2", - "@context": "https://open.charging.cloud/contexts/SessionSignatureFormats/OCMFv1.0+json", - "begin": null, - "end": null, - "EVSEId": "DE*BDO*E8025334492*2", - - "authorizationStart": { - "@id": "8057F5AA592904", - "type": "RFID_TAG_ID" - }, - - "signatureInfos": { - "hash": "SHA512", - "hashTruncation": "24", - "algorithm": "ECC", - "curve": "secp192r1", - "format": "rs" - }, - - "measurements": [//{ - - // "energyMeterId": "0901454D48000083E076", - // "@context": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/OCMFv1.0+json", - // "name": "ENERGY_TOTAL", - // "obis": "0100011100FF", - // "unit": "WATT_HOUR", - // "unitEncoded": 30, - // "valueType": "Integer64", - // "scale": -1, - - // "signatureInfos": { - // "hash": "SHA512", - // "hashTruncation": "24", - // "algorithm": "ECC", - // "curve": "secp192r1", - // "format": "rs" - // }, - - // "values": [ - // { - // "timestamp": "2019-04-02T07:00:19+02:00", - // "value": "66260", - // "infoStatus": "08", - // "secondsIndex": 65058, - // "paginationId": "00000012", - // "logBookIndex": "0006", - // "signatures": [{ - // "r": "71F76A80F170F87675AAEB19606BBD298355FDA7B0851700", - // "s": "2FAD322FA073255BD8B971BD69BFF051BCA9330703172E3C" - // }] - // }, - // { - // "timestamp": "2019-04-02T07:13:52+02:00", - // "value": "67327", - // "infoStatus": "08", - // "secondsIndex": 65871, - // "paginationId": "00000013", - // "logBookIndex": "0006", - // "signatures": [{ - // "r": "6DF01D7603CB49BB76141F8E67B371351BF1F87C1F8D38AE", - // "s": "B3600A9432B8CE0A378126D4FB9D9581457651A5D208AD9E" - // }] - // } - ] - - }] - - // }] - }; - - - // [ // Not standard compliant use of an array! - // - // { - // - // "FV": "1.0", - // "GI": "SEAL AG", - // "GS": "1850006a", - // "GV": "1.34", - // - // "PG": "T9289", - // - // "MV": "Carlo Gavazzi", - // "MM": "EM340-DIN.AV2.3.X.S1.PF", - // "MS": "******240084S", - // "MF": "B4", - // - // "IS": true, - // "IL": "TRUSTED", - // "IF": ["OCCP_AUTH"], - // "IT": "ISO14443", - // "ID": "56213C05", - // - // "RD": [{ - // "TM": "2019-06-26T08:57:44,337+0000 U", - // "TX": "B", - // "RV": 268.978, - // "RI": "1-b:1.8.0", - // "RU": "kWh", - // "RT": "AC", - // "EF": "", - // "ST": "G" - // }], - // - // "__signature": { // Not standard compliant property key! - // "SD": "304402201455BF1082C9EB8B1272D7FA838EB44286B03AC96E8BAFC5E79E30C5B3E1B872022006286CA81AEE0FAFCB1D6A137FFB2C0DD014727E2AEC149F30CD5A7E87619139" - // } - // - // }, - // - // [...] - // - // ] - - try - { - - for (let OCMFData of OCMFValues) - { - - let GatewayInformation :string = OCMFData.GI != null ? OCMFData.GI.trim() : ""; // Some text about the manufacturer, model, variant, ... of e.g. the gateway. - let GatewaySerial :string = OCMFData.GS != null ? OCMFData.GS.trim() : ""; // Serial number of the gateway, might be mandatory. - let GatewayVersion :string = OCMFData.GV != null ? OCMFData.GV.trim() : ""; // Software version of the gateway. - - let paging :string = OCMFData.PG != null ? OCMFData.PG.trim() : ""; // Paging, as this data might be part of a larger context. - let TransactionType = OCMFTransactionTypes.undefined; - switch (paging[0].toLowerCase()) - { - - case 't': - TransactionType = OCMFTransactionTypes.transaction; - break; - - case 'f': - TransactionType = OCMFTransactionTypes.fiscal; - break - - } - let Pagination = paging.substring(1); - - let MeterVendor :string = OCMFData.MV != null ? OCMFData.MV.trim() : ""; // Vendor of the device, optional. - let MeterModel :string = OCMFData.MM != null ? OCMFData.MM.trim() : ""; // Model of the device, optional. - let MeterSerial :string = OCMFData.MS != null ? OCMFData.MS.trim() : ""; // Serialnumber of the device, might be optional. - let MeterFirmware :string = OCMFData.MF != null ? OCMFData.MF.trim() : ""; // Software version of the device. - - let IdentificationStatus:boolean = OCMFData.IS != null ? OCMFData.IS : false; // true, if user is assigned, else false. - let IdentificationLevel :string = OCMFData.IL != null ? OCMFData.IL.trim() : ""; // optional - let IdentificationFlags :string[] = OCMFData.IF != null ? OCMFData.IF : []; // optional - let IdentificationType :string = OCMFData.IT != null ? OCMFData.IT.trim() : ""; // The type of the authentication data. - let IdentificationData :string = OCMFData.ID != null ? OCMFData.ID.trim() : ""; // The authentication data. - - let ChargePointIdType :string = OCMFData.CT != null ? OCMFData.CT.trim() : ""; // Type of the following ChargePointId: EVSEId|ChargingStationId|... - let ChargePointId :string = OCMFData.CI != null ? OCMFData.CI.trim() : ""; // The identification of the charge point - - if (!OCMFData.RD || OCMFData.RD.length == 0) - throw "Each OCMF data set must have at least one meter reading!"; - - for (let reading of OCMFData.RD) - { - - let metaTimestamp = reading.TM.split(' '); - let Timestamp = metaTimestamp[0]; - let TimeStatus = metaTimestamp[1]; - let Transaction = reading.TX; // B|C,X|E,L,R,A,P|S|T | null - let Value = reading.RV; // typeof RV == 'number', but MUST NOT be rounded! - let OBIS = reading.RI; // OBIS-Code - let Unit = reading.RU; // Reading-Unit: kWh, ... - let CurrentType = reading.RT; // Reading-Current-Type - let ErrorFlags = reading.EF; // Error-Flags - let Status = reading.ST; // Status - - if (CTR.chargingSessions[0].begin == null) - CTR.chargingSessions[0].begin = Timestamp; - - CTR.chargingSessions[0].end = Timestamp; - - if (CTR.chargingSessions[0].measurements.length == 0) - CTR.chargingSessions[0].measurements.push({ - "energyMeterId": MeterSerial, - "@context": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/OCMFv1.0+json", - "obis": OBIS, // "1-b:1.8.0" - "unit": Unit, // "kWh" - "currentType": CurrentType, // "AC" - "values": [] - }); - - CTR.chargingSessions[0].measurements[0].values.push({ - "timestamp": Timestamp, // "2019-06-26T08:57:44,337+0000" - "timeStatus": TimeStatus, // "U" - "transaction": Transaction, // "B" - "value": Value, // 2935.6 - "transactionType": TransactionType, // "T" - "pagination": Pagination, // "9289" - "errorFlags": ErrorFlags, // "" - "status": Status, // "G" - "signatures": [{ - "value": OCMFData["__signature"]["SD"] - }] - }); - - } - - CTR.begin = CTR.chargingSessions[0].begin; - CTR.end = CTR.chargingSessions[0].end; - - CTR.chargingSessions[0].authorizationStart["@id"] = OCMFData.ID; - CTR.chargingSessions[0].authorizationStart["type"] = OCMFData.IT; - CTR.chargingSessions[0].authorizationStart["IS"] = OCMFData.IS; - CTR.chargingSessions[0].authorizationStart["IL"] = OCMFData.IL; - CTR.chargingSessions[0].authorizationStart["IF"] = OCMFData.IF; - - } - - await this.processChargeTransparencyRecord(CTR); - return true; - - } catch (exception) - { } - - return false; - - } - - //#endregion - - - private async tryToParseOCMF(OCMFValues: string|string[], - PublicKey?: string) : Promise - { - - let commonVersion = ""; - let OCMFDataList:Object[] = []; - - if (typeof OCMFValues === 'string') - OCMFValues = [ OCMFValues ]; - - for (let OCMFValue of OCMFValues) - { - - // OCMF|{"FV":"1.0","GI":"SEAL AG","GS":"1850006a","GV":"1.34","PG":"T9289","MV":"Carlo Gavazzi","MM":"EM340-DIN.AV2.3.X.S1.PF","MS":"******240084S","MF":"B4","IS":true,"IL":"TRUSTED","IF":["OCCP_AUTH"],"IT":"ISO14443","ID":"56213C05","RD":[{"TM":"2019-06-26T08:57:44,337+0000 U","TX":"B","RV":268.978,"RI":"1-b:1.8.0","RU":"kWh","RT":"AC","EF":"","ST":"G"}]}|{"SD":"304402201455BF1082C9EB8B1272D7FA838EB44286B03AC96E8BAFC5E79E30C5B3E1B872022006286CA81AEE0FAFCB1D6A137FFB2C0DD014727E2AEC149F30CD5A7E87619139"} - let OCMFSections = OCMFValue.split('|'); - - if (OCMFSections.length == 3) - { - - if (OCMFSections[0] !== "OCMF") - throw "The given data does not have a valid OCMF header!" - - let OCMFVersion = ""; - let OCMFData:Object = {}; - let OCMFSignature:Object = {}; - - try - { - - // http://hers.abl.de/SAFE/Datenformat_OCMF/Datenformat_OCMF_v1.0.pdf - // Ein Darstellungsformat, JSON-basiert (nachvollziehbar) - // Ein Übertragungsformat, JSON-basiert (vereinheitlicht) - // - // { - // "FV": "1.0", - // "GI": "SEAL AG", - // "GS": "1850006a", - // "GV": "1.34", - // - // "PG": "T9289", - // - // "MV": "Carlo Gavazzi", - // "MM": "EM340-DIN.AV2.3.X.S1.PF", - // "MS": "******240084S", - // "MF": "B4", - // - // "IS": true, - // "IL": "TRUSTED", - // "IF": ["OCCP_AUTH"], - // "IT": "ISO14443", - // "ID": "56213C05", - // - // "RD": [{ - // "TM": "2019-06-26T08:57:44,337+0000 U", - // "TX": "B", - // "RV": 268.978, - // "RI": "1-b:1.8.0", - // "RU": "kWh", - // "RT": "AC", - // "EF": "", - // "ST": "G" - // }] - // } - // { - // "SD": "304402201455BF1082C9EB8B1272D7FA838EB44286B03AC96E8BAFC5E79E30C5B3E1B872022006286CA81AEE0FAFCB1D6A137FFB2C0DD014727E2AEC149F30CD5A7E87619139" - // } - - OCMFData = JSON.parse(OCMFSections[1]); - OCMFSignature = JSON.parse(OCMFSections[2]); - OCMFVersion = OCMFData["FV"] != null ? OCMFData["FV"].trim() : ""; - - } - catch (exception) - { - throw "Could not parse the given OCMF data!"; - } - - if (OCMFData == null || OCMFData == {}) - throw "Could not parse the given OCMF data!"; - - if (OCMFSignature == null || OCMFSignature == {}) - throw "Could not parse the given OCMF signature!"; - - if (commonVersion == "") - commonVersion = OCMFVersion; - else - if (OCMFVersion != commonVersion) - "Invalid mixture of different OCMF versions within the given SAFE XML!"; - - OCMFData["__signature"] = OCMFSignature; - - OCMFDataList.push(OCMFData); - - } - - else - throw "The given data is not valid OCMF!" - - } - - if (OCMFDataList.length == 1) - throw "The given data is not valid OCMF!"; - - if (OCMFDataList.length >= 2) - { - switch (commonVersion) - { - - case "0.1": - //@ts-ignore - return await this.tryToParseOCMFv0_1(OCMFDataList as IOCMFData_v0_1[], PublicKey); - - case "1.0": - //@ts-ignore - return await this.tryToParseOCMFv1_0(OCMFDataList as IOCMFData_v1_0[], PublicKey); - - default: - throw "Unknown OCMF version!"; - - } - } - - return false; - - } - - //#endregion - - //#region tryToParseALFENFormat(Content) - - private bufferToHex (buffer: ArrayBuffer) : string { - return Array - .from (new Uint8Array (buffer)) - .map (b => b.toString (16).padStart (2, "0")) - .join (""); - } - - private async tryToParseALFENFormat(Content: string|string[]) : Promise - { - - const base32Decode = require('base32-decode'); - - // AP; - // 0; - // 3; - // AJ2J7LYMGCIWT4AHUJPPFIIVB3FGRV2JQ2HVZG2I; - // BIHEIWSHAAA2WZUZOYYDCNWTWAFACRC2I4ADGAEDQ4AAAABASMBFSAHY2JWF2AIAAEEAB7Y6ABUVEAAAAAAAAABQGQ2EMNCFIVATANRVII4DAAAAAAAAAAADAAAAABIAAAAA====; - // S27J5BHL22ZBNFYTHTK433G7VU7Z6NN4JKO5DNPE7FNMT3SM3ZJGVWJ6ZKUOKE2LK4W63JYP4E6CY===; - - // AP; - // 1; - // 3; - // AJ2J7LYMGCIWT4AHUJPPFIIVB3FGRV2JQ2HVZG2I; - // BIHEIWSHAAA2WZUZOYYDCNWTWAFACRC2I4ADGAEDQ4AAAAAQEMWVSAASAAAAAAIAAEEAB7Y6ABXFEAAAAAAAAABQGQ2EMNCFIVATANRVII4DAAAAAAAAAAADAAAAABQAAAAA====; - // MVYFHY24SFHI35DSXBSXRFMQP4OLYVO77TIQ6REROGCPWHY36AXIU4FD4W4Q2AHBZSNJXWCIRXAGS===; - - try - { + "value": publicKey.value, - var common = { - PublicKey: "", - AdapterId: "", - AdapterFWVersion: "", - AdapterFWChecksum: "", - MeterId: "", - ObisId: "", - Unit: "", - Scalar: "", - UID: "", - SessionId: 0, - dataSets: [] as any[] - }; + "signature": { + "signer": signature.signer, + "timestamp": signature.timestamp, + "comment": signature.comment, + "algorithm": signature.algorithm, + "format": signature.format + } - let signedValues:string[] = []; - if (typeof (Content) === 'string') - signedValues = Content.split(/\r\n|\r|\n/g); - else - signedValues = Content; + } - for (let i=0; i 43675944 dec - let Timestamp = DataSet.slice(34, 38); // UNIX timestamp: 91 91 3D 5C => 1547538833 => 2019-01-15T07:53:53Z - let ObisId = DataSet.slice(38, 44); // 01 00 01 08 00 ff - let Unit = DataSet.slice(44, 45); // 1e == Wh - let Scalar = DataSet.slice(45, 46); // 00 - let Value = DataSet.slice(46, 54); // 73 29 00 00 00 00 00 00 => 10611 Wh so 10,611 KWh - let UID = DataSet.slice(54, 74); // ASCII: 30 35 38 39 38 41 42 42 00 00 00 00 00 00 00 00 00 00 00 00 => UID: 05 89 8A BB - let SessionId = DataSet.slice(74, 78); // 81 01 00 00 => 385(dec) - let Paging = DataSet.slice(78, 82); // 47 02 00 00 => 583(dec) - - let _AdapterId = this.bufferToHex(AdapterId); - let _AdapterFWVersion = String.fromCharCode.apply(null, new Uint8Array(AdapterFWVersion) as any); - let _AdapterFWChecksum = this.bufferToHex(AdapterFWChecksum); - let _MeterId = this.bufferToHex(MeterId); - let _Status = this.bufferToHex(Status); - let _SecondIndex = new DataView(SecondIndex, 0).getInt32 (0, true); - let _Timestamp = new Date(new DataView(Timestamp, 0).getInt32(0, true) * 1000).toISOString(); // this.moment.unix(timestamp).utc().format(), - let _ObisId = this.bufferToHex(ObisId); - let _Unit = this.bufferToHex(Unit); - let _Scalar = this.bufferToHex(Scalar); - let _Value = new DataView(Value, 0).getBigInt64(0, true); - let _UID = String.fromCharCode.apply(null, new Uint8Array(UID) as any).replace(/\0.*$/g, ''); - let _SessionId = new DataView(SessionId, 0).getInt32 (0, true); - let _Paging = new DataView(Paging, 0).getInt32 (0, true); - - - if (common.AdapterId === "") - common.AdapterId = _AdapterId; - else if (_AdapterId !== common.AdapterId) - return false; - - if (common.AdapterFWVersion === "") - common.AdapterFWVersion = _AdapterFWVersion; - else if (_AdapterFWVersion !== common.AdapterFWVersion) - return false; - - if (common.AdapterFWChecksum === "") - common.AdapterFWChecksum = _AdapterFWChecksum; - else if (_AdapterFWChecksum !== common.AdapterFWChecksum) - return false; - - if (common.MeterId === "") - common.MeterId = _MeterId; - else if (_MeterId !== common.MeterId) - return false; - - if (common.ObisId === "") - common.ObisId = _ObisId; - else if (_ObisId !== common.ObisId) - return false; - - if (common.Unit === "") - common.Unit = _Unit; - else if (_Unit !== common.Unit) - return false; - - if (common.Scalar === "") - common.Scalar = _Scalar; - else if (_Scalar !== common.Scalar) - return false; - - if (common.UID === "") - common.UID = _UID; - else if (_UID !== common.UID) - return false; - - if (common.SessionId === 0) - common.SessionId = _SessionId; - else if (_SessionId !== common.SessionId) - return false; - - - common.dataSets.push({ - //@ts-ignore - "Status": _Status, - //@ts-ignore - "SecondIndex": _SecondIndex, - //@ts-ignore - "Timestamp": _Timestamp, - //@ts-ignore - "Value": _Value, - //@ts-ignore - "Paging": _Paging, - //@ts-ignore - "Signature": this.bufferToHex(Signature) - }); - - } - - - var n = common.dataSets.length-1; - var _CTR: any = { //IChargeTransparencyRecord = { - - "@id": common.SessionId, - "@context": "https://open.charging.cloud/contexts/CTR+json", - - "begin": common.dataSets[0]["Timestamp"], - "end": common.dataSets[n]["Timestamp"], - - "description": { - "de": "Alle Ladevorgänge" - }, - - "contract": { - "@id": common.UID, - //"type": CTRArray[0]["contract"]["type"], - "username": "", - "email": "" - }, - - // "chargingStations": [ - // { - // "@id": evseId.substring(0, evseId.lastIndexOf("*")), - // // "description": { - // // "de": "GraphDefined Charging Station - CI-Tests Pool 3 / Station A" - // // }, - // "firmwareVersion": CTRArray[0]["chargePoint"]["softwareVersion"], - // "geoLocation": { "lat": geoLocation_lat, "lng": geoLocation_lon }, - // "address": { - // "street": address_street, - // "postalCode": address_zipCode, - // "city": address_town - // }, - // "EVSEs": [ - // { - // "@id": evseId, - // // "description": { - // // "de": "GraphDefined EVSE - CI-Tests Pool 3 / Station A / EVSE 1" - // // }, - // "sockets": [ { } ], - // "meters": [ - // { - // "@id": CTRArray[0]["meterInfo"]["meterId"], - // "vendor": CTRArray[0]["meterInfo"]["manufacturer"], - // "vendorURL": "http://www.emh-metering.de", - // "model": CTRArray[0]["meterInfo"]["type"], - // "hardwareVersion": "1.0", - // "firmwareVersion": CTRArray[0]["meterInfo"]["firmwareVersion"], - // "signatureFormat": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/EMHCrypt01", - // "publicKeys": [ - // { - // "algorithm": "secp192r1", - // "format": "DER", - // "value": CTRArray[0]["meterInfo"]["publicKey"].startsWith("04") - // ? CTRArray[0]["meterInfo"]["publicKey"] - // : "04" + CTRArray[0]["meterInfo"]["publicKey"], - // "signatures": CTRArray[0]["meterInfo"]["publicKeySignatures"] - // } - // ] - // } - // ] - // } - // ] - // } - - "chargingSessions": [ - - { - - "@id": common.SessionId, - "@context": "https://open.charging.cloud/contexts/SessionSignatureFormats/AlfenCrypt03+json", - "begin": common.dataSets[0]["Timestamp"], - "end": common.dataSets[n]["Timestamp"], - // "EVSEId": evseId, - - "authorizationStart": { - "@id": common.UID, - // "type": CTRArray[0]["contract"]["type"], - // "timestamp": this.moment.unix(CTRArray[0]["contract"]["timestampLocal"]["timestamp"]).utc().utcOffset( - // CTRArray[0]["contract"]["timestampLocal"]["localOffset"] + - // CTRArray[0]["contract"]["timestampLocal"]["seasonOffset"]).format(), - }, - - // "signatureInfos": { - // "hash": "SHA256", - // "hashTruncation": "24", - // "algorithm": "ECC", - // "curve": "secp192r1", - // "format": "rs" - // }, - - "measurements": [ - - { - - "energyMeterId": common.MeterId, - "@context": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/AlfenCrypt03+json", - // "name": CTRArray[0]["measurand"]["name"], - "obis": common.ObisId, - // "unit": CTRArray[0]["measuredValue"]["unit"], - "unitEncoded": common.Unit, - // "valueType": CTRArray[0]["measuredValue"]["valueType"], - "scale": common.Scalar, - - // "signatureInfos": { - // "hash": "SHA512", - // "hashTruncation": "24", - // "algorithm": "ECC", - // "curve": "secp192r1", - // "format": "rs" - // }, - - "values": [ ] - - } - - ] - - } - - ] + //ToDo: Checking the timestamp might be usefull! - }; + var Input = JSON.stringify(toCheck); + var sha256value = await this.sha256(Input); + //this.crypt.createHash('sha256'). + // update(Input, 'utf8'). + // digest('hex'); - for (var dataSet of common.dataSets) - { + var result = new this.elliptic.ec('secp256k1'). + keyFromPublic(signature.publicKey, 'hex'). + verify (sha256value, + signature.signature); - _CTR["chargingSessions"][0]["measurements"][0]["values"].push( - - { - "timestamp": dataSet["Timestamp"], - "value": dataSet["Value"], - "infoStatus": dataSet["Status"], - "secondsIndex": dataSet["SecondIndex"], - "paginationId": dataSet["Paging"], - // "logBookIndex": _measurement["additionalInfo"]["indexes"]["logBook"], - "signatures": [ - { - "r": dataSet["Signature"].substring(0, 48), - "s": dataSet["Signature"].substring(48) - } - ] - } - - ); - } + if (result) + return "" + signature.signer; - await this.processChargeTransparencyRecord(_CTR); - return true; } catch (exception) - { } + { } - return false; + return "" + signature.signer; } //#endregion - //#region detectContentFormat(Content) - private async detectContentFormat(Content: string) { - if (Content == null) - return; - this.inputInfosDiv.style.display = 'none'; - this.errorTextDiv.style.display = 'none'; + //#region detectContentFormat(Content) + + public async detectContentFormat(Content: string): Promise { //#region Clean data + if (Content == null) + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Unknown data format!" + } + Content = Content.trim(); // Catches EFBBBF (UTF-8 BOM) because the buffer-to-string @@ -3297,6 +224,9 @@ class ChargyApplication { //#endregion + //@ts-ignore + let result: IChargeTransparencyRecord|ISessionCryptoResult = null; + //#region XML processing... if (Content.startsWith(" { - var result = await this.verifyMeasurementCryptoDetails(measurementValue); + //#region Data - switch (result.status) - { + this.chargingStationOperators = []; + this.chargingPools = []; + this.chargingStations = []; + this.EVSEs = []; + this.meters = []; + this.eMobilityProviders = []; + this.mediationServices = []; + this.chargingSessions = []; - case VerificationResult.UnknownCTRFormat: - return ' Unbekanntes Transparenzdatenformat'; + this.currentCTR = {} as IChargeTransparencyRecord; - case VerificationResult.EnergyMeterNotFound: - return ' Ungültiger Energiezähler'; + //#endregion - case VerificationResult.PublicKeyNotFound: - return ' Ungültiger Public Key'; + //ToDo: Verify @context - case VerificationResult.InvalidPublicKey: - return ' Ungültiger Public Key'; + try + { - case VerificationResult.InvalidSignature: - return ' Ungültige Signatur'; + //#region Process operators, pools, stations, evse, tariffs, ... - case VerificationResult.ValidSignature: - return ' Gültige Signatur'; + if (CTR.chargingStationOperators) + { + for (var chargingStationOperator of CTR.chargingStationOperators) + { - default: - return ' Ungültige Signatur'; + this.chargingStationOperators.push(chargingStationOperator); - } + if (chargingStationOperator.chargingPools) { - } + for (var chargingPool of chargingStationOperator.chargingPools) + { - //#endregion + this.chargingPools.push(chargingPool); - //#region showChargingSessionDetails + if (chargingPool.chargingStations) + { - private async showChargingSessionDetails(chargingSession: IChargingSession) - { + for (var chargingStation of chargingPool.chargingStations) + { - try - { + this.chargingStations.push(chargingStation); - this.evseTarifInfosDiv.innerHTML = ""; + if (chargingStation.EVSEs) { - if (chargingSession.measurements) - { - for (var measurement of chargingSession.measurements) - { + for (var EVSE of chargingStation.EVSEs) + { - measurement.chargingSession = chargingSession; + EVSE.chargingStation = chargingStation; + EVSE.chargingStationId = chargingStation["@id"]; - let headline = CreateDiv(this.evseTarifInfosDiv); - headline.id = "headline"; - headline.innerHTML = "Informationen zum Ladevorgang"; + this.EVSEs.push(EVSE); - let MeasurementInfoDiv = CreateDiv(this.evseTarifInfosDiv, "measurementInfos"); + if (EVSE.meters) { - //#region Show charging station infos + for (var meter of EVSE.meters) + { - if (measurement.chargingSession.chargingStation != null) - { + meter.EVSE = EVSE; + meter.EVSEId = EVSE["@id"]; - let ChargingStationDiv = CreateDiv(MeasurementInfoDiv, "chargingStation"); - let ChargingStationHeadline = CreateDiv(ChargingStationDiv, "chargingStationHeadline", - "Ladestation"); + meter.chargingStation = chargingStation; + meter.chargingStationId = chargingStation["@id"]; - if (measurement.chargingSession.chargingStation["@id"] != null) - { + this.meters.push(meter); - let ChargingStationIdDiv = CreateDiv(ChargingStationDiv, "chargingStationId"); + } + + } + + } + + } - let ChargingStationIdIdDiv = CreateDiv(ChargingStationIdDiv, "chargingStationIdId", - "Identifikation"); + } - let ChargingStationIdValueDiv = CreateDiv(ChargingStationIdDiv, "chargingStationIdValue", - measurement.chargingSession.chargingStation["@id"]); + } } - if (measurement.chargingSession.chargingStation.firmwareVersion != null) + } + + if (chargingStationOperator.chargingStations) + { + + for (var chargingStation of chargingStationOperator.chargingStations) { - let firmwareVersionDiv = CreateDiv(ChargingStationDiv, "firmwareVersion"); + this.chargingStations.push(chargingStation); + + if (chargingStation.EVSEs) { - let firmwareVersionIdDiv = CreateDiv(firmwareVersionDiv, "firmwareVersionId", - "Firmware-Version"); + for (var EVSE of chargingStation.EVSEs) + { + + EVSE.chargingStation = chargingStation; + EVSE.chargingStationId = chargingStation["@id"]; + + this.EVSEs.push(EVSE); + + if (EVSE.meters) { + + for (var meter of EVSE.meters) + { + + meter.EVSE = EVSE; + meter.EVSEId = EVSE["@id"]; + + meter.chargingStation = chargingStation; + meter.chargingStationId = chargingStation["@id"]; + + this.meters.push(meter); + + } + + } + + } - let firmwareVersionValueDiv = CreateDiv(firmwareVersionDiv, "firmwareVersionValue", - measurement.chargingSession.chargingStation.firmwareVersion); + } } } - //#endregion + if (chargingStationOperator.EVSEs) { - //#region Show meter infos... + for (var EVSE of chargingStationOperator.EVSEs) + { - let meterDiv = CreateDiv(MeasurementInfoDiv, "meter"); - let meterHeadline = CreateDiv(meterDiv, "meterHeadline", - "Energiezähler"); + // EVSE.chargingStation = chargingStation; + // EVSE.chargingStationId = chargingStation["@id"]; - var meter = this.GetMeter(measurement.energyMeterId); + this.EVSEs.push(EVSE); - if (meter != null) - { + if (EVSE.meters) { - let meterIdDiv = CreateDiv(meterDiv, "meterId"); + for (var meter of EVSE.meters) + { - let meterIdIdDiv = CreateDiv(meterIdDiv, "meterIdId", - "Seriennummer"); + meter.EVSE = EVSE; + meter.EVSEId = EVSE["@id"]; - let meterIdValueDiv = CreateDiv(meterIdDiv, "meterIdValue", - measurement.energyMeterId); + // meter.chargingStation = chargingStation; + // meter.chargingStationId = chargingStation["@id"]; + this.meters.push(meter); - let MeterVendorDiv = CreateDiv(meterDiv, "meterVendor"); + } - let MeterVendorIdDiv = CreateDiv(MeterVendorDiv, "meterVendorId", - "Zählerhersteller"); + } - let MeterVendorValueDiv = CreateDiv(MeterVendorDiv, "meterVendorIdValue", - meter.vendor); + } + } - let MeterModelDiv = CreateDiv(meterDiv, "meterModel"); + } - let MeterModelIdDiv = CreateDiv(MeterModelDiv, "meterModelId", - "Model"); + } - let MeterModelValueDiv = CreateDiv(MeterModelDiv, "meterModelIdValue", - meter.model); + if (CTR.chargingPools) { - } + for (var chargingPool of CTR.chargingPools) + { + + this.chargingPools.push(chargingPool); + + if (chargingPool.chargingStations) + { + + for (var chargingStation of chargingPool.chargingStations) + { + + this.chargingStations.push(chargingStation); + + if (chargingStation.EVSEs) { - //#endregion + for (var EVSE of chargingStation.EVSEs) + { - //#region ...or show meterId infos + EVSE.chargingStation = chargingStation; + EVSE.chargingStationId = chargingStation["@id"]; - else { + this.EVSEs.push(EVSE); - let meterIdDiv = CreateDiv(meterDiv, "meterId"); + } - let meterIdIdDiv = CreateDiv(meterIdDiv, "meterIdId", - "Zählerseriennummer"); + } - let meterIdValueDiv = CreateDiv(meterIdDiv, "meterIdValue", - measurement.energyMeterId); + } } - //#endregion + } + + } - //#region Show measurement infos + if (CTR.chargingStations) { - let measurementDiv = CreateDiv(meterDiv, "measurement"); + for (var chargingStation of CTR.chargingStations) + { - let MeasurementIdDiv = CreateDiv(measurementDiv, "measurementId", - "Messung"); + this.chargingStations.push(chargingStation); - let MeasurementIdValueDiv = CreateDiv(measurementDiv, "measurementIdValue", - measurement.name); + if (chargingStation.EVSEs) { + for (var EVSE of chargingStation.EVSEs) + { - let OBISDiv = CreateDiv(meterDiv, "OBIS"); + EVSE.chargingStation = chargingStation; + EVSE.chargingStationId = chargingStation["@id"]; - let OBISIdDiv = CreateDiv(OBISDiv, "OBISId", - "OBIS-Kennzahl"); + this.EVSEs.push(EVSE); - let OBISValueDiv = CreateDiv(OBISDiv, "OBISValue", - parseOBIS(measurement.obis)); + if (EVSE.meters) { - //#endregion + for (var meter of EVSE.meters) + { + meter.EVSE = EVSE; + meter.EVSEId = EVSE["@id"]; - //#region Show measurement values... + meter.chargingStation = chargingStation; + meter.chargingStationId = chargingStation["@id"]; - if (measurement.values && measurement.values.length > 0) - { + this.meters.push(meter); - let meterHeadline = CreateDiv(this.evseTarifInfosDiv, "measurementsHeadline", - "Messwerte"); - meterHeadline.id = "measurementValues-headline"; + } - let MeasurementValuesDiv = CreateDiv(this.evseTarifInfosDiv, "measurementValues"); - let previousValue = 0; + } - for (let measurementValue of measurement.values) - { + } - measurementValue.measurement = measurement; + } - let MeasurementValueDiv = CreateDiv(MeasurementValuesDiv, "measurementValue"); - MeasurementValueDiv.onclick = (ev: MouseEvent) => { - this.showMeasurementCryptoDetails(measurementValue); - }; + if (chargingStation.meters) { - var timestamp = parseUTC(measurementValue.timestamp); + for (var meter of chargingStation.meters) + { - let timestampDiv = CreateDiv(MeasurementValueDiv, "timestamp", - timestamp.format('HH:mm:ss') + " Uhr"); + meter.chargingStation = chargingStation; + meter.chargingStationId = chargingStation["@id"]; + this.meters.push(meter); - // Show energy counter value - let value2Div = CreateDiv(MeasurementValueDiv, "value1", - parseFloat((measurementValue.value * Math.pow(10, measurementValue.measurement.scale)).toFixed(10)).toString()); + } - switch (measurement.unit) - { + } - case "KILO_WATT_HOURS": - CreateDiv(MeasurementValueDiv, "unit1", "kWh"); - break; + } - // "WATT_HOURS" - default: - CreateDiv(MeasurementValueDiv, "unit1", "Wh"); - break; + } - } + //#endregion + //#region Process charging sessions... - // Show energy difference - var currentValue = measurementValue.value; + if (CTR.chargingSessions) + { + for (let chargingSession of CTR.chargingSessions) + { - switch (measurement.unit) - { + chargingSession.ctr = CTR; + chargingSession.verificationResult = await this.processChargingSession(chargingSession); - case "KILO_WATT_HOURS": - currentValue = parseFloat((currentValue * Math.pow(10, measurementValue.measurement.scale)).toFixed(10)); - break; + try + { - // "WATT_HOURS" - default: - currentValue = parseFloat((currentValue / 1000 * Math.pow(10, measurementValue.measurement.scale)).toFixed(10)); - break; + // if (chargingSession.measurements) + // { + // for (var measurement of chargingSession.measurements) + // { - } + // measurement.chargingSession = chargingSession; - let valueDiv = CreateDiv(MeasurementValueDiv, "value2", - "+" + (previousValue > 0 - ? parseFloat((currentValue - previousValue).toFixed(10)) - : "0")); + // // var meter = this.GetMeter(measurement.energyMeterId); - let unitDiv = CreateDiv(MeasurementValueDiv, "unit2", - "kWh"); + // if (measurement.values && measurement.values.length > 0) + // { + // //@ts-ignore + // let currentValue: IMeasurementValue = null; - // Show signature status - let verificationStatusDiv = CreateDiv(MeasurementValueDiv, "verificationStatus", - await this.checkMeasurementCrypto(measurementValue)); + // for (let measurementValue of measurement.values) + // { + // measurementValue.measurement = measurement; + // measurementValue.previousValue = currentValue; + // measurementValue.result = await this.verifyMeasurementCryptoDetails(measurementValue); + // currentValue = measurementValue; + // } - previousValue = currentValue; + // } - } + // } + // } } + catch (exception) + { + console.log("Could not process charging session details: " + exception); + } - //#endregion + this.chargingSessions.push(chargingSession); } } + //#endregion + + this.currentCTR = CTR; + + return CTR; + } catch (exception) - { - console.log("Could not show charging session details: " + exception); + { + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Exception occured: " + exception.message + } } } @@ -3695,19 +683,28 @@ class ChargyApplication { //#endregion - //#region verifySessionCryptoDetails + //#region processChargingSession(chargingSession) - private async verifySessionCryptoDetails(chargingSession: IChargingSession) : Promise + public async processChargingSession(chargingSession: IChargingSession) : Promise { - var result: ISessionCryptoResult = { - status: SessionVerificationResult.UnknownSessionFormat - }; + //ToDo: Verify @id exists + //ToDo: Verify @context + //ToDo: Verify begin & end + //ToDo: Verify chargingStationOperatorId => set chargingStationOperator + //ToDo: Verify chargingPoolId => set chargingPool + //ToDo: Verify chargingStationId => set chargingStation + //ToDo: Verify EVSEId => set EVSE + //ToDo: Verify meterId => set meter + //ToDo: Verify tariffId => set tariff + //ToDo: Verify measurements exists & count >= 1 if (chargingSession == null || chargingSession.measurements == null) { - return result; + return { + status: SessionVerificationResult.InvalidSessionFormat + } } switch (chargingSession["@context"]) @@ -3726,206 +723,80 @@ class ChargyApplication { return await chargingSession.method.VerifyChargingSession(chargingSession); default: - return result; - - } - - } - - //#endregion - - //#region verifyMeasurementCryptoDetails - - private async verifyMeasurementCryptoDetails(measurementValue: IMeasurementValue) : Promise - { - - var result: ICryptoResult = { - status: VerificationResult.UnknownCTRFormat - }; - - if (measurementValue == null || - measurementValue.measurement == null) - { - return result; - } - - switch (measurementValue.measurement["@context"]) - { - - case "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/GDFCrypt01+json": - measurementValue.method = new GDFCrypt01(this.GetMeter, this.CheckMeterPublicKeySignature); - return measurementValue.method.VerifyMeasurement(measurementValue); - - case "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/EMHCrypt01+json": - if (measurementValue.measurement.chargingSession.method != null) - { - - measurementValue.method = measurementValue.measurement.chargingSession.method; - - if (measurementValue.result == null) - return measurementValue.method.VerifyMeasurement(measurementValue); - - return measurementValue.result; - - } - - measurementValue.method = new EMHCrypt01(this.GetMeter, this.CheckMeterPublicKeySignature); - return measurementValue.method.VerifyMeasurement(measurementValue); - - case "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/OCMFv1.0+json": - if (measurementValue.measurement.chargingSession.method != null) - { - - measurementValue.method = measurementValue.measurement.chargingSession.method; - - if (measurementValue.result == null) - return measurementValue.method.VerifyMeasurement(measurementValue); - - return measurementValue.result; - + return { + status: SessionVerificationResult.UnknownSessionFormat } - measurementValue.method = new OCMFv1_0(this.GetMeter, this.CheckMeterPublicKeySignature); - return measurementValue.method.VerifyMeasurement(measurementValue); - - default: - return result; - } } //#endregion - //#region showMeasurementCryptoDetails - - private showMeasurementCryptoDetails(measurementValue: IMeasurementValue) : void - { - - function doError(text: String) - { - //inputInfosDiv.style.display = 'flex'; - //errorTextDiv.style.display = 'inline-block'; - introDiv.innerHTML = ' ' + text; - } - - - let introDiv = this.overlayDiv.querySelector('#intro') as HTMLDivElement; - let cryptoDataDiv = this.overlayDiv.querySelector('#cryptoData') as HTMLDivElement; - - if (measurementValue == null || - measurementValue.measurement == null) - { - doError("Unbekanntes Messdatensatzformat!"); - } - - - //#region Show data and result on overlay - - this.overlayDiv.style.display = 'block'; - - let bufferValue = this.overlayDiv.querySelector('#buffer .value') as HTMLDivElement; - let hashedBufferValue = this.overlayDiv.querySelector('#hashedBuffer .value') as HTMLDivElement; - let publicKeyValue = this.overlayDiv.querySelector('#publicKey .value') as HTMLDivElement; - let signatureExpectedValue = this.overlayDiv.querySelector('#signatureExpected .value') as HTMLDivElement; - let signatureCheckValue = this.overlayDiv.querySelector('#signatureCheck') as HTMLDivElement; - - //introDiv.innerHTML = ''; - cryptoDataDiv.innerHTML = ''; - bufferValue.innerHTML = ''; - hashedBufferValue.innerHTML = '0x00000000000000000000000000000000000'; - publicKeyValue.innerHTML = '0x00000000000000000000000000000000000'; - signatureExpectedValue.innerHTML = '0x00000000000000000000000000000000000'; - signatureCheckValue.innerHTML = ''; - - if (measurementValue.method) - measurementValue.method.ViewMeasurement(measurementValue, - introDiv, - cryptoDataDiv, - bufferValue, - hashedBufferValue, - publicKeyValue, - signatureExpectedValue, - signatureCheckValue); - - else - { - doError("Unbekanntes Messdatensatzformat!"); - } + //#region verifyMeasurementCryptoDetails(measurementValue) - //#endregion + // private async verifyMeasurementCryptoDetails(measurementValue: IMeasurementValue) : Promise + // { - } + // var result: ICryptoResult = { + // status: VerificationResult.UnknownCTRFormat + // }; - //#endregion + // if (measurementValue == null || + // measurementValue.measurement == null) + // { + // return result; + // } + // switch (measurementValue.measurement["@context"]) + // { + // case "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/GDFCrypt01+json": + // measurementValue.method = new GDFCrypt01(this.GetMeter, this.CheckMeterPublicKeySignature); + // return measurementValue.method.VerifyMeasurement(measurementValue); - //#region Global error handling... + // case "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/EMHCrypt01+json": + // if (measurementValue.measurement.chargingSession.method != null) + // { - private doGlobalError(text: String, - context?: any) - { + // measurementValue.method = measurementValue.measurement.chargingSession.method; - this.inputInfosDiv.style.display = 'flex'; - this.chargingSessionScreenDiv.style.display = 'none'; - this.chargingSessionScreenDiv.innerHTML = ''; - this.errorTextDiv.style.display = 'inline-block'; - this.errorTextDiv.innerHTML = ' ' + text; + // if (measurementValue.result == null) + // return measurementValue.method.VerifyMeasurement(measurementValue); - console.log(text); - console.log(context); + // return measurementValue.result; - } + // } - //#endregion + // measurementValue.method = new EMHCrypt01(this.GetMeter, this.CheckMeterPublicKeySignature); + // return measurementValue.method.VerifyMeasurement(measurementValue); + // case "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/OCMFv1.0+json": + // if (measurementValue.measurement.chargingSession.method != null) + // { - //#region Read and parse CTR file + // measurementValue.method = measurementValue.measurement.chargingSession.method; - private readAndParseFile(file: File) { + // if (measurementValue.result == null) + // return measurementValue.method.VerifyMeasurement(measurementValue); - if (!file) - return; + // return measurementValue.result; - var reader = new FileReader(); + // } - reader.onload = (event) => { - try - { - this.detectContentFormat((event.target as any).result); - } - catch (exception) { - this.doGlobalError("Fehlerhafter Transparenzdatensatz!", exception); - } - } + // measurementValue.method = new OCMFv1_0(this.GetMeter, this.CheckMeterPublicKeySignature); + // return measurementValue.method.VerifyMeasurement(measurementValue); - reader.onerror = (event) => { - this.doGlobalError("Fehlerhafter Transparenzdatensatz!", event); - } + // default: + // return result; - reader.readAsText(file, 'UTF-8'); + // } - } + // } //#endregion - //#region Process .chargy file extentions/associations opened via this app - private readFileFromDisk(filename: string): void { - if (filename != null && filename.trim() != "" && filename != "." && filename[0] != '-') - { - try - { - let content = require('original-fs').readFileSync(filename.replace("file://", ""), 'utf-8'); - this.detectContentFormat(JSON.parse(content)); - } - catch (exception) { - this.doGlobalError("Fehlerhafter Transparenzdatensatz!", exception); - } - } - } - //#endregion } diff --git a/src/js/chargyApp.ts b/src/js/chargyApp.ts new file mode 100644 index 0000000..a996053 --- /dev/null +++ b/src/js/chargyApp.ts @@ -0,0 +1,1770 @@ +/* + * Copyright (c) 2018-2019 GraphDefined GmbH + * This file is part of Chargy Desktop App + * + * Licensed under the Affero GPL license, Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.gnu.org/licenses/agpl.html + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// + +// import { debug } from "util"; +// import * as crypto from "crypto"; +// import { readSync } from "fs"; +// import { version } from "punycode"; + +var map: any = ""; +var leaflet: any = ""; + +function OpenLink(url: string) +{ + if (url.startsWith("https://")) + require('electron').shell.openExternal(url); +} + +class ChargyApp { + + //#region Data + + private elliptic: any; + private moment: any; + private chargy: Chargy; + + // variable 'crypto' is already defined differently in Google Chrome! + private crypt = require('electron').remote.require('crypto'); + public appVersion = require('electron').remote.app.getVersion().split('.') as string[]; + private ipcRenderer = require('electron').ipcRenderer; + private path = require('path'); + + private exe_hash = ""; + private app_asar_hash = ""; + private electron_asar_hash = ""; + private complete_hash = ""; + + private input: HTMLDivElement; + private updateAvailableButton: HTMLButtonElement; + private aboutButton: HTMLButtonElement; + private fullScreenButton: HTMLButtonElement; + + private updateAvailableScreen: HTMLDivElement; + private inputInfosDiv: HTMLDivElement; + private aboutScreenDiv: HTMLDivElement; + private chargySHA512Div: HTMLDivElement; + private chargingSessionScreenDiv: HTMLDivElement; + private backButtonDiv: HTMLDivElement; + private fileInputButton: HTMLButtonElement; + private fileInput: HTMLInputElement; + private evseTarifInfosDiv: HTMLDivElement; + private errorTextDiv: HTMLDivElement; + private overlayDiv: HTMLDivElement; + private overlayOkButton: HTMLButtonElement; + + private markers: any = []; + private minlat: number = +1000; + private maxlat: number = -1000; + private minlng: number = +1000; + private maxlng: number = -1000; + + private currentAppInfos: any = null; + private currentVersionInfos: any = null; + private currentPackage: any = null; + + //#endregion + + constructor() { + + this.elliptic = require('elliptic'); + this.moment = require('moment'); + this.chargy = new Chargy(this.elliptic, + this.moment); + + //#region Calculate application hash + + switch (process.platform) + { + + case "win32": + this.calcSHA512Hash('Chargy Transparenzsoftware.exe', hash => this.exe_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); + this.calcSHA512Hash(this.path.join('resources', 'app.asar'), hash => this.app_asar_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); + this.calcSHA512Hash(this.path.join('resources', 'electron.asar'), hash => this.electron_asar_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); + break; + + case "linux": + case "freebsd": + case "openbsd": + this.calcSHA512Hash('/opt/Chargy\ Transparenzsoftware/chargytransparenzsoftware', hash => this.exe_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); + this.calcSHA512Hash('/opt/Chargy\ Transparenzsoftware/resources/app.asar', hash => this.app_asar_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); + this.calcSHA512Hash('/opt/Chargy\ Transparenzsoftware/resources/electron.asar', hash => this.electron_asar_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); + break; + + case "darwin": + this.calcSHA512Hash('/Applications/Chargy\ Transparenzsoftware.app/Contents/MacOS/Chargy Transparenzsoftware', hash => this.exe_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); + this.calcSHA512Hash('/Applications/Chargy\ Transparenzsoftware.app/Contents/Resources/app.asar', hash => this.app_asar_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); + this.calcSHA512Hash('/Applications/Chargy\ Transparenzsoftware.app/Contents/Resources/electron.asar', hash => this.electron_asar_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); + break; + + default: + document.getElementById('chargySHA512')!.children[1].innerHTML = "Kann nicht berechnet werden!" + break; + + } + + //#endregion + + //#region Get list of Chargy versions from GitHub + + let GetListOfVersionsFromGitHub = new XMLHttpRequest(); + GetListOfVersionsFromGitHub.open("GET", + "https://raw.githubusercontent.com/OpenChargingCloud/ChargyDesktopApp/master/versions/versions.json", + true); + + GetListOfVersionsFromGitHub.onreadystatechange = () => { + + // 0 UNSENT | 1 OPENED | 2 HEADERS_RECEIVED | 3 LOADING | 4 DONE + if (GetListOfVersionsFromGitHub.readyState == 4) { + if (GetListOfVersionsFromGitHub.status == 200) { // HTTP 200 - OK + + try { + + var versionsDiv = this.updateAvailableScreen.querySelector("#versions") as HTMLDivElement; + if (versionsDiv != null) + { + + this.currentAppInfos = JSON.parse(GetListOfVersionsFromGitHub.responseText) as IVersions; + + for (let version of this.currentAppInfos.versions) + { + + var versionElements = version.version.split('.'); + + //#region Find current version package + + if (versionElements[0] == this.appVersion[0] && versionElements[1] == this.appVersion[1] && versionElements[2] == this.appVersion[2]) + { + + this.currentVersionInfos = version; + + if (this.currentVersionInfos.packages && this.currentVersionInfos.packages.length > 0) + { + for (let _package of this.currentVersionInfos.packages) + { + if (_package.isInstaller == null && + (_package.platform === process.platform || + (_package.platforms != null && Array.isArray(_package.platforms) && _package.platforms.indexOf(process.platform) > -1))) + { + this.currentPackage = _package; + } + } + } + + } + + //#endregion + + //#region Find newer/updated version + + else if (versionElements[0] > this.appVersion[0] || + (versionElements[0] >= this.appVersion[0] && versionElements[1] > this.appVersion[1]) || + (versionElements[0] >= this.appVersion[0] && versionElements[1] >= this.appVersion[1] && versionElements[2] > this.appVersion[2])) + { + + this.updateAvailableButton.style.display = "block"; + + let versionDiv = versionsDiv.appendChild(document.createElement('div')); + versionDiv.className = "version"; + + let headlineDiv = versionDiv.appendChild(document.createElement('div')); + headlineDiv.className = "headline"; + + let versionnumberDiv = headlineDiv.appendChild(document.createElement('div')); + versionnumberDiv.className = "versionnumber"; + versionnumberDiv.innerHTML = "Version " + version.version; + + let releaseDateDiv = headlineDiv.appendChild(document.createElement('div')); + releaseDateDiv.className = "releaseDate"; + releaseDateDiv.innerHTML = parseUTC(version.releaseDate).format("ll"); + + let descriptionDiv = versionDiv.appendChild(document.createElement('div')); + descriptionDiv.className = "description"; + descriptionDiv.innerHTML = version.description["de"]; + + let tagsDiv = versionDiv.appendChild(document.createElement('div')); + tagsDiv.className = "tags"; + + for (let tag of version.tags) + { + let tagDiv = tagsDiv.appendChild(document.createElement('div')); + tagDiv.className = "tag"; + tagDiv.innerHTML = tag; + } + + let packagesDiv = versionDiv.appendChild(document.createElement('div')); + packagesDiv.className = "packages"; + + for (let versionpackage of version.packages) + { + + let packageDiv = packagesDiv.appendChild(document.createElement('div')); + packageDiv.className = "package"; + + let nameDiv = packageDiv.appendChild(document.createElement('div')); + nameDiv.className = "name"; + nameDiv.innerHTML = versionpackage.name; + + if (versionpackage.description && + versionpackage.description["de"]) + { + let descriptionDiv = packageDiv.appendChild(document.createElement('div')); + descriptionDiv.className = "description"; + descriptionDiv.innerHTML = versionpackage.description["de"]; + } + + if (versionpackage.additionalInfo && + versionpackage.additionalInfo["de"]) + { + let additionalInfoDiv = packageDiv.appendChild(document.createElement('div')); + additionalInfoDiv.className = "additionalInfo"; + additionalInfoDiv.innerHTML = versionpackage.additionalInfo["de"]; + } + + + let cryptoHashesDiv = packageDiv.appendChild(document.createElement('div')); + cryptoHashesDiv.className = "cryptoHashes"; + + for (let cryptoHash in versionpackage.cryptoHashes) + { + + let cryptoHashDiv = cryptoHashesDiv.appendChild(document.createElement('div')); + cryptoHashDiv.className = "cryptoHash"; + + let cryptoHashNameDiv = cryptoHashDiv.appendChild(document.createElement('div')); + cryptoHashNameDiv.className = "name"; + cryptoHashNameDiv.innerHTML = cryptoHash; + + let value = versionpackage.cryptoHashes[cryptoHash].replace(/\s+/g, ''); + + if (value.startsWith("0x")) + value = value.substring(2); + + let cryptoHashValueDiv = cryptoHashDiv.appendChild(document.createElement('div')); + cryptoHashValueDiv.className = "value"; + cryptoHashValueDiv.innerHTML = value.match(/.{1,8}/g).join(" "); + + } + + + let signaturesTextDiv = packageDiv.appendChild(document.createElement('div')); + signaturesTextDiv.className = "signaturesText"; + signaturesTextDiv.innerHTML = "Die Authentizität diese Software wurde durch folgende digitale Signaturen bestätigt"; + + let signaturesDiv = packageDiv.appendChild(document.createElement('div')); + signaturesDiv.className = "signatures"; + + for (let signature of versionpackage.signatures) + { + + let signatureDiv = signaturesDiv.appendChild(document.createElement('div')); + signatureDiv.className = "signature"; + + let signatureCheckDiv = signatureDiv.appendChild(document.createElement('div')); + signatureCheckDiv.className = "signatureCheck"; + signatureCheckDiv.innerHTML = ""; + + let authorDiv = signatureDiv.appendChild(document.createElement('div')); + authorDiv.className = "signer"; + authorDiv.innerHTML = signature.signer; + + } + + + if (versionpackage.downloadURLs) + { + + let downloadURLsTextDiv = packageDiv.appendChild(document.createElement('div')); + downloadURLsTextDiv.className = "downloadURLsText"; + downloadURLsTextDiv.innerHTML = "Diese Software kann über folgende Weblinks runtergeladen werden"; + + let downloadURLsDiv = packageDiv.appendChild(document.createElement('div')); + downloadURLsDiv.className = "downloadURLs"; + + for (let downloadURLName in versionpackage.downloadURLs) + { + let downloadURLDiv = downloadURLsDiv.appendChild(document.createElement('div')); + downloadURLDiv.className = "downloadURL"; + downloadURLDiv.innerHTML = "" + downloadURLName + ""; + } + + } + + } + + } + + //#endregion + + } + + } + + } + catch (exception) + { + // Just do nothing! + } + + } + } + + } + + GetListOfVersionsFromGitHub.send(); + + //#endregion + + + this.updateAvailableScreen = document.getElementById('updateAvailableScreen'); + this.aboutScreenDiv = document.getElementById('aboutScreen'); + this.chargySHA512Div = document.getElementById('chargySHA512'); + this.chargingSessionScreenDiv = document.getElementById('chargingSessionScreen'); + this.evseTarifInfosDiv = document.getElementById('evseTarifInfos'); + this.inputInfosDiv = document.getElementById('inputInfos'); + this.errorTextDiv = document.getElementById('errorText'); + + + //#region Handle Drag'n'Drop of charge transparency files + + this.input = document.getElementById('input'); + + this.input.addEventListener('dragenter', (event: DragEvent) => { + event.preventDefault(); + (event.currentTarget as HTMLDivElement)!.classList.add('over'); + }, false); + + this.input.addEventListener('dragover', (event: DragEvent) => { + event.stopPropagation(); + event.preventDefault(); + event.dataTransfer!.dropEffect = 'copy'; + (event.currentTarget as HTMLDivElement)!.classList.add('over'); + }, false); + + this.input.addEventListener('dragleave', (event: DragEvent) => { + (event.currentTarget as HTMLDivElement)!.classList.remove('over'); + }, false); + + this.input.addEventListener('drop', (event: DragEvent) => { + event.stopPropagation(); + event.preventDefault(); + (event.currentTarget as HTMLDivElement)!.classList.remove('over'); + this.readAndParseFile(event.dataTransfer!.files[0]); + }, false); + + //#endregion + + //#region Handle the 'Update available'-button + + this.updateAvailableButton = document.getElementById('updateAvailableButton'); + this.updateAvailableButton.onclick = (ev: MouseEvent) => { + this.updateAvailableScreen.style.display = "block"; + this.inputInfosDiv.style.display = "none"; + this.aboutScreenDiv.style.display = "none"; + this.chargingSessionScreenDiv.style.display = "none"; + this.backButtonDiv.style.display = "block"; + } + + //#endregion + + //#region Handle the 'About'-button + + this.aboutButton = document.getElementById('aboutButton'); + this.aboutButton.onclick = (ev: MouseEvent) => { + + this.updateAvailableScreen.style.display = "none"; + this.inputInfosDiv.style.display = "none"; + this.aboutScreenDiv.style.display = "block"; + this.chargingSessionScreenDiv.style.display = "none"; + this.backButtonDiv.style.display = "block"; + + //#region Calculate the over-all application hash + + if (this.complete_hash == "" && + this.exe_hash != "" && + this.app_asar_hash != "" && + this.electron_asar_hash != "") + { + + var sha512hash = this.crypt.createHash('sha512'); + sha512hash.update(this.exe_hash); + sha512hash.update(this.app_asar_hash); + sha512hash.update(this.electron_asar_hash); + + this.complete_hash = this.chargySHA512Div.children[1].innerHTML = sha512hash.digest('hex').match(/.{1,8}/g).join(" "); + + //#region Check application hash signatures, when given... + + if (this.currentAppInfos != null && + this.currentVersionInfos != null && + this.currentPackage != null) + { + + let sigHeadDiv = this.chargySHA512Div.children[2]; + let signaturesDiv = this.chargySHA512Div.children[3]; + + // Bad hash value + if (this.currentPackage.cryptoHashes.SHA512.replace("0x", "") !== this.complete_hash) + sigHeadDiv.innerHTML = " Ungültiger Hashwert!"; + + // At least the same hash value... + else + { + + if (this.currentPackage.signatures == null || this.currentPackage.signatures.length == 0) + { + sigHeadDiv.innerHTML = " Gültiger Hashwert"; + } + + // Some crypto signatures found... + else + { + + sigHeadDiv.innerHTML = "Bestätigt durch..."; + + for (let signature of this.currentPackage.signatures) + { + let signatureDiv = signaturesDiv.appendChild(document.createElement('div')); + signatureDiv.innerHTML = this.CheckApplicationHashSignature(this.currentAppInfos, + this.currentVersionInfos, + this.currentPackage, + signature); + } + + } + + } + + } + + //#endregion + + } + + //#endregion + + } + + //#endregion + + //#region Handle the 'fullScreen'-button + + var d = document as any; + this.fullScreenButton = document.getElementById('fullScreenButton'); + this.fullScreenButton.onclick = (ev: MouseEvent) => { + if (d.fullScreen || d.mozFullScreen || d.webkitIsFullScreen) + { + this.overlayDiv.classList.remove("fullScreen"); + closeFullscreen(); + this.fullScreenButton.innerHTML = ''; + } + else + { + this.overlayDiv.classList.add("fullScreen"); + openFullscreen(); + this.fullScreenButton.innerHTML = ''; + } + } + + //#endregion + + //#region Handle the 'Overlay Ok'-button + + this.overlayDiv = document.getElementById('overlay'); + this.overlayOkButton = document.getElementById('overlayOkButton'); + this.overlayOkButton.onclick = (ev: MouseEvent) => { + this.overlayDiv.style.display = 'none'; + } + + //#endregion + + //#region Handle the 'fileInput'-button + + this.fileInputButton = document.getElementById('fileInputButton'); + this.fileInput = document.getElementById('fileInput'); + this.fileInputButton.onclick = (ev: MouseEvent) => { + this.fileInput.value = ''; + this.fileInput.click(); + } + //@ts-ignokjre + this.fileInput.onchange = (ev: Event) => { + var files = ev!.target!["files"]; + if (files != null) + this.readAndParseFile(files[0]); + } + + //#endregion + + //#region Handle the 'paste'-button + + var pasteButton = document.getElementById('pasteButton'); + pasteButton.onclick = (ev: MouseEvent) => { + (navigator as any).clipboard.readText().then((clipText: string) => { + try + { + this.detectContentFormat(clipText); + } + catch (exception) { + this.doGlobalError("Fehlerhafter Transparenzdatensatz!", exception); + } + }); + } + + //#endregion + + //#region The Issue tracker + + var issueTracker = document.getElementById('issueTracker'); + var showIssueTrackerButton = document.getElementById('showIssueTracker'); + showIssueTrackerButton.onclick = function (this: GlobalEventHandlers, ev: MouseEvent) { + issueTracker.style.display = 'block'; + privacyStatement.style.display = "none"; + issueTrackerText.scrollTop = 0; + } + var newIssueForm = document.getElementById('newIssueForm'); + var issueTrackerText = document.getElementById('issueTrackerText'); + var privacyStatement = document.getElementById('privacyStatement'); + var showPrivacyStatement = document.getElementById('showPrivacyStatement'); + showPrivacyStatement.onclick = function(this: GlobalEventHandlers, ev: MouseEvent) { + ev.preventDefault(); + privacyStatement.style.display = "block"; + issueTrackerText.scrollTop = issueTrackerText.scrollHeight; + } + var privacyStatementAccepted = document.getElementById('privacyStatementAccepted'); + privacyStatementAccepted.onchange = function(this: GlobalEventHandlers, ev: Event) { + sendIssueButton.disabled = !privacyStatementAccepted.checked; + } + var sendIssueButton = document.getElementById('sendIssueButton'); + sendIssueButton.onclick = (ev: MouseEvent) => { // function (this: GlobalEventHandlers, ev: MouseEvent) { + + ev.preventDefault(); + + try + { + + //#region Collect issue data... + + var data = {}; + + data["timestamp"] = new Date().toISOString(); + data["chargyVersion"] = this.appVersion.join("."); + data["platform"] = process.platform; + + data["invalidCTR"] = (newIssueForm.querySelector("#invalidCTR") as HTMLInputElement).checked; + data["InvalidStationData"] = (newIssueForm.querySelector("#InvalidStationData") as HTMLInputElement).checked; + data["invalidSignatures"] = (newIssueForm.querySelector("#invalidSignatures") as HTMLInputElement).checked; + data["invalidCertificates"] = (newIssueForm.querySelector("#invalidCertificates") as HTMLInputElement).checked; + data["transparencenySoftwareBug"] = (newIssueForm.querySelector("#transparencenySoftwareBug") as HTMLInputElement).checked; + data["DSGVO"] = (newIssueForm.querySelector("#DSGVO") as HTMLInputElement).checked; + data["BITV"] = (newIssueForm.querySelector("#BITV") as HTMLInputElement).checked; + + data["description"] = (newIssueForm.querySelector("#issueDescription") as HTMLTextAreaElement).value; + + if ((newIssueForm.querySelector("#includeCTR") as HTMLSelectElement).value == "yes") + data["chargeTransparencyRecord"] = this.chargy.currentCTR; + + data["name"] = (newIssueForm.querySelector("#issueName") as HTMLInputElement).value; + data["phone"] = (newIssueForm.querySelector("#issuePhone") as HTMLInputElement).value; + data["eMail"] = (newIssueForm.querySelector("#issueEMail") as HTMLInputElement).value; + + //#endregion + + //#region Send issue to API + + let sendIssue = new XMLHttpRequest(); + + sendIssue.open("ADD", + "https://chargeit.charging.cloud/chargy/issues", + true); + sendIssue.setRequestHeader('Content-type', 'application/json'); + + sendIssue.onreadystatechange = function () { + + // 0 UNSENT | 1 OPENED | 2 HEADERS_RECEIVED | 3 LOADING | 4 DONE + if (this.readyState == 4) { + + if (this.status == 201) { // HTTP 201 - Created + issueTracker.style.display = 'none'; + // Show thank you for your issue + } + + else + { + alert("Leider ist ein Fehler bei der Datenübertragung aufgetreten. Bitte probieren Sie es erneut..."); + } + + } + + } + + sendIssue.send(JSON.stringify(data)); + + //#endregion + + } + catch (exception) + { + // Just do nothing! + } + + } + var issueBackButton = document.getElementById('issueBackButton'); + issueBackButton.onclick = function (this: GlobalEventHandlers, ev: MouseEvent) { + issueTracker.style.display = 'none'; + } + + //#endregion + + //#region Handle the 'Back'-button + + this.backButtonDiv = document.getElementById('backButtonDiv'); + this.backButtonDiv.onclick = (ev: MouseEvent) => { + + this.updateAvailableScreen.style.display = "none"; + this.inputInfosDiv.style.display = 'flex'; + this.aboutScreenDiv.style.display = "none"; + this.chargingSessionScreenDiv.style.display = "none"; + this.backButtonDiv.style.display = "none"; + this.fileInput.value = ""; + this.evseTarifInfosDiv.innerHTML = ""; + + // Clear the map and reset zoom bounds... + while(this.markers.length > 0) + map.removeLayer(this.markers.pop()); + + this.minlat = +1000; + this.maxlat = -1000; + this.minlng = +1000; + this.maxlng = -1000; + + } + + //#endregion + + //#region Modify external links to be opened in the external web browser + + var shell = require('electron').shell; + let linkButtons = document.getElementsByClassName('linkButton') as HTMLCollectionOf; + for (var i = 0; i < linkButtons.length; i++) { + + let linkButton = linkButtons[i]; + + linkButton.onclick = function (this: GlobalEventHandlers, ev: MouseEvent) { + ev.preventDefault(); + var link = linkButton.attributes["href"].nodeValue; + if (link.startsWith("http://") || link.startsWith("https://")) { + shell.openExternal(link); + } + } + + } + + //#endregion + + //#region Handle 'Open this file with Chargy'-events... + + // Note: The following is synchronous, therefore must be at the end of the file... + + // Windows and Linux + var cliArguments = require('electron').remote.process.argv; + if (cliArguments.length >= 2) + this.readFileFromDisk(cliArguments[1]); + + // Mac OS X - first file to open + this.readFileFromDisk(this.ipcRenderer.sendSync('get-chargy-filename')); + + // Mac OS X - when app is running + this.ipcRenderer.on('send-chargy-filename', (event:any, filename:string) => { + this.readFileFromDisk(filename); + }); + + //#endregion + + } + + + //#region calcSHA512Hash(...) + + private calcSHA512Hash(filename: string, + OnSuccess: { (hash: string): any; }, + OnFailed: { (errorMessage: string): any; }) + { + + const fs = require('original-fs'); + let sha512 = require('electron').remote. + require('crypto').createHash('sha512'); + let stream = fs.createReadStream(filename); + + stream.on('data', function(data: any) { + sha512.update(data) + }) + + stream.on('error', function() { + OnFailed("File not found!"); + }) + + stream.on('end', function() { + OnSuccess(sha512.digest('hex')); + }) + + } + + //#endregion + + //#region CheckApplicationHashSignature(...) + + private CheckApplicationHashSignature(app: any, + version: any, + _package: any, + signature: any): string + { + + if (app == null || version == null || _package == null || signature == null) + return "Ungültige Signatur!"; + + try { + + var toCheck = { + "name": app.name, + "description": app.description, + + "version": { + "version": this.appVersion.join("."), + "releaseDate": version.releaseDate, + "description": version.description, + "tags": version.tags, + + "package": { + "name": _package.name, + "description": _package.description, + "additionalInfo": _package.additonalInfo, + "platform": _package.platform, + "isInstaller": _package.isInstaller, // Note: Might be null! Keep null values! + "cryptoHashValue": this.complete_hash, + + "signature": { + "signer": signature.signer, + "timestamp": signature.timestamp, + "comment": signature.comment, + "algorithm": signature.algorithm, + "format": signature.format + } + + } + + } + + }; + + //ToDo: Checking the timestamp might be usefull! + + var Input = JSON.stringify(toCheck); + var sha256value = this.crypt.createHash('sha256'). + update(Input, 'utf8'). + digest('hex'); + + var result = new this.elliptic.ec('secp256k1'). + keyFromPublic(signature.publicKey, 'hex'). + verify (sha256value, + signature.signature); + + if (result) + return "" + signature.signer; + + + } + catch (exception) + { } + + return "" + signature.signer; + + } + + //#endregion + + + + + + + + + //#region detectContentFormat(Content) + + private async detectContentFormat(Content: string) { + + this.inputInfosDiv.style.display = 'none'; + this.errorTextDiv.style.display = 'none'; + + var result = await this.chargy.detectContentFormat(Content); + + if (IsAChargeTransparencyRecord(result)) + await this.showChargeTransparencyRecord(result); + + else + this.doGlobalError2(result, + "Unbekanntes Transparenzdatensatzformat!"); + + } + + //#endregion + + //#region showChargeTransparencyRecord(CTR) + + private async showChargeTransparencyRecord(CTR: IChargeTransparencyRecord) + { + + if (CTR == null) + return; + + //#region Prepare View + + this.chargingSessionScreenDiv.style.display = "flex"; + this.chargingSessionScreenDiv.innerText = ""; + this.backButtonDiv.style.display = "block"; + + //#endregion + + //#region Show CTR infos + + if (CTR.description) { + let descriptionDiv = this.chargingSessionScreenDiv.appendChild(document.createElement('div')); + descriptionDiv.id = "description"; + descriptionDiv.innerText = firstValue(CTR.description); + } + + if (CTR.begin) { + let beginDiv = this.chargingSessionScreenDiv.appendChild(document.createElement('div')); + beginDiv.id = "begin"; + beginDiv.className = "defi"; + beginDiv.innerHTML = "von " + parseUTC(CTR.begin).format('dddd, D. MMMM YYYY'); + } + + if (CTR.end) { + let endDiv = this.chargingSessionScreenDiv.appendChild(document.createElement('div')); + endDiv.id = "begin"; + endDiv.className = "defi"; + endDiv.innerHTML = "bis " + parseUTC(CTR.end).format('dddd, D. MMMM YYYY'); + } + + //#endregion + + //#region Show global contract infos + + if (CTR.contract) + { + } + + //#endregion + + //#region Show all charging sessions... + + if (CTR.chargingSessions) + { + + let chargingSessionsDiv = this.chargingSessionScreenDiv.appendChild(document.createElement('div')); + chargingSessionsDiv.id = "chargingSessions"; + + for (let chargingSession of CTR.chargingSessions) + { + + let chargingSessionDiv = CreateDiv(chargingSessionsDiv, "chargingSessions"); + chargingSession.GUI = chargingSessionDiv; + chargingSessionDiv.onclick = (ev: MouseEvent) => { + + //#region Highlight the selected charging session... + + var AllChargingSessionsDivs = document.getElementsByClassName("chargingSessions"); + for(var i=0; i Nov + replace(";", ".") + // 14; -> 14. + " Uhr"; + + if (chargingSession.end) + { + + var endUTC = parseUTC(chargingSession.end); + var duration = this.moment.duration(endUTC - beginUTC); + + dateDiv.innerHTML += " - " + + (Math.floor(duration.asDays()) > 0 ? endUTC.format("dddd") + " " : "") + + endUTC.format('HH:mm:ss') + + " Uhr"; + + } + + } + + } + catch (exception) + { + console.log("Could not show session time infos of charging session '" + chargingSession["@id"] + "':" + exception); + } + + //#endregion + + var tableDiv = chargingSessionDiv.appendChild(document.createElement('div')); + tableDiv.className = "table"; + + //#region Show energy infos + + try { + + var productInfoDiv = tableDiv.appendChild(document.createElement('div')); + productInfoDiv.className = "productInfos"; + + var productIconDiv = productInfoDiv.appendChild(document.createElement('div')); + productIconDiv.className = "icon"; + productIconDiv.innerHTML = ''; + + var productDiv = productInfoDiv.appendChild(document.createElement('div')); + productDiv.className = "text"; + productDiv.innerHTML = chargingSession.product != null ? chargingSession.product["@id"] + "
" : ""; + + productDiv.innerHTML += "Ladedauer "; + if (Math.floor(duration.asDays()) > 1) productDiv.innerHTML += duration.days() + " Tage " + duration.hours() + " Std. " + duration.minutes() + " Min. " + duration.seconds() + " Sek."; + else if (Math.floor(duration.asDays()) > 0) productDiv.innerHTML += duration.days() + " Tag " + duration.hours() + " Std. " + duration.minutes() + " Min. " + duration.seconds() + " Sek."; + else if (Math.floor(duration.asHours()) > 0) productDiv.innerHTML += duration.hours() + " Std. " + duration.minutes() + " Min. " + duration.seconds() + " Sek."; + else if (Math.floor(duration.asMinutes()) > 0) productDiv.innerHTML += duration.minutes() + " Min. " + duration.seconds() + " Sek."; + else if (Math.floor(duration.asSeconds()) > 0) productDiv.innerHTML += duration.seconds(); + + if (chargingSession.measurements) + { + for (var measurement of chargingSession.measurements) + { + // + if (measurement.values && measurement.values.length > 0) + { + + var first = measurement.values[0].value; + var last = measurement.values[measurement.values.length-1].value; + var amount = parseFloat(((last - first) * Math.pow(10, measurement.scale)).toFixed(10)); + + switch (measurement.unit) + { + + case "KILO_WATT_HOURS": + break; + + // "WATT_HOURS" + default: + amount = parseFloat((amount / 1000).toFixed(10)); + break; + + } + + productDiv.innerHTML += "
" + translateMeasurementName(measurement.name) + " " + amount.toString() + " kWh (" + measurement.values.length + " Messwerte)"; + + } + + } + } + + } + catch (exception) + { + console.log("Could not show energy infos of charging session '" + chargingSession["@id"] + "':" + exception); + } + + //#endregion + + //#region Show authorization start/stop information + + try { + + if (chargingSession.authorizationStart != null) + { + + var authorizationStartDiv = tableDiv.appendChild(document.createElement('div')); + authorizationStartDiv.className = "authorizationStart"; + + var authorizationStartIconDiv = authorizationStartDiv.appendChild(document.createElement('div')); + authorizationStartIconDiv.className = "icon"; + switch (chargingSession.authorizationStart.type) + { + + case "cryptoKey": + authorizationStartIconDiv.innerHTML = ''; + break; + + case "eMAId": + case "EVCOId": + authorizationStartIconDiv.innerHTML = ''; + break; + + default: + authorizationStartIconDiv.innerHTML = ''; + break; + + } + + var authorizationStartIdDiv = authorizationStartDiv.appendChild(document.createElement('div')); + authorizationStartIdDiv.className = "id"; + authorizationStartIdDiv.innerHTML = chargingSession.authorizationStart["@id"]; + + } + + if (chargingSession.authorizationStop != null) + { + + var authorizationStopDiv = tableDiv.appendChild(document.createElement('div')); + authorizationStopDiv.className = "authorizationStop"; + + var authorizationStopIconDiv = authorizationStopDiv.appendChild(document.createElement('div')); + authorizationStopIconDiv.className = "icon"; + switch (chargingSession.authorizationStop.type) + { + + case "cryptoKey": + authorizationStopIconDiv.innerHTML = ''; + break; + + case "eMAId": + case "EVCOId": + authorizationStopIconDiv.innerHTML = ''; + break; + + default: + authorizationStopIconDiv.innerHTML = ''; + break; + + } + + var authorizationStopIdDiv = authorizationStopDiv.appendChild(document.createElement('div')); + authorizationStopIdDiv.className = "id"; + authorizationStopIdDiv.innerHTML = chargingSession.authorizationStop["@id"]; + + } + + } catch (exception) + { + console.log("Could not show authorization start/stop infos of charging session '" + chargingSession["@id"] + "':" + exception); + } + + //#endregion + + //#region Show location infos... + + try + { + + if (chargingSession.EVSEId || chargingSession.EVSE || + chargingSession.chargingStationId || chargingSession.chargingStation || + chargingSession.chargingPoolId || chargingSession.chargingPool) { + + var address:IAddress|null = null; + + var locationInfoDiv = tableDiv.appendChild(document.createElement('div')); + locationInfoDiv.className = "locationInfos"; + + var locationIconDiv = locationInfoDiv.appendChild(document.createElement('div')); + locationIconDiv.className = "icon"; + locationIconDiv.innerHTML = ''; + + var locationDiv = locationInfoDiv.appendChild(document.createElement('div')); + locationDiv.classList.add("text"); + + if (chargingSession.EVSEId || chargingSession.EVSE) { + + if (chargingSession.EVSE == null || typeof chargingSession.EVSE !== 'object') + chargingSession.EVSE = this.chargy.GetEVSE(chargingSession.EVSEId); + + locationDiv.classList.add("EVSE"); + locationDiv.innerHTML = (chargingSession.EVSE != null && chargingSession.EVSE.description != null + ? firstValue(chargingSession.EVSE.description) + "
" + : "") + + (chargingSession.EVSEId != null + ? chargingSession.EVSEId + : chargingSession.EVSE!["@id"]); + + if (chargingSession.EVSE) + { + + chargingSession.chargingStation = chargingSession.EVSE.chargingStation; + chargingSession.chargingStationId = chargingSession.EVSE.chargingStationId; + + if (chargingSession.EVSE.chargingStation) + { + chargingSession.chargingPool = chargingSession.EVSE.chargingStation.chargingPool; + chargingSession.chargingPoolId = chargingSession.EVSE.chargingStation.chargingPoolId; + address = chargingSession.EVSE.chargingStation.address; + } + + } + + } + + else if (chargingSession.chargingStationId || chargingSession.chargingStation) { + + if (chargingSession.chargingStation == null || typeof chargingSession.chargingStation !== 'object') + chargingSession.chargingStation = this.chargy.GetChargingStation(chargingSession.chargingStationId); + + if (chargingSession.chargingStation != null) + { + + locationDiv.classList.add("chargingStation"); + locationDiv.innerHTML = (chargingSession.chargingStation != null && chargingSession.chargingStation.description != null + ? firstValue(chargingSession.chargingStation.description) + "
" + : "") + + (chargingSession.chargingStationId != null + ? chargingSession.chargingStationId + : chargingSession.chargingStation["@id"]); + + chargingSession.chargingPool = chargingSession.chargingStation.chargingPool; + chargingSession.chargingPoolId = chargingSession.chargingStation.chargingPoolId; + + address = chargingSession.chargingStation.address; + + } + else + locationInfoDiv.remove(); + + } + + else if (chargingSession.chargingPoolId || chargingSession.chargingPool) { + + if (chargingSession.chargingPool == null || typeof chargingSession.chargingPool !== 'object') + chargingSession.chargingPool = this.chargy.GetChargingPool(chargingSession.chargingPoolId); + + if (chargingSession.chargingPool != null) + { + + locationDiv.classList.add("chargingPool"); + locationDiv.innerHTML = (chargingSession.chargingPool != null && chargingSession.chargingPool.description != null + ? firstValue(chargingSession.chargingPool.description) + "
" + : "") + + (chargingSession.chargingPoolId != null + ? chargingSession.chargingPoolId + : chargingSession.chargingPool["@id"]); + + address = this.chargy.GetChargingPool(chargingSession.chargingPool["@id"])!.address; + + } + else + locationInfoDiv.remove(); + + } + + if (address != null) + locationDiv.innerHTML += "
" + + (address.street != null ? " " + address.street : "") + + (address.houseNumber != null ? " " + address.houseNumber : "") + + + (address.postalCode != null || address.city != null ? "," : "") + + (address.postalCode != null ? " " + address.postalCode : "") + + (address.city != null ? " " + address.city : ""); + + } + + } catch (exception) + { + console.log("Could not show location infos of charging session '" + chargingSession["@id"] + "':" + exception); + } + + //#endregion + + //#region Add marker to map + + var redMarker = leaflet.AwesomeMarkers.icon({ + prefix: 'fa', + icon: 'exclamation', + markerColor: 'red', + iconColor: '#ecc8c3' + }); + + var greenMarker = leaflet.AwesomeMarkers.icon({ + prefix: 'fa', + icon: 'charging-station', + markerColor: 'green', + iconColor: '#c2ec8e' + }); + + var markerIcon = redMarker; + + if (chargingSession.verificationResult) + switch (chargingSession.verificationResult.status) + { + + case SessionVerificationResult.UnknownSessionFormat: + case SessionVerificationResult.PublicKeyNotFound: + case SessionVerificationResult.InvalidPublicKey: + case SessionVerificationResult.InvalidSignature: + markerIcon = redMarker; + break; + + case SessionVerificationResult.ValidSignature: + markerIcon = greenMarker; + break; + + } + + var geoLocation = null; + + if (chargingSession.chargingPool != null && + chargingSession.chargingPool.geoLocation != null) + { + geoLocation = chargingSession.chargingPool.geoLocation; + } + + if (chargingSession.chargingStation != null && + chargingSession.chargingStation.geoLocation != null) + { + geoLocation = chargingSession.chargingStation.geoLocation; + } + + if (geoLocation != null) + { + + var marker = leaflet.marker([geoLocation.lat, geoLocation.lng], { icon: markerIcon }).addTo(map); + this.markers.push(marker); + + if (this.minlat > geoLocation.lat) + this.minlat = geoLocation.lat; + + if (this.maxlat < geoLocation.lat) + this.maxlat = geoLocation.lat; + + if (this.minlng > geoLocation.lng) + this.minlng = geoLocation.lng; + + if (this.maxlng < geoLocation.lng) + this.maxlng = geoLocation.lng; + + if (chargingSession.verificationResult) + switch (chargingSession.verificationResult.status) + { + + case SessionVerificationResult.UnknownSessionFormat: + case SessionVerificationResult.PublicKeyNotFound: + case SessionVerificationResult.InvalidPublicKey: + case SessionVerificationResult.InvalidSignature: + marker.bindPopup("Ungültiger Ladevorgang!"); + break; + + case SessionVerificationResult.ValidSignature: + marker.bindPopup("Gültiger Ladevorgang!"); + break; + + } + + } + + //#endregion + + //#region Show verification status + + let verificationStatusDiv = chargingSessionDiv.appendChild(document.createElement('div')); + verificationStatusDiv.className = "verificationStatus"; + + if (chargingSession.verificationResult) + switch (chargingSession.verificationResult.status) + { + + case SessionVerificationResult.UnknownSessionFormat: + case SessionVerificationResult.PublicKeyNotFound: + case SessionVerificationResult.InvalidPublicKey: + case SessionVerificationResult.InvalidSignature: + verificationStatusDiv.innerHTML = ' Ungültig'; + break; + + case SessionVerificationResult.ValidSignature: + verificationStatusDiv.innerHTML = ' Gültig'; + break; + + default: + verificationStatusDiv.innerHTML = ' Ungültig'; + break; + + } + + //#endregion + + } + + // If there is only one charging session show its details at once... + if (CTR.chargingSessions.length == 1) + CTR.chargingSessions[0].GUI.click(); + + map.fitBounds([[this.minlat, this.minlng], [this.maxlat, this.maxlng]], + { padding: [40, 40] }); + + } + + //#endregion + + } + + //#endregion + + //#region showChargingSessionDetails + + private async showChargingSessionDetails(chargingSession: IChargingSession) + { + + try + { + + this.evseTarifInfosDiv.innerHTML = ""; + + if (chargingSession.measurements) + { + for (var measurement of chargingSession.measurements) + { + + measurement.chargingSession = chargingSession; + + let headline = CreateDiv(this.evseTarifInfosDiv); + headline.id = "headline"; + headline.innerHTML = "Informationen zum Ladevorgang"; + + let MeasurementInfoDiv = CreateDiv(this.evseTarifInfosDiv, "measurementInfos"); + + //#region Show charging station infos + + if (measurement.chargingSession.chargingStation != null) + { + + let ChargingStationDiv = CreateDiv(MeasurementInfoDiv, "chargingStation"); + let ChargingStationHeadline = CreateDiv(ChargingStationDiv, "chargingStationHeadline", + "Ladestation"); + + if (measurement.chargingSession.chargingStation["@id"] != null) + { + + let ChargingStationIdDiv = CreateDiv(ChargingStationDiv, "chargingStationId"); + + let ChargingStationIdIdDiv = CreateDiv(ChargingStationIdDiv, "chargingStationIdId", + "Identifikation"); + + let ChargingStationIdValueDiv = CreateDiv(ChargingStationIdDiv, "chargingStationIdValue", + measurement.chargingSession.chargingStation["@id"]); + + } + + if (measurement.chargingSession.chargingStation.firmwareVersion != null) + { + + let firmwareVersionDiv = CreateDiv(ChargingStationDiv, "firmwareVersion"); + + let firmwareVersionIdDiv = CreateDiv(firmwareVersionDiv, "firmwareVersionId", + "Firmware-Version"); + + let firmwareVersionValueDiv = CreateDiv(firmwareVersionDiv, "firmwareVersionValue", + measurement.chargingSession.chargingStation.firmwareVersion); + + } + + } + + //#endregion + + //#region Show meter infos... + + let meterDiv = CreateDiv(MeasurementInfoDiv, "meter"); + let meterHeadline = CreateDiv(meterDiv, "meterHeadline", + "Energiezähler"); + + var meter = this.chargy.GetMeter(measurement.energyMeterId); + + if (meter != null) + { + + let meterIdDiv = CreateDiv(meterDiv, "meterId"); + + let meterIdIdDiv = CreateDiv(meterIdDiv, "meterIdId", + "Seriennummer"); + + let meterIdValueDiv = CreateDiv(meterIdDiv, "meterIdValue", + measurement.energyMeterId); + + + let MeterVendorDiv = CreateDiv(meterDiv, "meterVendor"); + + let MeterVendorIdDiv = CreateDiv(MeterVendorDiv, "meterVendorId", + "Zählerhersteller"); + + let MeterVendorValueDiv = CreateDiv(MeterVendorDiv, "meterVendorIdValue", + meter.vendor); + + + let MeterModelDiv = CreateDiv(meterDiv, "meterModel"); + + let MeterModelIdDiv = CreateDiv(MeterModelDiv, "meterModelId", + "Model"); + + let MeterModelValueDiv = CreateDiv(MeterModelDiv, "meterModelIdValue", + meter.model); + + } + + //#endregion + + //#region ...or show meterId infos + + else { + + let meterIdDiv = CreateDiv(meterDiv, "meterId"); + + let meterIdIdDiv = CreateDiv(meterIdDiv, "meterIdId", + "Zählerseriennummer"); + + let meterIdValueDiv = CreateDiv(meterIdDiv, "meterIdValue", + measurement.energyMeterId); + + } + + //#endregion + + //#region Show measurement infos + + let measurementDiv = CreateDiv(meterDiv, "measurement"); + + let MeasurementIdDiv = CreateDiv(measurementDiv, "measurementId", + "Messung"); + + let MeasurementIdValueDiv = CreateDiv(measurementDiv, "measurementIdValue", + measurement.name); + + + let OBISDiv = CreateDiv(meterDiv, "OBIS"); + + let OBISIdDiv = CreateDiv(OBISDiv, "OBISId", + "OBIS-Kennzahl"); + + let OBISValueDiv = CreateDiv(OBISDiv, "OBISValue", + parseOBIS(measurement.obis)); + + //#endregion + + //#region Show measurement values... + + if (measurement.values && measurement.values.length > 0) + { + + let meterHeadline = CreateDiv(this.evseTarifInfosDiv, "measurementsHeadline", + "Messwerte"); + meterHeadline.id = "measurementValues-headline"; + + let MeasurementValuesDiv = CreateDiv(this.evseTarifInfosDiv, "measurementValues"); + let previousValue = 0; + + for (let measurementValue of measurement.values) + { + + measurementValue.measurement = measurement; + + let MeasurementValueDiv = CreateDiv(MeasurementValuesDiv, "measurementValue"); + MeasurementValueDiv.onclick = (ev: MouseEvent) => { + this.showMeasurementCryptoDetails(measurementValue); + }; + + var timestamp = parseUTC(measurementValue.timestamp); + + let timestampDiv = CreateDiv(MeasurementValueDiv, "timestamp", + timestamp.format('HH:mm:ss') + " Uhr"); + + + // Show energy counter value + let value2Div = CreateDiv(MeasurementValueDiv, "value1", + parseFloat((measurementValue.value * Math.pow(10, measurementValue.measurement.scale)).toFixed(10)).toString()); + + switch (measurement.unit) + { + + case "KILO_WATT_HOURS": + CreateDiv(MeasurementValueDiv, "unit1", "kWh"); + break; + + // "WATT_HOURS" + default: + CreateDiv(MeasurementValueDiv, "unit1", "Wh"); + break; + + } + + + // Show energy difference + var currentValue = measurementValue.value; + + switch (measurement.unit) + { + + case "KILO_WATT_HOURS": + currentValue = parseFloat((currentValue * Math.pow(10, measurementValue.measurement.scale)).toFixed(10)); + break; + + // "WATT_HOURS" + default: + currentValue = parseFloat((currentValue / 1000 * Math.pow(10, measurementValue.measurement.scale)).toFixed(10)); + break; + + } + + let valueDiv = CreateDiv(MeasurementValueDiv, "value2", + "+" + (previousValue > 0 + ? parseFloat((currentValue - previousValue).toFixed(10)) + : "0")); + + let unitDiv = CreateDiv(MeasurementValueDiv, "unit2", + "kWh"); + + + // Show signature status + let verificationStatusDiv = CreateDiv(MeasurementValueDiv, "verificationStatus", + await this.showMeasurementCrypto(measurementValue)); + + previousValue = currentValue; + + } + + } + + //#endregion + + } + } + + } + catch (exception) + { + console.log("Could not show charging session details: " + exception); + } + + } + + //#endregion + + //#region showMeasurementCryptoDetails + + private showMeasurementCryptoDetails(measurementValue: IMeasurementValue) : void + { + + function doError(text: String) + { + //inputInfosDiv.style.display = 'flex'; + //errorTextDiv.style.display = 'inline-block'; + introDiv.innerHTML = ' ' + text; + } + + + let introDiv = this.overlayDiv.querySelector('#intro') as HTMLDivElement; + let cryptoDataDiv = this.overlayDiv.querySelector('#cryptoData') as HTMLDivElement; + + if (measurementValue == null || + measurementValue.measurement == null) + { + doError("Unbekanntes Messdatensatzformat!"); + } + + + //#region Show data and result on overlay + + this.overlayDiv.style.display = 'block'; + + let bufferValue = this.overlayDiv.querySelector('#buffer .value') as HTMLDivElement; + let hashedBufferValue = this.overlayDiv.querySelector('#hashedBuffer .value') as HTMLDivElement; + let publicKeyValue = this.overlayDiv.querySelector('#publicKey .value') as HTMLDivElement; + let signatureExpectedValue = this.overlayDiv.querySelector('#signatureExpected .value') as HTMLDivElement; + let signatureCheckValue = this.overlayDiv.querySelector('#signatureCheck') as HTMLDivElement; + + //introDiv.innerHTML = ''; + cryptoDataDiv.innerHTML = ''; + bufferValue.innerHTML = ''; + hashedBufferValue.innerHTML = '0x00000000000000000000000000000000000'; + publicKeyValue.innerHTML = '0x00000000000000000000000000000000000'; + signatureExpectedValue.innerHTML = '0x00000000000000000000000000000000000'; + signatureCheckValue.innerHTML = ''; + + if (measurementValue.method) + measurementValue.method.ViewMeasurement(measurementValue, + introDiv, + cryptoDataDiv, + bufferValue, + hashedBufferValue, + publicKeyValue, + signatureExpectedValue, + signatureCheckValue); + + else + { + doError("Unbekanntes Messdatensatzformat!"); + } + + //#endregion + + } + + //#endregion + + + + + + //#region showMeasurementCrypto(measurementValue) + + private async showMeasurementCrypto(measurementValue: IMeasurementValue) + { + + if (measurementValue == null) + return ' Ungültige Signatur'; + + switch (measurementValue.result.status) + { + + case VerificationResult.UnknownCTRFormat: + return ' Unbekanntes Transparenzdatenformat'; + + case VerificationResult.EnergyMeterNotFound: + return ' Ungültiger Energiezähler'; + + case VerificationResult.PublicKeyNotFound: + return ' Ungültiger Public Key'; + + case VerificationResult.InvalidPublicKey: + return ' Ungültiger Public Key'; + + case VerificationResult.InvalidSignature: + return ' Ungültige Signatur'; + + case VerificationResult.ValidSignature: + return ' Gültige Signatur'; + + + default: + return ' Ungültige Signatur'; + + } + + } + + //#endregion + + + + + //#region Global error handling... + + private doGlobalError2(result: ISessionCryptoResult, + text: String, + context?: any) + { + this.doGlobalError(result.message !== undefined ? result.message : text, + context); + } + + private doGlobalError(text: String, + context?: any) + { + + this.inputInfosDiv.style.display = 'flex'; + this.chargingSessionScreenDiv.style.display = 'none'; + this.chargingSessionScreenDiv.innerHTML = ''; + this.errorTextDiv.style.display = 'inline-block'; + this.errorTextDiv.innerHTML = ' ' + text; + + console.log(text); + console.log(context); + + } + + //#endregion + + + //#region Read and parse CTR file + + private readAndParseFile(file: File) { + + if (!file) + return; + + var reader = new FileReader(); + + reader.onload = (event) => { + try + { + this.detectContentFormat((event.target as any).result); + } + catch (exception) { + this.doGlobalError("Fehlerhafter Transparenzdatensatz!", exception); + } + } + + reader.onerror = (event) => { + this.doGlobalError("Fehlerhafter Transparenzdatensatz!", event); + } + + reader.readAsText(file, 'UTF-8'); + + } + + //#endregion + + //#region Process .chargy file extentions/associations opened via this app + + private readFileFromDisk(filename: string): void { + if (filename != null && filename.trim() != "" && filename != "." && filename[0] != '-') + { + try + { + let content = require('original-fs').readFileSync(filename.replace("file://", ""), 'utf-8'); + this.detectContentFormat(JSON.parse(content)); + } + catch (exception) { + this.doGlobalError("Fehlerhafter Transparenzdatensatz!", exception); + } + } + } + + //#endregion + +} + diff --git a/src/js/chargyInterfaces.ts b/src/js/chargyInterfaces.ts index 21aef92..0e0f821 100644 --- a/src/js/chargyInterfaces.ts +++ b/src/js/chargyInterfaces.ts @@ -17,6 +17,22 @@ /// +function IsAChargeTransparencyRecord(thing: IChargeTransparencyRecord|ISessionCryptoResult): thing is IChargeTransparencyRecord +{ + + let ctr = thing as IChargeTransparencyRecord; + + return ctr.begin !== undefined && + ctr.end !== undefined && + ctr.chargingSessions !== undefined; + +} + +function IsASessionCryptoResult(thing: IChargeTransparencyRecord|ISessionCryptoResult): thing is ISessionCryptoResult +{ + return (thing as ISessionCryptoResult).status !== undefined; +} + interface GetChargingPoolFunc { (Id: string): IChargingPool|null; } @@ -41,7 +57,6 @@ interface CheckMeterPublicKeySignatureFunc { signature: any|null): Promise; } - interface IChargeTransparencyRecord { "@id": string; @@ -56,6 +71,7 @@ interface IChargeTransparencyRecord chargingSessions: Array; eMobilityProviders: Array; mediationServices: Array; + verificatinResult?: ISessionCryptoResult; } interface IContract @@ -159,22 +175,29 @@ interface IChargingSession { "@id": string; "@context": string; + ctr?: IChargeTransparencyRecord; GUI: HTMLDivElement; begin: string; - end: string; + end?: string; description: {}; + chargingStationOperatorId: string; + chargingStationOperator?: IChargingStationOperator|null; chargingPoolId: string; chargingPool?: IChargingPool|null; chargingStationId: string; chargingStation?: IChargingStation|null; EVSEId: string; EVSE?: IEVSE|null; + meterId: string; + meter?: IMeter|null; + tariffId?: string; tariff?: ITariff|null; authorizationStart: IAuthorization; authorizationStop: IAuthorization; product: IChargingProduct; measurements: Array; method: ACrypt; + verificationResult?: ISessionCryptoResult; } interface IChargingProduct @@ -208,6 +231,7 @@ interface IMeasurement verifyChain: boolean; signatureInfos: ISignatureInfos; values: Array; + verificationResult?: ICryptoResult; } interface ISignatureInfos { @@ -227,6 +251,7 @@ interface IMeasurementValue { measurement: IMeasurement; method: ACrypt; + previousValue: IMeasurementValue; result: ICryptoResult; timestamp: string; @@ -237,6 +262,8 @@ interface IMeasurementValue interface ISessionCryptoResult { status: SessionVerificationResult; + message?: string; + exception?: any; } interface ICryptoResult @@ -290,6 +317,7 @@ interface IGeoLocation { enum SessionVerificationResult { UnknownSessionFormat, + InvalidSessionFormat, PublicKeyNotFound, InvalidPublicKey, InvalidSignature, diff --git a/tsconfig.json b/tsconfig.json index 4a32beb..496afd7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -37,6 +37,6 @@ }, "exclude": [ "node_modules" ], "files": [ - "src/js/chargy.ts" + "src/js/chargyApp.ts" ] } From eadbbe098426001a441192f37d8364c9510a9bdb Mon Sep 17 00:00:00 2001 From: Achim 'ahzf' Friedland Date: Fri, 20 Sep 2019 05:17:43 +0200 Subject: [PATCH 013/110] Small bugfix --- src/js/EMHCrypt01.ts | 4 +++- src/js/GDFCrypt01.ts | 2 ++ src/js/OCMFv1_0.ts | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/js/EMHCrypt01.ts b/src/js/EMHCrypt01.ts index b19a40b..84f20e9 100644 --- a/src/js/EMHCrypt01.ts +++ b/src/js/EMHCrypt01.ts @@ -206,6 +206,8 @@ class EMHCrypt01 extends ACrypt { return cryptoResult; } + measurementValue.method = this; + var buffer = new ArrayBuffer(320); var cryptoBuffer = new DataView(buffer); @@ -269,7 +271,7 @@ class EMHCrypt01 extends ACrypt { { return setResult(VerificationResult.ValidSignature); } - + return setResult(VerificationResult.InvalidSignature); } diff --git a/src/js/GDFCrypt01.ts b/src/js/GDFCrypt01.ts index 2ecd028..1b8d3a1 100644 --- a/src/js/GDFCrypt01.ts +++ b/src/js/GDFCrypt01.ts @@ -192,6 +192,8 @@ class GDFCrypt01 extends ACrypt { return cryptoResult; } + measurementValue.method = this; + var buffer = new ArrayBuffer(320); var cryptoBuffer = new DataView(buffer); diff --git a/src/js/OCMFv1_0.ts b/src/js/OCMFv1_0.ts index c7abad3..73a508e 100644 --- a/src/js/OCMFv1_0.ts +++ b/src/js/OCMFv1_0.ts @@ -207,6 +207,8 @@ class OCMFv1_0 extends ACrypt { return cryptoResult; } + measurementValue.method = this; + // { // // "FV": "1.0", From cb835c5f044c701a3f0df6c8c4a3474ae9c6d53e Mon Sep 17 00:00:00 2001 From: Achim 'ahzf' Friedland Date: Fri, 20 Sep 2019 05:29:40 +0200 Subject: [PATCH 014/110] Minor refactorings --- src/js/chargyApp.ts | 95 +++++++++++++++++++-------------------------- 1 file changed, 40 insertions(+), 55 deletions(-) diff --git a/src/js/chargyApp.ts b/src/js/chargyApp.ts index a996053..688a96e 100644 --- a/src/js/chargyApp.ts +++ b/src/js/chargyApp.ts @@ -538,6 +538,7 @@ class ChargyApp { //#endregion + //#region The Issue tracker var issueTracker = document.getElementById('issueTracker'); @@ -809,12 +810,6 @@ class ChargyApp { //#endregion - - - - - - //#region detectContentFormat(Content) private async detectContentFormat(Content: string) { @@ -1558,9 +1553,45 @@ class ChargyApp { "kWh"); - // Show signature status - let verificationStatusDiv = CreateDiv(MeasurementValueDiv, "verificationStatus", - await this.showMeasurementCrypto(measurementValue)); + //#region Show signature status + + let icon = ' Ungültige Signatur'; + + if (measurementValue.result) + switch (measurementValue.result.status) + { + + case VerificationResult.UnknownCTRFormat: + icon = ' Unbekanntes Transparenzdatenformat'; + break; + + case VerificationResult.EnergyMeterNotFound: + icon = ' Ungültiger Energiezähler'; + break; + + case VerificationResult.PublicKeyNotFound: + icon = ' Ungültiger Public Key'; + break; + + case VerificationResult.InvalidPublicKey: + icon = ' Ungültiger Public Key'; + break; + + case VerificationResult.InvalidSignature: + icon = ' Ungültige Signatur'; + break; + + case VerificationResult.ValidSignature: + icon = ' Gültige Signatur'; + break; + + } + + let verificationStatusDiv = CreateDiv(MeasurementValueDiv, + "verificationStatus", + icon); + + //#endregion previousValue = currentValue; @@ -1645,52 +1676,6 @@ class ChargyApp { //#endregion - - - - - //#region showMeasurementCrypto(measurementValue) - - private async showMeasurementCrypto(measurementValue: IMeasurementValue) - { - - if (measurementValue == null) - return ' Ungültige Signatur'; - - switch (measurementValue.result.status) - { - - case VerificationResult.UnknownCTRFormat: - return ' Unbekanntes Transparenzdatenformat'; - - case VerificationResult.EnergyMeterNotFound: - return ' Ungültiger Energiezähler'; - - case VerificationResult.PublicKeyNotFound: - return ' Ungültiger Public Key'; - - case VerificationResult.InvalidPublicKey: - return ' Ungültiger Public Key'; - - case VerificationResult.InvalidSignature: - return ' Ungültige Signatur'; - - case VerificationResult.ValidSignature: - return ' Gültige Signatur'; - - - default: - return ' Ungültige Signatur'; - - } - - } - - //#endregion - - - - //#region Global error handling... private doGlobalError2(result: ISessionCryptoResult, From 49319e06ba7a85ef8e386fa36b7a4c6e3d17abc0 Mon Sep 17 00:00:00 2001 From: Achim 'ahzf' Friedland Date: Fri, 20 Sep 2019 11:24:00 +0200 Subject: [PATCH 015/110] Minor refactorings and clean'ups --- src/js/ACrypt.ts | 69 +++++++------------ src/js/EMHCrypt01.ts | 50 +++++++------- src/js/GDFCrypt01.ts | 14 ++-- src/js/OCMFv1_0.ts | 26 ++++--- src/js/chargy.ts | 160 +++++-------------------------------------- src/js/chargyLib.ts | 25 +++++++ 6 files changed, 111 insertions(+), 233 deletions(-) diff --git a/src/js/ACrypt.ts b/src/js/ACrypt.ts index 364370a..21f77f0 100644 --- a/src/js/ACrypt.ts +++ b/src/js/ACrypt.ts @@ -20,36 +20,21 @@ abstract class ACrypt { - readonly description: string; - readonly GetMeter: GetMeterFunc; - readonly CheckMeterPublicKeySignature: CheckMeterPublicKeySignatureFunc; + readonly description: string; + readonly chargy: Chargy; + readonly elliptic: any; + readonly moment: any; - readonly elliptic: any; - readonly moment: any; + constructor(description: string, + chargy: Chargy) { - constructor(description: string, - GetMeter: GetMeterFunc, - CheckMeterPublicKeySignature: CheckMeterPublicKeySignatureFunc) { - - this.description = description; - this.GetMeter = GetMeter; - this.CheckMeterPublicKeySignature = CheckMeterPublicKeySignature; - - this.elliptic = require('elliptic'); - this.moment = require('moment'); + this.description = description; + this.chargy = chargy; + this.elliptic = require('elliptic'); + this.moment = require('moment'); } - protected pad(text: string|undefined, paddingValue: number) { - - if (text == null || text == undefined) - text = ""; - - return (text + Array(2*paddingValue).join('0')).substring(0, 2*paddingValue); - - }; - - protected CreateLine(id: string, value: string|number, valueHEX: string, @@ -65,7 +50,6 @@ abstract class ACrypt { } - protected AddToVisualBuffer(valueHEX: string, bufferDiv: HTMLDivElement, lineDiv: HTMLDivElement) @@ -93,28 +77,25 @@ abstract class ACrypt { } - async sha256(message: DataView) { - const hashBuffer = await crypto.subtle.digest('SHA-256', message); - const hashArray = Array.from(new Uint8Array(hashBuffer)); // convert hash to byte array - const hashHex = hashArray.map(b => ('00' + b.toString(16)).slice(-2)).join('').toLowerCase(); // convert bytes to hex string - return hashHex; - } + + //abstract SignChargingSession(...) abstract VerifyChargingSession(chargingSession: IChargingSession): Promise; - abstract SignMeasurement(measurementValue: IMeasurementValue, - privateKey: any, - publicKey: any): Promise; - abstract VerifyMeasurement(measurementValue: IMeasurementValue): Promise; + abstract SignMeasurement (measurementValue: IMeasurementValue, + privateKey: any, + publicKey: any): Promise; + + abstract VerifyMeasurement(measurementValue: IMeasurementValue): Promise; - abstract ViewMeasurement(measurementValue: IMeasurementValue, - introDiv: HTMLDivElement, - infoDiv: HTMLDivElement, - bufferValue: HTMLDivElement, - hashedBufferValue: HTMLDivElement, - publicKeyValue: HTMLDivElement, - signatureExpectedValue: HTMLDivElement, - signatureCheckValue: HTMLDivElement) : void; + abstract ViewMeasurement (measurementValue: IMeasurementValue, + introDiv: HTMLDivElement, + infoDiv: HTMLDivElement, + bufferValue: HTMLDivElement, + hashedBufferValue: HTMLDivElement, + publicKeyValue: HTMLDivElement, + signatureExpectedValue: HTMLDivElement, + signatureCheckValue: HTMLDivElement) : void; } diff --git a/src/js/EMHCrypt01.ts b/src/js/EMHCrypt01.ts index 84f20e9..85bb847 100644 --- a/src/js/EMHCrypt01.ts +++ b/src/js/EMHCrypt01.ts @@ -56,12 +56,10 @@ class EMHCrypt01 extends ACrypt { readonly curve = new this.elliptic.ec('p192'); - constructor(GetMeter: GetMeterFunc, - CheckMeterPublicKeySignature: CheckMeterPublicKeySignatureFunc) { + constructor(chargy: Chargy) { super("ECC secp192r1", - GetMeter, - CheckMeterPublicKeySignature); + chargy); } @@ -100,7 +98,7 @@ class EMHCrypt01 extends ACrypt { }; // Only the first 24 bytes/192 bits are used! - cryptoResult.sha256value = (await this.sha256(cryptoBuffer)).substring(0, 48); + cryptoResult.sha256value = (await sha256(cryptoBuffer)).substring(0, 48); cryptoResult.publicKey = publicKey.encode('hex'). toLowerCase(); @@ -242,10 +240,10 @@ class EMHCrypt01 extends ACrypt { }; // Only the first 24 bytes/192 bits are used! - cryptoResult.sha256value = (await this.sha256(cryptoBuffer)).substring(0, 48); + cryptoResult.sha256value = (await sha256(cryptoBuffer)).substring(0, 48); - const meter = this.GetMeter(measurementValue.measurement.energyMeterId); + const meter = this.chargy.GetMeter(measurementValue.measurement.energyMeterId); if (meter != null) { @@ -367,19 +365,19 @@ class EMHCrypt01 extends ACrypt { const cryptoSpan = introDiv.querySelector('#cryptoAlgorithm') as HTMLSpanElement; cryptoSpan.innerHTML = "EMHCrypt01 (" + this.description + ")"; - this.CreateLine("Zählernummer", measurementValue.measurement.energyMeterId, result.meterId || "", infoDiv, bufferValue); - this.CreateLine("Zeitstempel", parseUTC(measurementValue.timestamp), result.timestamp || "", infoDiv, bufferValue); + this.CreateLine("Zählernummer", measurementValue.measurement.energyMeterId, result.meterId || "", infoDiv, bufferValue); + this.CreateLine("Zeitstempel", parseUTC(measurementValue.timestamp), result.timestamp || "", infoDiv, bufferValue); this.CreateLine("Status", hex2bin(measurementValue.infoStatus) + " (" + measurementValue.infoStatus + " hex)
" + - this.DecodeStatus(measurementValue.infoStatus).join("
") + "
", result.infoStatus || "", infoDiv, bufferValue); - this.CreateLine("Sekundenindex", measurementValue.secondsIndex, result.secondsIndex || "", infoDiv, bufferValue); - this.CreateLine("Paginierungszähler", parseInt(measurementValue.paginationId, 16), result.paginationId || "", infoDiv, bufferValue); - this.CreateLine("OBIS-Kennzahl", parseOBIS(measurementValue.measurement.obis), result.obis || "", infoDiv, bufferValue); - this.CreateLine("Einheit (codiert)", measurementValue.measurement.unitEncoded, result.unitEncoded || "", infoDiv, bufferValue); - this.CreateLine("Skalierung", measurementValue.measurement.scale, result.scale || "", infoDiv, bufferValue); - this.CreateLine("Messwert", measurementValue.value + " Wh", result.value || "", infoDiv, bufferValue); - this.CreateLine("Logbuchindex", measurementValue.logBookIndex + " hex", result.logBookIndex || "", infoDiv, bufferValue); - this.CreateLine("Autorisierung", measurementValue.measurement.chargingSession.authorizationStart["@id"] + " hex", this.pad(result.authorizationStart, 128) || "", infoDiv, bufferValue); - this.CreateLine("Autorisierungszeitpunkt", parseUTC(measurementValue.measurement.chargingSession.authorizationStart.timestamp), this.pad(result.authorizationStartTimestamp, 151) || "", infoDiv, bufferValue); + this.DecodeStatus(measurementValue.infoStatus).join("
") + "", result.infoStatus || "", infoDiv, bufferValue); + this.CreateLine("Sekundenindex", measurementValue.secondsIndex, result.secondsIndex || "", infoDiv, bufferValue); + this.CreateLine("Paginierungszähler", parseInt(measurementValue.paginationId, 16), result.paginationId || "", infoDiv, bufferValue); + this.CreateLine("OBIS-Kennzahl", parseOBIS(measurementValue.measurement.obis), result.obis || "", infoDiv, bufferValue); + this.CreateLine("Einheit (codiert)", measurementValue.measurement.unitEncoded, result.unitEncoded || "", infoDiv, bufferValue); + this.CreateLine("Skalierung", measurementValue.measurement.scale, result.scale || "", infoDiv, bufferValue); + this.CreateLine("Messwert", measurementValue.value + " Wh", result.value || "", infoDiv, bufferValue); + this.CreateLine("Logbuchindex", measurementValue.logBookIndex + " hex", result.logBookIndex || "", infoDiv, bufferValue); + this.CreateLine("Autorisierung", measurementValue.measurement.chargingSession.authorizationStart["@id"] + " hex", pad(result.authorizationStart, 128) || "", infoDiv, bufferValue); + this.CreateLine("Autorisierungszeitpunkt", parseUTC(measurementValue.measurement.chargingSession.authorizationStart.timestamp), pad(result.authorizationStartTimestamp, 151) || "", infoDiv, bufferValue); // Buffer @@ -418,13 +416,13 @@ class EMHCrypt01 extends ACrypt { { let signatureDiv = publicKeyValue.parentElement!.children[3].appendChild(document.createElement('div')); - signatureDiv.innerHTML = await this.CheckMeterPublicKeySignature(measurementValue.measurement.chargingSession.chargingStation, - measurementValue.measurement.chargingSession.EVSE, - //@ts-ignore - measurementValue.measurement.chargingSession.EVSE.meters[0], - //@ts-ignore - measurementValue.measurement.chargingSession.EVSE.meters[0].publicKeys[0], - signature); + signatureDiv.innerHTML = await this.chargy.CheckMeterPublicKeySignature(measurementValue.measurement.chargingSession.chargingStation, + measurementValue.measurement.chargingSession.EVSE, + //@ts-ignore + measurementValue.measurement.chargingSession.EVSE.meters[0], + //@ts-ignore + measurementValue.measurement.chargingSession.EVSE.meters[0].publicKeys[0], + signature); } catch (exception) diff --git a/src/js/GDFCrypt01.ts b/src/js/GDFCrypt01.ts index 1b8d3a1..0c21346 100644 --- a/src/js/GDFCrypt01.ts +++ b/src/js/GDFCrypt01.ts @@ -45,14 +45,12 @@ interface IGDFCrypt01Result extends ICryptoResult class GDFCrypt01 extends ACrypt { - readonly curve = new this.elliptic.ec('p256'); + readonly curve = new this.elliptic.ec('p256'); - constructor(GetMeter: GetMeterFunc, - CheckMeterPublicKeySignature: CheckMeterPublicKeySignatureFunc) { + constructor(chargy: Chargy) { super("ECC secp256r1", - GetMeter, - CheckMeterPublicKeySignature); + chargy); } @@ -86,7 +84,7 @@ class GDFCrypt01 extends ACrypt { authorizationStartTimestamp: SetTimestamp(cryptoBuffer, measurementValue.measurement.chargingSession.authorizationStart.timestamp, 169) }; - cryptoResult.sha256value = await this.sha256(cryptoBuffer); + cryptoResult.sha256value = await sha256(cryptoBuffer); cryptoResult.publicKey = publicKey.encode('hex'). toLowerCase(); @@ -223,10 +221,10 @@ class GDFCrypt01 extends ACrypt { s: signatureExpected.s }; - cryptoResult.sha256value = await this.sha256(cryptoBuffer); + cryptoResult.sha256value = await sha256(cryptoBuffer); - const meter = this.GetMeter(measurementValue.measurement.energyMeterId); + const meter = this.chargy.GetMeter(measurementValue.measurement.energyMeterId); if (meter != null) { diff --git a/src/js/OCMFv1_0.ts b/src/js/OCMFv1_0.ts index 73a508e..77c66a7 100644 --- a/src/js/OCMFv1_0.ts +++ b/src/js/OCMFv1_0.ts @@ -57,12 +57,10 @@ class OCMFv1_0 extends ACrypt { readonly curve = new this.elliptic.ec('p256'); - constructor(GetMeter: GetMeterFunc, - CheckMeterPublicKeySignature: CheckMeterPublicKeySignatureFunc) { + constructor(chargy: Chargy) { super("ECC secp192r1", - GetMeter, - CheckMeterPublicKeySignature); + chargy); } @@ -101,7 +99,7 @@ class OCMFv1_0 extends ACrypt { }; // Only the first 24 bytes/192 bits are used! - cryptoResult.sha256value = (await this.sha256(cryptoBuffer)).substring(0, 48); + cryptoResult.sha256value = (await sha256(cryptoBuffer)).substring(0, 48); cryptoResult.publicKey = publicKey.encode('hex'). toLowerCase(); @@ -410,8 +408,8 @@ class OCMFv1_0 extends ACrypt { this.CreateLine("Skalierung", measurementValue.measurement.scale, result.scale || "", infoDiv, bufferValue); this.CreateLine("Messwert", measurementValue.value + " Wh", result.value || "", infoDiv, bufferValue); this.CreateLine("Logbuchindex", measurementValue.logBookIndex + " hex", result.logBookIndex || "", infoDiv, bufferValue); - this.CreateLine("Autorisierung", measurementValue.measurement.chargingSession.authorizationStart["@id"] + " hex", this.pad(result.authorizationStart, 128) || "", infoDiv, bufferValue); - this.CreateLine("Autorisierungszeitpunkt", parseUTC(measurementValue.measurement.chargingSession.authorizationStart.timestamp), this.pad(result.authorizationStartTimestamp, 151) || "", infoDiv, bufferValue); + this.CreateLine("Autorisierung", measurementValue.measurement.chargingSession.authorizationStart["@id"] + " hex", pad(result.authorizationStart, 128) || "", infoDiv, bufferValue); + this.CreateLine("Autorisierungszeitpunkt", parseUTC(measurementValue.measurement.chargingSession.authorizationStart.timestamp), pad(result.authorizationStartTimestamp, 151) || "", infoDiv, bufferValue); // Buffer @@ -450,13 +448,13 @@ class OCMFv1_0 extends ACrypt { { let signatureDiv = publicKeyValue.parentElement!.children[3].appendChild(document.createElement('div')); - signatureDiv.innerHTML = await this.CheckMeterPublicKeySignature(measurementValue.measurement.chargingSession.chargingStation, - measurementValue.measurement.chargingSession.EVSE, - //@ts-ignore - measurementValue.measurement.chargingSession.EVSE.meters[0], - //@ts-ignore - measurementValue.measurement.chargingSession.EVSE.meters[0].publicKeys[0], - signature); + signatureDiv.innerHTML = await this.chargy.CheckMeterPublicKeySignature(measurementValue.measurement.chargingSession.chargingStation, + measurementValue.measurement.chargingSession.EVSE, + //@ts-ignore + measurementValue.measurement.chargingSession.EVSE.meters[0], + //@ts-ignore + measurementValue.measurement.chargingSession.EVSE.meters[0].publicKeys[0], + signature); } catch (exception) diff --git a/src/js/chargy.ts b/src/js/chargy.ts index f215ba1..9e648f8 100644 --- a/src/js/chargy.ts +++ b/src/js/chargy.ts @@ -31,9 +31,10 @@ class Chargy { private chargingStations = new Array(); private EVSEs = new Array(); private meters = new Array(); + private chargingSessions = new Array(); + private eMobilityProviders = new Array(); private mediationServices = new Array(); - private chargingSessions = new Array(); public currentCTR = {} as IChargeTransparencyRecord; @@ -99,21 +100,6 @@ class Chargy { //#endregion - async sha256(message: string|DataView) { - - let hashBuffer = null; - - if (typeof message === 'string') - hashBuffer = await crypto.subtle.digest('SHA-256', Buffer.from(message, 'utf8')); - else - hashBuffer = await crypto.subtle.digest('SHA-256', message); - - const hashArray = Array.from(new Uint8Array(hashBuffer)); // convert hash to byte array - const hashHex = hashArray.map(b => ('00' + b.toString(16)).slice(-2)).join('').toLowerCase(); // convert bytes to hex string - - return hashHex; - - } //#region CheckMeterPublicKeySignature(...) @@ -174,8 +160,7 @@ class Chargy { //ToDo: Checking the timestamp might be usefull! - var Input = JSON.stringify(toCheck); - var sha256value = await this.sha256(Input); + var sha256value = await sha256(JSON.stringify(toCheck)); //this.crypt.createHash('sha256'). // update(Input, 'utf8'). // digest('hex'); @@ -201,8 +186,6 @@ class Chargy { //#endregion - - //#region detectContentFormat(Content) public async detectContentFormat(Content: string): Promise { @@ -346,9 +329,6 @@ class Chargy { //#endregion - - - //#region processChargeTransparencyRecord(CTR) public async processChargeTransparencyRecord(CTR: IChargeTransparencyRecord): Promise @@ -361,9 +341,10 @@ class Chargy { this.chargingStations = []; this.EVSEs = []; this.meters = []; + this.chargingSessions = []; + this.eMobilityProviders = []; this.mediationServices = []; - this.chargingSessions = []; this.currentCTR = {} as IChargeTransparencyRecord; @@ -374,7 +355,7 @@ class Chargy { try { - //#region Process operators, pools, stations, evse, tariffs, ... + //#region Process operators (pools, stations, evses, tariffs, ...) if (CTR.chargingStationOperators) { @@ -516,6 +497,10 @@ class Chargy { } + //#endregion + + //#region Process pools ( stations, evses, tariffs, ...) + if (CTR.chargingPools) { for (var chargingPool of CTR.chargingPools) @@ -553,6 +538,10 @@ class Chargy { } + //#endregion + + //#region Process stations ( evses, tariffs, ...) + if (CTR.chargingStations) { for (var chargingStation of CTR.chargingStations) @@ -611,60 +600,16 @@ class Chargy { //#endregion - //#region Process charging sessions... - if (CTR.chargingSessions) { for (let chargingSession of CTR.chargingSessions) { - - chargingSession.ctr = CTR; - chargingSession.verificationResult = await this.processChargingSession(chargingSession); - - try - { - - // if (chargingSession.measurements) - // { - // for (var measurement of chargingSession.measurements) - // { - - // measurement.chargingSession = chargingSession; - - // // var meter = this.GetMeter(measurement.energyMeterId); - - // if (measurement.values && measurement.values.length > 0) - // { - - // //@ts-ignore - // let currentValue: IMeasurementValue = null; - - // for (let measurementValue of measurement.values) - // { - // measurementValue.measurement = measurement; - // measurementValue.previousValue = currentValue; - // measurementValue.result = await this.verifyMeasurementCryptoDetails(measurementValue); - // currentValue = measurementValue; - // } - - // } - - // } - // } - - } - catch (exception) - { - console.log("Could not process charging session details: " + exception); - } - + chargingSession.ctr = CTR; + chargingSession.verificationResult = await this.processChargingSession(chargingSession); this.chargingSessions.push(chargingSession); - } } - //#endregion - this.currentCTR = CTR; return CTR; @@ -682,7 +627,6 @@ class Chargy { //#endregion - //#region processChargingSession(chargingSession) public async processChargingSession(chargingSession: IChargingSession) : Promise @@ -711,15 +655,15 @@ class Chargy { { case "https://open.charging.cloud/contexts/SessionSignatureFormats/GDFCrypt01+json": - chargingSession.method = new GDFCrypt01(this.GetMeter, await this.CheckMeterPublicKeySignature); + chargingSession.method = new GDFCrypt01(this); return await chargingSession.method.VerifyChargingSession(chargingSession); case "https://open.charging.cloud/contexts/SessionSignatureFormats/EMHCrypt01+json": - chargingSession.method = new EMHCrypt01(this.GetMeter, await this.CheckMeterPublicKeySignature); + chargingSession.method = new EMHCrypt01(this); return await chargingSession.method.VerifyChargingSession(chargingSession); case "https://open.charging.cloud/contexts/SessionSignatureFormats/OCMFv1.0+json": - chargingSession.method = new OCMFv1_0 (this.GetMeter, await this.CheckMeterPublicKeySignature); + chargingSession.method = new OCMFv1_0 (this); return await chargingSession.method.VerifyChargingSession(chargingSession); default: @@ -733,70 +677,4 @@ class Chargy { //#endregion - //#region verifyMeasurementCryptoDetails(measurementValue) - - // private async verifyMeasurementCryptoDetails(measurementValue: IMeasurementValue) : Promise - // { - - // var result: ICryptoResult = { - // status: VerificationResult.UnknownCTRFormat - // }; - - // if (measurementValue == null || - // measurementValue.measurement == null) - // { - // return result; - // } - - // switch (measurementValue.measurement["@context"]) - // { - - // case "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/GDFCrypt01+json": - // measurementValue.method = new GDFCrypt01(this.GetMeter, this.CheckMeterPublicKeySignature); - // return measurementValue.method.VerifyMeasurement(measurementValue); - - // case "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/EMHCrypt01+json": - // if (measurementValue.measurement.chargingSession.method != null) - // { - - // measurementValue.method = measurementValue.measurement.chargingSession.method; - - // if (measurementValue.result == null) - // return measurementValue.method.VerifyMeasurement(measurementValue); - - // return measurementValue.result; - - // } - - // measurementValue.method = new EMHCrypt01(this.GetMeter, this.CheckMeterPublicKeySignature); - // return measurementValue.method.VerifyMeasurement(measurementValue); - - // case "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/OCMFv1.0+json": - // if (measurementValue.measurement.chargingSession.method != null) - // { - - // measurementValue.method = measurementValue.measurement.chargingSession.method; - - // if (measurementValue.result == null) - // return measurementValue.method.VerifyMeasurement(measurementValue); - - // return measurementValue.result; - - // } - - // measurementValue.method = new OCMFv1_0(this.GetMeter, this.CheckMeterPublicKeySignature); - // return measurementValue.method.VerifyMeasurement(measurementValue); - - // default: - // return result; - - // } - - // } - - //#endregion - - - - } diff --git a/src/js/chargyLib.ts b/src/js/chargyLib.ts index 87680e0..c5b7e55 100644 --- a/src/js/chargyLib.ts +++ b/src/js/chargyLib.ts @@ -418,3 +418,28 @@ String.prototype.isNullOrEmpty = function() { String.prototype.isNotNullOrEmpty = function() { return typeof this === "string" && this.length > 0; } + +function pad(text: string|undefined, paddingValue: number) { + + if (text == null || text == undefined) + text = ""; + + return (text + Array(2*paddingValue).join('0')).substring(0, 2*paddingValue); + +}; + +async function sha256(message: string|DataView) { + + let hashBuffer = null; + + if (typeof message === 'string') + hashBuffer = await crypto.subtle.digest('SHA-256', Buffer.from(message, 'utf8')); + else + hashBuffer = await crypto.subtle.digest('SHA-256', message); + + const hashArray = Array.from(new Uint8Array(hashBuffer)); // convert hash to byte array + const hashHex = hashArray.map(b => ('00' + b.toString(16)).slice(-2)).join('').toLowerCase(); // convert bytes to hex string + + return hashHex; + +} From c78004e232a54137c36167eb583f40b197352f56 Mon Sep 17 00:00:00 2001 From: Achim 'ahzf' Friedland Date: Fri, 20 Sep 2019 11:41:35 +0200 Subject: [PATCH 016/110] More minor refactorings and clean'ups --- src/js/ACrypt.ts | 45 +++++---- src/js/EMHCrypt01.ts | 218 +++++++++++++++++++++++-------------------- src/js/GDFCrypt01.ts | 124 ++++++++++++------------ src/js/OCMFv1_0.ts | 124 ++++++++++++------------ src/js/chargy.ts | 4 +- 5 files changed, 276 insertions(+), 239 deletions(-) diff --git a/src/js/ACrypt.ts b/src/js/ACrypt.ts index 21f77f0..382d740 100644 --- a/src/js/ACrypt.ts +++ b/src/js/ACrypt.ts @@ -20,21 +20,23 @@ abstract class ACrypt { + //#region Data + readonly description: string; readonly chargy: Chargy; - readonly elliptic: any; - readonly moment: any; + + //#endregion constructor(description: string, chargy: Chargy) { this.description = description; this.chargy = chargy; - this.elliptic = require('elliptic'); - this.moment = require('moment'); } + //#region Protected methods + protected CreateLine(id: string, value: string|number, valueHEX: string, @@ -77,25 +79,32 @@ abstract class ACrypt { } + //#endregion + + + abstract GenerateKeyPair(): any; + + + + abstract SignChargingSession (chargingSession: IChargingSession, + privateKey: any): Promise; - //abstract SignChargingSession(...) + abstract VerifyChargingSession(chargingSession: IChargingSession): Promise; - abstract VerifyChargingSession(chargingSession: IChargingSession): Promise; - abstract SignMeasurement (measurementValue: IMeasurementValue, - privateKey: any, - publicKey: any): Promise; + abstract SignMeasurement (measurementValue: IMeasurementValue, + privateKey: any): Promise; - abstract VerifyMeasurement(measurementValue: IMeasurementValue): Promise; + abstract VerifyMeasurement (measurementValue: IMeasurementValue): Promise; - abstract ViewMeasurement (measurementValue: IMeasurementValue, - introDiv: HTMLDivElement, - infoDiv: HTMLDivElement, - bufferValue: HTMLDivElement, - hashedBufferValue: HTMLDivElement, - publicKeyValue: HTMLDivElement, - signatureExpectedValue: HTMLDivElement, - signatureCheckValue: HTMLDivElement) : void; + abstract ViewMeasurement (measurementValue: IMeasurementValue, + introDiv: HTMLDivElement, + infoDiv: HTMLDivElement, + bufferValue: HTMLDivElement, + hashedBufferValue: HTMLDivElement, + publicKeyValue: HTMLDivElement, + signatureExpectedValue: HTMLDivElement, + signatureCheckValue: HTMLDivElement) : void; } diff --git a/src/js/EMHCrypt01.ts b/src/js/EMHCrypt01.ts index 85bb847..b925cd9 100644 --- a/src/js/EMHCrypt01.ts +++ b/src/js/EMHCrypt01.ts @@ -54,7 +54,7 @@ interface IEMHCrypt01Result extends ICryptoResult class EMHCrypt01 extends ACrypt { - readonly curve = new this.elliptic.ec('p192'); + readonly curve = new this.chargy.elliptic.ec('p192'); constructor(chargy: Chargy) { @@ -73,9 +73,70 @@ class EMHCrypt01 extends ACrypt { // publicKeyHEX = publicKey.encode('hex').toLowerCase(); } - async SignMeasurement(measurementValue: IEMHMeasurementValue, - privateKey: any, - publicKey: any): Promise + + async SignChargingSession (chargingSession: IChargingSession, + privateKey: any): Promise + { + + return { + status: SessionVerificationResult.UnknownSessionFormat + } + + } + + async VerifyChargingSession(chargingSession: IChargingSession): Promise + { + + var sessionResult = SessionVerificationResult.UnknownSessionFormat; + + if (chargingSession.measurements) + { + for (var measurement of chargingSession.measurements) + { + + measurement.chargingSession = chargingSession; + + // Must include at least two measurements (start & stop) + if (measurement.values && measurement.values.length > 1) + { + + // Validate... + for (var measurementValue of measurement.values) + { + measurementValue.measurement = measurement; + await this.VerifyMeasurement(measurementValue as IEMHMeasurementValue); + } + + + // Find an overall result... + sessionResult = SessionVerificationResult.ValidSignature; + + for (var measurementValue of measurement.values) + { + if (sessionResult == SessionVerificationResult.ValidSignature && + measurementValue.result.status != VerificationResult.ValidSignature) + { + sessionResult = SessionVerificationResult.InvalidSignature; + } + } + + } + + else + sessionResult = SessionVerificationResult.AtLeastTwoMeasurementsExpected; + + } + } + + return { + status: sessionResult + } + + } + + + async SignMeasurement (measurementValue: IEMHMeasurementValue, + privateKey: any): Promise { var buffer = new ArrayBuffer(320); @@ -100,8 +161,8 @@ class EMHCrypt01 extends ACrypt { // Only the first 24 bytes/192 bits are used! cryptoResult.sha256value = (await sha256(cryptoBuffer)).substring(0, 48); - cryptoResult.publicKey = publicKey.encode('hex'). - toLowerCase(); + // cryptoResult.publicKey = publicKey.encode('hex'). + // toLowerCase(); const signature = this.curve.keyFromPrivate(privateKey.toString('hex')). sign(cryptoResult.sha256value); @@ -142,58 +203,6 @@ class EMHCrypt01 extends ACrypt { } - - async VerifyChargingSession(chargingSession: IChargingSession): Promise - { - - var sessionResult = SessionVerificationResult.UnknownSessionFormat; - - if (chargingSession.measurements) - { - for (var measurement of chargingSession.measurements) - { - - measurement.chargingSession = chargingSession; - - // Must include at least two measurements (start & stop) - if (measurement.values && measurement.values.length > 1) - { - - // Validate... - for (var measurementValue of measurement.values) - { - measurementValue.measurement = measurement; - await this.VerifyMeasurement(measurementValue as IEMHMeasurementValue); - } - - - // Find an overall result... - sessionResult = SessionVerificationResult.ValidSignature; - - for (var measurementValue of measurement.values) - { - if (sessionResult == SessionVerificationResult.ValidSignature && - measurementValue.result.status != VerificationResult.ValidSignature) - { - sessionResult = SessionVerificationResult.InvalidSignature; - } - } - - } - - else - sessionResult = SessionVerificationResult.AtLeastTwoMeasurementsExpected; - - } - } - - return { - status: sessionResult - } ; - - } - - async VerifyMeasurement(measurementValue: IEMHMeasurementValue): Promise { @@ -306,51 +315,7 @@ class EMHCrypt01 extends ACrypt { } - - private DecodeStatus(statusValue: string) : Array - { - - let statusArray:string[] = []; - - try - { - - let status = parseInt(statusValue); - - if ((status & 1) == 1) - statusArray.push("Fehler erkannt"); - - if ((status & 2) == 2) - statusArray.push("Synchrone Messwertübermittlung"); - - // Bit 3 is reserved! - - if ((status & 8) == 8) - statusArray.push("System-Uhr ist synchron"); - else - statusArray.push("System-Uhr ist nicht synchron"); - - if ((status & 16) == 16) - statusArray.push("Rücklaufsperre aktiv"); - - if ((status & 32) == 32) - statusArray.push("Energierichtung -A"); - - if ((status & 64) == 64) - statusArray.push("Magnetfeld erkannt"); - - } - catch (exception) - { - statusArray.push("Invalid status!"); - } - - return statusArray; - - } - - - async ViewMeasurement(measurementValue: IEMHMeasurementValue, + async ViewMeasurement (measurementValue: IEMHMeasurementValue, introDiv: HTMLDivElement, infoDiv: HTMLDivElement, bufferValue: HTMLDivElement, @@ -482,4 +447,51 @@ class EMHCrypt01 extends ACrypt { } + + //#region Helper methods + + private DecodeStatus(statusValue: string) : Array + { + + let statusArray:string[] = []; + + try + { + + let status = parseInt(statusValue); + + if ((status & 1) == 1) + statusArray.push("Fehler erkannt"); + + if ((status & 2) == 2) + statusArray.push("Synchrone Messwertübermittlung"); + + // Bit 3 is reserved! + + if ((status & 8) == 8) + statusArray.push("System-Uhr ist synchron"); + else + statusArray.push("System-Uhr ist nicht synchron"); + + if ((status & 16) == 16) + statusArray.push("Rücklaufsperre aktiv"); + + if ((status & 32) == 32) + statusArray.push("Energierichtung -A"); + + if ((status & 64) == 64) + statusArray.push("Magnetfeld erkannt"); + + } + catch (exception) + { + statusArray.push("Invalid status!"); + } + + return statusArray; + + } + + //#endregion + } \ No newline at end of file diff --git a/src/js/GDFCrypt01.ts b/src/js/GDFCrypt01.ts index 0c21346..93c80a9 100644 --- a/src/js/GDFCrypt01.ts +++ b/src/js/GDFCrypt01.ts @@ -45,7 +45,7 @@ interface IGDFCrypt01Result extends ICryptoResult class GDFCrypt01 extends ACrypt { - readonly curve = new this.elliptic.ec('p256'); + readonly curve = new this.chargy.elliptic.ec('p256'); constructor(chargy: Chargy) { @@ -64,9 +64,70 @@ class GDFCrypt01 extends ACrypt { // publicKeyHEX = publicKey.encode('hex').toLowerCase(); } + + async SignChargingSession (chargingSession: IChargingSession, + privateKey: any): Promise + { + + return { + status: SessionVerificationResult.UnknownSessionFormat + } + + } + + async VerifyChargingSession(chargingSession: IChargingSession): Promise + { + + var sessionResult = SessionVerificationResult.UnknownSessionFormat; + + if (chargingSession.measurements) + { + for (var measurement of chargingSession.measurements) + { + + measurement.chargingSession = chargingSession; + + // Must include at least two measurements (start & stop) + if (measurement.values && measurement.values.length > 1) + { + + // Validate... + for (var measurementValue of measurement.values) + { + measurementValue.measurement = measurement; + await this.VerifyMeasurement(measurementValue as IGDFMeasurementValue); + } + + + // Find an overall result... + sessionResult = SessionVerificationResult.ValidSignature; + + for (var measurementValue of measurement.values) + { + if (sessionResult == SessionVerificationResult.ValidSignature && + measurementValue.result.status != VerificationResult.ValidSignature) + { + sessionResult = SessionVerificationResult.InvalidSignature; + } + } + + } + + else + sessionResult = SessionVerificationResult.AtLeastTwoMeasurementsExpected; + + } + } + + return { + status: sessionResult + } ; + + } + + async SignMeasurement(measurementValue: IGDFMeasurementValue, - privateKey: any, - publicKey: any): Promise + privateKey: any): Promise { var buffer = new ArrayBuffer(320); @@ -86,8 +147,8 @@ class GDFCrypt01 extends ACrypt { cryptoResult.sha256value = await sha256(cryptoBuffer); - cryptoResult.publicKey = publicKey.encode('hex'). - toLowerCase(); + // cryptoResult.publicKey = publicKey.encode('hex'). + // toLowerCase(); const signature = this.curve.keyFromPrivate(privateKey.toString('hex')). sign(cryptoResult.sha256value); @@ -128,58 +189,6 @@ class GDFCrypt01 extends ACrypt { } - - async VerifyChargingSession(chargingSession: IChargingSession): Promise - { - - var sessionResult = SessionVerificationResult.UnknownSessionFormat; - - if (chargingSession.measurements) - { - for (var measurement of chargingSession.measurements) - { - - measurement.chargingSession = chargingSession; - - // Must include at least two measurements (start & stop) - if (measurement.values && measurement.values.length > 1) - { - - // Validate... - for (var measurementValue of measurement.values) - { - measurementValue.measurement = measurement; - await this.VerifyMeasurement(measurementValue as IGDFMeasurementValue); - } - - - // Find an overall result... - sessionResult = SessionVerificationResult.ValidSignature; - - for (var measurementValue of measurement.values) - { - if (sessionResult == SessionVerificationResult.ValidSignature && - measurementValue.result.status != VerificationResult.ValidSignature) - { - sessionResult = SessionVerificationResult.InvalidSignature; - } - } - - } - - else - sessionResult = SessionVerificationResult.AtLeastTwoMeasurementsExpected; - - } - } - - return { - status: sessionResult - } ; - - } - - async VerifyMeasurement(measurementValue: IGDFMeasurementValue): Promise { @@ -286,7 +295,6 @@ class GDFCrypt01 extends ACrypt { } - async ViewMeasurement(measurementValue: IMeasurementValue, introDiv: HTMLDivElement, infoDiv: HTMLDivElement, diff --git a/src/js/OCMFv1_0.ts b/src/js/OCMFv1_0.ts index 77c66a7..84fcd99 100644 --- a/src/js/OCMFv1_0.ts +++ b/src/js/OCMFv1_0.ts @@ -55,7 +55,7 @@ interface IOCMFv1_0Result extends ICryptoResult class OCMFv1_0 extends ACrypt { - readonly curve = new this.elliptic.ec('p256'); + readonly curve = new this.chargy.elliptic.ec('p256'); constructor(chargy: Chargy) { @@ -74,9 +74,70 @@ class OCMFv1_0 extends ACrypt { // publicKeyHEX = publicKey.encode('hex').toLowerCase(); } + + async SignChargingSession (chargingSession: IChargingSession, + privateKey: any): Promise + { + + return { + status: SessionVerificationResult.UnknownSessionFormat + } + + } + + async VerifyChargingSession(chargingSession: IChargingSession): Promise + { + + var sessionResult = SessionVerificationResult.UnknownSessionFormat; + + if (chargingSession.measurements) + { + for (var measurement of chargingSession.measurements) + { + + measurement.chargingSession = chargingSession; + + // Must include at least two measurements (start & stop) + if (measurement.values && measurement.values.length > 1) + { + + // Validate... + for (var measurementValue of measurement.values) + { + measurementValue.measurement = measurement; + await this.VerifyMeasurement(measurementValue as IOCMFv1_0MeasurementValue); + } + + + // Find an overall result... + sessionResult = SessionVerificationResult.ValidSignature; + + for (var measurementValue of measurement.values) + { + if (sessionResult == SessionVerificationResult.ValidSignature && + measurementValue.result.status != VerificationResult.ValidSignature) + { + sessionResult = SessionVerificationResult.InvalidSignature; + } + } + + } + + else + sessionResult = SessionVerificationResult.AtLeastTwoMeasurementsExpected; + + } + } + + return { + status: sessionResult + } ; + + } + + async SignMeasurement(measurementValue: IOCMFv1_0MeasurementValue, - privateKey: any, - publicKey: any): Promise + privateKey: any): Promise { var buffer = new ArrayBuffer(320); @@ -101,8 +162,8 @@ class OCMFv1_0 extends ACrypt { // Only the first 24 bytes/192 bits are used! cryptoResult.sha256value = (await sha256(cryptoBuffer)).substring(0, 48); - cryptoResult.publicKey = publicKey.encode('hex'). - toLowerCase(); + // cryptoResult.publicKey = publicKey.encode('hex'). + // toLowerCase(); const signature = this.curve.keyFromPrivate(privateKey.toString('hex')). sign(cryptoResult.sha256value); @@ -143,58 +204,6 @@ class OCMFv1_0 extends ACrypt { } - - async VerifyChargingSession(chargingSession: IChargingSession): Promise - { - - var sessionResult = SessionVerificationResult.UnknownSessionFormat; - - if (chargingSession.measurements) - { - for (var measurement of chargingSession.measurements) - { - - measurement.chargingSession = chargingSession; - - // Must include at least two measurements (start & stop) - if (measurement.values && measurement.values.length > 1) - { - - // Validate... - for (var measurementValue of measurement.values) - { - measurementValue.measurement = measurement; - await this.VerifyMeasurement(measurementValue as IOCMFv1_0MeasurementValue); - } - - - // Find an overall result... - sessionResult = SessionVerificationResult.ValidSignature; - - for (var measurementValue of measurement.values) - { - if (sessionResult == SessionVerificationResult.ValidSignature && - measurementValue.result.status != VerificationResult.ValidSignature) - { - sessionResult = SessionVerificationResult.InvalidSignature; - } - } - - } - - else - sessionResult = SessionVerificationResult.AtLeastTwoMeasurementsExpected; - - } - } - - return { - status: sessionResult - } ; - - } - - async VerifyMeasurement(measurementValue: IOCMFv1_0MeasurementValue): Promise { @@ -382,7 +391,6 @@ class OCMFv1_0 extends ACrypt { } - async ViewMeasurement(measurementValue: IOCMFv1_0MeasurementValue, introDiv: HTMLDivElement, infoDiv: HTMLDivElement, diff --git a/src/js/chargy.ts b/src/js/chargy.ts index 9e648f8..44eabfc 100644 --- a/src/js/chargy.ts +++ b/src/js/chargy.ts @@ -23,8 +23,8 @@ class Chargy { //#region Data - private elliptic: any; - private moment: any; + public elliptic: any; + public moment: any; private chargingStationOperators = new Array(); private chargingPools = new Array(); From 83ae98d047b212543640c9a3129644a438718c72 Mon Sep 17 00:00:00 2001 From: Achim 'ahzf' Friedland Date: Fri, 20 Sep 2019 11:48:37 +0200 Subject: [PATCH 017/110] Even more minor refactorings and clean'ups --- src/js/chargy.ts | 4 +- src/js/chargyApp.ts | 130 ++++++++++++++++++++++---------------------- 2 files changed, 66 insertions(+), 68 deletions(-) diff --git a/src/js/chargy.ts b/src/js/chargy.ts index 44eabfc..97546fd 100644 --- a/src/js/chargy.ts +++ b/src/js/chargy.ts @@ -186,9 +186,9 @@ class Chargy { //#endregion - //#region detectContentFormat(Content) + //#region detectAndConvertContentFormat(Content) - public async detectContentFormat(Content: string): Promise { + public async detectAndConvertContentFormat(Content: string): Promise { //#region Clean data diff --git a/src/js/chargyApp.ts b/src/js/chargyApp.ts index 688a96e..635ab22 100644 --- a/src/js/chargyApp.ts +++ b/src/js/chargyApp.ts @@ -104,23 +104,23 @@ class ChargyApp { { case "win32": - this.calcSHA512Hash('Chargy Transparenzsoftware.exe', hash => this.exe_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); - this.calcSHA512Hash(this.path.join('resources', 'app.asar'), hash => this.app_asar_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); - this.calcSHA512Hash(this.path.join('resources', 'electron.asar'), hash => this.electron_asar_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); + this.calcSHA512FileHash('Chargy Transparenzsoftware.exe', hash => this.exe_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); + this.calcSHA512FileHash(this.path.join('resources', 'app.asar'), hash => this.app_asar_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); + this.calcSHA512FileHash(this.path.join('resources', 'electron.asar'), hash => this.electron_asar_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); break; case "linux": case "freebsd": case "openbsd": - this.calcSHA512Hash('/opt/Chargy\ Transparenzsoftware/chargytransparenzsoftware', hash => this.exe_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); - this.calcSHA512Hash('/opt/Chargy\ Transparenzsoftware/resources/app.asar', hash => this.app_asar_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); - this.calcSHA512Hash('/opt/Chargy\ Transparenzsoftware/resources/electron.asar', hash => this.electron_asar_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); + this.calcSHA512FileHash('/opt/Chargy\ Transparenzsoftware/chargytransparenzsoftware', hash => this.exe_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); + this.calcSHA512FileHash('/opt/Chargy\ Transparenzsoftware/resources/app.asar', hash => this.app_asar_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); + this.calcSHA512FileHash('/opt/Chargy\ Transparenzsoftware/resources/electron.asar', hash => this.electron_asar_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); break; case "darwin": - this.calcSHA512Hash('/Applications/Chargy\ Transparenzsoftware.app/Contents/MacOS/Chargy Transparenzsoftware', hash => this.exe_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); - this.calcSHA512Hash('/Applications/Chargy\ Transparenzsoftware.app/Contents/Resources/app.asar', hash => this.app_asar_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); - this.calcSHA512Hash('/Applications/Chargy\ Transparenzsoftware.app/Contents/Resources/electron.asar', hash => this.electron_asar_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); + this.calcSHA512FileHash('/Applications/Chargy\ Transparenzsoftware.app/Contents/MacOS/Chargy Transparenzsoftware', hash => this.exe_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); + this.calcSHA512FileHash('/Applications/Chargy\ Transparenzsoftware.app/Contents/Resources/app.asar', hash => this.app_asar_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); + this.calcSHA512FileHash('/Applications/Chargy\ Transparenzsoftware.app/Contents/Resources/electron.asar', hash => this.electron_asar_hash = hash, errorMessage => this.chargySHA512Div.children[1].innerHTML = "Dateien nicht gefunden!"); break; default: @@ -528,7 +528,7 @@ class ChargyApp { (navigator as any).clipboard.readText().then((clipText: string) => { try { - this.detectContentFormat(clipText); + this.detectAndConvertContentFormat(clipText); } catch (exception) { this.doGlobalError("Fehlerhafter Transparenzdatensatz!", exception); @@ -709,12 +709,11 @@ class ChargyApp { } + //#region calcSHA512FileHash(...) - //#region calcSHA512Hash(...) - - private calcSHA512Hash(filename: string, - OnSuccess: { (hash: string): any; }, - OnFailed: { (errorMessage: string): any; }) + private calcSHA512FileHash(filename: string, + OnSuccess: { (hash: string): any; }, + OnFailed: { (errorMessage: string): any; }) { const fs = require('original-fs'); @@ -809,15 +808,62 @@ class ChargyApp { //#endregion + //#region Read and parse CTR file + + private readAndParseFile(file: File) { + + if (!file) + return; + + var reader = new FileReader(); + + reader.onload = (event) => { + try + { + this.detectAndConvertContentFormat((event.target as any).result); + } + catch (exception) { + this.doGlobalError("Fehlerhafter Transparenzdatensatz!", exception); + } + } + + reader.onerror = (event) => { + this.doGlobalError("Fehlerhafter Transparenzdatensatz!", event); + } + + reader.readAsText(file, 'UTF-8'); + + } + + //#endregion + + //#region Process .chargy file extentions/associations opened via this app + + private readFileFromDisk(filename: string): void { + if (filename != null && filename.trim() != "" && filename != "." && filename[0] != '-') + { + try + { + let content = require('original-fs').readFileSync(filename.replace("file://", ""), 'utf-8'); + this.detectAndConvertContentFormat(JSON.parse(content)); + } + catch (exception) { + this.doGlobalError("Fehlerhafter Transparenzdatensatz!", exception); + } + } + } + + //#endregion + - //#region detectContentFormat(Content) + //#region detectAndConvertContentFormat(Content) - private async detectContentFormat(Content: string) { + private async detectAndConvertContentFormat(Content: string) { this.inputInfosDiv.style.display = 'none'; this.errorTextDiv.style.display = 'none'; - var result = await this.chargy.detectContentFormat(Content); + var result = await this.chargy.detectAndConvertContentFormat(Content); if (IsAChargeTransparencyRecord(result)) await this.showChargeTransparencyRecord(result); @@ -1703,53 +1749,5 @@ class ChargyApp { //#endregion - - //#region Read and parse CTR file - - private readAndParseFile(file: File) { - - if (!file) - return; - - var reader = new FileReader(); - - reader.onload = (event) => { - try - { - this.detectContentFormat((event.target as any).result); - } - catch (exception) { - this.doGlobalError("Fehlerhafter Transparenzdatensatz!", exception); - } - } - - reader.onerror = (event) => { - this.doGlobalError("Fehlerhafter Transparenzdatensatz!", event); - } - - reader.readAsText(file, 'UTF-8'); - - } - - //#endregion - - //#region Process .chargy file extentions/associations opened via this app - - private readFileFromDisk(filename: string): void { - if (filename != null && filename.trim() != "" && filename != "." && filename[0] != '-') - { - try - { - let content = require('original-fs').readFileSync(filename.replace("file://", ""), 'utf-8'); - this.detectContentFormat(JSON.parse(content)); - } - catch (exception) { - this.doGlobalError("Fehlerhafter Transparenzdatensatz!", exception); - } - } - } - - //#endregion - } From 7e36b53034ce6ac4e7a6865ef190e949e20b4bbe Mon Sep 17 00:00:00 2001 From: Achim 'ahzf' Friedland Date: Tue, 29 Oct 2019 06:21:43 +0100 Subject: [PATCH 018/110] Update to electron 7.0.0 --- documentation/REBUILD.md | 24 +- package-lock.json | 2266 +++++++++++++------------------------- package.json | 21 +- src/js/OCMF.ts | 2 +- src/js/SAFE_XML.ts | 6 +- 5 files changed, 825 insertions(+), 1494 deletions(-) diff --git a/documentation/REBUILD.md b/documentation/REBUILD.md index 1c86bf1..99cb4ee 100644 --- a/documentation/REBUILD.md +++ b/documentation/REBUILD.md @@ -10,33 +10,41 @@ npm install ## Install additional Node modules ``` $ npm install electron@latest --save-dev -+ electron@5.0.6 ++ electron@7.0.0 $ npm install electron-builder@latest --save-dev -+ electron-builder@20.44.4 ++ electron-builder@21.2.0 $ npm install typescript@latest --save-dev -+ typescript@3.5.2 ++ typescript@3.6.4 $ npm install sass@latest --save-dev -+ sass@1.22.1 ++ sass@1.23.1 $ npm install @types/node@latest --save-dev -+ @types/node@12.0.10 ++ @types/node@12.11.7 $ npm install elliptic@latest -+ elliptic@6.5.0 ++ elliptic@6.5.1 $ npm install @types/elliptic@latest --save-dev -+ @types/elliptic@6.4.9 ++ @types/elliptic@6.4.10 $ npm install moment@latest + moment@2.24.0 $ npm install base32-decode + base32-decode@1.0.0 -``` +$ npm install decompress@latest ++ decompress@4.2.0 + +$ npm install chart.js@latest ++ chart.js@2.9.1 + +$ npm install @types/chart.js@latest --save-dev ++ @types/chart.js@2.8.9 +``` # Verify SHA512 hash values diff --git a/package-lock.json b/package-lock.json index 11ad054..be070f6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,41 @@ { "name": "chargytransparenzsoftware", - "version": "1.0.0", + "version": "1.1.0", "lockfileVersion": 1, "requires": true, "dependencies": { "7zip-bin": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/7zip-bin/-/7zip-bin-4.1.0.tgz", - "integrity": "sha512-AsnBZN3a8/JcNt+KPkGGODaA4c7l3W5+WpeKgGSbstSLxqWtTXqd1ieJGBQ8IFCtRg8DmmKUcSkIkUc0A4p3YA==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/7zip-bin/-/7zip-bin-5.0.3.tgz", + "integrity": "sha512-GLyWIFBbGvpKPGo55JyRZAo4lVbnBiD52cKlw/0Vt+wnmKvWJkpZvsjVoaIolyBXDeAQKSicRtqFNPem9w0WYA==", "dev": true }, + "@develar/schema-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.1.0.tgz", + "integrity": "sha512-qjCqB4ctMig9Gz5bd6lkdFr3bO6arOdQqptdBSpF1ZpCnjofieCciEzkoS9ujY9cMGyllYSCSmBJ3x9OKHXzoA==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-keywords": "^3.1.0" + } + }, + "@electron/get": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-1.6.0.tgz", + "integrity": "sha512-xuvAzbN9iBApfAMvW0hKUpxHR5wPVbG9RaoSTbpu/WaHISDu0MVfMWYhfeU0X730CpBV0G2RkLgwAs9WDan3GA==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "env-paths": "^2.2.0", + "fs-extra": "^8.1.0", + "global-agent": "^2.0.2", + "global-tunnel-ng": "^2.7.1", + "got": "^9.6.0", + "sanitize-filename": "^1.6.2", + "sumchecker": "^3.0.0" + } + }, "@sindresorhus/is": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", @@ -29,25 +55,28 @@ "version": "4.11.5", "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.5.tgz", "integrity": "sha512-AEAZcIZga0JgVMHNtl1CprA/hXX7/wPt79AgR4XqaDt7jyj3QWYw6LPoOiznPtugDmlubUnAahMs2PFxGcQrng==", + "dev": true, "requires": { "@types/node": "*" } }, "@types/chart.js": { - "version": "2.7.54", - "resolved": "https://registry.npmjs.org/@types/chart.js/-/chart.js-2.7.54.tgz", - "integrity": "sha512-BxIUR4mfk0zOqOPEu4gxLP5herra6INQLyFmgVE6JVRNNB+r36g2cd67nDUEEdD/EShZvaR33xausxOGv1+nbw==" + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/@types/chart.js/-/chart.js-2.8.9.tgz", + "integrity": "sha512-IMXVwV3VClTMDWIbD8cddj2Hhb7SCkVs5iiZ21Qevt2zbftPTw3DFx3nDSzwQtPZuLq0Ez/BgyfgIxNfbNs6bg==", + "dev": true }, "@types/debug": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.4.tgz", - "integrity": "sha512-D9MyoQFI7iP5VdpEyPZyjjqIJ8Y8EDNQFIFVLOmeg1rI1xiHOChyUPMPRUVfqFCerxfE+yS3vMyj37F6IdtOoQ==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.5.tgz", + "integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==", "dev": true }, "@types/elliptic": { - "version": "6.4.9", - "resolved": "https://registry.npmjs.org/@types/elliptic/-/elliptic-6.4.9.tgz", - "integrity": "sha512-Mn+OyENd6YHwJKgUSyCTUDunEDFMaFpCXt52JCA00sxtzEa1ji6H0doZHL3iXhqMTo1Ob53X+Dv0s4PAJ+IVlA==", + "version": "6.4.10", + "resolved": "https://registry.npmjs.org/@types/elliptic/-/elliptic-6.4.10.tgz", + "integrity": "sha512-9h+Bw+aNiLzcq9DGstHccNxSsJ5iNId7mzruid7+kwm7F1IGvb4rBOOPo3+twt9ZPhI3y+JJ2m1UfgU8cOEJuQ==", + "dev": true, "requires": { "@types/bn.js": "*" } @@ -66,14 +95,15 @@ } }, "@types/node": { - "version": "12.0.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.10.tgz", - "integrity": "sha512-LcsGbPomWsad6wmMNv7nBLw7YYYyfdYcz6xryKYQhx89c3XXan+8Q6AJ43G5XDIaklaVkK3mE4fCb0SBvMiPSQ==" + "version": "12.11.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.11.7.tgz", + "integrity": "sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA==", + "dev": true }, "ajv": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", - "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", "dev": true, "requires": { "fast-deep-equal": "^2.0.1", @@ -83,9 +113,9 @@ } }, "ajv-keywords": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.0.tgz", - "integrity": "sha512-aUjdRFISbuFOl0EIZc+9e4FfZp0bDZgAdOOf30bJmw8VM9v84SHyVyxDfbWxpGYbdZD/9XoKxfHVNmxPkhwyGw==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", + "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==", "dev": true }, "ansi-align": { @@ -95,46 +125,12 @@ "dev": true, "requires": { "string-width": "^3.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } } }, "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, "ansi-styles": { @@ -164,9 +160,9 @@ } }, "anymatch": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.0.2.tgz", - "integrity": "sha512-rUe9SxpRQlVg4EM8It7JMNWWYHAirTPpbTuvaSKybb5IejNgWB3PGBBX9rrPKDx2pM/p3Wh+7+ASaWRyyAbxmQ==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", "dev": true, "requires": { "normalize-path": "^3.0.0", @@ -174,58 +170,39 @@ } }, "app-builder-bin": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-2.7.1.tgz", - "integrity": "sha512-ubIBeiL9XysjMW4HETBKxj3DC8ika6dGyC0vftPc0kZwGh1iXQ5bycsjoAqY/3t3BBEEIg0VruicvBaUl1pOSQ==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-3.4.3.tgz", + "integrity": "sha512-qMhayIwi3juerQEVJMQ76trObEbfQT0nhUdxZz9a26/3NLT3pE6awmQ8S1cEnrGugaaM5gYqR8OElcDezfmEsg==", "dev": true }, "app-builder-lib": { - "version": "20.44.4", - "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-20.44.4.tgz", - "integrity": "sha512-1K1xfrhyqDgnibwyuYMgvfwGilGLMF31YwOUJ8IXreyjRef9lUjWW+BZuBXqk4Uqd0C0EYPjhofgpuN0WoAQ+A==", + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-21.2.0.tgz", + "integrity": "sha512-aOX/nv77/Bti6NymJDg7p9T067xD8m1ipIEJR7B4Mm1GsJWpMm9PZdXtCRiMNRjHtQS5KIljT0g17781y6qn5A==", "dev": true, "requires": { - "7zip-bin": "~4.1.0", - "app-builder-bin": "2.7.1", + "7zip-bin": "~5.0.3", + "@develar/schema-utils": "~2.1.0", "async-exit-hook": "^2.0.1", "bluebird-lst": "^1.0.9", - "builder-util": "10.1.2", - "builder-util-runtime": "8.2.5", + "builder-util": "21.2.0", + "builder-util-runtime": "8.3.0", "chromium-pickle-js": "^0.2.0", "debug": "^4.1.1", "ejs": "^2.6.2", - "electron-osx-sign": "0.4.11", - "electron-publish": "20.44.4", - "fs-extra-p": "^8.0.2", + "electron-publish": "21.2.0", + "fs-extra": "^8.1.0", "hosted-git-info": "^2.7.1", "is-ci": "^2.0.0", - "isbinaryfile": "^4.0.1", + "isbinaryfile": "^4.0.2", "js-yaml": "^3.13.1", "lazy-val": "^1.0.4", "minimatch": "^3.0.4", "normalize-package-data": "^2.5.0", - "plist": "^3.0.1", - "read-config-file": "3.2.2", - "sanitize-filename": "^1.6.1", - "semver": "^6.1.1", - "temp-file": "^3.3.3" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "semver": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.1.2.tgz", - "integrity": "sha512-z4PqiCpomGtWj8633oeAdXm1Kn1W++3T8epkZYnwiVgIYIJ0QHszhInYSJTYxebByQH7KVCEAn8R9duzZW2PhQ==", - "dev": true - } + "read-config-file": "5.0.0", + "sanitize-filename": "^1.6.2", + "semver": "^6.3.0", + "temp-file": "^3.3.4" } }, "argparse": { @@ -237,57 +214,12 @@ "sprintf-js": "~1.0.2" } }, - "array-find-index": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", - "dev": true - }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "dev": true, - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - }, - "async-each": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", - "dev": true - }, "async-exit-hook": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz", "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==", "dev": true }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true - }, - "aws4": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", - "dev": true - }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -302,17 +234,7 @@ "base64-js": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", - "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==", - "dev": true - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, - "requires": { - "tweetnacl": "^0.14.3" - } + "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==" }, "binary-extensions": { "version": "2.0.0", @@ -320,10 +242,48 @@ "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", "dev": true }, + "bl": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", + "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", + "requires": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "bluebird": { - "version": "3.5.5", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", - "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.1.tgz", + "integrity": "sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg==", "dev": true }, "bluebird-lst": { @@ -340,6 +300,13 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" }, + "boolean": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/boolean/-/boolean-2.0.2.tgz", + "integrity": "sha512-ymsbJQlux/uogyEWfsXJUYzuyoOzPyp6NvEV71s6/ptQR7ptKO9uHF+WZL2GRATDeN52EFhNyrIu+exNZKh3Cw==", + "dev": true, + "optional": true + }, "boxen": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/boxen/-/boxen-3.2.0.tgz", @@ -354,46 +321,6 @@ "term-size": "^1.2.0", "type-fest": "^0.3.0", "widest-line": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } } }, "brace-expansion": { @@ -420,11 +347,19 @@ "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" }, + "buffer": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.4.3.tgz", + "integrity": "sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, "buffer-alloc": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", - "dev": true, "requires": { "buffer-alloc-unsafe": "^1.1.0", "buffer-fill": "^1.0.0" @@ -433,14 +368,17 @@ "buffer-alloc-unsafe": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", - "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", - "dev": true + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" }, "buffer-fill": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", - "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=", - "dev": true + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=" }, "buffer-from": { "version": "1.1.1", @@ -449,58 +387,34 @@ "dev": true }, "builder-util": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-10.1.2.tgz", - "integrity": "sha512-LQMh36Cg0r4ZfKqNlaUclndS/IXxZ3OdCgmXvw1vdP3QwYT2NkyE7LfMikAFIHpXOs6zsVH+iW+Fe/AX1jfFag==", + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-21.2.0.tgz", + "integrity": "sha512-Nd6CUb6YgDY8EXAXEIegx+1kzKqyFQ5ZM5BoYkeunAlwz/zDJoH1UCyULjoS5wQe5czNClFQy07zz2bzYD0Z4A==", "dev": true, "requires": { - "7zip-bin": "~4.1.0", + "7zip-bin": "~5.0.3", "@types/debug": "^4.1.4", - "app-builder-bin": "2.7.1", + "app-builder-bin": "3.4.3", "bluebird-lst": "^1.0.9", - "builder-util-runtime": "^8.2.5", + "builder-util-runtime": "8.3.0", "chalk": "^2.4.2", "debug": "^4.1.1", - "fs-extra-p": "^8.0.2", + "fs-extra": "^8.1.0", "is-ci": "^2.0.0", "js-yaml": "^3.13.1", - "source-map-support": "^0.5.12", + "source-map-support": "^0.5.13", "stat-mode": "^0.3.0", - "temp-file": "^3.3.3" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } + "temp-file": "^3.3.4" } }, "builder-util-runtime": { - "version": "8.2.5", - "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.2.5.tgz", - "integrity": "sha512-YILT+YUlxrE3yNB6mDC1tF+Q24mr1LSYdjP5U861jbBeDZfvy1/VPDzW3boMVrDtzYnDnvkYrzLJnoh6TXA75w==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.3.0.tgz", + "integrity": "sha512-CSOdsYqf4RXIHh1HANPbrZHlZ9JQJXSuDDloblZPcWQVN62inyYoTQuSmY3KrgefME2Sv3Kn2MxHvbGQHRf8Iw==", "dev": true, "requires": { - "bluebird-lst": "^1.0.9", "debug": "^4.1.1", - "fs-extra-p": "^8.0.2", "sax": "^1.2.4" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } } }, "cacheable-request": { @@ -536,25 +450,9 @@ } }, "camelcase": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", - "dev": true - }, - "camelcase-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", - "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", - "dev": true, - "requires": { - "camelcase": "^2.0.0", - "map-obj": "^1.0.0" - } - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, "chalk": { @@ -569,21 +467,21 @@ } }, "chart.js": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.8.0.tgz", - "integrity": "sha512-Di3wUL4BFvqI5FB5K26aQ+hvWh8wnP9A3DWGvXHVkO13D3DSnaSsdZx29cXlEsYKVkn1E2az+ZYFS4t0zi8x0w==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.9.1.tgz", + "integrity": "sha512-DA5dFt0Bz79oz56ezmrwmZqj0hXGs+i9VbCFOcHqbwrHIGv7RI4YqninJKNIAC0qa29WBI9qYTN7LzULlOeunA==", "requires": { "chartjs-color": "^2.1.0", "moment": "^2.10.2" } }, "chartjs-color": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.3.0.tgz", - "integrity": "sha512-hEvVheqczsoHD+fZ+tfPUE+1+RbV6b+eksp2LwAhwRTVXEjCSEavvk+Hg3H6SZfGlPh/UfmWKGIvZbtobOEm3g==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.4.1.tgz", + "integrity": "sha512-haqOg1+Yebys/Ts/9bLo/BqUcONQOdr/hoEr2LLTRl6C5LXctUdHxsCYfvQVg5JIxITrfCNUDr4ntqmQk9+/0w==", "requires": { "chartjs-color-string": "^0.6.0", - "color-convert": "^0.5.3" + "color-convert": "^1.9.3" } }, "chartjs-color-string": { @@ -595,20 +493,19 @@ } }, "chokidar": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.0.1.tgz", - "integrity": "sha512-2ww34sJWehnbpV0Q4k4V5Hh7juo7po6z7LUWkcIQnSGN1lHOL8GGtLtfwabKvLFQw/hbSUQ0u6V7OgGYgBzlkQ==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.2.3.tgz", + "integrity": "sha512-GtrxGuRf6bzHQmXWRepvsGnXpkQkVU+D2/9a7dAe4a7v1NhrfZOZ2oKf76M3nOs46fFYL8D+Q8JYA4GYeJ8Cjw==", "dev": true, "requires": { - "anymatch": "^3.0.1", - "async-each": "^1.0.3", - "braces": "^3.0.2", - "fsevents": "^2.0.6", - "glob-parent": "^5.0.0", - "is-binary-path": "^2.1.0", - "is-glob": "^4.0.1", - "normalize-path": "^3.0.0", - "readdirp": "^3.0.2" + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" } }, "chromium-pickle-js": { @@ -638,40 +535,6 @@ "string-width": "^3.1.0", "strip-ansi": "^5.2.0", "wrap-ansi": "^5.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } } }, "clone-response": { @@ -683,37 +546,34 @@ "mimic-response": "^1.0.0" } }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true - }, "color-convert": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz", - "integrity": "sha1-vbbGnOZg+t/+CwAHzER+G59ygr0=" + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + }, + "dependencies": { + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + } + } }, "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, + "commander": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", + "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", "requires": { - "delayed-stream": "~1.0.0" + "graceful-readlink": ">= 1.0.0" } }, - "compare-version": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/compare-version/-/compare-version-0.1.2.tgz", - "integrity": "sha1-AWLsLZNR9d3VmpICy6k1NmpyUIA=", - "dev": true - }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -730,38 +590,17 @@ "inherits": "^2.0.3", "readable-stream": "^2.2.2", "typedarray": "^0.0.6" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } + } + }, + "config-chain": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", + "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", + "dev": true, + "optional": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" } }, "configstore": { @@ -778,11 +617,17 @@ "xdg-basedir": "^3.0.0" } }, + "core-js": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.3.5.tgz", + "integrity": "sha512-0J3K+Par/ZydhKg8pEiTcK/9d65/nqJOzY62uMkjeBmt05fDOt/khUVjDdh8TpeIuGQDy1yLDDCjiWN/8pFIuw==", + "dev": true, + "optional": true + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "cross-spawn": { "version": "5.1.0", @@ -801,28 +646,10 @@ "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", "dev": true }, - "currently-unhandled": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", - "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", - "dev": true, - "requires": { - "array-find-index": "^1.0.1" - } - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { "ms": "^2.1.1" @@ -834,6 +661,21 @@ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, + "decompress": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.0.tgz", + "integrity": "sha1-eu3YVCflqS2s/lVnSnxQXpbQH50=", + "requires": { + "decompress-tar": "^4.0.0", + "decompress-tarbz2": "^4.0.0", + "decompress-targz": "^4.0.0", + "decompress-unzip": "^4.0.1", + "graceful-fs": "^4.1.10", + "make-dir": "^1.0.0", + "pify": "^2.3.0", + "strip-dirs": "^2.0.0" + } + }, "decompress-response": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", @@ -843,6 +685,89 @@ "mimic-response": "^1.0.0" } }, + "decompress-tar": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", + "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", + "requires": { + "file-type": "^5.2.0", + "is-stream": "^1.1.0", + "tar-stream": "^1.5.2" + } + }, + "decompress-tarbz2": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", + "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", + "requires": { + "decompress-tar": "^4.1.0", + "file-type": "^6.1.0", + "is-stream": "^1.1.0", + "seek-bzip": "^1.0.5", + "unbzip2-stream": "^1.0.9" + }, + "dependencies": { + "file-type": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", + "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==" + } + } + }, + "decompress-targz": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", + "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", + "requires": { + "decompress-tar": "^4.1.1", + "file-type": "^5.2.0", + "is-stream": "^1.1.0" + } + }, + "decompress-unzip": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", + "integrity": "sha1-3qrM39FK6vhVePczroIQ+bSEj2k=", + "requires": { + "file-type": "^3.8.0", + "get-stream": "^2.2.0", + "pify": "^2.3.0", + "yauzl": "^2.4.2" + }, + "dependencies": { + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "requires": { + "pend": "~1.2.0" + } + }, + "file-type": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", + "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=" + }, + "get-stream": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", + "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=", + "requires": { + "object-assign": "^4.0.1", + "pinkie-promise": "^2.0.0" + } + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + } + } + }, "deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -855,26 +780,36 @@ "integrity": "sha512-k09hcQcTDY+cwgiwa6PYKLm3jlagNzQ+RSvhjzESOGOx+MNOuXkxTfEvPrO1IOQ81tArCFYQgi631clB70RpQw==", "dev": true }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "optional": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "detect-node": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", + "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==", + "dev": true, + "optional": true }, "dmg-builder": { - "version": "6.7.2", - "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-6.7.2.tgz", - "integrity": "sha512-xfYOwhHjOSOIqkk8A0h8zcaio/WyzrAWpMTu9hzV3Z5PI4tOG0Pq6a9Lh/mHr1r3bydif8R21qGvKU1Re9CpUg==", + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-21.2.0.tgz", + "integrity": "sha512-9cJEclnGy7EyKFCoHDYDf54pub/t92CQapyiUxU0w9Bj2vUvfoDagP1PMiX4XD5rPp96141h9A+QN0OB4VgvQg==", "dev": true, "requires": { - "app-builder-lib": "~20.44.4", + "app-builder-lib": "~21.2.0", "bluebird-lst": "^1.0.9", - "builder-util": "~10.1.2", - "fs-extra-p": "^8.0.2", - "iconv-lite": "^0.4.24", + "builder-util": "~21.2.0", + "fs-extra": "^8.1.0", + "iconv-lite": "^0.5.0", "js-yaml": "^3.13.1", - "parse-color": "^1.0.0", - "sanitize-filename": "^1.6.1" + "sanitize-filename": "^1.6.2" } }, "dot-prop": { @@ -887,15 +822,15 @@ } }, "dotenv": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.2.0.tgz", - "integrity": "sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==", "dev": true }, "dotenv-expand": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-4.2.0.tgz", - "integrity": "sha1-3vHxyl1gWdJKdm5YeULCEQbOEnU=", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", "dev": true }, "duplexer3": { @@ -904,138 +839,63 @@ "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", "dev": true }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, "ejs": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.6.2.tgz", - "integrity": "sha512-PcW2a0tyTuPHz3tWyYqtK6r1fZ3gp+3Sop8Ph+ZYN81Ob5rwmbHEzaqs10N3BEsaGTkh/ooniXK+WwszGlc2+Q==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.1.tgz", + "integrity": "sha512-kS/gEPzZs3Y1rRsbGX4UOSjtP/CeJP0CxSNZHYxGfVM/VgLcv0ZqM7C45YyTj2DI2g7+P9Dd24C+IMIg6D0nYQ==", "dev": true }, "electron": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/electron/-/electron-5.0.6.tgz", - "integrity": "sha512-0L53lv26eDhaaNxL6DqXGQrQOEAYbrQg40stRSb2pzrY06kwPbABzXEiaCvEsBuKUQ+9OQBbVyyvXRbLJlun/A==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/electron/-/electron-7.0.0.tgz", + "integrity": "sha512-vrF1loRW1p0vQCbduqO0EZpo8ePJOuxUT6tSoUSU3lsbGK3VnlJop+0PpCIPzbe2K4G4Gk7WexH08V9se7mJcA==", "dev": true, "requires": { - "@types/node": "^10.12.18", - "electron-download": "^4.1.0", + "@electron/get": "^1.0.1", + "@types/node": "^12.0.12", "extract-zip": "^1.0.3" - }, - "dependencies": { - "@types/node": { - "version": "10.14.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.10.tgz", - "integrity": "sha512-V8wj+w2YMNvGuhgl/MA5fmTxgjmVHVoasfIaxMMZJV6Y8Kk+Ydpi1z2whoShDCJ2BuNVoqH/h1hrygnBxkrw/Q==", - "dev": true - } } }, "electron-builder": { - "version": "20.44.4", - "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-20.44.4.tgz", - "integrity": "sha512-H8zzP01albkKh2Ec1zc0A7RGriUkHb5M99NJskaYtgKtGATTAGH+r9OIWVk5Hk9c1dLMVudbqEeaSlygMF2asw==", + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-21.2.0.tgz", + "integrity": "sha512-x8EXrqFbAb2L3N22YlGar3dGh8vwptbB3ovo3OF6K7NTpcsmM2zEoJv7GhFyX73rNzSG2HaWpXwGAtOp2JWiEw==", "dev": true, "requires": { - "app-builder-lib": "20.44.4", + "app-builder-lib": "21.2.0", "bluebird-lst": "^1.0.9", - "builder-util": "10.1.2", - "builder-util-runtime": "8.2.5", + "builder-util": "21.2.0", + "builder-util-runtime": "8.3.0", "chalk": "^2.4.2", - "dmg-builder": "6.7.2", - "fs-extra-p": "^8.0.2", + "dmg-builder": "21.2.0", + "fs-extra": "^8.1.0", "is-ci": "^2.0.0", "lazy-val": "^1.0.4", - "read-config-file": "3.2.2", - "sanitize-filename": "^1.6.1", - "update-notifier": "^3.0.0", - "yargs": "^13.2.4" - } - }, - "electron-download": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/electron-download/-/electron-download-4.1.1.tgz", - "integrity": "sha512-FjEWG9Jb/ppK/2zToP+U5dds114fM1ZOJqMAR4aXXL5CvyPE9fiqBK/9YcwC9poIFQTEJk/EM/zyRwziziRZrg==", - "dev": true, - "requires": { - "debug": "^3.0.0", - "env-paths": "^1.0.0", - "fs-extra": "^4.0.1", - "minimist": "^1.2.0", - "nugget": "^2.0.1", - "path-exists": "^3.0.0", - "rc": "^1.2.1", - "semver": "^5.4.1", - "sumchecker": "^2.0.2" - } - }, - "electron-osx-sign": { - "version": "0.4.11", - "resolved": "https://registry.npmjs.org/electron-osx-sign/-/electron-osx-sign-0.4.11.tgz", - "integrity": "sha512-VVd40nrnVqymvFrY9ZkOYgHJOvexHHYTR3di/SN+mjJ0OWhR1I8BRVj3U+Yamw6hnkZZNKZp52rqL5EFAAPFkQ==", - "dev": true, - "requires": { - "bluebird": "^3.5.0", - "compare-version": "^0.1.2", - "debug": "^2.6.8", - "isbinaryfile": "^3.0.2", - "minimist": "^1.2.0", - "plist": "^3.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "isbinaryfile": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.3.tgz", - "integrity": "sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==", - "dev": true, - "requires": { - "buffer-alloc": "^1.2.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } + "read-config-file": "5.0.0", + "sanitize-filename": "^1.6.2", + "update-notifier": "^3.0.1", + "yargs": "^13.3.0" } }, "electron-publish": { - "version": "20.44.4", - "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-20.44.4.tgz", - "integrity": "sha512-50NzsKOnNqOpGJzPl04vMyitdguUvp15FWKWtu4KISsHfgdLMWGgxHGZwfMphc/vf364zXvPHsYQza3MASgaEQ==", + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-21.2.0.tgz", + "integrity": "sha512-mWavuoWJe87iaeKd0I24dNWIaR+0yRzshjNVqGyK019H766fsPWl3caQJnVKFaEyrZRP397v4JZVG0e7s16AxA==", "dev": true, "requires": { "bluebird-lst": "^1.0.9", - "builder-util": "~10.1.2", - "builder-util-runtime": "^8.2.5", + "builder-util": "~21.2.0", + "builder-util-runtime": "8.3.0", "chalk": "^2.4.2", - "fs-extra-p": "^8.0.2", + "fs-extra": "^8.1.0", "lazy-val": "^1.0.4", "mime": "^2.4.4" } }, "elliptic": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.0.tgz", - "integrity": "sha512-eFOJTMyCYb7xtE/caJ6JJu+bhi67WCYNbkGSknu20pmM8Ke/bqOfdnZWxyoGN26JgfxTbXrsCkEw4KheCT/KGg==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.1.tgz", + "integrity": "sha512-xvJINNLbTeWQjrl6X+7eQCrIy/YPv5XCpKW6kB5mKvtnGILoLDcySuwomfdzt0BMdLNVnuRNTuzKNHj0bva1Cg==", "requires": { "bn.js": "^4.4.0", "brorand": "^1.0.1", @@ -1052,29 +912,33 @@ "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "dev": true }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true, + "optional": true + }, "end-of-stream": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", - "dev": true, "requires": { "once": "^1.4.0" } }, "env-paths": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-1.0.0.tgz", - "integrity": "sha1-QWgTO0K7BcOKNbGuQ5fIKYqzaeA=", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.0.tgz", + "integrity": "sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA==", "dev": true }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } + "optional": true }, "escape-string-regexp": { "version": "1.0.5", @@ -1103,12 +967,6 @@ "strip-eof": "^1.0.0" } }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, "extract-zip": { "version": "1.6.7", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.7.tgz", @@ -1138,12 +996,6 @@ } } }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true - }, "fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", @@ -1165,6 +1017,11 @@ "pend": "~1.2.0" } }, + "file-type": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", + "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=" + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -1175,81 +1032,41 @@ } }, "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "dependencies": { - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" - } - } + "locate-path": "^3.0.0" } }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" }, "fs-extra": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", - "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "dev": true, "requires": { - "graceful-fs": "^4.1.2", + "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, - "fs-extra-p": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/fs-extra-p/-/fs-extra-p-8.0.2.tgz", - "integrity": "sha512-dpWboLA/OlyuqGQdsTjC2PKNkise3O4ptcMpXoyfeM/VXrthkEape3I+drWLI0JAW46r1D3eb6QBSPkSyXPXzA==", + "fsevents": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.1.tgz", + "integrity": "sha512-4FRPXWETxtigtJW/gxzEDsX1LVbPAM93VleB83kZB+ellqbHMkyt2aJfuzNLRvFPnGi6bcE5SvfxgbXPeKteJw==", "dev": true, - "requires": { - "bluebird-lst": "^1.0.9", - "fs-extra": "^8.0.1" - }, - "dependencies": { - "fs-extra": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.0.1.tgz", - "integrity": "sha512-W+XLrggcDzlle47X/XnS7FXrXu9sDo+Ze9zpndeBxdgv88FHLm1HtmkhEwavruS6koanBjp098rUpHs65EmG7A==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - } - } + "optional": true }, - "fsevents": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.0.7.tgz", - "integrity": "sha512-a7YT0SV3RB+DjYcppwVDLtn13UQnmg0SWZS7ezZD0UjnLwXmy8Zm21GMVGLaFGimIqcvyMQaOJBrop8MyOp1kQ==", + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true, "optional": true }, @@ -1259,34 +1076,44 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, - "get-stdin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", - "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", - "dev": true - }, "get-stream": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", "dev": true }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "glob-parent": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", + "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", "dev": true, "requires": { - "assert-plus": "^1.0.0" + "is-glob": "^4.0.1" } }, - "glob-parent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.0.0.tgz", - "integrity": "sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg==", + "global-agent": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-2.1.5.tgz", + "integrity": "sha512-pYJjCxxNBzYxo6iNO62JZn8iCFVbvpiM0zE4w/G5hBNIvLjnvzIeCVQPMKc3aK8ju5L7Q8NNI/oBSosU0eeSYw==", "dev": true, + "optional": true, "requires": { - "is-glob": "^4.0.1" + "boolean": "^2.0.2", + "core-js": "^3.3.3", + "es6-error": "^4.1.1", + "matcher": "^2.0.0", + "roarr": "^2.14.2", + "semver": "^6.3.0", + "serialize-error": "^5.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "optional": true + } } }, "global-dirs": { @@ -1298,6 +1125,31 @@ "ini": "^1.3.4" } }, + "global-tunnel-ng": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/global-tunnel-ng/-/global-tunnel-ng-2.7.1.tgz", + "integrity": "sha512-4s+DyciWBV0eK148wqXxcmVAbFVPqtc3sEtUE/GTQfuU80rySLcMhUmHKSHI7/LDj8q0gDYI1lIhRRB7ieRAqg==", + "dev": true, + "optional": true, + "requires": { + "encodeurl": "^1.0.2", + "lodash": "^4.17.10", + "npm-conf": "^1.1.3", + "tunnel": "^0.0.6" + } + }, + "globalthis": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.0.tgz", + "integrity": "sha512-vcCAZTJ3r5Qcu5l8/2oyVdoFwxKgfYnMTR2vwWeux/NAVZK3PwcMaWkdUIn4GJbmKuRK7xcvDsLuK+CKcXyodg==", + "dev": true, + "optional": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "object-keys": "^1.0.12" + } + }, "got": { "version": "9.6.0", "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", @@ -1331,24 +1183,12 @@ "graceful-fs": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz", - "integrity": "sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg==", - "dev": true - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true + "integrity": "sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg==" }, - "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", - "dev": true, - "requires": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" - } + "graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=" }, "has-flag": { "version": "3.0.0", @@ -1382,9 +1222,9 @@ } }, "hosted-git-info": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", - "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz", + "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==", "dev": true }, "http-cache-semantics": { @@ -1393,26 +1233,20 @@ "integrity": "sha512-TcIMG3qeVLgDr1TEd2XvHaTnMPwYQUQMIBLy+5pLSDKYFc7UIqj39w8EGzZkaxoLv/l2K8HaI0t5AVA+YYgUew==", "dev": true }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.0.tgz", + "integrity": "sha512-NnEhI9hIEKHOzJ4f697DMz9IQEXr/MMJ5w64vN2/4Ai+wRnvV7SBrL0KLoRlwaKVghOc7LQ5YkPLuX146b6Ydw==", "dev": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" } }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, "import-lazy": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", @@ -1425,15 +1259,6 @@ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, - "indent-string": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", - "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", - "dev": true, - "requires": { - "repeating": "^2.0.0" - } - }, "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", @@ -1445,18 +1270,6 @@ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true }, - "invert-kv": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", - "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", - "dev": true - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, "is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -1481,23 +1294,11 @@ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true }, - "is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true }, "is-glob": { "version": "4.0.1", @@ -1518,6 +1319,11 @@ "is-path-inside": "^1.0.0" } }, + "is-natural-number": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", + "integrity": "sha1-q5124dtM7VHjXeDHLr7PCfc0zeg=" + }, "is-npm": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-3.0.0.tgz", @@ -1548,20 +1354,7 @@ "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", - "dev": true + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" }, "is-yarn-global": { "version": "0.3.0", @@ -1570,15 +1363,15 @@ "dev": true }, "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, "isbinaryfile": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.1.tgz", - "integrity": "sha512-bvJxbNWm72dy/1+qeBm9F8wUM4siDnlzid7NN5Ib4nQcc0tNIx/YWgEih1ZRHXr8xVbpGk1ccLlA9gOSlyx3gw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.2.tgz", + "integrity": "sha512-C3FSxJdNrEr2F4z6uFtNzECDM5hXk+46fxaa+cwBe5/XrWSmzdG8DDgyjfX6/NRdBB21q2JXuRAzPCUs+fclnQ==", "dev": true }, "isexe": { @@ -1587,12 +1380,6 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true - }, "js-yaml": { "version": "3.13.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", @@ -1603,24 +1390,12 @@ "esprima": "^4.0.0" } }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true - }, "json-buffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", "dev": true }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true - }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -1631,12 +1406,13 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true + "dev": true, + "optional": true }, "json5": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", - "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz", + "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==", "dev": true, "requires": { "minimist": "^1.2.0" @@ -1651,18 +1427,6 @@ "graceful-fs": "^4.1.6" } }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, "keyv": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", @@ -1687,15 +1451,6 @@ "integrity": "sha512-u93kb2fPbIrfzBuLjZE+w+fJbUUMhNDXxNmMfaqNgpfQf1CO5ZSe2LfsnBqVAk7i/2NF48OSoRj+Xe2VT+lE8Q==", "dev": true }, - "lcid": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", - "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", - "dev": true, - "requires": { - "invert-kv": "^2.0.0" - } - }, "leaflet": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.5.1.tgz", @@ -1706,19 +1461,6 @@ "resolved": "https://registry.npmjs.org/leaflet.awesome-markers/-/leaflet.awesome-markers-2.0.5.tgz", "integrity": "sha512-Ne/xDjkGyaujwNVVkv2tyXQUV0ZW7gZ0Mo0FuQY4jp2qWrvXi0hwDBvmZyF/8YOvybyMabTMM/mFWCTd1jZIQA==" }, - "load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" - } - }, "locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", @@ -1729,15 +1471,12 @@ "path-exists": "^3.0.0" } }, - "loud-rejection": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", - "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "dev": true, - "requires": { - "currently-unhandled": "^0.4.1", - "signal-exit": "^3.0.0" - } + "optional": true }, "lowercase-keys": { "version": "1.0.1", @@ -1759,7 +1498,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", - "dev": true, "requires": { "pify": "^3.0.0" }, @@ -1767,53 +1505,27 @@ "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" } } }, - "map-age-cleaner": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", - "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", - "dev": true, - "requires": { - "p-defer": "^1.0.0" - } - }, - "map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", - "dev": true - }, - "mem": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", - "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", - "dev": true, - "requires": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^2.0.0", - "p-is-promise": "^2.0.0" - } - }, - "meow": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", - "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "matcher": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/matcher/-/matcher-2.0.0.tgz", + "integrity": "sha512-nlmfSlgHBFx36j/Pl/KQPbIaqE8Zf0TqmSMjsuddHDg6PMSVgmyW9HpkLs0o0M1n2GIZ/S2BZBLIww/xjhiGng==", "dev": true, + "optional": true, "requires": { - "camelcase-keys": "^2.0.0", - "decamelize": "^1.1.2", - "loud-rejection": "^1.0.0", - "map-obj": "^1.0.1", - "minimist": "^1.1.3", - "normalize-package-data": "^2.3.4", - "object-assign": "^4.0.1", - "read-pkg-up": "^1.0.1", - "redent": "^1.0.0", - "trim-newlines": "^1.0.0" + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "optional": true + } } }, "mime": { @@ -1822,27 +1534,6 @@ "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", "dev": true }, - "mime-db": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", - "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", - "dev": true - }, - "mime-types": { - "version": "2.1.24", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", - "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", - "dev": true, - "requires": { - "mime-db": "1.40.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, "mimic-response": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", @@ -1902,12 +1593,6 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -1918,6 +1603,14 @@ "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } } }, "normalize-path": { @@ -1927,163 +1620,76 @@ "dev": true }, "normalize-url": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.3.0.tgz", - "integrity": "sha512-0NLtR71o4k6GLP+mr6Ty34c5GA6CMoEsncKJxvQd8NzPxaHRJNnb5gZE8R1XF4CPIS7QPHLJ74IFszwtNVAHVQ==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", + "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==", "dev": true }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, - "requires": { - "path-key": "^2.0.0" - } - }, - "nugget": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nugget/-/nugget-2.0.1.tgz", - "integrity": "sha1-IBCVpIfhrTYIGzQy+jytpPjQcbA=", + "npm-conf": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz", + "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==", "dev": true, + "optional": true, "requires": { - "debug": "^2.1.3", - "minimist": "^1.1.0", - "pretty-bytes": "^1.0.2", - "progress-stream": "^1.1.0", - "request": "^2.45.0", - "single-line-log": "^1.1.2", - "throttleit": "0.0.2" + "config-chain": "^1.1.11", + "pify": "^3.0.0" }, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "optional": true } } }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, "object-keys": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", - "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=", - "dev": true + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "optional": true }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, "requires": { "wrappy": "1" } }, - "os-locale": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", - "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", - "dev": true, - "requires": { - "execa": "^1.0.0", - "lcid": "^2.0.0", - "mem": "^4.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - } - } - }, "p-cancelable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", "dev": true }, - "p-defer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", - "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", - "dev": true - }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", "dev": true }, - "p-is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", - "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", - "dev": true - }, "p-limit": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", - "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -2105,41 +1711,15 @@ "dev": true }, "package-json": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.4.0.tgz", - "integrity": "sha512-bd1T8OBG7hcvMd9c/udgv6u5v9wISP3Oyl9Cm7Weop8EFwrtcQDnS2sb6zhwqus2WslSr5wSTIPiTTpxxmPm7Q==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", "dev": true, "requires": { "got": "^9.6.0", - "registry-auth-token": "^3.4.0", + "registry-auth-token": "^4.0.0", "registry-url": "^5.0.0", - "semver": "^6.1.1" - }, - "dependencies": { - "semver": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.1.2.tgz", - "integrity": "sha512-z4PqiCpomGtWj8633oeAdXm1Kn1W++3T8epkZYnwiVgIYIJ0QHszhInYSJTYxebByQH7KVCEAn8R9duzZW2PhQ==", - "dev": true - } - } - }, - "parse-color": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-color/-/parse-color-1.0.0.tgz", - "integrity": "sha1-e3SLlag/A/FqlPU15S1/PZRlhhk=", - "dev": true, - "requires": { - "color-convert": "~0.5.0" - } - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "^1.2.0" + "semver": "^6.2.0" } }, "path-exists": { @@ -2166,28 +1746,10 @@ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "dev": true }, - "path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, "pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", - "dev": true - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" }, "picomatch": { "version": "2.0.7", @@ -2198,66 +1760,38 @@ "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" }, "pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" }, "pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, "requires": { "pinkie": "^2.0.0" } }, - "plist": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.1.tgz", - "integrity": "sha512-GpgvHHocGRyQm74b6FWEZZVRroHKE1I0/BTjAmySaohK+cUn+hZpbqXkc3KWgW3gQYkqcQej35FohcT0FRlkRQ==", - "dev": true, - "requires": { - "base64-js": "^1.2.3", - "xmlbuilder": "^9.0.7", - "xmldom": "0.1.x" - } - }, "prepend-http": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", "dev": true }, - "pretty-bytes": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-1.0.4.tgz", - "integrity": "sha1-CiLoIQYJrTVUL4yNXSFZr/B1HIQ=", - "dev": true, - "requires": { - "get-stdin": "^4.0.1", - "meow": "^3.1.0" - } - }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, - "progress-stream": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/progress-stream/-/progress-stream-1.2.0.tgz", - "integrity": "sha1-LNPP6jO6OonJwSHsM0er6asSX3c=", + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", "dev": true, - "requires": { - "speedometer": "~0.1.2", - "through2": "~0.2.3" - } + "optional": true }, "pseudomap": { "version": "1.0.2", @@ -2265,12 +1799,6 @@ "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", "dev": true }, - "psl": { - "version": "1.1.33", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.33.tgz", - "integrity": "sha512-LTDP2uSrsc7XCb5lO7A8BI1qYxRe/8EqlRvMeEl6rsnYAqDOl8xHR+8lSAIVfrNaSAlTPTNOCgNjWcoUL3AZsw==", - "dev": true - }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -2287,12 +1815,6 @@ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", - "dev": true - }, "rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -2306,104 +1828,50 @@ } }, "read-config-file": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/read-config-file/-/read-config-file-3.2.2.tgz", - "integrity": "sha512-PuFpMgZF01VB0ydH1dfitAxCP/fh+qnfbA9cYNIPoxPbz0SMngsrafCtaHDWfER7MwlDz4fmrNBhPkakxxFpTg==", - "dev": true, - "requires": { - "ajv": "^6.9.2", - "ajv-keywords": "^3.4.0", - "bluebird-lst": "^1.0.7", - "dotenv": "^6.2.0", - "dotenv-expand": "^4.2.0", - "fs-extra-p": "^7.0.1", - "js-yaml": "^3.12.1", - "json5": "^2.1.0", - "lazy-val": "^1.0.4" - }, - "dependencies": { - "fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "fs-extra-p": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra-p/-/fs-extra-p-7.0.1.tgz", - "integrity": "sha512-yhd2OV0HnHt2oitlp+X9hl2ReX4X/7kQeL7/72qzPHTZj5eUPGzAKOvEglU02Fa1OeG2rSy/aKB4WGVaLiF8tw==", - "dev": true, - "requires": { - "bluebird-lst": "^1.0.7", - "fs-extra": "^7.0.1" - } - } - } - }, - "read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", - "dev": true, - "requires": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" - } - }, - "read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/read-config-file/-/read-config-file-5.0.0.tgz", + "integrity": "sha512-jIKUu+C84bfnKxyJ5j30CxCqgXWYjZLXuVE/NYlMEpeni+dhESgAeZOZd0JZbg1xTkMmnCdxksDoarkOyfEsOg==", "dev": true, "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" + "dotenv": "^8.0.0", + "dotenv-expand": "^5.1.0", + "fs-extra": "^8.1.0", + "js-yaml": "^3.13.1", + "json5": "^2.1.0", + "lazy-val": "^1.0.4" } }, "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "readdirp": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.0.2.tgz", - "integrity": "sha512-LbyJYv48eywrhOlScq16H/VkCiGKGPC2TpOdZCJ7QXnYEjn3NN/Oblh8QEU3vqfSRBB7OGvh5x45NKiVeNujIQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", "dev": true, "requires": { "picomatch": "^2.0.4" } }, - "redent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", - "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", - "dev": true, - "requires": { - "indent-string": "^2.1.0", - "strip-indent": "^1.0.1" - } - }, "registry-auth-token": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", - "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.0.0.tgz", + "integrity": "sha512-lpQkHxd9UL6tb3k/aHAVfnVtn+Bcs9ob5InuFLLEDqSqeq+AljB8GZW9xY0x7F+xYwEcjKe07nyoxzEYz6yvkw==", "dev": true, "requires": { - "rc": "^1.1.6", + "rc": "^1.2.8", "safe-buffer": "^5.0.1" } }, @@ -2416,43 +1884,6 @@ "rc": "^1.2.8" } }, - "repeating": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", - "dev": true, - "requires": { - "is-finite": "^1.0.0" - } - }, - "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", - "dev": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - } - }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -2466,9 +1897,9 @@ "dev": true }, "resolve": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.1.tgz", - "integrity": "sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", "dev": true, "requires": { "path-parse": "^1.0.6" @@ -2483,11 +1914,34 @@ "lowercase-keys": "^1.0.0" } }, + "roarr": { + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.14.2.tgz", + "integrity": "sha512-ibqv70DCUhGVMfPe0JSUHBZ9PKLhxdk8VJ/Y2M7vVr+L4VakW1CdVTU9cJQBbM2STQa84CgBAzd7hJGcnALGeg==", + "dev": true, + "optional": true, + "requires": { + "boolean": "^2.0.2", + "detect-node": "^2.0.4", + "globalthis": "^1.0.0", + "json-stringify-safe": "^5.0.1", + "semver-compare": "^1.0.0", + "sprintf-js": "^1.1.2" + }, + "dependencies": { + "sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "dev": true, + "optional": true + } + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safer-buffer": { "version": "2.1.2", @@ -2496,18 +1950,18 @@ "dev": true }, "sanitize-filename": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.1.tgz", - "integrity": "sha1-YS2hyWRz+gLczaktzVtKsWSmdyo=", + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz", + "integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==", "dev": true, "requires": { "truncate-utf8-bytes": "^1.0.0" } }, "sass": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.22.1.tgz", - "integrity": "sha512-VsWrNdfIzCLbD2TO2bq9tCaUzEE0UUSGtP3r9IhHi8ypAPCb3FOVP99kMRil+ZROEcTnKReZcQP9vk6ArV2eLw==", + "version": "1.23.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.23.1.tgz", + "integrity": "sha512-zQzJ3UETUWOMd/pJJGH/zvRsBVO97m11RcpfUhcQUHEXf0yHUBgOIE/Nw8aK0m1XyVJPeq228iIK7gVxsJ/Puw==", "dev": true, "requires": { "chokidar": ">=2.0.0 <4.0.0" @@ -2519,12 +1973,27 @@ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true }, + "seek-bzip": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.5.tgz", + "integrity": "sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w=", + "requires": { + "commander": "~2.8.1" + } + }, "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, + "semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", + "dev": true, + "optional": true + }, "semver-diff": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", @@ -2532,6 +2001,33 @@ "dev": true, "requires": { "semver": "^5.0.3" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "serialize-error": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-5.0.0.tgz", + "integrity": "sha512-/VtpuyzYf82mHYTtI4QKtwHa79vAdU5OQpNPAmE/0UDdlGT0ZxHwC+J6gXkw29wwoVI8fMPsfcVHOwXtUQYYQA==", + "dev": true, + "optional": true, + "requires": { + "type-fest": "^0.8.0" + }, + "dependencies": { + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "optional": true + } } }, "set-blocking": { @@ -2561,15 +2057,6 @@ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, - "single-line-log": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/single-line-log/-/single-line-log-1.1.2.tgz", - "integrity": "sha1-wvg/Jzo+GhbtsJlWYdoO1e8DM2Q=", - "dev": true, - "requires": { - "string-width": "^1.0.1" - } - }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -2577,9 +2064,9 @@ "dev": true }, "source-map-support": { - "version": "0.5.12", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.12.tgz", - "integrity": "sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==", + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.15.tgz", + "integrity": "sha512-wYF5aX1J0+V51BDT3Om7uXNn0ct2FWiV4bvwiGVefxkm+1S1o5jsecE5lb2U28DDblzxzxeIDbTVpXHI9D/9hA==", "dev": true, "requires": { "buffer-from": "^1.0.0", @@ -2613,15 +2100,9 @@ } }, "spdx-license-ids": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz", - "integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==", - "dev": true - }, - "speedometer": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/speedometer/-/speedometer-0.1.4.tgz", - "integrity": "sha1-mHbb0qFp0xFUAtSObqYynIgWpQ0=", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", "dev": true }, "sprintf-js": { @@ -2630,23 +2111,6 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "dev": true, - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, "stat-mode": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-0.3.0.tgz", @@ -2654,38 +2118,40 @@ "dev": true }, "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" } }, "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } }, "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "^4.1.0" } }, - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "dev": true, + "strip-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", + "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", "requires": { - "is-utf8": "^0.2.0" + "is-natural-number": "^4.0.1" } }, "strip-eof": { @@ -2694,15 +2160,6 @@ "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, - "strip-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", - "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", - "dev": true, - "requires": { - "get-stdin": "^4.0.1" - } - }, "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", @@ -2710,29 +2167,12 @@ "dev": true }, "sumchecker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-2.0.2.tgz", - "integrity": "sha1-D0LBDl0F2l1C7qPlbDOZo31sWz4=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.0.tgz", + "integrity": "sha512-yreseuC/z4iaodVoq07XULEOO9p4jnQazO7mbrnDSvWAU/y2cbyIKs+gWJptfcGu9R+1l27K8Rkj0bfvqnBpgQ==", "dev": true, "requires": { - "debug": "^2.2.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } + "debug": "^4.1.0" } }, "supports-color": { @@ -2744,15 +2184,62 @@ "has-flag": "^3.0.0" } }, + "tar-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", + "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", + "requires": { + "bl": "^1.0.0", + "buffer-alloc": "^1.2.0", + "end-of-stream": "^1.0.0", + "fs-constants": "^1.0.0", + "readable-stream": "^2.3.0", + "to-buffer": "^1.1.1", + "xtend": "^4.0.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + } + } + }, "temp-file": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.3.3.tgz", - "integrity": "sha512-ErWJ0vfZwkozaH7dn/5QtYdrGwy6fWID0GG3PEzNb9Vmt6urL4mQ3lKz7NWVi1/kmZsWQzgjTL7/P4mwGx5jqg==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.3.4.tgz", + "integrity": "sha512-qSZ5W5q54iyGnP8cNl49RE0jTJc5CrzNocux5APD5yIxcgonoMuMSbsZfaZy8rTGCYo0Xz6ySVv3adagZ8gffg==", "dev": true, "requires": { "async-exit-hook": "^2.0.1", - "bluebird-lst": "^1.0.9", - "fs-extra-p": "^8.0.2" + "fs-extra": "^8.1.0" } }, "term-size": { @@ -2764,21 +2251,15 @@ "execa": "^0.7.0" } }, - "throttleit": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-0.0.2.tgz", - "integrity": "sha1-z+34jmDADdlpe2H90qg0OptoDq8=", - "dev": true + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, - "through2": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.2.3.tgz", - "integrity": "sha1-6zKE2k6jEbbMis42U3SKUqvyWj8=", - "dev": true, - "requires": { - "readable-stream": "~1.1.9", - "xtend": "~2.1.1" - } + "to-buffer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", + "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==" }, "to-readable-stream": { "version": "1.0.0", @@ -2795,30 +2276,6 @@ "is-number": "^7.0.0" } }, - "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", - "dev": true, - "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - } - } - }, - "trim-newlines": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", - "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", - "dev": true - }, "truncate-utf8-bytes": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", @@ -2828,20 +2285,12 @@ "utf8-byte-length": "^1.0.1" } }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true + "optional": true }, "type-fest": { "version": "0.3.1", @@ -2856,11 +2305,20 @@ "dev": true }, "typescript": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.2.tgz", - "integrity": "sha512-7KxJovlYhTX5RaRbUdkAXN1KUZ8PwWlTzQdHV6xNqvuFOs7+WBo10TQUqT19Q/Jz2hk5v9TQDIhyLhhJY4p5AA==", + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.4.tgz", + "integrity": "sha512-unoCll1+l+YK4i4F8f22TaNVPRHcD9PA3yCuZ8g5e0qGqlVlJ/8FSateOLLSagn+Yg5+ZwuPkL8LFUc0Jcvksg==", "dev": true }, + "unbzip2-stream": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.3.3.tgz", + "integrity": "sha512-fUlAF7U9Ah1Q6EieQ4x4zLNejrRvDWUYmxXUpN3uziFYCHapjWFaCAnreY9bGgxzaMCFAPPpYNng57CypwJVhg==", + "requires": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, "unique-string": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", @@ -2877,9 +2335,9 @@ "dev": true }, "update-notifier": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-3.0.0.tgz", - "integrity": "sha512-6Xe3oF2bvuoj4YECUc52yxVs94yWrxwqHbzyveDktTS1WhnlTRpNcQMxUshcB7nRVGi1jEXiqL5cW1S5WSyzKg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-3.0.1.tgz", + "integrity": "sha512-grrmrB6Zb8DUiyDIaeRTBCkgISYUgETNe7NglEbVsrLWXeESnlCSP50WfRSj/GmzMPl6Uchj24S/p80nP/ZQrQ==", "dev": true, "requires": { "boxen": "^3.0.0", @@ -2923,14 +2381,7 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", - "dev": true + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "validate-npm-package-license": { "version": "3.0.4", @@ -2942,17 +2393,6 @@ "spdx-expression-parse": "^3.0.0" } }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", @@ -2983,12 +2423,6 @@ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", @@ -3019,47 +2453,12 @@ "ansi-styles": "^3.2.0", "string-width": "^3.0.0", "strip-ansi": "^5.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } } }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "write-file-atomic": { "version": "2.4.3", @@ -3078,27 +2477,6 @@ "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", "dev": true }, - "xmlbuilder": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", - "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", - "dev": true - }, - "xmldom": { - "version": "0.1.27", - "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz", - "integrity": "sha1-1QH5ezvbQDr4757MIFcxh6rawOk=", - "dev": true - }, - "xtend": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", - "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=", - "dev": true, - "requires": { - "object-keys": "~0.4.0" - } - }, "y18n": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", @@ -3112,65 +2490,21 @@ "dev": true }, "yargs": { - "version": "13.2.4", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz", - "integrity": "sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==", + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", + "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", "dev": true, "requires": { "cliui": "^5.0.0", "find-up": "^3.0.0", "get-caller-file": "^2.0.1", - "os-locale": "^3.1.0", "require-directory": "^2.1.1", "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", "string-width": "^3.0.0", "which-module": "^2.0.0", "y18n": "^4.0.0", - "yargs-parser": "^13.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } + "yargs-parser": "^13.1.1" } }, "yargs-parser": { @@ -3181,14 +2515,6 @@ "requires": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" - }, - "dependencies": { - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - } } }, "yauzl": { diff --git a/package.json b/package.json index db27c19..4d6b457 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "chargytransparenzsoftware", - "version": "1.0.0", + "version": "1.1.0", "description": "Chargy ist eine Transparenzsoftware für das Eichrecht in der Elektromobilität. Hiermit können Endkunden und E-Mobilitäts-Anbieter die Plausibilitäts und Validität von Ladevorgängen überprüfen.", "main": "src/main.js", "scripts": { @@ -26,22 +26,23 @@ "license": "AGPL-3.0-or-later", "homepage": "https://github.com/OpenChargingCloud/ChargyDesktopApp", "dependencies": { - "@types/chart.js": "^2.7.54", - "@types/elliptic": "^6.4.9", "@types/leaflet": "^1.4.4", "base32-decode": "^1.0.0", - "chart.js": "^2.8.0", - "elliptic": "^6.5.0", + "chart.js": "^2.9.1", + "decompress": "^4.2.0", + "elliptic": "^6.5.1", "leaflet": "^1.5.1", "leaflet.awesome-markers": "^2.0.5", "moment": "^2.24.0" }, "devDependencies": { - "@types/node": "^12.0.10", - "electron": "^5.0.6", - "electron-builder": "^20.44.4", - "sass": "^1.22.1", - "typescript": "^3.5.2" + "@types/chart.js": "^2.8.9", + "@types/elliptic": "^6.4.10", + "@types/node": "^12.11.7", + "electron": "^7.0.0", + "electron-builder": "^21.2.0", + "sass": "^1.23.1", + "typescript": "^3.6.4" }, "build": { "appId": "cloud.charging.open.chargy.desktop", diff --git a/src/js/OCMF.ts b/src/js/OCMF.ts index e6d18a8..16313f1 100644 --- a/src/js/OCMF.ts +++ b/src/js/OCMF.ts @@ -529,7 +529,7 @@ class OCMF { } - //#endregion + //#endregion } diff --git a/src/js/SAFE_XML.ts b/src/js/SAFE_XML.ts index c8cc459..b3d78e2 100644 --- a/src/js/SAFE_XML.ts +++ b/src/js/SAFE_XML.ts @@ -21,15 +21,13 @@ class SAFEXML { - //#region tryToParseSAFEXML(XMLDocument) - public async tryToParseSAFEXML(XMLDocument: Document) : Promise { const base32Decode = require('base32-decode'); // The SAFE transparency software v1.0 does not understand its own - // XML namespace. Therefore we have to guess the format. + // XML namespace. Therefore we have to guess the format. try { @@ -226,6 +224,4 @@ class SAFEXML { } - //#endregion - } From 23460c34fd61350b59166bd690ac95784cc1fcb0 Mon Sep 17 00:00:00 2001 From: Achim 'ahzf' Friedland Date: Thu, 31 Oct 2019 00:44:50 +0100 Subject: [PATCH 019/110] Revert "Update to electron 7.0.0" This reverts commit 7e36b53034ce6ac4e7a6865ef190e949e20b4bbe. --- documentation/REBUILD.md | 24 +- package-lock.json | 2278 ++++++++++++++++++++++++-------------- package.json | 21 +- src/js/OCMF.ts | 2 +- src/js/SAFE_XML.ts | 6 +- 5 files changed, 1500 insertions(+), 831 deletions(-) diff --git a/documentation/REBUILD.md b/documentation/REBUILD.md index 99cb4ee..1c86bf1 100644 --- a/documentation/REBUILD.md +++ b/documentation/REBUILD.md @@ -10,43 +10,35 @@ npm install ## Install additional Node modules ``` $ npm install electron@latest --save-dev -+ electron@7.0.0 ++ electron@5.0.6 $ npm install electron-builder@latest --save-dev -+ electron-builder@21.2.0 ++ electron-builder@20.44.4 $ npm install typescript@latest --save-dev -+ typescript@3.6.4 ++ typescript@3.5.2 $ npm install sass@latest --save-dev -+ sass@1.23.1 ++ sass@1.22.1 $ npm install @types/node@latest --save-dev -+ @types/node@12.11.7 ++ @types/node@12.0.10 $ npm install elliptic@latest -+ elliptic@6.5.1 ++ elliptic@6.5.0 $ npm install @types/elliptic@latest --save-dev -+ @types/elliptic@6.4.10 ++ @types/elliptic@6.4.9 $ npm install moment@latest + moment@2.24.0 $ npm install base32-decode + base32-decode@1.0.0 - -$ npm install decompress@latest -+ decompress@4.2.0 - -$ npm install chart.js@latest -+ chart.js@2.9.1 - -$ npm install @types/chart.js@latest --save-dev -+ @types/chart.js@2.8.9 ``` + # Verify SHA512 hash values ``` openssl dgst -sha512 -binary Chargy\ Transparenz\ Software\ Setup\ 0.26.0.exe | base64 diff --git a/package-lock.json b/package-lock.json index be070f6..11ad054 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,41 +1,15 @@ { "name": "chargytransparenzsoftware", - "version": "1.1.0", + "version": "1.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { "7zip-bin": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/7zip-bin/-/7zip-bin-5.0.3.tgz", - "integrity": "sha512-GLyWIFBbGvpKPGo55JyRZAo4lVbnBiD52cKlw/0Vt+wnmKvWJkpZvsjVoaIolyBXDeAQKSicRtqFNPem9w0WYA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/7zip-bin/-/7zip-bin-4.1.0.tgz", + "integrity": "sha512-AsnBZN3a8/JcNt+KPkGGODaA4c7l3W5+WpeKgGSbstSLxqWtTXqd1ieJGBQ8IFCtRg8DmmKUcSkIkUc0A4p3YA==", "dev": true }, - "@develar/schema-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.1.0.tgz", - "integrity": "sha512-qjCqB4ctMig9Gz5bd6lkdFr3bO6arOdQqptdBSpF1ZpCnjofieCciEzkoS9ujY9cMGyllYSCSmBJ3x9OKHXzoA==", - "dev": true, - "requires": { - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0" - } - }, - "@electron/get": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@electron/get/-/get-1.6.0.tgz", - "integrity": "sha512-xuvAzbN9iBApfAMvW0hKUpxHR5wPVbG9RaoSTbpu/WaHISDu0MVfMWYhfeU0X730CpBV0G2RkLgwAs9WDan3GA==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "env-paths": "^2.2.0", - "fs-extra": "^8.1.0", - "global-agent": "^2.0.2", - "global-tunnel-ng": "^2.7.1", - "got": "^9.6.0", - "sanitize-filename": "^1.6.2", - "sumchecker": "^3.0.0" - } - }, "@sindresorhus/is": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", @@ -55,28 +29,25 @@ "version": "4.11.5", "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.5.tgz", "integrity": "sha512-AEAZcIZga0JgVMHNtl1CprA/hXX7/wPt79AgR4XqaDt7jyj3QWYw6LPoOiznPtugDmlubUnAahMs2PFxGcQrng==", - "dev": true, "requires": { "@types/node": "*" } }, "@types/chart.js": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/@types/chart.js/-/chart.js-2.8.9.tgz", - "integrity": "sha512-IMXVwV3VClTMDWIbD8cddj2Hhb7SCkVs5iiZ21Qevt2zbftPTw3DFx3nDSzwQtPZuLq0Ez/BgyfgIxNfbNs6bg==", - "dev": true + "version": "2.7.54", + "resolved": "https://registry.npmjs.org/@types/chart.js/-/chart.js-2.7.54.tgz", + "integrity": "sha512-BxIUR4mfk0zOqOPEu4gxLP5herra6INQLyFmgVE6JVRNNB+r36g2cd67nDUEEdD/EShZvaR33xausxOGv1+nbw==" }, "@types/debug": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.5.tgz", - "integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.4.tgz", + "integrity": "sha512-D9MyoQFI7iP5VdpEyPZyjjqIJ8Y8EDNQFIFVLOmeg1rI1xiHOChyUPMPRUVfqFCerxfE+yS3vMyj37F6IdtOoQ==", "dev": true }, "@types/elliptic": { - "version": "6.4.10", - "resolved": "https://registry.npmjs.org/@types/elliptic/-/elliptic-6.4.10.tgz", - "integrity": "sha512-9h+Bw+aNiLzcq9DGstHccNxSsJ5iNId7mzruid7+kwm7F1IGvb4rBOOPo3+twt9ZPhI3y+JJ2m1UfgU8cOEJuQ==", - "dev": true, + "version": "6.4.9", + "resolved": "https://registry.npmjs.org/@types/elliptic/-/elliptic-6.4.9.tgz", + "integrity": "sha512-Mn+OyENd6YHwJKgUSyCTUDunEDFMaFpCXt52JCA00sxtzEa1ji6H0doZHL3iXhqMTo1Ob53X+Dv0s4PAJ+IVlA==", "requires": { "@types/bn.js": "*" } @@ -95,15 +66,14 @@ } }, "@types/node": { - "version": "12.11.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.11.7.tgz", - "integrity": "sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA==", - "dev": true + "version": "12.0.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.10.tgz", + "integrity": "sha512-LcsGbPomWsad6wmMNv7nBLw7YYYyfdYcz6xryKYQhx89c3XXan+8Q6AJ43G5XDIaklaVkK3mE4fCb0SBvMiPSQ==" }, "ajv": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", - "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", + "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", "dev": true, "requires": { "fast-deep-equal": "^2.0.1", @@ -113,9 +83,9 @@ } }, "ajv-keywords": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", - "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.0.tgz", + "integrity": "sha512-aUjdRFISbuFOl0EIZc+9e4FfZp0bDZgAdOOf30bJmw8VM9v84SHyVyxDfbWxpGYbdZD/9XoKxfHVNmxPkhwyGw==", "dev": true }, "ansi-align": { @@ -125,12 +95,46 @@ "dev": true, "requires": { "string-width": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } } }, "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true }, "ansi-styles": { @@ -160,9 +164,9 @@ } }, "anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.0.2.tgz", + "integrity": "sha512-rUe9SxpRQlVg4EM8It7JMNWWYHAirTPpbTuvaSKybb5IejNgWB3PGBBX9rrPKDx2pM/p3Wh+7+ASaWRyyAbxmQ==", "dev": true, "requires": { "normalize-path": "^3.0.0", @@ -170,39 +174,58 @@ } }, "app-builder-bin": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-3.4.3.tgz", - "integrity": "sha512-qMhayIwi3juerQEVJMQ76trObEbfQT0nhUdxZz9a26/3NLT3pE6awmQ8S1cEnrGugaaM5gYqR8OElcDezfmEsg==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-2.7.1.tgz", + "integrity": "sha512-ubIBeiL9XysjMW4HETBKxj3DC8ika6dGyC0vftPc0kZwGh1iXQ5bycsjoAqY/3t3BBEEIg0VruicvBaUl1pOSQ==", "dev": true }, "app-builder-lib": { - "version": "21.2.0", - "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-21.2.0.tgz", - "integrity": "sha512-aOX/nv77/Bti6NymJDg7p9T067xD8m1ipIEJR7B4Mm1GsJWpMm9PZdXtCRiMNRjHtQS5KIljT0g17781y6qn5A==", + "version": "20.44.4", + "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-20.44.4.tgz", + "integrity": "sha512-1K1xfrhyqDgnibwyuYMgvfwGilGLMF31YwOUJ8IXreyjRef9lUjWW+BZuBXqk4Uqd0C0EYPjhofgpuN0WoAQ+A==", "dev": true, "requires": { - "7zip-bin": "~5.0.3", - "@develar/schema-utils": "~2.1.0", + "7zip-bin": "~4.1.0", + "app-builder-bin": "2.7.1", "async-exit-hook": "^2.0.1", "bluebird-lst": "^1.0.9", - "builder-util": "21.2.0", - "builder-util-runtime": "8.3.0", + "builder-util": "10.1.2", + "builder-util-runtime": "8.2.5", "chromium-pickle-js": "^0.2.0", "debug": "^4.1.1", "ejs": "^2.6.2", - "electron-publish": "21.2.0", - "fs-extra": "^8.1.0", + "electron-osx-sign": "0.4.11", + "electron-publish": "20.44.4", + "fs-extra-p": "^8.0.2", "hosted-git-info": "^2.7.1", "is-ci": "^2.0.0", - "isbinaryfile": "^4.0.2", + "isbinaryfile": "^4.0.1", "js-yaml": "^3.13.1", "lazy-val": "^1.0.4", "minimatch": "^3.0.4", "normalize-package-data": "^2.5.0", - "read-config-file": "5.0.0", - "sanitize-filename": "^1.6.2", - "semver": "^6.3.0", - "temp-file": "^3.3.4" + "plist": "^3.0.1", + "read-config-file": "3.2.2", + "sanitize-filename": "^1.6.1", + "semver": "^6.1.1", + "temp-file": "^3.3.3" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "semver": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.1.2.tgz", + "integrity": "sha512-z4PqiCpomGtWj8633oeAdXm1Kn1W++3T8epkZYnwiVgIYIJ0QHszhInYSJTYxebByQH7KVCEAn8R9duzZW2PhQ==", + "dev": true + } } }, "argparse": { @@ -214,12 +237,57 @@ "sprintf-js": "~1.0.2" } }, + "array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "dev": true + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "dev": true + }, "async-exit-hook": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz", "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==", "dev": true }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "dev": true + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -234,7 +302,17 @@ "base64-js": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", - "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==" + "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } }, "binary-extensions": { "version": "2.0.0", @@ -242,48 +320,10 @@ "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", "dev": true }, - "bl": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", - "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", - "requires": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, "bluebird": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.1.tgz", - "integrity": "sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg==", + "version": "3.5.5", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", + "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==", "dev": true }, "bluebird-lst": { @@ -300,13 +340,6 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" }, - "boolean": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/boolean/-/boolean-2.0.2.tgz", - "integrity": "sha512-ymsbJQlux/uogyEWfsXJUYzuyoOzPyp6NvEV71s6/ptQR7ptKO9uHF+WZL2GRATDeN52EFhNyrIu+exNZKh3Cw==", - "dev": true, - "optional": true - }, "boxen": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/boxen/-/boxen-3.2.0.tgz", @@ -321,6 +354,46 @@ "term-size": "^1.2.0", "type-fest": "^0.3.0", "widest-line": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } } }, "brace-expansion": { @@ -347,19 +420,11 @@ "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" }, - "buffer": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.4.3.tgz", - "integrity": "sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" - } - }, "buffer-alloc": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "dev": true, "requires": { "buffer-alloc-unsafe": "^1.1.0", "buffer-fill": "^1.0.0" @@ -368,17 +433,14 @@ "buffer-alloc-unsafe": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", - "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" - }, - "buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "dev": true }, "buffer-fill": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", - "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=" + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=", + "dev": true }, "buffer-from": { "version": "1.1.1", @@ -387,34 +449,58 @@ "dev": true }, "builder-util": { - "version": "21.2.0", - "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-21.2.0.tgz", - "integrity": "sha512-Nd6CUb6YgDY8EXAXEIegx+1kzKqyFQ5ZM5BoYkeunAlwz/zDJoH1UCyULjoS5wQe5czNClFQy07zz2bzYD0Z4A==", + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-10.1.2.tgz", + "integrity": "sha512-LQMh36Cg0r4ZfKqNlaUclndS/IXxZ3OdCgmXvw1vdP3QwYT2NkyE7LfMikAFIHpXOs6zsVH+iW+Fe/AX1jfFag==", "dev": true, "requires": { - "7zip-bin": "~5.0.3", + "7zip-bin": "~4.1.0", "@types/debug": "^4.1.4", - "app-builder-bin": "3.4.3", + "app-builder-bin": "2.7.1", "bluebird-lst": "^1.0.9", - "builder-util-runtime": "8.3.0", + "builder-util-runtime": "^8.2.5", "chalk": "^2.4.2", "debug": "^4.1.1", - "fs-extra": "^8.1.0", + "fs-extra-p": "^8.0.2", "is-ci": "^2.0.0", "js-yaml": "^3.13.1", - "source-map-support": "^0.5.13", + "source-map-support": "^0.5.12", "stat-mode": "^0.3.0", - "temp-file": "^3.3.4" + "temp-file": "^3.3.3" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } } }, "builder-util-runtime": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.3.0.tgz", - "integrity": "sha512-CSOdsYqf4RXIHh1HANPbrZHlZ9JQJXSuDDloblZPcWQVN62inyYoTQuSmY3KrgefME2Sv3Kn2MxHvbGQHRf8Iw==", + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.2.5.tgz", + "integrity": "sha512-YILT+YUlxrE3yNB6mDC1tF+Q24mr1LSYdjP5U861jbBeDZfvy1/VPDzW3boMVrDtzYnDnvkYrzLJnoh6TXA75w==", "dev": true, "requires": { + "bluebird-lst": "^1.0.9", "debug": "^4.1.1", + "fs-extra-p": "^8.0.2", "sax": "^1.2.4" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } } }, "cacheable-request": { @@ -450,9 +536,25 @@ } }, "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "dev": true + }, + "camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "dev": true, + "requires": { + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" + } + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", "dev": true }, "chalk": { @@ -467,21 +569,21 @@ } }, "chart.js": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.9.1.tgz", - "integrity": "sha512-DA5dFt0Bz79oz56ezmrwmZqj0hXGs+i9VbCFOcHqbwrHIGv7RI4YqninJKNIAC0qa29WBI9qYTN7LzULlOeunA==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.8.0.tgz", + "integrity": "sha512-Di3wUL4BFvqI5FB5K26aQ+hvWh8wnP9A3DWGvXHVkO13D3DSnaSsdZx29cXlEsYKVkn1E2az+ZYFS4t0zi8x0w==", "requires": { "chartjs-color": "^2.1.0", "moment": "^2.10.2" } }, "chartjs-color": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.4.1.tgz", - "integrity": "sha512-haqOg1+Yebys/Ts/9bLo/BqUcONQOdr/hoEr2LLTRl6C5LXctUdHxsCYfvQVg5JIxITrfCNUDr4ntqmQk9+/0w==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.3.0.tgz", + "integrity": "sha512-hEvVheqczsoHD+fZ+tfPUE+1+RbV6b+eksp2LwAhwRTVXEjCSEavvk+Hg3H6SZfGlPh/UfmWKGIvZbtobOEm3g==", "requires": { "chartjs-color-string": "^0.6.0", - "color-convert": "^1.9.3" + "color-convert": "^0.5.3" } }, "chartjs-color-string": { @@ -493,19 +595,20 @@ } }, "chokidar": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.2.3.tgz", - "integrity": "sha512-GtrxGuRf6bzHQmXWRepvsGnXpkQkVU+D2/9a7dAe4a7v1NhrfZOZ2oKf76M3nOs46fFYL8D+Q8JYA4GYeJ8Cjw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.0.1.tgz", + "integrity": "sha512-2ww34sJWehnbpV0Q4k4V5Hh7juo7po6z7LUWkcIQnSGN1lHOL8GGtLtfwabKvLFQw/hbSUQ0u6V7OgGYgBzlkQ==", "dev": true, "requires": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "fsevents": "~2.1.1", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.2.0" + "anymatch": "^3.0.1", + "async-each": "^1.0.3", + "braces": "^3.0.2", + "fsevents": "^2.0.6", + "glob-parent": "^5.0.0", + "is-binary-path": "^2.1.0", + "is-glob": "^4.0.1", + "normalize-path": "^3.0.0", + "readdirp": "^3.0.2" } }, "chromium-pickle-js": { @@ -535,6 +638,40 @@ "string-width": "^3.1.0", "strip-ansi": "^5.2.0", "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } } }, "clone-response": { @@ -546,34 +683,37 @@ "mimic-response": "^1.0.0" } }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - }, - "dependencies": { - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - } - } + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz", + "integrity": "sha1-vbbGnOZg+t/+CwAHzER+G59ygr0=" }, "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "commander": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", - "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, "requires": { - "graceful-readlink": ">= 1.0.0" + "delayed-stream": "~1.0.0" } }, + "compare-version": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/compare-version/-/compare-version-0.1.2.tgz", + "integrity": "sha1-AWLsLZNR9d3VmpICy6k1NmpyUIA=", + "dev": true + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -590,17 +730,38 @@ "inherits": "^2.0.3", "readable-stream": "^2.2.2", "typedarray": "^0.0.6" - } - }, - "config-chain": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", - "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", - "dev": true, - "optional": true, - "requires": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } } }, "configstore": { @@ -617,17 +778,11 @@ "xdg-basedir": "^3.0.0" } }, - "core-js": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.3.5.tgz", - "integrity": "sha512-0J3K+Par/ZydhKg8pEiTcK/9d65/nqJOzY62uMkjeBmt05fDOt/khUVjDdh8TpeIuGQDy1yLDDCjiWN/8pFIuw==", - "dev": true, - "optional": true - }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true }, "cross-spawn": { "version": "5.1.0", @@ -646,10 +801,28 @@ "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", "dev": true }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "dev": true, + "requires": { + "array-find-index": "^1.0.1" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "dev": true, "requires": { "ms": "^2.1.1" @@ -661,21 +834,6 @@ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, - "decompress": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.0.tgz", - "integrity": "sha1-eu3YVCflqS2s/lVnSnxQXpbQH50=", - "requires": { - "decompress-tar": "^4.0.0", - "decompress-tarbz2": "^4.0.0", - "decompress-targz": "^4.0.0", - "decompress-unzip": "^4.0.1", - "graceful-fs": "^4.1.10", - "make-dir": "^1.0.0", - "pify": "^2.3.0", - "strip-dirs": "^2.0.0" - } - }, "decompress-response": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", @@ -685,89 +843,6 @@ "mimic-response": "^1.0.0" } }, - "decompress-tar": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", - "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", - "requires": { - "file-type": "^5.2.0", - "is-stream": "^1.1.0", - "tar-stream": "^1.5.2" - } - }, - "decompress-tarbz2": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", - "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", - "requires": { - "decompress-tar": "^4.1.0", - "file-type": "^6.1.0", - "is-stream": "^1.1.0", - "seek-bzip": "^1.0.5", - "unbzip2-stream": "^1.0.9" - }, - "dependencies": { - "file-type": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", - "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==" - } - } - }, - "decompress-targz": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", - "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", - "requires": { - "decompress-tar": "^4.1.1", - "file-type": "^5.2.0", - "is-stream": "^1.1.0" - } - }, - "decompress-unzip": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", - "integrity": "sha1-3qrM39FK6vhVePczroIQ+bSEj2k=", - "requires": { - "file-type": "^3.8.0", - "get-stream": "^2.2.0", - "pify": "^2.3.0", - "yauzl": "^2.4.2" - }, - "dependencies": { - "fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", - "requires": { - "pend": "~1.2.0" - } - }, - "file-type": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", - "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=" - }, - "get-stream": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", - "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=", - "requires": { - "object-assign": "^4.0.1", - "pinkie-promise": "^2.0.0" - } - }, - "yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", - "requires": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - } - } - }, "deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -780,36 +855,26 @@ "integrity": "sha512-k09hcQcTDY+cwgiwa6PYKLm3jlagNzQ+RSvhjzESOGOx+MNOuXkxTfEvPrO1IOQ81tArCFYQgi631clB70RpQw==", "dev": true }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "optional": true, - "requires": { - "object-keys": "^1.0.12" - } - }, - "detect-node": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", - "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==", - "dev": true, - "optional": true + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true }, "dmg-builder": { - "version": "21.2.0", - "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-21.2.0.tgz", - "integrity": "sha512-9cJEclnGy7EyKFCoHDYDf54pub/t92CQapyiUxU0w9Bj2vUvfoDagP1PMiX4XD5rPp96141h9A+QN0OB4VgvQg==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-6.7.2.tgz", + "integrity": "sha512-xfYOwhHjOSOIqkk8A0h8zcaio/WyzrAWpMTu9hzV3Z5PI4tOG0Pq6a9Lh/mHr1r3bydif8R21qGvKU1Re9CpUg==", "dev": true, "requires": { - "app-builder-lib": "~21.2.0", + "app-builder-lib": "~20.44.4", "bluebird-lst": "^1.0.9", - "builder-util": "~21.2.0", - "fs-extra": "^8.1.0", - "iconv-lite": "^0.5.0", + "builder-util": "~10.1.2", + "fs-extra-p": "^8.0.2", + "iconv-lite": "^0.4.24", "js-yaml": "^3.13.1", - "sanitize-filename": "^1.6.2" + "parse-color": "^1.0.0", + "sanitize-filename": "^1.6.1" } }, "dot-prop": { @@ -822,15 +887,15 @@ } }, "dotenv": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", - "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.2.0.tgz", + "integrity": "sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w==", "dev": true }, "dotenv-expand": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", - "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-4.2.0.tgz", + "integrity": "sha1-3vHxyl1gWdJKdm5YeULCEQbOEnU=", "dev": true }, "duplexer3": { @@ -839,63 +904,138 @@ "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", "dev": true }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, "ejs": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.1.tgz", - "integrity": "sha512-kS/gEPzZs3Y1rRsbGX4UOSjtP/CeJP0CxSNZHYxGfVM/VgLcv0ZqM7C45YyTj2DI2g7+P9Dd24C+IMIg6D0nYQ==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.6.2.tgz", + "integrity": "sha512-PcW2a0tyTuPHz3tWyYqtK6r1fZ3gp+3Sop8Ph+ZYN81Ob5rwmbHEzaqs10N3BEsaGTkh/ooniXK+WwszGlc2+Q==", "dev": true }, "electron": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/electron/-/electron-7.0.0.tgz", - "integrity": "sha512-vrF1loRW1p0vQCbduqO0EZpo8ePJOuxUT6tSoUSU3lsbGK3VnlJop+0PpCIPzbe2K4G4Gk7WexH08V9se7mJcA==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/electron/-/electron-5.0.6.tgz", + "integrity": "sha512-0L53lv26eDhaaNxL6DqXGQrQOEAYbrQg40stRSb2pzrY06kwPbABzXEiaCvEsBuKUQ+9OQBbVyyvXRbLJlun/A==", "dev": true, "requires": { - "@electron/get": "^1.0.1", - "@types/node": "^12.0.12", + "@types/node": "^10.12.18", + "electron-download": "^4.1.0", "extract-zip": "^1.0.3" + }, + "dependencies": { + "@types/node": { + "version": "10.14.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.10.tgz", + "integrity": "sha512-V8wj+w2YMNvGuhgl/MA5fmTxgjmVHVoasfIaxMMZJV6Y8Kk+Ydpi1z2whoShDCJ2BuNVoqH/h1hrygnBxkrw/Q==", + "dev": true + } } }, "electron-builder": { - "version": "21.2.0", - "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-21.2.0.tgz", - "integrity": "sha512-x8EXrqFbAb2L3N22YlGar3dGh8vwptbB3ovo3OF6K7NTpcsmM2zEoJv7GhFyX73rNzSG2HaWpXwGAtOp2JWiEw==", + "version": "20.44.4", + "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-20.44.4.tgz", + "integrity": "sha512-H8zzP01albkKh2Ec1zc0A7RGriUkHb5M99NJskaYtgKtGATTAGH+r9OIWVk5Hk9c1dLMVudbqEeaSlygMF2asw==", "dev": true, "requires": { - "app-builder-lib": "21.2.0", + "app-builder-lib": "20.44.4", "bluebird-lst": "^1.0.9", - "builder-util": "21.2.0", - "builder-util-runtime": "8.3.0", + "builder-util": "10.1.2", + "builder-util-runtime": "8.2.5", "chalk": "^2.4.2", - "dmg-builder": "21.2.0", - "fs-extra": "^8.1.0", + "dmg-builder": "6.7.2", + "fs-extra-p": "^8.0.2", "is-ci": "^2.0.0", "lazy-val": "^1.0.4", - "read-config-file": "5.0.0", - "sanitize-filename": "^1.6.2", - "update-notifier": "^3.0.1", - "yargs": "^13.3.0" + "read-config-file": "3.2.2", + "sanitize-filename": "^1.6.1", + "update-notifier": "^3.0.0", + "yargs": "^13.2.4" + } + }, + "electron-download": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/electron-download/-/electron-download-4.1.1.tgz", + "integrity": "sha512-FjEWG9Jb/ppK/2zToP+U5dds114fM1ZOJqMAR4aXXL5CvyPE9fiqBK/9YcwC9poIFQTEJk/EM/zyRwziziRZrg==", + "dev": true, + "requires": { + "debug": "^3.0.0", + "env-paths": "^1.0.0", + "fs-extra": "^4.0.1", + "minimist": "^1.2.0", + "nugget": "^2.0.1", + "path-exists": "^3.0.0", + "rc": "^1.2.1", + "semver": "^5.4.1", + "sumchecker": "^2.0.2" + } + }, + "electron-osx-sign": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/electron-osx-sign/-/electron-osx-sign-0.4.11.tgz", + "integrity": "sha512-VVd40nrnVqymvFrY9ZkOYgHJOvexHHYTR3di/SN+mjJ0OWhR1I8BRVj3U+Yamw6hnkZZNKZp52rqL5EFAAPFkQ==", + "dev": true, + "requires": { + "bluebird": "^3.5.0", + "compare-version": "^0.1.2", + "debug": "^2.6.8", + "isbinaryfile": "^3.0.2", + "minimist": "^1.2.0", + "plist": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "isbinaryfile": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.3.tgz", + "integrity": "sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==", + "dev": true, + "requires": { + "buffer-alloc": "^1.2.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } } }, "electron-publish": { - "version": "21.2.0", - "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-21.2.0.tgz", - "integrity": "sha512-mWavuoWJe87iaeKd0I24dNWIaR+0yRzshjNVqGyK019H766fsPWl3caQJnVKFaEyrZRP397v4JZVG0e7s16AxA==", + "version": "20.44.4", + "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-20.44.4.tgz", + "integrity": "sha512-50NzsKOnNqOpGJzPl04vMyitdguUvp15FWKWtu4KISsHfgdLMWGgxHGZwfMphc/vf364zXvPHsYQza3MASgaEQ==", "dev": true, "requires": { "bluebird-lst": "^1.0.9", - "builder-util": "~21.2.0", - "builder-util-runtime": "8.3.0", + "builder-util": "~10.1.2", + "builder-util-runtime": "^8.2.5", "chalk": "^2.4.2", - "fs-extra": "^8.1.0", + "fs-extra-p": "^8.0.2", "lazy-val": "^1.0.4", "mime": "^2.4.4" } }, "elliptic": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.1.tgz", - "integrity": "sha512-xvJINNLbTeWQjrl6X+7eQCrIy/YPv5XCpKW6kB5mKvtnGILoLDcySuwomfdzt0BMdLNVnuRNTuzKNHj0bva1Cg==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.0.tgz", + "integrity": "sha512-eFOJTMyCYb7xtE/caJ6JJu+bhi67WCYNbkGSknu20pmM8Ke/bqOfdnZWxyoGN26JgfxTbXrsCkEw4KheCT/KGg==", "requires": { "bn.js": "^4.4.0", "brorand": "^1.0.1", @@ -912,33 +1052,29 @@ "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "dev": true }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", - "dev": true, - "optional": true - }, "end-of-stream": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "dev": true, "requires": { "once": "^1.4.0" } }, "env-paths": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.0.tgz", - "integrity": "sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-1.0.0.tgz", + "integrity": "sha1-QWgTO0K7BcOKNbGuQ5fIKYqzaeA=", "dev": true }, - "es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, - "optional": true + "requires": { + "is-arrayish": "^0.2.1" + } }, "escape-string-regexp": { "version": "1.0.5", @@ -967,6 +1103,12 @@ "strip-eof": "^1.0.0" } }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, "extract-zip": { "version": "1.6.7", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.7.tgz", @@ -996,6 +1138,12 @@ } } }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, "fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", @@ -1017,11 +1165,6 @@ "pend": "~1.2.0" } }, - "file-type": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", - "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=" - }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -1032,41 +1175,81 @@ } }, "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "dev": true, "requires": { - "locate-path": "^3.0.0" + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + } } }, - "fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } }, "fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", "dev": true, "requires": { - "graceful-fs": "^4.2.0", + "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, - "fsevents": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.1.tgz", - "integrity": "sha512-4FRPXWETxtigtJW/gxzEDsX1LVbPAM93VleB83kZB+ellqbHMkyt2aJfuzNLRvFPnGi6bcE5SvfxgbXPeKteJw==", + "fs-extra-p": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/fs-extra-p/-/fs-extra-p-8.0.2.tgz", + "integrity": "sha512-dpWboLA/OlyuqGQdsTjC2PKNkise3O4ptcMpXoyfeM/VXrthkEape3I+drWLI0JAW46r1D3eb6QBSPkSyXPXzA==", "dev": true, - "optional": true + "requires": { + "bluebird-lst": "^1.0.9", + "fs-extra": "^8.0.1" + }, + "dependencies": { + "fs-extra": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.0.1.tgz", + "integrity": "sha512-W+XLrggcDzlle47X/XnS7FXrXu9sDo+Ze9zpndeBxdgv88FHLm1HtmkhEwavruS6koanBjp098rUpHs65EmG7A==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + } + } }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "fsevents": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.0.7.tgz", + "integrity": "sha512-a7YT0SV3RB+DjYcppwVDLtn13UQnmg0SWZS7ezZD0UjnLwXmy8Zm21GMVGLaFGimIqcvyMQaOJBrop8MyOp1kQ==", "dev": true, "optional": true }, @@ -1076,78 +1259,43 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "dev": true + }, "get-stream": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true - }, - "glob-parent": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", - "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "global-agent": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-2.1.5.tgz", - "integrity": "sha512-pYJjCxxNBzYxo6iNO62JZn8iCFVbvpiM0zE4w/G5hBNIvLjnvzIeCVQPMKc3aK8ju5L7Q8NNI/oBSosU0eeSYw==", - "dev": true, - "optional": true, - "requires": { - "boolean": "^2.0.2", - "core-js": "^3.3.3", - "es6-error": "^4.1.1", - "matcher": "^2.0.0", - "roarr": "^2.14.2", - "semver": "^6.3.0", - "serialize-error": "^5.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "optional": true - } - } + "dev": true }, - "global-dirs": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", - "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "dev": true, "requires": { - "ini": "^1.3.4" + "assert-plus": "^1.0.0" } }, - "global-tunnel-ng": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/global-tunnel-ng/-/global-tunnel-ng-2.7.1.tgz", - "integrity": "sha512-4s+DyciWBV0eK148wqXxcmVAbFVPqtc3sEtUE/GTQfuU80rySLcMhUmHKSHI7/LDj8q0gDYI1lIhRRB7ieRAqg==", + "glob-parent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.0.0.tgz", + "integrity": "sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg==", "dev": true, - "optional": true, "requires": { - "encodeurl": "^1.0.2", - "lodash": "^4.17.10", - "npm-conf": "^1.1.3", - "tunnel": "^0.0.6" + "is-glob": "^4.0.1" } }, - "globalthis": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.0.tgz", - "integrity": "sha512-vcCAZTJ3r5Qcu5l8/2oyVdoFwxKgfYnMTR2vwWeux/NAVZK3PwcMaWkdUIn4GJbmKuRK7xcvDsLuK+CKcXyodg==", + "global-dirs": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", + "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", "dev": true, - "optional": true, "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "object-keys": "^1.0.12" + "ini": "^1.3.4" } }, "got": { @@ -1183,12 +1331,24 @@ "graceful-fs": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz", - "integrity": "sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg==" + "integrity": "sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg==", + "dev": true }, - "graceful-readlink": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", - "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=" + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "dev": true, + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } }, "has-flag": { "version": "3.0.0", @@ -1222,9 +1382,9 @@ } }, "hosted-git-info": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz", - "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", + "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", "dev": true }, "http-cache-semantics": { @@ -1233,20 +1393,26 @@ "integrity": "sha512-TcIMG3qeVLgDr1TEd2XvHaTnMPwYQUQMIBLy+5pLSDKYFc7UIqj39w8EGzZkaxoLv/l2K8HaI0t5AVA+YYgUew==", "dev": true }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, "iconv-lite": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.0.tgz", - "integrity": "sha512-NnEhI9hIEKHOzJ4f697DMz9IQEXr/MMJ5w64vN2/4Ai+wRnvV7SBrL0KLoRlwaKVghOc7LQ5YkPLuX146b6Ydw==", + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" } }, - "ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" - }, "import-lazy": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", @@ -1259,6 +1425,15 @@ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "dev": true, + "requires": { + "repeating": "^2.0.0" + } + }, "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", @@ -1270,6 +1445,18 @@ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, "is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -1294,11 +1481,23 @@ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } }, "is-glob": { "version": "4.0.1", @@ -1319,11 +1518,6 @@ "is-path-inside": "^1.0.0" } }, - "is-natural-number": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", - "integrity": "sha1-q5124dtM7VHjXeDHLr7PCfc0zeg=" - }, "is-npm": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-3.0.0.tgz", @@ -1354,7 +1548,20 @@ "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true }, "is-yarn-global": { "version": "0.3.0", @@ -1363,15 +1570,15 @@ "dev": true }, "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", "dev": true }, "isbinaryfile": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.2.tgz", - "integrity": "sha512-C3FSxJdNrEr2F4z6uFtNzECDM5hXk+46fxaa+cwBe5/XrWSmzdG8DDgyjfX6/NRdBB21q2JXuRAzPCUs+fclnQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.1.tgz", + "integrity": "sha512-bvJxbNWm72dy/1+qeBm9F8wUM4siDnlzid7NN5Ib4nQcc0tNIx/YWgEih1ZRHXr8xVbpGk1ccLlA9gOSlyx3gw==", "dev": true }, "isexe": { @@ -1380,6 +1587,12 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, "js-yaml": { "version": "3.13.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", @@ -1390,12 +1603,24 @@ "esprima": "^4.0.0" } }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, "json-buffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", "dev": true }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -1406,13 +1631,12 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true, - "optional": true + "dev": true }, "json5": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz", - "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", + "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", "dev": true, "requires": { "minimist": "^1.2.0" @@ -1427,6 +1651,18 @@ "graceful-fs": "^4.1.6" } }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, "keyv": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", @@ -1451,6 +1687,15 @@ "integrity": "sha512-u93kb2fPbIrfzBuLjZE+w+fJbUUMhNDXxNmMfaqNgpfQf1CO5ZSe2LfsnBqVAk7i/2NF48OSoRj+Xe2VT+lE8Q==", "dev": true }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, "leaflet": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.5.1.tgz", @@ -1461,6 +1706,19 @@ "resolved": "https://registry.npmjs.org/leaflet.awesome-markers/-/leaflet.awesome-markers-2.0.5.tgz", "integrity": "sha512-Ne/xDjkGyaujwNVVkv2tyXQUV0ZW7gZ0Mo0FuQY4jp2qWrvXi0hwDBvmZyF/8YOvybyMabTMM/mFWCTd1jZIQA==" }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + } + }, "locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", @@ -1471,12 +1729,15 @@ "path-exists": "^3.0.0" } }, - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", "dev": true, - "optional": true + "requires": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" + } }, "lowercase-keys": { "version": "1.0.1", @@ -1498,6 +1759,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, "requires": { "pify": "^3.0.0" }, @@ -1505,27 +1767,53 @@ "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true } } }, - "matcher": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/matcher/-/matcher-2.0.0.tgz", - "integrity": "sha512-nlmfSlgHBFx36j/Pl/KQPbIaqE8Zf0TqmSMjsuddHDg6PMSVgmyW9HpkLs0o0M1n2GIZ/S2BZBLIww/xjhiGng==", + "map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", "dev": true, - "optional": true, "requires": { - "escape-string-regexp": "^2.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "optional": true - } + "p-defer": "^1.0.0" + } + }, + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + }, + "mem": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", + "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + } + }, + "meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "dev": true, + "requires": { + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", + "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", + "minimist": "^1.1.3", + "normalize-package-data": "^2.3.4", + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" } }, "mime": { @@ -1534,6 +1822,27 @@ "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", "dev": true }, + "mime-db": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", + "dev": true + }, + "mime-types": { + "version": "2.1.24", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", + "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "dev": true, + "requires": { + "mime-db": "1.40.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, "mimic-response": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", @@ -1593,6 +1902,12 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -1603,14 +1918,6 @@ "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } } }, "normalize-path": { @@ -1620,31 +1927,11 @@ "dev": true }, "normalize-url": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", - "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.3.0.tgz", + "integrity": "sha512-0NLtR71o4k6GLP+mr6Ty34c5GA6CMoEsncKJxvQd8NzPxaHRJNnb5gZE8R1XF4CPIS7QPHLJ74IFszwtNVAHVQ==", "dev": true }, - "npm-conf": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz", - "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==", - "dev": true, - "optional": true, - "requires": { - "config-chain": "^1.1.11", - "pify": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true, - "optional": true - } - } - }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -1654,42 +1941,149 @@ "path-key": "^2.0.0" } }, + "nugget": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/nugget/-/nugget-2.0.1.tgz", + "integrity": "sha1-IBCVpIfhrTYIGzQy+jytpPjQcbA=", + "dev": true, + "requires": { + "debug": "^2.1.3", + "minimist": "^1.1.0", + "pretty-bytes": "^1.0.2", + "progress-stream": "^1.1.0", + "request": "^2.45.0", + "single-line-log": "^1.1.2", + "throttleit": "0.0.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true }, "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "optional": true + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", + "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=", + "dev": true }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, "requires": { "wrappy": "1" } }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + } + } + }, "p-cancelable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", "dev": true }, + "p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", + "dev": true + }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", "dev": true }, + "p-is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", + "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", + "dev": true + }, "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -1711,15 +2105,41 @@ "dev": true }, "package-json": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", - "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.4.0.tgz", + "integrity": "sha512-bd1T8OBG7hcvMd9c/udgv6u5v9wISP3Oyl9Cm7Weop8EFwrtcQDnS2sb6zhwqus2WslSr5wSTIPiTTpxxmPm7Q==", "dev": true, "requires": { "got": "^9.6.0", - "registry-auth-token": "^4.0.0", + "registry-auth-token": "^3.4.0", "registry-url": "^5.0.0", - "semver": "^6.2.0" + "semver": "^6.1.1" + }, + "dependencies": { + "semver": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.1.2.tgz", + "integrity": "sha512-z4PqiCpomGtWj8633oeAdXm1Kn1W++3T8epkZYnwiVgIYIJ0QHszhInYSJTYxebByQH7KVCEAn8R9duzZW2PhQ==", + "dev": true + } + } + }, + "parse-color": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-color/-/parse-color-1.0.0.tgz", + "integrity": "sha1-e3SLlag/A/FqlPU15S1/PZRlhhk=", + "dev": true, + "requires": { + "color-convert": "~0.5.0" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" } }, "path-exists": { @@ -1746,10 +2166,28 @@ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "dev": true }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, "pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "dev": true + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true }, "picomatch": { "version": "2.0.7", @@ -1760,38 +2198,66 @@ "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true }, "pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true }, "pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, "requires": { "pinkie": "^2.0.0" } }, + "plist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.1.tgz", + "integrity": "sha512-GpgvHHocGRyQm74b6FWEZZVRroHKE1I0/BTjAmySaohK+cUn+hZpbqXkc3KWgW3gQYkqcQej35FohcT0FRlkRQ==", + "dev": true, + "requires": { + "base64-js": "^1.2.3", + "xmlbuilder": "^9.0.7", + "xmldom": "0.1.x" + } + }, "prepend-http": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", "dev": true }, + "pretty-bytes": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-1.0.4.tgz", + "integrity": "sha1-CiLoIQYJrTVUL4yNXSFZr/B1HIQ=", + "dev": true, + "requires": { + "get-stdin": "^4.0.1", + "meow": "^3.1.0" + } + }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true }, - "proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", + "progress-stream": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/progress-stream/-/progress-stream-1.2.0.tgz", + "integrity": "sha1-LNPP6jO6OonJwSHsM0er6asSX3c=", "dev": true, - "optional": true + "requires": { + "speedometer": "~0.1.2", + "through2": "~0.2.3" + } }, "pseudomap": { "version": "1.0.2", @@ -1799,6 +2265,12 @@ "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", "dev": true }, + "psl": { + "version": "1.1.33", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.33.tgz", + "integrity": "sha512-LTDP2uSrsc7XCb5lO7A8BI1qYxRe/8EqlRvMeEl6rsnYAqDOl8xHR+8lSAIVfrNaSAlTPTNOCgNjWcoUL3AZsw==", + "dev": true + }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -1815,6 +2287,12 @@ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, "rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -1828,50 +2306,104 @@ } }, "read-config-file": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/read-config-file/-/read-config-file-5.0.0.tgz", - "integrity": "sha512-jIKUu+C84bfnKxyJ5j30CxCqgXWYjZLXuVE/NYlMEpeni+dhESgAeZOZd0JZbg1xTkMmnCdxksDoarkOyfEsOg==", - "dev": true, - "requires": { - "dotenv": "^8.0.0", - "dotenv-expand": "^5.1.0", - "fs-extra": "^8.1.0", - "js-yaml": "^3.13.1", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/read-config-file/-/read-config-file-3.2.2.tgz", + "integrity": "sha512-PuFpMgZF01VB0ydH1dfitAxCP/fh+qnfbA9cYNIPoxPbz0SMngsrafCtaHDWfER7MwlDz4fmrNBhPkakxxFpTg==", + "dev": true, + "requires": { + "ajv": "^6.9.2", + "ajv-keywords": "^3.4.0", + "bluebird-lst": "^1.0.7", + "dotenv": "^6.2.0", + "dotenv-expand": "^4.2.0", + "fs-extra-p": "^7.0.1", + "js-yaml": "^3.12.1", "json5": "^2.1.0", "lazy-val": "^1.0.4" + }, + "dependencies": { + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs-extra-p": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra-p/-/fs-extra-p-7.0.1.tgz", + "integrity": "sha512-yhd2OV0HnHt2oitlp+X9hl2ReX4X/7kQeL7/72qzPHTZj5eUPGzAKOvEglU02Fa1OeG2rSy/aKB4WGVaLiF8tw==", + "dev": true, + "requires": { + "bluebird-lst": "^1.0.7", + "fs-extra": "^7.0.1" + } + } + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" } }, "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "dev": true, "requires": { "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" } }, "readdirp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", - "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.0.2.tgz", + "integrity": "sha512-LbyJYv48eywrhOlScq16H/VkCiGKGPC2TpOdZCJ7QXnYEjn3NN/Oblh8QEU3vqfSRBB7OGvh5x45NKiVeNujIQ==", "dev": true, "requires": { "picomatch": "^2.0.4" } }, + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "dev": true, + "requires": { + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" + } + }, "registry-auth-token": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.0.0.tgz", - "integrity": "sha512-lpQkHxd9UL6tb3k/aHAVfnVtn+Bcs9ob5InuFLLEDqSqeq+AljB8GZW9xY0x7F+xYwEcjKe07nyoxzEYz6yvkw==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", + "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==", "dev": true, "requires": { - "rc": "^1.2.8", + "rc": "^1.1.6", "safe-buffer": "^5.0.1" } }, @@ -1884,6 +2416,43 @@ "rc": "^1.2.8" } }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "requires": { + "is-finite": "^1.0.0" + } + }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -1897,9 +2466,9 @@ "dev": true }, "resolve": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", - "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.1.tgz", + "integrity": "sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==", "dev": true, "requires": { "path-parse": "^1.0.6" @@ -1914,34 +2483,11 @@ "lowercase-keys": "^1.0.0" } }, - "roarr": { - "version": "2.14.2", - "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.14.2.tgz", - "integrity": "sha512-ibqv70DCUhGVMfPe0JSUHBZ9PKLhxdk8VJ/Y2M7vVr+L4VakW1CdVTU9cJQBbM2STQa84CgBAzd7hJGcnALGeg==", - "dev": true, - "optional": true, - "requires": { - "boolean": "^2.0.2", - "detect-node": "^2.0.4", - "globalthis": "^1.0.0", - "json-stringify-safe": "^5.0.1", - "semver-compare": "^1.0.0", - "sprintf-js": "^1.1.2" - }, - "dependencies": { - "sprintf-js": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", - "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", - "dev": true, - "optional": true - } - } - }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -1950,18 +2496,18 @@ "dev": true }, "sanitize-filename": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz", - "integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.1.tgz", + "integrity": "sha1-YS2hyWRz+gLczaktzVtKsWSmdyo=", "dev": true, "requires": { "truncate-utf8-bytes": "^1.0.0" } }, "sass": { - "version": "1.23.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.23.1.tgz", - "integrity": "sha512-zQzJ3UETUWOMd/pJJGH/zvRsBVO97m11RcpfUhcQUHEXf0yHUBgOIE/Nw8aK0m1XyVJPeq228iIK7gVxsJ/Puw==", + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.22.1.tgz", + "integrity": "sha512-VsWrNdfIzCLbD2TO2bq9tCaUzEE0UUSGtP3r9IhHi8ypAPCb3FOVP99kMRil+ZROEcTnKReZcQP9vk6ArV2eLw==", "dev": true, "requires": { "chokidar": ">=2.0.0 <4.0.0" @@ -1973,27 +2519,12 @@ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true }, - "seek-bzip": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.5.tgz", - "integrity": "sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w=", - "requires": { - "commander": "~2.8.1" - } - }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", "dev": true }, - "semver-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", - "dev": true, - "optional": true - }, "semver-diff": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", @@ -2001,33 +2532,6 @@ "dev": true, "requires": { "semver": "^5.0.3" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "serialize-error": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-5.0.0.tgz", - "integrity": "sha512-/VtpuyzYf82mHYTtI4QKtwHa79vAdU5OQpNPAmE/0UDdlGT0ZxHwC+J6gXkw29wwoVI8fMPsfcVHOwXtUQYYQA==", - "dev": true, - "optional": true, - "requires": { - "type-fest": "^0.8.0" - }, - "dependencies": { - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, - "optional": true - } } }, "set-blocking": { @@ -2057,6 +2561,15 @@ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, + "single-line-log": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/single-line-log/-/single-line-log-1.1.2.tgz", + "integrity": "sha1-wvg/Jzo+GhbtsJlWYdoO1e8DM2Q=", + "dev": true, + "requires": { + "string-width": "^1.0.1" + } + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -2064,9 +2577,9 @@ "dev": true }, "source-map-support": { - "version": "0.5.15", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.15.tgz", - "integrity": "sha512-wYF5aX1J0+V51BDT3Om7uXNn0ct2FWiV4bvwiGVefxkm+1S1o5jsecE5lb2U28DDblzxzxeIDbTVpXHI9D/9hA==", + "version": "0.5.12", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.12.tgz", + "integrity": "sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==", "dev": true, "requires": { "buffer-from": "^1.0.0", @@ -2100,9 +2613,15 @@ } }, "spdx-license-ids": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", - "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz", + "integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==", + "dev": true + }, + "speedometer": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/speedometer/-/speedometer-0.1.4.tgz", + "integrity": "sha1-mHbb0qFp0xFUAtSObqYynIgWpQ0=", "dev": true }, "sprintf-js": { @@ -2111,6 +2630,23 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, "stat-mode": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-0.3.0.tgz", @@ -2118,40 +2654,38 @@ "dev": true }, "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true }, "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "^4.1.0" + "ansi-regex": "^2.0.0" } }, - "strip-dirs": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", - "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, "requires": { - "is-natural-number": "^4.0.1" + "is-utf8": "^0.2.0" } }, "strip-eof": { @@ -2160,6 +2694,15 @@ "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, + "strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "dev": true, + "requires": { + "get-stdin": "^4.0.1" + } + }, "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", @@ -2167,12 +2710,29 @@ "dev": true }, "sumchecker": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.0.tgz", - "integrity": "sha512-yreseuC/z4iaodVoq07XULEOO9p4jnQazO7mbrnDSvWAU/y2cbyIKs+gWJptfcGu9R+1l27K8Rkj0bfvqnBpgQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-2.0.2.tgz", + "integrity": "sha1-D0LBDl0F2l1C7qPlbDOZo31sWz4=", "dev": true, "requires": { - "debug": "^4.1.0" + "debug": "^2.2.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } } }, "supports-color": { @@ -2184,62 +2744,15 @@ "has-flag": "^3.0.0" } }, - "tar-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", - "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", - "requires": { - "bl": "^1.0.0", - "buffer-alloc": "^1.2.0", - "end-of-stream": "^1.0.0", - "fs-constants": "^1.0.0", - "readable-stream": "^2.3.0", - "to-buffer": "^1.1.1", - "xtend": "^4.0.0" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" - } - } - }, "temp-file": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.3.4.tgz", - "integrity": "sha512-qSZ5W5q54iyGnP8cNl49RE0jTJc5CrzNocux5APD5yIxcgonoMuMSbsZfaZy8rTGCYo0Xz6ySVv3adagZ8gffg==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.3.3.tgz", + "integrity": "sha512-ErWJ0vfZwkozaH7dn/5QtYdrGwy6fWID0GG3PEzNb9Vmt6urL4mQ3lKz7NWVi1/kmZsWQzgjTL7/P4mwGx5jqg==", "dev": true, "requires": { "async-exit-hook": "^2.0.1", - "fs-extra": "^8.1.0" + "bluebird-lst": "^1.0.9", + "fs-extra-p": "^8.0.2" } }, "term-size": { @@ -2251,15 +2764,21 @@ "execa": "^0.7.0" } }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + "throttleit": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-0.0.2.tgz", + "integrity": "sha1-z+34jmDADdlpe2H90qg0OptoDq8=", + "dev": true }, - "to-buffer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", - "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==" + "through2": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.2.3.tgz", + "integrity": "sha1-6zKE2k6jEbbMis42U3SKUqvyWj8=", + "dev": true, + "requires": { + "readable-stream": "~1.1.9", + "xtend": "~2.1.1" + } }, "to-readable-stream": { "version": "1.0.0", @@ -2276,6 +2795,30 @@ "is-number": "^7.0.0" } }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "dev": true, + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } + } + }, + "trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", + "dev": true + }, "truncate-utf8-bytes": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", @@ -2285,12 +2828,20 @@ "utf8-byte-length": "^1.0.1" } }, - "tunnel": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "dev": true, - "optional": true + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true }, "type-fest": { "version": "0.3.1", @@ -2305,20 +2856,11 @@ "dev": true }, "typescript": { - "version": "3.6.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.4.tgz", - "integrity": "sha512-unoCll1+l+YK4i4F8f22TaNVPRHcD9PA3yCuZ8g5e0qGqlVlJ/8FSateOLLSagn+Yg5+ZwuPkL8LFUc0Jcvksg==", + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.2.tgz", + "integrity": "sha512-7KxJovlYhTX5RaRbUdkAXN1KUZ8PwWlTzQdHV6xNqvuFOs7+WBo10TQUqT19Q/Jz2hk5v9TQDIhyLhhJY4p5AA==", "dev": true }, - "unbzip2-stream": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.3.3.tgz", - "integrity": "sha512-fUlAF7U9Ah1Q6EieQ4x4zLNejrRvDWUYmxXUpN3uziFYCHapjWFaCAnreY9bGgxzaMCFAPPpYNng57CypwJVhg==", - "requires": { - "buffer": "^5.2.1", - "through": "^2.3.8" - } - }, "unique-string": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", @@ -2335,9 +2877,9 @@ "dev": true }, "update-notifier": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-3.0.1.tgz", - "integrity": "sha512-grrmrB6Zb8DUiyDIaeRTBCkgISYUgETNe7NglEbVsrLWXeESnlCSP50WfRSj/GmzMPl6Uchj24S/p80nP/ZQrQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-3.0.0.tgz", + "integrity": "sha512-6Xe3oF2bvuoj4YECUc52yxVs94yWrxwqHbzyveDktTS1WhnlTRpNcQMxUshcB7nRVGi1jEXiqL5cW1S5WSyzKg==", "dev": true, "requires": { "boxen": "^3.0.0", @@ -2381,7 +2923,14 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true }, "validate-npm-package-license": { "version": "3.0.4", @@ -2393,6 +2942,17 @@ "spdx-expression-parse": "^3.0.0" } }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", @@ -2423,6 +2983,12 @@ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", @@ -2453,12 +3019,47 @@ "ansi-styles": "^3.2.0", "string-width": "^3.0.0", "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } } }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true }, "write-file-atomic": { "version": "2.4.3", @@ -2477,6 +3078,27 @@ "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", "dev": true }, + "xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", + "dev": true + }, + "xmldom": { + "version": "0.1.27", + "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz", + "integrity": "sha1-1QH5ezvbQDr4757MIFcxh6rawOk=", + "dev": true + }, + "xtend": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", + "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=", + "dev": true, + "requires": { + "object-keys": "~0.4.0" + } + }, "y18n": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", @@ -2490,21 +3112,65 @@ "dev": true }, "yargs": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", - "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz", + "integrity": "sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==", "dev": true, "requires": { "cliui": "^5.0.0", "find-up": "^3.0.0", "get-caller-file": "^2.0.1", + "os-locale": "^3.1.0", "require-directory": "^2.1.1", "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", "string-width": "^3.0.0", "which-module": "^2.0.0", "y18n": "^4.0.0", - "yargs-parser": "^13.1.1" + "yargs-parser": "^13.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } } }, "yargs-parser": { @@ -2515,6 +3181,14 @@ "requires": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + } } }, "yauzl": { diff --git a/package.json b/package.json index 4d6b457..db27c19 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "chargytransparenzsoftware", - "version": "1.1.0", + "version": "1.0.0", "description": "Chargy ist eine Transparenzsoftware für das Eichrecht in der Elektromobilität. Hiermit können Endkunden und E-Mobilitäts-Anbieter die Plausibilitäts und Validität von Ladevorgängen überprüfen.", "main": "src/main.js", "scripts": { @@ -26,23 +26,22 @@ "license": "AGPL-3.0-or-later", "homepage": "https://github.com/OpenChargingCloud/ChargyDesktopApp", "dependencies": { + "@types/chart.js": "^2.7.54", + "@types/elliptic": "^6.4.9", "@types/leaflet": "^1.4.4", "base32-decode": "^1.0.0", - "chart.js": "^2.9.1", - "decompress": "^4.2.0", - "elliptic": "^6.5.1", + "chart.js": "^2.8.0", + "elliptic": "^6.5.0", "leaflet": "^1.5.1", "leaflet.awesome-markers": "^2.0.5", "moment": "^2.24.0" }, "devDependencies": { - "@types/chart.js": "^2.8.9", - "@types/elliptic": "^6.4.10", - "@types/node": "^12.11.7", - "electron": "^7.0.0", - "electron-builder": "^21.2.0", - "sass": "^1.23.1", - "typescript": "^3.6.4" + "@types/node": "^12.0.10", + "electron": "^5.0.6", + "electron-builder": "^20.44.4", + "sass": "^1.22.1", + "typescript": "^3.5.2" }, "build": { "appId": "cloud.charging.open.chargy.desktop", diff --git a/src/js/OCMF.ts b/src/js/OCMF.ts index 16313f1..e6d18a8 100644 --- a/src/js/OCMF.ts +++ b/src/js/OCMF.ts @@ -529,7 +529,7 @@ class OCMF { } - //#endregion + //#endregion } diff --git a/src/js/SAFE_XML.ts b/src/js/SAFE_XML.ts index b3d78e2..c8cc459 100644 --- a/src/js/SAFE_XML.ts +++ b/src/js/SAFE_XML.ts @@ -21,13 +21,15 @@ class SAFEXML { + //#region tryToParseSAFEXML(XMLDocument) + public async tryToParseSAFEXML(XMLDocument: Document) : Promise { const base32Decode = require('base32-decode'); // The SAFE transparency software v1.0 does not understand its own - // XML namespace. Therefore we have to guess the format. + // XML namespace. Therefore we have to guess the format. try { @@ -224,4 +226,6 @@ class SAFEXML { } + //#endregion + } From f1328e9310e00fd02b599c076be0a2f22b791245 Mon Sep 17 00:00:00 2001 From: Achim 'ahzf' Friedland Date: Thu, 31 Oct 2019 18:49:08 +0100 Subject: [PATCH 020/110] Add support for parking times. Initial support of chargepoint charge transparency records. --- documentation/REBUILD.md | 16 +- .../Testdata/0024b10000027b29_1.pem | 4 + .../secrrct | 56 +++ .../secrrct.sign | Bin 0 -> 64 bytes .../secrrct | 56 +++ .../secrrct.sign | Bin 0 -> 64 bytes .../secrrct | 56 +++ .../secrrct.sign | Bin 0 -> 63 bytes .../secrrct | 86 ++++ .../secrrct.sign | 1 + .../secrrct | 56 +++ .../secrrct.sign | Bin 0 -> 63 bytes .../secrrct | 56 +++ .../secrrct.sign | 1 + .../Testdata/0024b1000002e300_2.pem | 4 + .../secrrct | 85 ++++ .../secrrct.sign | Bin 0 -> 62 bytes package-lock.json | 340 +++++++++++++-- package.json | 8 +- src/css/chargy.scss | 40 +- src/index.html | 1 + src/js/SAFE_XML.ts | 2 +- src/js/chargeIT.ts | 8 +- src/js/chargepoint.ts | 396 ++++++++++++++++- src/js/chargepointCrypt01.ts | 405 ++++++++++++++++++ src/js/chargy.ts | 29 +- src/js/chargyApp.ts | 187 +++++--- src/js/chargyInterfaces.ts | 25 +- 28 files changed, 1809 insertions(+), 109 deletions(-) create mode 100644 documentation/chargepoint/Testdata/0024b10000027b29_1.pem create mode 100644 documentation/chargepoint/Testdata/0024b10000027b29_1_121708795_payload.FLAT_SESSION/secrrct create mode 100644 documentation/chargepoint/Testdata/0024b10000027b29_1_121708795_payload.FLAT_SESSION/secrrct.sign create mode 100644 documentation/chargepoint/Testdata/0024b10000027b29_1_121708845_payload.Per_Min/secrrct create mode 100644 documentation/chargepoint/Testdata/0024b10000027b29_1_121708845_payload.Per_Min/secrrct.sign create mode 100644 documentation/chargepoint/Testdata/0024b10000027b29_1_121709375_payload._Per_KWh/secrrct create mode 100644 documentation/chargepoint/Testdata/0024b10000027b29_1_121709375_payload._Per_KWh/secrrct.sign create mode 100644 documentation/chargepoint/Testdata/0024b10000027b29_1_121709405_payload_Min_Variation_/secrrct create mode 100644 documentation/chargepoint/Testdata/0024b10000027b29_1_121709405_payload_Min_Variation_/secrrct.sign create mode 100644 documentation/chargepoint/Testdata/0024b10000027b29_1_121709415_payload._TOU_/secrrct create mode 100644 documentation/chargepoint/Testdata/0024b10000027b29_1_121709415_payload._TOU_/secrrct.sign create mode 100644 documentation/chargepoint/Testdata/0024b10000027b29_1_121709465_payload_Parking_Tap_ToCharge/secrrct create mode 100644 documentation/chargepoint/Testdata/0024b10000027b29_1_121709465_payload_Parking_Tap_ToCharge/secrrct.sign create mode 100644 documentation/chargepoint/Testdata/0024b1000002e300_2.pem create mode 100644 documentation/chargepoint/Testdata/0024b1000002e300_2_119693895_payload/secrrct create mode 100644 documentation/chargepoint/Testdata/0024b1000002e300_2_119693895_payload/secrrct.sign create mode 100644 src/js/chargepointCrypt01.ts diff --git a/documentation/REBUILD.md b/documentation/REBUILD.md index 1c86bf1..20e4b49 100644 --- a/documentation/REBUILD.md +++ b/documentation/REBUILD.md @@ -25,16 +25,28 @@ $ npm install @types/node@latest --save-dev + @types/node@12.0.10 $ npm install elliptic@latest -+ elliptic@6.5.0 ++ elliptic@6.5.1 $ npm install @types/elliptic@latest --save-dev -+ @types/elliptic@6.4.9 ++ @types/elliptic@6.4.10 $ npm install moment@latest + moment@2.24.0 $ npm install base32-decode + base32-decode@1.0.0 + +$ npm install decompress@latest ++ decompress@4.2.0 + +$ npm install @types/decompress --save ++ @types/decompress@4.2.3 + +$ npm install chart.js@latest ++ chart.js@2.9.1 + +$ npm install @types/chart.js@latest --save-dev ++ @types/chart.js@2.8.9 ``` diff --git a/documentation/chargepoint/Testdata/0024b10000027b29_1.pem b/documentation/chargepoint/Testdata/0024b10000027b29_1.pem new file mode 100644 index 0000000..c78f3d0 --- /dev/null +++ b/documentation/chargepoint/Testdata/0024b10000027b29_1.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +ME4wEAYHKoZIzj0CAQYFK4EEACADOgAE9rlNHQ1MlSRBuUQ0rEE7DD2X7ufxGTac +rDoHougSmPQv9uvxLd4W4bV9oRITRXAhHcep80ia4aQ= +-----END PUBLIC KEY----- diff --git a/documentation/chargepoint/Testdata/0024b10000027b29_1_121708795_payload.FLAT_SESSION/secrrct b/documentation/chargepoint/Testdata/0024b10000027b29_1_121708795_payload.FLAT_SESSION/secrrct new file mode 100644 index 0000000..6d8d61f --- /dev/null +++ b/documentation/chargepoint/Testdata/0024b10000027b29_1_121708795_payload.FLAT_SESSION/secrrct @@ -0,0 +1,56 @@ +{ + "company_name": "Chargepoint QA UK", + "display_unit": 3600, + "flat": [ + { + "flat_fee": 0.98999999999999999, + "flat_fee_subtotal": 0.98999999999999999, + "numSubSessions": 1, + "type": "FLAT" + } + ], + "minMaxAdj": [], + "parking": [ + { + "duration": 222, + "end_time": 1570088781, + "end_time_utc": 1570088781, + "line_item_cost": 0, + "overstay": 0, + "seq_num": 1, + "start_time": 1570088559, + "start_time_utc": 1570088559, + "type": "PARKING", + "unit_price": 0, + "units": 222 + }, + { + "duration": 222, + "parking_subtotal": 0, + "seq_num": "SUBTOTAL", + "type": "PARKING", + "units": 222 + } + ], + "subtotal": 0.98999999999999999, + "subtotal_before_adjustment": 0.98999999999999999, + "tax": [ + { + "seq_num": "SUBTOTAL", + "total_tax": 0, + "type": "TAX" + } + ], + "totalAmount": 0.98999999999999999, + "additional_info": { + "outlet": 1, + "session_id": 600, + "station_mac": "0024:b100:0002:7b29", + "driver_info": "urn:nema:5evse:dn:v1:chargepoint.com:cdid:cncp00000c35d9", + "meter_serial": "160160T", + "currency_code": "GBP", + "meter_startreading": 800, + "meter_endreading": 800, + "energy_units": "Wh" + } +} \ No newline at end of file diff --git a/documentation/chargepoint/Testdata/0024b10000027b29_1_121708795_payload.FLAT_SESSION/secrrct.sign b/documentation/chargepoint/Testdata/0024b10000027b29_1_121708795_payload.FLAT_SESSION/secrrct.sign new file mode 100644 index 0000000000000000000000000000000000000000..fb666c45a50574525c151544ca69b39cbfab6d5a GIT binary patch literal 64 zcmV-G0Kfk*J^~#8hhP)^_x|a4N4;}7yAGJ literal 0 HcmV?d00001 diff --git a/documentation/chargepoint/Testdata/0024b10000027b29_1_121709465_payload_Parking_Tap_ToCharge/secrrct b/documentation/chargepoint/Testdata/0024b10000027b29_1_121709465_payload_Parking_Tap_ToCharge/secrrct new file mode 100644 index 0000000..826ebc1 --- /dev/null +++ b/documentation/chargepoint/Testdata/0024b10000027b29_1_121709465_payload_Parking_Tap_ToCharge/secrrct @@ -0,0 +1,56 @@ +{ + "company_name": "Chargepoint QA UK", + "display_unit": 3600, + "flat": [ + { + "flat_fee": 0, + "flat_fee_subtotal": 0, + "numSubSessions": 1, + "type": "FLAT" + } + ], + "minMaxAdj": [], + "parking": [ + { + "duration": 316, + "end_time": 1570177531, + "end_time_utc": 1570170331, + "line_item_cost": 0.080000000000000002, + "overstay": 0, + "seq_num": 1, + "start_time": 1570177215, + "start_time_utc": 1570170015, + "type": "PARKING", + "unit_price": "0.89", + "units": 316 + }, + { + "duration": 316, + "parking_subtotal": 0.080000000000000002, + "seq_num": "SUBTOTAL", + "type": "PARKING", + "units": 316 + } + ], + "subtotal": 0.080000000000000002, + "subtotal_before_adjustment": 0.080000000000000002, + "tax": [ + { + "seq_num": "SUBTOTAL", + "total_tax": 0, + "type": "TAX" + } + ], + "totalAmount": 0.080000000000000002, + "additional_info": { + "outlet": 1, + "session_id": 621, + "station_mac": "0024:b100:0002:7b29", + "driver_info": "urn:nema:5evse:dn:v1:chargepoint.com:cdid:hce5294254791722", + "meter_serial": "160160T", + "currency_code": "GBP", + "meter_startreading": 1400, + "meter_endreading": 1500, + "energy_units": "Wh" + } +} \ No newline at end of file diff --git a/documentation/chargepoint/Testdata/0024b10000027b29_1_121709465_payload_Parking_Tap_ToCharge/secrrct.sign b/documentation/chargepoint/Testdata/0024b10000027b29_1_121709465_payload_Parking_Tap_ToCharge/secrrct.sign new file mode 100644 index 0000000..9e0a7e6 --- /dev/null +++ b/documentation/chargepoint/Testdata/0024b10000027b29_1_121709465_payload_Parking_Tap_ToCharge/secrrct.sign @@ -0,0 +1 @@ +0< (M)}b;#P~S|z){ o\Ys>2) \ No newline at end of file diff --git a/documentation/chargepoint/Testdata/0024b1000002e300_2.pem b/documentation/chargepoint/Testdata/0024b1000002e300_2.pem new file mode 100644 index 0000000..05532bf --- /dev/null +++ b/documentation/chargepoint/Testdata/0024b1000002e300_2.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +ME4wEAYHKoZIzj0CAQYFK4EEACADOgAE1MF2EIuqaDElJHyK9R64SFjJ5Q2HU6dF +4/0pmqBEgmycnUnOOQTNm9xos7Cfs56+qsC57Aq5rXY= +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/documentation/chargepoint/Testdata/0024b1000002e300_2_119693895_payload/secrrct b/documentation/chargepoint/Testdata/0024b1000002e300_2_119693895_payload/secrrct new file mode 100644 index 0000000..a630e3c --- /dev/null +++ b/documentation/chargepoint/Testdata/0024b1000002e300_2_119693895_payload/secrrct @@ -0,0 +1,85 @@ +{ + "company_name": "ChargePoint EU QA EUR", + "display_unit": 3600, + "energy": [{ + "active_charging": 0, + "duration": 421, + "end_time": 1543841929, + "end_time_utc": 1543838329, + "line_item_cost": 0, + "seq_num": 1, + "start_time": 1543841508, + "start_time_utc": 1543837908, + "type": "ENERGY", + "unit_price": "0.05000", + "units": 0.058999999999999997 + }, + { + "duration": 421, + "energy_subtotal": 0, + "seq_num": "SUBTOTAL", + "type": "ENERGY", + "units": 0.058999999999999997 + } + ], + "flat": [{ + "flat_fee": 0, + "flat_fee_subtotal": 0, + "numSubSessions": 1, + "type": "FLAT" + }], + "minMaxAdj": [{ + "session_length": 0, + "session_min": 0.070000000000000007, + "session_min_adjustment": 0.059999999999999998, + "session_total": 0.01, + "type": "SESS_MIN_ADJ" + }], + "parking": [{ + "duration": 421, + "end_time": 1543841929, + "end_time_utc": 1543838329, + "line_item_cost": 0.01, + "overstay": 0, + "seq_num": 1, + "start_time": 1543841508, + "start_time_utc": 1543837908, + "type": "PARKING", + "unit_price": "0.10", + "units": 421 + }, + { + "duration": 421, + "parking_subtotal": 0.01, + "seq_num": "SUBTOTAL", + "type": "PARKING", + "units": 421 + } + ], + "subtotal": 0.070000000000000007, + "subtotal_before_adjustment": 0.01, + "tax": [{ + "tax": 0.01, + "taxPercent": "19.0000", + "taxRuleName": "MwSt.", + "type": "TAX" + }, + { + "seq_num": "SUBTOTAL", + "total_tax": 0.01, + "type": "TAX" + } + ], + "totalAmount": 0.080000000000000002, + "additional_info": { + "outlet": 2, + "session_id": 2, + "station_mac": "0024:b100:0002:e300", + "driver_info": "urn:nema:5evse:dn:v1:chargepoint.com:cdid:cncp000009afd2", + "meter_serial": "240008S", + "currency_code": "EUR", + "meter_startreading": 3078, + "meter_endreading": 3137, + "energy_units": "Wh" + } +} \ No newline at end of file diff --git a/documentation/chargepoint/Testdata/0024b1000002e300_2_119693895_payload/secrrct.sign b/documentation/chargepoint/Testdata/0024b1000002e300_2_119693895_payload/secrrct.sign new file mode 100644 index 0000000000000000000000000000000000000000..2222a6799eeaa83a1ffa05af83e64ef0147ad39e GIT binary patch literal 62 zcmV-E0Kxw-JOUgCg8+{gDrUETCw$REJ$Y|-5V*j=FhcHq%om6P92P?>#iYC`HLke1 U>Bc*0**Kjm0T7FvLJ4v>HrP@aHUIzs literal 0 HcmV?d00001 diff --git a/package-lock.json b/package-lock.json index 11ad054..a5a0b36 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "chargytransparenzsoftware", - "version": "1.0.0", + "version": "1.1.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -29,6 +29,7 @@ "version": "4.11.5", "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.5.tgz", "integrity": "sha512-AEAZcIZga0JgVMHNtl1CprA/hXX7/wPt79AgR4XqaDt7jyj3QWYw6LPoOiznPtugDmlubUnAahMs2PFxGcQrng==", + "dev": true, "requires": { "@types/node": "*" } @@ -44,10 +45,19 @@ "integrity": "sha512-D9MyoQFI7iP5VdpEyPZyjjqIJ8Y8EDNQFIFVLOmeg1rI1xiHOChyUPMPRUVfqFCerxfE+yS3vMyj37F6IdtOoQ==", "dev": true }, + "@types/decompress": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@types/decompress/-/decompress-4.2.3.tgz", + "integrity": "sha512-W24e3Ycz1UZPgr1ZEDHlK4XnvOr+CpJH3qNsFeqXwwlW/9END9gxn3oJSsp7gYdiQxrXUHwUUd3xuzVz37MrZQ==", + "requires": { + "@types/node": "*" + } + }, "@types/elliptic": { - "version": "6.4.9", - "resolved": "https://registry.npmjs.org/@types/elliptic/-/elliptic-6.4.9.tgz", - "integrity": "sha512-Mn+OyENd6YHwJKgUSyCTUDunEDFMaFpCXt52JCA00sxtzEa1ji6H0doZHL3iXhqMTo1Ob53X+Dv0s4PAJ+IVlA==", + "version": "6.4.10", + "resolved": "https://registry.npmjs.org/@types/elliptic/-/elliptic-6.4.10.tgz", + "integrity": "sha512-9h+Bw+aNiLzcq9DGstHccNxSsJ5iNId7mzruid7+kwm7F1IGvb4rBOOPo3+twt9ZPhI3y+JJ2m1UfgU8cOEJuQ==", + "dev": true, "requires": { "@types/bn.js": "*" } @@ -302,8 +312,7 @@ "base64-js": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", - "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==", - "dev": true + "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==" }, "bcrypt-pbkdf": { "version": "1.0.2", @@ -320,6 +329,44 @@ "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", "dev": true }, + "bl": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", + "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", + "requires": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "bluebird": { "version": "3.5.5", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", @@ -420,11 +467,19 @@ "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" }, + "buffer": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.4.3.tgz", + "integrity": "sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, "buffer-alloc": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", - "dev": true, "requires": { "buffer-alloc-unsafe": "^1.1.0", "buffer-fill": "^1.0.0" @@ -433,14 +488,17 @@ "buffer-alloc-unsafe": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", - "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", - "dev": true + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" }, "buffer-fill": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", - "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=", - "dev": true + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=" }, "buffer-from": { "version": "1.1.1", @@ -708,6 +766,14 @@ "delayed-stream": "~1.0.0" } }, + "commander": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", + "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", + "requires": { + "graceful-readlink": ">= 1.0.0" + } + }, "compare-version": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/compare-version/-/compare-version-0.1.2.tgz", @@ -781,8 +847,7 @@ "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "cross-spawn": { "version": "5.1.0", @@ -834,6 +899,21 @@ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, + "decompress": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.0.tgz", + "integrity": "sha1-eu3YVCflqS2s/lVnSnxQXpbQH50=", + "requires": { + "decompress-tar": "^4.0.0", + "decompress-tarbz2": "^4.0.0", + "decompress-targz": "^4.0.0", + "decompress-unzip": "^4.0.1", + "graceful-fs": "^4.1.10", + "make-dir": "^1.0.0", + "pify": "^2.3.0", + "strip-dirs": "^2.0.0" + } + }, "decompress-response": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", @@ -843,6 +923,89 @@ "mimic-response": "^1.0.0" } }, + "decompress-tar": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", + "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", + "requires": { + "file-type": "^5.2.0", + "is-stream": "^1.1.0", + "tar-stream": "^1.5.2" + } + }, + "decompress-tarbz2": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", + "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", + "requires": { + "decompress-tar": "^4.1.0", + "file-type": "^6.1.0", + "is-stream": "^1.1.0", + "seek-bzip": "^1.0.5", + "unbzip2-stream": "^1.0.9" + }, + "dependencies": { + "file-type": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", + "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==" + } + } + }, + "decompress-targz": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", + "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", + "requires": { + "decompress-tar": "^4.1.1", + "file-type": "^5.2.0", + "is-stream": "^1.1.0" + } + }, + "decompress-unzip": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", + "integrity": "sha1-3qrM39FK6vhVePczroIQ+bSEj2k=", + "requires": { + "file-type": "^3.8.0", + "get-stream": "^2.2.0", + "pify": "^2.3.0", + "yauzl": "^2.4.2" + }, + "dependencies": { + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "requires": { + "pend": "~1.2.0" + } + }, + "file-type": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", + "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=" + }, + "get-stream": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", + "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=", + "requires": { + "object-assign": "^4.0.1", + "pinkie-promise": "^2.0.0" + } + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + } + } + }, "deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -1033,9 +1196,9 @@ } }, "elliptic": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.0.tgz", - "integrity": "sha512-eFOJTMyCYb7xtE/caJ6JJu+bhi67WCYNbkGSknu20pmM8Ke/bqOfdnZWxyoGN26JgfxTbXrsCkEw4KheCT/KGg==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.1.tgz", + "integrity": "sha512-xvJINNLbTeWQjrl6X+7eQCrIy/YPv5XCpKW6kB5mKvtnGILoLDcySuwomfdzt0BMdLNVnuRNTuzKNHj0bva1Cg==", "requires": { "bn.js": "^4.4.0", "brorand": "^1.0.1", @@ -1056,7 +1219,6 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", - "dev": true, "requires": { "once": "^1.4.0" } @@ -1165,6 +1327,11 @@ "pend": "~1.2.0" } }, + "file-type": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", + "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=" + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -1212,6 +1379,11 @@ "mime-types": "^2.1.12" } }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, "fs-extra": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", @@ -1331,8 +1503,12 @@ "graceful-fs": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz", - "integrity": "sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg==", - "dev": true + "integrity": "sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg==" + }, + "graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=" }, "har-schema": { "version": "2.0.0", @@ -1413,6 +1589,11 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, "import-lazy": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", @@ -1518,6 +1699,11 @@ "is-path-inside": "^1.0.0" } }, + "is-natural-number": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", + "integrity": "sha1-q5124dtM7VHjXeDHLr7PCfc0zeg=" + }, "is-npm": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-3.0.0.tgz", @@ -1548,8 +1734,7 @@ "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" }, "is-typedarray": { "version": "1.0.0", @@ -1759,7 +1944,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", - "dev": true, "requires": { "pify": "^3.0.0" }, @@ -1767,8 +1951,7 @@ "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" } } }, @@ -1988,8 +2171,7 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, "object-keys": { "version": "0.4.0", @@ -2001,7 +2183,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, "requires": { "wrappy": "1" } @@ -2180,8 +2361,7 @@ "pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", - "dev": true + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" }, "performance-now": { "version": "2.1.0", @@ -2198,20 +2378,17 @@ "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" }, "pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" }, "pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, "requires": { "pinkie": "^2.0.0" } @@ -2246,8 +2423,7 @@ "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, "progress-stream": { "version": "1.2.0", @@ -2486,8 +2662,7 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safer-buffer": { "version": "2.1.2", @@ -2519,6 +2694,14 @@ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true }, + "seek-bzip": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.5.tgz", + "integrity": "sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w=", + "requires": { + "commander": "~2.8.1" + } + }, "semver": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", @@ -2688,6 +2871,14 @@ "is-utf8": "^0.2.0" } }, + "strip-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", + "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", + "requires": { + "is-natural-number": "^4.0.1" + } + }, "strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", @@ -2744,6 +2935,54 @@ "has-flag": "^3.0.0" } }, + "tar-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", + "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", + "requires": { + "bl": "^1.0.0", + "buffer-alloc": "^1.2.0", + "end-of-stream": "^1.0.0", + "fs-constants": "^1.0.0", + "readable-stream": "^2.3.0", + "to-buffer": "^1.1.1", + "xtend": "^4.0.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + } + } + }, "temp-file": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.3.3.tgz", @@ -2770,6 +3009,11 @@ "integrity": "sha1-z+34jmDADdlpe2H90qg0OptoDq8=", "dev": true }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, "through2": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/through2/-/through2-0.2.3.tgz", @@ -2780,6 +3024,11 @@ "xtend": "~2.1.1" } }, + "to-buffer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", + "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==" + }, "to-readable-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", @@ -2861,6 +3110,15 @@ "integrity": "sha512-7KxJovlYhTX5RaRbUdkAXN1KUZ8PwWlTzQdHV6xNqvuFOs7+WBo10TQUqT19Q/Jz2hk5v9TQDIhyLhhJY4p5AA==", "dev": true }, + "unbzip2-stream": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.3.3.tgz", + "integrity": "sha512-fUlAF7U9Ah1Q6EieQ4x4zLNejrRvDWUYmxXUpN3uziFYCHapjWFaCAnreY9bGgxzaMCFAPPpYNng57CypwJVhg==", + "requires": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, "unique-string": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", @@ -2923,8 +3181,7 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "uuid": { "version": "3.3.2", @@ -3058,8 +3315,7 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "write-file-atomic": { "version": "2.4.3", diff --git a/package.json b/package.json index db27c19..440344d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "chargytransparenzsoftware", - "version": "1.0.0", + "version": "1.1.0", "description": "Chargy ist eine Transparenzsoftware für das Eichrecht in der Elektromobilität. Hiermit können Endkunden und E-Mobilitäts-Anbieter die Plausibilitäts und Validität von Ladevorgängen überprüfen.", "main": "src/main.js", "scripts": { @@ -27,16 +27,18 @@ "homepage": "https://github.com/OpenChargingCloud/ChargyDesktopApp", "dependencies": { "@types/chart.js": "^2.7.54", - "@types/elliptic": "^6.4.9", + "@types/decompress": "^4.2.3", "@types/leaflet": "^1.4.4", "base32-decode": "^1.0.0", "chart.js": "^2.8.0", - "elliptic": "^6.5.0", + "decompress": "^4.2.0", + "elliptic": "^6.5.1", "leaflet": "^1.5.1", "leaflet.awesome-markers": "^2.0.5", "moment": "^2.24.0" }, "devDependencies": { + "@types/elliptic": "^6.4.10", "@types/node": "^12.0.10", "electron": "^5.0.6", "electron-builder": "^20.44.4", diff --git a/src/css/chargy.scss b/src/css/chargy.scss index 57ec7a0..faf0c69 100644 --- a/src/css/chargy.scss +++ b/src/css/chargy.scss @@ -593,6 +593,24 @@ body { } + .parkingInfos { + + display: table-row; + + .icon { + display: table-cell; + padding: 0px 7px 0px 3px; + text-align: center; + vertical-align: top; + } + + .text { + display: table-cell; + color: #212427; + } + + } + .authorizationStart { display: table-row; @@ -625,13 +643,31 @@ body { } } + .chargingStationInfos { + + display: table-row; + + .icon { + display: table-cell; + padding: 0px 7px 0px 3px; + text-align: center; + vertical-align: top; + } + + .text { + display: table-cell; + color: #212427; + } + + } + .locationInfos { display: table-row; .icon { display: table-cell; - padding: 6px 7px 0px 3px; + padding: 0px 7px 0px 3px; text-align: center; vertical-align: top; } @@ -639,7 +675,7 @@ body { .text { display: table-cell; color: #212427; - } + } } diff --git a/src/index.html b/src/index.html index 72361f8..9d4bd6c 100644 --- a/src/index.html +++ b/src/index.html @@ -43,6 +43,7 @@ + diff --git a/src/js/SAFE_XML.ts b/src/js/SAFE_XML.ts index c8cc459..358ee97 100644 --- a/src/js/SAFE_XML.ts +++ b/src/js/SAFE_XML.ts @@ -29,7 +29,7 @@ class SAFEXML { const base32Decode = require('base32-decode'); // The SAFE transparency software v1.0 does not understand its own - // XML namespace. Therefore we have to guess the format. + // XML namespace. Therefore we have to guess the format. try { diff --git a/src/js/chargeIT.ts b/src/js/chargeIT.ts index b96e97a..fcf4063 100644 --- a/src/js/chargeIT.ts +++ b/src/js/chargeIT.ts @@ -376,14 +376,14 @@ class ChargeIT { "@id": CTRArray[n]["transactionId"], "@context": "https://open.charging.cloud/contexts/CTR+json", - + "begin": this.moment.unix(CTRArray[0]["measuredValue"]["timestampLocal"]["timestamp"]).utc().format(), "end": this.moment.unix(CTRArray[n]["measuredValue"]["timestampLocal"]["timestamp"]).utc().format(), - + "description": { "de": "Alle Ladevorgänge" }, - + "contract": { "@id": CTRArray[0]["contract"]["id"], "type": CTRArray[0]["contract"]["type"], @@ -399,7 +399,7 @@ class ChargeIT { "description": { "de": "chargeIT mobility GmbH - Charging Station Operator Services" }, - + "contact": { "email": "info@chargeit-mobility.com", "web": "https://www.chargeit-mobility.com", diff --git a/src/js/chargepoint.ts b/src/js/chargepoint.ts index 3ac464a..d6e436c 100644 --- a/src/js/chargepoint.ts +++ b/src/js/chargepoint.ts @@ -21,18 +21,406 @@ class Chargepoint { - //#region tryToParseChargepointXML(XMLDocument) + private moment: any; - public async tryToParseChargepointXML(XMLDocument: Document) : Promise + constructor() { + this.moment = require('moment'); + } + + //#region tryToParseChargepointJSON(SomeJSON) + + public async tryToParseChargepointJSON(SomeJSON: any) : Promise { try { - return { - status: SessionVerificationResult.InvalidSessionFormat + // { + // "company_name": "ChargePoint EU QA EUR", + // "display_unit": 3600, + // "energy": [ + // { + // "active_charging": 0, + // "duration": 421, + // "end_time": 1543841929, + // "end_time_utc": 1543838329, + // "line_item_cost": 0, + // "seq_num": 1, + // "start_time": 1543841508, + // "start_time_utc": 1543837908, + // "type": "ENERGY", + // "unit_price": "0.05000", + // "units": 0.058999999999999997 + // }, + // { + // "duration": 421, + // "energy_subtotal": 0, + // "seq_num": "SUBTOTAL", + // "type": "ENERGY", + // "units": 0.058999999999999997 + // } + // ], + // "flat": [ + // { + // "flat_fee": 0, + // "flat_fee_subtotal": 0, + // "numSubSessions": 1, + // "type": "FLAT" + // } + // ], + // "minMaxAdj": [ + // { + // "session_length": 0, + // "session_min": 0.070000000000000007, + // "session_min_adjustment": 0.059999999999999998, + // "session_total": 0.01, + // "type": "SESS_MIN_ADJ" + // } + // ], + // "parking": [ + // { + // "duration": 421, + // "end_time": 1543841929, + // "end_time_utc": 1543838329, + // "line_item_cost": 0.01, + // "overstay": 0, + // "seq_num": 1, + // "start_time": 1543841508, + // "start_time_utc": 1543837908, + // "type": "PARKING", + // "unit_price": "0.10", + // "units": 421 + // }, + // { + // "duration": 421, + // "parking_subtotal": 0.01, + // "seq_num": "SUBTOTAL", + // "type": "PARKING", + // "units": 421 + // } + // ], + // "subtotal": 0.070000000000000007, + // "subtotal_before_adjustment": 0.01, + // "tax": [ + // { + // "tax": 0.01, + // "taxPercent": "19.0000", + // "taxRuleName": "MwSt.", + // "type": "TAX" + // }, + // { + // "seq_num": "SUBTOTAL", + // "total_tax": 0.01, + // "type": "TAX" + // } + // ], + // "totalAmount": 0.080000000000000002, + // "additional_info": { + // "outlet": 2, + // "session_id": 2, + // "station_mac": "0024:b100:0002:e300", + // "driver_info": "urn:nema:5evse:dn:v1:chargepoint.com:cdid:cncp000009afd2", + // "meter_serial": "240008S", + // "currency_code": "EUR", + // "meter_startreading": 3078, + // "meter_endreading": 3137, + // "energy_units": "Wh" + // } + // } + + let chargingStart = ""; + let chargingEnd = ""; + + if (SomeJSON.energy && SomeJSON.energy.length > 0) + { + for (let i=0; i chargingEnd) + chargingEnd = SomeJSON.energy[i].end_time_utc; + } } + let parkingStart = ""; + let parkingEnd = ""; + + if (SomeJSON.parking && SomeJSON.parking.length > 0) + { + for (let i=0; i parkingEnd) + parkingEnd = SomeJSON.parking[i].end_time_utc; + } + } + + // Sometimes there is "parking" but no "energy"... + if (chargingStart == "") + chargingStart = parkingStart; + + if (chargingEnd == "") + chargingEnd = parkingEnd; + + + let sessionStart = parkingStart < chargingStart ? parkingStart : chargingStart; + + if (sessionStart == "" && chargingStart != "") + sessionStart = chargingStart; + + if (sessionStart == "" && parkingStart != "") + sessionStart = parkingStart; + + + let sessionEnd = parkingEnd < chargingEnd ? parkingEnd : chargingEnd; + + if (sessionEnd == "" && chargingEnd != "") + sessionEnd = chargingEnd; + + if (sessionEnd == "" && parkingEnd != "") + sessionEnd = parkingEnd; + + + var _CTR: any = { //IChargeTransparencyRecord = { + + "@id": "chargepoint-" + SomeJSON.additional_info.station_mac + "-" + + SomeJSON.additional_info.outlet + "-" + + SomeJSON.additional_info.session_id, + "@context": "https://open.charging.cloud/contexts/CTR+json", + + "begin": this.moment.unix(sessionStart).utc().format(), + "end": this.moment.unix(sessionEnd).utc().format(), + + "description": { + "de": "Alle Ladevorgänge" + }, + + "contract": { + "@id": SomeJSON.additional_info.driver_info, + "type": "userId" + // "username": "", + // "email": "" + }, + + "chargingStationOperators": [ + { + + "@id": SomeJSON.company_name, + // "eMobilityIds": [ ], + "description": { + "de": "chargepoint - Charging Station Operator Services" + }, + + "contact": { + "email": "info@chargeit-mobility.com", + "web": "https://www.chargeit-mobility.com", + "logoUrl": "http://www.chargeit-mobility.com/fileadmin/BELECTRIC_Drive/templates/pics/chargeit_logo_408x70.png", + "publicKeys": [ + { + "algorithm": "secp192r1", + "format": "DER", + "value": "042313b9e469612b4ca06981bfdecb226e234632b01d84b6a814f63a114b7762c34ddce2e6853395b7a0f87275f63ffe3c", + "signatures": [ + { + "keyId": "...", + "algorithm": "secp192r1", + "format": "DER", + "value": "????" + } + ] + }, + { + "algorithm": "secp256k1", + "format": "DER", + "value": "04a8ff0d82107922522e004a167cc658f0eef408c5020f98e7a2615be326e61852666877335f4f8d9a0a756c26f0c9fb3f401431416abb5317cc0f5d714d3026fe", + "signatures": [ ] + } + ] + }, + + "support": { + "hotline": "+49 9321 / 2680 - 700", + "email": "service@chargeit-mobility.com", + "web": "https://cso.chargeit.charging.cloud/issues" + // "mediationServices": [ "GraphDefined Mediation" ], + // "publicKeys": [ + // { + // "algorithm": "secp256k1", + // "format": "DER", + // "value": "04a8ff0d82107922522e004a167cc658f0eef408c5020f98e7a2615be326e61852666877335f4f8d9a0a756c26f0c9fb3f401431416abb5317cc0f5d714d3026fe", + // "signatures": [ ] + // } + // ] + }, + + "privacy": { + "contact": "Dr. iur. Christian Borchers, datenschutz süd GmbH", + "email": "datenschutz@chargeit-mobility.com", + "web": "http://www.chargeit-mobility.com/de/datenschutz/" + // "publicKeys": [ + // { + // "algorithm": "secp256k1", + // "format": "DER", + // "value": "04a8ff0d82107922522e004a167cc658f0eef408c5020f98e7a2615be326e61852666877335f4f8d9a0a756c26f0c9fb3f401431416abb5317cc0f5d714d3026fe", + // "signatures": [ ] + // } + // ] + }, + + "chargingStations": [ + { + "@id": SomeJSON.additional_info.station_mac, + "firmwareVersion": "", + "geoLocation": null, + "address": null, + "EVSEs": [ + { + "@id": SomeJSON.additional_info.station_mac + "-" + SomeJSON.additional_info.outlet, + "sockets": [ { } ], + "meters": [ + { + "@id": SomeJSON.additional_info.meter_serial, + "vendor": null, + "vendorURL": null, + "model": null, + "hardwareVersion": null, + "firmwareVersion": null, + "signatureFormat": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/EMHCrypt01", + "publicKeys": [ + { + "algorithm": "secp192r1", + "format": "DER", + "value": null, + "signatures": null + } + ] + } + ] + } + ] + } + ], + + "chargingTariffs": [{ + "@id": "default", + "currency": SomeJSON.additional_info.currency_code, + "taxes": [ + { + "@id": "MwSt", + "percentage": 19.0, + } + ] + }], + + "parkingTariffs": [{ + "@id": "default", + "currency": SomeJSON.additional_info.currency_code, + "taxes": [ + { + "@id": "MwSt", + "percentage": 19.0, + } + ] + }] + + } + ], + + "chargingSessions": [ + + { + + "rawData": SomeJSON, + + "@id": SomeJSON.additional_info.station_mac + "-" + + SomeJSON.additional_info.outlet + "-" + + SomeJSON.additional_info.session_id, + "@context": "https://open.charging.cloud/contexts/SessionSignatureFormats/ChargepointCrypt01+json", + "begin": this.moment.unix(sessionStart).utc().format(), + "end": this.moment.unix(sessionEnd).utc().format(), + "EVSEId": SomeJSON.additional_info.station_mac + "-" + + SomeJSON.additional_info.outlet, + + "authorizationStart": { + "@id": SomeJSON.additional_info.driver_info, + "type": "userId" + }, + + "signatureInfos": { + "hash": "SHA512", + "hashTruncation": "24", + "algorithm": "ECC", + "curve": "secp192r1", + "format": "rs" + }, + + "measurements": [ + + { + + "energyMeterId": SomeJSON.additional_info.meter_serial, + "@context": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/ChargepointCrypt01+json", + "name": SomeJSON.energy != null && SomeJSON.energy.length > 0 ? SomeJSON.energy[0].type : "ENERGY", + "obis": "123...", + "unit": SomeJSON.additional_info.energy_units, + // "unitEncoded": CTRArray[0]["measuredValue"]["unitEncoded"], + // "valueType": CTRArray[0]["measuredValue"]["valueType"], + "scale": 0, + + "signatureInfos": { + "hash": "SHA512", + "hashTruncation": "24", + "algorithm": "ECC", + "curve": "secp192r1", + "format": "rs" + }, + + "values": [ + { + "timestamp": this.moment.unix(chargingStart).utc().format(), + "value": SomeJSON.additional_info.meter_startreading + }, + { + "timestamp": this.moment.unix(chargingEnd).utc().format(), + "value": SomeJSON.additional_info.meter_endreading + } + ] + + } + + ] + + } + + ] + + }; + + + if (SomeJSON.parking && SomeJSON.parking.length > 0) + { + + _CTR.chargingSessions[0].parking = []; + + for (let parking of SomeJSON.parking) + { + if (parking.seq_num != "SUBTOTAL") + { + _CTR.chargingSessions[0].parking.push({ + begin: this.moment.unix(parking.start_time_utc).utc().format(), + end: this.moment.unix(parking.end_time_utc).utc().format(), + overstay: parking.overstay == 1, + }); + } + } + + } + + return _CTR as IChargeTransparencyRecord; + } catch (exception) { diff --git a/src/js/chargepointCrypt01.ts b/src/js/chargepointCrypt01.ts new file mode 100644 index 0000000..f3aa73a --- /dev/null +++ b/src/js/chargepointCrypt01.ts @@ -0,0 +1,405 @@ +/* + * Copyright (c) 2018-2019 GraphDefined GmbH + * This file is part of Chargy Desktop App + * + * Licensed under the Affero GPL license, Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.gnu.org/licenses/agpl.html + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/// +/// +/// + + +interface IChargepointMeasurementValue extends IMeasurementValue +{ + infoStatus: string, + secondsIndex: number, + paginationId: string, + logBookIndex: string +} + +interface IChargepointCrypt01Result extends ICryptoResult +{ + sha256value?: any, + meterId?: string, + meter?: IMeter, + timestamp?: string, + infoStatus?: string, + secondsIndex?: string, + paginationId?: string, + obis?: string, + unitEncoded?: string, + scale?: string, + value?: string, + logBookIndex?: string, + authorizationStart?: string, + authorizationStop?: string, + authorizationStartTimestamp?: string, + publicKey?: string, + publicKeyFormat?: string, + publicKeySignatures?: any, + signature?: IECCSignature +} + + +class ChargepointCrypt01 extends ACrypt { + + readonly curve = new this.chargy.elliptic.ec('p192'); + + constructor(chargy: Chargy) { + + super("ECC secp192r1", + chargy); + + } + + + GenerateKeyPair()//options?: elliptic.ec.GenKeyPairOptions) + { + return this.curve.genKeyPair(); + // privateKey = keypair.getPrivate(); + // publicKey = keypair.getPublic(); + // privateKeyHEX = privateKey.toString('hex').toLowerCase(); + // publicKeyHEX = publicKey.encode('hex').toLowerCase(); + } + + + async SignChargingSession (chargingSession: IChargingSession, + privateKey: any): Promise + { + + return { + status: SessionVerificationResult.UnknownSessionFormat + } + + } + + async VerifyChargingSession(chargingSession: IChargingSession): Promise + { + + var sessionResult = SessionVerificationResult.UnknownSessionFormat; + + if (chargingSession.measurements) + { + for (var measurement of chargingSession.measurements) + { + + measurement.chargingSession = chargingSession; + + // Must include at least two measurements (start & stop) + if (measurement.values && measurement.values.length > 1) + { + + // Validate... + for (var measurementValue of measurement.values) + { + measurementValue.measurement = measurement; + await this.VerifyMeasurement(measurementValue as IChargepointMeasurementValue); + } + + + // Find an overall result... + sessionResult = SessionVerificationResult.ValidSignature; + + for (var measurementValue of measurement.values) + { + if (sessionResult == SessionVerificationResult.ValidSignature && + measurementValue.result.status != VerificationResult.ValidSignature) + { + sessionResult = SessionVerificationResult.InvalidSignature; + } + } + + } + + else + sessionResult = SessionVerificationResult.AtLeastTwoMeasurementsExpected; + + } + } + + return { + status: sessionResult + } + + } + + + async SignMeasurement (measurementValue: IChargepointMeasurementValue, + privateKey: any): Promise + { + + var buffer = new ArrayBuffer(320); + var cryptoBuffer = new DataView(buffer); + + var cryptoResult:IChargepointCrypt01Result = { + status: VerificationResult.InvalidSignature, + meterId: SetHex (cryptoBuffer, measurementValue.measurement.energyMeterId, 0), + timestamp: SetTimestamp32(cryptoBuffer, measurementValue.timestamp, 10), + infoStatus: SetHex (cryptoBuffer, measurementValue.infoStatus, 14, false), + secondsIndex: SetUInt32 (cryptoBuffer, measurementValue.secondsIndex, 15, true), + paginationId: SetHex (cryptoBuffer, measurementValue.paginationId, 19, true), + obis: SetHex (cryptoBuffer, measurementValue.measurement.obis, 23, false), + unitEncoded: SetInt8 (cryptoBuffer, measurementValue.measurement.unitEncoded, 29), + scale: SetInt8 (cryptoBuffer, measurementValue.measurement.scale, 30), + value: SetUInt64 (cryptoBuffer, measurementValue.value, 31, true), + logBookIndex: SetHex (cryptoBuffer, measurementValue.logBookIndex, 39, false), + authorizationStart: SetText (cryptoBuffer, measurementValue.measurement.chargingSession.authorizationStart["@id"], 41), + authorizationStartTimestamp: SetTimestamp32(cryptoBuffer, measurementValue.measurement.chargingSession.authorizationStart.timestamp, 169) + }; + + // Only the first 24 bytes/192 bits are used! + cryptoResult.sha256value = (await sha256(cryptoBuffer)).substring(0, 48); + + // cryptoResult.publicKey = publicKey.encode('hex'). + // toLowerCase(); + + const signature = this.curve.keyFromPrivate(privateKey.toString('hex')). + sign(cryptoResult.sha256value); + + switch (measurementValue.measurement.signatureInfos.format) + { + + case SignatureFormats.DER: + + cryptoResult.signature = { + algorithm: measurementValue.measurement.signatureInfos.algorithm, + format: measurementValue.measurement.signatureInfos.format, + value: signature.toDER('hex') + }; + + return cryptoResult; + + + case SignatureFormats.rs: + + cryptoResult.signature = { + algorithm: measurementValue.measurement.signatureInfos.algorithm, + format: measurementValue.measurement.signatureInfos.format, + r: signature.r, + s: signature.s + }; + + return cryptoResult; + + + //default: + + + } + + cryptoResult.status = VerificationResult.ValidSignature; + return cryptoResult; + + } + + async VerifyMeasurement(measurementValue: IChargepointMeasurementValue): Promise + { + + function setResult(verificationResult: VerificationResult) + { + cryptoResult.status = verificationResult; + measurementValue.result = cryptoResult; + return cryptoResult; + } + + measurementValue.method = this; + + var cryptoResult:IChargepointCrypt01Result = { + status: VerificationResult.NoOperation, + }; + + return setResult(VerificationResult.NoOperation); + + } + + async ViewMeasurement (measurementValue: IChargepointMeasurementValue, + introDiv: HTMLDivElement, + infoDiv: HTMLDivElement, + bufferValue: HTMLDivElement, + hashedBufferValue: HTMLDivElement, + publicKeyValue: HTMLDivElement, + signatureExpectedValue: HTMLDivElement, + signatureCheckValue: HTMLDivElement) + { + + const result = measurementValue.result as IChargepointCrypt01Result; + + const cryptoSpan = introDiv.querySelector('#cryptoAlgorithm') as HTMLSpanElement; + cryptoSpan.innerHTML = "EMHCrypt01 (" + this.description + ")"; + + this.CreateLine("Zählernummer", measurementValue.measurement.energyMeterId, result.meterId || "", infoDiv, bufferValue); + this.CreateLine("Zeitstempel", parseUTC(measurementValue.timestamp), result.timestamp || "", infoDiv, bufferValue); + this.CreateLine("Status", hex2bin(measurementValue.infoStatus) + " (" + measurementValue.infoStatus + " hex)
" + + this.DecodeStatus(measurementValue.infoStatus).join("
") + "
", result.infoStatus || "", infoDiv, bufferValue); + this.CreateLine("Sekundenindex", measurementValue.secondsIndex, result.secondsIndex || "", infoDiv, bufferValue); + this.CreateLine("Paginierungszähler", parseInt(measurementValue.paginationId, 16), result.paginationId || "", infoDiv, bufferValue); + this.CreateLine("OBIS-Kennzahl", parseOBIS(measurementValue.measurement.obis), result.obis || "", infoDiv, bufferValue); + this.CreateLine("Einheit (codiert)", measurementValue.measurement.unitEncoded, result.unitEncoded || "", infoDiv, bufferValue); + this.CreateLine("Skalierung", measurementValue.measurement.scale, result.scale || "", infoDiv, bufferValue); + this.CreateLine("Messwert", measurementValue.value + " Wh", result.value || "", infoDiv, bufferValue); + this.CreateLine("Logbuchindex", measurementValue.logBookIndex + " hex", result.logBookIndex || "", infoDiv, bufferValue); + this.CreateLine("Autorisierung", measurementValue.measurement.chargingSession.authorizationStart["@id"] + " hex", pad(result.authorizationStart, 128) || "", infoDiv, bufferValue); + this.CreateLine("Autorisierungszeitpunkt", parseUTC(measurementValue.measurement.chargingSession.authorizationStart.timestamp), pad(result.authorizationStartTimestamp, 151) || "", infoDiv, bufferValue); + + + // Buffer + bufferValue.parentElement!.children[0].innerHTML = "Puffer (320 Bytes, hex)"; + + // Hashed Buffer + hashedBufferValue.parentElement!.children[0].innerHTML = "Hashed Puffer (SHA256, 24 bytes, hex)"; + hashedBufferValue.innerHTML = result.sha256value.match(/.{1,8}/g).join(" ");; + + + // Public Key + publicKeyValue.parentElement!.children[0].innerHTML = "Public Key (" + + (result.publicKeyFormat + ? result.publicKeyFormat + ", " + : "") + + "hex)"; + + var pubKey = WhenNullOrEmpty(result.publicKey, ""); + + if (!IsNullOrEmpty(result.publicKey)) + publicKeyValue.innerHTML = pubKey.startsWith("04") // Add some space after '04' to avoid confused customers + ? "04 " + + pubKey.substring(2).match(/.{1,8}/g)!.join(" ") + : pubKey.match(/.{1,8}/g)!.join(" "); + + + if (!IsNullOrEmpty(result.publicKeySignatures)) { + +// publicKeyValue.parentElement!.children[2].innerHTML = "Bestätigt durch..."; + publicKeyValue.parentElement!.children[3].innerHTML = ""; + + for (let signature of result.publicKeySignatures) + { + + try + { + + let signatureDiv = publicKeyValue.parentElement!.children[3].appendChild(document.createElement('div')); + signatureDiv.innerHTML = await this.chargy.CheckMeterPublicKeySignature(measurementValue.measurement.chargingSession.chargingStation, + measurementValue.measurement.chargingSession.EVSE, + //@ts-ignore + measurementValue.measurement.chargingSession.EVSE.meters[0], + //@ts-ignore + measurementValue.measurement.chargingSession.EVSE.meters[0].publicKeys[0], + signature); + + } + catch (exception) + { } + + } + + } + + + // Signature + signatureExpectedValue.parentElement!.children[0].innerHTML = "Erwartete Signatur (" + (result.signature!.format || "") + ", hex)"; + + if (result.signature!.r && result.signature!.s) + signatureExpectedValue.innerHTML = "r: " + result.signature!.r!.toLowerCase().match(/.{1,8}/g)!.join(" ") + "
" + + "s: " + result.signature!.s!.toLowerCase().match(/.{1,8}/g)!.join(" "); + + else if (result.signature!.value) + signatureExpectedValue.innerHTML = result.signature!.value!.toLowerCase().match(/.{1,8}/g)!.join(" "); + + + // Result + switch (result.status) + { + + case VerificationResult.UnknownCTRFormat: + signatureCheckValue.innerHTML = '
Unbekanntes Transparenzdatenformat
'; + break; + + case VerificationResult.EnergyMeterNotFound: + signatureCheckValue.innerHTML = '
Ungültiger Energiezähler
'; + break; + + case VerificationResult.PublicKeyNotFound: + signatureCheckValue.innerHTML = '
Ungültiger Public Key
'; + break; + + case VerificationResult.InvalidPublicKey: + signatureCheckValue.innerHTML = '
Ungültiger Public Key
'; + break; + + case VerificationResult.InvalidSignature: + signatureCheckValue.innerHTML = '
Ungültige Signatur
'; + break; + + case VerificationResult.ValidSignature: + signatureCheckValue.innerHTML = '
Gültige Signatur
'; + break; + + + default: + signatureCheckValue.innerHTML = '
Ungültige Signatur
'; + break; + + } + + + } + + + //#region Helper methods + + private DecodeStatus(statusValue: string) : Array + { + + let statusArray:string[] = []; + + try + { + + let status = parseInt(statusValue); + + if ((status & 1) == 1) + statusArray.push("Fehler erkannt"); + + if ((status & 2) == 2) + statusArray.push("Synchrone Messwertübermittlung"); + + // Bit 3 is reserved! + + if ((status & 8) == 8) + statusArray.push("System-Uhr ist synchron"); + else + statusArray.push("System-Uhr ist nicht synchron"); + + if ((status & 16) == 16) + statusArray.push("Rücklaufsperre aktiv"); + + if ((status & 32) == 32) + statusArray.push("Energierichtung -A"); + + if ((status & 64) == 64) + statusArray.push("Magnetfeld erkannt"); + + } + catch (exception) + { + statusArray.push("Invalid status!"); + } + + return statusArray; + + } + + //#endregion + +} \ No newline at end of file diff --git a/src/js/chargy.ts b/src/js/chargy.ts index 97546fd..23a6459 100644 --- a/src/js/chargy.ts +++ b/src/js/chargy.ts @@ -198,6 +198,22 @@ class Chargy { message: "Unknown data format!" } + if (Content.startsWith("BZ")) + { + + const decompress = require('decompress'); + const decompressTarbz = require('decompress-tarbz2'); + + decompress('unicorn.tar.gz', 'dist', { + plugins: [ + decompressTarbz() + ] + }).then(() => { + console.log('Files decompressed'); + }); + + } + Content = Content.trim(); // Catches EFBBBF (UTF-8 BOM) because the buffer-to-string @@ -298,8 +314,13 @@ class Chargy { break; default: - // The current chargeIT mobility does not provide any context or format identifiers + // The current chargeIT mobility format does not provide any context or format identifiers result = await new ChargeIT().tryToParseChargeITJSON(JSONContent); + + // The current chargepoint format does not provide any context or format identifiers + if (isISessionCryptoResult(result)) + result = await new Chargepoint().tryToParseChargepointJSON(JSONContent); + break; } @@ -663,7 +684,11 @@ class Chargy { return await chargingSession.method.VerifyChargingSession(chargingSession); case "https://open.charging.cloud/contexts/SessionSignatureFormats/OCMFv1.0+json": - chargingSession.method = new OCMFv1_0 (this); + chargingSession.method = new OCMFv1_0(this); + return await chargingSession.method.VerifyChargingSession(chargingSession); + + case "https://open.charging.cloud/contexts/SessionSignatureFormats/ChargepointCrypt01+json": + chargingSession.method = new ChargepointCrypt01(this); return await chargingSession.method.VerifyChargingSession(chargingSession); default: diff --git a/src/js/chargyApp.ts b/src/js/chargyApp.ts index 635ab22..82eb47f 100644 --- a/src/js/chargyApp.ts +++ b/src/js/chargyApp.ts @@ -21,6 +21,7 @@ /// /// /// +/// /// /// /// @@ -956,7 +957,8 @@ class ChargyApp { //#region Show session time infos - try { + try + { if (chargingSession.begin) { @@ -973,8 +975,8 @@ class ChargyApp { if (chargingSession.end) { - var endUTC = parseUTC(chargingSession.end); - var duration = this.moment.duration(endUTC - beginUTC); + let endUTC = parseUTC(chargingSession.end); + let duration = this.moment.duration(endUTC - beginUTC); dateDiv.innerHTML += " - " + (Math.floor(duration.asDays()) > 0 ? endUTC.format("dddd") + " " : "") + @@ -993,50 +995,63 @@ class ChargyApp { //#endregion - var tableDiv = chargingSessionDiv.appendChild(document.createElement('div')); + let tableDiv = chargingSessionDiv.appendChild(document.createElement('div')); tableDiv.className = "table"; //#region Show energy infos - try { + try + { - var productInfoDiv = tableDiv.appendChild(document.createElement('div')); + let productInfoDiv = tableDiv.appendChild(document.createElement('div')); productInfoDiv.className = "productInfos"; - var productIconDiv = productInfoDiv.appendChild(document.createElement('div')); + let productIconDiv = productInfoDiv.appendChild(document.createElement('div')); productIconDiv.className = "icon"; productIconDiv.innerHTML = ''; - var productDiv = productInfoDiv.appendChild(document.createElement('div')); + let productDiv = productInfoDiv.appendChild(document.createElement('div')); productDiv.className = "text"; productDiv.innerHTML = chargingSession.product != null ? chargingSession.product["@id"] + "
" : ""; - productDiv.innerHTML += "Ladedauer "; - if (Math.floor(duration.asDays()) > 1) productDiv.innerHTML += duration.days() + " Tage " + duration.hours() + " Std. " + duration.minutes() + " Min. " + duration.seconds() + " Sek."; - else if (Math.floor(duration.asDays()) > 0) productDiv.innerHTML += duration.days() + " Tag " + duration.hours() + " Std. " + duration.minutes() + " Min. " + duration.seconds() + " Sek."; - else if (Math.floor(duration.asHours()) > 0) productDiv.innerHTML += duration.hours() + " Std. " + duration.minutes() + " Min. " + duration.seconds() + " Sek."; - else if (Math.floor(duration.asMinutes()) > 0) productDiv.innerHTML += duration.minutes() + " Min. " + duration.seconds() + " Sek."; - else if (Math.floor(duration.asSeconds()) > 0) productDiv.innerHTML += duration.seconds(); + if (chargingSession.end) + { + + let endUTC = parseUTC(chargingSession.end); + let duration = this.moment.duration(endUTC - beginUTC); + + productDiv.innerHTML += "Ladedauer "; + if (Math.floor(duration.asDays()) > 1) productDiv.innerHTML += duration.days() + " Tage " + duration.hours() + " Std. " + duration.minutes() + " Min. " + duration.seconds() + " Sek."; + else if (Math.floor(duration.asDays()) > 0) productDiv.innerHTML += duration.days() + " Tag " + duration.hours() + " Std. " + duration.minutes() + " Min. " + duration.seconds() + " Sek."; + else if (Math.floor(duration.asHours()) > 0) productDiv.innerHTML += duration.hours() + " Std. " + duration.minutes() + " Min. " + duration.seconds() + " Sek."; + else if (Math.floor(duration.asMinutes()) > 0) productDiv.innerHTML += duration.minutes() + " Min. " + duration.seconds() + " Sek."; + else if (Math.floor(duration.asSeconds()) > 0) productDiv.innerHTML += duration.seconds(); + + } if (chargingSession.measurements) { - for (var measurement of chargingSession.measurements) + for (let measurement of chargingSession.measurements) { // if (measurement.values && measurement.values.length > 0) { - var first = measurement.values[0].value; - var last = measurement.values[measurement.values.length-1].value; - var amount = parseFloat(((last - first) * Math.pow(10, measurement.scale)).toFixed(10)); + if (measurement.scale == null) + measurement.scale = 0; + + let first = measurement.values[0].value; + let last = measurement.values[measurement.values.length-1].value; + let amount = parseFloat(((last - first) * Math.pow(10, measurement.scale)).toFixed(10)); switch (measurement.unit) { + case "kWh": case "KILO_WATT_HOURS": break; - // "WATT_HOURS" + // "WATT_HOURS" or "Wh" default: amount = parseFloat((amount / 1000).toFixed(10)); break; @@ -1058,6 +1073,52 @@ class ChargyApp { //#endregion + //#region Show parking infos + + try + { + + if (chargingSession.parking && chargingSession.parking.length > 0) + { + + var parkingInfoDiv = tableDiv.appendChild(document.createElement('div')); + parkingInfoDiv.className = "parkingInfos"; + + var parkingIconDiv = parkingInfoDiv.appendChild(document.createElement('div')); + parkingIconDiv.className = "icon"; + parkingIconDiv.innerHTML = ''; + + var parkingDiv = parkingInfoDiv.appendChild(document.createElement('div')); + parkingDiv.className = "text"; + // parkingDiv.innerHTML = chargingSession.parking != null ? chargingSession.product["@id"] + "
" : ""; + + if (chargingSession.parking[chargingSession.parking.length-1].end != null) + { + + let parkingBegin = parseUTC(chargingSession.parking[0].begin); + //@ts-ignore + let parkingEnd = parseUTC(chargingSession.parking[chargingSession.parking.length-1].end); + let duration = this.moment.duration(parkingEnd - parkingBegin); + + parkingDiv.innerHTML += "Parkdauer "; + if (Math.floor(duration.asDays()) > 1) parkingDiv.innerHTML += duration.days() + " Tage " + duration.hours() + " Std. " + duration.minutes() + " Min. " + duration.seconds() + " Sek."; + else if (Math.floor(duration.asDays()) > 0) parkingDiv.innerHTML += duration.days() + " Tag " + duration.hours() + " Std. " + duration.minutes() + " Min. " + duration.seconds() + " Sek."; + else if (Math.floor(duration.asHours()) > 0) parkingDiv.innerHTML += duration.hours() + " Std. " + duration.minutes() + " Min. " + duration.seconds() + " Sek."; + else if (Math.floor(duration.asMinutes()) > 0) parkingDiv.innerHTML += duration.minutes() + " Min. " + duration.seconds() + " Sek."; + else if (Math.floor(duration.asSeconds()) > 0) parkingDiv.innerHTML += duration.seconds(); + + } + + } + + } + catch (exception) + { + console.log("Could not show parking infos of charging session '" + chargingSession["@id"] + "':" + exception); + } + + //#endregion + //#region Show authorization start/stop information try { @@ -1133,7 +1194,7 @@ class ChargyApp { //#endregion - //#region Show location infos... + //#region Show charging station infos... try { @@ -1142,25 +1203,23 @@ class ChargyApp { chargingSession.chargingStationId || chargingSession.chargingStation || chargingSession.chargingPoolId || chargingSession.chargingPool) { - var address:IAddress|null = null; - - var locationInfoDiv = tableDiv.appendChild(document.createElement('div')); - locationInfoDiv.className = "locationInfos"; + var chargingStationInfoDiv = tableDiv.appendChild(document.createElement('div')); + chargingStationInfoDiv.className = "chargingStationInfos"; - var locationIconDiv = locationInfoDiv.appendChild(document.createElement('div')); - locationIconDiv.className = "icon"; - locationIconDiv.innerHTML = ''; + var chargingStationIconDiv = chargingStationInfoDiv.appendChild(document.createElement('div')); + chargingStationIconDiv.className = "icon"; + chargingStationIconDiv.innerHTML = ''; - var locationDiv = locationInfoDiv.appendChild(document.createElement('div')); - locationDiv.classList.add("text"); + var chargingStationDiv = chargingStationInfoDiv.appendChild(document.createElement('div')); + chargingStationDiv.classList.add("text"); if (chargingSession.EVSEId || chargingSession.EVSE) { if (chargingSession.EVSE == null || typeof chargingSession.EVSE !== 'object') chargingSession.EVSE = this.chargy.GetEVSE(chargingSession.EVSEId); - locationDiv.classList.add("EVSE"); - locationDiv.innerHTML = (chargingSession.EVSE != null && chargingSession.EVSE.description != null + chargingStationDiv.classList.add("EVSE"); + chargingStationDiv.innerHTML = (chargingSession.EVSE != null && chargingSession.EVSE.description != null ? firstValue(chargingSession.EVSE.description) + "
" : "") + (chargingSession.EVSEId != null @@ -1192,8 +1251,8 @@ class ChargyApp { if (chargingSession.chargingStation != null) { - locationDiv.classList.add("chargingStation"); - locationDiv.innerHTML = (chargingSession.chargingStation != null && chargingSession.chargingStation.description != null + chargingStationDiv.classList.add("chargingStation"); + chargingStationDiv.innerHTML = (chargingSession.chargingStation != null && chargingSession.chargingStation.description != null ? firstValue(chargingSession.chargingStation.description) + "
" : "") + (chargingSession.chargingStationId != null @@ -1203,11 +1262,9 @@ class ChargyApp { chargingSession.chargingPool = chargingSession.chargingStation.chargingPool; chargingSession.chargingPoolId = chargingSession.chargingStation.chargingPoolId; - address = chargingSession.chargingStation.address; - } else - locationInfoDiv.remove(); + chargingStationDiv.remove(); } @@ -1219,30 +1276,60 @@ class ChargyApp { if (chargingSession.chargingPool != null) { - locationDiv.classList.add("chargingPool"); - locationDiv.innerHTML = (chargingSession.chargingPool != null && chargingSession.chargingPool.description != null + chargingStationDiv.classList.add("chargingPool"); + chargingStationDiv.innerHTML = (chargingSession.chargingPool != null && chargingSession.chargingPool.description != null ? firstValue(chargingSession.chargingPool.description) + "
" : "") + (chargingSession.chargingPoolId != null ? chargingSession.chargingPoolId : chargingSession.chargingPool["@id"]); - address = this.chargy.GetChargingPool(chargingSession.chargingPool["@id"])!.address; - } else - locationInfoDiv.remove(); + chargingStationDiv.remove(); } - if (address != null) - locationDiv.innerHTML += "
" + - (address.street != null ? " " + address.street : "") + - (address.houseNumber != null ? " " + address.houseNumber : "") + + } + + } catch (exception) + { + console.log("Could not show charging station infos of charging session '" + chargingSession["@id"] + "':" + exception); + } + + //#endregion + + //#region Show location infos... + + try + { + + var address:IAddress|null = null; + + if (chargingSession.chargingStation != null && chargingSession.chargingStation.address != null) + address = chargingSession.chargingStation.address; + + else if (chargingSession.chargingPool != null && chargingSession.chargingPool.address != null) + address = chargingSession.chargingPool.address; - (address.postalCode != null || address.city != null ? "," : "") + - (address.postalCode != null ? " " + address.postalCode : "") + - (address.city != null ? " " + address.city : ""); + if (address != null) + { + + var locationInfoDiv = tableDiv.appendChild(document.createElement('div')); + locationInfoDiv.className = "locationInfos"; + + var locationIconDiv = locationInfoDiv.appendChild(document.createElement('div')); + locationIconDiv.className = "icon"; + locationIconDiv.innerHTML = ''; + + var locationDiv = locationInfoDiv.appendChild(document.createElement('div')); + locationDiv.classList.add("text"); + locationDiv.innerHTML = (address.street != null ? " " + address.street : "") + + (address.houseNumber != null ? " " + address.houseNumber : "") + + + (address.postalCode != null || address.city != null ? "," : "") + + (address.postalCode != null ? " " + address.postalCode : "") + + (address.city != null ? " " + address.city : ""); } @@ -1627,6 +1714,10 @@ class ChargyApp { icon = ' Ungültige Signatur'; break; + case VerificationResult.NoOperation: + icon = ' Keine Validierung'; + break; + case VerificationResult.ValidSignature: icon = ' Gültige Signatur'; break; diff --git a/src/js/chargyInterfaces.ts b/src/js/chargyInterfaces.ts index 0e0f821..f0f2bc9 100644 --- a/src/js/chargyInterfaces.ts +++ b/src/js/chargyInterfaces.ts @@ -196,6 +196,7 @@ interface IChargingSession authorizationStop: IAuthorization; product: IChargingProduct; measurements: Array; + parking: Array; method: ACrypt; verificationResult?: ISessionCryptoResult; } @@ -206,6 +207,14 @@ interface IChargingProduct "@context": string; } +interface IParking +{ + "@id": string; + "@context": string; + begin: string; + end?: string; +} + interface IAuthorization { "@id": string; @@ -266,11 +275,19 @@ interface ISessionCryptoResult exception?: any; } +function isISessionCryptoResult(obj: any): obj is ISessionCryptoResult { + return obj.status !== undefined +} + interface ICryptoResult { status: VerificationResult; } +function isICryptoResult(obj: any): obj is ICryptoResult { + return obj.status !== undefined +} + interface IPublicKey { algorithm: string; @@ -331,7 +348,8 @@ enum VerificationResult { PublicKeyNotFound, InvalidPublicKey, InvalidSignature, - ValidSignature + NoOperation, + ValidSignature, } interface IVersions { @@ -370,3 +388,8 @@ interface IVersionSignature { format: string, signature: string } + +interface IResult { + status: SessionVerificationResult, + message: string +} \ No newline at end of file From 18759999e3f215ccdbc55d2686ec11eec5b8a46f Mon Sep 17 00:00:00 2001 From: Achim 'ahzf' Friedland Date: Sat, 9 Nov 2019 11:30:00 +0100 Subject: [PATCH 021/110] Upgrade some libs, esp. TypeScript to the great new 3.7 version :) --- .gitignore | 1 + documentation/REBUILD.md | 6 ++-- package-lock.json | 77 ++++++++++++++++++---------------------- package.json | 6 ++-- 4 files changed, 42 insertions(+), 48 deletions(-) diff --git a/.gitignore b/.gitignore index 34e0d77..15d0ba6 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ src/css/*.css.map !src/css/fontawesome-all.min.css src/js/*.js src/js/*.js.map +.vscode/* diff --git a/documentation/REBUILD.md b/documentation/REBUILD.md index 20e4b49..2614711 100644 --- a/documentation/REBUILD.md +++ b/documentation/REBUILD.md @@ -16,13 +16,13 @@ $ npm install electron-builder@latest --save-dev + electron-builder@20.44.4 $ npm install typescript@latest --save-dev -+ typescript@3.5.2 ++ typescript@3.7.2 $ npm install sass@latest --save-dev -+ sass@1.22.1 ++ sass@1.23.3 $ npm install @types/node@latest --save-dev -+ @types/node@12.0.10 ++ @types/node@12.12.7 $ npm install elliptic@latest + elliptic@6.5.1 diff --git a/package-lock.json b/package-lock.json index a5a0b36..d55e9fc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -76,9 +76,9 @@ } }, "@types/node": { - "version": "12.0.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.10.tgz", - "integrity": "sha512-LcsGbPomWsad6wmMNv7nBLw7YYYyfdYcz6xryKYQhx89c3XXan+8Q6AJ43G5XDIaklaVkK3mE4fCb0SBvMiPSQ==" + "version": "12.12.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.7.tgz", + "integrity": "sha512-E6Zn0rffhgd130zbCbAr/JdXfXkoOUFAKNs/rF8qnafSJ8KYaA/j3oz7dcwal+lYjLA7xvdd5J4wdYpCTlP8+w==" }, "ajv": { "version": "6.10.0", @@ -174,9 +174,9 @@ } }, "anymatch": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.0.2.tgz", - "integrity": "sha512-rUe9SxpRQlVg4EM8It7JMNWWYHAirTPpbTuvaSKybb5IejNgWB3PGBBX9rrPKDx2pM/p3Wh+7+ASaWRyyAbxmQ==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", "dev": true, "requires": { "normalize-path": "^3.0.0", @@ -268,12 +268,6 @@ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "dev": true }, - "async-each": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", - "dev": true - }, "async-exit-hook": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz", @@ -653,20 +647,19 @@ } }, "chokidar": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.0.1.tgz", - "integrity": "sha512-2ww34sJWehnbpV0Q4k4V5Hh7juo7po6z7LUWkcIQnSGN1lHOL8GGtLtfwabKvLFQw/hbSUQ0u6V7OgGYgBzlkQ==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", "dev": true, "requires": { - "anymatch": "^3.0.1", - "async-each": "^1.0.3", - "braces": "^3.0.2", - "fsevents": "^2.0.6", - "glob-parent": "^5.0.0", - "is-binary-path": "^2.1.0", - "is-glob": "^4.0.1", - "normalize-path": "^3.0.0", - "readdirp": "^3.0.2" + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" } }, "chromium-pickle-js": { @@ -1419,9 +1412,9 @@ } }, "fsevents": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.0.7.tgz", - "integrity": "sha512-a7YT0SV3RB+DjYcppwVDLtn13UQnmg0SWZS7ezZD0UjnLwXmy8Zm21GMVGLaFGimIqcvyMQaOJBrop8MyOp1kQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.1.tgz", + "integrity": "sha512-4FRPXWETxtigtJW/gxzEDsX1LVbPAM93VleB83kZB+ellqbHMkyt2aJfuzNLRvFPnGi6bcE5SvfxgbXPeKteJw==", "dev": true, "optional": true }, @@ -1453,9 +1446,9 @@ } }, "glob-parent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.0.0.tgz", - "integrity": "sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", + "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", "dev": true, "requires": { "is-glob": "^4.0.1" @@ -2370,9 +2363,9 @@ "dev": true }, "picomatch": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.0.7.tgz", - "integrity": "sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.1.1.tgz", + "integrity": "sha512-OYMyqkKzK7blWO/+XZYP6w8hH0LDvkBvdvKukti+7kqYFCiEAk+gI3DWnryapc0Dau05ugGTy0foQ6mqn4AHYA==", "dev": true }, "pify": { @@ -2555,9 +2548,9 @@ } }, "readdirp": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.0.2.tgz", - "integrity": "sha512-LbyJYv48eywrhOlScq16H/VkCiGKGPC2TpOdZCJ7QXnYEjn3NN/Oblh8QEU3vqfSRBB7OGvh5x45NKiVeNujIQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", "dev": true, "requires": { "picomatch": "^2.0.4" @@ -2680,9 +2673,9 @@ } }, "sass": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.22.1.tgz", - "integrity": "sha512-VsWrNdfIzCLbD2TO2bq9tCaUzEE0UUSGtP3r9IhHi8ypAPCb3FOVP99kMRil+ZROEcTnKReZcQP9vk6ArV2eLw==", + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.23.3.tgz", + "integrity": "sha512-1DKRZxJMOh4Bme16AbWTyYeJAjTlrvw2+fWshHHaepeJfGq2soFZTnt0YhWit+bohtDu4LdyPoEj6VFD4APHog==", "dev": true, "requires": { "chokidar": ">=2.0.0 <4.0.0" @@ -3105,9 +3098,9 @@ "dev": true }, "typescript": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.2.tgz", - "integrity": "sha512-7KxJovlYhTX5RaRbUdkAXN1KUZ8PwWlTzQdHV6xNqvuFOs7+WBo10TQUqT19Q/Jz2hk5v9TQDIhyLhhJY4p5AA==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.2.tgz", + "integrity": "sha512-ml7V7JfiN2Xwvcer+XAf2csGO1bPBdRbFCkYBczNZggrBZ9c7G3riSUeJmqEU5uOtXNPMhE3n+R4FA/3YOAWOQ==", "dev": true }, "unbzip2-stream": { diff --git a/package.json b/package.json index 440344d..e153a57 100644 --- a/package.json +++ b/package.json @@ -39,11 +39,11 @@ }, "devDependencies": { "@types/elliptic": "^6.4.10", - "@types/node": "^12.0.10", + "@types/node": "^12.12.7", "electron": "^5.0.6", "electron-builder": "^20.44.4", - "sass": "^1.22.1", - "typescript": "^3.5.2" + "sass": "^1.23.3", + "typescript": "^3.7.2" }, "build": { "appId": "cloud.charging.open.chargy.desktop", From ab188d866aa81c3ef5a5485383d133040609f75d Mon Sep 17 00:00:00 2001 From: Achim 'ahzf' Friedland Date: Thu, 14 Nov 2019 04:46:39 +0100 Subject: [PATCH 022/110] Allow multiple CTR files to be opened. Allow public key files (PEM format) to be processed. --- documentation/REBUILD.md | 14 +- package-lock.json | 459 +++++++++++++++++++++++++++++++++---- package.json | 12 +- src/index.html | 6 +- src/js/EMHCrypt01.ts | 9 +- src/js/GDFCrypt01.ts | 8 +- src/js/chargy.ts | 377 ++++++++++++++++++++++-------- src/js/chargyApp.ts | 66 +++--- src/js/chargyInterfaces.ts | 69 ++++-- 9 files changed, 817 insertions(+), 203 deletions(-) diff --git a/documentation/REBUILD.md b/documentation/REBUILD.md index 2614711..8bceeb0 100644 --- a/documentation/REBUILD.md +++ b/documentation/REBUILD.md @@ -36,12 +36,24 @@ $ npm install moment@latest $ npm install base32-decode + base32-decode@1.0.0 +$ npm install file-type@latest ++ file-type@12.4.0 + $ npm install decompress@latest + decompress@4.2.0 -$ npm install @types/decompress --save +$ npm install @types/decompress --save-dev + @types/decompress@4.2.3 +$ npm install decompress-tarxz@latest ++ decompress-tarxz@3.0.0 + +$ npm install decompress-bzip2@latest ++ decompress-bzip2@4.0.0 + +$ npm install decompress-gz@latest ++ decompress-gz@0.0.1 + $ npm install chart.js@latest + chart.js@2.9.1 diff --git a/package-lock.json b/package-lock.json index d55e9fc..9d5d16f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,7 +37,8 @@ "@types/chart.js": { "version": "2.7.54", "resolved": "https://registry.npmjs.org/@types/chart.js/-/chart.js-2.7.54.tgz", - "integrity": "sha512-BxIUR4mfk0zOqOPEu4gxLP5herra6INQLyFmgVE6JVRNNB+r36g2cd67nDUEEdD/EShZvaR33xausxOGv1+nbw==" + "integrity": "sha512-BxIUR4mfk0zOqOPEu4gxLP5herra6INQLyFmgVE6JVRNNB+r36g2cd67nDUEEdD/EShZvaR33xausxOGv1+nbw==", + "dev": true }, "@types/debug": { "version": "4.1.4", @@ -49,6 +50,7 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/@types/decompress/-/decompress-4.2.3.tgz", "integrity": "sha512-W24e3Ycz1UZPgr1ZEDHlK4XnvOr+CpJH3qNsFeqXwwlW/9END9gxn3oJSsp7gYdiQxrXUHwUUd3xuzVz37MrZQ==", + "dev": true, "requires": { "@types/node": "*" } @@ -65,12 +67,14 @@ "@types/geojson": { "version": "7946.0.7", "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.7.tgz", - "integrity": "sha512-wE2v81i4C4Ol09RtsWFAqg3BUitWbHSpSlIo+bNdsCJijO9sjme+zm+73ZMCa/qMC8UEERxzGbvmr1cffo2SiQ==" + "integrity": "sha512-wE2v81i4C4Ol09RtsWFAqg3BUitWbHSpSlIo+bNdsCJijO9sjme+zm+73ZMCa/qMC8UEERxzGbvmr1cffo2SiQ==", + "dev": true }, "@types/leaflet": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.4.4.tgz", "integrity": "sha512-CROxHvsRDFyR1OQKZv/WJsCVFv8Wj6wFF/FOI/yiGwX7GMivyvF8Ks5AT3/JYk269pGiE43wP9JOgcr7EK2eUw==", + "dev": true, "requires": { "@types/geojson": "*" } @@ -78,7 +82,13 @@ "@types/node": { "version": "12.12.7", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.7.tgz", - "integrity": "sha512-E6Zn0rffhgd130zbCbAr/JdXfXkoOUFAKNs/rF8qnafSJ8KYaA/j3oz7dcwal+lYjLA7xvdd5J4wdYpCTlP8+w==" + "integrity": "sha512-E6Zn0rffhgd130zbCbAr/JdXfXkoOUFAKNs/rF8qnafSJ8KYaA/j3oz7dcwal+lYjLA7xvdd5J4wdYpCTlP8+w==", + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, "ajv": { "version": "6.10.0", @@ -144,8 +154,7 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, "ansi-styles": { "version": "3.2.1", @@ -238,6 +247,49 @@ } } }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -295,8 +347,7 @@ "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "base32-decode": { "version": "1.0.0", @@ -441,7 +492,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -662,6 +712,11 @@ "readdirp": "~3.2.0" } }, + "chownr": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz", + "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==" + }, "chromium-pickle-js": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz", @@ -737,8 +792,7 @@ "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, "color-convert": { "version": "0.5.3", @@ -776,8 +830,7 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "concat-stream": { "version": "1.6.2", @@ -837,6 +890,11 @@ "xdg-basedir": "^3.0.0" } }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -881,7 +939,6 @@ "version": "3.2.6", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, "requires": { "ms": "^2.1.1" } @@ -907,6 +964,37 @@ "strip-dirs": "^2.0.0" } }, + "decompress-bzip2": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decompress-bzip2/-/decompress-bzip2-4.0.0.tgz", + "integrity": "sha1-0SVMlJ4F6vYol1QoawY/3Hz/AT8=", + "requires": { + "file-type": "^4.3.0", + "seek-bzip": "^1.0.5" + }, + "dependencies": { + "file-type": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-4.4.0.tgz", + "integrity": "sha1-G2AOX8ofvcboDApwxxyNul95BsU=" + } + } + }, + "decompress-gz": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/decompress-gz/-/decompress-gz-0.0.1.tgz", + "integrity": "sha512-YMdCWdxHvPplsTbV1tvr2oFJOtAFNxqVMFnKWEmePBXl+LKG5z5bFrowzc12Jzd7O29nnzI/D1M95Asx0Qa1fg==", + "requires": { + "file-type": "^5.2.0" + }, + "dependencies": { + "file-type": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", + "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=" + } + } + }, "decompress-response": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", @@ -924,6 +1012,13 @@ "file-type": "^5.2.0", "is-stream": "^1.1.0", "tar-stream": "^1.5.2" + }, + "dependencies": { + "file-type": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", + "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=" + } } }, "decompress-tarbz2": { @@ -953,6 +1048,31 @@ "decompress-tar": "^4.1.1", "file-type": "^5.2.0", "is-stream": "^1.1.0" + }, + "dependencies": { + "file-type": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", + "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=" + } + } + }, + "decompress-tarxz": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/decompress-tarxz/-/decompress-tarxz-3.0.0.tgz", + "integrity": "sha512-/85049bKZOmkVXrFz9Zf90DMBPYuXGGAMOQaytNgMGiB7u4iIJKLUaEXRiLBvugtknmYcP1Zv6KQWEYWshTblg==", + "requires": { + "decompress-tar": "^4.1.0", + "file-type": "^12.3.0", + "is-stream": "^2.0.0", + "lzma-native": "^4.0.5" + }, + "dependencies": { + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" + } } }, "decompress-unzip": { @@ -1002,8 +1122,7 @@ "deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" }, "defer-to-connect": { "version": "1.0.2", @@ -1017,6 +1136,16 @@ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", "dev": true }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" + }, "dmg-builder": { "version": "6.7.2", "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-6.7.2.tgz", @@ -1321,9 +1450,9 @@ } }, "file-type": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", - "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=" + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-12.4.0.tgz", + "integrity": "sha512-WTvyKq8yjtNmUtVAD8LGcTkvtCdJglM6ks2HTqEClm6+65XTqM6MoZYA1Vtra50DLRWLiM38fEs1y56f5VhnUA==" }, "fill-range": { "version": "7.0.1", @@ -1411,6 +1540,19 @@ } } }, + "fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "requires": { + "minipass": "^2.6.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, "fsevents": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.1.tgz", @@ -1418,6 +1560,21 @@ "dev": true, "optional": true }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -1445,6 +1602,19 @@ "assert-plus": "^1.0.0" } }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, "glob-parent": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", @@ -1525,6 +1695,11 @@ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + }, "has-yarn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", @@ -1577,7 +1752,6 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" } @@ -1587,6 +1761,14 @@ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" }, + "ignore-walk": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", + "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", + "requires": { + "minimatch": "^3.0.4" + } + }, "import-lazy": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", @@ -1608,6 +1790,15 @@ "repeating": "^2.0.0" } }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", @@ -1616,8 +1807,7 @@ "ini": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", - "dev": true + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" }, "invert-kv": { "version": "2.0.0", @@ -1668,7 +1858,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, "requires": { "number-is-nan": "^1.0.0" } @@ -1933,6 +2122,46 @@ "yallist": "^2.1.2" } }, + "lzma-native": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/lzma-native/-/lzma-native-4.0.5.tgz", + "integrity": "sha512-pmLMsHQlXQAikqGqapzUOtACPW/gEtt9xhkcrkJnsjWn+I1g7OIbrV2SugL8jinkBCD+QxqAze51VtRsECDcxQ==", + "requires": { + "nan": "^2.14.0", + "node-pre-gyp": "^0.11.0", + "readable-stream": "^2.3.5", + "rimraf": "^2.6.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "make-dir": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", @@ -2039,7 +2268,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -2047,14 +2275,36 @@ "minimist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + }, + "minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + }, + "dependencies": { + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + } + } + }, + "minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "requires": { + "minipass": "^2.9.0" + } }, "mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, "requires": { "minimist": "0.0.8" }, @@ -2062,8 +2312,7 @@ "minimist": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" } } }, @@ -2075,8 +2324,22 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" + }, + "needle": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.4.0.tgz", + "integrity": "sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==", + "requires": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } }, "nice-try": { "version": "1.0.5", @@ -2084,6 +2347,32 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "node-pre-gyp": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz", + "integrity": "sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q==", + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", + "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -2108,6 +2397,20 @@ "integrity": "sha512-0NLtR71o4k6GLP+mr6Ty34c5GA6CMoEsncKJxvQd8NzPxaHRJNnb5gZE8R1XF4CPIS7QPHLJ74IFszwtNVAHVQ==", "dev": true }, + "npm-bundled": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz", + "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==" + }, + "npm-packlist": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.6.tgz", + "integrity": "sha512-u65uQdb+qwtGvEJh/DgQgW1Xg7sqeNbmxYyrvlNznaVTjV3E5P6F/EFjM+BVHXl7JJlsdG8A64M0XI8FI/IOlg==", + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -2117,6 +2420,17 @@ "path-key": "^2.0.0" } }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, "nugget": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/nugget/-/nugget-2.0.1.tgz", @@ -2152,8 +2466,7 @@ "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "oauth-sign": { "version": "0.9.0", @@ -2180,6 +2493,11 @@ "wrappy": "1" } }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + }, "os-locale": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", @@ -2230,6 +2548,20 @@ } } }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, "p-cancelable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", @@ -2322,6 +2654,11 @@ "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", "dev": true }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, "path-is-inside": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", @@ -2466,7 +2803,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, "requires": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -2652,6 +2988,14 @@ "lowercase-keys": "^1.0.0" } }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -2660,8 +3004,7 @@ "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "sanitize-filename": { "version": "1.6.1", @@ -2684,8 +3027,7 @@ "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, "seek-bzip": { "version": "1.0.5", @@ -2698,8 +3040,7 @@ "semver": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "dev": true + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" }, "semver-diff": { "version": "2.1.0", @@ -2713,8 +3054,7 @@ "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, "shebang-command": { "version": "1.2.0", @@ -2734,8 +3074,7 @@ "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" }, "single-line-log": { "version": "1.1.2", @@ -2833,7 +3172,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -2850,7 +3188,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, "requires": { "ansi-regex": "^2.0.0" } @@ -2890,8 +3227,7 @@ "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" }, "sumchecker": { "version": "2.0.2", @@ -2928,6 +3264,27 @@ "has-flag": "^3.0.0" } }, + "tar": { + "version": "4.4.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", + "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + }, + "dependencies": { + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + } + } + }, "tar-stream": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", @@ -3218,6 +3575,14 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "requires": { + "string-width": "^1.0.2 || 2" + } + }, "widest-line": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", diff --git a/package.json b/package.json index e153a57..65db7f5 100644 --- a/package.json +++ b/package.json @@ -26,20 +26,24 @@ "license": "AGPL-3.0-or-later", "homepage": "https://github.com/OpenChargingCloud/ChargyDesktopApp", "dependencies": { - "@types/chart.js": "^2.7.54", - "@types/decompress": "^4.2.3", - "@types/leaflet": "^1.4.4", "base32-decode": "^1.0.0", "chart.js": "^2.8.0", "decompress": "^4.2.0", + "decompress-bzip2": "^4.0.0", + "decompress-gz": "0.0.1", + "decompress-tarxz": "^3.0.0", "elliptic": "^6.5.1", + "file-type": "^12.4.0", "leaflet": "^1.5.1", "leaflet.awesome-markers": "^2.0.5", "moment": "^2.24.0" }, "devDependencies": { - "@types/elliptic": "^6.4.10", "@types/node": "^12.12.7", + "@types/elliptic": "^6.4.10", + "@types/decompress": "^4.2.3", + "@types/leaflet": "^1.4.4", + "@types/chart.js": "^2.7.54", "electron": "^5.0.6", "electron-builder": "^20.44.4", "sass": "^1.23.3", diff --git a/src/index.html b/src/index.html index 9d4bd6c..775e896 100644 --- a/src/index.html +++ b/src/index.html @@ -81,7 +81,7 @@
- +
@@ -105,7 +105,7 @@

Diese Software ist Open Source und basiert auf den folgenden Open-Source-Software-Bibliotheken:

- +
Chargy
@@ -132,7 +132,7 @@
-
TypeScript 3.5.2
+
TypeScript 3.7.2
diff --git a/src/js/EMHCrypt01.ts b/src/js/EMHCrypt01.ts index b925cd9..530201c 100644 --- a/src/js/EMHCrypt01.ts +++ b/src/js/EMHCrypt01.ts @@ -258,16 +258,15 @@ class EMHCrypt01 extends ACrypt { cryptoResult.meter = meter; - var iPublicKey = meter.publicKeys[0] as IPublicKey; - if (iPublicKey != null) + if (meter.publicKeys != null && meter.publicKeys.length > 0) { try { - cryptoResult.publicKey = iPublicKey.value.toLowerCase(); - cryptoResult.publicKeyFormat = iPublicKey.format; - cryptoResult.publicKeySignatures = iPublicKey.signatures; + cryptoResult.publicKey = meter.publicKeys[0].value.toLowerCase(); + cryptoResult.publicKeyFormat = meter.publicKeys[0].format; + cryptoResult.publicKeySignatures = meter.publicKeys[0].signatures; try { diff --git a/src/js/GDFCrypt01.ts b/src/js/GDFCrypt01.ts index 93c80a9..3aa30ee 100644 --- a/src/js/GDFCrypt01.ts +++ b/src/js/GDFCrypt01.ts @@ -239,15 +239,15 @@ class GDFCrypt01 extends ACrypt { cryptoResult.meter = meter; - var iPublicKey = meter.publicKeys[0] as IPublicKey; - if (iPublicKey != null) + if (meter.publicKeys != null && meter.publicKeys.length > 0) { try { - cryptoResult.publicKey = iPublicKey.value.toLowerCase(); - cryptoResult.publicKeyFormat = iPublicKey.format; + cryptoResult.publicKey = meter.publicKeys[0].value.toLowerCase(); + cryptoResult.publicKeyFormat = meter.publicKeys[0].format; + cryptoResult.publicKeySignatures = meter.publicKeys[0].signatures; try { diff --git a/src/js/chargy.ts b/src/js/chargy.ts index 23a6459..ac95ed9 100644 --- a/src/js/chargy.ts +++ b/src/js/chargy.ts @@ -186,162 +186,324 @@ class Chargy { //#endregion - //#region detectAndConvertContentFormat(Content) + //#region detectAndConvertContentFormat(FileInfos) - public async detectAndConvertContentFormat(Content: string): Promise { + public async detectAndConvertContentFormat(FileInfos: Array): Promise { - //#region Clean data + //#region Initial checks - if (Content == null) + if (FileInfos == null || FileInfos.length == 0) return { status: SessionVerificationResult.InvalidSessionFormat, message: "Unknown data format!" } - if (Content.startsWith("BZ")) + const fileType = require('file-type'); + const decompress = require('decompress'); + const decompressTar = require('decompress-tar'); + const decompressTargz = require('decompress-targz'); + const decompressTarbz2 = require('decompress-tarbz2'); + // const decompressTarxz = require('decompress-tarxz'); // Does not compile! + const decompressUnzip = require('decompress-unzip'); + const decompressGz = require('decompress-gz'); + const decompressBzip2 = require('decompress-bzip2'); + + //#endregion + + // DataInfos.sort(function (a, b) { + // if (a.name < b.name) return -1; + // if (a.name > b.name) return +1; + // return 0; + // }); + + //#region Process compressed files or archive files + + let expandedFiles = new Array(); + + for (let FileInfo of FileInfos) { - const decompress = require('decompress'); - const decompressTarbz = require('decompress-tarbz2'); + let file_mimetype = fileType(FileInfo.data)?.mime; - decompress('unicorn.tar.gz', 'dist', { - plugins: [ - decompressTarbz() - ] - }).then(() => { - console.log('Files decompressed'); - }); + if (file_mimetype != null && file_mimetype != undefined) + { - } + try + { + + let compressedFiles:Array = await decompress(Buffer.from(FileInfo.data), + { plugins: [ decompressTar(), + decompressTargz(), + decompressTarbz2(), + // decompressTarxz(), + decompressUnzip(), + decompressGz(), + decompressBzip2() + ] }); + + //#region A single compressed file without a path/filename, e.g. within bz2 + + if (compressedFiles.length == 1 && compressedFiles[0].path == null) + { + expandedFiles.push({ name: FileInfo.name.substring(0, FileInfo.name.lastIndexOf('.')), + data: compressedFiles[0].data }); + continue; + } + + //#endregion + + //#region A chargepoint compressed archive file + + let CTRfile:any = null; + let dataFile = ""; + let singatureFile = ""; + + if (compressedFiles.length >= 2) + { + + for (let file of compressedFiles) + { + + if (file.type === "file" && file.path === "secrrct") + { + try + { + dataFile = new TextDecoder('utf-8').decode(file.data); + } + catch (Exception) + { + console.debug("Invalid chargepoint CTR file!") + } + } + + if (file.type === "file" && file.path === "secrrct.sign") + { + try + { + singatureFile = buf2hex(file.data); + } + catch (Exception) + { + console.debug("Invalid chargepoint CTR file!") + } + } + + } + + if (dataFile != null && dataFile.length > 0 && singatureFile != null && singatureFile != "") + { + CTRfile = JSON.parse(dataFile); + CTRfile.original = btoa(dataFile); // Save the original JSON with whitespaces for later signature verification! + CTRfile.signature = singatureFile; + expandedFiles.push({ name: FileInfo.name, + data: new TextEncoder().encode(JSON.stringify(CTRfile)) }); + continue; + } + + } + + //#endregion + + //#region Multiple files + + for (let compressedFile of compressedFiles) + { + if (compressedFile.type === "file") + { + expandedFiles.push({ name: compressedFile.path?.substring(compressedFile.path.lastIndexOf('/') + 1 + ?? FileInfo.name), + data: compressedFile.data }); + } + } + + //#endregion + + continue; + + } + catch (exception) + { + // Just forward the file as it is! + } + + } - Content = Content.trim(); + expandedFiles.push({ name: FileInfo.name, + data: FileInfo.data }); - // Catches EFBBBF (UTF-8 BOM) because the buffer-to-string - // conversion translates it to FEFF (UTF-16 BOM) - if (Content.charCodeAt(0) === 0xFEFF) - Content = Content.substr(1); + } //#endregion - //@ts-ignore - let result: IChargeTransparencyRecord|ISessionCryptoResult = null; + //#region Process JSON/XML/text files - //#region XML processing... + let processedFiles = new Array(); - if (Content.startsWith(" -1 + ? processedFile.name.substring(0, processedFile.name.indexOf('.')) + : processedFile.name; - // ALFEN processing - else if (Content.startsWith("AP;")) - result = await new Alfen().tryToParseALFENFormat(Content); + processedFile.result = { + "@id": keyId, + "@context": "https://open.charging.cloud/contexts/CTR+json", + publicKeys: [ + { + keyId: keyId, + value: textContent + } + ] + }; - //#region JSON processing + } - else - { - try + // JSON processing + else if (textContent?.startsWith("{") || textContent?.startsWith("[")) { + try + { - let JSONContent = JSON.parse(Content); + let JSONContent = JSON.parse(textContent); - switch (JSONContent["@context"]) - { + switch (JSONContent["@context"]) + { - case "https://open.charging.cloud/contexts/CTR+json": - result = JSONContent as IChargeTransparencyRecord; - break; + case "https://open.charging.cloud/contexts/CTR+json": + processedFile.result = JSONContent as IChargeTransparencyRecord; + break; - default: - // The current chargeIT mobility format does not provide any context or format identifiers - result = await new ChargeIT().tryToParseChargeITJSON(JSONContent); + default: + // The current chargeIT mobility format does not provide any context or format identifiers + processedFile.result = await new ChargeIT().tryToParseChargeITJSON(JSONContent); - // The current chargepoint format does not provide any context or format identifiers - if (isISessionCryptoResult(result)) - result = await new Chargepoint().tryToParseChargepointJSON(JSONContent); + // The current chargepoint format does not provide any context or format identifiers + if (isISessionCryptoResult(processedFile.result)) + processedFile.result = await new Chargepoint().tryToParseChargepointJSON(JSONContent); - break; + break; - } + } - } catch (exception) - { - return { - status: SessionVerificationResult.InvalidSessionFormat, - message: "Unknown or invalid JSON data format!", - exception: exception + } catch (exception) + { + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Unknown or invalid JSON data format!", + exception: exception + } } } + + processedFiles.push(processedFile); + } //#endregion - if (IsAChargeTransparencyRecord(result)) - return this.processChargeTransparencyRecord(result); + //#region If multiple CTR had been found => merge them into a single one + + if (processedFiles.length == 1 && IsAChargeTransparencyRecord(processedFiles[0].result)) + return this.processChargeTransparencyRecord(processedFiles[0].result); - return result = { + else if (processedFiles.length > 1) + { + let CTR = await this.mergeChargeTransparencyRecords(processedFiles.map(file => file.result)); + if (IsAChargeTransparencyRecord(CTR)) + return this.processChargeTransparencyRecord(CTR); + } + + //#endregion + + return { status: SessionVerificationResult.InvalidSessionFormat, message: "Unbekanntes Transparenzdatensatzformat!" } @@ -350,11 +512,38 @@ class Chargy { //#endregion + //region mergeChargeTransparencyRecord(CTRs) + + public async mergeChargeTransparencyRecords(CTRs: Array): Promise + { + + if (CTRs == null || CTRs.length == 0) + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Ungültiges Transparenzdatensatzformat!" + } + + return CTRs[0]; + + } + + //#endregion + //#region processChargeTransparencyRecord(CTR) public async processChargeTransparencyRecord(CTR: IChargeTransparencyRecord): Promise { + //#region Initial checks + + if (!IsAChargeTransparencyRecord(CTR)) + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Unbekanntes Transparenzdatensatzformat!" + } + + //#endregion + //#region Data this.chargingStationOperators = []; diff --git a/src/js/chargyApp.ts b/src/js/chargyApp.ts index 82eb47f..7b03d23 100644 --- a/src/js/chargyApp.ts +++ b/src/js/chargyApp.ts @@ -376,7 +376,10 @@ class ChargyApp { event.stopPropagation(); event.preventDefault(); (event.currentTarget as HTMLDivElement)!.classList.remove('over'); - this.readAndParseFile(event.dataTransfer!.files[0]); + + if (event.dataTransfer?.files != null) + this.readAndParseFiles(event.dataTransfer.files); + }, false); //#endregion @@ -513,11 +516,15 @@ class ChargyApp { this.fileInput.value = ''; this.fileInput.click(); } - //@ts-ignokjre - this.fileInput.onchange = (ev: Event) => { - var files = ev!.target!["files"]; + + this.fileInput.onchange = (ev: Event) => { + + //@ts-ignore + var files = ev?.target?.files; + if (files != null) - this.readAndParseFile(files[0]); + this.readAndParseFiles(files); + } //#endregion @@ -563,7 +570,7 @@ class ChargyApp { sendIssueButton.disabled = !privacyStatementAccepted.checked; } var sendIssueButton = document.getElementById('sendIssueButton'); - sendIssueButton.onclick = (ev: MouseEvent) => { // function (this: GlobalEventHandlers, ev: MouseEvent) { + sendIssueButton.onclick = (ev: MouseEvent) => { ev.preventDefault(); @@ -809,30 +816,21 @@ class ChargyApp { //#endregion - //#region Read and parse CTR file + //#region Read and parse CTR files - private readAndParseFile(file: File) { + private readAndParseFiles(files: FileList) { - if (!file) + if (!files || files.length == 0) return; - var reader = new FileReader(); + let fs = require('original-fs'); + let fileInfos = new Array(); - reader.onload = (event) => { - try - { - this.detectAndConvertContentFormat((event.target as any).result); - } - catch (exception) { - this.doGlobalError("Fehlerhafter Transparenzdatensatz!", exception); - } - } - - reader.onerror = (event) => { - this.doGlobalError("Fehlerhafter Transparenzdatensatz!", event); - } + for (let i = 0; i < files.length; i++) + //@ts-ignore - File.path seems to be missing within the declaration files! + fileInfos.push({ name: files[i].name, data: fs.readFileSync(files[i].path) }); - reader.readAsText(file, 'UTF-8'); + this.detectAndConvertContentFormat(fileInfos); } @@ -845,8 +843,8 @@ class ChargyApp { { try { - let content = require('original-fs').readFileSync(filename.replace("file://", ""), 'utf-8'); - this.detectAndConvertContentFormat(JSON.parse(content)); + this.detectAndConvertContentFormat(require('original-fs'). + readFileSync(filename.replace("file://", ""))); } catch (exception) { this.doGlobalError("Fehlerhafter Transparenzdatensatz!", exception); @@ -857,14 +855,24 @@ class ChargyApp { //#endregion - //#region detectAndConvertContentFormat(Content) + //#region detectAndConvertContentFormat(FileInfos) - private async detectAndConvertContentFormat(Content: string) { + private async detectAndConvertContentFormat(FileInfos: Array|IFileInfo|string) { this.inputInfosDiv.style.display = 'none'; this.errorTextDiv.style.display = 'none'; - var result = await this.chargy.detectAndConvertContentFormat(Content); + //@ts-ignore + let result:IChargeTransparencyRecord|ISessionCryptoResult = null; + + if (typeof FileInfos === 'string') + result = await this.chargy.detectAndConvertContentFormat([ { name: "clipboard", data: new TextEncoder().encode(FileInfos) } ]); + + else if (isIFileInfo(FileInfos)) + result = await this.chargy.detectAndConvertContentFormat([ FileInfos ]); + + else + result = await this.chargy.detectAndConvertContentFormat(FileInfos); if (IsAChargeTransparencyRecord(result)) await this.showChargeTransparencyRecord(result); diff --git a/src/js/chargyInterfaces.ts b/src/js/chargyInterfaces.ts index f0f2bc9..90d7977 100644 --- a/src/js/chargyInterfaces.ts +++ b/src/js/chargyInterfaces.ts @@ -17,10 +17,13 @@ /// -function IsAChargeTransparencyRecord(thing: IChargeTransparencyRecord|ISessionCryptoResult): thing is IChargeTransparencyRecord +function IsAChargeTransparencyRecord(data: IChargeTransparencyRecord|ISessionCryptoResult|undefined): data is IChargeTransparencyRecord { - let ctr = thing as IChargeTransparencyRecord; + if (data == null || data == undefined) + return false; + + let ctr = data as IChargeTransparencyRecord; return ctr.begin !== undefined && ctr.end !== undefined && @@ -28,9 +31,9 @@ function IsAChargeTransparencyRecord(thing: IChargeTransparencyRecord|ISessionCr } -function IsASessionCryptoResult(thing: IChargeTransparencyRecord|ISessionCryptoResult): thing is ISessionCryptoResult +function IsASessionCryptoResult(data: IChargeTransparencyRecord|ISessionCryptoResult): data is ISessionCryptoResult { - return (thing as ISessionCryptoResult).status !== undefined; + return (data as ISessionCryptoResult).status !== undefined; } interface GetChargingPoolFunc { @@ -61,16 +64,17 @@ interface IChargeTransparencyRecord { "@id": string; "@context": string; - begin: string; - end: string; - description: {}; - contract: IContract; - chargingStationOperators: Array; - chargingPools: Array; - chargingStations: Array; - chargingSessions: Array; - eMobilityProviders: Array; - mediationServices: Array; + begin?: string; + end?: string; + description?: {}; + contract?: IContract; + chargingStationOperators?: Array; + chargingPools?: Array; + chargingStations?: Array; + publicKeys?: Array; + chargingSessions?: Array; + eMobilityProviders?: Array; + mediationServices?: Array; verificatinResult?: ISessionCryptoResult; } @@ -78,7 +82,13 @@ interface IContract { "@id": string; username: string; - email: string + email: string; +} + +interface IPublicKeyLookup +{ + keyId: string; + value: string; } interface IChargingStationOperator @@ -92,6 +102,7 @@ interface IChargingStationOperator chargingStations: Array; EVSEs: Array; tariffs: Array; + publicKeys?: Array; } interface IChargingPool @@ -104,6 +115,7 @@ interface IChargingPool chargingStationOperator: IChargingStationOperator; chargingStations: Array; tariffs: Array; + publicKeys?: Array; } interface IChargingStation @@ -121,6 +133,7 @@ interface IChargingStation EVSEIds: Array; meters: Array; tariffs: Array; + publicKeys?: Array; } interface IEVSE @@ -132,6 +145,7 @@ interface IEVSE chargingStationId: string; meters: Array; tariffs: Array; + publicKeys?: Array; } interface IMeter @@ -146,7 +160,7 @@ interface IMeter chargingStationId: string; EVSE: IEVSE; EVSEId: string; - publicKeys: Array; + publicKeys?: Array; } interface IEMobilityProvider @@ -155,6 +169,7 @@ interface IEMobilityProvider "@context": string; description: {}; tariffs: Array; + publicKeys?: Array; } interface ITariff @@ -169,6 +184,7 @@ interface IMediationService "@id": string; "@context": string; description: {}; + publicKeys?: Array; } interface IChargingSession @@ -392,4 +408,25 @@ interface IVersionSignature { interface IResult { status: SessionVerificationResult, message: string +} + +interface TarInfo { + data: Buffer, + mode: number, + mtime: string, + path: string + type: string +} + +interface IFileInfo { + name: string, + data: ArrayBuffer +} + +function isIFileInfo(obj: any): obj is IFileInfo { + return obj.status !== undefined && obj.name && typeof obj.name === 'string' && obj.data && obj.data instanceof ArrayBuffer; +} + +interface ICTRInfo extends IFileInfo { + result: IChargeTransparencyRecord|ISessionCryptoResult } \ No newline at end of file From 0cc73d587ca728d7ff4435a583e6ba7d8d7c4141 Mon Sep 17 00:00:00 2001 From: Achim 'ahzf' Friedland Date: Thu, 14 Nov 2019 04:47:02 +0100 Subject: [PATCH 023/110] Add more compressed chargeIT test files --- .../chargeIT/chargeIT-Testdatensatz-01+02.tar | Bin 0 -> 13312 bytes .../chargeIT-Testdatensatz-01+02.tar.bz2 | Bin 0 -> 2993 bytes .../chargeIT/chargeIT-Testdatensatz-01+02.zip | Bin 0 -> 3578 bytes .../chargeIT-Testdatensatz-02.chargy.bz2 | Bin 0 -> 2169 bytes .../chargeIT-Testdatensatz-02.chargy.gz | Bin 0 -> 1975 bytes .../chargeIT-Testdatensatz-02.chargy.xz | Bin 0 -> 1952 bytes .../chargeIT/chargeIT-Testdatensatz-02.tar | Bin 0 -> 7680 bytes .../chargeIT/chargeIT-Testdatensatz-02.tar.bz2 | Bin 0 -> 2247 bytes .../chargeIT/chargeIT-Testdatensatz-02.tar.gz | Bin 0 -> 2051 bytes .../chargeIT/chargeIT-Testdatensatz-02.zip | Bin 0 -> 2122 bytes ...b29_1_121708795_payload.FLAT_SESSION.tar.bz2 | Bin 0 -> 799 bytes ...00027b29_1_121708845_payload.Per_Min.tar.bz2 | Bin 0 -> 807 bytes ...0027b29_1_121709375_payload._Per_KWh.tar.bz2 | Bin 0 -> 805 bytes ...9_1_121709405_payload_Min_Variation_.tar.bz2 | Bin 0 -> 947 bytes ...0000027b29_1_121709415_payload._TOU_.tar.bz2 | Bin 0 -> 803 bytes ...1709465_payload_Parking_Tap_ToCharge.tar.bz2 | Bin 0 -> 807 bytes ...0024b1000002e300_2_119693895_payload.tar.bz2 | Bin 0 -> 995 bytes 17 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 documentation/chargeIT/chargeIT-Testdatensatz-01+02.tar create mode 100644 documentation/chargeIT/chargeIT-Testdatensatz-01+02.tar.bz2 create mode 100644 documentation/chargeIT/chargeIT-Testdatensatz-01+02.zip create mode 100644 documentation/chargeIT/chargeIT-Testdatensatz-02.chargy.bz2 create mode 100644 documentation/chargeIT/chargeIT-Testdatensatz-02.chargy.gz create mode 100644 documentation/chargeIT/chargeIT-Testdatensatz-02.chargy.xz create mode 100644 documentation/chargeIT/chargeIT-Testdatensatz-02.tar create mode 100644 documentation/chargeIT/chargeIT-Testdatensatz-02.tar.bz2 create mode 100644 documentation/chargeIT/chargeIT-Testdatensatz-02.tar.gz create mode 100644 documentation/chargeIT/chargeIT-Testdatensatz-02.zip create mode 100644 documentation/chargepoint/Testdata/0024b10000027b29_1_121708795_payload.FLAT_SESSION.tar.bz2 create mode 100644 documentation/chargepoint/Testdata/0024b10000027b29_1_121708845_payload.Per_Min.tar.bz2 create mode 100644 documentation/chargepoint/Testdata/0024b10000027b29_1_121709375_payload._Per_KWh.tar.bz2 create mode 100644 documentation/chargepoint/Testdata/0024b10000027b29_1_121709405_payload_Min_Variation_.tar.bz2 create mode 100644 documentation/chargepoint/Testdata/0024b10000027b29_1_121709415_payload._TOU_.tar.bz2 create mode 100644 documentation/chargepoint/Testdata/0024b10000027b29_1_121709465_payload_Parking_Tap_ToCharge.tar.bz2 create mode 100644 documentation/chargepoint/Testdata/0024b1000002e300_2_119693895_payload.tar.bz2 diff --git a/documentation/chargeIT/chargeIT-Testdatensatz-01+02.tar b/documentation/chargeIT/chargeIT-Testdatensatz-01+02.tar new file mode 100644 index 0000000000000000000000000000000000000000..8d20b2cb20a0d08f4199121f7ab274974e0985e2 GIT binary patch literal 13312 zcmeHNTaVi|7S5{+^gn3zn8qGnB#N4st!>%KV3W-v+#h1CXK{j2C5ZD>NIyH@7<-gF!PIq`gFOeKCkRuI(I*!A413?X#I~%$0$93}@c)zG*KfbE zEPJyGBXO1`xqWJ>H}LLK8A0g^uil4~^!&l0h)b#C_~a>3)S5-ROfNGLzY>)w-i52JkgWcs zSF0rgN37B{m`S+az#w*A2XpRVzvXo;r}yQkM3bb&`Z_GcJ5iKco;D`5JqIkk*)CUU z^fz%Mne}I5&U|m~PAMjA#@U#9#0Lvufy+=Zy>fetCrbhXCEi$Rv&GV~e3#G>|#A=mW*Lksu|6*Il zKpHyB&hly^lDv>wT|YML%ZC^bk+Z<;)bUOcKC~}P9VeiI?Mw@%5;{b5h{*!eQ`b4g zuC=_xQlIfKb=Udzr1_P{HiY0m={31+=S5 zdYgj7Lj-diM*?(|f-=R-5iVt98F8_6n26(q&@hgco@6 zgcIh(#PwY)e8-DC;qW9xOXQ&?CxS$waB%I(G^bKTgMoEVJ5-SyV!E}?m+304ZVnu< z>uzdkJX&Eb2>JDBg_iwjg*#T*dakZBvUSu~Sq21N?6^+gaGC3JIzt}oTAy9rY*e-) zUi@gC{lI6|?A41N!8**gNf^m6EZw**$IZU2r?jgggiJk>*_qC7bUK0wb{q$v4zbT% z2%M1UP!5R-XPlmPv#Kc1V2MbEs3yGutvBqwnV$t0i}CY|v!KUa6BA`>xav=q)A#Zt zV5rTHlwqyp%-2a$s??96o?8d^9hQ0488&CPdZF^bPQ6SFcuCcTaO6T7H6FV@@sV># zl55xzge~K>mZYvya93J2O{_A*{;69|{?{TgG0SF*Fx0!YZI-G$`-kyjaq;5y+g`}C zOSllJl*2Ze2l=Vx7PY#bWtF%T1#|Y6on;Xu;8NBUnY-%fsg_)rNrJAT>D!T&A;K6w z=kwmmS-4haGW+}N&GUa=EM70hFArTFlohG8fpB#o>y`z>FDgyx>|AT9v@PZ$m-p3g zm0wQs{5=fXz!__{+|fR$0jjOcOKij&n$D?p1pY^!svNMhyItl>&w=ax^E&QMT@7lfocrf-+ypA_M&p&(K2I!b9XA-M*Yksqj=M&e8ZFh1 zn|s|@1q%GNJ8l-t5e__t=yc-vlZnRwjF|Ho^Cr{-@Doqw@TWJ0kAQOU>69Tf_8kh4 z&UA(V{{b9_1&V;uN1OlLHl<_r;8AXma^*jL!p0I)KZzV`_vex<>yfgOu7 zD$-30PY>ifx#)Pc64uKw1`MgV{O#Y_r2yj?$dqPa_sbrbQXhS%OpvsLW5p1RY)es? z6jdDw7+!~|EQsvRW;GOg4%s5)r~r=w!j=~bU6pcgb~i?7@S5rQYqRRB8p1h?)wCMM zwx20L`{g^xnl1Y~$A8KRv47TVACQa@joGL{hOFo72ZO37%=_4Tz@8fX9;_#ln4)^y1b5^Ris{l94)X!2Upi5Un9uPt ziAA&|0AvHC$S7GN9CK&MLU8g4qanu5((@RJs1pP7NCe~1!0_Fr7ovoF#B+fvNd%2* z?gwqj&}DyMzZW;U!X1r9hW4&g9XZxOmxuBu{|b*%4p0w>JaFhw&t$2mPQNFz2AWmF zcZ%$5XbUJ#Wxu2CjnwB^G(ZAwy`>Py8&AWBiUin_oLjQHe@@1wp+S|kLgvBmQ@;N z)+8^YE9h7~vvgxPy4qGBt@5}3#L8{#9iT&X??c>b&#^e^ta;Ksin3q`G_}9#D7ta! z`wc(C@PV4NTZ1bvI@s@jDm~cme(KlYJD@ObdY|x8>jl_XxAUop@929fnoSNE!>Zrg z)Qo}qm5@GIUZ*2k+nxHdXYbBu9f34qW?v%E0yT@4dGuaXdfF!)NkEBJh1^}MS?n0n zDY*yl0P#C-@XLA+^ZMX{whfPXMr;7B`y;HIZS^_B?x{ywmp{ zbG{w#i<~dfD^}7v7FR&dO*i;h4_GhI5rkBLucPa0SnFcfbz-{T=QYG_gSU=!a^O&d zSI0pZtlfd4>vnjLwss{YJhBmGdb&q@xterfgVOezxb=H|K|8Hm)4A=@D3yL^e*d7m zwKYNa0DGMw)txn5+#d9S>Ts$g2byf@i#J;}^KI%PxoOpUFL7>M6p%I9;-gYSLZ>pG zW4~9>QhrqGFZ2t7TB&uq+T`a=p04v(`Kcqm-DFkpQ!S`i+h}Eys(V8OkS9D8BRJQa z-V#t-2;n{$!rdUkK&48$COV!R+2OXjg5Q~ZR8>4AoZT${7X08A00D+Nozfl*0zd7M zFvxd^z<;_KuXIML0+F3Ac{6nme-)Nj((#-p!| zRQ(!EzK^!W2W7qTH#FVaw&Sk>y^tYI2Ll7I%id|LD^l)FdZdMWOS1TIJ-J`<)zKAj zH;3AZI?1#FV3EAryS+#$k%REN8R&LC>$Oz)I@mLnlX`tt_2TfA>f779(_1g~=&jyz zt=%|W->XSebRh2B>Af|!PTku`-gKkk!~->)vg%vXOH4I0IW%ClBqXHeugZI`cc)tMWkmILR&UK!KjM zJ1|FT(j;a&MoLci7q0G~+$LPrMNeQ3{PN4USE1tR%1!tDmP2Q)837`g%C`BUKE`nKLkd#DW1QHS?Bm*=E0*a#;s$# zkYf}SiwFqFoB)7A$plTaZ;*@@DI*Z$PbJtWi7KjCfKY`VqQc@aRaPp=FM8t(FpLz1 z!sS{^ETa6ihABkBkYW@W;!6t=kVPn@XL9o7UYOpvE>W7xDzU#dkOY%4BswHy1YsgD z1Vo5Pf>6;$h1||$kQM|oi40i>H)7_V?4lhbVbB{H_fym0cUEm1izV5ugjj|WY;HM+ zZE(pZ@r}}z0_u6z*y;6i?0oO}{+-o4`@1vm*X(^y$i3vG8wiXKfDC0yfme$aAka3_ z)F*%(IU=kb6q#7c7_C!!5(ELe<%h64CsCs7GK+WLk5#ZsE13hbMK8Ea>J+JjQ2HU* z9QUwWdq-2N&$D}?j?UiJt-5$Y_|%0e6sP1+{HhHZzoW78KGK)HsrK2%KG)pB6QZnH&UkZmla-x-*2p+=+ph6M3&T7;3g1#zV$1EJ#xWQ^a9ik)5uW^AfCGFG5sU zsR~JYFfwFw2OUMyMTsW1B7;jiF=Q4KK`mC=6BUY#CvnK66LE0E4#Si#X@W{9s**~O zO$&m>0D-p07-I6)DiK@D$*?smc~Ru4Axer2#Gp`2hD;oTisi{eLov-dy3o=Fi`F#_ zI)O>x*SnCGB-ju{IDDfAzm^7_->eNJ2Sn!i-*juo-g3^!%#qd1z^W7Xs!!ITW) z<>mHBfSGW(yhlfQ*LA7eOJ7CPsr7r_OpV zbp7pS&M}eWB>LK)i(gbe(-W-ikKs1TPNI(1TTG8L6~;1kD9$Y$TaBHD1}3ui+p6ay z_`8hV(X8122RP+BQu8UwQ8ZI&bE4_Mql_*)5phxbBK_&O`2R&Rt16ahr)8;bqmCYh zMblWsw7PEj{MA*;O(i!@a??Y=yB12>;@rl0jZ-!8z@u}9k!_A6DB~KPP~!8pZoO#U zT1|@5DA~bje8NQ^o;%$PSewk$@0u=b{cKmBCtaw_^`3JVzZt6fam9vDIOwmjhay3x znR-b@B^Uw$lLO}tI5doACoFdyy#~#t@sX>|6+P#B!Z=4)7}F^1jbhI3MNYNy_DOpu z90lpBnAcgfbs5G*<=dkS^2(_)G@DK_V`;tKX6~AHMy=7x`?zYobmJCe;WEL`z-E@-`~=ULgL zV-{b&FE8piP9c%ZgqX}7`Pt8q|cjJ!$Wbr z;W^Fj{>MguKczF#t%6&vHKJ5Diy$}zVNrB$sYTymYorcQ>Ut-1?qs<;*}10XQ^snq!6&MGr!Lm@s?F^k(W7$tQ`X|<$xbh1 zeAh8>K7-rI=54;I$-ZeXn$4LnoZYjV>E(a=eJ3RK{@)pa$-%VnZ1x>%r=D73=;?DWUWKeA+VGi`Q_6Zy(#iD_%2+P(5;?)iMp-0KV7PnJDr zx<|P6AKfZ!@tsrhwEa%moZ@rg^7)=C<0&+qv-wX6*7!Ro&sB2e#!(|^G%`-Zm%ii} zvgBMq=Z6B%vUPDI#vShtx-A`NWPMqfMWf{0@Si(#?%sDEuSWCce$vM8YSLtlO-b^q zRH|TOA^mt7E_{E!N{KB-(l3$C?~Vnrv8vyu;@YND1eYBgwVv-W`Hgx;1|OCv@4&2b zJGOn1`V7otdyB{1Pr4fI91lcmx-XAOfyO)`aI_3uz$%lEWDlq9?Q}@yPzl5pv z)Lkjzw7Y%rw4}J%Oy*^!$jPnyp@P2uLEQQyDN>Z)v|6gQmoJWx?mQ#5JUsE7^gj`6)h%V6Ebi!beR}0a3?8hlE>cqks`>Ad)c3TQJPa@N!_P;r z*Bf#_2e9rljQnFm&R0>}I}?@nuf5J)Csrq1p82WhJ1`|rHf|;nXN-Qc(>tFVkj1S0 zM^SY3XXL!1%RH56=_ZRgDVodI%gK^&VJ_!ee3E_=|Iy#yGFHl>%RhSE7qM}W`dzI@ z?7XQd`tmdDq}EUBm{jzhG478FT*KOiKLH; zQmGtF`=oPY5%?Tw@i#bBxO1u0%Xvzb3ZYbeI5(U8*LKblRHSuNL^$M9*Tr2(v>b$v-n9={yW3aTgzDUD=`8 zFi(a$NM*RSnGF>dK8r<*yo-t|COJ#jq`~iflFb-DAxoMqlwFGmzEY=uZK3z-n}(^m ztT9sNl96lKo|yI3>TK&rvv=k*DepA!cuekMpL2nNIbkXoP_avw)FT?BF?<&lM6b_$l-@*+f0 zkwrm=6j_2mbt!wfX&vnhButd4m2-5t95>tdQXCAlRn#=KjgN`4=c0U8s`eWW_RzMIp@s1XXcsn&ok$T(4(ed0{{SYfJqu#qhPf; zMgT1UFmo9I5d7oS;UU_`*+~Z}g>>@ub42?&dHSOLf~Bs>O8?^rLqS=TkE^p`&9~Ji zRO4FkU!9LL%${AfWM@y-ftPm3i|df%&WYKzEo-8n*J5)B6QAM02S>wj=hklxs@%^} zg@!{F{p&k^6M7ZyX!41FS@Y|vfH4~z@-WsE1B?{Hd4l8kW9M-|n7has!7R}~L!rn6 ztmWF=1Gzpu?WI4OEg?J936jwYQem8(6u26LK_IimN!j*|#lKA|aLRIqGEwTTA@Y?+ zBRLk!6KKByumCX*YNth42qJZIv~)Cevpwr~1nWEJtTf%{sh{}r!nl>$O+2HB^3!KY zu^*yoVp0&jB$<1pnrMZwksnBGlKpHj?)i&XL_a!IiL)ZL=H6EJXTwrqBcChw9G4<7 z&_-<<^Y};naAq`AB=M?X7JU>I`>#BN5HR7Lmjav$A?QG2;9@}v^TIhU0O_xkgat)j zTye&_ijNSR8s|G)bJAu`xyK;UJ41W5=8~lxrD33lNN4lF!T@dquk-zI>xV z!YEcjD@`!2!H`ueiI2l4gZ{1@6^GLSXE1p~kLyB#XgiE%88Ci!NRD^0l*ue2AFLg@ zMpOs>wl>Y!Uv(g+eI43aoh^N27TEe}y@z-BDvZt`Y?$Sxi7f5J=f|$(C1Q_Egt+Ks z!OM{=vHD!O!Xd-8HrYi+2dBKZ_Az!jRecOroX28ZOHJ-W6oF3g?k7<51CNCE6|skd zF&=A}14lx2$mud$(SRnAjo7@zZ(6B?%Gxot z(0&sKhqP(CekFx?Z+yWRH0_1tfb6J64xKL4P{}UB$L$S3zwC-$QW0Foc-SR6+rCds z!USD1r~nldOrD-c^28C+-CwQF)Y%SoO%%S$9?~9A7Vm$35|SQ;vIt6#YI_;g)teCg zeS+l2^~ya`j@yL(AQ?*40cM`v+$-BMA0(pQd}ZKz{`z7d7@%ie>6_c+(C|pTm{i(E z@z;D_Wy$b<`0L;Y7wt=0X(sZyg5B8$7PqBn%|#la;mE~2{2ccQH(px$z45Z_$mU$`@P76hQ{OSlONwf>rNNd9OZD z;MQZGS00p&VQ-va^b4;Aw7LHSG`FEq^z*U_#rXs!Dm6zGig|ngrmHRHHW5+qdkOvyr(Wn%c)o^ zLK3~{O#)Y^L{=;Pj0C4x(9KUX&=b5a9T3`oBaU?i)fW2`9qjtRDw?rUn1gFQEcDV_ zMrv(GV*1-puzQUXb5GiIPmekc&XC`G6gSUkuH5-f(2=MD9m=qIijSO|HDDmrAli$p zzmP|*^9S5)1F;M*>F&B;NuU(dZCr(pP5E^KRWzSUxogl6Kr``+LeE3lB}6?cS@A-N zQ2_xm$k8hA=C8{apjR z=L3xtzD|su`5(MXG_H@kn)Wt>yNb&_Bsc$MyC%DWD|BWo zi#x6H?_CS~<3Z*-Svs$4t!zqcoQ{_Fdi~yrhMgjO%|J^w2!dqG8mnxzW6>u@dqF-Z zvSF9fYP0>#XGz8O#g~_F@f^Nl$h_cY?pfT#@Uv9%xnPBF&*@nC#D`{7BkBPLh&1XQ zY-)JhT_ zFrDVsJ+FtRL!M@nmezHK7L?Y0+wO1)iTB*i+%n9DygUNM#sQVdteNA6{gQnFsaKiS z+?EpGFYm8^d7t`IhwzDiQK#28&WXSK>29Yrepu=-gW*Pf&C8pZ-?~G3b+a&=(zqj4 z<~U66*$2zh#)L(l@CPS;n8rQG$sboBhy$9jiF5yiKMP6?UJ^pJ94q`P3~nyl^H6*-S*wPg zJRCfpsVd*jmLCCsCX>LZS~+Vi$de-m={-lbd<1KJqz0YHT_J$IG!9^C8krU+7!15a zqZy6t6ycS#HQpBOO<@^sWW$+otR*utfibw9ux&b8twmG29_4Q3<-9GqIJ5;@HNx&z z0bR)im$U~ZM6vAYk9Q>JqY_bqMfOMWX=Bck2MAnUqgKORgcntQz*>GlT+tY|Gz2HS z?)H6lnTNCc`+5`cj#N;`tVVBs63kF_{0Ftlh6g{V(?(%V`cjAaQa8I)DJpwAKTV#pTk@v2gvJbY{FKAbvDn$j~B{kD_b?xjn`9 zMj;N4Dhp^zFNbXGnY9Av_1(-WZl|*sW=>m-*9*l|k1kMc8_~A#73b>`B)%E6rmU)d z*g9aov6ieC(JstjQ&xjM*{+D#M3zP~xqX1ZU-@NiuCjJ$n{d*rl9}HD;Y%VJVapD&^%~e&VWux>b75=UMOoe`pHz_j zwVuWF=vsI!cD%*^DK91xDNKl$W zFPiyB6A?NoE^ptf(90MGZ^WufM#{|7@b-+Ro7{U*(j0WxUth47!`*dzNS`aL z-0f&R)Ok#m`u3ra%U+SdK@JnJ#>}S2m{F=S!FKUVRMRe#LGBn>sL?eAu2!V+>fLO1fNVwD|8afn*sQs~}4s!3DeiRh`#_Cm5)0+ksKP zcv+%E=4CILgu}8EZ&@D$6B_tgA6%AKoi{IGL!OSr>y`^J zYG2+$cnTeCk>|p~-@n{7`X+#HP*;*3)X*5s^5$X*T7!MtS#HM31;{Ep2XzxH7tfed z(Fjaf)!v;MsGn4U`MOxT_3Y++htQM41kvQTrZ>;Y>eZ$;KyEW@2bJ)0w2EaeKgSc8 z5!UlpnQvk0C~>kOaPILJ0X18a^^1CCUiqJ|r&uCfAzi+W8{RSURr|q?RbM`P&4qe< z#e0tfipKj@;{bE0!YBBdp7wRy*f<*bhe8uL993eGxOuin(N?^{j)G zzW$m_1z)}PCw@F8TeqlWXs=(fv=7fP@dhevSdL6xs+Wv`q`(P&`e>m~VUB*aCHpYF z@qC)Rd+lLElG>Kh?HOH6ZjE;ttq3j%kTn;<<%h}1YThCYZ*^EMm&@SO?WKeQ{ia?S zQwx+1%%Ho86LGa_LR;XvCTh~8IXT#~aE~*#QPbPrCGtcsyqj@ClFKTap#o=zyII*1ONa82moLSd=q@& zhN^(6A=1E7Kma=lBvVt`jHvZI#F?O>nj_kpO)vle27myRf?{ORp-qubM9)$IriMTP zpaG_U2LJ#700093000002{jU)sRPmg(V){n01W^D0MkG*zyJUM006)M00002NP#o} zguyj3VMdVJnWk!Du>he8Jtc+2VydiFl3u%_7l^?~TrO3lvd`ns zm_iX!NRuO}Yt*{H9Y_7aGFp<9#p|R8rc+q(;*j9e-iw)QtMvG)3+7$+PkbrND0raL`_g1U}#H>%mzqIRTuXnxL!{K*-u zi|}65vl!cajnaW6vlz`5mqeZ+P~t78)pa<$#5mvrH3knEORilJJidh0ffd*;;0fI3MrL}vtDgOX`kdKdA$E+Sr7 zuE3HAo=D-LBEsUv;aFey&L=ZhVg~uJ)MxFREn=`~4A4%Wo@t$_A%M6cbycIBQbjr# z7)4E2dT#@dHGu~3N%kvS<9!zAVxaV+6o%G{Op z&N!!@bE1lC49pYhOI8z_xu>Orp5R#Dy7b*hD5o zWXY*{%%Q_lw;W3j;`P;x!p8$$JIk-^yIqu5Ug#6({)tSm#8ReV~|YH%$Zv$ zYhG7slB-~>n6V;6JjE<|IdNs{Rf4jk3|kDy(zAF?X0WhruZg0K<6ERyGg5C_lS-KV z+tJt;!7;tJ>VU|%7}sO%v0|8jTri-U+Z`=-FS}yHW)hVtjTR)isNpj{lqoH02}!U_ zRAMQ1KBAD^NEAn=L`XEMr5PqA^KnN*8)`Qbg97p6tvo~NS~dhp6Qs6k!n9n7;gf$m zp6Jr?mCHrA#Yo9b^WN@-13m-qlHfY2L~+oO63v@wa~e4<74XBi8e2M>*By(30R&G# zyVglE!tr9s3Shvzprk$NE`m7E4F*tcPV;O&vg4b=%-!ecwO z#yKF%4DM#svCM*@6Pupgo3RyGoa;JmA4iOCqQ)h4?4~bTy%c;VFlot(yau#6V2*+h zEfthBG&y>V@*HEyNbUs}4J_hf5=oWCx9tut!=nd@(CUUQiM}-JzfLTOjbTHyZyF$I zZk)=n*?c`FZ?w97okPs!3A{7ynqSPR8b($xXzAVm7=gH%&Jw9VpRJ|sP{oV`(CqAk7n=}v*UP}OmnvKrkOMiUNjSj5KGVD|J2{ce!!SB}h>PIED>y)J z5T1h7839F!_^-ognAV=V>CLJtt;7P}LyqL9@BPS#Nr^B&or#ImctBigNeG}(v^GEt zZ-2#vu_;lY!B=wwyug9cce^!WRLVYczicdI?aKCxz%cEQ@{(I;uvZt@qH`c47StF@ z)p=|_YQ?55hwYUbzeL@+-Q3FdaGDO1hkY2{r z6RT!D+08QRKwJg z$F9>r@C*|FU~&YKZ1EQ70&anbCP4rJLda#E7#usY9jf>nK7$)S#<&~83+)0DQRFyN zcKYn>zQ1t(+~isuP8Qk(Gp1vS3D$KTFQ(Ywj5A4fol3w+F6n|yuG9=cmX_*GS#fR4 za$hXw^K7ruS+Mo;O`L9KL6RN9c}rHz?e)FOFN!Q}*nI^w6)!>9m?C|O$QrQ)LJMp> zX-HHW9ur`?V5B7oRT1RzzKpYKrOJ#7R`HlgqO@CHs9t6H=JUsNqb7j;P;*rZ zEWPOxF|lN($qZs39VAq^^6kD}@ZNIeJYSpFpRb%2b0}1vdb=9ig4E87lj{ETm(xzlEXa0~D-G#u<&U%G_3PKOlk`cp$sXiM$8(Bh9>t0B!d;xsE%%lSIk&Q( zJ9+#{%}cf0Ctj(F`92PcdB^^|TK&0>lU4sNQqeXJ^|mu#{;F1Nc% znL-77Y>*rSPlJxKeCL5vs?gl)p|8B;Q2QR~gktI&O6La0#Mc84aYJH13RU0}!WE%9 zr^H7%l)BG7iS>w64`baIf|G#iVHhZ)xMY+X%oiStq#%L;RTL>2^fHThlX~SLSH1c* z_@#Qgs`G6&o7J>GVb%A{`r59m@R>Bw56|k~4_CA^T}Bvx`3o-dWE7!L5{!gF2qQ!x z0AenJ09sRol!_pF0Yd~uhE&2M95Y{0@FvHS5ze_3f>IXgkqiwFd4lnP@CXG)kEXp6@e?VObQhP+&cz2&mK7jOtrqX_?e1anDYvJ4G8yCgl>$=@TEqKA(LC2wxCr&=o;sZSFZ5|h8?4_EO z<-u0v#T6}t(n*V8dnn&&#ph39-8PO47*YMS5hv?8RP)iA^TCv(-r6U6-&EU9dC8TC zK)vX?K|1kKobO(Hxq1k;HBE9tXJ|&)j38-rR2!Au$^viHM(cJ|r>ib!h%!v^l@6S4 z0F2R$Ax>G79ql?^7(&(*qcw^$SE_cpm8%%+^Hsh9;7n^(tU{F)rI*-Q)3+gqvC-oK z@J|K39jBp6wkqCDzLMxZyzll7Iq8v0gTNvSUaGQT`|zxT?o_FU4Qsp@GN5#r?&uQ1 zM^YCFKI#sze`k3`=ia{YE%?E`Ti=9V?Y7feRF%D<8W?uqfI7F-jVIdbk#x1M)`KJn zzlkKCwUu>7q%omAeyHkY)rfw6oN-f#*xTEc#`nKk0&t+9oxk0esBLrK-%oz3_kOoQ ze%m4q*Oc6V>BXj)a947Z3SuzExx+YeT<@24XXUL~CdXogzBLWL?d|`T~=$Xd!9yrXTj24FR%MUdB-jEv=4Ur}ejaO%a8t!)XLY9!L!eF$}q` z80Ewdr1EvH!Z0G#3j<%k0fqP+5rre*F%VLLCz+2uUHSozxE>N_Fsuw+1VZUD@{o@N z@+DCu@RW}GFb$*2kk;QFoc|~F|D^tBk{agJ{-yhEf0`#ezCN+Sz%rhye*KEzH|_{p zp(i%f;R@kr?ht-_iO`Hns~-$U6Yo%NA@=X;+<<|zpYl)MADp;AI4;aVLD86S84-Bt zC*JYqyMi-zF*;{>#kN}H{tc61PnN37+wS1OA%CTgCXugGJOAoH zu~S|F8dY6mJb|lWJX)O|7JnyCes1`xbET8f-PO2v+QC#K_L9iTvX?b;OTd408&dB*0xtzOC0b&EmQrv5HSAi@))2QW zhZvGFwscHkA<2MbbhN1TCri_z1fEF1fXysNT86-u!wqY>L=0QDX;2DX8MbNSQv2wh zw3UJwQ+w)WlHgl$&Qj z4Ifc&7FR@NC%P`r4CO+F|Az_|i^CT`hz#OgNvSnOvh~_UN9qo(wS%>mZVCN@Je(81 z3^DizF3HFF)aiXCrbu2xa7}@swM|#7?i2Rl0}1r8W#-B{@b%3^pZM5aIInwdbB}sU z5=h(CmCU}dX-2PqCRKd{ij*)fOlF)OVTOMao4M&ZR{rFCVg=~W_gIPzzsWSSdMSnC zuqd{cv5&qX0gZeeQ$v>^7a-7Lj8w1jWqwm&2P0N{Pc-cOpL9Rc#}!@GRqNm$>|G8g zYpd|nCJhfVFY#y-_eNzS{w+u23t0x0BGhbQ%1Q6uz4pu)#btjytJ3g~3MXunne>LB z8>47aY~A-XT0XI8WEY;m0MT==%)Ly)<9WrDKPZE`EU3{#-T?ncDgTrFNu6#8+ul{B zRAn)@ZuaLx|KB+GO8n@_%sr3ob(O6mE*!&;ll zwxbO&hnGha{AdJaVet*NXG{1xFm@=6<8?8yp=5fa0#pB| zUTP3SN`L4t4fJlwNcDoQA@<=ON3+#hgW1kjRqTV$7_pn0ir~==0*_j`EbzX^0XpG`%^-Jj-rv0oLF@=h~fynTQ zPN4K?L&(5#C`mg_0WRoL(PvtJC12QL`|cRJBlJ3#zBas|!u6MtrDsbd zEm~xzbm1%Bl2I;ux&4W=gR`yZtu7Zqx5lHxaBkQ44J1Gm3JKOi8{^E#niM@q05s{T zq(;N~O(KB}MvQY8K_~rXezrA`tkiFGF^wVXGxHuN%07J{T?$;yc+5C>#WVvS7WF{F zoj649naID$vQtsZ_V{9yo8`h5d>`&)GwW}<6wHoP05ZUmuS60Wx}apv!Ul4j6e%d? z0IK=TG=MZ~u`BcZgTdgBxWox28}wF>1#TTnJSp=5+7yDokm&Q+|HXPv&t!FG0eg$8d-b=9qS>#9j;{ID=xCN`%BX}?zz8%E>w z96MHzLQ#!^qE#9~+F0zi&gyCpYhFX)^%C+^A zc|rM9H;s8R!_&CIfqOr68Njl+2QA9x|*8&+tpdb3%CS< zBL_`kFpb-mzlu_@-|*>HAA_PC8*d&MSu}|1Q z9BLBB>y9)HCMks$$@?cfpZ1^-gF_&!;jD>Q+x2wqg#+^zC&1%tbw|#;Qt;f+B9cYm zHL9kiAlECbWe)Te5%|J4JY%3erK`7PQuTR5VAp|-JY1vDvSYVv7gS${r^G{xd`L9V z4CYfW3@Blwplv~q(jBFU3wk$eE4-WL8?4}-W`sj~YBN}o1@!!eyf}(Y8eB%l?|TRF z@?|#ZVUIk;;+O~(T5A*k;zWhTPBRHB%^k3mvMCy4Dt^H4#`%1oUfp^%j4OTxNGj7E zpEaMHWUFDk^;adB;iGt{`whbv$wQ2sK*JJ$>H>}i^vp^j1K$B9t^6>+)>b>Fvvu54 zheOhbnpg7p^Xs3M-g?1ihB)o6pA@C$fzDuvjt%=DHQ!S@;)yXy*FWAa1tfo!5`g-c zsm#j58Add#00=<9gcq^a!tDSCUI)uATA>{*bey|OTpQzqxkq&j1O6Juy~4b6qh$Ac zX%((24Hr)^(VFN?&tdvpuxxYE~}#VskOUnhrdKzwPtrcr7IRGnYm z;}R|(+jin>@(-u8SrfJiF;%?Yi~ZVFs;|BO3>vkdpF>dIbTyE?B3Er}u>(I`TQW3Y m0I8^1fdBy0&ixkv0s9W?EdT)QklQjoFb#_W000000a;p>Ev{1l literal 0 HcmV?d00001 diff --git a/documentation/chargeIT/chargeIT-Testdatensatz-02.tar b/documentation/chargeIT/chargeIT-Testdatensatz-02.tar new file mode 100644 index 0000000000000000000000000000000000000000..84220140afff37276b00c7c40bc1182d6167ba58 GIT binary patch literal 7680 zcmeHM*>2lN7R{>ykjYjzcB9kzCRVv41cd;v%orr&{k?*Y&QNjK{@JX_lzmh;+ID(+MN( zf<#quneFNf4xLz9je(sgedu(vQPz2wsEj z?M{_pU6d89`q#r#~;vshJHt;UE0TU+tShy%M< zKFibM$L5x-9(K2k;$qtt2$FDj_AWE9#y3b^U z@eki&vQVZeN+iKZxP&l56hcmjxrk$crW7fag7;#E2ufY4L`XPhk)mKtjwK_Ub14K= znAAyS;)W;`jK_qhD0b6`!e;DH>|h>75u+H6MJY=Jb`pwUmFmo7pPIDQ)BG~PGO(-t zZda5&ung>VQE#%`xE>PJaw);q*dkma$Txvdd-Nf908@0PeOLO#Rne!$<=0(i-0Rx~9IVi?&4g(If8SwT@TGwnmT~Wty$rIFo3~+b@q$3_*n+l z$$1b2$t_RfQI}cwdm0mZIKI#7d5_&)VS1F#1UY!@=8ZPaWrwxR5!Dz3oRv4b8uc&- z-n_4#fP9Zv6sr(_3$b&aBK;TF@_ohCh!U6K8O1o|PC}T=uyP#{ z3+2c(L=h4wl0=a>R1WUlbf7L;%tKh;ANk%FfG2$KjG(>rvMVxo3+iEnFtEQqLx8sQD?@~aDm6XP z!{o>g_w^bYzt09)p+P=o`H##G9vL9qTWy*#2;jdSgSM^ln+_qIoP4P;PPgr*n(Jq#;o zGj%C6RiJGv)PWu~#(jh=et(>N8~Hklm4V&OYJz_R7q9<$wS2prp0@~Y!+=H0ZtE!} z!Wcg1FjZ-|`##SMPyczkTwa~MeRpyEBFJN4r@Eo0s9kSp*|HrQEnq~pQYG*0Ud7=? z+jrQu4F^7T>Qd+(@AGN%_yMOr=vCk<54rWY4!3^o5WOLoM?U@Lh;13gfuV9vcu&b~ zJs{FErhQ{`+0{`!Pbu=GT0l$l32ej}VzN7H7s43LWM3OjW{}(mJG5WL$}5Tw-DVr! z_sz(`%E#&qY(uC7o(n#eXpRM%OTh)q00R#upNM;&Ph1IO>A61@9+C`}^m+g{&@n^i zQ=by}L;?sl^L**K0((Apz4;t5?9HYwr9d@cv_JwnYk5Y8zlS-=J>;{412gn&;h-}} zPyadGD|#D#yK$xHTh|AS+jmL7-?-eLBkT)~=*)9m&l4ObEpr)g;ZXqtf9%cSPcefJ zpUP>_>Cqb3qa2~B>rm)aW&wh>2HF$uJ9E$VT?W%J2LDTdr_6`0ed@cxE#n>+w-?X9 XymAn literal 0 HcmV?d00001 diff --git a/documentation/chargeIT/chargeIT-Testdatensatz-02.tar.bz2 b/documentation/chargeIT/chargeIT-Testdatensatz-02.tar.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..f75d1c3983757b15d9c2a8315b0138e45385cfbf GIT binary patch literal 2247 zcmV;&2srmbT4*^jL0KkKS^ua}*Z>Fo=|Nr0m1ONa82mlBG;0eEY zGr7Ud(tsr<$)pqqKmfQ(K}VBB8mHk?@{dJ4Q)Hf+YI!t`G#;m@0BubNs4&U^38N)8 zQ9nr=C;-sNGynh%00V#k000001^@s6005IwDte)lPf#%c^)vtg(9xg`01XWd4gdfE z0000O000000!V;Bngqca6!d5mdYPy^r-;##0Lhb2Q2*bSvBJ?vH}kz9KfUK&xUo`T z!ek-SxZ@C#2LK2HilZ2+v5EqV5fo4oFk=*h7@(wBKt@E&K#<+t)>ib%z=9XqQ^&9OFEb(^0y zNkT(fu(}>v*)cMVyDC#?EH;K@;HW)(2+i@Is2r%#dChZPpi*phF61SNJYookBxqqUhfeB5(5XO$Q9-LoF|#r!F?A9G zi&70Wnhu=U1k9RC@&2p`#O#^Olofft1)YVuJ~= zK&eT-;~k+QWzqa@hG*TpuJv-n`0F$32$ao$vttc#$YVkvZ4?Gx)f@uz$@#HHah$cb z>NIni3zUb2`Eerw1WKuZ&?(ME+T_!ih!0tyK$RdJHt(?pVpTut^EtwmJ`ki8Y8)XQU`IgT6(@3z%->kDTblg~NP zT_pB1F;Awqs>!D7jZWuhli(Rngps4V=ZStK^WdWqsDnNN{Ag8RQ!_yuGS_hsp%IfN zt_LE9{Y9@h6+6rqR#OVN8uVqD>o*@#cx&98hhFj)jnLR_vYK)@D5&Z(&=fS8lPz_t z2Cf5aQdVqLW-N%24rMCxa`Lz>OBGuTF?2HvbQ+a3;BI(b9TB!E8{xaCm|#|;ze90i zovx*}6?w+1uBU}Xc*YY>k=8M|=Xu-I6EGiruL9{yv6}&`9U4*x_S_Lu@ zwoB!bWVcKp$kgf-EEkri4APP)8Sfu-mhsh!BZiVhO6%E6*wW;*tRatXRJwLIE*jSK z0tlXAcdZK(14!eSjRFCr%w&D)`!vze)I$TG7UHwLhN_&xx5|;a!X6~W&R?cQu1KmO z8&$IUxfksNg-xL19Q*USXu@z*ZgT1}uO18c@r(fTXjU(}e97z>t9dQ8lJ@UMA~m2G zI17TiG>mc~QyJc^4BDru@Hci{rM04>6R~C%j-&47(F`e56q6OpU8j1EKvd+$jpC&i zmO6p#B^nROjOg&Q%xN4)8RHA@Kv5F!Q$&UXw@;HT#OpO| z#EVIZ(__m>w1Hm;iR|Nu_8)Ls69YkE9z(R6KQ{0ACP@y#h3Gw=@Wgq#u>R-|s3@e7 z1J#|&#klqtYf>faOmL9Xp}!OBUecu229CcPN9Y$~vN@}-QC$fd7a-H9sj?=6B`yWR zWg|)QZ;#%Ye)dEYa=}9QqXrZV1}dr#04QA@>O*|_oBowXV*!EM=%ZRUoR?DN#dFmx zvXwZF;Mys0{{sn{TUbC^#mus)iaMa>7@ch#FiDy|3H%FkAr6S*$9HnaGt2ZF%BuCN z97fa~TS3Rz>sHSNW0|vPhRA}iTKF9|9!$WUk5Qx{+g`Yg4(C|T8kL;v9nmntDjHiK zGWtmW9vm}f3XV3S5;8~Cx8R5$WXd9`f3hrdIWH3IR6Q#N=Uo?j*n|@*9&^ER!C@tT zp!9Z})`7rt+AxpQFm(cqm!N=(peA{MfVv!5uRvX+AaI-YpoCcj6e1c=8RGPTBFOp^ zAkY-tBTUiYXk($Lnp~VlWuzjJK}$4E9b44k$fW_IaZouye>KT&C!=|4Ij%iXFN~N8 zg&ruP4SY=)C8^#mTElAJ>7Dw8?8wAFxe(Wj9tSc>~1Eu_k4&>?e`q2=R z5@32UF*=U;3x$aZ6lPRyCb$8X5B9K@MJzNJEbd}=n2kaSiwFoJvdmos0Apxja%W{pR4r6xb97{3bY*UHVRU*eFfuN5VR8WN8QG50 zFpyV}_=nI(psjB^`vSQN6_*4B1PGxVP8(>GDoHuT-|!i{@ncNx?k>A5hY(0ut0bKn zd+zbr8?O9(sppIFLKkJ^mpU!{^8FZ*NsW1T?l%mC5t34#L(Mqy#*}h;4pYtr!;%3U zKvM8?20Hf##;z#+{2clty#B)R;o^n!qw7gDIxt3j`0&mild3&03Y^wm6thv#m~>ph?o@BwS~^Xxfq$Q)hAi%F7~4o9TfDnrbdV z*c>AU;kH2h0HFhHK5a;J8XYIV^njC=AksycC)+Z~s+B4=Dp)ngTCcTn+mH0?EMI>4 zlrHrMupjGLl|Z>4mhF^Yb%nT`am(T+F%bg}6|Q`@trxsMo4YR-){Pf)x5exVou~e$ z#8+%L1d0IFw)xOYjo$%15^l<%Ae_qtW@w4ixZPaC=3 zW!nX;QGMNhG^@U@F!Qn^Wc0k5bKEjDaG#OUaWZaff}6(Ja9UA~R#u}E)_9=v*GZ_0 zO07n(#)^Xx_mxl5IJ@3(Ny>4@WfEqa(bb0ZjSlvs=FOWolT+!}*)n^Wue&*?O_|2Y zTKmx^NvF1V+k=>!J1^Wkd9A0V-fY)U-HPcp35#hr{YAC<3x?ENi6+~0*)iSjf^`z! z((ig-RZxGu%<`mMZ7N|39d5Bnatw1Cbe!cIABKsZt?5Wd1J7SzX>1yTwUQWiy_CR!*?smTNBqgY8IIZ(y1 zreV*sNS3Kz?sDCWUxQ!ick?>lCX-1`dj_q(rPg7+uE7{J(2vjS_s6Toi6$dly!ru? z`6`Z4qzFdRB!m;95dg7}VF;xuMq0<yFtbwkwC_W#XrXo#o+5=fzc{X$->Eu6%D4Up_~5**K=a9@UwZI5nRmJ>6S#I;e82 zw)TPE7uB{>UiK6skS~mxq+=f^`R0wE>qnqlQzS=pf+mDd2vTN8wba?|EcExvXkCu# zaAj(OD903E?ZD|0z!*(95|lU5(XQi15kyU~w?{CJSBx$7AE1hgchd6qV9(cV$PPNG8fnkw_uXNc=`}n+rZgi=K z4QqcfWJ2n2<}!s~DC!|8_NoKy-&tPKd3SCe1wXuh`-uDXW;L!^RnZ&iVZsIsP{)?O z`P7&{R-SQaJqUv6h$r!+&8!nVjS21XLsrkKLUi_a#!JCt@9tC*KRC1m;6Okpf441B zTjsvKpPZ@oezQOxEs>^YDPcnQ;!sS4r-Vf%F`=6lE*Hr4lxGPOQNpE(9n-NbX}T1_ z4rBvHc?cY-X13*WDj76?F6XY}P*)+-p%xWR!}X+nWkBfK-S@z3LpR}6W@{EWVu-)1 zyjP-?$wouYZMH+-DaI5npewEap6(Mvb=v5(tM(mK*AaG8uh*IJCd=2+rBRRlxHmh^ zN?U_#b<0YPF@`R8fyDun2M9N;24X9QKx=3T9V0r%WKs3P>;RKPv=Fp;QxAK|1_wDh zFOxWdl2-dK_Sc2JdW5D9=|>P;HA$K8^fwjA_3O4YKD<9~cEkpIhE4z5VSO~NDWc$Y zIE_Hd1EE2|hml~KQ$d1I>3|6xMKPg%6b2FwC?pVwXdJ^F6CoY?iU-(dDhP2bSVXwV zu{N0urDiJjQGg^06wxH~HN(A|hSp^W>u)yB|AYE}Q2#SQ4Sj0=(Y@PO^MuFY6Du?< z`(4$KUlIJo9YM?Vlnr&bLO9DE!uKx`npSE4o#trd@5&YU{(T)A&~Wx${;Br|r(7T$ zPs~9;*{E;@5%}mk-u=yY4rlCQ@0{Tmt7?%4H!Y4q4x02n{eg%*c8C{(h#p*D5LIWkU1M`K zoIf-;I4b6FqziwRN&JcE`K-96BY1>jj*D_O{ zkT#W=f_Y}}Q#$Z)sj|Ey#}#X$h$*{ z_+J2kRdE17?&tL8Eo_jtr#V^$?HP>sz~Vgvg0c8;6*Ud`KS>xH(qB1Zya^UPb_?Rk z^xG0&;R=XNK92wZOU%O4Gkd8pcT)^)*R$3$VFFZ5MS>q5ErV?H#zInMI70 zwfGc|X35PI{_zlL)so4DR88}ce2dO&a3=A3&h-ve@GFAYVqxXO~*3&f8D0@ z(|74X-SW=rL>>97Ib%R((Y!yHRDQ=s%wA#p( zSQLF|X0@>D#Uk=Rh8ge9lC)Sk(f@LSTlmgpcO#Jf!l~}lg?gng&2+O`-W#OsB%_3H z&Pou;1Qr%@;c1gc7W9pT45>(t2(%ab75Y`<{ylQ|lDuQvzV^4`@K!p>&)21uPK(4}2W??9)WH`DklBlri z`*C_%Qlj_cYRl|pm3v*&i2lNKn6=@^CvN>Ue;EnSwcZu`=L(A%=5Zn#7=hx0MC zt%6LvZ<$V}%K6~Yl9bs&uE0^#)lhV4Iovy0$yNo#>Jj# zlQbOZp)Hhh$QsAK9k_7a*Z#Q)<#ch*q|->Fd{WJa&s>`}ylv8@g%%8@Iji=}FNQBR zc7=XtW?05`DhRmHYq1BL&*Rq7Wr>2mFCZFE@VV<>M7zxFB=`+kLe(+eVOLk?+P74` zb+z4?k9TD=MlfhfTOkw@xGP{vhp#1x+|8q86Nl&ySyXp0Y8}c+fQ$28e0suNlX%7V7Jt5iUayDq z+wOfXa@8$)A5MwvZk`~p*50Mh7OYZ{=DK(;p=DdpDt}m5zWH{hh7oN8nqKbc?;D8= z99v5k+=b~JZj|mchFOUu(0Y7$Ol7VKg4Dsym5`;E!bRI5mECFzqXOKnoxp@|QX&aw z7t~MM#ljvwFmT=nrZvfkdZ|4JJM)+@HMY|q@NA#6Rou)e z^3H@Vj~*2t_{ZeI^xF+ktsu|7Ui;Fvr`+$ z0Qubw)(j!G?(w$GoGi7;SQq{Vf%uS%J0o(B37gwmZY64ls_S{*>t$dTj|9nBWEi26 zb9qV;uTtc&dV%6Ry}r;TA5)xmKBEeC>6m3)gK_~v?VWGx$ChLDG5Ip$F)*9xfN%8R zV)BRCv8KB-5fidTuJg{18ug^KzCIlniMtKy32t7)C23XegnLv@ybqj-!Ud+{MgS!v zgN7u)jN^XGpZlP%voz{nv?`ZsncB$yB+lX5`()<8lY%p2WUN7&uk>VBreR4(dW~7q zy?6W@T|2zCAzqiX40C$EUq%pm+J8L&1pVM%88*5Lznjf> ziFo$*jTWpEv1hb43oapkI+qxcz3Di)iKA)F22y=()6#vuh*>K!?l1g{TT=M$*J4lI z6XYQzkN2d95OvC`9|!aH3)uPGlfZEWAT5DhMu7jtaK)b#|GVV=>HnYTp#N+F0T95C f&Z7$v55|E1?MO@B6Mvrr{#4LU@BaBQ004ghPL21M literal 0 HcmV?d00001 diff --git a/documentation/chargepoint/Testdata/0024b10000027b29_1_121708795_payload.FLAT_SESSION.tar.bz2 b/documentation/chargepoint/Testdata/0024b10000027b29_1_121708795_payload.FLAT_SESSION.tar.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..916bdbc891f488f737e8b1efd745b68c60dc9dda GIT binary patch literal 799 zcmV+)1K|8ZT4*^jL0KkKS&r-F@Bjj0fA9Pqh-=#gfB8AD{{H{}|9%9)0YCtY9RQIf zNFV`=zyjD-FoiA>h*QdHpOXYmaxk4Q8cXaE2-00TfY00E!?07_~l4Kx5605oU@fB*mh13(%80005N0000q z00001pwIvS05Sm30FY}cW9)Fd6LHFn1X3w55QnCKDMb)W53{mx(n`@L5*QLPQYzyl z_z)9q0+VXT)-Qg9;Zyfedu!fAIEbta;7OAtm`F$j1V&*FNMwddk^uq%(8R+t+2G{P zS()-O3}OlsGbRzSt2!RhX``7_TUp~=s|YdGRa$e0YTrgh?vk(|m^6#9z5O3HGFLA{ z>0`OhdJ+(ax;(58-)D);Lng_1Pz*H%1wo8J>75~n8d~o*c$xOYsuet&ip4|f+RGAL zuOw<(hCnFqRbim8P~=29cmWNxD440SOP(K9pdl0wEE&XvY`_gJlviCNvxw zf)Uz?^B~~|q4=^Og(EGFh|+=SX`Pbo z{i;XAVbddZSYqV{%IYbZlii;8RLEsVwfGV5JI{lyD!_5~n2fIDV+2S_tD?h9V8pDG z3{7=zhKJfU3y&#%Wgm8SO*ts$!>Fty@o2DqUbVJG>FvdpB}v-jM|HjxrRLq^FS53>#4qA|&R@h*XaWBV7E{ zimcv@4A+HWH!76EGS3mE0vVKL*C+93TR3?EirOA~nRGb}*5TR2-MN1)#fKmFYaYB0 drTxp>e2q=r%zLqk{_FeryOJrwgoJlrFMx9~XB+?k literal 0 HcmV?d00001 diff --git a/documentation/chargepoint/Testdata/0024b10000027b29_1_121708845_payload.Per_Min.tar.bz2 b/documentation/chargepoint/Testdata/0024b10000027b29_1_121708845_payload.Per_Min.tar.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..3652e65ec57f05a739ade3956e7312e3c3e36d55 GIT binary patch literal 807 zcmV+?1K9jRT4*^jL0KkKS(waF4FCdU|Ns0E0AqO#fBQSX{_g+x|LbT8Pz4l#Aq!j} zlpqixh>Ac0+y-V~STz)ydsKN%4^tCO4F;M4=@}Xg4FCpe4^!0B)WI--$k6nS>8c4t zOw`hC6x95usGgubKmY&$00000000070000q0002c13&;Y007Vc001R4iKM6EC#o4e zLusf7q|glpn43@rjRuSp)M(HE003y33lRQ}FXC(x7!A$bVxZkoGHC`Nu*AU*HRl@z z)R`toU`W1^Rl!0i3?_`2d=wWgo}434#b#m9m`Rf)nIRw$834}WNrZ%kNr3_Z=MXbN zpbnYWw*N=DmUPPIDlHVjnX+KcJF!d#X$WS!cUth$V)d!=LNgS+N1%2- zu&Zh&=D7~m>7?gWJ%YMB>p>mlN-iYl1$Z1nl18&6)VQf+NOIG(LM9=qLD{XwwhFaq z28ck#1;VAP)mZq}fy=Dx#R7mCP(VQGqbRbetguKP?TnEet43eADnBEnM(KfENEXeV%J0Nj~iYm`eYI7R4JpPE~FN)p&lIJchS5p;>aJJpxGBl%*bO@-ksjQZZtsX@aMZ#dz|Y?6fCj3~@8ajH13|T;!r( z+6?e8Oz7RCO4jnaZw6q=PGXi#o|3x|QIW{xCWKY*BABOXD@7tDVMFQ*M7~rzC|@#v zHzk6Fq{{Kl@koYb8&G%)N3u&fO()aQdShI-8Q9CFL}hb_4=hopH8wnphukoXB&AUr zl7OWjC^lBGl@ezSG|4va|73K=t0p934$;FF64@Ep&>Dtpc*JxWBC98 literal 0 HcmV?d00001 diff --git a/documentation/chargepoint/Testdata/0024b10000027b29_1_121709375_payload._Per_KWh.tar.bz2 b/documentation/chargepoint/Testdata/0024b10000027b29_1_121709375_payload._Per_KWh.tar.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..1fffbbff85e6aed4da4babb7903d0b7d0543dddb GIT binary patch literal 805 zcmV+=1KRvTT4*^jL0KkKS%wA$wEzNffB*itBt}^c|N1+R{_6kt|7rk00D%wyaS;k9 zumVvK6evIfyfm1ALrDgy?38+p)OkimhJZBn8Uc_14FC=5n@9$LXleSOlqA6d5$I6$ zG&E=c0iZH628{q@Gyu>BfN%f+&@?nOG{^wZ00w|)XaE6_00Kmcngkdon^BW$F`)p{ z69E~cQwfoiAjCA&BLy%a{Mv2D-KhVP_~P3YbG z?%=kYO^6#RHe6s1Q(#=Fy9B87+Lf<4-O2VZ(nK+#w9{=iHUk6H3LtHvv9UIRg90nY z2}wvHsC6psXBua2yCBo+O*~#5W;xCEuB%(Q zR}sWKCEcdnN)X0IJ`75GYD0i5%-+!?0|uH@Apt@Am<5!tZ+EGRX;ZPVl*=1Hn&_8D zt`?%Co4ARv(xMGXDjpR*3^Dg^q>! zlv&Gwn*m9Hz_(K1^GoOnctHRlLH^ey#DvbA4jfhJ%r->$_azAgpl)s!DhB6;NKkl9 zr`Jue=*E`pD5wsRQ zlugDkFs3KvZDu8Faa`^RNH-F{w8iVva#M9-Mn*(6AVpb*99pDnBP(1%hh>ox zB2ILWr6>s_rugQhm1%-7X1ps3XjLn?YQCqI1Ts`#)4-DxXu~Fi2#9g1f*!xC>G=7@ jt6vN5Ids1)99Uk9E2E&ixP9z_e~Y;yoG3^`0|MHBSY~5x literal 0 HcmV?d00001 diff --git a/documentation/chargepoint/Testdata/0024b10000027b29_1_121709405_payload_Min_Variation_.tar.bz2 b/documentation/chargepoint/Testdata/0024b10000027b29_1_121709405_payload_Min_Variation_.tar.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..1b6b4c44078fca87e0ed4874a2bdce4d64f825d2 GIT binary patch literal 947 zcmV;k15ErvT4*^jL0KkKS!K#**8l@*fByQ|2y9(VfBwJ!{_6k#|LOn&q5vlX07{qy zkO-Iy&;xiqA&3Bml*LcUM$`cH4FG5j17!i~003wM)CYwC14fLWsSW@GKmalT0078n z&;S4c00001CZ!Oe=?x77K*^z?13(%y4K&aIGypUJ0MIx94FCYh0009aqd))v00000 z1fpmJXpIQcYHcIXo}eC}$jP*T^hS*|05T6z>H|TiqBQ%+E?zffoT~$6@xV6T-HEC^hA2o< zFccW9iUN`(oCpO_tOXWDiU5L1SB4T6LdhwGCr6i=-RDf)r%_GpBQK$RJAJ1)1H&IL z*Yq?vv+*|k#c;G4(<&4O^VU%q8|k`jUfr+}5HfT!kG_jG=6-%2{LC7m;@QTg$&oWo z64h5G+5r;VxdpbqAa2z|8HNdjbu1uMFd8Xu*i9N+0PI2+yaHZE_ZIk)u%>f=3ce*v zln07fQQzbA`ezP7b=h2f(7EttOBG-rbs~c(Yaz89a2}Gf&4h80gveCL81)ZgXPH?{ z+d3r-fwZ_vGl>rohk)BI%443TUf|R#l%NV^M~1AGxGY4Gpdwl11B3vPWB>p$8YE0+ zo@OveWq+`C$}GU~oy&SMb@tt0LL&w+V|ZlqX^pP7k}3)gn;TdJMA=0RXosmmpoorQ zZ#MxloQ#ywGEE&<0a*Zry0C06&AV1Ob%IQkgMgnR2?-$oeo#E&MJECwVy0n_5a8pg zB^7vFc9Fx7vSJQT9b2c;{O?pcQ4g{<7Am|M++&=;tRFvFTo3JgP9v|F#iaxqCeEaq zg_u4pJ<5=PJc0Qe+KEEJp;KKA!l+L5D2&R7izz0>N~Fvc3)5lFPCI#8PDmwnW{?;r zBn+Z{hbWLtRYh0ek{sk8Rz)?4Y^J$KNy|dz)R3N_BuO5tw>;5sUuGE+I&Kl>+mXnN zU?SnnMGLKoOhqCIcs+`SAZek!24kFwrxO8Cz)-|2Uw(FqL^BU!T;uUE8c;%su%_oH z9!O?XH*ynZ;WQQ^5?u^3F!L2AVKpg>h`3^*AS4AS>V!(B)Ig#StYmJaR*JVt2O@68 z3kfHRp>06xzfEhz#ks;_AU4GTYH=lM-S>0V6>o zWssco1v?(5$u0Wv<172}A&z=Y1d#?bHkxgw#=u}{0)z(I8ygd77%(9rf>BWjH3!4% zETUM2^ujYa=4{OniHn!g^ZgNf&loBJPV)jOztCfNmRMU~AO_$+RV<99> zS7|lPV1zdg@(+g#943Jg`553$jWp3aAPb_UsT7K{^Y-*bBSxwyv|GF#v=~?~cGD7- z4@59At9?VG2GRlOsK`Ux_Z2W;fhgV!Jvvf>LZ2>sRC6Xtj#VJi4ra)cR8b8i4-D7T z`N6@6h)WJJC9VOBR2r^**Nm!j0)m435<=oTXR~!%j!Gdfe^nUxnM{gN?AwC5G*1EG2yANPyIp)vAP~ zFmB1wh|Dw?^Au&kZxwA(vRhKAlqj4m$t*OKsTMVHVQX{8jzps#%b{JCi}RUAOo|xh zu#_OCrX=8GEH<&TRZjs`7y?oZx-PQ1?3dzYhK!Fm*O5rLji9874 zBq<8qP6*{R2vo?93F?H2$fbciz<3U65Pe`=exr>7O;8prE4?wjMi#&a#S3{cm{8eF h!ZrwSfPyY0;9%rKNUxba*(MAAF64@Ep&?@Sx3a>JUZDU0 literal 0 HcmV?d00001 diff --git a/documentation/chargepoint/Testdata/0024b10000027b29_1_121709465_payload_Parking_Tap_ToCharge.tar.bz2 b/documentation/chargepoint/Testdata/0024b10000027b29_1_121709465_payload_Parking_Tap_ToCharge.tar.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..d16332ff5edad7441b7c1711108b707c94ee9d99 GIT binary patch literal 807 zcmV+?1K9jRT4*^jL0KkKSwFxK>;M93|Nr{C5oK9rfBiYH{_g+(|9?^dA%sYh004*r zgg_9D04hKN*i$ml7&QnPB=sJn)Ovu>0BubMjTry{00)HBGyoX}GJ;V6ngk6aL=1pv z007X?00003)BpeiM3FRxN2vg4#A)hi$kC=FCYcAQVl-&cpk!d0WHK5IhX4Vf02u%P z0Aw_100000000N9(0s#yf!#Ins30tJ?~1`<#L;X}j%d(+Fmh){E$?k=oguU~AZ+lq zbZfUMm>g9zs*4fV)};I0n4Duw=paxHrkiMNYz77>CPQLuO{TzLz={S5Nk}26c6@%W z>6Bzn@$C1l7pKtah#m!o11Cm~Qbj3NSkHt5gv7w3%9#`^m;iv9<4Il3J`Xm=7I#s* zsW_HC6huj(jFHuzQ+rg00U<*AMId-&DP>V^z2cC$^n=H6Y z9ym>`e8@S>LBUI4DWs>WJp?I*hNH;46fC**okz*;ZK2g8GN)2D*pwv4Ce~Drkpcm8 z;Lu`|d5X|5Fa=PjHtInLV1c_+oUMWa1tCcC*Je|KC4wcpcrygkWXziQXgUj?5`1Nc zX|(uYJh;T$K>kcQB|B_70aeE-HpU)ZAk$v5n*9DY)z|XA8cw0mFqYG$vkhq_zj_q7EvZkEREic4>Tj lQ}U}?lo4Qkxv^FhhvapwDn%SnAQC_EcO+AV2?P8A4#0WaWE%hg literal 0 HcmV?d00001 diff --git a/documentation/chargepoint/Testdata/0024b1000002e300_2_119693895_payload.tar.bz2 b/documentation/chargepoint/Testdata/0024b1000002e300_2_119693895_payload.tar.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..37c8142663716e5af40a15e91f66ca039f116978 GIT binary patch literal 995 zcmV<9104K9T4*^jL0KkKS<)uY6j~$uDGbAh$gj3Kdl07v&N0c6?rjXH)4TN*Lq3Q>y0Q7@E000^Q8fXAL$Ej?X z#x1gLzyP#D*)V0?xhx36!8;&Ze?Ep5e*4wAX`!(;4W!ygZ0L+_mv+YO#6@Hj`54*&s( zK*TiWoE}KJMmKE&;xQagP6}vy4_b8 zd-mq1P!K};Qt|6=VAT70>~&6vtirIWsn*qSqsBvsh#Co|g9(i|my{(;S7L!EFAya| zgqsyCP6V=Kge@%{9q+RcuU2q5*DV=Vg;7B?@l{d&w>JhRB?{ftBdF#$CLwf&gT%B9!Oxv?1XRhRf$*ykx#jLz z7C%9+9>9vULz8ITJ|b{}Sj8MALM!}GKqR9k^px!6U&G^yHNzUsRyI-rRF19NA zDo|=|IaSAeoTGKbX+3KaPEeeR=<>U=YY`I^vm$z>Ti=|x`g_R{u98TKItQSOKtjx1 zI@X(3q13)Xp#or+%@QP0KVq5;Lm5>Bg5hMWnAsThY^7nk^yWK?2u0OcKxj2KO>1o& zN&USr~(e7)-dxKG4Le zUDygu2~kcY(auyh5{h#1P@+h~@q|{hq86=uoWgZyJ1#(FD#{IXjbi~wR5qKQ;-rW~ z_ILBBGX!iF3^pphOp9*%qN6klN>uIV)t4v==+UT^VwjFIn2bbP0aFo;DnfL$mb&H; z1fV^n!r(J-WmmO>K*w!@p<(b~Tnj?F^BV+sTsfpRr^vW$9)y!rrpNoIdKgs zF5d{qz- Date: Thu, 14 Nov 2019 18:17:07 +0100 Subject: [PATCH 024/110] Merge multiple CTRs. Allow separate public key files. --- src/js/chargy.ts | 98 +++++++++++++++++++++++++++++++++++++- src/js/chargyInterfaces.ts | 23 +++++++-- 2 files changed, 116 insertions(+), 5 deletions(-) diff --git a/src/js/chargy.ts b/src/js/chargy.ts index ac95ed9..c46fd0a 100644 --- a/src/js/chargy.ts +++ b/src/js/chargy.ts @@ -514,16 +514,110 @@ class Chargy { //region mergeChargeTransparencyRecord(CTRs) - public async mergeChargeTransparencyRecords(CTRs: Array): Promise + public async mergeChargeTransparencyRecords(CTRs: Array): Promise { + //#region Initial checks + if (CTRs == null || CTRs.length == 0) return { status: SessionVerificationResult.InvalidSessionFormat, message: "Ungültiges Transparenzdatensatzformat!" } - return CTRs[0]; + //#endregion + + let mergedCTR:IChargeTransparencyRecord = { + "@id": "", + "@context": "" + }; + + for (let currentCTR of CTRs) + { + + if (IsAChargeTransparencyRecord(currentCTR)) + { + + if (mergedCTR["@id"] === "") + mergedCTR["@id"] = currentCTR["@id"]; + + if (mergedCTR["@context"] === "") + mergedCTR["@context"] = currentCTR["@context"]; + + if (!mergedCTR.begin || (mergedCTR.begin && currentCTR.begin && mergedCTR.begin > currentCTR.begin)) + mergedCTR.begin = currentCTR.begin; + + if (!mergedCTR.end || (mergedCTR.end && currentCTR.end && mergedCTR.end < currentCTR.end)) + mergedCTR.end = currentCTR.end; + + if (!mergedCTR.description) + mergedCTR.description = currentCTR.description; + + //ToDo: Is this a really good idea? Or should we fail, whenever this information is different? + if (!mergedCTR.contract) + mergedCTR.contract = currentCTR.contract; + + + if (!mergedCTR.chargingStationOperators) + mergedCTR.chargingStationOperators = currentCTR.chargingStationOperators; + else if (currentCTR.chargingStationOperators) + for (let chargingStationOperator of currentCTR.chargingStationOperators) + mergedCTR.chargingStationOperators.push(chargingStationOperator); + + if (!mergedCTR.chargingPools) + mergedCTR.chargingPools = currentCTR.chargingPools; + else if (currentCTR.chargingPools) + for (let chargingPool of currentCTR.chargingPools) + mergedCTR.chargingPools.push(chargingPool); + + if (!mergedCTR.chargingStations) + mergedCTR.chargingStations = currentCTR.chargingStations; + else if (currentCTR.chargingStations) + for (let chargingStation of currentCTR.chargingStations) + mergedCTR.chargingStations.push(chargingStation); + + // publicKeys + + if (!mergedCTR.chargingSessions) + mergedCTR.chargingSessions = currentCTR.chargingSessions; + else if (currentCTR.chargingSessions) + for (let chargingSession of currentCTR.chargingSessions) + mergedCTR.chargingSessions.push(chargingSession); + + if (!mergedCTR.eMobilityProviders) + mergedCTR.eMobilityProviders = currentCTR.eMobilityProviders; + else if (currentCTR.eMobilityProviders) + for (let eMobilityProvider of currentCTR.eMobilityProviders) + mergedCTR.eMobilityProviders.push(eMobilityProvider); + + if (!mergedCTR.mediationServices) + mergedCTR.mediationServices = currentCTR.mediationServices; + else if (currentCTR.mediationServices) + for (let mediationService of currentCTR.mediationServices) + mergedCTR.mediationServices.push(mediationService); + + } + + else if (IsAPublicKeyLookup(currentCTR)) + { + + if (!mergedCTR.publicKeys) + mergedCTR.publicKeys = new Array(); + + for (let publicKey of currentCTR.publicKeys) + mergedCTR.publicKeys.push(publicKey); + + } + + } + + if (mergedCTR["@id"] === "" || mergedCTR["@context"] === "") + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Ungültiges Transparenzdatensatzformat!" + } + + return mergedCTR; } diff --git a/src/js/chargyInterfaces.ts b/src/js/chargyInterfaces.ts index 90d7977..c9749ee 100644 --- a/src/js/chargyInterfaces.ts +++ b/src/js/chargyInterfaces.ts @@ -17,7 +17,7 @@ /// -function IsAChargeTransparencyRecord(data: IChargeTransparencyRecord|ISessionCryptoResult|undefined): data is IChargeTransparencyRecord +function IsAChargeTransparencyRecord(data: IChargeTransparencyRecord|ISessionCryptoResult|IPublicKeyLookup|undefined): data is IChargeTransparencyRecord { if (data == null || data == undefined) @@ -31,11 +31,23 @@ function IsAChargeTransparencyRecord(data: IChargeTransparencyRecord|ISessionCry } -function IsASessionCryptoResult(data: IChargeTransparencyRecord|ISessionCryptoResult): data is ISessionCryptoResult +function IsASessionCryptoResult(data: IChargeTransparencyRecord|IPublicKeyLookup|ISessionCryptoResult): data is ISessionCryptoResult { return (data as ISessionCryptoResult).status !== undefined; } +function IsAPublicKeyLookup(data: IChargeTransparencyRecord|ISessionCryptoResult|IPublicKeyLookup|undefined): data is IPublicKeyLookup +{ + + if (data == null || data == undefined) + return false; + + let lookup = data as IPublicKeyLookup; + + return lookup.publicKeys !== undefined; + +} + interface GetChargingPoolFunc { (Id: string): IChargingPool|null; } @@ -71,7 +83,7 @@ interface IChargeTransparencyRecord chargingStationOperators?: Array; chargingPools?: Array; chargingStations?: Array; - publicKeys?: Array; + publicKeys?: Array; chargingSessions?: Array; eMobilityProviders?: Array; mediationServices?: Array; @@ -86,6 +98,11 @@ interface IContract } interface IPublicKeyLookup +{ + publicKeys: Array; +} + +interface IPublicKeyInfo { keyId: string; value: string; From d398cc5da5c5be1879d34c6e66c30d85f2b33f36 Mon Sep 17 00:00:00 2001 From: Achim 'ahzf' Friedland Date: Thu, 14 Nov 2019 19:57:38 +0100 Subject: [PATCH 025/110] Allow recursive (compressed) charge transparency file archives (.tar, .tar.bz2, .zip, ...) --- src/js/chargy.ts | 205 +++++++++++++++++++++++++++++------------------ 1 file changed, 125 insertions(+), 80 deletions(-) diff --git a/src/js/chargy.ts b/src/js/chargy.ts index c46fd0a..1448ca5 100644 --- a/src/js/chargy.ts +++ b/src/js/chargy.ts @@ -186,17 +186,14 @@ class Chargy { //#endregion - //#region detectAndConvertContentFormat(FileInfos) + //#region decompressFiles(FileInfos) - public async detectAndConvertContentFormat(FileInfos: Array): Promise { + public async decompressFiles(FileInfos: Array): Promise> { //#region Initial checks if (FileInfos == null || FileInfos.length == 0) - return { - status: SessionVerificationResult.InvalidSessionFormat, - message: "Unknown data format!" - } + return FileInfos; const fileType = require('file-type'); const decompress = require('decompress'); @@ -216,125 +213,173 @@ class Chargy { // return 0; // }); - //#region Process compressed files or archive files + let archiveFound = false; + let expandedFileInfos = new Array(); - let expandedFiles = new Array(); + do { - for (let FileInfo of FileInfos) - { - - let file_mimetype = fileType(FileInfo.data)?.mime; + archiveFound = false; + expandedFileInfos = new Array(); - if (file_mimetype != null && file_mimetype != undefined) + for (let FileInfo of FileInfos) { - try + let mimeType = fileType(FileInfo.data)?.mime; + + if (mimeType != null && mimeType != undefined) { - let compressedFiles:Array = await decompress(Buffer.from(FileInfo.data), - { plugins: [ decompressTar(), - decompressTargz(), - decompressTarbz2(), - // decompressTarxz(), - decompressUnzip(), - decompressGz(), - decompressBzip2() - ] }); + try + { - //#region A single compressed file without a path/filename, e.g. within bz2 + let compressedFiles:Array = await decompress(Buffer.from(FileInfo.data), + { plugins: [ decompressTar(), + decompressTargz(), + decompressTarbz2(), + // decompressTarxz(), + decompressUnzip(), + decompressGz(), + decompressBzip2() + ] }); - if (compressedFiles.length == 1 && compressedFiles[0].path == null) - { - expandedFiles.push({ name: FileInfo.name.substring(0, FileInfo.name.lastIndexOf('.')), - data: compressedFiles[0].data }); - continue; - } + archiveFound = true; - //#endregion + //#region A single compressed file without a path/filename, e.g. within bz2 + + if (compressedFiles.length == 1 && compressedFiles[0].path == null) + { + expandedFileInfos.push({ name: FileInfo.name.substring(0, FileInfo.name.lastIndexOf('.')), + data: compressedFiles[0].data }); + continue; + } - //#region A chargepoint compressed archive file + //#endregion - let CTRfile:any = null; - let dataFile = ""; - let singatureFile = ""; + //#region A chargepoint compressed archive file - if (compressedFiles.length >= 2) - { + let CTRfile:any = null; + let dataFile = ""; + let singatureFile = ""; - for (let file of compressedFiles) + if (compressedFiles.length >= 2) { - if (file.type === "file" && file.path === "secrrct") + for (let file of compressedFiles) { - try + + if (file.type === "file" && file.path === "secrrct") { - dataFile = new TextDecoder('utf-8').decode(file.data); + try + { + dataFile = new TextDecoder('utf-8').decode(file.data); + } + catch (Exception) + { + console.debug("Invalid chargepoint CTR file!") + } } - catch (Exception) + + if (file.type === "file" && file.path === "secrrct.sign") { - console.debug("Invalid chargepoint CTR file!") + try + { + singatureFile = buf2hex(file.data); + } + catch (Exception) + { + console.debug("Invalid chargepoint CTR file!") + } } + } - if (file.type === "file" && file.path === "secrrct.sign") + if (dataFile != null && dataFile.length > 0 && singatureFile != null && singatureFile != "") { - try - { - singatureFile = buf2hex(file.data); - } - catch (Exception) - { - console.debug("Invalid chargepoint CTR file!") - } + CTRfile = JSON.parse(dataFile); + CTRfile.original = btoa(dataFile); // Save the original JSON with whitespaces for later signature verification! + CTRfile.signature = singatureFile; + expandedFileInfos.push({ name: FileInfo.name, + data: new TextEncoder().encode(JSON.stringify(CTRfile)) }); + continue; } } - if (dataFile != null && dataFile.length > 0 && singatureFile != null && singatureFile != "") + //#endregion + + //#region Multiple files + + for (let compressedFile of compressedFiles) { - CTRfile = JSON.parse(dataFile); - CTRfile.original = btoa(dataFile); // Save the original JSON with whitespaces for later signature verification! - CTRfile.signature = singatureFile; - expandedFiles.push({ name: FileInfo.name, - data: new TextEncoder().encode(JSON.stringify(CTRfile)) }); - continue; + if (compressedFile.type === "file") + { + expandedFileInfos.push({ name: compressedFile.path?.substring(compressedFile.path.lastIndexOf('/') + 1 + ?? FileInfo.name), + data: compressedFile.data }); + } } - } - - //#endregion + //#endregion - //#region Multiple files + continue; - for (let compressedFile of compressedFiles) + } + catch (exception) { - if (compressedFile.type === "file") - { - expandedFiles.push({ name: compressedFile.path?.substring(compressedFile.path.lastIndexOf('/') + 1 - ?? FileInfo.name), - data: compressedFile.data }); - } + // Just forward the file as it is! } - //#endregion - - continue; - - } - catch (exception) - { - // Just forward the file as it is! } + expandedFileInfos.push({ name: FileInfo.name, + data: FileInfo.data }); + } - expandedFiles.push({ name: FileInfo.name, - data: FileInfo.data }); + if (archiveFound) + FileInfos = expandedFileInfos; } + while (archiveFound); + + return expandedFileInfos; + + } + + //#endregion + + //#region detectAndConvertContentFormat(FileInfos) + + public async detectAndConvertContentFormat(FileInfos: Array): Promise { + + //#region Initial checks + + if (FileInfos == null || FileInfos.length == 0) + return { + status: SessionVerificationResult.InvalidSessionFormat, + message: "Unknown data format!" + } + + const fileType = require('file-type'); + const decompress = require('decompress'); + const decompressTar = require('decompress-tar'); + const decompressTargz = require('decompress-targz'); + const decompressTarbz2 = require('decompress-tarbz2'); + // const decompressTarxz = require('decompress-tarxz'); // Does not compile! + const decompressUnzip = require('decompress-unzip'); + const decompressGz = require('decompress-gz'); + const decompressBzip2 = require('decompress-bzip2'); //#endregion + // DataInfos.sort(function (a, b) { + // if (a.name < b.name) return -1; + // if (a.name > b.name) return +1; + // return 0; + // }); + + let expandedFiles = await this.decompressFiles(FileInfos); + //#region Process JSON/XML/text files let processedFiles = new Array(); From 56bbcc6f6f1e17e6c0bb5894426bb427a5248d23 Mon Sep 17 00:00:00 2001 From: Achim 'ahzf' Friedland Date: Thu, 14 Nov 2019 20:04:38 +0100 Subject: [PATCH 026/110] Add chargepoint zip archive of test data --- .../chargepoint/Testdata/0024b10000027b29_1.zip | Bin 0 -> 6387 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 documentation/chargepoint/Testdata/0024b10000027b29_1.zip diff --git a/documentation/chargepoint/Testdata/0024b10000027b29_1.zip b/documentation/chargepoint/Testdata/0024b10000027b29_1.zip new file mode 100644 index 0000000000000000000000000000000000000000..88d5e99df544e3c23eaf947daa722bb273289241 GIT binary patch literal 6387 zcma)>2UJtp*2ixOp(T_M5D+2sDufUs2q-m#5(!m7kPuozFBTM~8Cob33`$W9y-E`i zM3Jh1=+FcN8Fd5%#Daa)fiKLPZ=AKpnfK0J=bj|@X76*e&hPy9-XYsTpeO(U_yCZC zw?kE!Q%@fET@|-Wa61Nr#Zh%JTMfI5iZ%4s)sFBFop`_lR^5NhVQ+E*Syj#y1KF}Wf}3;%j*0cvoBe5O2YR=*5*>zdR(N9E#nNkY;>F&u6Oq+Har+ojooIoO(;hSO| z6_l847Eo$K@3zC|)!syb0P-IX0szVc3kPjVE3X^`0Jgf}4N;OK5j8u$ZrY4sjn7~j-qa7MXjEHDb>1Z()NMRbZq4rfB0)G;Edl?m!rBKE>p zS|Y}6$5fD#NUW2_Go{ZWVxi!(L3gHf;uuezKapdDf3`G8tA{_aIjfXUBtoGCA0eV& zicKyE3>xk4(|h=2;l6vpTP&O^Af~4x+FZ9=c8p$D;C#^inP(lJ?gLkk=+vOc1glrM zP3U}FM$^sT?{HM%1| zq`6VDgE_l;iMyBDXFvif@joE`O6(WN-|Vi>Z`6-T&Fd~9lF|PweoTx zPuXVnnYBV##MqtoS-*h~=j*RB#*H5+O*I@fsMKKQTGfi@pLcM8*!Z+PX_-D_vQ(WY zEGw&1WK zeCp}L{`rphodcb(rcF>jrO@6>hMS~z@O zD!io1C2p&4Ez-YlAAeA1fcs7z*+0sgL=XEraQP!-1OWEi-25gA_#Q{Ze>J+b@oMwa z<_j7>nFp01FX)M8qebM?n5N)IumH*deNRv zlQ1~?K5M0x-_m|^JQOwgt*W}1V`9pk5eyd#zlLpSyJ2Rt&(42B;ZtMV@Htnn%I*>GK~5CM98fi|#8s;5mJu$ynWZeA^={PB-Fc;c?APhs zm`*;61>a#kS}RWmOk*dir=W#$->BIhM&}FYJm&Fcocf{Wt+^iRhBfEto~F7Wm8A}$ zsg?5QE+$FWjb51TSg_Srdd?FgW1dU6qBPlF<425|Xf;=nuQhvk`F5MYRT?bKbbzO~ zqVBt76j6QszdrYmJ?Ej9H`MA?^_ESWljce@4wWFgPMo&U%Qw0fuT?Px<^ z^GStXXTiNUl=5k+5j5aY0VSAir)6NZy#G?+!Q-~b89K2Lo4uQ?;EuQQL!8QhyX1Y^ zy;fM+Vieq`sXAmUWWQ8jU!$CN@Tr@JS|MIfjP+C3!sU6!EWZrK)-BxdW8@+qO2jzj zntq9URD}tcIK!@x4SI|9adgt9R?w5G&J4u7Em~_;^@B(14Q7^h`FSpsde6e&VC|JD=qz_Q-!r0EA{cl8L5vjnMxIo(zyv0a%yrM{IsEI;jVFd+t#Ds$#%okjQKCKO?;OOQGb zqkc}DMAu;`&%%m?53#~X;Uo&2K}LuRfyjGEh1&tP?%)f@FMX zM}UQ=*BL_RrJk5aEH`Z$Qo&Dc>ZAUi!Zql&riQwM9s5Q5jg{vsAK8lBChURR#s*m= zXpQ_lrUZc%y2yjfzUK3=8^e#)FzL?CP3*hdO$(RLTQ^9QmKU|BH;tDfY&2xWP2jqp z!WI=$#@sVBG(u5FOC0s$cNsfnM!psoFm>$bGs)kPe1PqKH=zh*lhA$5>B&30W&Rj5 z0ByE0t<=xBe?dsbb$JAD`T3JFKa>*|CZPd)o=haikgBFhP0P2>t*KQDu@+s7mS@p? zUNMPLg@#uUEx+y5RX=_4?3CgK{Mc;2ZUKTf6=|6>x?Z0op|Px6%RHxCrrPuHx1EJ- z!)Ak=W=h@tuIa{e?5=eB5vjfpILYkC`cnfd@R)JC;H-nQ&auP1MXK9T-tJN5oeSgo z>PnG)L#P28Tg$6Xt^GBZ-nK_-UcMpW@eYb;25V^6qes}J+Zarx>SAbsa&V;QD}LfG zM3A)V4R(X=x6lSNAB9axH+s#!E$xaJw?W&JXlfF(=64Wg;dygIHy95U$OG@Qh6Rd2@`Nb zQ-J2G*&ftYbqp-2i;48z!x3pvq9LmrvC_!d?8+>_>EheT>3UQR{?M-pb7?T^PxF>`GTX67!&z4AcZ~PFhrOH zJ|F-Z0^$!^^Zj=ZBgTE^l_XS9$LZoB`fq<9}m2kL0B@Tfb zuxQ zjldmu;4P^;iepR45dZaV{Ll00wZ{pouA?G@H+PctT4=kio_!&pE&@LEh_3#;z^g&?F zeA^B1A;Kq#&$&&N(eVOZ%64pC<^jjY&)$Ct6f!&V(DT%2$D05gXd zWOG~YF(O%vL6V309bwipewCpA5a{CA^OKR9Ua!{UcY$v1op_sd5XCr4C5Q)_l};`(3Yzq zAXK#d0MzoK6@r#pW5!9#riSkVVJ~E|$FQUw`$6tN^7W<=?R%YW21k}FE32a-=k$RoReUj`0MuBbn~7PXD>u=^}Y{knZv0W>M8@a z=C1kTWKJJy_Eugj0rOZO)t3#^SzK>B?cmQll!&2 zd^@ORO&(?LN$>!-zmCsdWi2*LVqQnB8;v^K1UT`etow$mRzIsMlJGBI@#G|&# zu&talEfuc!3oCbHUbEp<2pbUOS7nxjn!dQ@ys99&@aRU!O}Ve8^jq7oFBNroU_x?K}7EHydrlW z*y>xv{i6osbpPB7w7p#%Tz{|yG{+u%2!I1NH#cM$1h0Y3uDxeAe-~ggG*kotS<1Tr zIZ&901XqCP$GjS@C(Q&gPpBY(OwmfP4+ey#`t=X?V(f=7Kr!QI&gAH@bdU%RH^GgI z6SkCg3vB>evnn9Jisyj1$DbbpEXyLBv+_8a$OIY(OUZ(u0l(1?2x(xH1{n^%(f7?X zcIu{c8hqv2q8TSbz)lTbrU6#@Wwl2RJ2w_|7D=@LDVizx=UjNtV|>yPHA>GhnmZw~NsvG4k?Bj*fi#ynQbg*2a$sPIcTl=$6;qxRj(T z96ZLvw>{Phi`pl~Mk=c8M<4_x>FWquyN3G^`OPv zCvglVQSE0zlif~<=9jc%U7}TNvR%>RLIHzkT^tcg!tm+IUweAe((HtEl^Z}AF47IB zrZa1!!AVJ9k;dBwY;(+X79UOW7DQIW`HJsv*P`;A?ll=Vdlf4z&~pbJg()|CqtCik zcG)yFhxpv+n!Qk$z*7ye4BM)3jJ=1V*bp&cHmlUKdrUIT7QV;e+RoCp51bH{IyaF6 zWmPrr+xzxex1D(O@`ZQu+~Vo1rhCdMF9WrdPc9J?Ci5QDGRiSwLt|+pILUV?|L$<{ zP{)>oPBm<`3tB^3IChPMexy%u^qp+WGTFN&Ugt926%g#1l1oi&bY-Q|6F)6{^A%SI zkgFuv34UF><@%y{xHP9oTY&GfSbP6PSI@9>uQJmbpkw9Q89W^&#gdwuLCwj@y|s;m zBL-fD?$5iMGV`voiaI+J4;`Pmy?sewXvn}c5qaD8sfJd%G2as-&@cthIAcd8 z_4%ZfKFF3$p5Ou&N`hrcai_z}n8X26Fl>?|PzXgRTEY{!1)kBZ%n>pPa06WyF2%YA zp!L&NX@g^xiYf)X)l?j9jN?Zs^utQSQ@O!1uw}=O8#n*nc#tX%wW41$ zd#L?mA>?e@XdEUg(0b?V(4dR*t$1|Eo3_Kj*VOZ6T=i-*M5m|9zs~1h@U>q?lM$6g zw2%-OOijgt8bYeJO}uYJ0_t!i{7O_nDGqDshivQl?D@Dl^V z=y~n z)k; zI43D5DR;)`K_~o13P00!3l<|!`lr%cKU0j``{ztI>_T8-8A`u4!+3{g(HOBAci3m=T#XGT_%ln#_Q zW<@RbL^HM9KD!6sDV~u3JpjI~3`gCA=<4~Wy0IG+3aEVjdKE0&x(uiE(-F-{E~h_? zM5ih1&z{hIj7mEPnIn6P$qYDKYBx1I^_Y*BMt9GM?2INpHt{c`zAux$ Date: Fri, 15 Nov 2019 01:45:28 +0100 Subject: [PATCH 027/110] Allow the current charge detail record to be exported and saved on disc --- src/css/chargy.scss | 67 ++++++++++++++++++++++++++++++++------------- src/index.html | 7 +++-- src/js/chargy.ts | 28 +++++++++---------- src/js/chargyApp.ts | 53 +++++++++++++++++++++++++++++++---- 4 files changed, 114 insertions(+), 41 deletions(-) diff --git a/src/css/chargy.scss b/src/css/chargy.scss index faf0c69..77438b6 100644 --- a/src/css/chargy.scss +++ b/src/css/chargy.scss @@ -721,21 +721,51 @@ body { position: absolute; left: 0px; bottom: 0px; + width: 100%; #backButton { border: 0; - // background-color: #cce5f7; - // padding: 7px 14px 8px 13px; - // border-radius: 50%; + outline: 0; background-color: transparent; - color: #b6d8f1; + color: #b6d8f1; margin: 4px; font-size: 280%; } #backButton:hover { - // background-color: #519ad0; - color: #519ad0; + color: #519ad0; + } + + #downloadButtonDiv { + + flex-grow: 2; + display: none; + flex-direction: row-reverse; + margin-right: 25px; + + #downloadButton { + + color: #b6d8f1; + background-color: transparent; + font-size: 90%; + border: 0; + outline: 0; + position: relative; + top: -2px; + margin-right: 2px; + + i { + font-size: 120%; + position: relative; + top: 1px; + } + + } + + #downloadButton:hover { + color: #519ad0; + } + } } @@ -758,8 +788,8 @@ body { button { border: 0; + outline: 0; padding: 8px 15px; - /*font-size: 120%;*/ border-radius: 4px; box-shadow: 2px 2px 6px #999; } @@ -1050,23 +1080,24 @@ body { a { text-decoration: none; - color: #34668a; + color: #34668a; margin-bottom: 3px; } button { background-color: transparent; - padding: 0px; + padding: 0; + outline: 0; font-weight: bold; font-size: 100%; - color: #34668a; + color: #34668a; border: 0; text-align: left; margin-bottom: 3px; } button:hover, a:hover { - color: rgba(52, 102, 138, 0.6); + color: rgba(52, 102, 138, 0.6); } #eMail { @@ -1097,7 +1128,7 @@ body { position: absolute; font-family: sans-serif; font-size: 90%; - background-color: rgba(0, 0, 0, 0.3); + background-color: rgba(0, 0, 0, 0.3); width: 100vw; height: 100vh; margin: auto; @@ -1111,7 +1142,7 @@ body { height: calc(90% - 50px); margin: auto; padding: 1px; - background-color: #f5f5f5; + background-color: #f5f5f5; border: 20px solid #f5f5f5; border-radius: 6px; box-shadow: 2px 0 16px 0 rgba(0,0,0,.3); @@ -1180,7 +1211,7 @@ body { position: relative; top: 8px; left: 10px; - background-color: #98c3e2; + background-color: #98c3e2; display: inline-block; padding: 1px 6px; border-radius: 4px; @@ -1189,7 +1220,7 @@ body { .value { overflow-wrap: break-word; - background-color: #E1E1E1; + background-color: #E1E1E1; border-radius: 4px; padding: 11px 10px 6px 10px; width: calc(100% - 20px); @@ -1209,11 +1240,11 @@ body { } .entry:hover { - background-color: orange; + background-color: orange; } .overEntry { - background-color: orange; + background-color: orange; } } @@ -1242,8 +1273,6 @@ body { color: #6d6d6d; i { - // position: relative; - // top: 0px; padding: 0px 3px 0px 10px; } diff --git a/src/index.html b/src/index.html index 775e896..08a3c76 100644 --- a/src/index.html +++ b/src/index.html @@ -76,8 +76,8 @@
Sie können den Transparenzdatensatz zu Ihren Ladevorgängen entweder aus - einer Datei laden, über die Zwischenablage einfügen oder Drag'n'Drop - verwenden...
+ einer Datei laden, über die Zwischenablage einfügen oder Drag'n'Drop + verwenden...
@@ -216,6 +216,9 @@
+
+ +
diff --git a/src/js/chargy.ts b/src/js/chargy.ts index 1448ca5..f2e59d8 100644 --- a/src/js/chargy.ts +++ b/src/js/chargy.ts @@ -37,6 +37,7 @@ class Chargy { private mediationServices = new Array(); public currentCTR = {} as IChargeTransparencyRecord; + public internalCTR = {} as IChargeTransparencyRecord; //#endregion @@ -557,7 +558,7 @@ class Chargy { //#endregion - //region mergeChargeTransparencyRecord(CTRs) + //#region mergeChargeTransparencyRecord(CTRs) public async mergeChargeTransparencyRecords(CTRs: Array): Promise { @@ -695,7 +696,8 @@ class Chargy { this.eMobilityProviders = []; this.mediationServices = []; - this.currentCTR = {} as IChargeTransparencyRecord; + this.currentCTR = CTR; + this.internalCTR = JSON.parse(JSON.stringify(CTR)); // Operate on a copy of the data! //#endregion @@ -706,10 +708,10 @@ class Chargy { //#region Process operators (pools, stations, evses, tariffs, ...) - if (CTR.chargingStationOperators) + if (this.internalCTR.chargingStationOperators) { - for (var chargingStationOperator of CTR.chargingStationOperators) + for (var chargingStationOperator of this.internalCTR.chargingStationOperators) { this.chargingStationOperators.push(chargingStationOperator); @@ -850,9 +852,9 @@ class Chargy { //#region Process pools ( stations, evses, tariffs, ...) - if (CTR.chargingPools) { + if (this.internalCTR.chargingPools) { - for (var chargingPool of CTR.chargingPools) + for (var chargingPool of this.internalCTR.chargingPools) { this.chargingPools.push(chargingPool); @@ -891,9 +893,9 @@ class Chargy { //#region Process stations ( evses, tariffs, ...) - if (CTR.chargingStations) { + if (this.internalCTR.chargingStations) { - for (var chargingStation of CTR.chargingStations) + for (var chargingStation of this.internalCTR.chargingStations) { this.chargingStations.push(chargingStation); @@ -949,19 +951,17 @@ class Chargy { //#endregion - if (CTR.chargingSessions) + if (this.internalCTR.chargingSessions) { - for (let chargingSession of CTR.chargingSessions) + for (let chargingSession of this.internalCTR.chargingSessions) { - chargingSession.ctr = CTR; + chargingSession.ctr = this.internalCTR; chargingSession.verificationResult = await this.processChargingSession(chargingSession); this.chargingSessions.push(chargingSession); } } - this.currentCTR = CTR; - - return CTR; + return this.internalCTR; } catch (exception) diff --git a/src/js/chargyApp.ts b/src/js/chargyApp.ts index 7b03d23..2d0d9bf 100644 --- a/src/js/chargyApp.ts +++ b/src/js/chargyApp.ts @@ -73,6 +73,9 @@ class ChargyApp { private chargySHA512Div: HTMLDivElement; private chargingSessionScreenDiv: HTMLDivElement; private backButtonDiv: HTMLDivElement; + private backButton: HTMLButtonElement; + private downloadButtonDiv: HTMLDivElement; + private downloadButton: HTMLButtonElement; private fileInputButton: HTMLButtonElement; private fileInput: HTMLInputElement; private evseTarifInfosDiv: HTMLDivElement; @@ -393,6 +396,7 @@ class ChargyApp { this.aboutScreenDiv.style.display = "none"; this.chargingSessionScreenDiv.style.display = "none"; this.backButtonDiv.style.display = "block"; + this.downloadButtonDiv.style.display = "none"; } //#endregion @@ -407,6 +411,7 @@ class ChargyApp { this.aboutScreenDiv.style.display = "block"; this.chargingSessionScreenDiv.style.display = "none"; this.backButtonDiv.style.display = "block"; + this.downloadButtonDiv.style.display = "none"; //#region Calculate the over-all application hash @@ -596,7 +601,10 @@ class ChargyApp { data["description"] = (newIssueForm.querySelector("#issueDescription") as HTMLTextAreaElement).value; if ((newIssueForm.querySelector("#includeCTR") as HTMLSelectElement).value == "yes") - data["chargeTransparencyRecord"] = this.chargy.currentCTR; + { + let stringify = require('safe-stable-stringify'); + data["chargeTransparencyRecord"] = stringify(this.chargy.currentCTR); + } data["name"] = (newIssueForm.querySelector("#issueName") as HTMLInputElement).value; data["phone"] = (newIssueForm.querySelector("#issuePhone") as HTMLInputElement).value; @@ -650,16 +658,18 @@ class ChargyApp { //#endregion - //#region Handle the 'Back'-button + //#region Handle the 'back'-button this.backButtonDiv = document.getElementById('backButtonDiv'); - this.backButtonDiv.onclick = (ev: MouseEvent) => { + this.backButton = this.backButtonDiv.querySelector("#backButton") as HTMLButtonElement; + this.backButton.onclick = (ev: MouseEvent) => { this.updateAvailableScreen.style.display = "none"; this.inputInfosDiv.style.display = 'flex'; this.aboutScreenDiv.style.display = "none"; this.chargingSessionScreenDiv.style.display = "none"; this.backButtonDiv.style.display = "none"; + this.downloadButtonDiv.style.display = "none"; this.fileInput.value = ""; this.evseTarifInfosDiv.innerHTML = ""; @@ -676,6 +686,36 @@ class ChargyApp { //#endregion + //#region Handle the 'download'-button + + this.downloadButtonDiv = document.getElementById('downloadButtonDiv'); + this.downloadButton = this.downloadButtonDiv.querySelector("#downloadButton") as HTMLButtonElement; + this.downloadButton.onclick = (ev: MouseEvent) => { + + // ev.stopPropagation(); + + try + { + + let electron = require('electron').remote; + let fs = require('original-fs'); + let userChosenPath = electron.dialog.showSaveDialog({ defaultPath: electron.app.getPath("desktop") }); + + if (userChosenPath) + fs.writeFileSync(userChosenPath, + JSON.stringify(this.chargy.currentCTR, null, '\t'), + 'utf-8'); + + } + catch(exception) + { + alert('Failed to save the charge transparency record!'); + } + + } + + //#endregion + //#region Modify external links to be opened in the external web browser var shell = require('electron').shell; @@ -897,7 +937,8 @@ class ChargyApp { this.chargingSessionScreenDiv.style.display = "flex"; this.chargingSessionScreenDiv.innerText = ""; - this.backButtonDiv.style.display = "block"; + this.backButtonDiv.style.display = "flex"; + this.downloadButtonDiv.style.display = "flex"; //#endregion @@ -1466,8 +1507,8 @@ class ChargyApp { } - // If there is only one charging session show its details at once... - if (CTR.chargingSessions.length == 1) + // If there is at least one charging session show its details at once... + if (CTR.chargingSessions.length >= 1) CTR.chargingSessions[0].GUI.click(); map.fitBounds([[this.minlat, this.minlng], [this.maxlat, this.maxlng]], From 3637c08c850cab36c79f238781874f704e15ac33 Mon Sep 17 00:00:00 2001 From: Achim 'ahzf' Friedland Date: Sat, 16 Nov 2019 10:19:39 +0100 Subject: [PATCH 028/110] OpenSSL scripts for chargepoint signatures added (secp224k1 workaround) --- .../Testdata/0024b10000027b29_1.verify.sh | 3 + documentation/chargepoint/Testdata/genKeys.sh | 8 +++ .../Testdata/showPublicKeyInfos.sh | 4 ++ documentation/chargepoint/Testdata/sign.sh | 4 ++ documentation/chargepoint/Testdata/test.txt | 8 +++ .../chargepoint/Testdata/test.txt.sign | Bin 0 -> 71 bytes .../Testdata/testbox1-parameters.pem | 3 + .../Testdata/testbox1-privateKey.pem | 5 ++ .../Testdata/testbox1-publicKey.pem | 4 ++ documentation/chargepoint/Testdata/verify.sh | 4 ++ src/index.html | 2 +- src/js/chargepoint.ts | 8 +-- src/js/chargepointCrypt01.ts | 67 +++++++++++++++++- src/js/chargyApp.ts | 3 + src/js/chargyInterfaces.ts | 1 + 15 files changed, 116 insertions(+), 8 deletions(-) create mode 100644 documentation/chargepoint/Testdata/0024b10000027b29_1.verify.sh create mode 100644 documentation/chargepoint/Testdata/genKeys.sh create mode 100644 documentation/chargepoint/Testdata/showPublicKeyInfos.sh create mode 100644 documentation/chargepoint/Testdata/sign.sh create mode 100644 documentation/chargepoint/Testdata/test.txt create mode 100644 documentation/chargepoint/Testdata/test.txt.sign create mode 100644 documentation/chargepoint/Testdata/testbox1-parameters.pem create mode 100644 documentation/chargepoint/Testdata/testbox1-privateKey.pem create mode 100644 documentation/chargepoint/Testdata/testbox1-publicKey.pem create mode 100644 documentation/chargepoint/Testdata/verify.sh diff --git a/documentation/chargepoint/Testdata/0024b10000027b29_1.verify.sh b/documentation/chargepoint/Testdata/0024b10000027b29_1.verify.sh new file mode 100644 index 0000000..8f096ce --- /dev/null +++ b/documentation/chargepoint/Testdata/0024b10000027b29_1.verify.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +openssl dgst -sha256 -verify 0024b10000027b29_1.pem -signature 0024b10000027b29_1_121708795_payload.FLAT_SESSION/secrrct.sign 0024b10000027b29_1_121708795_payload.FLAT_SESSION/secrrct diff --git a/documentation/chargepoint/Testdata/genKeys.sh b/documentation/chargepoint/Testdata/genKeys.sh new file mode 100644 index 0000000..b2f5643 --- /dev/null +++ b/documentation/chargepoint/Testdata/genKeys.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +#openssl ecparam -list_curves +openssl ecparam -name secp256k1 -out $1-parameters.pem +#openssl ecparam -in secp256k1.pem -text -param_enc explicit -noout +openssl ecparam -name secp256k1 -genkey -noout -out $1-privateKey.pem +#openssl ec -in secp256k1-privateKey.pem -text -noout +openssl ec -in $1-privateKey.pem -pubout -out $1-publicKey.pem diff --git a/documentation/chargepoint/Testdata/showPublicKeyInfos.sh b/documentation/chargepoint/Testdata/showPublicKeyInfos.sh new file mode 100644 index 0000000..23cbab6 --- /dev/null +++ b/documentation/chargepoint/Testdata/showPublicKeyInfos.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +#openssl ec -inform PEM -pubin -in 0024b10000027b29_1.pem -text -noout +openssl pkey -inform PEM -pubin -in $1 -text -noout diff --git a/documentation/chargepoint/Testdata/sign.sh b/documentation/chargepoint/Testdata/sign.sh new file mode 100644 index 0000000..c933873 --- /dev/null +++ b/documentation/chargepoint/Testdata/sign.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +echo "$1 -> $1.sign using private key file $2" +openssl dgst -sha256 -sign $2 $1 > $1.sign diff --git a/documentation/chargepoint/Testdata/test.txt b/documentation/chargepoint/Testdata/test.txt new file mode 100644 index 0000000..2447e8a --- /dev/null +++ b/documentation/chargepoint/Testdata/test.txt @@ -0,0 +1,8 @@ +Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test +Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test +Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test +Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test +Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test +Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test +Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test +Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test diff --git a/documentation/chargepoint/Testdata/test.txt.sign b/documentation/chargepoint/Testdata/test.txt.sign new file mode 100644 index 0000000000000000000000000000000000000000..efa94919c8497f0cf4c2ef3573c6f4ee9167c2e7 GIT binary patch literal 71 zcmV-N0J#4!MFJrJ)e_Quylq8#_Z!HwbWr|ZxG?h_f`FnS7ohpYzcO|q0w6<5_Kvom d_aI2FK%W|3=F+l9?w-Fu=6!mQG1m*6N2r&!B2fSU literal 0 HcmV?d00001 diff --git a/documentation/chargepoint/Testdata/testbox1-parameters.pem b/documentation/chargepoint/Testdata/testbox1-parameters.pem new file mode 100644 index 0000000..32d952e --- /dev/null +++ b/documentation/chargepoint/Testdata/testbox1-parameters.pem @@ -0,0 +1,3 @@ +-----BEGIN EC PARAMETERS----- +BgUrgQQACg== +-----END EC PARAMETERS----- diff --git a/documentation/chargepoint/Testdata/testbox1-privateKey.pem b/documentation/chargepoint/Testdata/testbox1-privateKey.pem new file mode 100644 index 0000000..e6fbfb1 --- /dev/null +++ b/documentation/chargepoint/Testdata/testbox1-privateKey.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHQCAQEEIGxpehQPVKTZrtkX5PQIvzAxxwQSx8sgu2d4qb6ydwYroAcGBSuBBAAK +oUQDQgAEx07RoGSzlEVC/bhGBGP/pmQ2H+lsWP8jQ1mlMBHOOuJfgSs2agKtmpIL +YbzI3ruxyX2cyCGS1GFQWQ2pSHaxJA== +-----END EC PRIVATE KEY----- diff --git a/documentation/chargepoint/Testdata/testbox1-publicKey.pem b/documentation/chargepoint/Testdata/testbox1-publicKey.pem new file mode 100644 index 0000000..7ed51dc --- /dev/null +++ b/documentation/chargepoint/Testdata/testbox1-publicKey.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEx07RoGSzlEVC/bhGBGP/pmQ2H+lsWP8j +Q1mlMBHOOuJfgSs2agKtmpILYbzI3ruxyX2cyCGS1GFQWQ2pSHaxJA== +-----END PUBLIC KEY----- diff --git a/documentation/chargepoint/Testdata/verify.sh b/documentation/chargepoint/Testdata/verify.sh new file mode 100644 index 0000000..69ffaa4 --- /dev/null +++ b/documentation/chargepoint/Testdata/verify.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +echo "Trying to verify $1 via signature $1.sign and public key file $2" +openssl dgst -sha256 -verify $2 -signature $1.sign $1 diff --git a/src/index.html b/src/index.html index 08a3c76..5e75b14 100644 --- a/src/index.html +++ b/src/index.html @@ -136,7 +136,7 @@
-
elliptic 6.5.0
+
elliptic 6.5.1
diff --git a/src/js/chargepoint.ts b/src/js/chargepoint.ts index d6e436c..4e4da64 100644 --- a/src/js/chargepoint.ts +++ b/src/js/chargepoint.ts @@ -371,10 +371,10 @@ class Chargepoint { "scale": 0, "signatureInfos": { - "hash": "SHA512", - "hashTruncation": "24", - "algorithm": "ECC", - "curve": "secp192r1", + "hash": "SHA256", + // "hashTruncation": "24", + "algorithm": "ECDSA", + "curve": "secp224k1", "format": "rs" }, diff --git a/src/js/chargepointCrypt01.ts b/src/js/chargepointCrypt01.ts index f3aa73a..407b271 100644 --- a/src/js/chargepointCrypt01.ts +++ b/src/js/chargepointCrypt01.ts @@ -54,13 +54,46 @@ interface IChargepointCrypt01Result extends ICryptoResult class ChargepointCrypt01 extends ACrypt { - readonly curve = new this.chargy.elliptic.ec('p192'); + readonly curve = new this.chargy.elliptic.ec('secp224k1'); + // Koblitz 224-bit curve + // https://www.secg.org/sec2-v2.pdf + // this.chargy.elliptic.defineCurve('secp224k1', { + // type: 'short', + // prime: 'k224', + // p: 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFE56D', + // a: '00000000 00000000 00000000 00000000 00000000 00000000 00000000', + // b: '00000000 00000000 00000000 00000000 00000000 00000000 00000005', + // n: '00000000 00000000 00000000 0001DCE8 D2EC6184 CAF0A971 769FB1F7', + // h: 1, + // hash: this.chargy.elliptic.hash.sha512, + // gRed: false, + // g: [ + // 'A1455B33 4DF099DF 30FC28A1 69A467E9 E47075A9 0F7E650E B6B7A45C', + // '7E089FED 7FBA3442 82CAFBD6 F7E319F7 C0B0BD59 E2CA4BDB 556D61A5' + // ] + // }); constructor(chargy: Chargy) { - super("ECC secp192r1", + super("ECC secp224k1", chargy); + // defineCurve('p224', { + // type: 'short', + // prime: 'p224', + // p: 'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001', + // a: 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff fffffffe', + // b: 'b4050a85 0c04b3ab f5413256 5044b0b7 d7bfd8ba 270b3943 2355ffb4', + // n: 'ffffffff ffffffff ffffffff ffff16a2 e0b8f03e 13dd2945 5c5c2a3d', + // hash: hash.sha256, + // gRed: false, + // g: [ + // 'b70e0cbd 6bb4bf7f 321390b9 4a03c1d3 56c21122 343280d6 115c1d21', + // 'bd376388 b5f723fb 4c22dfe6 cd4375a0 5a074764 44d58199 85007e34' + // ] + //}); + + } @@ -87,7 +120,35 @@ class ChargepointCrypt01 extends ACrypt { async VerifyChargingSession(chargingSession: IChargingSession): Promise { - var sessionResult = SessionVerificationResult.UnknownSessionFormat; + // $ openssl ec -inform PEM -pubin -in 0024b10000027b29_1.pem -text -noout + // Public-Key: (225 bit) + // pub: + // 04:f6:b9:4d:1d:0d:4c:95:24:41:b9:44:34:ac:41: + // 3b:0c:3d:97:ee:e7:f1:19:36:9c:ac:3a:07:a2:e8: + // 12:98:f4:2f:f6:eb:f1:2d:de:16:e1:b5:7d:a1:12: + // 13:45:70:21:1d:c7:a9:f3:48:9a:e1:a4 + // ASN1 OID: secp224k1 + // read EC key + + let sessionResult = SessionVerificationResult.UnknownSessionFormat; + + let publicKeyId = chargingSession.EVSEId.replace(/:/g, "").replace(/-/g, "_"); + let publicKey = ""; + if (chargingSession.ctr?.publicKeys != null) + { + for (let publicKeyInfo of chargingSession.ctr?.publicKeys) + { + if (publicKeyInfo.keyId === publicKeyId) + publicKey = publicKeyInfo.value; + } + } + + var plainText = chargingSession.rawData; + + if (publicKey != null && plainText != null) + { + sessionResult = SessionVerificationResult.ValidSignature; + } if (chargingSession.measurements) { diff --git a/src/js/chargyApp.ts b/src/js/chargyApp.ts index 2d0d9bf..000da2b 100644 --- a/src/js/chargyApp.ts +++ b/src/js/chargyApp.ts @@ -102,6 +102,9 @@ class ChargyApp { this.chargy = new Chargy(this.elliptic, this.moment); + const curves = require("crypto").getCurves(); +console.log(curves); + //#region Calculate application hash switch (process.platform) diff --git a/src/js/chargyInterfaces.ts b/src/js/chargyInterfaces.ts index c9749ee..031013e 100644 --- a/src/js/chargyInterfaces.ts +++ b/src/js/chargyInterfaces.ts @@ -231,6 +231,7 @@ interface IChargingSession measurements: Array; parking: Array; method: ACrypt; + rawData?: string; verificationResult?: ISessionCryptoResult; } From e0b474c1b489bae0c7a0a7c4c5c9d4c90c8faeea Mon Sep 17 00:00:00 2001 From: Achim 'ahzf' Friedland Date: Sat, 16 Nov 2019 10:32:30 +0100 Subject: [PATCH 029/110] Switch to SECG secp256r1/ANSI prime256v1/NIST P-256 for chargepoint workaround --- documentation/chargepoint/Testdata/genKeys.sh | 10 ++++++---- documentation/chargepoint/Testdata/test.sign | 0 documentation/chargepoint/Testdata/test.txt.sign | Bin 71 -> 71 bytes .../chargepoint/Testdata/testbox1-parameters.pem | 2 +- .../chargepoint/Testdata/testbox1-privateKey.pem | 6 +++--- .../chargepoint/Testdata/testbox1-publicKey.pem | 4 ++-- 6 files changed, 12 insertions(+), 10 deletions(-) create mode 100644 documentation/chargepoint/Testdata/test.sign diff --git a/documentation/chargepoint/Testdata/genKeys.sh b/documentation/chargepoint/Testdata/genKeys.sh index b2f5643..16fd0c0 100644 --- a/documentation/chargepoint/Testdata/genKeys.sh +++ b/documentation/chargepoint/Testdata/genKeys.sh @@ -1,8 +1,10 @@ #!/bin/bash #openssl ecparam -list_curves -openssl ecparam -name secp256k1 -out $1-parameters.pem -#openssl ecparam -in secp256k1.pem -text -param_enc explicit -noout -openssl ecparam -name secp256k1 -genkey -noout -out $1-privateKey.pem -#openssl ec -in secp256k1-privateKey.pem -text -noout + +echo "Generating a private/public key for $1 using SECG secp256r1/ANSI prime256v1/NIST P-256" +openssl ecparam -name secp256r1 -out $1-parameters.pem +openssl ecparam -in $1-parameters.pem -text -param_enc explicit -noout +openssl ecparam -name secp256r1 -genkey -noout -out $1-privateKey.pem +openssl ec -in $1-privateKey.pem -text -noout openssl ec -in $1-privateKey.pem -pubout -out $1-publicKey.pem diff --git a/documentation/chargepoint/Testdata/test.sign b/documentation/chargepoint/Testdata/test.sign new file mode 100644 index 0000000..e69de29 diff --git a/documentation/chargepoint/Testdata/test.txt.sign b/documentation/chargepoint/Testdata/test.txt.sign index efa94919c8497f0cf4c2ef3573c6f4ee9167c2e7..86fd9ec55f84f9a121b35593fbcf05c14e26a62d 100644 GIT binary patch literal 71 zcmV-N0J#4!MFJpi6B#C>=y>vL&FfRO@12%HW!B@$QZTvO$9tt#v2tVrAppa}i%*^Y de_HO`Tf;;E{&1n*Pon@LoPCLyk5W^h&(-qsBy|7) literal 71 zcmV-N0J#4!MFJrJ)e_Quylq8#_Z!HwbWr|ZxG?h_f`FnS7ohpYzcO|q0w6<5_Kvom d_aI2FK%W|3=F+l9?w-Fu=6!mQG1m*6N2r&!B2fSU diff --git a/documentation/chargepoint/Testdata/testbox1-parameters.pem b/documentation/chargepoint/Testdata/testbox1-parameters.pem index 32d952e..a76e47d 100644 --- a/documentation/chargepoint/Testdata/testbox1-parameters.pem +++ b/documentation/chargepoint/Testdata/testbox1-parameters.pem @@ -1,3 +1,3 @@ -----BEGIN EC PARAMETERS----- -BgUrgQQACg== +BggqhkjOPQMBBw== -----END EC PARAMETERS----- diff --git a/documentation/chargepoint/Testdata/testbox1-privateKey.pem b/documentation/chargepoint/Testdata/testbox1-privateKey.pem index e6fbfb1..5842985 100644 --- a/documentation/chargepoint/Testdata/testbox1-privateKey.pem +++ b/documentation/chargepoint/Testdata/testbox1-privateKey.pem @@ -1,5 +1,5 @@ -----BEGIN EC PRIVATE KEY----- -MHQCAQEEIGxpehQPVKTZrtkX5PQIvzAxxwQSx8sgu2d4qb6ydwYroAcGBSuBBAAK -oUQDQgAEx07RoGSzlEVC/bhGBGP/pmQ2H+lsWP8jQ1mlMBHOOuJfgSs2agKtmpIL -YbzI3ruxyX2cyCGS1GFQWQ2pSHaxJA== +MHcCAQEEIGWgcrZT6Pa1AdVDlWQ7BMfusZool1V/zoXalnVE7otDoAoGCCqGSM49 +AwEHoUQDQgAE+P+5XA+m5hJi+0P/6bQG1QEjNKbSPQmx7cuPj418qaocYFLiHgsZ +hr9dfNuKgG0kNsM04505HJ8NUM9N96AqLQ== -----END EC PRIVATE KEY----- diff --git a/documentation/chargepoint/Testdata/testbox1-publicKey.pem b/documentation/chargepoint/Testdata/testbox1-publicKey.pem index 7ed51dc..82714b8 100644 --- a/documentation/chargepoint/Testdata/testbox1-publicKey.pem +++ b/documentation/chargepoint/Testdata/testbox1-publicKey.pem @@ -1,4 +1,4 @@ -----BEGIN PUBLIC KEY----- -MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEx07RoGSzlEVC/bhGBGP/pmQ2H+lsWP8j -Q1mlMBHOOuJfgSs2agKtmpILYbzI3ruxyX2cyCGS1GFQWQ2pSHaxJA== +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE+P+5XA+m5hJi+0P/6bQG1QEjNKbS +PQmx7cuPj418qaocYFLiHgsZhr9dfNuKgG0kNsM04505HJ8NUM9N96AqLQ== -----END PUBLIC KEY----- From 48312499a6f9f29f43cba2752c0106137abb7c03 Mon Sep 17 00:00:00 2001 From: Achim 'ahzf' Friedland Date: Sat, 16 Nov 2019 12:26:06 +0100 Subject: [PATCH 030/110] Resign all chargepoint test data with secp256r1 --- documentation/REBUILD.md | 8 +- .../0024b10000027b29_1-parameters.pem} | 0 .../0024b10000027b29_1-privateKey.pem | 5 + .../0024b10000027b29_1-publicKey.pem | 4 + ...9_1_121708795_payload.FLAT_SESSION.tar.bz2 | Bin 0 -> 816 bytes .../secrrct | 56 ++++++++++++ .../secrrct.sign | Bin 0 -> 71 bytes ...027b29_1_121708845_payload.Per_Min.tar.bz2 | Bin 0 -> 827 bytes .../secrrct | 56 ++++++++++++ .../secrrct.sign | Bin 0 -> 71 bytes ...27b29_1_121709375_payload._Per_KWh.tar.bz2 | Bin 0 -> 819 bytes .../secrrct | 56 ++++++++++++ .../secrrct.sign | Bin 0 -> 71 bytes ...1_121709405_payload_Min_Variation_.tar.bz2 | Bin 0 -> 977 bytes .../secrrct | 86 ++++++++++++++++++ .../secrrct.sign | Bin 0 -> 71 bytes ...00027b29_1_121709415_payload._TOU_.tar.bz2 | Bin 0 -> 829 bytes .../secrrct | 56 ++++++++++++ .../secrrct.sign | Bin 0 -> 72 bytes ...09465_payload_Parking_Tap_ToCharge.tar.bz2 | Bin 0 -> 826 bytes .../secrrct | 56 ++++++++++++ .../secrrct.sign | Bin 0 -> 72 bytes .../0024b1000002e300_2-parameters.pem | 3 + .../0024b1000002e300_2-privateKey.pem | 5 + .../0024b1000002e300_2-publicKey.pem | 4 + ...24b1000002e300_2_119693895_payload.tar.bz2 | Bin 0 -> 998 bytes .../secrrct | 85 +++++++++++++++++ .../secrrct.sign | Bin 0 -> 70 bytes .../Testdata-secp256r1/Testdata-secp256r1.zip | Bin 0 -> 8318 bytes .../genKeys.sh | 0 .../showPublicKeyInfos.sh | 0 .../{Testdata => Testdata-secp256r1}/sign.sh | 0 .../chargepoint/Testdata-secp256r1/tar.sh | 6 ++ .../{Testdata => Testdata-secp256r1}/test.txt | 0 .../verify.sh | 0 documentation/chargepoint/Testdata/test.sign | 0 .../chargepoint/Testdata/test.txt.sign | Bin 71 -> 0 bytes .../Testdata/testbox1-privateKey.pem | 5 - .../Testdata/testbox1-publicKey.pem | 4 - package-lock.json | 56 ++++++++---- package.json | 10 +- src/js/chargepointCrypt01.ts | 4 +- 42 files changed, 525 insertions(+), 40 deletions(-) rename documentation/chargepoint/{Testdata/testbox1-parameters.pem => Testdata-secp256r1/0024b10000027b29_1-parameters.pem} (100%) create mode 100644 documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1-privateKey.pem create mode 100644 documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1-publicKey.pem create mode 100644 documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121708795_payload.FLAT_SESSION.tar.bz2 create mode 100644 documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121708795_payload.FLAT_SESSION/secrrct create mode 100644 documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121708795_payload.FLAT_SESSION/secrrct.sign create mode 100644 documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121708845_payload.Per_Min.tar.bz2 create mode 100644 documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121708845_payload.Per_Min/secrrct create mode 100644 documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121708845_payload.Per_Min/secrrct.sign create mode 100644 documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121709375_payload._Per_KWh.tar.bz2 create mode 100644 documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121709375_payload._Per_KWh/secrrct create mode 100644 documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121709375_payload._Per_KWh/secrrct.sign create mode 100644 documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121709405_payload_Min_Variation_.tar.bz2 create mode 100644 documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121709405_payload_Min_Variation_/secrrct create mode 100644 documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121709405_payload_Min_Variation_/secrrct.sign create mode 100644 documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121709415_payload._TOU_.tar.bz2 create mode 100644 documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121709415_payload._TOU_/secrrct create mode 100644 documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121709415_payload._TOU_/secrrct.sign create mode 100644 documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121709465_payload_Parking_Tap_ToCharge.tar.bz2 create mode 100644 documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121709465_payload_Parking_Tap_ToCharge/secrrct create mode 100644 documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121709465_payload_Parking_Tap_ToCharge/secrrct.sign create mode 100644 documentation/chargepoint/Testdata-secp256r1/0024b1000002e300_2-parameters.pem create mode 100644 documentation/chargepoint/Testdata-secp256r1/0024b1000002e300_2-privateKey.pem create mode 100644 documentation/chargepoint/Testdata-secp256r1/0024b1000002e300_2-publicKey.pem create mode 100644 documentation/chargepoint/Testdata-secp256r1/0024b1000002e300_2_119693895_payload.tar.bz2 create mode 100644 documentation/chargepoint/Testdata-secp256r1/0024b1000002e300_2_119693895_payload/secrrct create mode 100644 documentation/chargepoint/Testdata-secp256r1/0024b1000002e300_2_119693895_payload/secrrct.sign create mode 100644 documentation/chargepoint/Testdata-secp256r1/Testdata-secp256r1.zip rename documentation/chargepoint/{Testdata => Testdata-secp256r1}/genKeys.sh (100%) rename documentation/chargepoint/{Testdata => Testdata-secp256r1}/showPublicKeyInfos.sh (100%) rename documentation/chargepoint/{Testdata => Testdata-secp256r1}/sign.sh (100%) create mode 100644 documentation/chargepoint/Testdata-secp256r1/tar.sh rename documentation/chargepoint/{Testdata => Testdata-secp256r1}/test.txt (100%) rename documentation/chargepoint/{Testdata => Testdata-secp256r1}/verify.sh (100%) delete mode 100644 documentation/chargepoint/Testdata/test.sign delete mode 100644 documentation/chargepoint/Testdata/test.txt.sign delete mode 100644 documentation/chargepoint/Testdata/testbox1-privateKey.pem delete mode 100644 documentation/chargepoint/Testdata/testbox1-publicKey.pem diff --git a/documentation/REBUILD.md b/documentation/REBUILD.md index 8bceeb0..e8c96b4 100644 --- a/documentation/REBUILD.md +++ b/documentation/REBUILD.md @@ -19,10 +19,10 @@ $ npm install typescript@latest --save-dev + typescript@3.7.2 $ npm install sass@latest --save-dev -+ sass@1.23.3 ++ sass@1.23.6 $ npm install @types/node@latest --save-dev -+ @types/node@12.12.7 ++ @types/node@12.12.8 $ npm install elliptic@latest + elliptic@6.5.1 @@ -55,10 +55,10 @@ $ npm install decompress-gz@latest + decompress-gz@0.0.1 $ npm install chart.js@latest -+ chart.js@2.9.1 ++ chart.js@2.9.3 $ npm install @types/chart.js@latest --save-dev -+ @types/chart.js@2.8.9 ++ @types/chart.js@2.9.0 ``` diff --git a/documentation/chargepoint/Testdata/testbox1-parameters.pem b/documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1-parameters.pem similarity index 100% rename from documentation/chargepoint/Testdata/testbox1-parameters.pem rename to documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1-parameters.pem diff --git a/documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1-privateKey.pem b/documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1-privateKey.pem new file mode 100644 index 0000000..1e3e41f --- /dev/null +++ b/documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1-privateKey.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIMqm8LW7wkj5IllH7Dox6tGc0o4tF6ifIyqZ+WDRc19xoAoGCCqGSM49 +AwEHoUQDQgAEhPaA1TxBxFzyP9xN/iM0MpxvLwobD3YLuhtRZl0E8CtFTND0iWxq +dvL+L31zAcFLGDHe50SjLuX8yXM/CtEMqA== +-----END EC PRIVATE KEY----- diff --git a/documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1-publicKey.pem b/documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1-publicKey.pem new file mode 100644 index 0000000..4951119 --- /dev/null +++ b/documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1-publicKey.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEhPaA1TxBxFzyP9xN/iM0MpxvLwob +D3YLuhtRZl0E8CtFTND0iWxqdvL+L31zAcFLGDHe50SjLuX8yXM/CtEMqA== +-----END PUBLIC KEY----- diff --git a/documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121708795_payload.FLAT_SESSION.tar.bz2 b/documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121708795_payload.FLAT_SESSION.tar.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..2cfd4df3ef51dcd8d1f345da6c5e926f5457793d GIT binary patch literal 816 zcmV-01JC?IT4*^jL0KkKS-7LqQvd>$fB*d03K)4EfBHYK{_6k#|L-V(5P(L6KmZ6J zaUuYL04Tr$-Nv^rU=V2t(k9Xvng&3~G-;DV)D1EQfule)*r4?WnlfZJstH6U5YaT7 zQ68tMqtqGz01O~B00006jDP_ts8kvN4FCZ2fM@_313&-(000dDl$6?;CiN$%G9IAF z4AdC_13+j7ni>N^qd))|C((GSP&%LjCv$*^7vzD#Md^ICkU`;A>W-iSWY!#=*PWYv zBtlFiFeFPzx4KF2Ku2hOI{k|N*rrE0h?p6`lO{p{VfdzNKN)hN&8pLRR4^VI0W2-q5ZKm?=<1W&fJn zMIf?f z+XvYUIw-Ux#r$wX6_m)Z-QaH8<5oiWGd#js4+sdd`HP=2ClKy1l_!=JP4OJ-r3v~Z zq*F@^O)|i7X-K9Pn%eO~YPzgDqXs2uV8qr|>1k|Kq0V{beAU9gPXjH$SUIuORub=Z zSU)>#*}{a*z6z0>j|Gu)hK@E3?kG`Fg=3JCL$st?)zHTT&7`FwSfN>(uh;tFM-s(m zd2m^4$D6Yl@+vE>9>ygsI}A2hz}cfEej`05xuoSlLIILE)UL=iC4E5bj9`;N>ei1+ zr)eui9wS+3m%wWnZUZg#m8w=KOt`k`wd2ebG=+lD)P?G8f1L}G#mj)cqUnzyw>6_n zV__Lu(uNI@NRSdzWh3cI0w~u}l_0As5rLL~tR&@80vJ3SL%kt0<1&a{lj0VAgTcQ( uOkgxfKUEYE#f5Ilu3c2>N{dhW>y;N#&s^0_Fu;hF{x0N-aG@b_N2aFO$Y)Rh literal 0 HcmV?d00001 diff --git a/documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121708795_payload.FLAT_SESSION/secrrct b/documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121708795_payload.FLAT_SESSION/secrrct new file mode 100644 index 0000000..6d8d61f --- /dev/null +++ b/documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121708795_payload.FLAT_SESSION/secrrct @@ -0,0 +1,56 @@ +{ + "company_name": "Chargepoint QA UK", + "display_unit": 3600, + "flat": [ + { + "flat_fee": 0.98999999999999999, + "flat_fee_subtotal": 0.98999999999999999, + "numSubSessions": 1, + "type": "FLAT" + } + ], + "minMaxAdj": [], + "parking": [ + { + "duration": 222, + "end_time": 1570088781, + "end_time_utc": 1570088781, + "line_item_cost": 0, + "overstay": 0, + "seq_num": 1, + "start_time": 1570088559, + "start_time_utc": 1570088559, + "type": "PARKING", + "unit_price": 0, + "units": 222 + }, + { + "duration": 222, + "parking_subtotal": 0, + "seq_num": "SUBTOTAL", + "type": "PARKING", + "units": 222 + } + ], + "subtotal": 0.98999999999999999, + "subtotal_before_adjustment": 0.98999999999999999, + "tax": [ + { + "seq_num": "SUBTOTAL", + "total_tax": 0, + "type": "TAX" + } + ], + "totalAmount": 0.98999999999999999, + "additional_info": { + "outlet": 1, + "session_id": 600, + "station_mac": "0024:b100:0002:7b29", + "driver_info": "urn:nema:5evse:dn:v1:chargepoint.com:cdid:cncp00000c35d9", + "meter_serial": "160160T", + "currency_code": "GBP", + "meter_startreading": 800, + "meter_endreading": 800, + "energy_units": "Wh" + } +} \ No newline at end of file diff --git a/documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121708795_payload.FLAT_SESSION/secrrct.sign b/documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121708795_payload.FLAT_SESSION/secrrct.sign new file mode 100644 index 0000000000000000000000000000000000000000..33f9b0c1848fec85fdba277936e19ed99f4b7a75 GIT binary patch literal 71 zcmV-N0J#4!MFJrJuvtcTYgy5!Qh^m3|4=Fb-5XMMengj7rK~;4q}B>d0w60!HqlLR dYy#&26Eg01H7moQ&^2fXhl2-r`Fv1W*^<5l98CZK literal 0 HcmV?d00001 diff --git a/documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121708845_payload.Per_Min.tar.bz2 b/documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121708845_payload.Per_Min.tar.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..33a9eb53060f7ad1b58247b5ba8308a0f47dc919 GIT binary patch literal 827 zcmV-B1H}A7T4*^jL0KkKSz^!R3jhL^fB*avW7T`rfBAdw{_6kt|7zvH5fp$3A&eq` z*$PAff*L>q*lHO7gHVcpswb4ur<63&pa2h00MO6?(9i%48UWKrsiuuQqfb-yK`1~7 zA*oN))byD$U}>ltG69K*0{~47)HHg4(7Z@68L?r(m?1$3r*n!?_unR<39(Kl0Di}%#^o|h zlO!-CV1dqM->|J;u zm?jh%xt|@D`AJPVWsc3TNzb{2A=Y*ZzG%SSm=~96lL=bJMRj3Oz&>=EJs}YEM z>?*!~z{@8Rg?a{Ho6`FPA)SFtB=jXvxVeb57CS*KJA(V_zo`%H0QflFJKc7151zz$ zq8bR4DTX2xO2zyIR}U~KDV%Ym^_mwd`%HXjsd8R2es1-BKGl>sayERD!DSJfi=DG) zF(n7j*H$0#dJIQbbnE2=j;`4zx48LmoPJIp%rt8rLV-MB9Rfzh?z;vy9}&ZQo@DCV+_|iDG^EJ F2tr37 z(122-K&U_h+y*mXFlr$`RMKQUL(@^ApaUk<13&-(8X5*irc*|ZFo1d%kFzDtNx;58>KKvsjdLC=?qeg-_V|27(W|Vcmc%5D| zhtQ*i1R)|U6|CF^0C@{1R8@ehjG4pFIFx)ir{1^c))5jSOufuR zA1F#jJCQQct6YNFGfz^oEVrEpbv0#LAzPO(o2!Jwkx8Wc748_#{pMYGw1cXT4OmsB z#$f!c_Sy7{(ivFNOKVQ8+A?#BhZ<(j6dgkfqH9GHC+UN+vZ=hT{k{ zjvI5!!EMhkz|0;+MQx+l#HwvFz{Hr{g88XRE)tS(LIIl_l(NV*C4#W4HHgG4LF(3z zO6--y?i7HHWx`;KS*#2cD5*h0!tr%?HR$lVs8ClV69#ANvyhgqed7(rMT5vI7%;XJ zAsbpbgK`Op0VOGqnp6=+$ xk%KC|Bb#EsLMQ#Y#bkWgcD*0p?HbFW>kXmjpNHINOc=)h7ji{7P>`_vbXqJoYmWc` literal 0 HcmV?d00001 diff --git a/documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121709375_payload._Per_KWh/secrrct b/documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121709375_payload._Per_KWh/secrrct new file mode 100644 index 0000000..f4789cc --- /dev/null +++ b/documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121709375_payload._Per_KWh/secrrct @@ -0,0 +1,56 @@ +{ + "company_name": "Chargepoint QA UK", + "display_unit": 3600, + "energy": [ + { + "active_charging": 0, + "duration": 238, + "end_time": 1570169657, + "end_time_utc": 1570162457, + "line_item_cost": 0.10000000000000001, + "seq_num": 1, + "start_time": 1570169419, + "start_time_utc": 1570162219, + "type": "ENERGY", + "unit_price": "0.99000", + "units": 0.10000000000000001 + }, + { + "duration": 238, + "energy_subtotal": 0.10000000000000001, + "seq_num": "SUBTOTAL", + "type": "ENERGY", + "units": 0.10000000000000001 + } + ], + "flat": [ + { + "flat_fee": 0, + "flat_fee_subtotal": 0, + "numSubSessions": 1, + "type": "FLAT" + } + ], + "minMaxAdj": [], + "subtotal": 0.10000000000000001, + "subtotal_before_adjustment": 0.10000000000000001, + "tax": [ + { + "seq_num": "SUBTOTAL", + "total_tax": 0, + "type": "TAX" + } + ], + "totalAmount": 0.10000000000000001, + "additional_info": { + "outlet": 1, + "session_id": 614, + "station_mac": "0024:b100:0002:7b29", + "driver_info": "urn:nema:5evse:dn:v1:chargepoint.com:cdid:cncp00000c35d9", + "meter_serial": "160160T", + "currency_code": "GBP", + "meter_startreading": 1000, + "meter_endreading": 1100, + "energy_units": "Wh" + } +} \ No newline at end of file diff --git a/documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121709375_payload._Per_KWh/secrrct.sign b/documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121709375_payload._Per_KWh/secrrct.sign new file mode 100644 index 0000000000000000000000000000000000000000..0db1940d83d416d10611fd16a422b62dcf579a62 GIT binary patch literal 71 zcmV-N0J#4!MFJrJkxg5HJix7!dSNYDL(f*FI;}MaxF66gp6QsyLr#?E0w4wL;0`VK di1`8?;yL9iTOIHNm=VdB#J#K##@DlCZipufAT9s^ literal 0 HcmV?d00001 diff --git a/documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121709405_payload_Min_Variation_.tar.bz2 b/documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121709405_payload_Min_Variation_.tar.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..d61572bcf07da559d5e3d1df0d767caef465717e GIT binary patch literal 977 zcmV;?11|hRT4*^jL0KkKS>+x7KmY@mfB*bm3nF=?|NMWy{_g+(|7#HfKm-F4rVR!H zz(9ZnGMG>Up6XN#fCw~*r>W{Zp!FJP(DgJ1jRPT|Js<`^10W33NE#1N24y^W^ZH8ed<4=JEDG#;ZvKpvoI(?ik$w15C<+xLDgvG~rs1T54*gPXg$ zH#!53^&}f3Ev5vY-Xl2<3Zzj90+0z33PJFKFd+)`%=CgFO`=pen z{K)2lL$Jshfs->N%m7FdfiVaHm?Ve^1c^wb00;yLXdw_taS)y*$cG^3@G`aV&SnyV z%1V4civSH>MYe!9({=jYSC=NIBk))>2B`3`v?>q6)R^G^9o9X+E*SVC2?GR3!{vuV zW--EM3HMzxakn`F*(PSZd4LEaGvOl^>Vr-YM(ZOn`eZnhBKCm>Yn)YLC|;zcd_i=3 z-t&`yrXv{~7~2_^moN+wAVwhA4oCW)fZ{l^3$4oI=eyCQ8H`Fe7uHByM1HtSJ|vZw z*y3|k!opQGLCvnA)2ZOyW74KIJb~hABP|Xn16bmWECIGWTS&#N2D;b9ylhDy+7LHIyU6b^7| z15h(Ea+N_sZI~AR`=Oyo)}+$Gl!BoHn4o50dL;`ZxRX%3Ye`g7Tqhuc<{?b!@9Eu# zvyty~$-;9SC(4PFB_D2*I0hK9M8gu%jX}-BmZ@0H>A>SqAdA)^1>ZCIT^`lUk0xQ* zo&!!qA=1wSHggh^jh=HrBge%8di=*Qq>(dULa~Df4}Tw4q@)ofc8&c7C3tGG*s0u> zqRZH-cVu%ZMW)i#VT&U5rVw46J37G?U2NNh0L5k|WkZ14C>0r#G;vfR1V-mv=o>;d z7R{8xI#G8w zlF@;9$o;S&7=}iCGI^8Bt3t}T>f`&Nr#xzL_GBWlPrA#&0`f|0!h8DbX6%4ctJg>gr0w8NnT+NNd dFRDQqIjV2Qm-X_H1EXa}Ntnhco@8hT8Jw1ZPb z^*tyvM2!Fd0MGz5&;S4c4FCWDZ~)Uy00uw+13&-+KmZJY0BC3ckwj!^0aMyF0Y53I zW|8V)phiO@)Ea4s-l3uDn3{S3XhGHN@6Yh-8;}IB%n}UQ^BV0y`6#3t<9*#_wqulOjje1|uHzIBlEG9=}(fr1nm#=~sNb}2X z-#)STv9^5gVYo&JV$OLhg>dH64$_ah5j_?GB|Ar0pJ<1K*o za#j+m!H}V=kt%8xAe_Oo7HpF;qO;6w<(+rUR;=t6socvHPCp83EeO#}z}4lIuP*LD z(NRrYJVO{_!y{5>1d(GLaFT=-RMx2A0R_IV{nf~4SKhIHm4%ZI9hjMe1mdmLxGLen zK^M^{7?M|C#9N4Dg&1KLNyZ#d$#Hk43h=`DjKg~zWTX*1kODO#rq=y@OjC-^F*U+C z1K|m43lOBRjfH^L85u!LR@*{URRxMR*FGY#x=BDdUTt}X0KF#683CxYEglckL?!dh z0E(dW(~M9Bh#0nM1ot3*Bv(UPCliJE(uZ3b=oL2qe$miv*wr<{^#fB8AD{_6k#|7vKE05JmYIhZ11 zA_4$`g9tzZ*kEJ<4O2}=svf3>N2nSGnG8=;&`mNKG%*@922G}f7$YVT=?@YKK>+}g zo5Y@|+DD=uQ_=zHsgn?T1Tc8UO$Q00001ov9H1G!3@{HAKiW1X|d|bM7A>o@tV=0|KIb8nF}uuV77+1gg5OL z5@d-;U`G~t>H=_sDjYgT4l=;K88 zrYXJBQX|crHq~ZCys%RjKR(?My;r)&&M?VxU^0G+{C|JFYKEQJlD_7FJ?xt!0rIG% z{%(^I(SzMMq_glSsdJF&Ur5Aq2Xx|k6OE>2rlP4nYLs_hQ-d_-SXh)WP`J>&&gQmt zAXh#*jbO(q5e3J53bB5 z$VFYqrI%o9;wd2=u@g+s<(SzGHy0{gC|+hUw=>9*lpLM{#nO6I*z$Fwyfd% z?`@&e?6M!<{jjkxy>Ww^3zjDMuC#_%V~Lg5V~rL`M*9UFn5L8*ao^(ZNT&)C4+5Ba EK$Ayqk^lez literal 0 HcmV?d00001 diff --git a/documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121709465_payload_Parking_Tap_ToCharge/secrrct b/documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121709465_payload_Parking_Tap_ToCharge/secrrct new file mode 100644 index 0000000..826ebc1 --- /dev/null +++ b/documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121709465_payload_Parking_Tap_ToCharge/secrrct @@ -0,0 +1,56 @@ +{ + "company_name": "Chargepoint QA UK", + "display_unit": 3600, + "flat": [ + { + "flat_fee": 0, + "flat_fee_subtotal": 0, + "numSubSessions": 1, + "type": "FLAT" + } + ], + "minMaxAdj": [], + "parking": [ + { + "duration": 316, + "end_time": 1570177531, + "end_time_utc": 1570170331, + "line_item_cost": 0.080000000000000002, + "overstay": 0, + "seq_num": 1, + "start_time": 1570177215, + "start_time_utc": 1570170015, + "type": "PARKING", + "unit_price": "0.89", + "units": 316 + }, + { + "duration": 316, + "parking_subtotal": 0.080000000000000002, + "seq_num": "SUBTOTAL", + "type": "PARKING", + "units": 316 + } + ], + "subtotal": 0.080000000000000002, + "subtotal_before_adjustment": 0.080000000000000002, + "tax": [ + { + "seq_num": "SUBTOTAL", + "total_tax": 0, + "type": "TAX" + } + ], + "totalAmount": 0.080000000000000002, + "additional_info": { + "outlet": 1, + "session_id": 621, + "station_mac": "0024:b100:0002:7b29", + "driver_info": "urn:nema:5evse:dn:v1:chargepoint.com:cdid:hce5294254791722", + "meter_serial": "160160T", + "currency_code": "GBP", + "meter_startreading": 1400, + "meter_endreading": 1500, + "energy_units": "Wh" + } +} \ No newline at end of file diff --git a/documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121709465_payload_Parking_Tap_ToCharge/secrrct.sign b/documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121709465_payload_Parking_Tap_ToCharge/secrrct.sign new file mode 100644 index 0000000000000000000000000000000000000000..ad87b9a07544075cb64dcafa962ebae8b465ed59 GIT binary patch literal 72 zcmV-O0Jr}zMgk!K$*fT`tA|dd86oGgZLFc2_CIm_CssP0wDmJK~;H* e#Xg?Ry0b#DnR$b|7zy2|2*I|1BB$^5fg2`KZXi7X literal 0 HcmV?d00001 diff --git a/documentation/chargepoint/Testdata-secp256r1/0024b1000002e300_2-parameters.pem b/documentation/chargepoint/Testdata-secp256r1/0024b1000002e300_2-parameters.pem new file mode 100644 index 0000000..a76e47d --- /dev/null +++ b/documentation/chargepoint/Testdata-secp256r1/0024b1000002e300_2-parameters.pem @@ -0,0 +1,3 @@ +-----BEGIN EC PARAMETERS----- +BggqhkjOPQMBBw== +-----END EC PARAMETERS----- diff --git a/documentation/chargepoint/Testdata-secp256r1/0024b1000002e300_2-privateKey.pem b/documentation/chargepoint/Testdata-secp256r1/0024b1000002e300_2-privateKey.pem new file mode 100644 index 0000000..c83438c --- /dev/null +++ b/documentation/chargepoint/Testdata-secp256r1/0024b1000002e300_2-privateKey.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIPSG8elLLqPyWLoOwMx/juCEbiQe2vJziGjDyQ3xt7tNoAoGCCqGSM49 +AwEHoUQDQgAEw4TdYIkJ0f9NR5FiiS+jH6rRiju8aTBJnYQKMbvl+5gdYrdaLO+k +SwGZl/Nhz+mUh/Zi9kn5xjMY14/41Xc6JA== +-----END EC PRIVATE KEY----- diff --git a/documentation/chargepoint/Testdata-secp256r1/0024b1000002e300_2-publicKey.pem b/documentation/chargepoint/Testdata-secp256r1/0024b1000002e300_2-publicKey.pem new file mode 100644 index 0000000..b9be515 --- /dev/null +++ b/documentation/chargepoint/Testdata-secp256r1/0024b1000002e300_2-publicKey.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEw4TdYIkJ0f9NR5FiiS+jH6rRiju8 +aTBJnYQKMbvl+5gdYrdaLO+kSwGZl/Nhz+mUh/Zi9kn5xjMY14/41Xc6JA== +-----END PUBLIC KEY----- diff --git a/documentation/chargepoint/Testdata-secp256r1/0024b1000002e300_2_119693895_payload.tar.bz2 b/documentation/chargepoint/Testdata-secp256r1/0024b1000002e300_2_119693895_payload.tar.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..44ab690926f3ba364712fce6300bd0e715a6a94c GIT binary patch literal 998 zcmVL;=|)|M@?^{_6k#|LTB6V3K13Wh#gR z0I1M}nodvyj5X~`mL)3&kfikVNub$7Y5|A<^%?*JKxhDH82|y0149CBAe5R3lT+0_ zHAke=)MPzCdW`@L000^^001-q0000IYLrkh4KxF40MjNkfW$Ir1NA_{42?7Z05s45 z0E0|S00000000000003PMgRZ+1fmntBLXAThK&zVpc()G0QCR>&>8{i00006zU$FK zDZ#*wpdd)FG(iATfclaA1cA{s`X|fTRV2tP6|Vs#2A!ur?C3vQpMk``dY+x8A}U(IkZ$j<+|9qvK8oKN+{9 zQ@N{fxB6Svsvz8SD?E0;84#Aem2Sm}g8-D!&QAvae3%`p)Z2tXc0(N)#% zYp;v3M52jM-jr613pMN3DPds;$ZHYI*`XG6^GG5%_EbFFC?r+rilR)SE?Ce`L=_O+ z>TQ6Q*ktafDb+!&tV}sCc=kLMf}|*3Ap`Y}gOzUzDv(pQygH{YxQG=v@Ka7(7+6e* z+^W)JSemPAF^sg}+_01ul>@+hZ@4NFbOFQL2@z_5#-;WtTx#h^-H^@^NwwoqMgqB7 zAraOj!8}DCB_m?XF_GY)%`)7j3zouhW+Ww*U0*J$D}$lpPXfs!K!`p5|= zvL03~7;+VB1mG}=hS&)X!jKZ+#Ka!=$%D>LM=>g?7$HHm3?~4DEYM+OwNux}(Wx8| zgE^RZHY6Bf@?ngIV4{++!BJJx`2$F8JXcXGV=dt{%S9Cn63|f9u^aK;`6$FPpbnuW zgBioMOD!Nt?vIU%4$I6^7w|NtPeKMY;w)AnMGCVoW8LFiBM@;>X@?Z4_66o8%e9o6 z5~B>MqnyMrN-4j+LWG#HP^mH;mNG;;I?>&-0tb@qVERRAdYMEaTy=YRXV604gqF7KcMQnKVX=Wsb zBxPf8G7TJ769OPgwj#_RO)tO+Aq$NY0y502b|^Rs84c|sOCYKg;{&JjnWF=3*t-Z` z;c_M&Qym6m0U%$IgGPzt57&9g0fg#<$o6df&62Ova-`=>W{kCbCQkmGw7IEneHrbx Upli(J8>9X%8FaQ7m literal 0 HcmV?d00001 diff --git a/documentation/chargepoint/Testdata-secp256r1/0024b1000002e300_2_119693895_payload/secrrct b/documentation/chargepoint/Testdata-secp256r1/0024b1000002e300_2_119693895_payload/secrrct new file mode 100644 index 0000000..a630e3c --- /dev/null +++ b/documentation/chargepoint/Testdata-secp256r1/0024b1000002e300_2_119693895_payload/secrrct @@ -0,0 +1,85 @@ +{ + "company_name": "ChargePoint EU QA EUR", + "display_unit": 3600, + "energy": [{ + "active_charging": 0, + "duration": 421, + "end_time": 1543841929, + "end_time_utc": 1543838329, + "line_item_cost": 0, + "seq_num": 1, + "start_time": 1543841508, + "start_time_utc": 1543837908, + "type": "ENERGY", + "unit_price": "0.05000", + "units": 0.058999999999999997 + }, + { + "duration": 421, + "energy_subtotal": 0, + "seq_num": "SUBTOTAL", + "type": "ENERGY", + "units": 0.058999999999999997 + } + ], + "flat": [{ + "flat_fee": 0, + "flat_fee_subtotal": 0, + "numSubSessions": 1, + "type": "FLAT" + }], + "minMaxAdj": [{ + "session_length": 0, + "session_min": 0.070000000000000007, + "session_min_adjustment": 0.059999999999999998, + "session_total": 0.01, + "type": "SESS_MIN_ADJ" + }], + "parking": [{ + "duration": 421, + "end_time": 1543841929, + "end_time_utc": 1543838329, + "line_item_cost": 0.01, + "overstay": 0, + "seq_num": 1, + "start_time": 1543841508, + "start_time_utc": 1543837908, + "type": "PARKING", + "unit_price": "0.10", + "units": 421 + }, + { + "duration": 421, + "parking_subtotal": 0.01, + "seq_num": "SUBTOTAL", + "type": "PARKING", + "units": 421 + } + ], + "subtotal": 0.070000000000000007, + "subtotal_before_adjustment": 0.01, + "tax": [{ + "tax": 0.01, + "taxPercent": "19.0000", + "taxRuleName": "MwSt.", + "type": "TAX" + }, + { + "seq_num": "SUBTOTAL", + "total_tax": 0.01, + "type": "TAX" + } + ], + "totalAmount": 0.080000000000000002, + "additional_info": { + "outlet": 2, + "session_id": 2, + "station_mac": "0024:b100:0002:e300", + "driver_info": "urn:nema:5evse:dn:v1:chargepoint.com:cdid:cncp000009afd2", + "meter_serial": "240008S", + "currency_code": "EUR", + "meter_startreading": 3078, + "meter_endreading": 3137, + "energy_units": "Wh" + } +} \ No newline at end of file diff --git a/documentation/chargepoint/Testdata-secp256r1/0024b1000002e300_2_119693895_payload/secrrct.sign b/documentation/chargepoint/Testdata-secp256r1/0024b1000002e300_2_119693895_payload/secrrct.sign new file mode 100644 index 0000000000000000000000000000000000000000..196f2348c8649b73e04c78523d10abc738904942 GIT binary patch literal 70 zcmV-M0J;A#L;@fldsw{)kN|(%otn_Fd)LEZh_C~7k)^qCDg04;v9&@YRsaA1 literal 0 HcmV?d00001 diff --git a/documentation/chargepoint/Testdata-secp256r1/Testdata-secp256r1.zip b/documentation/chargepoint/Testdata-secp256r1/Testdata-secp256r1.zip new file mode 100644 index 0000000000000000000000000000000000000000..802a88a75303cb5695863466d22161990715745b GIT binary patch literal 8318 zcma)>2UL?=vxdJU5PAzeASNV)P)`VXn*P4=1$$y)o}S^JrpJs-si!XX9#05@QI`@B}Xn-1@-lc;WRtG}J=(djTlq$*hx!Klp0weM!vVzCacgad z5=41kJf^-fJ~lOg4|{l5{&FjaVfoE%nISF1vu7WEup$~^YM+XQCe<)1wepgf{l~49 zQ>Nn71c*4N7xPl(3fniQJ9cw!$rU8HKl8az=FW$B82!}Yke0v;d_e;3i%gsE$0lAYTbX8}*-ONB_)BD52t~$vbYkM|R*xTY|ZvX(UyM@|j zYL}YfAnfh1r{3Rg%R>XNp@Y-a(bMt>rA7tqrTVCwS(6++984V?ENr){M^MAmy`u3( zJ860vq#YQC9Ze;}4gfgk=-TQyuT<2gqhAa!d|zB!TYHVA3)9UKhyXWYpF9u?U|Yct zZa1oX3j1>pVTPpgpu{eMf0prx03I4!LL`hcSD<-#ADt>56O8a6A>U4}f>kmC2LOHq zfh`o8N(U)bI>G?~0C-QQ0dNSB{a?11ojsY0Sy8OS%Q3t7N2CD=kp|6!Lr5h=Kw5Dy zvWl{W304fJCrdt!Z8KenxtvaV;=Fj03HBM2J$wIb{$aF{H5!MuA~!Z$EECOXhqru7 z`95B5u9wV^Zq342;L_8%`7u;MvQLslCI}1~8}(-R#S>+7@4{9BRQTJ){7yzthd0+G zF!$^_eXSpj^p;K%yfiBfrtPft(*GzO2Ley=4V5M2O6l?JZV{@w8eZ@ojTDMF-eeeC zsHj1-6{+yNMaGK7r59{RAiGhuZ$9qog_2a#T}Mol!mW%ye~N1#*<17_&_Xd``dBm7 zzNm6}=|&lKIEe+%GID;RM3wEj_Hf`lA47>^;=7hNWs10%gt~E;lk2)vTY8r_iCev6 z)8T~o5{OA5Zp6F~Hfxhlx3|}*KbS&$7cm)Od_j~2o8p?_--2yGcdmvSi)VM$J$M{4 zIqPinNpoxa4k2#ti=R)N!z&8E!sRHQ7PomLyHv*W1zqZ3#b<+W-RDm(m&luZV-(O_ zqhA75@b~N(b6)TdaxChLnu{52ziA6mYjxGDA904g-tTItA2iXP(07A3BmWd79sbUmzV#A;TRjkgL{o|`fLQ(=lbdXJ-Ymfp)TPs z3@N^09yb0VzZ2-y|CA2^pJo#X^Bz4kdi3+5*K7hmt_94siipvy{VU;k z(D7slV8cH`h^7x?^5Fd33R?1oOt$m^_WU)3Jpl&5L;vNnt@LD8#R4<9NxGie#z2y| zE5cLkK0d-QdFr=gfFpOxZqMPZv)KH3qs{Di<_BP^tNi*E_a933hxq9jcCfD7UBW%Z zze!gb|z65q?pHT$r!~-}xZ#JdOsfh2GD~=d}9=Fs&`8YR@&? zNUvV8+@6a{()Z&y)w1%!Jrcpdh)G{Px9Rj}3mZM(lf88o{Z|u^V+U}C0?z%sho7O2 zi%ykv==GaPr&GC8kk=mu2T2vxr#7{Ik|51AUx4l@dYlw`6KO~JTJl=`ghaXrhoOqG z(${wi)!{g5ADVK1=i~>x@`@j}y?=z%CSyV4n~SKA0p*Do#tufBT$)9k&#f&Ws3xo| z*vHD62nVyAD)|TlNW4k4Nb;c<$~TU*-cy7nMngUGhrV(k&&FD#-z!j>t|m7~=#y0S z=8F`PSFDM?<;vU8QwMF@vgD%e-Dk|(MB)jEd83fql8 z60&l5+i13Kn08ENo3BXziL;mXXee;?-*?{pCYs;eC1PogmM(AgnjIpWK_ zFTQ-KIf^~l%!^s(vI5t$Y%EJt#no+;&z|pN>K2yE`7?00F~{Y0zyeh2e;f?**r%%hBxt8#F$s+OaX^_maKd6)R9`rQs(!qkbo$B{~w8C6>`CrcHsT2zf; z+pf~x#G_f^AigU)++tcC(hbjQcY?*XBGgk+3kbMqnD4#2Z$1>9e(84ZBkBI8!gFVo zZS^ly1*6A0 zjaDwS-)XE{jo1l*&mCR+p6dzzEO~TQ|J2$#jnN3AY8x2JZDfuZpxc)aD~aG~sHP__ z0BPtrXIQ%+l5aN2cV1GxDZD;@h zVnXR`3u3Zea)$B|lTN}49D=+|&}IsNijt%05aNnlMmii1Kx{(Bj!d5kdfTcHmrm9} zUc1WK{>)6oQU|Jv;0Zj^ba8D%Z%fSL zbiE_)YIT|_3ZMOky-?)Uh4jnbe>3vzZq4Kv&W7#~1#WMY@(ar&rpWKOJrvFo{sfEw zp(;W795t?9HRiBP>Cm;EEbH1JDeHo^9p6~fYR_qjT`UQI`N;Va2kf@yxH|~n;eijA z3!3;3J6+1mGqLQ=&Q%hW$x-s4*R|FT(;OF6auFd4KCyxM+>aD2r%h+bG?!f#&vmnV z&OIc@iS^}Zzq=67RkdpOrVY+@ub(l#+LYQ%Vup^ZtUex9_-wL7)hpvb%BzakOmhNJ ze2R`v^y<{yTm8D(F}f8G8|TMFVDi>2Jtmv6mS*}H_`zzoxCu>L`-`fLXSw!k`R+vS zI`c<afgEBT&9f_CT`E$zD`H5QoqF+MJjX!_N~iK1Ma;Sf`p8wi&s+OK zDT?+it67yQeQq%_(l_lO7-n&nz755&%*%*ZZb9XH-854C*4*h6Gk&0D^P`vWdqqnE zMf2y5P1CHUZvRQ)IwXHlILoHc_a%4EAe+GTsn0&m|41PL_a6$^)1ikmHO!wH;lDS; z<98P4Hmwl>$QgEK+|4H+RkpTz^yc?h?AkO?1We?Bz{&-n;8r4?6VISP3Kt#u>D+|m z3fAIQ<_erPutI>QL6A%X1e6Ft@DG#WLKLX))}mInw)OF!yw{OQr$On^JT{d+1jxwG zPl3=s?K-YM20DvG;4UmdRInBdvpZczI zsE!ch^RG4QY=N9yLCc`j$~n$GMCl3gmfG=v(|KULq~$mqlJ|Yj`#6M6v7_E>tKOm7 z7i)^%9V5qAyPm}v*L6w9W@(~(05U9AgB!#^C-ZO|Czk@;96U6nFnOPFp+eU&#QZY; z@^YUaEbgvljNu7Dz}@r;U1xazmj^CqFcqj}R|2$hxvoK3sC|U-cx}^|!A*6kPx3qv z4)U$JW5#|O?S4ET-SPVx^}rJtzw1$SZh6foD2c`R?ZReDD2*>Zx>@ocVxfTrPF~pE zrDZXsh(izGWzow~(y~%h(x=bh_(c$Ah;c#lFNO3O-HUv+cW39X4VFr$TIx!Uk$0IK zX|mde&N(wa6YkjF?xaQPJzq4;di=n9s9bAn?2JE3O%Mxlok>*%UD>*e+*u249_MT} zM-R$F;ALXqS?=m(-fV0@#(c}I44$(#bl}*a>K5_FqIR@)!QR@+M5ekeN-xQBz?bxi zxLr&zGyp=;#E0dOjDi^w-@g_Wk;h7h+Op${APlCTXS4zzswsHkd~0y>*)9+Ply?OF^6%LvlXS{Om3_ z+H(p+9WR7zH$e{dL$t$TnQ4XLMAV&5aP;aOTxo`;hf#ezm(bD8&ZVUy=mTlrI29rT zE{?ONPZ!@CuR7=xu4Gz1G)g@ozfvyjUZB6FP24?bDiP@P!}uE0C$ZwvS%iI#NDi}k zx92iO+7i9l1A#KhZ4In3BBl6*_Jh1Ey2pu=+3(%3`JohxI&diB>EHqBlxI>5#aM=b z*cQ8kI+=s9kzL>F5K>8IG59D}Qjw%m@=(Nq7du~s8{YIl@A28|qjsn><2bIwXSPCf z+}m5cA54+0+{p>lQfbzggL-(2wfmCZ<~!vr%Jb~Ck>bseju-Gue3UVU5p^f-uOaTN zcVN=clvYt)LEv!XrXyu!k8qD~I%tEVcig@o+-q@+F>JDR1)F@sllx}pbjEfuw4V9V z0pPDlvA~WL03u)=NfTu;_JY0d&m$67?ni-=;;Qq-Ei;5N*dC>rkH2UIo|MHSdI!9d(jDO-C{3Y=-wp3>J2$5*M zCz|V!d&6W9abh^=8gAAB0%v_HkGb)B`)ebqzJ;@BQkp<{zJGn4lx#YMK4t9f6%2uL zXhC^QO%Nk;-mJ#21FNZ8?*uEROvjg=$LW?#zoMl@dkpBvhrm=Z=01a~xAV_jh?6A0 zyBG3kTm8rSD>1LBO=jHQ$nM$uPSIlK0QS(b#0ZDfu#Kn>FzFmFpM7b5xXyaK`JRee z2fy~UI&) zCENnFU=uPis=7w5fhq%02cDx5e~{E25^$bHk2!Dp)joD)%>{-`)ry^>2+GTT*U zuTtd{)7w!w9Qm**_KkRlt&whh1=!xsP)`qWIiCoqnEx6nOS+ zR*k+A<_xQ9OE0RZlUb=aAbJPhGr&+JC0R8265iF@NKkfkITdQBRPp#f}0q*@f5&FiHmJ!7 z4Vx&u>jhGn?}t+aPHBy=}54D6z9>;dOsUW0km{L1N=&lA@3y*24ds6+1FZ6ACQ29jd_(^ zd6Ic09Gc5->o8!0mnLYy2~eBz1Su3oWI+hVLjnPr`5lFoljg;84nv>?R+exy2f?Si zM3^6gp|g*qy$QRP?uyQfrn9SXFZO=e1Juf{u-V`O((Ehpj{!Q%68=sQXoP5)bZK(z z9PbQ&wRv-)KQjf}?kQwN+q1Q~cL;=mNx{%)l3CV3x(FPW?|tiDNs56|6S1|ABNuOx zkU%H8Ly+D4>D_oDg1DuC*z<0yp!J+=!`(C0sa}%HBQTBmUAEp;T_JoQzNHD?51iib zR4`TJSOj^98qIRKu>Wz~;jb0ShrZ@tvut+X@v%`lca&2sJnRp_V%-`AtL|n9xVQ*I zEMGYpJM!eE%=6&4L1%~H^24*QQ)? z64>%S@42w9mSfWb;=#LR&nrny2|6z&U_Qsmp5_u!i{Q|BWyJBWN;Mr`g!=AMI!$z3 z<=7}GUCtXNUBsU**}XMB(Am%J`K-x@a;26bdsJ_M_Nbr9^*RSh!)*_QTU?s&^x?Y0 zJn=_TR*xQS2}n9Sk$K};tig+X6zFYb>GzN zY|S1>_a<~kFvgI2$9M}f8QwaU<3i_q6uL~^yUNaZ2F@rUH`R+;_s=mV1au^o-LSj; zG#WL#GO}e0!JR|Vj^l6lU$mCogEA-&>=t$Fn`I1xb2_`~R#ahL&b3q(7}6xt+!s^r zS_17cdR!xJwLj_R4PSXTnO&-Jr?1pJ`T9DzX!ym&&5yp-)#F;^Vr*yvb3+xxo)wy!1* z=Yjw42KF`HcpLy6Y&#lyrZ~=WlWdGh+Np*&ptO9aDvKJYfT25gU&>OTbL~FF(!iWzj*EQA9s!&D=)IWQGC_|T9hGEiK>5Cfmm}fsJ0^7i z-nIU1e?=TocEq^|*ShtL9c|X9Dtm())Bn$nd1z?pY3pg~ZfIfu*0sJYUquEWp=)ca zpG-g#3TvMYZ~o|7FVamtGrhsS%ItPmE-b_yg_>!sCc1r=y|>HGH<%n9QFP%^Lr zXXkMmK$8YQ=@4UZFd{pTC(B{fK+C*zc*Mtm7@fAB^Wp63|HlOY7LZNR5FkJTfME=Q z-hrn&NV)4hYz9?;U^n)PL#}U=Q5OT zEOEG6*?5eyF!91UHea-HeDQ{KU5LsVf>(#%XtnD?0_lN&%3Gw4^Y>m25m9cUoXMcm z=&QgBC+ba#k5e9IJE!t#EsZHrsa#!wB0UpD5)tpn^12@!w@zcxPR~<{t&7!N2ezAt z3r{Zw(@&54ysA(dCDqhe>-`b=VXJstDRws!vT`y$XD_dEy2F+0TPoC>lErnG9k%b1 zaw$)Tl0Y$yR&2e@31?I}6rr@Eh;fcQ1vn2;+eH&X8?$c&)U5`kqv6(2Y zFI_y?i*n9tQeonO9FK7+N#i_%?dh<`9UXEXyW{(|n`!Y`{E9$=>HyW}vcvs5 zgDhF$cs)j>Hd>1MmYSO6S)5tdX6H2Y8A1-;>SCwjt@ea)&s3ZbHb5DzmwEH>GqwZI z6f9DRm%eq`N)2K0>Qq{a;JqGu$z?*Btr1jfM%5W<%6sV#?+3GPDB*o}{>Q{vA2^>W z+`F8e2P@%cl@xT~ER}Ay7$q?3DJ;C~(~mP3#NV1+Ev%=rRL~lXx4CE|J123frAc^t zV&AGr=NtYnK65r|B?D)JEfmziXnWqCt1ZcBSARe!s_V6q7IXZ({!G zR=ZJyo8&jCbq&AlZpW1${>C5V_ws$C2CV46Y50E@^BX07e|dECx};xLv@7z5|5MUW zT7NHGHcD!f_}`NLu8i5ZV#GkL?K-XhZ8!c1zgH9+SIm?AyA}VrzSy|>{jZmm)&c!x a-;Dh9DOQ}&_0Yq^{ww4FfV(p5-v0nP{oYjo literal 0 HcmV?d00001 diff --git a/documentation/chargepoint/Testdata/genKeys.sh b/documentation/chargepoint/Testdata-secp256r1/genKeys.sh similarity index 100% rename from documentation/chargepoint/Testdata/genKeys.sh rename to documentation/chargepoint/Testdata-secp256r1/genKeys.sh diff --git a/documentation/chargepoint/Testdata/showPublicKeyInfos.sh b/documentation/chargepoint/Testdata-secp256r1/showPublicKeyInfos.sh similarity index 100% rename from documentation/chargepoint/Testdata/showPublicKeyInfos.sh rename to documentation/chargepoint/Testdata-secp256r1/showPublicKeyInfos.sh diff --git a/documentation/chargepoint/Testdata/sign.sh b/documentation/chargepoint/Testdata-secp256r1/sign.sh similarity index 100% rename from documentation/chargepoint/Testdata/sign.sh rename to documentation/chargepoint/Testdata-secp256r1/sign.sh diff --git a/documentation/chargepoint/Testdata-secp256r1/tar.sh b/documentation/chargepoint/Testdata-secp256r1/tar.sh new file mode 100644 index 0000000..7e993a1 --- /dev/null +++ b/documentation/chargepoint/Testdata-secp256r1/tar.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +echo "Compressing $1 -> $1.tar.bz2" +cd $1 +tar -cjf ../$1.tar.bz2 * +cd .. diff --git a/documentation/chargepoint/Testdata/test.txt b/documentation/chargepoint/Testdata-secp256r1/test.txt similarity index 100% rename from documentation/chargepoint/Testdata/test.txt rename to documentation/chargepoint/Testdata-secp256r1/test.txt diff --git a/documentation/chargepoint/Testdata/verify.sh b/documentation/chargepoint/Testdata-secp256r1/verify.sh similarity index 100% rename from documentation/chargepoint/Testdata/verify.sh rename to documentation/chargepoint/Testdata-secp256r1/verify.sh diff --git a/documentation/chargepoint/Testdata/test.sign b/documentation/chargepoint/Testdata/test.sign deleted file mode 100644 index e69de29..0000000 diff --git a/documentation/chargepoint/Testdata/test.txt.sign b/documentation/chargepoint/Testdata/test.txt.sign deleted file mode 100644 index 86fd9ec55f84f9a121b35593fbcf05c14e26a62d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 71 zcmV-N0J#4!MFJpi6B#C>=y>vL&FfRO@12%HW!B@$QZTvO$9tt#v2tVrAppa}i%*^Y de_HO`Tf;;E{&1n*Pon@LoPCLyk5W^h&(-qsBy|7) diff --git a/documentation/chargepoint/Testdata/testbox1-privateKey.pem b/documentation/chargepoint/Testdata/testbox1-privateKey.pem deleted file mode 100644 index 5842985..0000000 --- a/documentation/chargepoint/Testdata/testbox1-privateKey.pem +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN EC PRIVATE KEY----- -MHcCAQEEIGWgcrZT6Pa1AdVDlWQ7BMfusZool1V/zoXalnVE7otDoAoGCCqGSM49 -AwEHoUQDQgAE+P+5XA+m5hJi+0P/6bQG1QEjNKbSPQmx7cuPj418qaocYFLiHgsZ -hr9dfNuKgG0kNsM04505HJ8NUM9N96AqLQ== ------END EC PRIVATE KEY----- diff --git a/documentation/chargepoint/Testdata/testbox1-publicKey.pem b/documentation/chargepoint/Testdata/testbox1-publicKey.pem deleted file mode 100644 index 82714b8..0000000 --- a/documentation/chargepoint/Testdata/testbox1-publicKey.pem +++ /dev/null @@ -1,4 +0,0 @@ ------BEGIN PUBLIC KEY----- -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE+P+5XA+m5hJi+0P/6bQG1QEjNKbS -PQmx7cuPj418qaocYFLiHgsZhr9dfNuKgG0kNsM04505HJ8NUM9N96AqLQ== ------END PUBLIC KEY----- diff --git a/package-lock.json b/package-lock.json index 9d5d16f..42f1ab0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,9 +35,9 @@ } }, "@types/chart.js": { - "version": "2.7.54", - "resolved": "https://registry.npmjs.org/@types/chart.js/-/chart.js-2.7.54.tgz", - "integrity": "sha512-BxIUR4mfk0zOqOPEu4gxLP5herra6INQLyFmgVE6JVRNNB+r36g2cd67nDUEEdD/EShZvaR33xausxOGv1+nbw==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@types/chart.js/-/chart.js-2.9.0.tgz", + "integrity": "sha512-AsojgiTzlfLmIAyzzN5KkNrlkg645bg6MRBjkFsPuFYff0toasck6Jx/W772kyrSPcO90bBGtExM8wrBn/niJA==", "dev": true }, "@types/debug": { @@ -80,9 +80,9 @@ } }, "@types/node": { - "version": "12.12.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.7.tgz", - "integrity": "sha512-E6Zn0rffhgd130zbCbAr/JdXfXkoOUFAKNs/rF8qnafSJ8KYaA/j3oz7dcwal+lYjLA7xvdd5J4wdYpCTlP8+w==", + "version": "12.12.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.8.tgz", + "integrity": "sha512-XLla8N+iyfjvsa0KKV+BP/iGSoTmwxsu5Ci5sM33z9TjohF72DEz95iNvD6pPmemvbQgxAv/909G73gUn8QR7w==", "dev": true }, "abbrev": { @@ -671,21 +671,36 @@ } }, "chart.js": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.8.0.tgz", - "integrity": "sha512-Di3wUL4BFvqI5FB5K26aQ+hvWh8wnP9A3DWGvXHVkO13D3DSnaSsdZx29cXlEsYKVkn1E2az+ZYFS4t0zi8x0w==", + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.9.3.tgz", + "integrity": "sha512-+2jlOobSk52c1VU6fzkh3UwqHMdSlgH1xFv9FKMqHiNCpXsGPQa/+81AFa+i3jZ253Mq9aAycPwDjnn1XbRNNw==", "requires": { "chartjs-color": "^2.1.0", "moment": "^2.10.2" } }, "chartjs-color": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.3.0.tgz", - "integrity": "sha512-hEvVheqczsoHD+fZ+tfPUE+1+RbV6b+eksp2LwAhwRTVXEjCSEavvk+Hg3H6SZfGlPh/UfmWKGIvZbtobOEm3g==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.4.1.tgz", + "integrity": "sha512-haqOg1+Yebys/Ts/9bLo/BqUcONQOdr/hoEr2LLTRl6C5LXctUdHxsCYfvQVg5JIxITrfCNUDr4ntqmQk9+/0w==", "requires": { "chartjs-color-string": "^0.6.0", - "color-convert": "^0.5.3" + "color-convert": "^1.9.3" + }, + "dependencies": { + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + } } }, "chartjs-color-string": { @@ -797,7 +812,8 @@ "color-convert": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz", - "integrity": "sha1-vbbGnOZg+t/+CwAHzER+G59ygr0=" + "integrity": "sha1-vbbGnOZg+t/+CwAHzER+G59ygr0=", + "dev": true }, "color-name": { "version": "1.1.4", @@ -1554,9 +1570,9 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "fsevents": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.1.tgz", - "integrity": "sha512-4FRPXWETxtigtJW/gxzEDsX1LVbPAM93VleB83kZB+ellqbHMkyt2aJfuzNLRvFPnGi6bcE5SvfxgbXPeKteJw==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", + "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==", "dev": true, "optional": true }, @@ -3016,9 +3032,9 @@ } }, "sass": { - "version": "1.23.3", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.23.3.tgz", - "integrity": "sha512-1DKRZxJMOh4Bme16AbWTyYeJAjTlrvw2+fWshHHaepeJfGq2soFZTnt0YhWit+bohtDu4LdyPoEj6VFD4APHog==", + "version": "1.23.6", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.23.6.tgz", + "integrity": "sha512-awBvj9xrAuiS2TOCcYSUGCmaBV3UW6fVSK4oJ2LHS8IRfnRLc5EJihw90C7ZJ/skcEwFGSf9/XO5NlMiKupBCg==", "dev": true, "requires": { "chokidar": ">=2.0.0 <4.0.0" diff --git a/package.json b/package.json index 65db7f5..ad19b9e 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "homepage": "https://github.com/OpenChargingCloud/ChargyDesktopApp", "dependencies": { "base32-decode": "^1.0.0", - "chart.js": "^2.8.0", + "chart.js": "^2.9.3", "decompress": "^4.2.0", "decompress-bzip2": "^4.0.0", "decompress-gz": "0.0.1", @@ -39,14 +39,14 @@ "moment": "^2.24.0" }, "devDependencies": { - "@types/node": "^12.12.7", - "@types/elliptic": "^6.4.10", + "@types/chart.js": "^2.9.0", "@types/decompress": "^4.2.3", + "@types/elliptic": "^6.4.10", "@types/leaflet": "^1.4.4", - "@types/chart.js": "^2.7.54", + "@types/node": "^12.12.8", "electron": "^5.0.6", "electron-builder": "^20.44.4", - "sass": "^1.23.3", + "sass": "^1.23.6", "typescript": "^3.7.2" }, "build": { diff --git a/src/js/chargepointCrypt01.ts b/src/js/chargepointCrypt01.ts index 407b271..e636934 100644 --- a/src/js/chargepointCrypt01.ts +++ b/src/js/chargepointCrypt01.ts @@ -54,7 +54,7 @@ interface IChargepointCrypt01Result extends ICryptoResult class ChargepointCrypt01 extends ACrypt { - readonly curve = new this.chargy.elliptic.ec('secp224k1'); + readonly curve = new this.chargy.elliptic.ec('p256'); // Koblitz 224-bit curve // https://www.secg.org/sec2-v2.pdf // this.chargy.elliptic.defineCurve('secp224k1', { @@ -75,7 +75,7 @@ class ChargepointCrypt01 extends ACrypt { constructor(chargy: Chargy) { - super("ECC secp224k1", + super("ECC secp256r1", chargy); // defineCurve('p224', { From a51ef53530f065439adb05e7e6f7793f3d62f03f Mon Sep 17 00:00:00 2001 From: Achim 'ahzf' Friedland Date: Sun, 17 Nov 2019 01:07:09 +0100 Subject: [PATCH 031/110] Verify chargepoint charge details records (secp256r1) --- documentation/REBUILD.md | 6 + .../0024b10000027b29_1_121709375.zip | Bin 0 -> 6539 bytes .../Testdata-secp256r1/0024b1000002e300_2.zip | Bin 0 -> 1480 bytes package-lock.json | 26 +++- package.json | 2 + src/js/chargepoint.ts | 3 +- src/js/chargepointCrypt01.ts | 104 ++++++++++------ src/js/chargy.ts | 113 +++++++++++++----- src/js/chargyInterfaces.ts | 19 ++- 9 files changed, 201 insertions(+), 72 deletions(-) create mode 100644 documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121709375.zip create mode 100644 documentation/chargepoint/Testdata-secp256r1/0024b1000002e300_2.zip diff --git a/documentation/REBUILD.md b/documentation/REBUILD.md index e8c96b4..d545235 100644 --- a/documentation/REBUILD.md +++ b/documentation/REBUILD.md @@ -30,6 +30,12 @@ $ npm install elliptic@latest $ npm install @types/elliptic@latest --save-dev + @types/elliptic@6.4.10 +$ npm install key-encoder@latest ++ key-encoder@2.0.3 + +$ npm install asn1.js@latest ++ asn1.js@5.2.0 + $ npm install moment@latest + moment@2.24.0 diff --git a/documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121709375.zip b/documentation/chargepoint/Testdata-secp256r1/0024b10000027b29_1_121709375.zip new file mode 100644 index 0000000000000000000000000000000000000000..caf6043a83e928e70a545ff973009d84ac2d86eb GIT binary patch literal 6539 zcma)=3p~^9-^YL3m^riNu#q;K8Oc2}r%;>YoHFM_ia9lhBveSuF^R&cIW~tdQIuO! z3Q?5vDWs!RbkaeolxKRL|K0t(?z*4n+P<%A*YCIeKG(I^_5Oap*OzVs5kLTI?TS~p zeXee$1rY)OYi7W|MkJERzFNe!M$+>o8F*`XYmv0{i28a4I^N-on9w~8e@zQps4Oag)LijJI4DUdf1-q|Ku zdnvN`0}dk@b);o$VyUVY#a_DF=Q@pmNXjnWhQ{<_>)(Fb-Vdd2%yu6$Pm8oM{k)vi zIku=koobv!Wa|x>>+#;azj|`84d+ zTY^GYlVxqAP7g^K?EL4Wr%0+&uZj7pCuHp2D!w=^`~_F(WFu-v zYTp|~tCB68erpokT4z`RRSELxnsA*D3Uw|Uh?$EU@4RLY+0^cC&^YD_f3weht6}I= zXUf1;k({FAf;o|C$8^PC6C4~;{jzgSn<_oWhi(e=SDsdOFY_oocjwC^OL%u+Ot?qL z&7uqP@6VlB!P7S+tc8BwV^-=pTFY@Ia2EE4Zi0$e5-!-3PgqLCVT2@uj|H5#BkKutmCPYI% zf@`+6yMK$JKKUnx^neI&yP&Xt66iblL=*s@;1dY<8$URn@cG~yK7pTBgXh|%5iA%c zQ<*g-Vg^b=QNWYINFbS>kx;9eH(Z@Z9_9j)bYN&`?JbT1MlE?&SwXVs8pRi)#9%5q%B5WX)Q9-?pC;u4Z~$S}e}?=XInAz~ z=k9JnHZnRm7%HqfGQ;8113Xu_aT^|pzj^w`9Lbi==g$vk;UN5M2(GarW>|gazT99~ zpx)Ll-W7)n#3y*Te=nX!6A*0IF2-?aG=Gj1dc7t(Fs4)pACVI9EYz=1ph;)G|Filj z-N7Mzd)x8)Q%zU1&n#JQE5N211_~T+TY9-88qL8Yke5!aKk?bh&LH4ee}mQFr4-D> ze&SYf*Flj(Pq9bV-L2>{7_>lUGhi8*EBAMY%9k}}wzMzHQXjXTgYGJOm==Bw<3Rsf z@kaBgY__++){UlWU*D^oi6k-xaP&K#(;rFdOM!&W!7*xwf)!JAE~+sOR47xLI2>(u zVHSP1puU)_k+L-Jn5bwbwVUTsBT62^kj&0VryqQ&el@=RwkkX|7V1+p@>Kv+l4y(j zph9oCl-?w3NYyY*`nqt9C;19k*1u?Fm9Egjl2o~Iw78<*P=AYF8{Sz31&JhACKH){`dn9)a*lL=dVy8{ zWwAOB$IjFneqwhvt4ZB}x47fZJ8kcd_wP6$L3-b)eVm($_n7VZYqh_5` zYlJ^msdCAxc7o7xiRC2|%ZmhwHtWFD1Jz_Rk;XreR}p9EI(nK=EIosoO@fF58|5X@b~QR zU^LLy`w64>8jUt?%zx6@uoC47fKMf?elPF=f0j#FF+9GyMq@0RqR|0{!b~jDLoCM% zN(}`(1J(8+24l85kN6v#jyjZaA^5SixQ0SOEvuX?vWTo$r95~#XPt?yZ4zk>H3((R zUGTpn!S9#=0OCSf{2s*R4{15-@n+rRB@_hnCs~&(4k}BJWkD!QN;%mm5&*Fan~0w| z8TzhWB`KSxhq-)7u=A;fw6z{o11%g9-*SF+b7;(`{;E-5=Ct zxQi}WA(ny{C)cK^pJF66YQ!B~J>lyRM zG^X2jtLOT8eW&izk`M#=y6?{g_tdU9yzM{<-5%sjuC!#fQn}%i8&@8Vt9&+l!7w;2 zfKk?vshbf5VnkJ)U07!_3$739=f&w)-@o{5LK?1Y+tz2cfnaT6m_r&qKAiwh%=VLi6rD-Ao?}({RpzyP|F@?*qMMRykBhszoW9|+QulG{!_g6>`-n}* zw)$yOWX54s;2>hXsYqpPSFQ{X5mZ(raFY}S9=FEp*r(0H$j1~SZ+Gk-{G+{3$=rN* z#bj6QZc=*}=U&ohp0y@CH{1kNq>y)>9}kln&gi6fY5WL?FY~)zBUo7hojylB>ckKP z9@V7t?Y;v#&lg*3=x(@m&|NPsWS=;DXjc4&d2-K2d15mHqu^JVf86B$ zwha$np>CJG5HEXn>hKKHR{qBSP`C!kPYP%G6b8J4D9aiBkmH4IkZHEWFZkL5q#jP?B_LfKgdHe{O5-uejHh%VI)V z&_X_y{$$A5f8Pbd|EFKW^+&_8sbpAb1-hCyZ>&Q$wv$xjlF3RHrW7SEbJTPM)WiaU z?tY5j)VMrwML=VWl3aATRc|xo*b+_wyQxax)P1ahgh-`>FgRNnE<#;QB4R{7^nFM| z+m$;T%(fdGtbe(x>en@PWToe6l4(N^GLfx~>jP-;L@gMIgG(0{I6|ugU;@HSj1+CJ zRH;hOVf3>_(w~b1f$*eT)^S^p0^&Q&n^}6J`@YXMyfoQJFH zCycLY$}cMmLj-8o=MI|&YIOz*f7(IXd(i+qg%7+E!-6SmKf=l`ByW?lc!AaW;;+wE z{+I|2DR%KC?5sQ;M~ymo|2>;kg+(gL-$kA{NfeVtTc9T;EWebp9_ybMt-m$QCXzQe4t0it&8G<^E0MEkCEQ;h2f^(j=UC$9Nv10*;hc!0KTrBIv=@##)uSw-< z+G7pUtcL=q%am;hiSS?uU7HkO)gy&|JMpCdhyTP$5H;I)w+TJFO$wHC|8(b?Z zrE&YSz6q*C2cMth&73H|Jz0CeKT^%SYGj;oRC%dNYDcl*<_?)1p?6b(?m&EiDQlV_ zgJhHUI%5PZo_Rf2FwvFm&l?I+NbhLkO;G6NM|JNNvRU3okL7*vA{2$wts21L=qJPb zkr_|rIjV^qal~ea1A4i`iP1gZ8qo4-7ICB)URs%)TKY)T{+FIFBe!1j#_jUoI?V<#_?gG?6pNqvwr zfnT?SvagQf+33V&;^^(`^d*2p7uUz1rg=wtf78PmC*1Vu?Ddzc}Li|nFxG~>LtQm>V*6%%q)?c1N)7#nJLISPRykOjmK5Q?UP%@j8DyrLv|>4hL1r z4PslMnL_2Ug<=Kbs94*>P03DXOU49kvn>AHh5+)Kqu?J}`5s}^4uJCA(T}$nKWsCB z95eqQkkhmdXscRHV9o-AYhj8VLj|SZFDqN%6vhHf>iEkygNrW|vIQFY;9^tnQLiYU z36%=7@f3>Xu2`XiJDR3LDO01Nmx;4Z5EO5@D(>o=ZEsBE2j)v~)GYC;qM*hGdBtox z>#nJv?`{ZGKnE&pZiXIH^5b3nI<%6h^IoF*uKDDP=Slh%Gq0IhvED;^%3*K~yruu} z%8jCv=aS@T?{9}a*wXl^u{rJyqs0Q|hv}WY;}VOo1PBKgWyb{MNA1@61JkaN%6S)_ zjW*a$w%*>jsY^_E*u#SrTKqjbE)@jl7&u&t;H+G?VmydH>)MLN^0ZUA!^^UY^U*>brSFr#CZ$uy%a?_RMs}=!Vf@)?3Nis88_GR_k<4?%)g&wU&3+2wY>F+M+) zEwP?ckSy@He!NBfQ3q9SSXDmP&AV%Rx__!XL)PksBE5I-fhv*3&d-_G4=VasN*iT^ zb(E_nzQx%(WejNPbm~JM35SSERW@X$vL=v7s;%o?6K5B}4Bb0hlp9;EDEd2h$D{#m z_&y}4rfHLs&~@p=7YFq)PIFh_b(W|>5Pbwps-!u&Wvzx z=RKxOM#Qdwe+KVp#PtyXT#&Fj6AccE5lr}O@ZW`{U}iR;1%7S7QT9~^1BuBn{;}4_ zA0+N%XIZOMm1bFkf)9kYp_s8ERLRB9FyO&r8CEsURS?sH?PQ+Ok~9X#_OS zV@t&fko|irq{Q%e7Jo}Rn(=e#p4h@z7C#I3<*$d|K<)etn-4C4N{Ed zB1FfmM_a&ivODtih7F}b+zdjekE9KAmr-l~2nY|ChvRTm3-(a9Gzwnicl~xnhOt@; zrF}r4fMk`D!lLYeV0y)}dr1^DWpgp5@4b!9^Db%!yV={)=HX3BM zqFMSyJm+2ei6rTpgc-Z(#b-HPb*MH&%M)4}<rSx^2TjtUC-Y@zzr?sT$y^@9dAEEhJ%El~!!;{s~M|x^D>4~5< zcUH2P>n1lI9;aq2`C*Y|V%c)NM#&+rfnLvN%|2GCwT(Dp`-^qQ1I?~9ILU3@a!;zw zt@Y*ru{Xkp6rZt@kkA&KRx*`)^=YE<%OWi3T}|cpFt+q?@;&{^3yTC^WcIu_tt&z( z>T&G4tg3*ja^9BUyaV1&$>gW*?s-Id%TU|E)8>6>w=J8qd~T}24R4g2Biwzh3N*q{ zjcMFhHNo~4_mKT5-BFwgjKN`%(p-+8p7o^U**=vX^Bp~>Px^#BR>Q1sTxUBt$C(n> zlT-I1>JJ{*2&oHOS^V8K-o)SyGGK9=DJ5;-|Q|MeR+PvgKrIu#J0W3MWQG0 z%V(R?-29H@-|@?mwX*msxSms$r?~gQbZG{XaS2OPUBl1v1E104zBfB2e-><>?mVG@O>g>=H|H@R$Y zNIL%f&L`@{`%yDd&EN1iX|`)D%)r#uWUP9s3iJGsGCPCa>|+Cw>O*`rNb@*yK>_Cy zoAi3;;X=*G*5MJJpp?DwJDzb7^dn+JZTxm4;H`uGCwTIgn#;F)+-4%>+#Qu3Ew@51 zr%7Jg`mB>`EWKU~Jh~hvb!2sLC*1}FMgR!@B7R-O{&C~SBG*3sbD{swlJ?(aepRIV zDRY?b?0zfrFD1LbEBvbR@KXUH^m~PWtwa1>;#bG2pAv;4|03~!AF}=~^sB7wr%)Ha zR`I)k%Ygj59PRJV|5c#*`FscXzdir|8Fqfk{TiP&Ina+iwjlE>x&I9l-9`|)_6s5Y N>pU0$uFI~C{tF!eHJ1PY literal 0 HcmV?d00001 diff --git a/documentation/chargepoint/Testdata-secp256r1/0024b1000002e300_2.zip b/documentation/chargepoint/Testdata-secp256r1/0024b1000002e300_2.zip new file mode 100644 index 0000000000000000000000000000000000000000..31086d4f65dff18c4b687e6eaf6fc8dd4a53c92c GIT binary patch literal 1480 zcmWIWW@Zs#00H5c0{=}?riY&~GcbU#4p7X%z{n)Y&;SICQjHA^;*H`B4K2+qjV&xq z;|mfibMg~Y^hy$o^pdKKoT4%;4ILxZf+M#ot@2=CF8Kfd&kq;Io2vhR+VB7O>i_@$ zuNqtvCM7eaYIQI(thmrJ%P)Yr$MmiDG*xZ32}{0w@mz4zIg7D_;j0t_vqJ_$h9m>y z1ZHQZT!ksKI41{RwKa8La`{S%twU8W11|%ElnDa^5HTUV=*2^EbKnf`Em4V@c6yqx(i*4WQ zi%yyc5A-ci@YrDD$Pm=wrsNq0h1eZ>? z2&1T&$B}N~y=BLk8kVp&t>Nyzy((zx>J4T>TQ&t<3;KP#a{l&vhomm5v`Y1DH}78j z*pJ;_a{J=ooh!Dt2fV!bCaiI`@b(+8_DOEY)1GdUbR_NS>WG&uj(0P=J}H`q{X1(Y zD9qs?=W;Rh>bvaq-5XsNbq3s<64t|Q`udt?Vj}yAY{4@(7mAg9_E56;7GiTpLnZV@ z*CL-qdJz}=Tto%#yvl8ub|dB8a?PubYu5N!>Q{WT5p7zc5vR!fwXb<=!K&;nQ(v)urT!S*x=Rd$v5dvtf$ZROSOU`8%|PN*E8{<`m3oIJWeg zW=z&gkGm7j33_gQ9O%ZhGfGkLn#w^NS2lu#>PTY6wX`H0Y{_6y%#wNKiU5O&mY?cQGU2Qiw`3_AGdT`{3-1n2s=lt9a zwN^?fI&S4rXK2y6keISH`1ZWKN)XqX zj@zu_hlL)xk9NMd zo#e2l`NRdCekaYWneqI4GlEtmtnsN{6cJ$Hnp5#5GfkyUB{jLgh*u^|m`TBFo6;Et zU;P7|irl@zOh#u`muXmVN%Fo`@>W3r^=z$C^ZPev%g&W~wUTeQEyzCeM0)W*y(e7- z3l+0mLnZ`3%L@*Mfan5$lgm!+bAb6~8xSi1F=lz8TTq&mlbP(DTB%o%ntS;wE0cP7 zxxamDLx8%xe>!Xab&m-%^z^5%k1pGpUAd&aylzT*=(NVo$q7r;r@Vb6G2@NUjCU`h z@`NS{y`1?rbwb)p@swB7W=gJ^`!q33WXjCYtb?bgN<4ZpRb2AL+u0%07U#~IClonl z(u>FI=gP*slbgEu{q(@4bERi3l%JY8b8dRn#HZ4k8H@6hBqruOdzz7b`ZQ}<+v@q; z%T6-{cr!AIFyJl=f!+fG1u%)tr?^W-gvr=L4P+!EB>Y&gnT#5S0p6@^ARSCVxB^IX Hv4VI2)51RU literal 0 HcmV?d00001 diff --git a/package-lock.json b/package-lock.json index 42f1ab0..c72a887 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,7 +29,6 @@ "version": "4.11.5", "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.5.tgz", "integrity": "sha512-AEAZcIZga0JgVMHNtl1CprA/hXX7/wPt79AgR4XqaDt7jyj3QWYw6LPoOiznPtugDmlubUnAahMs2PFxGcQrng==", - "dev": true, "requires": { "@types/node": "*" } @@ -59,7 +58,6 @@ "version": "6.4.10", "resolved": "https://registry.npmjs.org/@types/elliptic/-/elliptic-6.4.10.tgz", "integrity": "sha512-9h+Bw+aNiLzcq9DGstHccNxSsJ5iNId7mzruid7+kwm7F1IGvb4rBOOPo3+twt9ZPhI3y+JJ2m1UfgU8cOEJuQ==", - "dev": true, "requires": { "@types/bn.js": "*" } @@ -82,8 +80,7 @@ "@types/node": { "version": "12.12.8", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.8.tgz", - "integrity": "sha512-XLla8N+iyfjvsa0KKV+BP/iGSoTmwxsu5Ci5sM33z9TjohF72DEz95iNvD6pPmemvbQgxAv/909G73gUn8QR7w==", - "dev": true + "integrity": "sha512-XLla8N+iyfjvsa0KKV+BP/iGSoTmwxsu5Ci5sM33z9TjohF72DEz95iNvD6pPmemvbQgxAv/909G73gUn8QR7w==" }, "abbrev": { "version": "1.1.1", @@ -314,6 +311,16 @@ "safer-buffer": "~2.1.0" } }, + "asn1.js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.2.0.tgz", + "integrity": "sha512-Q7hnYGGNYbcmGrCPulXfkEw7oW7qjWeM4ZTALmgpuIcZLxyqqKYWxCZg2UBm8bklrnB4m2mGyJPWfoktdORD8A==", + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", @@ -2046,6 +2053,17 @@ "verror": "1.10.0" } }, + "key-encoder": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/key-encoder/-/key-encoder-2.0.3.tgz", + "integrity": "sha512-fgBtpAGIr/Fy5/+ZLQZIPPhsZEcbSlYu/Wu96tNDFNSjSACw5lEIOFeaVdQ/iwrb8oxjlWi6wmWdH76hV6GZjg==", + "requires": { + "@types/elliptic": "^6.4.9", + "asn1.js": "^5.0.1", + "bn.js": "^4.11.8", + "elliptic": "^6.4.1" + } + }, "keyv": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", diff --git a/package.json b/package.json index ad19b9e..cfc6b19 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "license": "AGPL-3.0-or-later", "homepage": "https://github.com/OpenChargingCloud/ChargyDesktopApp", "dependencies": { + "asn1.js": "^5.2.0", "base32-decode": "^1.0.0", "chart.js": "^2.9.3", "decompress": "^4.2.0", @@ -34,6 +35,7 @@ "decompress-tarxz": "^3.0.0", "elliptic": "^6.5.1", "file-type": "^12.4.0", + "key-encoder": "^2.0.3", "leaflet": "^1.5.1", "leaflet.awesome-markers": "^2.0.5", "moment": "^2.24.0" diff --git a/src/js/chargepoint.ts b/src/js/chargepoint.ts index 4e4da64..448337a 100644 --- a/src/js/chargepoint.ts +++ b/src/js/chargepoint.ts @@ -333,7 +333,8 @@ class Chargepoint { { - "rawData": SomeJSON, + "original": SomeJSON.original, + "signature": SomeJSON.signature, "@id": SomeJSON.additional_info.station_mac + "-" + SomeJSON.additional_info.outlet + "-" + diff --git a/src/js/chargepointCrypt01.ts b/src/js/chargepointCrypt01.ts index e636934..8faebda 100644 --- a/src/js/chargepointCrypt01.ts +++ b/src/js/chargepointCrypt01.ts @@ -130,67 +130,93 @@ class ChargepointCrypt01 extends ACrypt { // ASN1 OID: secp224k1 // read EC key - let sessionResult = SessionVerificationResult.UnknownSessionFormat; - - let publicKeyId = chargingSession.EVSEId.replace(/:/g, "").replace(/-/g, "_"); - let publicKey = ""; - if (chargingSession.ctr?.publicKeys != null) + try { - for (let publicKeyInfo of chargingSession.ctr?.publicKeys) + + let sessionResult = SessionVerificationResult.UnknownSessionFormat; + + let publicKeyId = chargingSession.EVSEId.replace(/:/g, "").replace(/-/g, "_"); + let publicKey = ""; + if (chargingSession.ctr?.publicKeys != null) { - if (publicKeyInfo.keyId === publicKeyId) - publicKey = publicKeyInfo.value; + for (let publicKeyInfo of chargingSession.ctr?.publicKeys) + { + if (publicKeyInfo.id === publicKeyId) + publicKey = publicKeyInfo.value; + } } - } - var plainText = chargingSession.rawData; + var plainText = chargingSession.original != null ? atob(chargingSession.original) : ""; + var signature = chargingSession.signature; - if (publicKey != null && plainText != null) - { - sessionResult = SessionVerificationResult.ValidSignature; - } - - if (chargingSession.measurements) - { - for (var measurement of chargingSession.measurements) + if (publicKey !== "" && plainText !== "" && signature !== "") { - measurement.chargingSession = chargingSession; + let sha256value = await sha256(plainText); - // Must include at least two measurements (start & stop) - if (measurement.values && measurement.values.length > 1) + if (this.curve.keyFromPublic(publicKey, 'hex'). + verify (sha256value, + signature)) { - // Validate... - for (var measurementValue of measurement.values) - { - measurementValue.measurement = measurement; - await this.VerifyMeasurement(measurementValue as IChargepointMeasurementValue); - } - - - // Find an overall result... sessionResult = SessionVerificationResult.ValidSignature; - for (var measurementValue of measurement.values) + if (chargingSession.measurements) { - if (sessionResult == SessionVerificationResult.ValidSignature && - measurementValue.result.status != VerificationResult.ValidSignature) + for (let measurement of chargingSession.measurements) { - sessionResult = SessionVerificationResult.InvalidSignature; + + measurement.chargingSession = chargingSession; + + // Must include at least two measurements (start & stop) + if (measurement.values && measurement.values.length > 1) + { + + // Validate... + for (let measurementValue of measurement.values) + { + measurementValue.measurement = measurement; + await this.VerifyMeasurement(measurementValue as IChargepointMeasurementValue); + } + + // Find an overall result... + for (let measurementValue of measurement.values) + { + if (measurementValue.result.status != VerificationResult.ValidSignature && + measurementValue.result.status != VerificationResult.NoOperation) + { + sessionResult = SessionVerificationResult.InvalidSignature; + } + } + + } + + else + sessionResult = SessionVerificationResult.AtLeastTwoMeasurementsExpected; + } } + else + sessionResult = SessionVerificationResult.InvalidSessionFormat; } else - sessionResult = SessionVerificationResult.AtLeastTwoMeasurementsExpected; + sessionResult = SessionVerificationResult.InvalidSignature; } - } - return { - status: sessionResult + return { + status: sessionResult + } + + } + catch (exception) + { + return { + status: SessionVerificationResult.InvalidSignature, + message: exception.message + } } } @@ -284,7 +310,7 @@ class ChargepointCrypt01 extends ACrypt { } - async ViewMeasurement (measurementValue: IChargepointMeasurementValue, + async ViewMeasurement(measurementValue: IChargepointMeasurementValue, introDiv: HTMLDivElement, infoDiv: HTMLDivElement, bufferValue: HTMLDivElement, diff --git a/src/js/chargy.ts b/src/js/chargy.ts index f2e59d8..3cffcb3 100644 --- a/src/js/chargy.ts +++ b/src/js/chargy.ts @@ -234,14 +234,14 @@ class Chargy { { let compressedFiles:Array = await decompress(Buffer.from(FileInfo.data), - { plugins: [ decompressTar(), - decompressTargz(), - decompressTarbz2(), - // decompressTarxz(), - decompressUnzip(), - decompressGz(), - decompressBzip2() - ] }); + { plugins: [ decompressTar(), + decompressTargz(), + decompressTarbz2(), + //decompressTarxz(), + decompressUnzip(), + decompressGz(), + decompressBzip2() + ] }); archiveFound = true; @@ -299,8 +299,10 @@ class Chargy { CTRfile = JSON.parse(dataFile); CTRfile.original = btoa(dataFile); // Save the original JSON with whitespaces for later signature verification! CTRfile.signature = singatureFile; - expandedFileInfos.push({ name: FileInfo.name, - data: new TextEncoder().encode(JSON.stringify(CTRfile)) }); + expandedFileInfos.push({ + name: FileInfo.name, + data: new TextEncoder().encode(JSON.stringify(CTRfile)) + }); continue; } @@ -469,25 +471,82 @@ class Chargy { textContent?.endsWith ("-----END PUBLIC KEY-----")) { - textContent = textContent.replace("-----BEGIN PUBLIC KEY-----", ""). - replace("-----END PUBLIC KEY-----", ""). - replace(/\s+/g, ''). - trim(); + try + { - let keyId = processedFile.name.indexOf('.') > -1 - ? processedFile.name.substring(0, processedFile.name.indexOf('.')) - : processedFile.name; + const keyId = (processedFile.name.indexOf('.') > -1 + ? processedFile.name.substring(0, processedFile.name.indexOf('.')) + : processedFile.name).replace("-publicKey", ""); + + const publicKeyPEM = textContent.replace("-----BEGIN PUBLIC KEY-----", ""). + replace("-----END PUBLIC KEY-----", ""). + split ('\n'). + map ((line) => line.trim()). + filter ((line) => line !== '' && !line.startsWith('#')). + join (""); + + // https://lapo.it/asn1js/ for a visual check... + const ASN1 = require('asn1.js'); + + const ASN1_OIDs = ASN1.define('OIDs', function() { + //@ts-ignore + this.key('oid').objid() + }); + + const ASN1_PublicKey = ASN1.define('PublicKey', function() { + //@ts-ignore + this.seq().obj( + //@ts-ignore + this.key('oids').seqof(ASN1_OIDs), + //@ts-ignore + this.key('publicKey').bitstr() + ); + }); + + const publicKeyDER = ASN1_PublicKey.decode(Buffer.from(publicKeyPEM, 'base64'), 'der'); + + const KeyType_OID = publicKeyDER.oids[0].join(".") as string; + let KeyType = "unknown"; + switch (KeyType_OID) + { + case "1.2.840.10045.2.1": + KeyType = "ecPublicKey"; // ANSI X9.62 public key type + break; + } - processedFile.result = { - "@id": keyId, - "@context": "https://open.charging.cloud/contexts/CTR+json", - publicKeys: [ - { - keyId: keyId, - value: textContent - } - ] - }; + const Curve_OID = publicKeyDER.oids[1].join(".") as string; + let Curve = "unknown"; + switch (Curve_OID) + { + case "1.2.840.10045.3.1.7": + Curve = "prime256v1"; // ANSI X9.62 named elliptic curve + break; + } + + processedFile.result = { + "@id": keyId, + "@context": "https://open.charging.cloud/contexts/CTR+json", + publicKeys: [ + { + id: keyId, + type: { + oid: KeyType_OID, + description: KeyType + }, + curve: { + oid: Curve_OID, + description: Curve + }, + value: buf2hex(publicKeyDER.publicKey.data) + } + ] + }; + + } + catch (exception) + { + // Just ignore this file... + } } diff --git a/src/js/chargyInterfaces.ts b/src/js/chargyInterfaces.ts index 031013e..67ec7eb 100644 --- a/src/js/chargyInterfaces.ts +++ b/src/js/chargyInterfaces.ts @@ -103,8 +103,24 @@ interface IPublicKeyLookup } interface IPublicKeyInfo +{ + id: string; + type: IOIDInfo; + curve: IOIDInfo; + value: string; +} + +interface IOIDInfo +{ + oid: string; + description: string; +} + +interface IKeyInfo { keyId: string; + keyType: string; + curve: string; value: string; } @@ -231,7 +247,8 @@ interface IChargingSession measurements: Array; parking: Array; method: ACrypt; - rawData?: string; + original?: string; + signature?: string; verificationResult?: ISessionCryptoResult; } From 4ff58a0c22aa5c5af71e06f340d9841b928678b0 Mon Sep 17 00:00:00 2001 From: Achim 'ahzf' Friedland Date: Sun, 17 Nov 2019 16:47:47 +0100 Subject: [PATCH 032/110] Fix OCMF parsing bug --- src/js/OCMF.ts | 14 ++++---- src/js/chargepointCrypt01.ts | 62 +++++++++++++++++++----------------- src/js/chargy.ts | 20 ++++++++---- 3 files changed, 51 insertions(+), 45 deletions(-) diff --git a/src/js/OCMF.ts b/src/js/OCMF.ts index e6d18a8..f5fa5bd 100644 --- a/src/js/OCMF.ts +++ b/src/js/OCMF.ts @@ -359,9 +359,7 @@ class OCMF { } - return { - status: SessionVerificationResult.InvalidSessionFormat - } + return CTR; } catch (exception) @@ -505,13 +503,13 @@ class OCMF { switch (commonVersion) { - case "0.1": - //@ts-ignore - return await this.tryToParseOCMFv0_1(OCMFDataList as IOCMFData_v0_1[], PublicKey); + // case "0.1": + + // return await this.tryToParseOCMFv0_1(OCMFDataList as IOCMFData_v0_1[], PublicKey); case "1.0": - //@ts-ignore - return await this.tryToParseOCMFv1_0(OCMFDataList as IOCMFData_v1_0[], PublicKey); + + return await this.tryToParseOCMF(OCMFDataList as IOCMFData_v1_0[], PublicKey); default: return { diff --git a/src/js/chargepointCrypt01.ts b/src/js/chargepointCrypt01.ts index 8faebda..8fe1757 100644 --- a/src/js/chargepointCrypt01.ts +++ b/src/js/chargepointCrypt01.ts @@ -55,23 +55,34 @@ interface IChargepointCrypt01Result extends ICryptoResult class ChargepointCrypt01 extends ACrypt { readonly curve = new this.chargy.elliptic.ec('p256'); - // Koblitz 224-bit curve - // https://www.secg.org/sec2-v2.pdf - // this.chargy.elliptic.defineCurve('secp224k1', { - // type: 'short', - // prime: 'k224', - // p: 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFE56D', - // a: '00000000 00000000 00000000 00000000 00000000 00000000 00000000', - // b: '00000000 00000000 00000000 00000000 00000000 00000000 00000005', - // n: '00000000 00000000 00000000 0001DCE8 D2EC6184 CAF0A971 769FB1F7', - // h: 1, - // hash: this.chargy.elliptic.hash.sha512, - // gRed: false, - // g: [ - // 'A1455B33 4DF099DF 30FC28A1 69A467E9 E47075A9 0F7E650E B6B7A45C', - // '7E089FED 7FBA3442 82CAFBD6 F7E319F7 C0B0BD59 E2CA4BDB 556D61A5' - // ] - // }); + + // $ openssl ec -inform PEM -pubin -in 0024b10000027b29_1.pem -text -noout + // Public-Key: (225 bit) + // pub: + // 04:f6:b9:4d:1d:0d:4c:95:24:41:b9:44:34:ac:41: + // 3b:0c:3d:97:ee:e7:f1:19:36:9c:ac:3a:07:a2:e8: + // 12:98:f4:2f:f6:eb:f1:2d:de:16:e1:b5:7d:a1:12: + // 13:45:70:21:1d:c7:a9:f3:48:9a:e1:a4 + // ASN1 OID: secp224k1 + // read EC key + // + // Koblitz 224-bit curve + // https://www.secg.org/sec2-v2.pdf + // this.chargy.elliptic.defineCurve('secp224k1', { + // type: 'short', + // prime: 'k224', + // p: 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFE56D', + // a: '00000000 00000000 00000000 00000000 00000000 00000000 00000000', + // b: '00000000 00000000 00000000 00000000 00000000 00000000 00000005', + // n: '00000000 00000000 00000000 0001DCE8 D2EC6184 CAF0A971 769FB1F7', + // h: 1, + // hash: this.chargy.elliptic.hash.sha512, + // gRed: false, + // g: [ + // 'A1455B33 4DF099DF 30FC28A1 69A467E9 E47075A9 0F7E650E B6B7A45C', + // '7E089FED 7FBA3442 82CAFBD6 F7E319F7 C0B0BD59 E2CA4BDB 556D61A5' + // ] + // }); constructor(chargy: Chargy) { @@ -93,7 +104,6 @@ class ChargepointCrypt01 extends ACrypt { // ] //}); - } @@ -120,16 +130,6 @@ class ChargepointCrypt01 extends ACrypt { async VerifyChargingSession(chargingSession: IChargingSession): Promise { - // $ openssl ec -inform PEM -pubin -in 0024b10000027b29_1.pem -text -noout - // Public-Key: (225 bit) - // pub: - // 04:f6:b9:4d:1d:0d:4c:95:24:41:b9:44:34:ac:41: - // 3b:0c:3d:97:ee:e7:f1:19:36:9c:ac:3a:07:a2:e8: - // 12:98:f4:2f:f6:eb:f1:2d:de:16:e1:b5:7d:a1:12: - // 13:45:70:21:1d:c7:a9:f3:48:9a:e1:a4 - // ASN1 OID: secp224k1 - // read EC key - try { @@ -146,8 +146,8 @@ class ChargepointCrypt01 extends ACrypt { } } - var plainText = chargingSession.original != null ? atob(chargingSession.original) : ""; - var signature = chargingSession.signature; + let plainText = chargingSession.original != null ? atob(chargingSession.original) : ""; + let signature = chargingSession.signature; if (publicKey !== "" && plainText !== "" && signature !== "") { @@ -293,6 +293,8 @@ class ChargepointCrypt01 extends ACrypt { async VerifyMeasurement(measurementValue: IChargepointMeasurementValue): Promise { + // Note: chargepoint does not sign individual measurements! + function setResult(verificationResult: VerificationResult) { cryptoResult.status = verificationResult; diff --git a/src/js/chargy.ts b/src/js/chargy.ts index 3cffcb3..effa647 100644 --- a/src/js/chargy.ts +++ b/src/js/chargy.ts @@ -227,7 +227,9 @@ class Chargy { let mimeType = fileType(FileInfo.data)?.mime; - if (mimeType != null && mimeType != undefined) + if (mimeType != null && + mimeType != undefined && + mimeType != "application/xml") { try @@ -243,6 +245,9 @@ class Chargy { decompressBzip2() ] }); + if (compressedFiles.length == 0) + continue; + archiveFound = true; //#region A single compressed file without a path/filename, e.g. within bz2 @@ -317,8 +322,8 @@ class Chargy { if (compressedFile.type === "file") { expandedFileInfos.push({ name: compressedFile.path?.substring(compressedFile.path.lastIndexOf('/') + 1 - ?? FileInfo.name), - data: compressedFile.data }); + ?? FileInfo.name), + data: compressedFile.data }); } } @@ -335,7 +340,7 @@ class Chargy { } expandedFileInfos.push({ name: FileInfo.name, - data: FileInfo.data }); + data: FileInfo.data }); } @@ -486,6 +491,7 @@ class Chargy { join (""); // https://lapo.it/asn1js/ for a visual check... + // https://github.com/indutny/asn1.js const ASN1 = require('asn1.js'); const ASN1_OIDs = ASN1.define('OIDs', function() { @@ -755,9 +761,6 @@ class Chargy { this.eMobilityProviders = []; this.mediationServices = []; - this.currentCTR = CTR; - this.internalCTR = JSON.parse(JSON.stringify(CTR)); // Operate on a copy of the data! - //#endregion //ToDo: Verify @context @@ -765,6 +768,9 @@ class Chargy { try { + this.currentCTR = CTR; + this.internalCTR = JSON.parse(JSON.stringify(CTR)); // Operate on a copy of the data! + //#region Process operators (pools, stations, evses, tariffs, ...) if (this.internalCTR.chargingStationOperators) From 5c8d871f4e8e38d8f541239eeb036c7157300816 Mon Sep 17 00:00:00 2001 From: Achim 'ahzf' Friedland Date: Thu, 21 Nov 2019 22:08:52 +0100 Subject: [PATCH 033/110] Fix Alfen BigInt issue --- src/js/Alfen.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/Alfen.ts b/src/js/Alfen.ts index 3778359..5df81e8 100644 --- a/src/js/Alfen.ts +++ b/src/js/Alfen.ts @@ -140,7 +140,7 @@ class Alfen { let _ObisId = this.bufferToHex(ObisId); let _Unit = this.bufferToHex(Unit); let _Scalar = this.bufferToHex(Scalar); - let _Value = new DataView(Value, 0).getBigInt64(0, true); + let _Value = new Number(new DataView(Value, 0).getBigInt64(0, true)); let _UID = String.fromCharCode.apply(null, new Uint8Array(UID) as any).replace(/\0.*$/g, ''); let _SessionId = new DataView(SessionId, 0).getInt32 (0, true); let _Paging = new DataView(Paging, 0).getInt32 (0, true); From 069669091071380ed7fd0e30fdd250e6ce4c3c8a Mon Sep 17 00:00:00 2001 From: Achim 'ahzf' Friedland Date: Thu, 28 Nov 2019 04:10:34 +0100 Subject: [PATCH 034/110] Extend measurement verification interface to allow results like: (In)ValidStartValue, (In)ValidIntermediateValue, (In)ValidStopValue and StartValue, IntermediateValue, StopValue (without any verification at all) as this is assumed to be more userfriendly --- src/css/chargy.scss | 23 ++++-- src/js/chargepointCrypt01.ts | 72 +++++++++++++++- src/js/chargyApp.ts | 156 ++++++++++++++++------------------- src/js/chargyInterfaces.ts | 14 ++++ src/js/chargyLib.ts | 23 ++++++ 5 files changed, 195 insertions(+), 93 deletions(-) diff --git a/src/css/chargy.scss b/src/css/chargy.scss index 77438b6..5f0f140 100644 --- a/src/css/chargy.scss +++ b/src/css/chargy.scss @@ -998,41 +998,51 @@ body { display: table-cell; padding: 2px 16px 2px 12px; border-radius: 4px 0px 0px 4px; - white-space: nowrap + white-space: nowrap; } .value1 { display: table-cell; text-align: right; padding-right: 5px; - white-space: nowrap + white-space: nowrap; } .unit1 { display: table-cell; padding-right: 10px; - white-space: nowrap + white-space: nowrap; } .value2 { display: table-cell; text-align: right; padding-right: 5px; - white-space: nowrap + white-space: nowrap; } .unit2 { display: table-cell; padding-right: 10px; - white-space: nowrap + white-space: nowrap; } .verificationStatus { + display: table-cell; padding: 2px 6px; border-radius: 0px 4px 4px 0px; width: 100%; - white-space: nowrap + white-space: nowrap; + + .noValidation { + position: relative; + top: -1px; + font-size: 85%; + font-style: italic; + color: rgba(44, 74, 96, 0.5); + } + } } @@ -1305,6 +1315,7 @@ body { #overlayOkButton { border: 0; + outline: 0; background-color: transparent; color: #b6d8f1; margin: 4px; diff --git a/src/js/chargepointCrypt01.ts b/src/js/chargepointCrypt01.ts index 8fe1757..5b91094 100644 --- a/src/js/chargepointCrypt01.ts +++ b/src/js/chargepointCrypt01.ts @@ -179,7 +179,8 @@ class ChargepointCrypt01 extends ACrypt { await this.VerifyMeasurement(measurementValue as IChargepointMeasurementValue); } - // Find an overall result... + //#region Find an overall result... + for (let measurementValue of measurement.values) { if (measurementValue.result.status != VerificationResult.ValidSignature && @@ -189,8 +190,74 @@ class ChargepointCrypt01 extends ACrypt { } } - } + //#endregion + + //#region Adapt measurement results + + if (sessionResult == SessionVerificationResult.ValidSignature) + { + for (let i = 0; i < measurement.values.length; i++) + { + + // Start value + if (i == 0) + { + switch (measurement.values[i].result.status) + { + + case VerificationResult.ValidSignature: + measurement.values[i].result.status = VerificationResult.ValidStartValue; + break; + + case VerificationResult.NoOperation: + measurement.values[i].result.status = VerificationResult.StartValue; + break; + + } + } + + // Stop value + else if (i = measurement.values.length-1) + { + switch (measurement.values[i].result.status) + { + + case VerificationResult.ValidSignature: + measurement.values[i].result.status = VerificationResult.ValidStopValue; + break; + + case VerificationResult.NoOperation: + measurement.values[i].result.status = VerificationResult.StopValue; + break; + } + + } + + // Intermediate values + else + { + switch (measurement.values[i].result.status) + { + + case VerificationResult.ValidSignature: + measurement.values[i].result.status = VerificationResult.ValidIntermediateValue; + break; + + case VerificationResult.NoOperation: + measurement.values[i].result.status = VerificationResult.IntermediateValue; + break; + + } + + } + + } + } + + //#endregion + + } else sessionResult = SessionVerificationResult.AtLeastTwoMeasurementsExpected; @@ -200,7 +267,6 @@ class ChargepointCrypt01 extends ACrypt { sessionResult = SessionVerificationResult.InvalidSessionFormat; } - else sessionResult = SessionVerificationResult.InvalidSignature; diff --git a/src/js/chargyApp.ts b/src/js/chargyApp.ts index 000da2b..d0613b2 100644 --- a/src/js/chargyApp.ts +++ b/src/js/chargyApp.ts @@ -1557,31 +1557,13 @@ console.log(curves); let ChargingStationHeadline = CreateDiv(ChargingStationDiv, "chargingStationHeadline", "Ladestation"); - if (measurement.chargingSession.chargingStation["@id"] != null) - { - - let ChargingStationIdDiv = CreateDiv(ChargingStationDiv, "chargingStationId"); - - let ChargingStationIdIdDiv = CreateDiv(ChargingStationIdDiv, "chargingStationIdId", - "Identifikation"); - - let ChargingStationIdValueDiv = CreateDiv(ChargingStationIdDiv, "chargingStationIdValue", - measurement.chargingSession.chargingStation["@id"]); - - } - - if (measurement.chargingSession.chargingStation.firmwareVersion != null) - { - - let firmwareVersionDiv = CreateDiv(ChargingStationDiv, "firmwareVersion"); + if (measurement.chargingSession.chargingStation["@id"]?.length > 0) + CreateDiv2(ChargingStationDiv, "chargingStationId", + "Identifikation", measurement.chargingSession.chargingStation["@id"]); - let firmwareVersionIdDiv = CreateDiv(firmwareVersionDiv, "firmwareVersionId", - "Firmware-Version"); - - let firmwareVersionValueDiv = CreateDiv(firmwareVersionDiv, "firmwareVersionValue", - measurement.chargingSession.chargingStation.firmwareVersion); - - } + if (measurement.chargingSession.chargingStation.firmwareVersion?.length > 0) + CreateDiv2(ChargingStationDiv, "firmwareVersion", + "Firmware-Version", measurement.chargingSession.chargingStation.firmwareVersion); } @@ -1590,78 +1572,44 @@ console.log(curves); //#region Show meter infos... let meterDiv = CreateDiv(MeasurementInfoDiv, "meter"); - let meterHeadline = CreateDiv(meterDiv, "meterHeadline", - "Energiezähler"); + let meterHeadline = CreateDiv(meterDiv, "meterHeadline", + "Energiezähler"); - var meter = this.chargy.GetMeter(measurement.energyMeterId); + var meter = this.chargy.GetMeter(measurement.energyMeterId); if (meter != null) { - let meterIdDiv = CreateDiv(meterDiv, "meterId"); - - let meterIdIdDiv = CreateDiv(meterIdDiv, "meterIdId", - "Seriennummer"); - - let meterIdValueDiv = CreateDiv(meterIdDiv, "meterIdValue", - measurement.energyMeterId); + CreateDiv2(meterDiv, "meterId", + "Seriennummer", measurement.energyMeterId); + if (meter.vendor?.length > 0) + CreateDiv2(meterDiv, "meterVendor", + "Zählerhersteller", meter.vendor); - let MeterVendorDiv = CreateDiv(meterDiv, "meterVendor"); - - let MeterVendorIdDiv = CreateDiv(MeterVendorDiv, "meterVendorId", - "Zählerhersteller"); - - let MeterVendorValueDiv = CreateDiv(MeterVendorDiv, "meterVendorIdValue", - meter.vendor); - - - let MeterModelDiv = CreateDiv(meterDiv, "meterModel"); - - let MeterModelIdDiv = CreateDiv(MeterModelDiv, "meterModelId", - "Model"); - - let MeterModelValueDiv = CreateDiv(MeterModelDiv, "meterModelIdValue", - meter.model); + if (meter.model?.length > 0) + CreateDiv2(meterDiv, "meterModel", + "Model", meter.model); } //#endregion - //#region ...or show meterId infos - - else { + //#region ...or just show the meter identification - let meterIdDiv = CreateDiv(meterDiv, "meterId"); - - let meterIdIdDiv = CreateDiv(meterIdDiv, "meterIdId", - "Zählerseriennummer"); - - let meterIdValueDiv = CreateDiv(meterIdDiv, "meterIdValue", - measurement.energyMeterId); - - } + else + CreateDiv2(meterDiv, "meterId", + "Zählerseriennummer", measurement.energyMeterId); //#endregion //#region Show measurement infos - let measurementDiv = CreateDiv(meterDiv, "measurement"); - - let MeasurementIdDiv = CreateDiv(measurementDiv, "measurementId", - "Messung"); + CreateDiv2(meterDiv, "measurement", + "Messung", measurement.name); - let MeasurementIdValueDiv = CreateDiv(measurementDiv, "measurementIdValue", - measurement.name); - - - let OBISDiv = CreateDiv(meterDiv, "OBIS"); - - let OBISIdDiv = CreateDiv(OBISDiv, "OBISId", - "OBIS-Kennzahl"); - - let OBISValueDiv = CreateDiv(OBISDiv, "OBISValue", - parseOBIS(measurement.obis)); + CreateDiv2(meterDiv, "OBIS", + "OBIS-Kennzahl", parseOBIS(measurement.obis)); //#endregion @@ -1672,7 +1620,7 @@ console.log(curves); let meterHeadline = CreateDiv(this.evseTarifInfosDiv, "measurementsHeadline", "Messwerte"); - meterHeadline.id = "measurementValues-headline"; + meterHeadline.id = "measurementValues-headline"; let MeasurementValuesDiv = CreateDiv(this.evseTarifInfosDiv, "measurementValues"); let previousValue = 0; @@ -1730,13 +1678,14 @@ console.log(curves); } let valueDiv = CreateDiv(MeasurementValueDiv, "value2", - "+" + (previousValue > 0 - ? parseFloat((currentValue - previousValue).toFixed(10)) - : "0")); + previousValue > 0 + ? "+" + parseFloat((currentValue - previousValue).toFixed(10)) + : "0"); let unitDiv = CreateDiv(MeasurementValueDiv, "unit2", - "kWh"); - + previousValue > 0 + ? "kWh" + : ""); //#region Show signature status @@ -1762,18 +1711,57 @@ console.log(curves); icon = ' Ungültiger Public Key'; break; + case VerificationResult.InvalidSignature: icon = ' Ungültige Signatur'; break; + case VerificationResult.InvalidStartValue: + icon = ' Ungültiger Startwert'; + break; + + case VerificationResult.InvalidIntermediateValue: + icon = ' Ungültiger Zwischenwert'; + break; + + case VerificationResult.InvalidStopValue: + icon = ' Ungültiger Endwert'; + break; + + case VerificationResult.NoOperation: - icon = ' Keine Validierung'; + icon = '
Messwert
'; break; + case VerificationResult.StartValue: + icon = '
Startwert
'; + break; + + case VerificationResult.IntermediateValue: + icon = '
Zwischenwert
'; + break; + + case VerificationResult.StopValue: + icon = '
Endwert
'; + break; + + case VerificationResult.ValidSignature: icon = ' Gültige Signatur'; break; + case VerificationResult.ValidStartValue: + icon = ' Gültiger Startwert'; + break; + + case VerificationResult.ValidIntermediateValue: + icon = ' Gültiger Zwischenwert'; + break; + + case VerificationResult.ValidStopValue: + icon = ' Gültiger Endwert'; + break; + } let verificationStatusDiv = CreateDiv(MeasurementValueDiv, diff --git a/src/js/chargyInterfaces.ts b/src/js/chargyInterfaces.ts index 67ec7eb..946bd93 100644 --- a/src/js/chargyInterfaces.ts +++ b/src/js/chargyInterfaces.ts @@ -394,13 +394,27 @@ enum SessionVerificationResult { } enum VerificationResult { + UnknownCTRFormat, EnergyMeterNotFound, PublicKeyNotFound, InvalidPublicKey, + InvalidSignature, + InvalidStartValue, + InvalidIntermediateValue, + InvalidStopValue, + NoOperation, + StartValue, + IntermediateValue, + StopValue, + ValidSignature, + ValidStartValue, + ValidIntermediateValue, + ValidStopValue + } interface IVersions { diff --git a/src/js/chargyLib.ts b/src/js/chargyLib.ts index c5b7e55..3183d84 100644 --- a/src/js/chargyLib.ts +++ b/src/js/chargyLib.ts @@ -395,6 +395,29 @@ function CreateDiv(ParentDiv: HTMLDivElement, } +function CreateDiv2(ParentDiv: HTMLDivElement, + ChildClassName: string, + // ChildAClassName: string, + ChildAInnerHTML: string, + // ChildBClassName: string, + ChildBInnerHTML: string) : HTMLDivElement +{ + + let childDiv = ParentDiv.appendChild(document.createElement('div')); + childDiv.className = ChildClassName; + + let childADiv = childDiv.appendChild(document.createElement('div')); + childADiv.className = ChildClassName + "Id"; + childADiv.innerHTML = ChildAInnerHTML; + + let childBDiv = childDiv.appendChild(document.createElement('div')); + childBDiv.className = ChildClassName + "IdValue"; + childBDiv.innerHTML = ChildBInnerHTML; + + return childDiv; + +} + function OpenExternal(URL: string) { From da4659e00ad589c3e3bfacddefad97fa216636bd Mon Sep 17 00:00:00 2001 From: Achim 'ahzf' Friedland Date: Thu, 28 Nov 2019 06:41:34 +0100 Subject: [PATCH 035/110] Fix visualization of chargepoint crypto information --- src/css/chargy.scss | 2 +- src/js/EMHCrypt01.ts | 7 +- src/js/chargepointCrypt01.ts | 171 +++++++++++++++++++---------------- src/js/chargyInterfaces.ts | 6 +- 4 files changed, 104 insertions(+), 82 deletions(-) diff --git a/src/css/chargy.scss b/src/css/chargy.scss index 5f0f140..6cb8f9f 100644 --- a/src/css/chargy.scss +++ b/src/css/chargy.scss @@ -1242,7 +1242,7 @@ body { .value { .entry { - display: inline-block; + display: inline; padding: 1px 4px 1px 4px; margin-left: -4px; border-radius: 4px; diff --git a/src/js/EMHCrypt01.ts b/src/js/EMHCrypt01.ts index 530201c..5964f6c 100644 --- a/src/js/EMHCrypt01.ts +++ b/src/js/EMHCrypt01.ts @@ -368,10 +368,11 @@ class EMHCrypt01 extends ACrypt { : pubKey.match(/.{1,8}/g)!.join(" "); - if (!IsNullOrEmpty(result.publicKeySignatures)) { + // Public key signatures + if (publicKeyValue.parentElement != null) + publicKeyValue.parentElement.children[3].innerHTML = ""; -// publicKeyValue.parentElement!.children[2].innerHTML = "Bestätigt durch..."; - publicKeyValue.parentElement!.children[3].innerHTML = ""; + if (!IsNullOrEmpty(result.publicKeySignatures)) { for (let signature of result.publicKeySignatures) { diff --git a/src/js/chargepointCrypt01.ts b/src/js/chargepointCrypt01.ts index 5b91094..4ec181c 100644 --- a/src/js/chargepointCrypt01.ts +++ b/src/js/chargepointCrypt01.ts @@ -134,28 +134,27 @@ class ChargepointCrypt01 extends ACrypt { { let sessionResult = SessionVerificationResult.UnknownSessionFormat; - let publicKeyId = chargingSession.EVSEId.replace(/:/g, "").replace(/-/g, "_"); - let publicKey = ""; - if (chargingSession.ctr?.publicKeys != null) + + if (chargingSession.ctr.publicKeys != null) { for (let publicKeyInfo of chargingSession.ctr?.publicKeys) { if (publicKeyInfo.id === publicKeyId) - publicKey = publicKeyInfo.value; + chargingSession.publicKey = publicKeyInfo; } } let plainText = chargingSession.original != null ? atob(chargingSession.original) : ""; let signature = chargingSession.signature; - if (publicKey !== "" && plainText !== "" && signature !== "") + if (chargingSession.publicKey != null && plainText !== "" && signature !== "") { - let sha256value = await sha256(plainText); + chargingSession.hashValue = await sha256(plainText); - if (this.curve.keyFromPublic(publicKey, 'hex'). - verify (sha256value, + if (this.curve.keyFromPublic(chargingSession.publicKey.value, 'hex'). + verify (chargingSession.hashValue, signature)) { @@ -386,117 +385,139 @@ class ChargepointCrypt01 extends ACrypt { publicKeyValue: HTMLDivElement, signatureExpectedValue: HTMLDivElement, signatureCheckValue: HTMLDivElement) + { - const result = measurementValue.result as IChargepointCrypt01Result; + const chargingSession = measurementValue?.measurement?.chargingSession; + const result = measurementValue.result as IChargepointCrypt01Result; - const cryptoSpan = introDiv.querySelector('#cryptoAlgorithm') as HTMLSpanElement; - cryptoSpan.innerHTML = "EMHCrypt01 (" + this.description + ")"; + const cryptoSpan = introDiv.querySelector('#cryptoAlgorithm') as HTMLSpanElement; + cryptoSpan.innerHTML = "chargepointCrypt01 (" + this.description + ")"; - this.CreateLine("Zählernummer", measurementValue.measurement.energyMeterId, result.meterId || "", infoDiv, bufferValue); - this.CreateLine("Zeitstempel", parseUTC(measurementValue.timestamp), result.timestamp || "", infoDiv, bufferValue); - this.CreateLine("Status", hex2bin(measurementValue.infoStatus) + " (" + measurementValue.infoStatus + " hex)
" + - this.DecodeStatus(measurementValue.infoStatus).join("
") + "
", result.infoStatus || "", infoDiv, bufferValue); - this.CreateLine("Sekundenindex", measurementValue.secondsIndex, result.secondsIndex || "", infoDiv, bufferValue); - this.CreateLine("Paginierungszähler", parseInt(measurementValue.paginationId, 16), result.paginationId || "", infoDiv, bufferValue); - this.CreateLine("OBIS-Kennzahl", parseOBIS(measurementValue.measurement.obis), result.obis || "", infoDiv, bufferValue); - this.CreateLine("Einheit (codiert)", measurementValue.measurement.unitEncoded, result.unitEncoded || "", infoDiv, bufferValue); - this.CreateLine("Skalierung", measurementValue.measurement.scale, result.scale || "", infoDiv, bufferValue); - this.CreateLine("Messwert", measurementValue.value + " Wh", result.value || "", infoDiv, bufferValue); - this.CreateLine("Logbuchindex", measurementValue.logBookIndex + " hex", result.logBookIndex || "", infoDiv, bufferValue); - this.CreateLine("Autorisierung", measurementValue.measurement.chargingSession.authorizationStart["@id"] + " hex", pad(result.authorizationStart, 128) || "", infoDiv, bufferValue); - this.CreateLine("Autorisierungszeitpunkt", parseUTC(measurementValue.measurement.chargingSession.authorizationStart.timestamp), pad(result.authorizationStartTimestamp, 151) || "", infoDiv, bufferValue); + // this.CreateLine("Zählernummer", measurementValue.measurement.energyMeterId, result.meterId || "", infoDiv, bufferValue); + // this.CreateLine("Zeitstempel", parseUTC(measurementValue.timestamp), result.timestamp || "", infoDiv, bufferValue); + // this.CreateLine("Status", hex2bin(measurementValue.infoStatus) + " (" + measurementValue.infoStatus + " hex)
" + + // this.DecodeStatus(measurementValue.infoStatus).join("
") + "
", result.infoStatus || "", infoDiv, bufferValue); + // this.CreateLine("Sekundenindex", measurementValue.secondsIndex, result.secondsIndex || "", infoDiv, bufferValue); + // this.CreateLine("Paginierungszähler", parseInt(measurementValue.paginationId, 16), result.paginationId || "", infoDiv, bufferValue); + // this.CreateLine("OBIS-Kennzahl", parseOBIS(measurementValue.measurement.obis), result.obis || "", infoDiv, bufferValue); + // this.CreateLine("Einheit (codiert)", measurementValue.measurement.unitEncoded, result.unitEncoded || "", infoDiv, bufferValue); + // this.CreateLine("Skalierung", measurementValue.measurement.scale, result.scale || "", infoDiv, bufferValue); + // this.CreateLine("Messwert", measurementValue.value + " Wh", result.value || "", infoDiv, bufferValue); + // this.CreateLine("Logbuchindex", measurementValue.logBookIndex + " hex", result.logBookIndex || "", infoDiv, bufferValue); + // this.CreateLine("Autorisierung", measurementValue.measurement.chargingSession.authorizationStart["@id"] + " hex", pad(result.authorizationStart, 128) || "", infoDiv, bufferValue); + // this.CreateLine("Autorisierungszeitpunkt", parseUTC(measurementValue.measurement.chargingSession.authorizationStart.timestamp), pad(result.authorizationStartTimestamp, 151) || "", infoDiv, bufferValue); // Buffer - bufferValue.parentElement!.children[0].innerHTML = "Puffer (320 Bytes, hex)"; + if (bufferValue.parentElement != null) + bufferValue.parentElement.children[0].innerHTML = "Plain text (secrrct)"; + bufferValue.innerText = atob(chargingSession.original ?? ""); + + bufferValue.style.fontFamily = "monospace"; + bufferValue.style.whiteSpace = "pre"; + bufferValue.style.maxHeight = "25vh"; + bufferValue.style.overflowY = "scroll"; // Hashed Buffer - hashedBufferValue.parentElement!.children[0].innerHTML = "Hashed Puffer (SHA256, 24 bytes, hex)"; - hashedBufferValue.innerHTML = result.sha256value.match(/.{1,8}/g).join(" ");; + if (hashedBufferValue.parentElement != null) + hashedBufferValue.parentElement.children[0].innerHTML = "Hashed plain text (SHA256, 32 bytes, hex)"; + hashedBufferValue.innerHTML = chargingSession.hashValue?.match(/.{1,8}/g)?.join(" ") ?? "-"; // Public Key - publicKeyValue.parentElement!.children[0].innerHTML = "Public Key (" + - (result.publicKeyFormat - ? result.publicKeyFormat + ", " - : "") + - "hex)"; + if (chargingSession.publicKey != null) + { - var pubKey = WhenNullOrEmpty(result.publicKey, ""); + if (publicKeyValue.parentElement != null) + publicKeyValue.parentElement.children[0].innerHTML = "Public Key (" + + (chargingSession.publicKey.type.description + ? chargingSession.publicKey.type.description + ", " + : "") + + (chargingSession.publicKey.curve.description + ? chargingSession.publicKey.curve.description + ", " + : "") + + "hex)"; - if (!IsNullOrEmpty(result.publicKey)) - publicKeyValue.innerHTML = pubKey.startsWith("04") // Add some space after '04' to avoid confused customers - ? "04 " - + pubKey.substring(2).match(/.{1,8}/g)!.join(" ") - : pubKey.match(/.{1,8}/g)!.join(" "); + publicKeyValue.innerHTML = chargingSession.publicKey.value.startsWith("04") // Add some space after '04' to avoid confused customers + ? "04 " + + chargingSession.publicKey.value.substring(2).match(/.{1,8}/g)!.join(" ") + : chargingSession.publicKey.value.match(/.{1,8}/g)!.join(" "); - if (!IsNullOrEmpty(result.publicKeySignatures)) { + // Public key signatures + if (publicKeyValue.parentElement != null) + publicKeyValue.parentElement.children[3].innerHTML = ""; -// publicKeyValue.parentElement!.children[2].innerHTML = "Bestätigt durch..."; - publicKeyValue.parentElement!.children[3].innerHTML = ""; + if (!IsNullOrEmpty(result.publicKeySignatures)) { - for (let signature of result.publicKeySignatures) - { + // publicKeyValue.parentElement!.children[2].innerHTML = "Bestätigt durch..."; + - try + for (let signature of result.publicKeySignatures) { - let signatureDiv = publicKeyValue.parentElement!.children[3].appendChild(document.createElement('div')); - signatureDiv.innerHTML = await this.chargy.CheckMeterPublicKeySignature(measurementValue.measurement.chargingSession.chargingStation, - measurementValue.measurement.chargingSession.EVSE, - //@ts-ignore - measurementValue.measurement.chargingSession.EVSE.meters[0], - //@ts-ignore - measurementValue.measurement.chargingSession.EVSE.meters[0].publicKeys[0], - signature); + try + { - } - catch (exception) - { } + let signatureDiv = publicKeyValue.parentElement!.children[3].appendChild(document.createElement('div')); + signatureDiv.innerHTML = await this.chargy.CheckMeterPublicKeySignature(measurementValue.measurement.chargingSession.chargingStation, + measurementValue.measurement.chargingSession.EVSE, + //@ts-ignore + measurementValue.measurement.chargingSession.EVSE.meters[0], + //@ts-ignore + measurementValue.measurement.chargingSession.EVSE.meters[0].publicKeys[0], + signature); + } + catch (exception) + { } + + } + } - - } + } // Signature - signatureExpectedValue.parentElement!.children[0].innerHTML = "Erwartete Signatur (" + (result.signature!.format || "") + ", hex)"; + if (signatureExpectedValue.parentElement != null) + signatureExpectedValue.parentElement.children[0].innerHTML = "Erwartete Signatur (secrrct.sign, rs, hex)";// " + (result.signature?.format ?? "") + ", hex)"; - if (result.signature!.r && result.signature!.s) - signatureExpectedValue.innerHTML = "r: " + result.signature!.r!.toLowerCase().match(/.{1,8}/g)!.join(" ") + "
" + - "s: " + result.signature!.s!.toLowerCase().match(/.{1,8}/g)!.join(" "); + // if (chargingSession.signature?.r && chargingSession.signature.s) + if (chargingSession.signature != null) + signatureExpectedValue.innerHTML = "r: " + chargingSession.signature.substr( 8, 64).toLowerCase().match(/.{1,8}/g)?.join(" ") + "
" + + "s: " + chargingSession.signature.substr(76, 64).toLowerCase().match(/.{1,8}/g)?.join(" "); - else if (result.signature!.value) - signatureExpectedValue.innerHTML = result.signature!.value!.toLowerCase().match(/.{1,8}/g)!.join(" "); + //if (chargingSession.signature != null) + // signatureExpectedValue.innerHTML = chargingSession.signature.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "-"; // Result - switch (result.status) + if (chargingSession.verificationResult != null) + switch (chargingSession.verificationResult.status) { - case VerificationResult.UnknownCTRFormat: - signatureCheckValue.innerHTML = '
Unbekanntes Transparenzdatenformat
'; - break; + // case SessionVerificationResult.UnknownCTRFormat: + // signatureCheckValue.innerHTML = '
Unbekanntes Transparenzdatenformat
'; + // break; - case VerificationResult.EnergyMeterNotFound: - signatureCheckValue.innerHTML = '
Ungültiger Energiezähler
'; - break; + // case SessionVerificationResult.EnergyMeterNotFound: + // signatureCheckValue.innerHTML = '
Ungültiger Energiezähler
'; + // break; - case VerificationResult.PublicKeyNotFound: + case SessionVerificationResult.PublicKeyNotFound: signatureCheckValue.innerHTML = '
Ungültiger Public Key
'; break; - case VerificationResult.InvalidPublicKey: + case SessionVerificationResult.InvalidPublicKey: signatureCheckValue.innerHTML = '
Ungültiger Public Key
'; break; - case VerificationResult.InvalidSignature: + case SessionVerificationResult.InvalidSignature: signatureCheckValue.innerHTML = '
Ungültige Signatur
'; break; - case VerificationResult.ValidSignature: + case SessionVerificationResult.ValidSignature: signatureCheckValue.innerHTML = '
Gültige Signatur
'; break; @@ -507,10 +528,8 @@ class ChargepointCrypt01 extends ACrypt { } - } - //#region Helper methods private DecodeStatus(statusValue: string) : Array diff --git a/src/js/chargyInterfaces.ts b/src/js/chargyInterfaces.ts index 946bd93..4070bed 100644 --- a/src/js/chargyInterfaces.ts +++ b/src/js/chargyInterfaces.ts @@ -113,7 +113,7 @@ interface IPublicKeyInfo interface IOIDInfo { oid: string; - description: string; + description?: string; } interface IKeyInfo @@ -224,7 +224,7 @@ interface IChargingSession { "@id": string; "@context": string; - ctr?: IChargeTransparencyRecord; + ctr: IChargeTransparencyRecord; GUI: HTMLDivElement; begin: string; end?: string; @@ -239,6 +239,7 @@ interface IChargingSession EVSE?: IEVSE|null; meterId: string; meter?: IMeter|null; + publicKey?: IPublicKeyInfo; tariffId?: string; tariff?: ITariff|null; authorizationStart: IAuthorization; @@ -249,6 +250,7 @@ interface IChargingSession method: ACrypt; original?: string; signature?: string; + hashValue?: string; verificationResult?: ISessionCryptoResult; } From 2ff12b307d46a51f1bec3f30d551067907a943c2 Mon Sep 17 00:00:00 2001 From: Achim 'ahzf' Friedland Date: Thu, 28 Nov 2019 07:09:59 +0100 Subject: [PATCH 036/110] Add chargepoint default values --- src/js/chargepoint.ts | 94 +++++++++++++++++++++---------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/src/js/chargepoint.ts b/src/js/chargepoint.ts index 448337a..ea64823 100644 --- a/src/js/chargepoint.ts +++ b/src/js/chargepoint.ts @@ -215,40 +215,40 @@ class Chargepoint { }, "contact": { - "email": "info@chargeit-mobility.com", - "web": "https://www.chargeit-mobility.com", - "logoUrl": "http://www.chargeit-mobility.com/fileadmin/BELECTRIC_Drive/templates/pics/chargeit_logo_408x70.png", - "publicKeys": [ - { - "algorithm": "secp192r1", - "format": "DER", - "value": "042313b9e469612b4ca06981bfdecb226e234632b01d84b6a814f63a114b7762c34ddce2e6853395b7a0f87275f63ffe3c", - "signatures": [ - { - "keyId": "...", - "algorithm": "secp192r1", - "format": "DER", - "value": "????" - } - ] - }, - { - "algorithm": "secp256k1", - "format": "DER", - "value": "04a8ff0d82107922522e004a167cc658f0eef408c5020f98e7a2615be326e61852666877335f4f8d9a0a756c26f0c9fb3f401431416abb5317cc0f5d714d3026fe", - "signatures": [ ] - } - ] + "email": "sales@chargepoint.com", + "web": "https://www.chargepoint.com", + "logoUrl": "https://www.chargepoint.com/themes/chargepoint/logo.svg", + // "publicKeys": [ + // { + // "algorithm": "secp256r1", + // "format": "DER", + // "value": "042313b9e469612b4ca06981bfdecb226e234632b01d84b6a814f63a114b7762c34ddce2e6853395b7a0f87275f63ffe3c", + // "signatures": [ + // { + // "keyId": "...", + // "algorithm": "secp256r1", + // "format": "DER", + // "value": "????" + // } + // ] + // }, + // { + // "algorithm": "secp256r1", + // "format": "DER", + // "value": "04a8ff0d82107922522e004a167cc658f0eef408c5020f98e7a2615be326e61852666877335f4f8d9a0a756c26f0c9fb3f401431416abb5317cc0f5d714d3026fe", + // "signatures": [ ] + // } + // ] }, "support": { - "hotline": "+49 9321 / 2680 - 700", - "email": "service@chargeit-mobility.com", - "web": "https://cso.chargeit.charging.cloud/issues" + "hotline": "+49(69) 95307383", + "email": "support.eu@chargepoint.com", + "web": "https://chargepoint.charging.cloud/issues" // "mediationServices": [ "GraphDefined Mediation" ], // "publicKeys": [ // { - // "algorithm": "secp256k1", + // "algorithm": "secp256r1", // "format": "DER", // "value": "04a8ff0d82107922522e004a167cc658f0eef408c5020f98e7a2615be326e61852666877335f4f8d9a0a756c26f0c9fb3f401431416abb5317cc0f5d714d3026fe", // "signatures": [ ] @@ -257,12 +257,12 @@ class Chargepoint { }, "privacy": { - "contact": "Dr. iur. Christian Borchers, datenschutz süd GmbH", - "email": "datenschutz@chargeit-mobility.com", - "web": "http://www.chargeit-mobility.com/de/datenschutz/" + "contact": "ChargePoint, Attn: Data Protection Officer, ChargePoint Network (Netherlands) B.V., Hoogoorddreef 56E, 1101BE Amsterdam", + "email": "privacy.eu@chargepoint.com ", + "web": "https://de.chargepoint.com/privacy_policy" // "publicKeys": [ // { - // "algorithm": "secp256k1", + // "algorithm": "secp256r1", // "format": "DER", // "value": "04a8ff0d82107922522e004a167cc658f0eef408c5020f98e7a2615be326e61852666877335f4f8d9a0a756c26f0c9fb3f401431416abb5317cc0f5d714d3026fe", // "signatures": [ ] @@ -283,20 +283,20 @@ class Chargepoint { "meters": [ { "@id": SomeJSON.additional_info.meter_serial, - "vendor": null, - "vendorURL": null, - "model": null, - "hardwareVersion": null, - "firmwareVersion": null, - "signatureFormat": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/EMHCrypt01", - "publicKeys": [ - { - "algorithm": "secp192r1", - "format": "DER", - "value": null, - "signatures": null - } - ] + "vendor": "Carlo Gavazzi", + //"vendorURL": null, + "model": "EM340-DIN.AV2.3.X.S1.X", + //"hardwareVersion": null, + //"firmwareVersion": null, + // "signatureFormat": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/EMHCrypt01", + // "publicKeys": [ + // { + // "algorithm": "secp224k1", + // "format": "DER", + // "value": null, + // "signatures": null + // } + // ] } ] } @@ -365,7 +365,7 @@ class Chargepoint { "energyMeterId": SomeJSON.additional_info.meter_serial, "@context": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/ChargepointCrypt01+json", "name": SomeJSON.energy != null && SomeJSON.energy.length > 0 ? SomeJSON.energy[0].type : "ENERGY", - "obis": "123...", + "obis": "1-0:1.17.0*255", "unit": SomeJSON.additional_info.energy_units, // "unitEncoded": CTRArray[0]["measuredValue"]["unitEncoded"], // "valueType": CTRArray[0]["measuredValue"]["valueType"], From 830433a3cefe027107a7b3c461893b16071b3e1e Mon Sep 17 00:00:00 2001 From: Achim 'ahzf' Friedland Date: Fri, 29 Nov 2019 07:04:21 +0100 Subject: [PATCH 037/110] Remove decompress-tarxz because of build errors --- package-lock.json | 397 +++++----------------------------------------- package.json | 1 - 2 files changed, 41 insertions(+), 357 deletions(-) diff --git a/package-lock.json b/package-lock.json index c72a887..c4ad0ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -82,11 +82,6 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.8.tgz", "integrity": "sha512-XLla8N+iyfjvsa0KKV+BP/iGSoTmwxsu5Ci5sM33z9TjohF72DEz95iNvD6pPmemvbQgxAv/909G73gUn8QR7w==" }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" - }, "ajv": { "version": "6.10.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", @@ -151,7 +146,8 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true }, "ansi-styles": { "version": "3.2.1", @@ -244,49 +240,6 @@ } } }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" - }, - "are-we-there-yet": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", - "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -354,7 +307,8 @@ "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true }, "base32-decode": { "version": "1.0.0", @@ -499,6 +453,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -734,11 +689,6 @@ "readdirp": "~3.2.0" } }, - "chownr": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz", - "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==" - }, "chromium-pickle-js": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz", @@ -814,7 +764,8 @@ "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true }, "color-convert": { "version": "0.5.3", @@ -853,7 +804,8 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true }, "concat-stream": { "version": "1.6.2", @@ -913,11 +865,6 @@ "xdg-basedir": "^3.0.0" } }, - "console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" - }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -962,6 +909,7 @@ "version": "3.2.6", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, "requires": { "ms": "^2.1.1" } @@ -1080,24 +1028,6 @@ } } }, - "decompress-tarxz": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/decompress-tarxz/-/decompress-tarxz-3.0.0.tgz", - "integrity": "sha512-/85049bKZOmkVXrFz9Zf90DMBPYuXGGAMOQaytNgMGiB7u4iIJKLUaEXRiLBvugtknmYcP1Zv6KQWEYWshTblg==", - "requires": { - "decompress-tar": "^4.1.0", - "file-type": "^12.3.0", - "is-stream": "^2.0.0", - "lzma-native": "^4.0.5" - }, - "dependencies": { - "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" - } - } - }, "decompress-unzip": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", @@ -1145,7 +1075,8 @@ "deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true }, "defer-to-connect": { "version": "1.0.2", @@ -1159,16 +1090,6 @@ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", "dev": true }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" - }, - "detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" - }, "dmg-builder": { "version": "6.7.2", "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-6.7.2.tgz", @@ -1563,19 +1484,6 @@ } } }, - "fs-minipass": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", - "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", - "requires": { - "minipass": "^2.6.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, "fsevents": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", @@ -1583,21 +1491,6 @@ "dev": true, "optional": true }, - "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -1625,19 +1518,6 @@ "assert-plus": "^1.0.0" } }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, "glob-parent": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", @@ -1718,11 +1598,6 @@ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" - }, "has-yarn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", @@ -1775,6 +1650,7 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" } @@ -1784,14 +1660,6 @@ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" }, - "ignore-walk": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", - "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", - "requires": { - "minimatch": "^3.0.4" - } - }, "import-lazy": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", @@ -1813,15 +1681,6 @@ "repeating": "^2.0.0" } }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", @@ -1830,7 +1689,8 @@ "ini": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true }, "invert-kv": { "version": "2.0.0", @@ -1881,6 +1741,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, "requires": { "number-is-nan": "^1.0.0" } @@ -2156,46 +2017,6 @@ "yallist": "^2.1.2" } }, - "lzma-native": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/lzma-native/-/lzma-native-4.0.5.tgz", - "integrity": "sha512-pmLMsHQlXQAikqGqapzUOtACPW/gEtt9xhkcrkJnsjWn+I1g7OIbrV2SugL8jinkBCD+QxqAze51VtRsECDcxQ==", - "requires": { - "nan": "^2.14.0", - "node-pre-gyp": "^0.11.0", - "readable-stream": "^2.3.5", - "rimraf": "^2.6.1" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, "make-dir": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", @@ -2302,6 +2123,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -2309,36 +2131,14 @@ "minimist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" - }, - "minipass": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", - "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - }, - "dependencies": { - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - } - } - }, - "minizlib": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", - "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", - "requires": { - "minipass": "^2.9.0" - } + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true }, "mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, "requires": { "minimist": "0.0.8" }, @@ -2346,7 +2146,8 @@ "minimist": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true } } }, @@ -2358,22 +2159,8 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" - }, - "needle": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.4.0.tgz", - "integrity": "sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==", - "requires": { - "debug": "^3.2.6", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true }, "nice-try": { "version": "1.0.5", @@ -2381,32 +2168,6 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, - "node-pre-gyp": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz", - "integrity": "sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q==", - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - } - }, - "nopt": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", - "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -2431,20 +2192,6 @@ "integrity": "sha512-0NLtR71o4k6GLP+mr6Ty34c5GA6CMoEsncKJxvQd8NzPxaHRJNnb5gZE8R1XF4CPIS7QPHLJ74IFszwtNVAHVQ==", "dev": true }, - "npm-bundled": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz", - "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==" - }, - "npm-packlist": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.6.tgz", - "integrity": "sha512-u65uQdb+qwtGvEJh/DgQgW1Xg7sqeNbmxYyrvlNznaVTjV3E5P6F/EFjM+BVHXl7JJlsdG8A64M0XI8FI/IOlg==", - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -2454,17 +2201,6 @@ "path-key": "^2.0.0" } }, - "npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, "nugget": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/nugget/-/nugget-2.0.1.tgz", @@ -2500,7 +2236,8 @@ "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true }, "oauth-sign": { "version": "0.9.0", @@ -2527,11 +2264,6 @@ "wrappy": "1" } }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" - }, "os-locale": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", @@ -2582,20 +2314,6 @@ } } }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" - }, - "osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, "p-cancelable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", @@ -2688,11 +2406,6 @@ "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", "dev": true }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, "path-is-inside": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", @@ -2837,6 +2550,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, "requires": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -3022,14 +2736,6 @@ "lowercase-keys": "^1.0.0" } }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "requires": { - "glob": "^7.1.3" - } - }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -3038,7 +2744,8 @@ "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true }, "sanitize-filename": { "version": "1.6.1", @@ -3061,7 +2768,8 @@ "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true }, "seek-bzip": { "version": "1.0.5", @@ -3074,7 +2782,8 @@ "semver": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true }, "semver-diff": { "version": "2.1.0", @@ -3088,7 +2797,8 @@ "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true }, "shebang-command": { "version": "1.2.0", @@ -3108,7 +2818,8 @@ "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true }, "single-line-log": { "version": "1.1.2", @@ -3206,6 +2917,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -3222,6 +2934,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, "requires": { "ansi-regex": "^2.0.0" } @@ -3261,7 +2974,8 @@ "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true }, "sumchecker": { "version": "2.0.2", @@ -3298,27 +3012,6 @@ "has-flag": "^3.0.0" } }, - "tar": { - "version": "4.4.13", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", - "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.8.6", - "minizlib": "^1.2.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.3" - }, - "dependencies": { - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - } - } - }, "tar-stream": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", @@ -3609,14 +3302,6 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "requires": { - "string-width": "^1.0.2 || 2" - } - }, "widest-line": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", diff --git a/package.json b/package.json index cfc6b19..2d7c55c 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,6 @@ "decompress": "^4.2.0", "decompress-bzip2": "^4.0.0", "decompress-gz": "0.0.1", - "decompress-tarxz": "^3.0.0", "elliptic": "^6.5.1", "file-type": "^12.4.0", "key-encoder": "^2.0.3", From e7ecb5f6a6af11f5163fe245a228108d7f472877 Mon Sep 17 00:00:00 2001 From: Achim 'ahzf' Friedland Date: Sun, 1 Dec 2019 01:24:47 +0100 Subject: [PATCH 038/110] Implement secp224k1 via BigInt (elliptic did not work). Allow secp224k1 and secp256r1 of chargepoint charge transparency records --- .../chargepoint/2/0024b1000002e300_2.pem | 4 + .../0024b1000002e300_2_119693895_payload.tar | Bin 0 -> 4608 bytes ...24b1000002e300_2_119693895_payload.tar.bz2 | Bin 0 -> 995 bytes documentation/chargepoint/2/secrrct | 92 +++++++ documentation/chargepoint/2/secrrct.sign | Bin 0 -> 62 bytes .../Testdata/0024b1000002e300_2.zip | Bin 0 -> 1447 bytes src/index.html | 1 + src/js/chargepointCrypt01.ts | 94 +++---- src/js/chargy.ts | 20 +- src/js/chargyLib.ts | 49 ++++ src/js/secp224k1.ts | 255 ++++++++++++++++++ 11 files changed, 459 insertions(+), 56 deletions(-) create mode 100644 documentation/chargepoint/2/0024b1000002e300_2.pem create mode 100644 documentation/chargepoint/2/0024b1000002e300_2_119693895_payload.tar create mode 100644 documentation/chargepoint/2/0024b1000002e300_2_119693895_payload.tar.bz2 create mode 100644 documentation/chargepoint/2/secrrct create mode 100644 documentation/chargepoint/2/secrrct.sign create mode 100644 documentation/chargepoint/Testdata/0024b1000002e300_2.zip create mode 100644 src/js/secp224k1.ts diff --git a/documentation/chargepoint/2/0024b1000002e300_2.pem b/documentation/chargepoint/2/0024b1000002e300_2.pem new file mode 100644 index 0000000..05532bf --- /dev/null +++ b/documentation/chargepoint/2/0024b1000002e300_2.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +ME4wEAYHKoZIzj0CAQYFK4EEACADOgAE1MF2EIuqaDElJHyK9R64SFjJ5Q2HU6dF +4/0pmqBEgmycnUnOOQTNm9xos7Cfs56+qsC57Aq5rXY= +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/documentation/chargepoint/2/0024b1000002e300_2_119693895_payload.tar b/documentation/chargepoint/2/0024b1000002e300_2_119693895_payload.tar new file mode 100644 index 0000000000000000000000000000000000000000..594ba3a7b2c1e14a8abb64936fe874bdd5d04a8f GIT binary patch literal 4608 zcmeHIKW`jG6u+cFxJpHu6sti3LC|UTcJKCXLyEIwqCjkn&lVtrM&sSN^CY*km)Y6F zC$K1JBBkI9K$n`9AW@`&iiVPpK*ML?z1>;gAD`{UmJ;cv*`4?1y?O69zxQ4yBCR7+ z&*VVWu4qwME#I%<7uMpJ(x6pyJ)gP_x8=G)4S#5(=FlsOXU=V&8Ll0trqk5SDHb*t z=@*W_E?fHH^;>WJQ2X)b`~6?PfA_n;H||c-@r@TRU()sej{my(^!ly0Hg5m%{P*{o zzr6VE-#_ojf7(CazINl;PwQ{$cI$P?auw%U2xMjbpQXMOITrmn_3!zCSJi*h4VqB@ zuG?JI|D|Amk&|!N91^9;h^q-xJP{;x$i^Yp1F@4zW!`z)Yuwq~FFv1j?QWNR09LWg zMngVfxsnE~ycVS>7E0*B1O#8LISzPt9Ks_b$AU%ZR;mH$@FXbWTyrB+1ropEmNKDY zW@HhF+w{G*?{*rUc@@h|1SW;rYkQS?D3xH+h=fIHh9TKoGVz3|JVA@n4|aUBa7mN4 z7nO6@1fA-DnT!gQHn%r-?|+F_?#!(KjE~Vn3Dj~t z5Korn2PQRqxGXKw+h5=Nbg%o+UU+7N=S8vRd<}t+{*WVd)5k*r>kG`w;#oJXLZHZJ{{HPm0n!7S9?b%SMfjOLBT*<)-g>@QWXPH@n zeL`yw=NOM4!GuqQDhL5DFo%DqQ@y%1Il;J27eeoC_IhmV!8YsO`*=2m5!a7PQcp2k z{*IT&>yzNpvCzO~EVrvA`%ZWFlLy=PXBa)pc6X8LP|X)J+afndqm#_0MSB*zPltqr zvo~9Q%~s8Fx{&G!I}rU;i&KO_8W6*e!1wfl%RMl#A_+g*5jrYaM%+#vNm*4RKibWQ zV%s*?t#5j!Ua4#=+3S8$P-@x<&PgA;06P`Hf+w4QLFaCg<`w4a|TCkSVq!lICV8ux#*FGv6Y literal 0 HcmV?d00001 diff --git a/documentation/chargepoint/2/0024b1000002e300_2_119693895_payload.tar.bz2 b/documentation/chargepoint/2/0024b1000002e300_2_119693895_payload.tar.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..37c8142663716e5af40a15e91f66ca039f116978 GIT binary patch literal 995 zcmV<9104K9T4*^jL0KkKS<)uY6j~$uDGbAh$gj3Kdl07v&N0c6?rjXH)4TN*Lq3Q>y0Q7@E000^Q8fXAL$Ej?X z#x1gLzyP#D*)V0?xhx36!8;&Ze?Ep5e*4wAX`!(;4W!ygZ0L+_mv+YO#6@Hj`54*&s( zK*TiWoE}KJMmKE&;xQagP6}vy4_b8 zd-mq1P!K};Qt|6=VAT70>~&6vtirIWsn*qSqsBvsh#Co|g9(i|my{(;S7L!EFAya| zgqsyCP6V=Kge@%{9q+RcuU2q5*DV=Vg;7B?@l{d&w>JhRB?{ftBdF#$CLwf&gT%B9!Oxv?1XRhRf$*ykx#jLz z7C%9+9>9vULz8ITJ|b{}Sj8MALM!}GKqR9k^px!6U&G^yHNzUsRyI-rRF19NA zDo|=|IaSAeoTGKbX+3KaPEeeR=<>U=YY`I^vm$z>Ti=|x`g_R{u98TKItQSOKtjx1 zI@X(3q13)Xp#or+%@QP0KVq5;Lm5>Bg5hMWnAsThY^7nk^yWK?2u0OcKxj2KO>1o& zN&USr~(e7)-dxKG4Le zUDygu2~kcY(auyh5{h#1P@+h~@q|{hq86=uoWgZyJ1#(FD#{IXjbi~wR5qKQ;-rW~ z_ILBBGX!iF3^pphOp9*%qN6klN>uIV)t4v==+UT^VwjFIn2bbP0aFo;DnfL$mb&H; z1fV^n!r(J-WmmO>K*w!@p<(b~Tnj?F^BV+sTsfpRr^vW$9)y!rrpNoIdKgs zF5d{qz-#iYC`HLke1 U>Bc*0**Kjm0T7FvLJ4v>HrP@aHUIzs literal 0 HcmV?d00001 diff --git a/documentation/chargepoint/Testdata/0024b1000002e300_2.zip b/documentation/chargepoint/Testdata/0024b1000002e300_2.zip new file mode 100644 index 0000000000000000000000000000000000000000..e50854a347339ac1f0665ae6ab3f8ca77bfc1640 GIT binary patch literal 1447 zcmWIWW@Zs#U|`^2h}|LV-*vHJ+aw@w2@s0`v4Me+Ns^%f2pFXr8yLhJ=@q2rUcSo8 zq#j=GZ{OMwpf2y9&YFMSW5NtQ{psshd+uDFyrjLnZc2LSw8qWJ2}@>g?_9ll@#e+d z^}80YUbuet#MSAUiHo|k`=+}u-JUvOrssy}Y11p+VW8T8a*;RR| zMR6JP_SYwL#IH+rt=qV>IBMg{nPrI^H?Q28yf8D+Wr?o7_>HJ=d-0O#3=9EKUobF4 z0DUn{NZ9EyGXnz%>tOXoyrH3`nWeFXrD=RYVr5Q#Vv1f#Vv$}_m620ahNYonq*`#~ zCADwU7?}I(|Nq+IcqDRf{XhHt|6cw7|NmWwM*|xRBg2!!EDIDE6d5=InEPdC9y37TAWa|%hFkxKG+4(crL2lvl$pKypGnOxFnb)~Oiunoy zg9!t(!^H(aC-O9LI`}YUE@NQINJ?N3_BFZXYh)y4lAxy6)1&6xz>vX^!R)}m*5kl% z0jQec0;5vEMMhg+wJR52eXTl0}EJO|IuEn*2dxw!GeYJr_k z-$jbqJFb^I(6z;Ra>iXdrGlo2qcW;a+J6EZR2Hj!nU-_;b=QoPvp+7L^*r}le0Tin zm3rH>erW|{}W$&6`?e5tcX*?^4-)XVgC#|DSJsg?wYj&@W zlxXgd@Y!*~?!u9ku{XGUIRpJvE}jc96Y47Z7_i9W@W+<0&5Oj=*33Cnnr^M)7ZFV@G+q5w8LqZI<)2`3bEEO@9OU#y^ z*pVaGGC5?~@!!j z`0(%B|CzIYmFqo!*e#}ME_3_GKR*l0ia-3$|MZ@86)aR-;`>%7z?+dtgaLP<2g+cK r3<@9$2(TA{2s5x3IS{=HK + diff --git a/src/js/chargepointCrypt01.ts b/src/js/chargepointCrypt01.ts index 4ec181c..093bb35 100644 --- a/src/js/chargepointCrypt01.ts +++ b/src/js/chargepointCrypt01.ts @@ -18,7 +18,7 @@ /// /// /// - +/// interface IChargepointMeasurementValue extends IMeasurementValue { @@ -54,62 +54,27 @@ interface IChargepointCrypt01Result extends ICryptoResult class ChargepointCrypt01 extends ACrypt { - readonly curve = new this.chargy.elliptic.ec('p256'); - - // $ openssl ec -inform PEM -pubin -in 0024b10000027b29_1.pem -text -noout - // Public-Key: (225 bit) - // pub: - // 04:f6:b9:4d:1d:0d:4c:95:24:41:b9:44:34:ac:41: - // 3b:0c:3d:97:ee:e7:f1:19:36:9c:ac:3a:07:a2:e8: - // 12:98:f4:2f:f6:eb:f1:2d:de:16:e1:b5:7d:a1:12: - // 13:45:70:21:1d:c7:a9:f3:48:9a:e1:a4 - // ASN1 OID: secp224k1 - // read EC key - // - // Koblitz 224-bit curve - // https://www.secg.org/sec2-v2.pdf - // this.chargy.elliptic.defineCurve('secp224k1', { - // type: 'short', - // prime: 'k224', - // p: 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFE56D', - // a: '00000000 00000000 00000000 00000000 00000000 00000000 00000000', - // b: '00000000 00000000 00000000 00000000 00000000 00000000 00000005', - // n: '00000000 00000000 00000000 0001DCE8 D2EC6184 CAF0A971 769FB1F7', - // h: 1, - // hash: this.chargy.elliptic.hash.sha512, - // gRed: false, - // g: [ - // 'A1455B33 4DF099DF 30FC28A1 69A467E9 E47075A9 0F7E650E B6B7A45C', - // '7E089FED 7FBA3442 82CAFBD6 F7E319F7 C0B0BD59 E2CA4BDB 556D61A5' - // ] - // }); + // Koblitz 224-bit curve + // https://www.secg.org/sec2-v2.pdf + // For older chargepoint charging station firmwares + readonly curve224k1 = new secp224k1(); + + // NIST/ANSI X9.62 named 256-bit elliptic curve + // https://www.secg.org/sec2-v2.pdf + // For newer chargepoint charging station firmwares + readonly curve256r1 = new this.chargy.elliptic.ec('p256'); constructor(chargy: Chargy) { - super("ECC secp256r1", + super("ECC secp224k1/secp256r1", chargy); - // defineCurve('p224', { - // type: 'short', - // prime: 'p224', - // p: 'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001', - // a: 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff fffffffe', - // b: 'b4050a85 0c04b3ab f5413256 5044b0b7 d7bfd8ba 270b3943 2355ffb4', - // n: 'ffffffff ffffffff ffffffff ffff16a2 e0b8f03e 13dd2945 5c5c2a3d', - // hash: hash.sha256, - // gRed: false, - // g: [ - // 'b70e0cbd 6bb4bf7f 321390b9 4a03c1d3 56c21122 343280d6 115c1d21', - // 'bd376388 b5f723fb 4c22dfe6 cd4375a0 5a074764 44d58199 85007e34' - // ] - //}); - } GenerateKeyPair()//options?: elliptic.ec.GenKeyPairOptions) { - return this.curve.genKeyPair(); + return this.curve256r1.genKeyPair(); // privateKey = keypair.getPrivate(); // publicKey = keypair.getPublic(); // privateKeyHEX = privateKey.toString('hex').toLowerCase(); @@ -145,17 +110,36 @@ class ChargepointCrypt01 extends ACrypt { } } - let plainText = chargingSession.original != null ? atob(chargingSession.original) : ""; - let signature = chargingSession.signature; + let plainText = chargingSession.original != null ? atob(chargingSession.original) : ""; - if (chargingSession.publicKey != null && plainText !== "" && signature !== "") + if (chargingSession.publicKey != null && plainText !== "" && chargingSession.signature != null && chargingSession.signature !== "") { - chargingSession.hashValue = await sha256(plainText); + let validated = false; + + switch (chargingSession.publicKey.curve.description) + { + + case "secp224k1": + let SHA256HashValue = await sha256(plainText); + chargingSession.hashValue = (BigInt("0x" + SHA256HashValue) >> BigInt(31)).toString(16); + validated = this.curve224k1.validate(BigInt("0x" + chargingSession.hashValue), + BigInt("0x" + chargingSession.signature.substr(8, 56)), + BigInt("0x" + chargingSession.signature.substr(68, 56)), + [ BigInt("0x" + chargingSession.publicKey.value.substr(2, 56)), + BigInt("0x" + chargingSession.publicKey.value.substr(58, 56)) ]); + break; + + case "secp256r1": + chargingSession.hashValue = await sha256(plainText); + validated = this.curve256r1.keyFromPublic(chargingSession.publicKey.value, 'hex'). + verify (chargingSession.hashValue, + chargingSession.signature) + break; + + } - if (this.curve.keyFromPublic(chargingSession.publicKey.value, 'hex'). - verify (chargingSession.hashValue, - signature)) + if (validated) { sessionResult = SessionVerificationResult.ValidSignature; @@ -316,7 +300,7 @@ class ChargepointCrypt01 extends ACrypt { // cryptoResult.publicKey = publicKey.encode('hex'). // toLowerCase(); - const signature = this.curve.keyFromPrivate(privateKey.toString('hex')). + const signature = this.curve256r1.keyFromPrivate(privateKey.toString('hex')). sign(cryptoResult.sha256value); switch (measurementValue.measurement.signatureInfos.format) diff --git a/src/js/chargy.ts b/src/js/chargy.ts index effa647..89fe176 100644 --- a/src/js/chargy.ts +++ b/src/js/chargy.ts @@ -524,9 +524,27 @@ class Chargy { let Curve = "unknown"; switch (Curve_OID) { + + // Koblitz 224-bit curve + case "1.3.132.0.32": + Curve = "secp224k1"; + break; + + // NIST/ANSI X9.62 named 256-bit elliptic curve used with SHA256 case "1.2.840.10045.3.1.7": - Curve = "prime256v1"; // ANSI X9.62 named elliptic curve + Curve = "secp256r1"; // also: ANSI prime256v1, NIST P-256 + break; + + // NIST/ANSI X9.62 named 384-bit elliptic curve used with SHA384 + case "1.3.132.0.34": + Curve = "secp384r1"; // also: ANSI prime384v1, NIST P-384 + break; + + // NIST/ANSI X9.62 named 521-bit elliptic curve used with SHA512 + case "1.3.132.0.35": + Curve = "secp521r1"; // also: ANSI prime521v1, NIST P-521 break; + } processedFile.result = { diff --git a/src/js/chargyLib.ts b/src/js/chargyLib.ts index 3183d84..0d94574 100644 --- a/src/js/chargyLib.ts +++ b/src/js/chargyLib.ts @@ -451,6 +451,23 @@ function pad(text: string|undefined, paddingValue: number) { }; +async function sha224(message: string|DataView) { + + let hashBuffer = null; + const SHA224 = require("sha224"); + + if (typeof message === 'string') + hashBuffer = SHA224(Buffer.from(message, 'utf8')); + else + hashBuffer = SHA224(message); + + // const hashArray = Array.from(hashBuffer); // convert hash to byte array + const hashHex = hashBuffer.toString("hex"); + + return hashHex; + +} + async function sha256(message: string|DataView) { let hashBuffer = null; @@ -466,3 +483,35 @@ async function sha256(message: string|DataView) { return hashHex; } + +async function sha384(message: string|DataView) { + + let hashBuffer = null; + + if (typeof message === 'string') + hashBuffer = await crypto.subtle.digest('SHA-384', Buffer.from(message, 'utf8')); + else + hashBuffer = await crypto.subtle.digest('SHA-384', message); + + const hashArray = Array.from(new Uint8Array(hashBuffer)); // convert hash to byte array + const hashHex = hashArray.map(b => ('00' + b.toString(16)).slice(-2)).join('').toLowerCase(); // convert bytes to hex string + + return hashHex; + +} + +async function sha512(message: string|DataView) { + + let hashBuffer = null; + + if (typeof message === 'string') + hashBuffer = await crypto.subtle.digest('SHA-512', Buffer.from(message, 'utf8')); + else + hashBuffer = await crypto.subtle.digest('SHA-512', message); + + const hashArray = Array.from(new Uint8Array(hashBuffer)); // convert hash to byte array + const hashHex = hashArray.map(b => ('00' + b.toString(16)).slice(-2)).join('').toLowerCase(); // convert bytes to hex string + + return hashHex; + +} \ No newline at end of file diff --git a/src/js/secp224k1.ts b/src/js/secp224k1.ts new file mode 100644 index 0000000..3371c18 --- /dev/null +++ b/src/js/secp224k1.ts @@ -0,0 +1,255 @@ +/** This implementation is for educaitonal purposes only + * and should not be used in production for obvious reasons. + * If you would like to contribute, you are more than welcome to. + * + * const GcompressedLE = BigInt("A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C", 16); + * const GunCompressedLE = BigInt("A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5", 16); + * + * Actual curve: y^2 = x^3 + Acurve * x + Bcurve + * + **/ + +class secp224k1 { + + // Pcurve = 2**224 - 2**32 - 2**12 - 2**11 - 2**9 - 2**7 - 2**4 - 2**1 - 1 OR FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFE56D + private Zero = BigInt("0"); + private One = BigInt("1"); + private Two = BigInt("2"); + private Three = BigInt("3"); + private Pcurve = BigInt("26959946667150639794667015087019630673637144422540572481099315275117"); // The proven prime + private N = BigInt("0x010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7"); // Number of points in the field + private Acurve = BigInt(0); // These two are defined on the elliptic curve. y^2 = x^3 + Acurve * x + Bcurve + private Bcurve = BigInt(5); // These two are defined on the elliptic curve. y^2 = x^3 + Acurve * x + Bcurve + private Gx = BigInt("0xA1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C"); + private Gy = BigInt("0x7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5"); + private GPoint = [this.Gx, this.Gy]; // This is our generator point. Trillions of dif ones possible + + // Individual Transaction/Personal Information + public privKey = BigInt("0x0065A09645613C7793A6129544F0CE700CC4ED5E0D7369DD0DB50A0230"); + // publicKey: 04 + 0e63cfc97d998270f9f09a4f78f0e6d33bc6c7258a302e9cb5cb8b5b + // 2423b0caf3044e657c5af7e11a6967ce7c752023273bc79e1ab95768 + // 1dce8d2ec6184caf0a971769fb1f7 + //public privKey = BigInt("0x00000000000000000000000000015B9526505DAAAED38515AAAED385"); // replace with any private key + public RandNum = BigInt("00000000000000000000000000019373285210420739438520739434"); // replace with a truly random number + // public HashOfThingToSign = BigInt("86032112319101611046176971828093669637772856272766963803"); // the hash of your message/transaction + + + + constructor() { + + // console.log(); + // console.log("******* Public Key Generation *********"); + // console.log(); + // let PublicKey = this.ECmultiply(this.GPoint, this.privKey); + // let Px = this.zfill(PublicKey[0].toString(16)); + // let Py = this.zfill(PublicKey[1].toString(16)); + // console.log("the private key:") + // console.log( this.privKey.toString() + " (HEXADECIMAL)" ); + // console.log(); + // console.log("the uncompressed public key (NOT ADDRESS):"); + // console.log(PublicKey[0].toString(16) + PublicKey[1].toString(16)); + // console.log(); + // console.log("the uncompressed public key (HEX):"); + // console.log("04" + Px + Py); + // console.log(); + // console.log("the official Public Key (Address) - compressed:"); + + // if (this.modulo(PublicKey[1], this.Two) == this.One) { + // console.log("03" + Px); + // } else { + // console.log("02" + Px); + // } + + // console.log(); + // console.log("******* Signature Generation *********"); + // let RandSignPoint = this.ECmultiply(this.GPoint, this.RandNum); + // let Sx = this.zfill(RandSignPoint[0].toString(16)); + // let Sy = this.zfill(RandSignPoint[1].toString(16)); + + // let signatureR = this.modulo(RandSignPoint[0], this.N); + // console.log("R", signatureR.toString()); + + // let signatureS = this.modulo((this.HashOfThingToSign + signatureR^this.privKey)^(this.modInv(this.RandNum, this.N)), this.N); + // console.log("S", signatureS.toString()); + // // s = ((HashOfThingToSign + r*privKey)*(modinv(RandNum,N))) % N; print "s =", s + + // console.log(); + // console.log("******* Signature Verification *********"); + + // let w = this.modInv(signatureS, this.N); + // console.log("w", w.toString()); + + // let u1 = this.ECmultiply(this.GPoint, this.modulo(this.HashOfThingToSign^w, this.N)); + // // let u1x = u1[0]; + // // let u1y = u1[1]; + + // let u2 = this.ECmultiply(PublicKey, this.modulo(signatureR^w, this.N)); + // // let u2x = u2[0]; + // // let u2y = u2[1]; + + // let validation = this.ECadd(u1, u2); + // let validationX = validation[0]; + + // console.log("Signature Verified", validationX==signatureR); + + // //module.exports = { PublicKeyGenerate }; + + } + + public Sign(hash: bigint, + privateKey: bigint) + { + + let RandSignPoint = this.ECmultiply(this.GPoint, this.RandNum); + let r = this.modulo(RandSignPoint[0], this.N); + let s = this.modulo((hash + r*privateKey) * (this.modInv(this.RandNum, this.N)), this.N); + + return [ r, s ]; + + } + + public validate(hash: bigint, + signatureR: bigint, + signatureS: bigint, + PublicKey: Array) : boolean + { + + if (signatureR==this.Zero || signatureR>=this.N) + throw "Invalid R"; + + if (signatureS==this.Zero || signatureS>=this.N) + throw "Invalid S"; + + let w = this.modInv(signatureS, this.N); + let u1 = this.ECmultiply(this.GPoint, this.modulo(w * hash, this.N)); + let u2 = this.ECmultiply(PublicKey, this.modulo(w * signatureR, this.N)); + let validation = this.ECadd(u1, u2); + + return validation[0] == signatureR; + + } + + + public modulo(n: bigint, m: bigint) { + return (((n % m) + m) % m); + } + + public zfill(s: string): string { + + while (s.length < 56) { + s = "0" + s; + } + + return s; + + } + + public modInv(a: bigint, n: bigint = this.Pcurve) { + + let lm = BigInt(1), + hm = BigInt(0), + high = n, + low = this.modulo(a, n); + + while (low > 1) { + + let ratio = high / low, + nm = hm - (ratio*lm), + newm = high - (ratio*low); + + hm = lm; + lm = nm; + high = low; + low = newm; + + } + + return this.modulo(lm, n); + + } + + public ECadd(a: Array, b: Array) { + + let LamAdd = this.modulo((b[1]-a[1])*( this.modInv( b[0]-a[0] ) ), this.Pcurve); + let x = this.modulo((LamAdd*LamAdd)-a[0]-b[0], this.Pcurve); + let y = this.modulo((LamAdd*( a[0]-x )-a[1]), this.Pcurve); + + // const LamAdd = modulo(b[1].minus(a[1]).times( modInv( b[0].minus(a[0]) ) ), Pcurve); + // const x = modulo(LamAdd.times(LamAdd).minus(a[0]).minus(b[0]), Pcurve); + // const y = modulo(LamAdd.times( a[0].minus(x) ).minus(a[1]), Pcurve); + + return [x, y]; + + } + + public ECdouble(a: Array) { + + let Lam = this.modulo((((a[0]*a[0])*this.Three) + this.Acurve)*( this.modInv( a[1]*this.Two )), this.Pcurve); + let x = this.modulo((Lam*Lam)-(a[0]*this.Two), this.Pcurve); + let y = this.modulo( Lam*( a[0]-x )-a[1], this.Pcurve); + + // const Lam = this.modulo(a[0].times(a[0]).times(3).add(this.Acurve).times( this.modInv( a[1].times(2) ) ), this.Pcurve); + // const x = this.modulo(Lam.times(Lam).minus(a[0].times(2)), this.Pcurve); + // const y = this.modulo(Lam.times( a[0].minus(x) ).minus(a[1]), this.Pcurve); + + return [x, y]; + + } + + public ECmultiply(GenPoint: Array, ScalarHex: bigint) { + + if (ScalarHex==this.Zero || ScalarHex>=this.N) + throw "Invalid Scalar/Private Key"; + + let ScalarBinary = ScalarHex.toString(2); + let Q = GenPoint; + + for (let i = 1; i < ScalarBinary.length; i++) { + + Q = this.ECdouble(Q); + + if (ScalarBinary[i] === "1") { + Q = this.ECadd(Q, GenPoint); + } + + } + + return Q; + + } + + // uncompressed is the accumulation of both the x and y points + // compressed is the public key to share in transactions + // address is the public address tho whom someone can send coin + public PublicKeyGenerate(PrivateKey: string | number | bigint) : bigint[] { + + if (typeof PrivateKey === 'number') + PrivateKey = BigInt(PrivateKey); + + if (typeof PrivateKey === 'string') + PrivateKey = BigInt(PrivateKey); + + let PublicKey = this.ECmultiply(this.GPoint, this.privKey); + let Px = this.zfill(PublicKey[0].toString(16)); + let Py = this.zfill(PublicKey[1].toString(16)); + + let uncompressed = PublicKey[0].toString(16) + PublicKey[1].toString(16); + let compressed = "04" + Px + Py; + let address = (this.modulo(PublicKey[1], this.Two) == this.One) + ? "03" + Px + : "02" + Px; + let xy = [ Px, Py ]; + + return [ PublicKey[0], PublicKey[1] ]; + + // return { + // uncompressed, + // compressed, + // address, + // xy + // }; + + } + + +} From cf12fc7b5985ffaf9c7256d55cf34c5902952c0b Mon Sep 17 00:00:00 2001 From: Achim 'ahzf' Friedland Date: Tue, 3 Dec 2019 04:07:15 +0100 Subject: [PATCH 039/110] Fix multiple chargepoint crypt issues, e.g. leading zeros of signature r/s values --- .../secrrct | 173 ++++---- .../chargepoint/Testdata/verifyAll.sh | 18 + src/index.html | 2 + src/js/chargepointCrypt01.ts | 372 ++++++++++-------- src/js/chargyApp.ts | 46 +-- src/js/chargyInterfaces.ts | 7 +- 6 files changed, 349 insertions(+), 269 deletions(-) create mode 100644 documentation/chargepoint/Testdata/verifyAll.sh diff --git a/documentation/chargepoint/Testdata/0024b1000002e300_2_119693895_payload/secrrct b/documentation/chargepoint/Testdata/0024b1000002e300_2_119693895_payload/secrrct index a630e3c..58ad017 100644 --- a/documentation/chargepoint/Testdata/0024b1000002e300_2_119693895_payload/secrrct +++ b/documentation/chargepoint/Testdata/0024b1000002e300_2_119693895_payload/secrrct @@ -1,85 +1,92 @@ { - "company_name": "ChargePoint EU QA EUR", - "display_unit": 3600, - "energy": [{ - "active_charging": 0, - "duration": 421, - "end_time": 1543841929, - "end_time_utc": 1543838329, - "line_item_cost": 0, - "seq_num": 1, - "start_time": 1543841508, - "start_time_utc": 1543837908, - "type": "ENERGY", - "unit_price": "0.05000", - "units": 0.058999999999999997 - }, - { - "duration": 421, - "energy_subtotal": 0, - "seq_num": "SUBTOTAL", - "type": "ENERGY", - "units": 0.058999999999999997 - } - ], - "flat": [{ - "flat_fee": 0, - "flat_fee_subtotal": 0, - "numSubSessions": 1, - "type": "FLAT" - }], - "minMaxAdj": [{ - "session_length": 0, - "session_min": 0.070000000000000007, - "session_min_adjustment": 0.059999999999999998, - "session_total": 0.01, - "type": "SESS_MIN_ADJ" - }], - "parking": [{ - "duration": 421, - "end_time": 1543841929, - "end_time_utc": 1543838329, - "line_item_cost": 0.01, - "overstay": 0, - "seq_num": 1, - "start_time": 1543841508, - "start_time_utc": 1543837908, - "type": "PARKING", - "unit_price": "0.10", - "units": 421 - }, - { - "duration": 421, - "parking_subtotal": 0.01, - "seq_num": "SUBTOTAL", - "type": "PARKING", - "units": 421 - } - ], - "subtotal": 0.070000000000000007, - "subtotal_before_adjustment": 0.01, - "tax": [{ - "tax": 0.01, - "taxPercent": "19.0000", - "taxRuleName": "MwSt.", - "type": "TAX" - }, - { - "seq_num": "SUBTOTAL", - "total_tax": 0.01, - "type": "TAX" - } - ], - "totalAmount": 0.080000000000000002, - "additional_info": { - "outlet": 2, - "session_id": 2, - "station_mac": "0024:b100:0002:e300", - "driver_info": "urn:nema:5evse:dn:v1:chargepoint.com:cdid:cncp000009afd2", - "meter_serial": "240008S", - "currency_code": "EUR", - "meter_startreading": 3078, - "meter_endreading": 3137, - "energy_units": "Wh" - } + "company_name": "ChargePoint EU QA EUR", + "display_unit": 3600, + "energy": [ + { + "active_charging": 0, + "duration": 421, + "end_time": 1543841929, + "end_time_utc": 1543838329, + "line_item_cost": 0, + "seq_num": 1, + "start_time": 1543841508, + "start_time_utc": 1543837908, + "type": "ENERGY", + "unit_price": "0.05000", + "units": 0.058999999999999997 + }, + { + "duration": 421, + "energy_subtotal": 0, + "seq_num": "SUBTOTAL", + "type": "ENERGY", + "units": 0.058999999999999997 + } + ], + "flat": [ + { + "flat_fee": 0, + "flat_fee_subtotal": 0, + "numSubSessions": 1, + "type": "FLAT" + } + ], + "minMaxAdj": [ + { + "session_length": 0, + "session_min": 0.070000000000000007, + "session_min_adjustment": 0.059999999999999998, + "session_total": 0.01, + "type": "SESS_MIN_ADJ" + } + ], + "parking": [ + { + "duration": 421, + "end_time": 1543841929, + "end_time_utc": 1543838329, + "line_item_cost": 0.01, + "overstay": 0, + "seq_num": 1, + "start_time": 1543841508, + "start_time_utc": 1543837908, + "type": "PARKING", + "unit_price": "0.10", + "units": 421 + }, + { + "duration": 421, + "parking_subtotal": 0.01, + "seq_num": "SUBTOTAL", + "type": "PARKING", + "units": 421 + } + ], + "subtotal": 0.070000000000000007, + "subtotal_before_adjustment": 0.01, + "tax": [ + { + "tax": 0.01, + "taxPercent": "19.0000", + "taxRuleName": "MwSt.", + "type": "TAX" + }, + { + "seq_num": "SUBTOTAL", + "total_tax": 0.01, + "type": "TAX" + } + ], + "totalAmount": 0.080000000000000002, + "additional_info": { + "outlet": 2, + "session_id": 2, + "station_mac": "0024:b100:0002:e300", + "driver_info": "urn:nema:5evse:dn:v1:chargepoint.com:cdid:cncp000009afd2", + "meter_serial": "240008S", + "currency_code": "EUR", + "meter_startreading": 3078, + "meter_endreading": 3137, + "energy_units": "Wh" + } } \ No newline at end of file diff --git a/documentation/chargepoint/Testdata/verifyAll.sh b/documentation/chargepoint/Testdata/verifyAll.sh new file mode 100644 index 0000000..c2c7dbb --- /dev/null +++ b/documentation/chargepoint/Testdata/verifyAll.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +openssl dgst -sha256 -verify 0024b1000002e300_2.pem -signature 0024b1000002e300_2_119693895_payload/secrrct.sign 0024b1000002e300_2_119693895_payload/secrrct + +openssl dgst -sha256 -verify 0024b10000027b29_1.pem -signature 0024b10000027b29_1_121708795_payload.FLAT_SESSION/secrrct.sign 0024b10000027b29_1_121708795_payload.FLAT_SESSION/secrrct + +openssl dgst -sha256 -verify 0024b10000027b29_1.pem -signature 0024b10000027b29_1_121708845_payload.Per_Min/secrrct.sign 0024b10000027b29_1_121708845_payload.Per_Min/secrrct + +openssl dgst -sha256 -verify 0024b10000027b29_1.pem -signature 0024b10000027b29_1_121709375_payload._Per_KWh/secrrct.sign 0024b10000027b29_1_121709375_payload._Per_KWh/secrrct + +openssl dgst -sha256 -verify 0024b10000027b29_1.pem -signature 0024b10000027b29_1_121709405_payload_Min_Variation_/secrrct.sign 0024b10000027b29_1_121709405_payload_Min_Variation_/secrrct + +openssl dgst -sha256 -verify 0024b10000027b29_1.pem -signature 0024b10000027b29_1_121709415_payload._TOU_/secrrct.sign 0024b10000027b29_1_121709415_payload._TOU_/secrrct + +openssl dgst -sha256 -verify 0024b10000027b29_1.pem -signature 0024b10000027b29_1_121709465_payload_Parking_Tap_ToCharge/secrrct.sign 0024b10000027b29_1_121709465_payload_Parking_Tap_ToCharge/secrrct + + + diff --git a/src/index.html b/src/index.html index c2b6eab..36c8d8c 100644 --- a/src/index.html +++ b/src/index.html @@ -252,6 +252,8 @@