diff --git a/.editorconfig b/.editorconfig index a874c9a1c35579196462886593fa38dd1dd0efb2..cb6f93bdf205892f7301735ef40840093df17697 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,13 +1,13 @@ # top-most EditorConfig file root = true -# Unix-style newlines with a newline ending every file -[**] -end_of_line = lf -insert_final_newline = true - # ASN.1, XML: 4 space indents [**.{asn,asn1,xml,xsd}] indent_style = space indent_size = 4 trim_trailing_whitespace = true + +[**.json] +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true diff --git a/.gitignore b/.gitignore index 3e3760376b450b5a9b9e6c9c8ff79d2305903cc0..fc05895014b2a3d61b7fe31c6096ba5f0ab514ce 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ .vscode/ .idea/ +testing/dockerfiles/build.log + # Vagrant .vagrant/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4c0fc3081cc8cb383e9fc7c21aa5d73a7adae609..0305e9ef326156f7974ede392c958e6cc5eae89c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -7,9 +7,14 @@ workflow: stages: - preflight - - check + - compile + - lint - build + +# ----------------------------------------------------------- +# Preflight + preflight: image: "forge.etsi.org:5050/li/schemas-definitions/forgelib" stage: preflight @@ -19,19 +24,102 @@ preflight: script: - forgelib-preflight https://$CI_SERVER_HOST $CI_PROJECT_ID $CI_MERGE_REQUEST_IID -process_asn: + +# ----------------------------------------------------------- +# Compile + +compile_asn: image: "forge.etsi.org:5050/li/schemas-definitions/asn1test:latest" - stage: check + stage: compile interruptible: true script: - - python3 testing/asn_process.py + - python3 testing/asn/asn_process.py -process_xsd: - image: "forge.etsi.org:5050/li/schemas-definitions/xsdtest:latest" - stage: check +compile_xsd: + image: "forge.etsi.org:5050/li/schemas-definitions/forgeschema:latest" + stage: compile interruptible: true script: - - python3 testing/xsd_process.py + - export PYCHARM_HOSTED=1 + - | + check_count=0 + fail_count=0 + while IFS= read -r -d '' file; do + let "check_count=check_count+1" + if ! forgeschema -c "$file"; then + echo "❌ failed schema checks for $file" + let "fail_count=fail_count+1" + fi + echo "" + echo "..." + echo "" + done < <(find ./testing/xml -type f -name "*.json" -print0) + if [ "$fail_count" -gt 0 ]; then + echo "┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅" + echo "❌ Failed schema checks for $fail_count of $check_count files" + echo "┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅" + exit 1 + fi + echo "┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅" + echo "✅ XSD validation OK ($check_count files checked)" + echo "┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅" + echo "✅ XSD validation OK for $file" + +compile_json: + image: "forge.etsi.org:5050/li/schemas-definitions/forgeschema:latest" + stage: compile + interruptible: true + script: + - export PYCHARM_HOSTED=1 + - | + check_count=0 + fail_count=0 + while IFS= read -r -d '' file; do + let "check_count=check_count+1" + if ! forgeschema -c "$file"; then + echo "❌ failed schema checks for $file" + let "fail_count=fail_count+1" + fi + echo "" + echo "..." + echo "" + done < <(find ./testing/json -type f -name "*.json" -print0) + if [ "$fail_count" -gt 0 ]; then + echo "┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅" + echo "❌ Failed schema checks for $fail_count of $check_count files" + echo "┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅" + exit 1 + fi + echo "┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅" + echo "✅ JSON validation OK ($check_count files checked)" + echo "┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅" + - forgeschema -s 103120/schema/json/ts_103120_Core.schema.json -u 103120/schema/json -u 103120/dictionaries/ts_103120_Dictionaries.schema.json -u 103280/TS_103_280.schema.json -i 103120/examples/json + + +# ----------------------------------------------------------- +# Lint + +lint_xml: + image: "forge.etsi.org:5050/li/schemas-definitions/forgeschema:latest" + stage: lint + interruptible: true + allow_failure: true + script: + - export PYCHARM_HOSTED=1 + - python testing/xml/lint_xml.py + +lint_json: + image: "forge.etsi.org:5050/li/schemas-definitions/forgeschema:latest" + stage: lint + interruptible: true + allow_failure: true + script: + - export PYCHARM_HOSTED=1 + - python testing/json/lint_json.py + + +# ----------------------------------------------------------- +# Build generate_artefacts: image: "forge.etsi.org:5050/li/schemas-definitions/forgelib" diff --git a/102232-1/LI-PS-PDU.asn b/102232-1/LI-PS-PDU.asn index 7d187add68e1eef79466a269fc683024d15952f0..d084ae6ad2b826d68315c97015706df0d9d9d489 100644 --- a/102232-1/LI-PS-PDU.asn +++ b/102232-1/LI-PS-PDU.asn @@ -1,5 +1,5 @@ LI-PS-PDU -{itu-t(0) identified-organization(4) etsi(0) securityDomain(2) lawfulIntercept(2) li-ps(5) genHeader(1) version39(39)} +{itu-t(0) identified-organization(4) etsi(0) securityDomain(2) lawfulIntercept(2) li-ps(5) genHeader(1) version40(40)} DEFINITIONS IMPLICIT TAGS ::= @@ -43,14 +43,14 @@ IMPORTS IPIRIOnly, IPIRIPacketReport FROM IPAccessPDU - {itu-t(0) identified-organization(4) etsi(0) securityDomain(2) lawfulIntercept(2) li-ps(5) iPAccess(3) version19(19)} + {itu-t(0) identified-organization(4) etsi(0) securityDomain(2) lawfulIntercept(2) li-ps(5) iPAccess(3) version20(20)} -- from ETSI TS 102 232-4 [32] L2CC, L2IRI, L2IRIOnly FROM L2AccessPDU - {itu-t(0) identified-organization(4) etsi(0) securityDomain(2) lawfulIntercept(2) li-ps(5) l2Access(4) version9(9)} + {itu-t(0) identified-organization(4) etsi(0) securityDomain(2) lawfulIntercept(2) li-ps(5) l2Access(4) version10(10)} -- from ETSI TS 102 232-5 [37] IPMMCC, @@ -207,7 +207,7 @@ IMPORTS lawfulInterceptDomainId OBJECT IDENTIFIER ::= {itu-t(0) identified-organization(4) etsi(0) securityDomain(2) lawfulIntercept(2)} -li-psDomainId OBJECT IDENTIFIER ::= {lawfulInterceptDomainId li-ps(5) genHeader(1) version39(39)} +li-psDomainId OBJECT IDENTIFIER ::= {lawfulInterceptDomainId li-ps(5) genHeader(1) version40(40)} -- ==================== -- Top-level definition diff --git a/102232-3/IPAccessPDU.asn b/102232-3/IPAccessPDU.asn index 0a2366f09728ec9da9d85d58c480f0a85a4e7270..54dfa3e368ccb9ce8e293983908ecb30eeff7ac1 100644 --- a/102232-3/IPAccessPDU.asn +++ b/102232-3/IPAccessPDU.asn @@ -1,5 +1,5 @@ IPAccessPDU -{itu-t(0) identified-organization(4) etsi(0) securityDomain(2) lawfulIntercept(2) li-ps(5) iPAccess(3) version19(19)} +{itu-t(0) identified-organization(4) etsi(0) securityDomain(2) lawfulIntercept(2) li-ps(5) iPAccess(3) version20(20)} DEFINITIONS IMPLICIT TAGS ::= BEGIN @@ -9,14 +9,14 @@ IMPORTS IPAddress, Location FROM LI-PS-PDU - {itu-t(0) identified-organization(4) etsi(0) securityDomain(2) lawfulIntercept(2) li-ps(5) genHeader(1) version39(39)}; + {itu-t(0) identified-organization(4) etsi(0) securityDomain(2) lawfulIntercept(2) li-ps(5) genHeader(1) version40(40)}; -- ============================ -- Object Identifier Definition -- ============================ -iPAccessPDUObjId RELATIVE-OID ::= {li-ps(5) iPAccess(3) version19(19)} +iPAccessPDUObjId RELATIVE-OID ::= {li-ps(5) iPAccess(3) version20(20)} iPIRIObjId RELATIVE-OID ::= {iPAccessPDUObjId iRI(1)} iPCCObjId RELATIVE-OID ::= {iPAccessPDUObjId cC(2)} iPIRIOnlyObjId RELATIVE-OID ::= {iPAccessPDUObjId iRIOnly(3)} @@ -152,7 +152,13 @@ AccessEventType ::= ENUMERATED -- A target stops using the IAS, the session ends endOfInterceptionWithSessionActive(9), -- LI is ended on a target who still has an active session - unknown(10) + unknown(10), + startOfInterceptionWithoutNetworkSession(11), + -- Start of LI session without a network session + endOfInterceptionWithoutNetworkSession(12), + -- End of LI session without a network session + sessionExpired(13) + -- LI session terminated due to expiry by MF } InternetAccessType ::= ENUMERATED diff --git a/102232-4/L2AccessPDU.asn b/102232-4/L2AccessPDU.asn index eaf7cc85ed13b2c3714685dc2bd6c0e6c073ba04..2a2be089c005e7018fcee15d8967fb24e2942e71 100644 --- a/102232-4/L2AccessPDU.asn +++ b/102232-4/L2AccessPDU.asn @@ -1,6 +1,6 @@ L2AccessPDU {itu-t(0) identified-organization(4) etsi(0) securityDomain(2) lawfulIntercept(2) -li-ps(5) l2Access(4) version9(9)} +li-ps(5) l2Access(4) version10(10)} DEFINITIONS IMPLICIT TAGS ::= BEGIN @@ -9,7 +9,7 @@ BEGIN -- Object Identifier Definition -- ============================ -l2AccessPDUObjId RELATIVE-OID ::= {li-ps(5) l2Access(4) version9(9)} +l2AccessPDUObjId RELATIVE-OID ::= {li-ps(5) l2Access(4) version10(10)} l2IRIObjId RELATIVE-OID ::= {l2AccessPDUObjId iRI(1)} l2CCObjId RELATIVE-OID ::= {l2AccessPDUObjId cC(2)} l2IRIOnlyObjId RELATIVE-OID ::= {l2AccessPDUObjId iRIOnly(3)} @@ -131,8 +131,14 @@ AccessEventType ::= ENUMERATED -- LI is started on a target who already has an active session accessEnd(9), -- A target stops using the IAS, the session ends. - endOfInterceptionWithSessionActive(10) + endOfInterceptionWithSessionActive(10), -- LI is ended on a target who still has an active session + startOfInterceptionWithoutNetworkSession(11), + -- Start of LI session without a network session + endOfInterceptionWithoutNetworkSession(12), + -- End of LI session without a network session + sessionExpired(13) + -- LI session terminated due to expiry by MF } InternetAccessType ::= ENUMERATED diff --git a/102657/RDMessage.asn b/102657/RDMessage.asn index cdf451c0c7f2a9e35e920b91f47e6f77057d9c6d..074a35fec6f89ab82cdf50e61e072b2f27f528da 100644 --- a/102657/RDMessage.asn +++ b/102657/RDMessage.asn @@ -1,4 +1,4 @@ -RDMessage {itu-t(0) identified-organization(4) etsi(0) securityDomain(2) retainedData(3) rdHeader(0) version32(32)} +RDMessage {itu-t(0) identified-organization(4) etsi(0) securityDomain(2) retainedData(3) rdHeader(0) version33(33)} DEFINITIONS IMPLICIT TAGS ::= @@ -12,7 +12,7 @@ BEGIN retainedDataDomainId OBJECT IDENTIFIER ::= {itu-t(0) identified-organization(4) etsi(0) securityDomain(2) retainedData(3)} -- rdHeader -rdHeaderId OBJECT IDENTIFIER ::= {retainedDataDomainId rdHeader(0) version32(32)} +rdHeaderId OBJECT IDENTIFIER ::= {retainedDataDomainId rdHeader(0) version33(33)} -- ====================================== -- Top level definitions for RDHI wrapper @@ -1771,6 +1771,8 @@ MsgBillingDetails ::= SEQUENCE -- Only to be used in case the present document cannot fulfil the national requirements ..., copyOfBill [7] SEQUENCE OF File OPTIONAL + -- copyOfBill in MsgBillingDetails is obsolete from v2.6.1. + -- Use copyOfBill in MsgBillingRecords instead } @@ -1804,8 +1806,9 @@ MsgBillingRecords ::= SEQUENCE mgsTransactionStatus [8] UTF8String OPTIONAL, -- Status of the transaction (i.e. "declined", "succeeded" etc.) -- Details to be defined on a national bases - cryptocurrency [9] DigitalTokenIdentifier OPTIONAL + cryptocurrency [9] DigitalTokenIdentifier OPTIONAL, -- Cryptocurrency of payment as per ISO 24165-2 [57] + copyOfBill [10] SEQUENCE OF File OPTIONAL } NationalMsgBillingRecords ::= SEQUENCE @@ -2157,6 +2160,8 @@ MultimediaBillingDetails ::= SEQUENCE ..., multimediaBillingAddress [7] MultimediaBillingAddress OPTIONAL, copyOfBill [8] SEQUENCE OF File OPTIONAL + -- copyOfBill in MultimediaBillingDetails is obsolete from v2.6.1. + -- Use copyOfBill in MultimediaBillingRecords instead } @@ -2198,8 +2203,9 @@ MultimediaBillingRecords ::= SEQUENCE multimediaTransactionStatus [8] UTF8String OPTIONAL, -- Status of the transaction (i.e. "declined", "succeeded", etc.) -- Details to be defined on a national bases - cryptocurrency [9] DigitalTokenIdentifier OPTIONAL + cryptocurrency [9] DigitalTokenIdentifier OPTIONAL, -- Cryptocurrency of payment as per ISO 24165-2 [57] + copyOfBill [10] SEQUENCE OF File OPTIONAL } NationalMultimediaBillingRecords ::= SEQUENCE @@ -2461,7 +2467,8 @@ DigitalTokenIdentifier ::= SEQUENCE -- NOTE - as of v2.5.1, this field has been changed from mandatory to optional. informativeDataElements [3] InformativeDataElements OPTIONAL, -- NOTE - as of v2.5.1, this field has been changed from mandatory to optional. - ... + ..., + digitalTokenIdentifierCode [4] UTF8String (SIZE(9)) OPTIONAL } BaseRecord ::= OCTET STRING diff --git a/102657/RDMessage.xsd b/102657/RDMessage.xsd index 956bafa64f3eb773c451ee33700448efd7ed2535..e13e6f33628e5fbca565edb3f6aa4b23878ac214 100644 --- a/102657/RDMessage.xsd +++ b/102657/RDMessage.xsd @@ -1,8 +1,8 @@ - + - XSD translated from ASN.1 derived from outcome of TS 102 657 v2.5.1 + XSD translated from ASN.1 derived from outcome of TS 102 657 v2.6.1 @@ -1882,6 +1882,13 @@ + + + + + + + @@ -1914,6 +1921,8 @@ + + @@ -3090,6 +3099,8 @@ + + @@ -3140,6 +3151,13 @@ + + + + + + + @@ -3543,6 +3561,13 @@ + + + + + + + diff --git a/103120/dictionaries/ts_103120_ETSIDictionaryDefinitions.xml b/103120/dictionaries/ts_103120_ETSIDictionaryDefinitions.xml index 51dbaf90fed0da7e8343a27db8e9b1d7d11a2401..6641af7949ad99e6e3971a6243ece223fbd7abb7 100644 --- a/103120/dictionaries/ts_103120_ETSIDictionaryDefinitions.xml +++ b/103120/dictionaries/ts_103120_ETSIDictionaryDefinitions.xml @@ -617,6 +617,14 @@ StoredContentData Refers to content data in the European Production or Preservation order + + SubscriberDataAndUserIdentifyingData + Refers to both 'subscriber data' and 'data requested for the sole purpose of identifying the user' in the European Production or Preservation Order. + + + TrafficDataAndStoredContentData + Refers to both 'traffic data' and 'content data' in the European Production or Preservation order. + Other Used in all other cases @@ -761,7 +769,7 @@ Implementer supports the "Change of Delivery" Endpoint. - + ETSI @@ -857,5 +865,5 @@ The data related to the Delivery object has been received - + diff --git a/103120/examples/json/request5-JSON-Delivery.json b/103120/examples/json/request5-JSON-Delivery.json index 34d84a01608f9b52c2ef1906b034da26b2894603..61ea27680211dd81000f89ad37e57b22b15e9cf8 100644 --- a/103120/examples/json/request5-JSON-Delivery.json +++ b/103120/examples/json/request5-JSON-Delivery.json @@ -44,18 +44,18 @@ "delivery:LastSequence": true, "delivery:Manifest": { "delivery:ExternalSchema": { - "delivery:ManifestID" : "ExampleJSONSchema", - "delivery:ManifestContents" : { - "delivery:JSONSchema" : { - "schema_goes_here" : "schema_goes_here" + "delivery:ManifestID": "ExampleJSONSchema", + "delivery:ManifestContents": { + "delivery:JSONSchema": { + "schema_goes_here": "schema_goes_here" } } } }, "delivery:Delivery": { "delivery:JSONData": { - "field1" : "this is native JSON embedded data", - "field2" : 1234 + "field1": "this is native JSON embedded data", + "field2": 1234 } } } diff --git a/103120/examples/json/request_ee_config.json b/103120/examples/json/request_ee_config.json new file mode 100644 index 0000000000000000000000000000000000000000..80d46a70007a3f2b5354614eb19b2599025072d3 --- /dev/null +++ b/103120/examples/json/request_ee_config.json @@ -0,0 +1,36 @@ +{ + "@xmlns": "http://uri.etsi.org/03120/common/2019/10/Core", + "@xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance", + "@xmlns:common": "http://uri.etsi.org/03120/common/2016/02/Common", + "@xmlns:task": "http://uri.etsi.org/03120/common/2020/09/Task", + "@xmlns:auth": "http://uri.etsi.org/03120/common/2020/09/Authorisation", + "Header": { + "SenderIdentifier": { + "CountryCode": "XX", + "UniqueIdentifier": "ACTOR01" + }, + "ReceiverIdentifier": { + "CountryCode": "XX", + "UniqueIdentifier": "ACTOR02" + }, + "TransactionIdentifier": "da735c3f-3ab9-4e9e-810e-daf84d973505", + "Timestamp": "2025-05-14T15:21:00.000000Z", + "Version": { + "ETSIVersion": "V1.18.1", + "NationalProfileOwner": "XX", + "NationalProfileVersion": "v1.0" + } + }, + "Payload": { + "RequestPayload": { + "ActionRequests": { + "ActionRequest": [ + { + "ActionIdentifier": 0, + "GETCSPCONFIG": {} + } + ] + } + } + } +} diff --git a/103120/examples/json/response_config.json b/103120/examples/json/response_config.json index d0f4a1f82b231b8fb273bb2a6d747d533a482bc6..d38cac70c2c1804bcd615f8b70a75973b8bec3b7 100644 --- a/103120/examples/json/response_config.json +++ b/103120/examples/json/response_config.json @@ -33,7 +33,7 @@ "Dictionaries": { "dictionaries:Dictionary": [ { - "dictionaries:Owner": "ACTOR2", + "dictionaries:Owner": "ACTOR02", "dictionaries:Name": "LIServiceTypes", "dictionaries:DictionaryEntries": { "dictionaries:DictionaryEntry": [ diff --git a/103120/examples/json/response_ee_config.json b/103120/examples/json/response_ee_config.json new file mode 100644 index 0000000000000000000000000000000000000000..4ea6e8c85437aac5f7cb6692613961c5c79ad9de --- /dev/null +++ b/103120/examples/json/response_ee_config.json @@ -0,0 +1,209 @@ +{ + "@xmlns": "http://uri.etsi.org/03120/common/2019/10/Core", + "@xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance", + "@xmlns:common": "http://uri.etsi.org/03120/common/2016/02/Common", + "@xmlns:task": "http://uri.etsi.org/03120/common/2020/09/Task", + "@xmlns:config": "http://uri.etsi.org/03120/common/2024/06/Config", + "@xmlns:dictionaries": "http://uri.etsi.org/03280/common/2019/10/Dictionaries", + "Header": { + "SenderIdentifier": { + "CountryCode": "XX", + "UniqueIdentifier": "ACTOR01" + }, + "ReceiverIdentifier": { + "CountryCode": "XX", + "UniqueIdentifier": "ACTOR02" + }, + "TransactionIdentifier": "da735c3f-3ab9-4e9e-810e-daf84d973505", + "Timestamp": "2025-05-14T15:21:03.000000Z", + "Version": { + "ETSIVersion": "V1.18.1", + "NationalProfileOwner": "XX", + "NationalProfileVersion": "v1.0" + } + }, + "Payload": { + "ResponsePayload": { + "ActionResponses": { + "ActionResponse": [ + { + "ActionIdentifier": 0, + "GETCSPCONFIGResponse": { + "LastChanged": "2025-04-03T07:25:21Z", + "Dictionaries": { + "dictionaries:Dictionary": [ + { + "dictionaries:Owner": "ACTOR02", + "dictionaries:Name": "LDRequestSubtype", + "dictionaries:DictionaryEntries": { + "dictionaries:DictionaryEntry": [ + { + "dictionaries:Value": "ServiceA", + "dictionaries:Meaning": "Service A allows users to ..." + }, + { + "dictionaries:Value": "ServiceB", + "dictionaries:Meaning": "Service B allows users to ..." + } + ] + } + }, + { + "dictionaries:Owner": "ACTOR02", + "dictionaries:Name": "LPRequestSubtype", + "dictionaries:DictionaryEntries": { + "dictionaries:DictionaryEntry": [ + { + "dictionaries:Value": "ServiceA", + "dictionaries:Meaning": "Service A allows users to ..." + }, + { + "dictionaries:Value": "ServiceB", + "dictionaries:Meaning": "Service B allows users to ..." + } + ] + } + } + ] + }, + "TargetFormatTypeDefinitions": { + "config:FormatOwner": "ACTOR02", + "config:TargetFormatTypeDefinitionEntries": { + "config:TargetFormatTypeDefinitionEntry": [ + { + "config:FormatName": "ProprietaryIdentifier", + "config:Description": "This is an illustration of a proprietary identifier type specific to this CSP, which consists of the string \"CSP\" followed by 10 digits", + "config:FormatRegex": "^CSP[0-9]{10}$" + } + ] + } + }, + "TargetingConfigurations": { + "config:TargetingConfiguration": [ + { + "config:FormatName": "PropietaryIdentifier", + "config:FormatOwner": "ACTOR02", + "config:Guidance": "This targeting configuration defines that the service provider accepts lawful disclosure and lawful preservation requests for the propietary identifier format type described in the TargetFormatTypeDefinitions, associated with Service A for the \"Subscriber Data\" category only", + "config:AssociatedLIServiceTypes": {}, + "config:AssociatedLDRequestTypes": { + "common:DictionaryEntry": [ + { + "common:Owner": "ETSI", + "common:Name": "RequestType", + "common:Value": "SubscriberData" + } + ] + }, + "config:AssociatedLDRequestSubtypes": { + "common:DictionaryEntry": [ + { + "common:Owner": "ACTOR02", + "common:Name": "LDRequestSubtype", + "common:Value": "ServiceA" + } + ] + }, + "config:AssociatedLPRequestTypes": { + "common:DictionaryEntry": [ + { + "common:Owner": "ETSI", + "common:Name": "RequestType", + "common:Value": "SubscriberData" + } + ] + }, + "config:AssociatedLPRequestSubtypes": { + "common:DictionaryEntry": [ + { + "common:Owner": "ACTOR02", + "common:Name": "LPRequestSubtype", + "common:Value": "ServiceA" + } + ] + } + }, + { + "config:FormatName": "InternationalE164", + "config:FormatOwner": "ETSI", + "config:Guidance": "This targeting configuration defines that the service provider accepts lawful disclosure and lawful preservation requests for a telephone number (as ETSI standard format E164 number) associated with Service A and Service B for the \"Traffic Data\" and \"Content Data\" categories", + "config:AssociatedLIServiceTypes": {}, + "config:AssociatedLDRequestTypes": { + "common:DictionaryEntry": [ + { + "common:Owner": "ETSI", + "common:Name": "RequestType", + "common:Value": "TrafficData" + }, + { + "common:Owner": "ETSI", + "common:Name": "RequestType", + "common:Value": "StoredContentData" + } + ] + }, + "config:AssociatedLDRequestSubtypes": { + "common:DictionaryEntry": [ + { + "common:Owner": "ACTOR02", + "common:Name": "LDRequestSubtype", + "common:Value": "ServiceA" + }, + { + "common:Owner": "ACTOR02", + "common:Name": "LDRequestSubtype", + "common:Value": "ServiceB" + } + ] + }, + "config:AssociatedLPRequestTypes": { + "common:DictionaryEntry": [ + { + "common:Owner": "ETSI", + "common:Name": "RequestType", + "common:Value": "TrafficData" + }, + { + "common:Owner": "ETSI", + "common:Name": "RequestType", + "common:Value": "StoredContentData" + } + ] + }, + "config:AssociatedLPRequestSubtypes": { + "common:DictionaryEntry": [ + { + "common:Owner": "ACTOR02", + "common:Name": "LPRequestSubtype", + "common:Value": "ServiceA" + }, + { + "common:Owner": "ACTOR02", + "common:Name": "LPRequestSubtype", + "common:Value": "ServiceB" + } + ] + } + } + ] + }, + "SupportedLIWorkflowEndpoints": {}, + "SupportedLPWorkflowEndpoints": { + "config:SupportedLPWorkflowEndpoint": [ + { + "config:LPWorkflowEndpoint": { + "common:Owner": "ETSI", + "common:Name": "LPWorkflowEndpoint", + "common:Value": "NewAuthorisation" + }, + "config:Guidance": "This tells the LEA what endpoint to use for new warrants. For brevity, in this example, this is the only endpoint specified.", + "config:URL": "https://ts103120.example.com/lp/authorisation/new" + } + ] + } + } + } + ] + } + } + } +} diff --git a/103120/examples/xml/request4-TargetIdentifierSubtype.xml b/103120/examples/xml/request4-TargetIdentifierSubtype.xml index 99f201a98309daea4d2f35f510d0acb3b873e7a6..4668ba9eb87e71b940f69703ec4f5a6501dc0b5d 100644 --- a/103120/examples/xml/request4-TargetIdentifierSubtype.xml +++ b/103120/examples/xml/request4-TargetIdentifierSubtype.xml @@ -23,7 +23,7 @@ Additionally, note that the RequestType is SubscriberData. This describes the type of data to be disclosed, and could apply equally to an account of either type A or type B. - --> + -->
diff --git a/103120/examples/xml/request_ee_config.xml b/103120/examples/xml/request_ee_config.xml new file mode 100644 index 0000000000000000000000000000000000000000..33a96810b8cf50c509ef8638baf3a788432c0b7f --- /dev/null +++ b/103120/examples/xml/request_ee_config.xml @@ -0,0 +1,31 @@ + + + +
+ + XX + ACTOR01 + + + XX + ACTOR02 + + da735c3f-3ab9-4e9e-810e-daf84d973505 + 2025-05-14T15:21:00.000000Z + + V1.18.1 + XX + v1.0 + +
+ + + + + 0 + + + + + +
\ No newline at end of file diff --git a/103120/examples/xml/response_config.xml b/103120/examples/xml/response_config.xml index bf99aa57af9bf10a742fcbc5e4c8ebb4a2367220..bf268b7037e728c0b787e7aa23861a4a7d7e088b 100644 --- a/103120/examples/xml/response_config.xml +++ b/103120/examples/xml/response_config.xml @@ -26,7 +26,7 @@ 2024-05-10T08:52:32Z - ACTOR2 + ACTOR02 LIServiceTypes diff --git a/103120/examples/xml/response_ee_config.xml b/103120/examples/xml/response_ee_config.xml new file mode 100644 index 0000000000000000000000000000000000000000..bcb763d60df9304df76dabcd51a7331f9607785b --- /dev/null +++ b/103120/examples/xml/response_ee_config.xml @@ -0,0 +1,182 @@ + + + +
+ + XX + + ACTOR01 + + + XX + + ACTOR02 + + da735c3f-3ab9-4e9e-810e-daf84d973505 + 2025-05-14T15:21:03.000000Z + + V1.18.1 + XX + v1.0 + +
+ + + + + 0 + + 2025-04-03T07:25:21Z + + + + ACTOR02 + LDRequestSubtype + + + ServiceA + Service A allows users to ... + + + ServiceB + Service B allows users to ... + + + + + ACTOR02 + LPRequestSubtype + + + ServiceA + Service A allows users to ... + + + ServiceB + Service B allows users to ... + + + + + + + ACTOR02 + + + ProprietaryIdentifier + This is an illustration of a proprietary identifier type specific to this CSP, which consists of the string "CSP" followed by 10 digits + ^CSP[0-9]{10}$ + + + + + + + + PropietaryIdentifier + ACTOR02 + This targeting configuration defines that the service provider accepts lawful disclosure and lawful preservation requests for the propietary identifier format type described in the TargetFormatTypeDefinitions, associated with Service A for the "Subscriber Data" category only + + + + ETSI + RequestType + SubscriberData + + + + + ACTOR02 + LDRequestSubtype + ServiceA + + + + + ETSI + RequestType + SubscriberData + + + + + ACTOR02 + LPRequestSubtype + ServiceA + + + + + + InternationalE164 + ETSI + This targeting configuration defines that the service provider accepts lawful disclosure and lawful preservation requests for a telephone number (as ETSI standard format E164 number) associated with Service A and Service B for the "Traffic Data" and "Content Data" categories + + + + ETSI + RequestType + TrafficData + + + ETSI + RequestType + StoredContentData + + + + + ACTOR02 + LDRequestSubtype + ServiceA + + + ACTOR02 + LDRequestSubtype + ServiceB + + + + + ETSI + RequestType + TrafficData + + + ETSI + RequestType + StoredContentData + + + + + ACTOR02 + LPRequestSubtype + ServiceA + + + ACTOR02 + LPRequestSubtype + ServiceB + + + + + + + + + ETSI + LPWorkflowEndpoint + NewAuthorisation + + This tells the LEA what endpoint to use for new warrants. For brevity, in this example, this is the only endpoint specified. + https://ts103120.example.com/lp/authorisation/new + + + + + + + +
diff --git a/103120/schema/json/ts_103120_Config.schema.json b/103120/schema/json/ts_103120_Config.schema.json index 6686a31991092727e7438abdea454efde324d5be..925e2641e5a2b39c216f8d515c4761e8aa411090 100644 --- a/103120/schema/json/ts_103120_Config.schema.json +++ b/103120/schema/json/ts_103120_Config.schema.json @@ -79,9 +79,15 @@ "config:AssociatedLIServiceTypes": { "$ref": "ts_103120_Common_2016_02#/$defs/DictionaryEntries" }, + "config:AssociatedLDRequestTypes": { + "$ref": "ts_103120_Common_2016_02#/$defs/DictionaryEntries" + }, "config:AssociatedLDRequestSubtypes": { "$ref": "ts_103120_Common_2016_02#/$defs/DictionaryEntries" }, + "config:AssociatedLPRequestTypes": { + "$ref": "ts_103120_Common_2016_02#/$defs/DictionaryEntries" + }, "config:AssociatedLPRequestSubtypes": { "$ref": "ts_103120_Common_2016_02#/$defs/DictionaryEntries" } @@ -140,7 +146,7 @@ "SupportedLPWorkflowEndpoint": { "type": "object", "properties": { - "config:LIWorkflowEndpoint": { + "config:LPWorkflowEndpoint": { "$ref": "ts_103120_Common_2016_02#/$defs/DictionaryEntry" }, "config:Guidance": { @@ -151,7 +157,39 @@ } }, "required": [ - "config:LIWorkflowEndpoint", + "config:LPWorkflowEndpoint", + "config:URL" + ], + "additionalProperties": false + }, + "SupportedLDWorkflowEndpoints": { + "type": "object", + "properties": { + "config:SupportedLDWorkflowEndpoint": { + "type": "array", + "items": { + "$ref": "#/$defs/SupportedLDWorkflowEndpoint" + } + } + }, + "required": [], + "additionalProperties": false + }, + "SupportedLDWorkflowEndpoint": { + "type": "object", + "properties": { + "config:LDWorkflowEndpoint": { + "$ref": "ts_103120_Common_2016_02#/$defs/DictionaryEntry" + }, + "config:Guidance": { + "$ref": "ts_103280_2017_07#/$defs/LongString" + }, + "config:URL": { + "$ref": "ts_103280_2017_07#/$defs/LongString" + } + }, + "required": [ + "config:LDWorkflowEndpoint", "config:URL" ], "additionalProperties": false diff --git a/103120/schema/json/ts_103120_Core.schema.json b/103120/schema/json/ts_103120_Core.schema.json index aa321a61bffdf00b1f57dfbba6d2ce18e74c594b..61d682a021c8b36105aea93aa655bff3a6ed9b13 100644 --- a/103120/schema/json/ts_103120_Core.schema.json +++ b/103120/schema/json/ts_103120_Core.schema.json @@ -57,6 +57,9 @@ }, "Version": { "$ref": "#/$defs/Version" + }, + "WorkflowIdentifier": { + "$ref": "ts_103280_2017_07#/$defs/LongString" } }, "required": [ @@ -599,6 +602,9 @@ }, "SupportedLPWorkflowEndpoints": { "$ref": "ts_103120_Config_2024_06#/$defs/SupportedLPWorkflowEndpoints" + }, + "SupportedLDWorkflowEndpoints": { + "$ref": "ts_103120_Config_2024_06#/$defs/SupportedLDWorkflowEndpoints" } }, "required": [ diff --git a/103120/schema/json/ts_103120_Task.schema.json b/103120/schema/json/ts_103120_Task.schema.json index 5ced7ab9c49a323ec708f934c1f8d151229aece8..b90964d8721ff83dfa56a75111f4e0d7165518d8 100644 --- a/103120/schema/json/ts_103120_Task.schema.json +++ b/103120/schema/json/ts_103120_Task.schema.json @@ -457,6 +457,12 @@ }, "task:NationalLDTaskingParameters": { "$ref": "#/$defs/NationalLDTaskingParameters" + }, + "task:Deadlines": { + "$ref": "#/$defs/ListOfLDDeadlines" + }, + "task:ManualInformation": { + "$ref": "ts_103280_2017_07#/$defs/LongString" } }, "required": [ @@ -759,6 +765,35 @@ }, "required": [], "additionalProperties": false + }, + "ListOfLDDeadlines": { + "type": "object", + "properties": { + "task:LDDeadline": { + "type": "array", + "items": { + "$ref": "#/$defs/LDDeadline" + } + } + }, + "required": [], + "additionalProperties": false + }, + "LDDeadline": { + "type": "object", + "properties": { + "task:DateTime": { + "$ref": "ts_103280_2017_07#/$defs/QualifiedDateTime" + }, + "task:NatureOfDeadline": { + "$ref": "ts_103120_Common_2016_02#/$defs/DictionaryEntry" + }, + "task:OtherInformation": { + "$ref": "ts_103280_2017_07#/$defs/LongString" + } + }, + "required": [], + "additionalProperties": false } } } diff --git a/103120/schema/xsd/ts_103120_Config.xsd b/103120/schema/xsd/ts_103120_Config.xsd index 4e752e98082cec330220ce182f74ec6c3772093c..4bc1e590cc34fdb82da781bcc5162dc63e0ab67a 100644 --- a/103120/schema/xsd/ts_103120_Config.xsd +++ b/103120/schema/xsd/ts_103120_Config.xsd @@ -31,14 +31,16 @@ + + - - + + @@ -49,12 +51,25 @@ - + - + + + + + + + + + + + + + + diff --git a/103120/schema/xsd/ts_103120_Core.xsd b/103120/schema/xsd/ts_103120_Core.xsd index 36bfdc8eac0366936b07f447d8113ab955bc40fd..8fca0a86709c0d30c880cad168454d4ccd6421cd 100644 --- a/103120/schema/xsd/ts_103120_Core.xsd +++ b/103120/schema/xsd/ts_103120_Core.xsd @@ -2,7 +2,7 @@ - + @@ -22,6 +22,7 @@ + @@ -174,6 +175,7 @@ + diff --git a/103120/schema/xsd/ts_103120_Task.xsd b/103120/schema/xsd/ts_103120_Task.xsd index 59343ea78b3455ffa7a856cf41fc46268d9572d6..c815f12070705be3f9b6318d62e0ee39d4f33bd0 100644 --- a/103120/schema/xsd/ts_103120_Task.xsd +++ b/103120/schema/xsd/ts_103120_Task.xsd @@ -124,6 +124,8 @@ + + @@ -191,7 +193,7 @@ - + @@ -232,4 +234,16 @@ + + + + + + + + + + + + diff --git a/103221-1/TS_103_221_01_Configuration.xsd b/103221-1/TS_103_221_01_Configuration.xsd index dd803fac79bfc6e9715878cfcd7ce57978e762a1..237d2ce0caa4f15fb518e035509a71a387c1beac 100644 --- a/103221-1/TS_103_221_01_Configuration.xsd +++ b/103221-1/TS_103_221_01_Configuration.xsd @@ -1,7 +1,7 @@ - - - + + + @@ -16,7 +16,7 @@ - + @@ -44,11 +44,10 @@ - + - - - \ No newline at end of file + + \ No newline at end of file diff --git a/103221-1/TS_103_221_01_TrafficPolicy.xsd b/103221-1/TS_103_221_01_TrafficPolicy.xsd index 2e59aa91533e0ac94096483a97c1468fc50f385c..3a7d271fb98a8b18aae35f23c1f688a6abc7b374 100644 --- a/103221-1/TS_103_221_01_TrafficPolicy.xsd +++ b/103221-1/TS_103_221_01_TrafficPolicy.xsd @@ -8,7 +8,7 @@ - + @@ -17,7 +17,7 @@ - + diff --git a/103221-1/examples/CreateTrafficPolicy_example.xml b/103221-1/examples/CreateTrafficPolicy_example.xml index 2edc79858298c25d81b5c616a4bb181fbfabe622..f25b696e80736e31ee08c2ab8360684421ed4ce5 100644 --- a/103221-1/examples/CreateTrafficPolicy_example.xml +++ b/103221-1/examples/CreateTrafficPolicy_example.xml @@ -1,6 +1,6 @@ - + admfID neID 2023-02-14T18:46:21.247432Z @@ -55,10 +55,10 @@ X2andX3 - + b04057af-362f-4e8d-9337-416f43bfd7ec - + diff --git a/103221-2/TS_103_221_02_Configuration.xsd b/103221-2/TS_103_221_02_Configuration.xsd index 7d4f198f1f8cafad46e4660ff3ef4f51782758f1..c9ef671e101f2e5b497d0d352bf4f0728eba76a0 100644 --- a/103221-2/TS_103_221_02_Configuration.xsd +++ b/103221-2/TS_103_221_02_Configuration.xsd @@ -1,6 +1,6 @@ - - + + @@ -26,14 +26,14 @@ - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + \ No newline at end of file diff --git a/103705/examples/example1/csp_records.schema.json b/103705/examples/example1/csp_records.schema.json index e68458c71a5a7852f577f6f49dd1678e7ed99e30..d071346b0d44b9f7d046a06a85bed9daef473de9 100644 --- a/103705/examples/example1/csp_records.schema.json +++ b/103705/examples/example1/csp_records.schema.json @@ -1,5 +1,5 @@ { - "$id": "urn:etsi:li:103705:record-schema-id:v1.1.1", + "$id": "urn:etsi:li:103705:record-schema-id:v1.2.1", "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "CSP Record Schema", "description": "Defines the valid set of Records that may appear in a RecordSet (see ETSI TS 103 705 clause 6.2.4)", @@ -13,12 +13,12 @@ { "allOf": [ { - "$ref": "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/CallRecord" + "$ref": "urn:etsi:li:103705:type-schema-id:v1.2.1#/$defs/CallRecord" }, { "properties": { "type": { - "const": "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/CallRecord" + "const": "urn:etsi:li:103705:type-schema-id:v1.2.1#/$defs/CallRecord" } } } @@ -27,12 +27,12 @@ { "allOf": [ { - "$ref": "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/MessagingRecord" + "$ref": "urn:etsi:li:103705:type-schema-id:v1.2.1#/$defs/MessagingRecord" }, { "properties": { "type": { - "const": "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/MessagingRecord" + "const": "urn:etsi:li:103705:type-schema-id:v1.2.1#/$defs/MessagingRecord" } } } diff --git a/103705/examples/example1/csp_results.json b/103705/examples/example1/csp_results.json index cc407fe5bfae99b6f8f3ae18928ee97729f3fe73..eb0fd78af23464032e062a1d365376034e0a3ff5 100644 --- a/103705/examples/example1/csp_results.json +++ b/103705/examples/example1/csp_results.json @@ -1,6 +1,6 @@ { "recordSetDescription": { - "etsiSchemaId": "urn:etsi:li:103705:response-schema-id:v1.1.1", + "etsiSchemaId": "urn:etsi:li:103705:response-schema-id:v1.2.1", "etsiSpecificationVersion": "0.3.0", "cspName": "csp.example.com", "cspSchemaId": "csp.example_1", @@ -12,7 +12,7 @@ "recordSet": [ { "id": "3da91ade-f526-4e55-b5da-0c8178f25c24", - "type": "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/CallRecord", + "type": "urn:etsi:li:103705:type-schema-id:v1.2.1#/$defs/CallRecord", "timeBegin": "2024-04-20T10:04:00.000000Z", "timeEnd": "2024-04-20T10:05:00.000000Z", "endReason": 16, @@ -34,7 +34,7 @@ }, { "id": "8be3fc6b-a2dd-4104-9af1-d6b1f70081a0", - "type": "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/MessagingRecord", + "type": "urn:etsi:li:103705:type-schema-id:v1.2.1#/$defs/MessagingRecord", "eventTime": "2024-04-18T10:04:00.000000Z", "parties": [ { diff --git a/103705/examples/example2/csp_records.schema.json b/103705/examples/example2/csp_records.schema.json index 5807a2867135a20714576d4f73559257a2747a24..7ab693c666dbd3891affab89d6bcca8a1b683337 100644 --- a/103705/examples/example2/csp_records.schema.json +++ b/103705/examples/example2/csp_records.schema.json @@ -1,5 +1,5 @@ { - "$id": "urn:etsi:li:103705:record-schema-id:v1.1.1", + "$id": "urn:etsi:li:103705:record-schema-id:v1.2.1", "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "CSP Record Schema", "description": "Defines the valid set of Records that may appear in a RecordSet (see ETSI TS 103 705 clause 6.2.4)", @@ -13,12 +13,12 @@ { "allOf": [ { - "$ref": "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/CallRecord" + "$ref": "urn:etsi:li:103705:type-schema-id:v1.2.1#/$defs/CallRecord" }, { "properties": { "type": { - "const": "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/CallRecord" + "const": "urn:etsi:li:103705:type-schema-id:v1.2.1#/$defs/CallRecord" } } } diff --git a/103705/examples/example2/csp_results.json b/103705/examples/example2/csp_results.json index c50ca26cd0d27f399b93ad21eba1a4c344ed965e..e536e17165aa55b8a7596e3aeb4a03347337bd72 100644 --- a/103705/examples/example2/csp_results.json +++ b/103705/examples/example2/csp_results.json @@ -1,6 +1,6 @@ { "recordSetDescription": { - "etsiSchemaId": "urn:etsi:li:103705:response-schema-id:v1.1.1", + "etsiSchemaId": "urn:etsi:li:103705:response-schema-id:v1.2.1", "etsiSpecificationVersion": "0.3.0", "cspName": "csp.example.com", "cspSchemaId": "csp.example_2", @@ -12,7 +12,7 @@ "recordSet": [ { "id": "3da91ade-f526-4e55-b5da-0c8178f25c24", - "type": "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/CallRecord", + "type": "urn:etsi:li:103705:type-schema-id:v1.2.1#/$defs/CallRecord", "timeBegin": "2024-04-20T10:04:00.000000Z", "timeEnd": "2024-04-20T10:05:00.000000Z", "endReason": 16, diff --git a/103705/examples/example2/csp_types.schema.json b/103705/examples/example2/csp_types.schema.json index 9e70a51f2397023f4e3df2e29132fda54cb57e51..68534756083381b0c777d24d469296ff4f87ef13 100644 --- a/103705/examples/example2/csp_types.schema.json +++ b/103705/examples/example2/csp_types.schema.json @@ -7,7 +7,7 @@ "CSPMessagingRecord": { "allOf": [ { - "$ref": "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/MessagingRecord" + "$ref": "urn:etsi:li:103705:type-schema-id:v1.2.1#/$defs/MessagingRecord" } ], "properties": { diff --git a/103705/examples/example3/csp_records.schema.json b/103705/examples/example3/csp_records.schema.json index 35c2613d99a173656ebc0037cadcf1642303200b..d387f839e466162d260867eaee45abdcabe551c7 100644 --- a/103705/examples/example3/csp_records.schema.json +++ b/103705/examples/example3/csp_records.schema.json @@ -1,5 +1,5 @@ { - "$id": "urn:etsi:li:103705:record-schema-id:v1.1.1", + "$id": "urn:etsi:li:103705:record-schema-id:v1.2.1", "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "CSP Record Schema", "description": "Defines the valid set of Records that may appear in a RecordSet (see ETSI TS 103 705 clause 6.2.4)", @@ -13,12 +13,12 @@ { "allOf": [ { - "$ref": "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/CallRecord" + "$ref": "urn:etsi:li:103705:type-schema-id:v1.2.1#/$defs/CallRecord" }, { "properties": { "type": { - "const": "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/CallRecord" + "const": "urn:etsi:li:103705:type-schema-id:v1.2.1#/$defs/CallRecord" } } } diff --git a/103705/examples/example3/csp_results.json b/103705/examples/example3/csp_results.json index 32317a99a66723bc2fdf40d7407f3e044f505ab1..ea63bce03808ddb5e6e21da6998c5cf0791c8e4c 100644 --- a/103705/examples/example3/csp_results.json +++ b/103705/examples/example3/csp_results.json @@ -1,6 +1,6 @@ { "recordSetDescription": { - "etsiSchemaId": "urn:etsi:li:103705:response-schema-id:v1.1.1", + "etsiSchemaId": "urn:etsi:li:103705:response-schema-id:v1.2.1", "etsiSpecificationVersion": "0.3.0", "cspName": "csp.example.com", "cspSchemaId": "csp.example_3", @@ -12,7 +12,7 @@ "recordSet": [ { "id": "3da91ade-f526-4e55-b5da-0c8178f25c24", - "type": "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/CallRecord", + "type": "urn:etsi:li:103705:type-schema-id:v1.2.1#/$defs/CallRecord", "timeBegin": "2024-04-20T10:04:00.000000Z", "timeEnd": "2024-04-20T10:05:00.000000Z", "endReason": 16, diff --git a/103705/examples/example3/csp_types.schema.json b/103705/examples/example3/csp_types.schema.json index 17ff73f8ef99aaf936249b87e8cea801f48548b4..1dcc0927653424fc785d552f47d4e648e2968649 100644 --- a/103705/examples/example3/csp_types.schema.json +++ b/103705/examples/example3/csp_types.schema.json @@ -15,7 +15,7 @@ }, "dataVolumeUsed": { "description": "A data volume associated with this service record (using an ETSI TS 103 705 type) ", - "$ref": "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/DataVolume" + "$ref": "urn:etsi:li:103705:type-schema-id:v1.2.1#/$defs/DataVolume" }, "numberOfService": { "description": "Some number associated with this service record (using a native JSON type)", diff --git a/103705/examples/example4/csp_records.schema.json b/103705/examples/example4/csp_records.schema.json index f25e384090be3c89ea40de859cecd3f3df2fbca9..2f17e9bd3ccfa8b3e0bdf3d6ecbd2dde2732a354 100644 --- a/103705/examples/example4/csp_records.schema.json +++ b/103705/examples/example4/csp_records.schema.json @@ -1,5 +1,5 @@ { - "$id": "urn:etsi:li:103705:record-schema-id:v1.1.1", + "$id": "urn:etsi:li:103705:record-schema-id:v1.2.1", "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "CSP Record Schema", "description": "Defines the valid set of Records that may appear in a RecordSet (see ETSI TS 103 705 clause 6.2.4)", diff --git a/103705/examples/example4/csp_results.json b/103705/examples/example4/csp_results.json index ec0678328ce7f431b36addbf6534bad06996391b..58af5e0a640305cc40dc04190173309a3c2ddc72 100644 --- a/103705/examples/example4/csp_results.json +++ b/103705/examples/example4/csp_results.json @@ -1,6 +1,6 @@ { "recordSetDescription": { - "etsiSchemaId": "urn:etsi:li:103705:response-schema-id:v1.1.1", + "etsiSchemaId": "urn:etsi:li:103705:response-schema-id:v1.2.1", "etsiSpecificationVersion": "0.3.0", "cspName": "csp.example.com", "cspSchemaId": "csp.example_4", diff --git a/103705/examples/example4/csp_types.schema.json b/103705/examples/example4/csp_types.schema.json index 74b7bdc1163aa26a62876323dcab6cc2391c7bad..720aac246ff7cfce59330b71fa7fa2a7cd703e15 100644 --- a/103705/examples/example4/csp_types.schema.json +++ b/103705/examples/example4/csp_types.schema.json @@ -15,19 +15,19 @@ }, "registeredAddress": { "description": "Points to the address registered as part of the service", - "$ref": "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/Pointer" + "$ref": "urn:etsi:li:103705:type-schema-id:v1.2.1#/$defs/Pointer" }, "deliveryAddress": { "description": "Points to the address used for delivery", - "$ref": "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/Pointer" + "$ref": "urn:etsi:li:103705:type-schema-id:v1.2.1#/$defs/Pointer" }, "billingAddress": { "description": "Points to the address used for billing", - "$ref": "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/Pointer" + "$ref": "urn:etsi:li:103705:type-schema-id:v1.2.1#/$defs/Pointer" }, "contactAddress": { "description": "Points to the address used for mailing purposes", - "$ref": "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/Pointer" + "$ref": "urn:etsi:li:103705:type-schema-id:v1.2.1#/$defs/Pointer" } } }, diff --git a/103705/examples/example5/csp_records.schema.json b/103705/examples/example5/csp_records.schema.json index bcbfc87e7462e1257ab28c3bdb80b25bae5559c2..1498fdd46621625f08ffdd401f2f2375954047fe 100644 --- a/103705/examples/example5/csp_records.schema.json +++ b/103705/examples/example5/csp_records.schema.json @@ -1,5 +1,5 @@ { - "$id": "urn:etsi:li:103705:record-schema-id:v1.1.1", + "$id": "urn:etsi:li:103705:record-schema-id:v1.2.1", "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "CSP Record Schema", "description": "Defines the valid set of Records that may appear in a RecordSet (see ETSI TS 103 705 clause 6.2.4)", @@ -13,12 +13,12 @@ { "allOf": [ { - "$ref": "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/CallRecord" + "$ref": "urn:etsi:li:103705:type-schema-id:v1.2.1#/$defs/CallRecord" }, { "properties": { "type": { - "const": "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/CallRecord" + "const": "urn:etsi:li:103705:type-schema-id:v1.2.1#/$defs/CallRecord" } } } @@ -27,12 +27,12 @@ { "allOf": [ { - "$ref": "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/MessagingRecord" + "$ref": "urn:etsi:li:103705:type-schema-id:v1.2.1#/$defs/MessagingRecord" }, { "properties": { "type": { - "const": "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/MessagingRecord" + "const": "urn:etsi:li:103705:type-schema-id:v1.2.1#/$defs/MessagingRecord" } } } diff --git a/103705/examples/example5/csp_results.json b/103705/examples/example5/csp_results.json index 9bbedcf53bf53bef0ebf1d5bcefc6ccd413bb2c8..9b2ab4a47ec848324c1bde2936e7a549c945b0d0 100644 --- a/103705/examples/example5/csp_results.json +++ b/103705/examples/example5/csp_results.json @@ -1,6 +1,6 @@ { "recordSetDescription": { - "etsiSchemaId": "urn:etsi:li:103705:response-schema-id:v1.1.1", + "etsiSchemaId": "urn:etsi:li:103705:response-schema-id:v1.2.1", "etsiSpecificationVersion": "0.3.0", "cspName": "csp.example.com", "cspSchemaId": "csp.example_1", @@ -12,7 +12,7 @@ "recordSet": [ { "id": "3da91ade-f526-4e55-b5da-0c8178f25c24", - "type": "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/CallRecord", + "type": "urn:etsi:li:103705:type-schema-id:v1.2.1#/$defs/CallRecord", "timeBegin": "2024-04-20T10:04:00.000000Z", "timeEnd": "2024-04-20T10:05:00.000000Z", "endReason": 16, @@ -33,7 +33,7 @@ }, { "id": "8be3fc6b-a2dd-4104-9af1-d6b1f70081a0", - "type": "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/MessagingRecord", + "type": "urn:etsi:li:103705:type-schema-id:v1.2.1#/$defs/MessagingRecord", "eventTime": "2024-04-18T10:04:00.000000Z", "parties": [ { diff --git a/103705/schema/etsi_types.schema.json b/103705/schema/etsi_types.schema.json index d14629af583e01d603a7df7863f72584832de5b7..00c95cd28688a2a00ac4b80e1773fe9a1e4e995a 100644 --- a/103705/schema/etsi_types.schema.json +++ b/103705/schema/etsi_types.schema.json @@ -1,5 +1,5 @@ { - "$id": "urn:etsi:li:103705:type-schema-id:v1.1.1", + "$id": "urn:etsi:li:103705:type-schema-id:v1.2.1", "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "ETSI TS 103 705 Types schema", "description": "JSON schema for ETSI-defined types (see clause 6.1 and Annex A)", @@ -66,7 +66,7 @@ "roamingRecord": { "$ref": "#/$defs/RoamingInformation", "description": "Information for inbound / outbound roaming record." - } + } } }, "MessagingRecord": { @@ -524,7 +524,7 @@ "IBAN": { "type": "string", "pattern": "[A-Z]{2}[0-9]{2}[A-Z0-9]{1,30}", - "description": "International Bank Account Number according to ISO 13616-1:2020" + "description": "International Bank Account Number according to ISO 13616-1:2020, converted to upper-case letters." }, "PaymentCard": { "type": "object", diff --git a/103705/schema/records.schema.json b/103705/schema/records.schema.json index 0ae439406665e0d6925bfaab21c4a18277d5330d..70e8b32c71d91585f15972c3ec71cd1e1384e151 100644 --- a/103705/schema/records.schema.json +++ b/103705/schema/records.schema.json @@ -1,5 +1,5 @@ { - "$id": "urn:etsi:li:103705:record-schema-id:v1.1.1", + "$id": "urn:etsi:li:103705:record-schema-id:v1.2.1", "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "CSP Record Schema", "description": "Defines the valid set of Records that may appear in a RecordSet (see ETSI TS 103 705 clause 6.2.4)", @@ -14,12 +14,12 @@ "$comment": "This is an example", "allOf": [ { - "$ref": "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/CallRecord" + "$ref": "urn:etsi:li:103705:type-schema-id:v1.2.1#/$defs/CallRecord" }, { "properties": { "type": { - "const": "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/CallRecord" + "const": "urn:etsi:li:103705:type-schema-id:v1.2.1#/$defs/CallRecord" } } } diff --git a/103705/schema/response.schema.json b/103705/schema/response.schema.json index 0fd4ab3c6ed118e4b43a08703d54b131e663e57d..d41c1b2d261cda43fc02bd02c2c70cfd0fb627e5 100644 --- a/103705/schema/response.schema.json +++ b/103705/schema/response.schema.json @@ -1,5 +1,5 @@ { - "$id": "urn:etsi:li:103705:response-schema-id:v1.1.1", + "$id": "urn:etsi:li:103705:response-schema-id:v1.2.1", "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "ETSI TS 103 705 Response", "description": "Overall Response structure, representing the results of a lawful disclosure request (see clause 5)", @@ -93,7 +93,7 @@ "record": { "allOf": [ { - "$ref": "urn:etsi:li:103705:record-schema-id:v1.1.1#/$defs/record" + "$ref": "urn:etsi:li:103705:record-schema-id:v1.2.1#/$defs/record" } ], "type": "object", diff --git a/103976/examples/CommsIDtoVIN.json b/103976/examples/CommsIDtoVIN.json index 14bc4199ba9990b400311f7cc0a3f3bd5e69d467..25920a37803eef9bb8899cf5be25405594c97503 100644 --- a/103976/examples/CommsIDtoVIN.json +++ b/103976/examples/CommsIDtoVIN.json @@ -1,5 +1,7 @@ { - "CommsIDtoVINRecords" : [ - { "VIN" : "1G9Y817H34LSP7293" } - ] -} \ No newline at end of file + "CommsIDtoVINRecords": [ + { + "VIN": "1G9Y817H34LSP7293" + } + ] +} diff --git a/103976/examples/VINtoCommsID.json b/103976/examples/VINtoCommsID.json index 471523a361109866b7589eaa811a30ab2b483cbd..b130c84fb66c49e753c3c29e701ab90d0c18d476 100644 --- a/103976/examples/VINtoCommsID.json +++ b/103976/examples/VINtoCommsID.json @@ -1,67 +1,87 @@ { - "VINtoCommsIDRecords" : [ - { - "CommsID" : { "IMEI" : "00440123456789" }, - "AssociationTime" : { - "PeriodInTime" : { - "StartTime" : "2022-01-16T15:57:00Z", - "EndTime" : "2022-01-16T15:57:00Z" - } - } - }, - { - "CommsID" : { "IMSI" : "999990123456789" }, - "AssociationTime" : { - "PointInTime" : "2022-01-16T15:57:00Z" - } - }, - { - "CommsID" : { "ICCID" : "89999012345678901234" }, - "AssociationTime" : { - "PointInTime" : "2022-01-16T15:57:00Z" - } - }, - { - "CommsID" : { "PEIIMEI" : "00440123456789" }, - "AssociationTime" : { - "PointInTime" : "2022-01-16T15:57:00Z" - } - }, - { - "CommsID" : { "SUPIIMSI" : "999990123456789" }, - "AssociationTime" : { - "PointInTime" : "2022-01-16T15:57:00Z" - } - }, - { - "CommsID" : { "SUPINAI" : "example@example.com" }, - "AssociationTime" : { - "PointInTime" : "2022-01-16T15:57:00Z" - } - }, - { - "CommsID" : { "MSISDN" : "491713920000" }, - "AssociationTime" : { - "PointInTime" : "2022-01-16T15:57:00Z" - } - }, - { - "CommsID" : { "GPSIMSISDN" : "491713920000" }, - "AssociationTime" : { - "PointInTime" : "2022-01-16T15:57:00Z" - } - }, - { - "CommsID" : { "MACAddress" : "00:00:5e:00:53:00" }, - "AssociationTime" : { - "PointInTime" : "2022-01-16T15:57:00Z" - } - }, - { - "CommsID" : { "EUI164" : "00:00:5e:ef:10:00:00:00" }, - "AssociationTime" : { - "PointInTime" : "2022-01-16T15:57:00Z" - } + "VINtoCommsIDRecords": [ + { + "CommsID": { + "IMEI": "00440123456789" + }, + "AssociationTime": { + "PeriodInTime": { + "StartTime": "2022-01-16T15:57:00Z", + "EndTime": "2022-01-16T15:57:00Z" } - ] -} \ No newline at end of file + } + }, + { + "CommsID": { + "IMSI": "999990123456789" + }, + "AssociationTime": { + "PointInTime": "2022-01-16T15:57:00Z" + } + }, + { + "CommsID": { + "ICCID": "89999012345678901234" + }, + "AssociationTime": { + "PointInTime": "2022-01-16T15:57:00Z" + } + }, + { + "CommsID": { + "PEIIMEI": "00440123456789" + }, + "AssociationTime": { + "PointInTime": "2022-01-16T15:57:00Z" + } + }, + { + "CommsID": { + "SUPIIMSI": "999990123456789" + }, + "AssociationTime": { + "PointInTime": "2022-01-16T15:57:00Z" + } + }, + { + "CommsID": { + "SUPINAI": "example@example.com" + }, + "AssociationTime": { + "PointInTime": "2022-01-16T15:57:00Z" + } + }, + { + "CommsID": { + "MSISDN": "491713920000" + }, + "AssociationTime": { + "PointInTime": "2022-01-16T15:57:00Z" + } + }, + { + "CommsID": { + "GPSIMSISDN": "491713920000" + }, + "AssociationTime": { + "PointInTime": "2022-01-16T15:57:00Z" + } + }, + { + "CommsID": { + "MACAddress": "00:00:5e:00:53:00" + }, + "AssociationTime": { + "PointInTime": "2022-01-16T15:57:00Z" + } + }, + { + "CommsID": { + "EUI164": "00:00:5e:ef:10:00:00:00" + }, + "AssociationTime": { + "PointInTime": "2022-01-16T15:57:00Z" + } + } + ] +} diff --git a/103976/examples/VINtoLocation.json b/103976/examples/VINtoLocation.json index 708d23bc7ce49f0af98118a860539a8b444907b7..832fb2a459bc13cd842f271a274534f3c88d4636 100644 --- a/103976/examples/VINtoLocation.json +++ b/103976/examples/VINtoLocation.json @@ -1,28 +1,28 @@ { - "VINtoLocationRecords" : [ - { - "Location" : { - "WGS84CoordinateDecimal" : { - "etsi280:latitude" : "N43.617003", - "etsi280:longitude" : "E007.053222" - } - }, - "TimeOfLocation" : { - "PointInTime" : "2022-01-16T15:57:00Z" - } - }, - { - "Location" : { - "WGS84CoordinateDecimal" : { - "etsi280:latitude" : "N43.617003", - "etsi280:longitude" : "E007.053222" - } - }, - "TimeOfLocation" : { - "PointInTime" : "2022-01-16T15:57:00Z" - }, - "SourceOfLocation" : "GNSS", - "LocationRecordReason" : "Location record reason" + "VINtoLocationRecords": [ + { + "Location": { + "WGS84CoordinateDecimal": { + "etsi280:latitude": "N43.617003", + "etsi280:longitude": "E007.053222" } - ] -} \ No newline at end of file + }, + "TimeOfLocation": { + "PointInTime": "2022-01-16T15:57:00Z" + } + }, + { + "Location": { + "WGS84CoordinateDecimal": { + "etsi280:latitude": "N43.617003", + "etsi280:longitude": "E007.053222" + } + }, + "TimeOfLocation": { + "PointInTime": "2022-01-16T15:57:00Z" + }, + "SourceOfLocation": "GNSS", + "LocationRecordReason": "Location record reason" + } + ] +} diff --git a/103976/ts_103976.schema.json b/103976/ts_103976.schema.json index e0b0e670360d027156f3d668af52f65293a8e390..2f45d02434fc1530db81b6e5e4e94f3915461e02 100644 --- a/103976/ts_103976.schema.json +++ b/103976/ts_103976.schema.json @@ -1,191 +1,363 @@ -{ - "$id": "ts_103976_core", - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$defs": { - "AssociationPeriod" : { - "type" : "object", - "properties" : { - "StartTime" : { "$ref": "ts_103280_2017_07#/$defs/QualifiedDateTime" }, - "EndTime" : { "$ref": "ts_103280_2017_07#/$defs/QualifiedDateTime" } - }, - "required" : ["StartTime"] - }, - "AssociationTime" : { - "oneOf" : [ - { - "type" : "object", - "properties" : { - "PointInTime" : { "$ref": "ts_103280_2017_07#/$defs/QualifiedDateTime" } - }, - "required" : ["PointInTime"] - }, - { - "type" : "object", - "properties" : { - "PeriodInTime" : { "$ref": "#/$defs/AssociationPeriod" } - }, - "required" : ["PeriodInTime"] - } - ] - }, - "CommsID" : { - "oneOf" : [ - { - "type" : "object", - "properties" : { "IMEI" : { "$ref" : "ts_103280_2017_07#/$defs/IMEI"} }, - "required" : ["IMEI"] - }, - { - "type" : "object", - "properties" : { "IMSI" : { "$ref" : "ts_103280_2017_07#/$defs/IMSI"} }, - "required" : ["IMSI"] - }, - { - "type" : "object", - "properties" : { "ICCID" : { "$ref" : "ts_103280_2017_07#/$defs/ICCID"} }, - "required" : ["ICCID"] - }, - { - "type" : "object", - "properties" : { "PEIIMEI" : { "$ref" : "ts_103280_2017_07#/$defs/PEIIMEI"} }, - "required" : ["PEIIMEI"] - }, - { - "type" : "object", - "properties" : { "SUPIIMSI" : { "$ref" : "ts_103280_2017_07#/$defs/SUPIIMSI"} }, - "required" : ["SUPIIMSI"] - }, - { - "type" : "object", - "properties" : { "SUPINAI" : { "$ref" : "ts_103280_2017_07#/$defs/SUPINAI"} }, - "required" : ["SUPINAI"] - }, - { - "type" : "object", - "properties" : { "MSISDN" : { "$ref" : "ts_103280_2017_07#/$defs/InternationalE164"} }, - "required" : ["MSISDN"] - }, - { - "type" : "object", - "properties" : { "GPSIMSISDN" : { "$ref" : "ts_103280_2017_07#/$defs/GPSIMSISDN"} }, - "required" : ["GPSIMSISDN"] - }, - { - "type" : "object", - "properties" : { "GPSINAI" : { "$ref" : "ts_103280_2017_07#/$defs/GPSINAI"} }, - "required" : ["GPSINAI"] - }, - { - "type" : "object", - "properties" : { "MACAddress" : { "$ref" : "ts_103280_2017_07#/$defs/MACAddress"} }, - "required" : ["MACAddress"] - }, - { - "type" : "object", - "properties" : { "EUI164" : { "$ref" : "ts_103280_2017_07#/$defs/EUI64"} }, - "required" : ["EUI164"] - } - ] - }, - "Location" : { - "oneOf" : [ - { - "type" : "object", - "properties" : { - "WGS84CoordinateDecimal" : { "$ref" : "ts_103280_2017_07#/$defs/WGS84CoordinateDecimal"} - }, - "required" : ["WGS84CoordinateDecimal"] - } - ] - }, - "SourceOfLocation" : { - "enum" : ["GNSS"] - }, - "VINtoCommsIDRecord" : { - "type" : "object", - "properties" : { - "CommsID" : { "$ref" : "#/$defs/CommsID" }, - "AssociationTime" : { "$ref" : "#/$defs/AssociationTime"} - }, - "required" : ["CommsID"] - }, - "CommsIDToVINRecord" : { - "type" : "object", - "properties" : { - "VIN" : { "$ref" : "ts_103280_2017_07#/$defs/VIN" }, - "AssociationTime" : { "$ref" : "#/$defs/AssociationTime"} - }, - "required" : ["VIN"] - }, - "VINtoLocationRecord" : { - "type" : "object", - "properties" : { - "Location" : { "$ref" : "#/$defs/Location" }, - "TimeOfLocation" : { "$ref" : "#/$defs/AssociationTime" }, - "SourceOfLocation" : { "$ref" : "#/$defs/SourceOfLocation" }, - "LocationRecordReason" : { "$ref" : "ts_103280_2017_07#/$defs/LongString" } - }, - "required" : ["Location", "TimeOfLocation"] - }, - "VINtoUniquePartNumberRecord" : { - "type" : "object", - "properties" : { - "UniquePartNumber" : { "$ref" : "ts_103280_2017_07#/$defs/ShortString" }, - "PartType" : { "$ref" : "ts_103120_Common_2016_02#/$defs/DictionaryEntry"}, - "PartTypeFreeText" : { "$ref" : "ts_103280_2017_07#/$defs/ShortString" } - }, - "required" : ["UniquePartNumber"] - }, - "UniquePartNumbertoVINRecord" : { - "type" : "object", - "properties" : { - "VIN" : { "$ref" : "ts_103280_2017_07#/$defs/VIN" } - }, - "required" : ["VIN"] - }, - "VINtoSubscribedServicesRecord" : { - "type" : "object", - "properties" : { - "NameOfService" : { "$ref" : "ts_103280_2017_07#/$defs/ShortString" }, - "FirstPaymentDate" : { "$ref": "ts_103280_2017_07#/$defs/QualifiedDateTime" }, - "MostRecentPaymentDate" : { "$ref": "ts_103280_2017_07#/$defs/QualifiedDateTime" }, - "TerminationDate" : { "$ref": "ts_103280_2017_07#/$defs/QualifiedDateTime" }, - "UserID" : { "$ref" : "ts_103280_2017_07#/$defs/ShortString" }, - "CustomerName" : { "$ref" : "ts_103280_2017_07#/$defs/ShortString" }, - "CustomerAddress": { "$ref" : "ts_103280_2017_07#/$defs/LongString" }, - "TypeOfPaymentMethod" : { "$ref" : "ts_103120_Common_2016_02#/$defs/DictionaryEntry"} - }, - "required" : [] - }, - "ResultRecords" : { - "type" : "object", - "properties" : { - "VINtoCommsIDRecords" : { - "type" : "array", - "items" : { "$ref" : "#/$defs/VINtoCommsIDRecord"} - }, - "CommsIDtoVINRecords" : { - "type" : "array", - "items" : { "$ref" : "#/$defs/CommsIDToVINRecord"} - }, - "VINtoLocationRecords" : { - "type" : "array", - "items" : { "$ref" : "#/$defs/VINtoLocationRecord"} - }, - "VINtoUniquePartNumberRecords" : { - "type" : "array", - "items" : { "$ref" : "#/$defs/VINtoUniquePartNumberRecord"} - }, - "UniquePartNumbertoVINRecords" : { - "type" : "array", - "items" : { "$ref" : "#/$defs/UniquePartNumbertoVINRecord"} - }, - "VINtoSubscribedServicesRecords" : { - "type" : "array", - "items" : { "$ref" : "#/$defs/VINtoSubscribedServicesRecord"} - } - } - } - }, - "$ref": "#/$defs/ResultRecords" -} \ No newline at end of file +{ + "$id": "ts_103976_core", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$defs": { + "AssociationPeriod": { + "type": "object", + "properties": { + "StartTime": { + "$ref": "ts_103280_2017_07#/$defs/QualifiedDateTime" + }, + "EndTime": { + "$ref": "ts_103280_2017_07#/$defs/QualifiedDateTime" + } + }, + "required": [ + "StartTime" + ] + }, + "AssociationTime": { + "oneOf": [ + { + "type": "object", + "properties": { + "PointInTime": { + "$ref": "ts_103280_2017_07#/$defs/QualifiedDateTime" + } + }, + "required": [ + "PointInTime" + ] + }, + { + "type": "object", + "properties": { + "PeriodInTime": { + "$ref": "#/$defs/AssociationPeriod" + } + }, + "required": [ + "PeriodInTime" + ] + } + ] + }, + "CommsID": { + "oneOf": [ + { + "type": "object", + "properties": { + "IMEI": { + "$ref": "ts_103280_2017_07#/$defs/IMEI" + } + }, + "required": [ + "IMEI" + ] + }, + { + "type": "object", + "properties": { + "IMSI": { + "$ref": "ts_103280_2017_07#/$defs/IMSI" + } + }, + "required": [ + "IMSI" + ] + }, + { + "type": "object", + "properties": { + "ICCID": { + "$ref": "ts_103280_2017_07#/$defs/ICCID" + } + }, + "required": [ + "ICCID" + ] + }, + { + "type": "object", + "properties": { + "PEIIMEI": { + "$ref": "ts_103280_2017_07#/$defs/PEIIMEI" + } + }, + "required": [ + "PEIIMEI" + ] + }, + { + "type": "object", + "properties": { + "SUPIIMSI": { + "$ref": "ts_103280_2017_07#/$defs/SUPIIMSI" + } + }, + "required": [ + "SUPIIMSI" + ] + }, + { + "type": "object", + "properties": { + "SUPINAI": { + "$ref": "ts_103280_2017_07#/$defs/SUPINAI" + } + }, + "required": [ + "SUPINAI" + ] + }, + { + "type": "object", + "properties": { + "MSISDN": { + "$ref": "ts_103280_2017_07#/$defs/InternationalE164" + } + }, + "required": [ + "MSISDN" + ] + }, + { + "type": "object", + "properties": { + "GPSIMSISDN": { + "$ref": "ts_103280_2017_07#/$defs/GPSIMSISDN" + } + }, + "required": [ + "GPSIMSISDN" + ] + }, + { + "type": "object", + "properties": { + "GPSINAI": { + "$ref": "ts_103280_2017_07#/$defs/GPSINAI" + } + }, + "required": [ + "GPSINAI" + ] + }, + { + "type": "object", + "properties": { + "MACAddress": { + "$ref": "ts_103280_2017_07#/$defs/MACAddress" + } + }, + "required": [ + "MACAddress" + ] + }, + { + "type": "object", + "properties": { + "EUI164": { + "$ref": "ts_103280_2017_07#/$defs/EUI64" + } + }, + "required": [ + "EUI164" + ] + } + ] + }, + "Location": { + "oneOf": [ + { + "type": "object", + "properties": { + "WGS84CoordinateDecimal": { + "$ref": "ts_103280_2017_07#/$defs/WGS84CoordinateDecimal" + } + }, + "required": [ + "WGS84CoordinateDecimal" + ] + } + ] + }, + "SourceOfLocation": { + "enum": [ + "GNSS" + ] + }, + "VINtoCommsIDRecord": { + "type": "object", + "properties": { + "CommsID": { + "$ref": "#/$defs/CommsID" + }, + "AssociationTime": { + "$ref": "#/$defs/AssociationTime" + } + }, + "required": [ + "CommsID" + ] + }, + "CommsIDToVINRecord": { + "type": "object", + "properties": { + "VIN": { + "$ref": "ts_103280_2017_07#/$defs/VIN" + }, + "AssociationTime": { + "$ref": "#/$defs/AssociationTime" + } + }, + "required": [ + "VIN" + ] + }, + "VINtoLocationRecord": { + "type": "object", + "properties": { + "Location": { + "$ref": "#/$defs/Location" + }, + "TimeOfLocation": { + "$ref": "#/$defs/AssociationTime" + }, + "SourceOfLocation": { + "$ref": "#/$defs/SourceOfLocation" + }, + "LocationRecordReason": { + "$ref": "ts_103280_2017_07#/$defs/LongString" + } + }, + "required": [ + "Location", + "TimeOfLocation" + ] + }, + "VINtoUniquePartNumberRecord": { + "type": "object", + "properties": { + "UniquePartNumber": { + "$ref": "ts_103280_2017_07#/$defs/ShortString" + }, + "PartType": { + "$ref": "ts_103120_Common_2016_02#/$defs/DictionaryEntry" + }, + "PartTypeFreeText": { + "$ref": "ts_103280_2017_07#/$defs/ShortString" + } + }, + "required": [ + "UniquePartNumber" + ] + }, + "UniquePartNumbertoVINRecord": { + "type": "object", + "properties": { + "VIN": { + "$ref": "ts_103280_2017_07#/$defs/VIN" + } + }, + "required": [ + "VIN" + ] + }, + "VINtoSubscribedServicesRecord": { + "type": "object", + "properties": { + "NameOfService": { + "$ref": "ts_103280_2017_07#/$defs/ShortString" + }, + "FirstPaymentDate": { + "$ref": "ts_103280_2017_07#/$defs/QualifiedDateTime" + }, + "MostRecentPaymentDate": { + "$ref": "ts_103280_2017_07#/$defs/QualifiedDateTime" + }, + "TerminationDate": { + "$ref": "ts_103280_2017_07#/$defs/QualifiedDateTime" + }, + "UserID": { + "$ref": "ts_103280_2017_07#/$defs/ShortString" + }, + "CustomerName": { + "$ref": "ts_103280_2017_07#/$defs/ShortString" + }, + "CustomerAddress": { + "$ref": "ts_103280_2017_07#/$defs/LongString" + }, + "TypeOfPaymentMethod": { + "$ref": "ts_103120_Common_2016_02#/$defs/DictionaryEntry" + } + }, + "required": [] + }, + "VINtoConnectedDevicesRecord": { + "type": "object", + "properties": { + "ConnectionType": { + "$ref": "ts_103120_Common_2016_02#/$defs/DictionaryEntry" + }, + "DeviceIdentifiers": { + "$ref": "#/$defs/ListOfCommsIDs" + }, + "ConnectionTime": { + "$ref": "#/$defs/AssociationTime" + } + }, + "required": [ + "ConnectionTime" + ] + }, + "ListOfCommsIDs": { + "type": "array", + "items": { + "$ref": "#/$defs/CommsID" + } + }, + "ResultRecords": { + "type": "object", + "properties": { + "VINtoCommsIDRecords": { + "type": "array", + "items": { + "$ref": "#/$defs/VINtoCommsIDRecord" + } + }, + "CommsIDtoVINRecords": { + "type": "array", + "items": { + "$ref": "#/$defs/CommsIDToVINRecord" + } + }, + "VINtoLocationRecords": { + "type": "array", + "items": { + "$ref": "#/$defs/VINtoLocationRecord" + } + }, + "VINtoUniquePartNumberRecords": { + "type": "array", + "items": { + "$ref": "#/$defs/VINtoUniquePartNumberRecord" + } + }, + "UniquePartNumbertoVINRecords": { + "type": "array", + "items": { + "$ref": "#/$defs/UniquePartNumbertoVINRecord" + } + }, + "VINtoSubscribedServicesRecords": { + "type": "array", + "items": { + "$ref": "#/$defs/VINtoSubscribedServicesRecord" + } + } + } + } + }, + "$ref": "#/$defs/ResultRecords" +} diff --git a/103976/ts_103976_ETSIDictionaryDefinitions.xml b/103976/ts_103976_ETSIDictionaryDefinitions.xml index 9aa4e487c8d2236863803ade1a20ebe8791b8712..6c0b2f5f9f8e0feb8291375d8f895bc990f7c6f4 100644 --- a/103976/ts_103976_ETSIDictionaryDefinitions.xml +++ b/103976/ts_103976_ETSIDictionaryDefinitions.xml @@ -70,4 +70,40 @@ + + ETSI + TS103976HandoverFormat + + + TS103976ISOFormat + The LEA accepts that the RPS may use ISO containers to respond to the request. + + + + + ETSI + TS103976ConnectionType + + + Infotainment + A device which is connected to the vehicle either via a cable (e.g. via USB) or wirelessly (e.g. via Bluetooth) in order to allow features from the device (e.g. navigation, calls, music) to be displayed on the vehicle or accessed through the vehicle. Typically used when the device is in the vehicle. + + + RemoteAccess + A device which is connected to the vehicle (typically wirelessly) in order to access data from the vehicle or to remotely engage functions on the vehicle. Typically used when the device is not in the vehicle. + + + KeyPairing + Device is authorized to be used for gaining entry to the vehicle or to facilitate starting the vehicle, or both. This connection type is used to indicate that the device has the capability to assist with entry to the vehicle or starting the vehicle. + + + KeyUse + The use of a device to gain entry to the vehicle or to start the vehicle. + + + WLAN + Device that is using the car as a Wireless Local Area Network hot spot. + + +
diff --git a/104000/examples/01_registration_request.xml b/104000/examples/01_registration_request.xml index f10bb7df4e3abbb9c6c3c9faa358f2ed43e0b27b..55fe38fccfb06c9d654dd539861f7072b4896047 100644 --- a/104000/examples/01_registration_request.xml +++ b/104000/examples/01_registration_request.xml @@ -1,4 +1,5 @@ - + + ADMF X0ID 2024-06-07T08:43:17.000000Z diff --git a/104000/examples/01_registration_response.xml b/104000/examples/01_registration_response.xml index 747f4463f9171778b5bfe9bd525c559c7f926d62..c7aee5d4b6f02384cf5968e953f7e87d6c496798 100644 --- a/104000/examples/01_registration_response.xml +++ b/104000/examples/01_registration_response.xml @@ -1,4 +1,5 @@ - + + ADMF ELI 2024-06-07T08:43:17.000000Z diff --git a/104000/examples/02_xn_cert_enrolment_request.xml b/104000/examples/02_xn_cert_enrolment_request.xml index d70c54bff687023dbde939bc7b1b960ce93af16f..0c9b76c64ec4b2405912f0f49185fcb5b6e93aab 100644 --- a/104000/examples/02_xn_cert_enrolment_request.xml +++ b/104000/examples/02_xn_cert_enrolment_request.xml @@ -1,23 +1,24 @@ - + + ADMF ELI_1234 2024-06-07T11:08:07.000000Z v1.1.1 be165469-1024-4551-baab-84932e92abfb - - - LI_X1 - - ETSI-TC-LI - X1-client - - - - LI_T2 - - ETSI-TC-LI - X1-server - - - - + + + LI_X1 + + ETSI-TC-LI + X1-client + + + + LI_T2 + + ETSI-TC-LI + X1-server + + + + \ No newline at end of file diff --git a/104000/examples/02_xn_cert_enrolment_response.xml b/104000/examples/02_xn_cert_enrolment_response.xml index 8eaf1dff6880d41c528f04b7ea86ac96bb263270..dfb0adb91e889d3b0b958e1821d3149013a8c6a5 100644 --- a/104000/examples/02_xn_cert_enrolment_response.xml +++ b/104000/examples/02_xn_cert_enrolment_response.xml @@ -1,4 +1,5 @@ - + + ADMF ELI_1234 2024-06-07T11:08:07.000000Z diff --git a/104000/examples/03_configuration_request.xml b/104000/examples/03_configuration_request.xml index b05908ec2bafa9055e586e5fb768a783088e0af8..0d7879238c1ec2210e06ca45227cc156519c7fa5 100644 --- a/104000/examples/03_configuration_request.xml +++ b/104000/examples/03_configuration_request.xml @@ -1,4 +1,5 @@ - + + ADMF ELI_1234 2024-06-07T11:54:04.000000Z diff --git a/104000/examples/03_configuration_response.xml b/104000/examples/03_configuration_response.xml index cc4c48cf203f6b834b802c0b3e851cb20d1844bc..0a3f703dd94809d10f68c6f35f2e459de660d328 100644 --- a/104000/examples/03_configuration_response.xml +++ b/104000/examples/03_configuration_response.xml @@ -1,4 +1,5 @@ - + + ADMF ELI_1234 2024-06-07T11:54:04.000000Z diff --git a/104000/examples/04_notification_request.xml b/104000/examples/04_notification_request.xml index 76ee3e8236d0afdeb5f085b1ef7e89d98b36944a..8283d0a76db7afd47fc6bd5b3484e9955d513135 100644 --- a/104000/examples/04_notification_request.xml +++ b/104000/examples/04_notification_request.xml @@ -1,4 +1,5 @@ - + + ADMF ELI_1234 2024-06-07T11:54:04.000000Z diff --git a/104000/examples/04_notification_response.xml b/104000/examples/04_notification_response.xml index 80a81bb1430678471d535fd0f5f6ee1fdf5a41a8..f3768ef8e12065ea4836145daacba37503a90ef2 100644 --- a/104000/examples/04_notification_response.xml +++ b/104000/examples/04_notification_response.xml @@ -1,4 +1,5 @@ - + + ADMF ELI_1234 2024-06-07T11:54:04.000000Z diff --git a/104000/examples/05_getallconfiguration_request.xml b/104000/examples/05_getallconfiguration_request.xml new file mode 100644 index 0000000000000000000000000000000000000000..49d9192064893fdd3d366ab7afeae0872919ad7f --- /dev/null +++ b/104000/examples/05_getallconfiguration_request.xml @@ -0,0 +1,8 @@ + + + ADMF + ELI_1234 + 2025-05-19T11:54:04.000000Z + v1.3.1 + c4556686-90fd-4c6f-ab1b-721d72b954fc + diff --git a/104000/examples/05_getallconfiguration_response.xml b/104000/examples/05_getallconfiguration_response.xml new file mode 100644 index 0000000000000000000000000000000000000000..7226a3509997bac1358d37cc753149fd7bda2a6d --- /dev/null +++ b/104000/examples/05_getallconfiguration_response.xml @@ -0,0 +1,78 @@ + + + ADMF + ELI_1234 + 2025-05-19T11:54:04.000000Z + v1.3.1 + c4556686-90fd-4c6f-ab1b-721d72b954fc + + + X0 + + be0b4911-e55c-40a2-aece-04802d5e25fc + PKCS12BASE64 + value + + + + + + LI_X1 + + ETSI-TC-LI + X1-client + + + + + + server_name + certificate_authority + http://example.com + + + + + 1.2.840.113549.1.1.1 + 2048 + + key_identifier + password + subject + subject_alt_name + 1 + + + + + + LI_X1 + + ETSI-TC-LI + X1-server + + + + + + server_name + certificate_authority + http://example.com + + + + + 1.2.840.10045.2.1 + 1.2.840.10045.3.1.7 + + key_identifier + password + subject + subject_alt_name + 1 + + + + + + diff --git a/104000/schema/TS_104_000.xsd b/104000/schema/TS_104_000.xsd index 3364ef5d3b2e299b7467bc00482973ef119c9819..09dfcffb5e40602340c9fefef0ae18511f01460b 100644 --- a/104000/schema/TS_104_000.xsd +++ b/104000/schema/TS_104_000.xsd @@ -1,5 +1,5 @@ - + @@ -234,7 +234,24 @@ - + + + + + + + + + + + + + + + + + + diff --git a/104112/examples/xml/MessagingServiceSchema.xsd b/104112/examples/xml/MessagingServiceSchema.xsd new file mode 100644 index 0000000000000000000000000000000000000000..4089b7fbc11990b9a7a2530af96b9a49979c8e24 --- /dev/null +++ b/104112/examples/xml/MessagingServiceSchema.xsd @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/104112/examples/xml/TC-03_LIDelivery_TSC001.xml b/104112/examples/xml/TC-03_LIDelivery_TSC001.xml new file mode 100644 index 0000000000000000000000000000000000000000..22907810a53f1312c70dfaf6d59d572d625d0750 --- /dev/null +++ b/104112/examples/xml/TC-03_LIDelivery_TSC001.xml @@ -0,0 +1,101 @@ + + +
+ + XX + ACTOR02 + + + XX + ACTOR01 + + 8854cfad-44ac-43b8-99ae-530b690b43da + 2025-04-04T13:37:37.000000Z + + V1.18.1 + XX + v1.0 + +
+ + + + + 0 + + 71ff52ca-bcea-4fa3-b34e-1b89dcfb0d9e + + 71ff52ca-bcea-4fa3-b34e-1b89dcfb0d9e + + 2b36a78b-b628-416d-bd22-404e68a0cd36 + + + XX-ACTOR01-1234 + + d1079830-8e9a-4731-8fb7-36b9b961eb73 + 1 + true + + + ETSI + ManifestSpecification + TS103707 + + + + + + + + + + + + + ETSI + EmailAddress + + PartyA@example.com + + + true + + + + + + + ETSI + EmailAddress + + PartyA@example.com + + + + + 2025-04-04T13:37:37.000000+00:00 + + + + + http://MessagingServiceSchema.example.com/schema/v1.1.1/ + + + + 633523913219 + Foo for you + + + + + + + + + + + + + + +
diff --git a/104112/examples/xml/TC-03_LIDelivery_TSC007.xml b/104112/examples/xml/TC-03_LIDelivery_TSC007.xml new file mode 100644 index 0000000000000000000000000000000000000000..68ca2ca9af637dd736066f360259475ce0ac1013 --- /dev/null +++ b/104112/examples/xml/TC-03_LIDelivery_TSC007.xml @@ -0,0 +1,112 @@ + + +
+ + XX + ACTOR02 + + + XX + ACTOR01 + + 8854cfad-44ac-43b8-99ae-530b690b43da + 2025-04-04T13:37:37.000000Z + + V1.18.1 + XX + v1.0 + +
+ + + + + 0 + + 71ff52ca-bcea-4fa3-b34e-1b89dcfb0d9e + + 71ff52ca-bcea-4fa3-b34e-1b89dcfb0d9e + + 2b36a78b-b628-416d-bd22-404e68a0cd36 + + + XX-ACTOR01-1234 + + d1079830-8e9a-4731-8fb7-36b9b961eb73 + 1 + true + + + ETSI + ManifestSpecification + TS103707 + + + + + + + + + + + + + ETSI + EmailAddress + + PartyA@example.com + + + true + + + + + + + ETSI + EmailAddress + + PartyB@example.com + + + + + + + + ETSI + EmailAddress + + PartyC@example.com + + + + + 2025-04-04T13:37:37.000000+00:00 + + + + + http://MessagingServiceSchema.example.com/schema/v1.1.1/ + + + + 633523913219 + Foo for the group + + + + + + + + + + + + + + +
diff --git a/104144/dictionaries/ts_104144_DictionaryDefinitions.xml b/104144/dictionaries/ts_104144_DictionaryDefinitions.xml new file mode 100644 index 0000000000000000000000000000000000000000..b9654374d3c88ea054f8ace1cd5bc18eccbb0cb0 --- /dev/null +++ b/104144/dictionaries/ts_104144_DictionaryDefinitions.xml @@ -0,0 +1,346 @@ + + + + + ETSI + EPOCLegalType + + + EPOC + The Authorisation is associated with an EPOC. + + + EPOC-PR + The Authorisation is associated with an EPOC-PR. + + + + + + ETSI + EPOCPriority + + + TenDaysASAP + Indicates that Form 1 Section C specifies that data is required as soon as possible and within ten days (no notification to enforcing authority). + + + TenDaysSubjectToEA + Indicates that Form 1 Section C specifies that data is required at the end of ten days if the Enforcing Authority raises no grounds for refusal, or as soon as possible after the Enforcing Authority has confirmed that it will not raise grounds for refusal. + + + EightHours + Indicates that Form 1 Section C specifies that data is required as soon as possible and within eight hours due to an emergency case. + + + + + + ETSI + EPOCAuthorisationFlag + + + DelayInformingUser + Indicates that Form 1 Section H specifies that the Issuing Authority will delay informing the person whose data are being requested. + + + EnforcingAuthorityNotified + Indicates that Form 1 Section K indicates that the Enforcing Authority has been notified of the EPOC. + + + + + + ETSI + EPOCRequestSubtype + + + UserInformation + Form 1 Section F checkbox labelled "Name, date of birth, postal or geographic address" etc. was checked. + + + RegistrationInformation + Form 1 Section F checkbox labelled "Date and time of initial registration" etc. was checked. + + + TypeOfServiceInformation + Form 1 Section F checkbox labelled "Type of service and its duration" etc. was checked. + + + ProfileInformation + Form 1 Section F checkbox labelled "Profile information" etc. was checked. + + + DataOnValidationOfUse + Form 1 Section F checkbox labelled "Data on the validation of the use of service" etc. was checked. + + + DebitOrCreditCardInformation + Form 1 Section F checkbox labelled "Debit or credit card information" etc. was checked. + + + SubscriberDataOther + Form 1 Section F checkbox labelled "Other" in bullet (a) was checked. If the value provided next to the "other" box can be interpreted as a valid Service Provider supplied RequestSubtype DictionaryEntry, then that DictionaryEntry may be used instead, otherwise the relevant details shall also be provided in the LDTask ManualInformation field. + + + IPConnectionRecords + Form 1 Section F checkbox labelled "IP connection records such as IP addresses" etc. was checked. If any details are provided in the associated free-text field, these shall be included in the LDTask ManualInformation field. + + + IdentfyingUserOther + Form 1 Section F checkbox labelled "Other" in bullet (b) was checked. If the value provided next to the "other" box can be interpreted as a valid Service Provider supplied RequestSubtype DictionaryEntry, then that DictionaryEntry may be used instead, otherwise the relevant details shall also be provided in the LDTask ManualInformation field. + + + OutgoingAndIncomingTrafficData + Form 1 Section F checkbox labelled "Outgoing (A) and incoming (B) identifiers" etc. was checked. + + + TimeAndDurationOfConnections + Form 1 Section F checkbox labelled "Time and duration of connection(s)" was checked. + + + CallAttempts + Form 1 Section F checkbox labelled "Call Attempt(s)" was checked. + + + MobileBaseStationID + Form 1 Section F checkbox labelled "Base station ID, including geographical information" etc. under bullet (c) (i) was checked. + + + BearerUsed + Form 1 Section F checkbox labelled "Bearer / teleservice used (e.g. UMTS, GPRS)" was checked. + + + TrafficDataMobileOther + Form 1 Section F checkbox labelled "Other" in bullet (c) (i) was checked. If the value provided next to the "other" box can be interpreted as a valid Service Provider supplied RequestSubtype DictionaryEntry, then that DictionaryEntry may be used instead, otherwise the relevant details shall also be provided in the LDTask ManualInformation field. + + + RoutingInformation + Form 1 Section F checkbox labelled "Routing information (source IP address" etc. was checked. + + + InternetBaseStationID + Form 1 Section F checkbox labelled "Base station ID, including geographical information" etc. under bullet (c) (ii) was checked. + + + VolumeOfData + Form 1 Section F checkbox labelled "Volume of data" was checked. + + + DateAndTimeOfConnection + Form 1 Section F checkbox labelled "Date and time of connection(s)" was checked. + + + DurationOfConnection + Form 1 Section F checkbox labelled "Duration of connection or access session(s)" was checked. + + + TrafficDataMobileOther + Form 1 Section F checkbox labelled "Other" in bullet (c) (ii) was checked. If the value provided next to the "other" box can be interpreted as a valid Service Provider supplied RequestSubtype DictionaryEntry, then that DictionaryEntry may be used instead, otherwise the relevant details shall also be provided in the LDTask ManualInformation field. + + + Logfiles + Form 1 Section F checkbox labelled "Logfiles" was checked. + + + Tickets + Form 1 Section F checkbox labelled "Tickets" was checked. + + + TrafficDataInternetOther + Form 1 Section F checkbox labelled "Other" in bullet (c) (iii) was checked. If the value provided next to the "other" box can be interpreted as a valid Service Provider supplied RequestSubtype DictionaryEntry, then that DictionaryEntry may be used instead, otherwise the relevant details shall also be provided in the LDTask ManualInformation field. + + + PurchaseHistory + Form 1 Section F checkbox labelled "Purchase History" was checked. + + + PrepaidBalance + Form 1 Section F checkbox labelled "Prepaid balance charging history" was checked. + + + TrafficDataOtherOther + Form 1 Section F checkbox labelled "Other" in bullet (c) (iv) was checked. If the value provided next to the "other" box can be interpreted as a valid Service Provider supplied RequestSubtype DictionaryEntry, then that DictionaryEntry may be used instead, otherwise the relevant details shall also be provided in the LDTask ManualInformation field. + + + MailboxDump + Form 1 Section F checkbox labelled "(web)mailbox dump" was checked. + + + OnlineStorageDump + Form 1 Section F checkbox labelled "Online storage dump" etc. was checked. + + + Pagedump + Form 1 Section F checkbox labelled "Pagedump" was checked. + + + MessageLog + Form 1 Section F checkbox labelled "Message log/backup" was checked. + + + VoicemailDump + Form 1 Section F checkbox labelled "Voicemail dump" was checked. + + + ServerContents + Form 1 Section F checkbox labelled "Server contents" was checked. + + + DeviceBackup + Form 1 Section F checkbox labelled "Device backup" was checked. + + + ContactList + Form 1 Section F checkbox labelled "Contact list" was checked. + + + ContentDataOther + Form 1 Section F checkbox labelled "Other" in bullet (d) was checked. If the value provided next to the "other" box can be interpreted as a valid Service Provider supplied RequestSubtype DictionaryEntry, then that DictionaryEntry may be used instead, otherwise the relevant details shall also be provided in the LDTask ManualInformation field. + + + AdditionalRequestTypeInfo + Form 1 Section F checkbox labelled "Additional information in case necessary to (further) specify or limit the range of the requested data" was checked. Any information present in the associated free text field shall be included in the LDTaskObject ManualInformation field. + + + + + + ETSI + EPOCDeliveryProfile + + + IssuingAuthority + The data shall be transferred to the Issuing Authority. + + + ValidatingAuthority + The data shall be transferred to the Validating Authority. + + + OtherCompetentAuthority + The data shall be transferred to another competent authority. Any details specified in Form 1 Section L shall be placed in the LDTask ManualInformation field. + + + + + + ETSI + EPOCDocumentType + + + NoGroundsForRefusal + The Enforcing Authority has determined that there are no grounds for refusal. + + + PartialGroundsForRefusal + The Enforcing Authority has determined that there are partial grounds for refusal. + + + FullGroundsForRefusal + The Enforcing Authority has determined that there are full grounds for refusal. + + + ProceedingToCourt + The Issuing Authority, disagreeing with the reasons given in Form 3, is upholding the EPOC and intends to proceed to court. + + + Maintain + The Issuing Authority wishes to maintain the initial request upon receipt of Form 3, where reasons for non-execution of the request are explained by the Service Provider, or after discussion with the notified Enforcing Authority. + + + RequestAdditionalInformation + Additional information is requested from the Service Provider. + + + ProvideAdditionalInformation + Additional information is provided to the Service Provider. + + + EnforcingAuthorityAgreesWithObjection + A decision of the Enforcing Authority after receiving an objection from the Service Provider. + + + EnforcingAuthorityDisagreesWithObjection + A decision of the Enforcing Authority after receiving an objection from the Service Provider. + + + EnforcementProceduresInitiated + The Issuing Authority has initiated enforcement procedures to comply with an EPOC or EPOC-PR. + + + EnforcingAuthorityRecognisesOrder + Used to indicate that the Enforcing Authority has decided to recognise an order as part of enforcement procedures and requiring the Service Provider to comply. + + + EnforcingAuthorityDoesNotRecogniseOrder + A decision of the Enforcing Authority not to recognise the order upon the initiation of enforcement procedures by the Issuing Authority. + + + Form1 + The DocumentObject contains a signed EPOC certificate from Annex I of the Regulation [i.1] (Form 1). + + + Form2 + The DocumentObject contains a signed EPOC-PR certificate from Annex II of the Regulation [i.1] (Form 2). + + + Form3 + The DocumentObject contains a signed notice regarding the impossibility of executing an EPOC/EPOC-PR as defined in Annex III of the Regulation [i.1] (Form 3). + + + Form5 + The DocumentObject contains a signed confirmation of issuance of request for production following an EPOC-PR as defined in Annex V of the Regulation [i.1] (Form 5). + + + Form6 + The DocumentObject contains a signed notice of extension of an EPOC-PR as defined in Annex VI of the Regulation [i.1] (Form 6). + + + OtherAttachment + The DocumentObject contains an arbitrary attachment as described in Annex B.3 of the present document. + + + + + + ETSI + EPOCPRPreservationStatus + + + SubsequentProductionRequested + Indicates that a subsequent production request has been issued against the data covered by the LPTaskObject, and as such the data should not be removed until the production request has been completed, regardless of the value of the PreservationExpiration field. + + + + + + ETSI + EPOCDocumentProperties + + + ResponseRequiredBy + A response to the correspondence is required by a specific date/time. + + + + + + ETSI + EPOCNotificationType + + + DeFactoImpossibility + Indicates that the Service Provider has raised an object to the EPOC or EPOC-PR according to the Regulation [i.1] Form 3. + + + DataPreserved + Indicates that the Service Provider has preserved data in accordance with the associated EPOC-PR. + + + ConfirmationOfWithdrawal + Indicates that the Service Provider is confirming the withdrawal of an EPOC. + + + + diff --git a/104144/examples/form1.xml b/104144/examples/form1.xml new file mode 100644 index 0000000000000000000000000000000000000000..73ca1de4e0ad3a79b48b878ffeb9a5afdef7cd71 --- /dev/null +++ b/104144/examples/form1.xml @@ -0,0 +1,239 @@ + + +
+ + DE + RI_API + + + DE + service-provider-1 + + 6a8725e7-4187-4602-b407-14bf2ac73311 + 2025-05-30T14:53:46.428663+01:00 + + V1.20.1 + EU + v1.1.1 + +
+ + + + + 0 + + + 7e84603b-be7b-4cba-af26-8468d177f36a + DE + service-provider-1 + EPOC-FR-DE-2025-05-20-0002-1 + + ETSI + EPOCLegalType + EPOC + + + ETSI + EPOCPriority + TenDaysASAP + + + ETSI + AuthorisationDesiredSatus + SubmittedToCSP + + + + DE + service-provider-1 + + + + IssuingAuthority + IA Approval Reference + + Issuing Authority + PublicProsecutor + + Name of IA official + Role of IA official + issuing_authority@example.org + 33199000000 + 33199000001 + Address of IA + + fr + + + et + + + en + + + + Issuing Authority Point of Contact + Point of Contact + issuing_authority_poc@example.org + 33199000002 + 33199000003 + Point of contact address + + + 2025-05-30T00:00:00+01:00 + true + + + ValidatingAuthority + Validating Authority Reference + + Validating Authority + PublicProsecutor + + Name of Validating Authority + Role of VA official + validating_authority@example.org + 33199000004 + 33199000005 + Address of Validating Authority + + nl + + + et + + + fr + + + + 2025-08-30T00:00:00+01:00 + + + + ETSI + AuthorisationFlag + IsEmergency + + + ETSI + EPOCAuthorisationFlag + DelayInformingUser + + + ETSI + EPOCAuthorisationFlag + EnforcingAuthorityNotified + + + Service Provider 1 + + + + + 1 + + + f966e795-bc92-4bc4-9c6b-96c1b1b8cb1d + DE + service-provider-1 + + 7e84603b-be7b-4cba-af26-8468d177f36a + + DE-service-provider-1-f966e795-bc92-4bc4-9c6b-96c1b1b8cb1d-1 + + ETSI + LDTaskDesiredStatus + AwaitingDisclosure + + + + ETSI + RequestType + SubscriberData + + 2025-05-26T23:03:00+01:00 + 2025-06-27T23:03:00+01:00 + + + + ETSI + InternationalE164 + + 49171392001 + + + + + ETSI + EPOCRequestSubtype + USER_INFORMATION + + + + + + + + DE + service-provider-1 + + + + ETSI + EPOCDeliveryProfile + IssuingAuthority + + + + + + FR + epoc-authority-1 + + + + ETSI + EPOCDeliveryProfile + ValidatingAuthority + + + + + ETSI + EPOCDeliveryProfile + OtherCompetentAuthority + + + + + + + + 2 + + + 46a57ee9-57df-4f8f-8bb0-48aa350f974f + DE + service-provider-1 + + 7e84603b-be7b-4cba-af26-8468d177f36a + + EPOC/EPOC-PR Form + + ETSI + EPOCDocumentType + Form1 + + + RVBPQy9FUE9DLVBSIEZvcm0= + text/plain + + + + + + + +
\ No newline at end of file diff --git a/104144/examples/form2.xml b/104144/examples/form2.xml new file mode 100644 index 0000000000000000000000000000000000000000..e37b05f193df98b6b1466cc6c1e1dc6108877ff9 --- /dev/null +++ b/104144/examples/form2.xml @@ -0,0 +1,186 @@ + + +
+ + XX + RI_API + + + DE + service-provider-1 + + ee14afe1-acec-440b-a9e0-47fdd6db5672 + 2025-05-30T14:54:05.171742+01:00 + + V1.20.1 + EU + v1.1.1 + +
+ + + + + 0 + + + e241c1da-b108-48a4-a31a-04554d7bd3f8 + DE + service-provider-1 + EPOCPR-FR-DE-2025-05-20-0001-1 + + ETSI + EPOCLegalType + EPOCPR + + + ETSI + AuthorisationDesiredSatus + SubmittedToCSP + + + + DE + service-provider-1 + + + + IssuingAuthority + IA Approval Reference + + Issuing Authority + PublicProsecutor + + Name of IA official + Role of IA official + issuing_authority@example.org + 33199000000 + 33199000001 + Address of IA + + fr + + + nl + + + en + + + + Issuing Authority Point of Contact + Point of Contact + issuing_authority_poc@example.org + 33199000002 + 33199000003 + Point of contact address + + + + + ValidatingAuthority + Validating Authority Reference + + Validating Authority + JudgeCourtOrInvestigatingJudge + + Name of Validating Authority + Role of VA official + validating_authority@example.org + 33199000004 + 33199000005 + Address of Validating Authority + + nl + + + en + + + hr + + + + + + + ETSI + AuthorisationFlag + IsEmergency + + + Service Provider authority 1 + + + + + 1 + + + 4f64f242-603b-4998-9916-b8e1b8849aca + DE + service-provider-1 + + e241c1da-b108-48a4-a31a-04554d7bd3f8 + + + ETSI + LDTaskDesiredStatus + AwaitingPreservation + + + + ETSI + RequestType + SubscriberData + + 2025-06-20T23:02:00+01:00 + 2025-06-28T22:58:00+01:00 + + + + ETSI + MACAddress + + 00:00:5e:00:53:00 + + + + + ETSI + EPOCRequestSubtype + USER_INFORMATION + + + + 2025-07-29T14:54:05+01:00 + + + + + 2 + + + 22d5daf0-9e21-4ce6-9021-5b6d23fbd9eb + DE + service-provider-1 + + e241c1da-b108-48a4-a31a-04554d7bd3f8 + + EPOC/EPOC-PR Form + + ETSI + EPOCDocumentType + Form2 + + + RVBPQy9FUE9DLVBSIEZvcm0= + text/plain + + + + + + + +
\ No newline at end of file diff --git a/104144/examples/form3.xml b/104144/examples/form3.xml new file mode 100644 index 0000000000000000000000000000000000000000..f4c0cddbd389e6bc24fe7812a4f22e9d12e9e316 --- /dev/null +++ b/104144/examples/form3.xml @@ -0,0 +1,101 @@ + + +
+ + DE + service-provider-1 + + + XX + RI_API + + 116e67f9-82ad-481e-9b17-e9f007f91434 + 2025-05-30T14:54:24.545502+01:00 + + V1.20.1 + EU + v1.1.1 + +
+ + + + + 0 + + + 6801ad8b-4e86-4237-acaa-611684207af9 + DE + service-provider-1 + + 7e84603b-be7b-4cba-af26-8468d177f36a + + Notification of Form 3 + + ETSI + EPOCNotificationType + DeFactoImpossibility + + true + 2025-05-30T14:54:24+01:00 + + + 7e84603b-be7b-4cba-af26-8468d177f36a + + ETSI + AuthorisationStatus + Invalid + + From Form 3 Section E (as an example of what could be done) +TitleOfLaw: SectionE_1_Form3 +ApplicableStatutoryProvision: SectionE_2_Form3 +WhyLawIsApplicable: SectionE_6_Form3 +WhyConflictOfLawConsidered: SectionE_7_Form3 +LinkBetweenServiceProviderAndThirdCountry: SectionE_8_Form3 +ConsequencesForAddressee: SectionE_9_Form3 +AnyOtherRelevantInformation: SectionE_10_Form3 +From Section F +InformationRequiredFromIssuingAuthority: SectionF_1_Form3 + + + f966e795-bc92-4bc4-9c6b-96c1b1b8cb1d + + ETSI + LPTaskStatus + Invalid + + Reason: INCOMPLETE +Reason: CONTAINS_MANIFEST_ERRORS +ExplanationOrOtherReason:SectionD_1_Form3 + + + + + + + 1 + + + 03e36530-cdf2-4cb8-bfa3-ceff9fd96c59 + DE + service-provider-1 + + 7e84603b-be7b-4cba-af26-8468d177f36a + + EPOC/EPOC-PR Form + + ETSI + EPOCDocumentType + Form3 + + + RVBPQy9FUE9DLVBSIEZvcm0= + text/plain + + + + + + + +
\ No newline at end of file diff --git a/104144/examples/form5.xml b/104144/examples/form5.xml new file mode 100644 index 0000000000000000000000000000000000000000..f0fc81bab6d08072b5c612a2d29276c69b0a0949 --- /dev/null +++ b/104144/examples/form5.xml @@ -0,0 +1,67 @@ + + +
+ + XX + RI_API + + + DE + service-provider-1 + + fb3ad91c-f374-489f-b347-e6ddaf7b22cd + 2025-05-30T14:54:46.417519+01:00 + + V1.20.1 + EU + v1.1.1 + +
+ + + + + 0 + + + 4f64f242-603b-4998-9916-b8e1b8849aca + FR + epoc-authority-1 + + e241c1da-b108-48a4-a31a-04554d7bd3f8 + + + ETSI + LDTaskDesiredStatus + SubsequentProductionRequest + + + + + + 1 + + + a123e20b-b849-4e3f-b23b-9118a137320e + FR + epoc-authority-1 + + e241c1da-b108-48a4-a31a-04554d7bd3f8 + + EPOC/EPOC-PR Form + + ETSI + EPOCDocumentType + Form5 + + + RVBPQy9FUE9DLVBSIEZvcm0= + text/plain + + + + + + + +
\ No newline at end of file diff --git a/104144/examples/form6.xml b/104144/examples/form6.xml new file mode 100644 index 0000000000000000000000000000000000000000..5f8e55a05b5f297b49042094c42a4992d4a5b203 --- /dev/null +++ b/104144/examples/form6.xml @@ -0,0 +1,63 @@ + + +
+ + XX + RI_API + + + DE + service-provider-1 + + e17a6d1f-c91e-49b6-b61d-1ee344be2637 + 2025-05-30T14:55:14.650404+01:00 + + V1.20.1 + EU + v1.1.1 + +
+ + + + + 0 + + + 4f64f242-603b-4998-9916-b8e1b8849aca + FR + epoc-authority-1 + + e241c1da-b108-48a4-a31a-04554d7bd3f8 + + 2025-07-29T14:55:14+01:00 + + + + + 1 + + + 7f09fa28-19de-48a9-beed-cc68b0a8d9a7 + FR + epoc-authority-1 + + e241c1da-b108-48a4-a31a-04554d7bd3f8 + + EPOC/EPOC-PR Form + + ETSI + EPOCDocumentType + Form6 + + + RVBPQy9FUE9DLVBSIEZvcm0= + text/plain + + + + + + + +
\ No newline at end of file diff --git a/104144/schema/xsd/ts_104144_EPOCAdditionalInfo.xsd b/104144/schema/xsd/ts_104144_EPOCAdditionalInfo.xsd new file mode 100644 index 0000000000000000000000000000000000000000..0c671832eb8a39b12d1e0dd9e4ad40509ead7dde --- /dev/null +++ b/104144/schema/xsd/ts_104144_EPOCAdditionalInfo.xsd @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testing/asn/asn_compile_targets.json b/testing/asn/asn_compile_targets.json new file mode 100644 index 0000000000000000000000000000000000000000..f12b657b20ca861ca06c42479109ec09dc8791d0 --- /dev/null +++ b/testing/asn/asn_compile_targets.json @@ -0,0 +1,35 @@ +[ + [ + "./102232-1/LI-PS-PDU.asn", + "./103280/TS_103_280.asn1", + "./testing/deps/33128/TS33128Payloads.asn", + "./testing/deps/33108/Three3gppHI1Notifications.asn", + "./testing/deps/33108/UMTSHI2Operations.asn", + "./testing/deps/33108/UMTSHI3PS.asn", + "./testing/deps/33108/EpsHI3PS.asn", + "./testing/deps/33108/ConfHI3IMS.asn", + "./testing/deps/33108/VoipHI3IMS.asn", + "./testing/deps/33108/GCSEHI3.asn", + "./testing/deps/33108/CSVoiceHI3IP.asn", + "./testing/deps/33108/UMTSCSHI2Operations.asn", + "./testing/deps/33108/EpsHI2Operations.asn", + "./testing/deps/33108/ConfHI2Operations.asn", + "./testing/deps/33108/ProSeHI2Operations.asn", + "./testing/deps/33108/GCSEHI2Operations.asn", + "./testing/deps/101671/HI1NotificationOperations,ver7.asn", + "./testing/deps/101671/HI2Operations,ver18.asn", + "./testing/deps/101909/TS101909201.asn", + "./testing/deps/101909/TS101909202.asn", + "./testing/deps/101909/PCESP.asn", + "./testing/deps/301040/06132v203_C01.asn", + "./103462/ILHIPDU.asn", + "./102232-2/EmailPDU.asn", + "./102232-3/IPAccessPDU.asn", + "./102232-4/L2AccessPDU.asn", + "./102232-5/IPMultimediaPDU.asn", + "./102232-6/PstnIsdnPDU.asn" + ], + [ + "./102657/RDMessage.asn" + ] +] diff --git a/testing/asn_ignore.txt b/testing/asn/asn_ignore.txt similarity index 100% rename from testing/asn_ignore.txt rename to testing/asn/asn_ignore.txt diff --git a/testing/asn_ignore_lint.txt b/testing/asn/asn_ignore_lint.txt similarity index 100% rename from testing/asn_ignore_lint.txt rename to testing/asn/asn_ignore_lint.txt diff --git a/testing/asn_process.py b/testing/asn/asn_process.py similarity index 60% rename from testing/asn_process.py rename to testing/asn/asn_process.py index 5ca7aa5bf880d352c0ef9de3b7a3181fd0c680b5..508569153837abddc43900cd34773396890e0b56 100644 --- a/testing/asn_process.py +++ b/testing/asn/asn_process.py @@ -6,26 +6,32 @@ from shutil import which from pycrate_asn1c.asnproc import * -def reconstrainInteger (filename): - Path('temp.asn').write_text(Path(filename).read_text().replace("18446744073709551615", "65536")) - return 'temp.asn' + +def reconstrainInteger(filename): + Path("temp.asn").write_text( + Path(filename).read_text().replace("18446744073709551615", "65536") + ) + return "temp.asn" + filesWithBigInts = [ - '102232-1/LI-PS-PDU.asn', - '102232-3/IPAccessPDU.asn', - '102232-4/L2AccessPDU.asn' + "102232-1/LI-PS-PDU.asn", + "102232-3/IPAccessPDU.asn", + "102232-4/L2AccessPDU.asn", ] asn1c_path = "" change_path_to_unix = False + def fix_path(path): if change_path_to_unix: - return "./" + path.replace("\\","/") + return "./" + path.replace("\\", "/") else: return path -def syntaxCheckASN (fileList): + +def syntaxCheckASN(fileList): """ Performs ASN syntax checking on a list of filenames (or pathlib Paths) @@ -40,56 +46,48 @@ def syntaxCheckASN (fileList): try: if file.as_posix() in filesWithBigInts: newFile = reconstrainInteger(str(file)) - p = run([asn1c_path, '-E', fix_path(newFile)], capture_output=True) + p = run([asn1c_path, "-E", fix_path(newFile)], capture_output=True) Path(newFile).unlink() else: - p = run([asn1c_path, '-E', fix_path(str(file))], capture_output=True) - if (p.returncode != 0): + p = run([asn1c_path, "-E", fix_path(str(file))], capture_output=True) + if p.returncode != 0: errorMessage = p.stderr.decode().splitlines()[0] if errorMessage.startswith(' Value "18446744073709551615" at line'): - results[str(file)] = { 'ok' : True} + results[str(file)] = {"ok": True} continue results[str(file)] = { - 'ok' : False, - 'code' : p.returncode, - 'message' : p.stderr.decode().splitlines()[0] + "ok": False, + "code": p.returncode, + "message": p.stderr.decode().splitlines()[0], } else: - results[str(file)] = { - 'ok' : True - } + results[str(file)] = {"ok": True} except Exception as ex: raise ex - results[str(file)] = { - 'ok' : False, - 'code' : -1, - 'message' : f"{ex!r}" - } + results[str(file)] = {"ok": False, "code": -1, "message": f"{ex!r}"} return results duplicateObjects = { - '102232-1/LI-PS-PDU.asn' : [ - 'CCPayload', - 'IRIPayload', - 'Location' - ], - 'testing/mod1.asn' : [ - 'ClashField' - ] + "102232-1/LI-PS-PDU.asn": ["CCPayload", "IRIPayload", "Location"], + "testing/mod1.asn": ["ClashField"], } + + def fixDuplicateObjects(filename): stringContent = filename.read_text() for object in duplicateObjects[filename.as_posix()]: - stringContent = stringContent.replace(f'{object} ::=', f'Native{object} ::=', 1) - stringContent = stringContent.replace(f'SEQUENCE OF {object}', f'SEQUENCE OF Native{object}') - #stringContent = sub(f"]\\w{object}", f"] Native{object}", stringContent) + stringContent = stringContent.replace(f"{object} ::=", f"Native{object} ::=", 1) + stringContent = stringContent.replace( + f"SEQUENCE OF {object}", f"SEQUENCE OF Native{object}" + ) + # stringContent = sub(f"]\\w{object}", f"] Native{object}", stringContent) - Path('temp.asn').write_text(stringContent) - return 'temp.asn' + Path("temp.asn").write_text(stringContent) + return "temp.asn" -def compileAllTargets (compileTargets): +def compileAllTargets(compileTargets): """ Attempts to compile a set of compile targets using the pycrate ASN1 tools @@ -100,10 +98,10 @@ def compileAllTargets (compileTargets): to be the "primary" file. This doesn't have any relavance to the compilation, but will be used as the identifier when reporting any compile errors. The compilation is performed by the pycrate ASN compile functions; errors - are caught as exceptions and rendered into a list. - + are caught as exceptions and rendered into a list. + Unfortunately, the pycrate compiler doesn't report line numbers. - The asn1c compiler does, but doesn't properly handle identifiers with the + The asn1c compiler does, but doesn't properly handle identifiers with the same name in different modules; as this occurs multiple times in TS 33.108, we can't use it. """ @@ -120,107 +118,105 @@ def compileAllTargets (compileTargets): if pFile.as_posix() in duplicateObjects: tmpFile = Path(fixDuplicateObjects(pFile)) fileTexts.append(tmpFile.read_text()) - #tmpFile.unlink() + # tmpFile.unlink() else: fileTexts.append(pFile.read_text()) fileNames.append(filename) - logging.debug (f" Loading {filename}") - compile_text(fileTexts, filenames = fileNames) + logging.debug(f" Loading {filename}") + compile_text(fileTexts, filenames=fileNames) results[str(firstTarget)] = { - 'ok' : True, + "ok": True, } except Exception as ex: - results[str(firstTarget)] = { - 'ok' : False, - 'code' : -1, - 'message' : f"{ex!r}" - } + results[str(firstTarget)] = {"ok": False, "code": -1, "message": f"{ex!r}"} continue return results - -def processResults (results, stageName): +def processResults(results, stageName): """ Counts the number of errors and writes out the output per filename :param results: List of filenames (str or Pathlib Path) :param stageName: Name to decorate the output with :returns: The number of files which had errors - """ + """ print("") - errorCount = sum([1 for r in results.values() if not r['ok']]) + errorCount = sum([1 for r in results.values() if not r["ok"]]) logging.info(f"{errorCount} {stageName} errors encountered") - + print(f"{'-':-<60}") print(f"{stageName} results:") print(f"{'-':-<60}") for filename, result in results.items(): print(f" {filename:.<55}{'..OK' if result['ok'] else 'FAIL'}") - if not result['ok']: - if isinstance(result['message'], list): - for thing in result['message']: + if not result["ok"]: + if isinstance(result["message"], list): + for thing in result["message"]: print(f" {thing['message']}") else: print(f" {result['message']}") - + print(f"{'-':-<60}") print(f"{stageName} errors: {errorCount}") print(f"{'-':-<60}") - + return errorCount -if __name__ == '__main__': - logging.info ('Searching for ASN1C') +if __name__ == "__main__": + logging.info("Searching for ASN1C") asn1c_path = which("asn1c") if asn1c_path is None: - raise Exception ("No asn1c executable found. Please install asn1c") - logging.info (f"asn1c found at {asn1c_path}") + raise Exception("No asn1c executable found. Please install asn1c") + logging.info(f"asn1c found at {asn1c_path}") if asn1c_path.lower().endswith("bat"): - logging.info (f"asn1c is a batch file, so assume path separators need to be changed") + logging.info( + f"asn1c is a batch file, so assume path separators need to be changed" + ) change_path_to_unix = True - - logging.info('Searching for ASN.1 files') + logging.info("Searching for ASN.1 files") fileList = list(Path(".").rglob("*.asn1")) + list(Path(".").rglob("*.asn")) - logging.info(f'{len(fileList)} ASN.1 files found') + logging.info(f"{len(fileList)} ASN.1 files found") for file in fileList: - logging.debug(f' {file}') - - ignoreList = Path('testing/asn_ignore.txt').read_text().splitlines() + logging.debug(f" {file}") + + ignoreList = Path("testing/asn/asn_ignore.txt").read_text().splitlines() ignoredFiles = [] for ignore in ignoreList: - logging.debug(f'Ignoring pattern {ignore}') + logging.debug(f"Ignoring pattern {ignore}") for file in fileList: if ignore in str(file): ignoredFiles.append(file) logging.debug(f" Ignoring {str(file)} as contains {ignore}") ignoredFiles = list(set(ignoredFiles)) - logging.info(f'{len(ignoredFiles)} files ignored') + logging.info(f"{len(ignoredFiles)} files ignored") for file in ignoredFiles: - logging.debug(f' {file}') - + logging.debug(f" {file}") + fileList = [file for file in fileList if file not in ignoredFiles] - logging.info(f'{len(fileList)} files to process') + logging.info(f"{len(fileList)} files to process") for file in fileList: - logging.debug(f' {file}') + logging.debug(f" {file}") if len(fileList) == 0: - logging.warning ("No files specified") + logging.warning("No files specified") exit(0) - + logging.info("Parsing ASN1 files") parseResults = syntaxCheckASN(fileList) if processResults(parseResults, "Parsing") > 0: exit(-1) - logging.info ("Getting compile targets") - compileTargets = json.loads(Path('testing/asn_compile_targets.json').read_text()) - logging.info (f"{len(compileTargets)} compile targets found") + logging.info("Getting compile targets") + compileTargets = json.loads( + Path("testing/asn/asn_compile_targets.json").read_text() + ) + logging.info(f"{len(compileTargets)} compile targets found") compileResults = compileAllTargets(compileTargets) if processResults(compileResults, "Compiling") > 0: exit(-1) - + exit(0) diff --git a/testing/asn_compile_targets.json b/testing/asn_compile_targets.json deleted file mode 100644 index e186addc0214f2ecf1f25f507336f33725fafe2f..0000000000000000000000000000000000000000 --- a/testing/asn_compile_targets.json +++ /dev/null @@ -1,33 +0,0 @@ -[ - [ - "./102232-1/LI-PS-PDU.asn", - "./103280/TS_103_280.asn1", - "./testing/deps/33128/TS33128Payloads.asn", - "./testing/deps/33108/Three3gppHI1Notifications.asn", - "./testing/deps/33108/UMTSHI2Operations.asn", - "./testing/deps/33108/UMTSHI3PS.asn", - "./testing/deps/33108/EpsHI3PS.asn", - "./testing/deps/33108/ConfHI3IMS.asn", - "./testing/deps/33108/VoipHI3IMS.asn", - "./testing/deps/33108/GCSEHI3.asn", - "./testing/deps/33108/CSVoiceHI3IP.asn", - "./testing/deps/33108/UMTSCSHI2Operations.asn", - "./testing/deps/33108/EpsHI2Operations.asn", - "./testing/deps/33108/ConfHI2Operations.asn", - "./testing/deps/33108/ProSeHI2Operations.asn", - "./testing/deps/33108/GCSEHI2Operations.asn", - "./testing/deps/101671/HI1NotificationOperations,ver7.asn", - "./testing/deps/101671/HI2Operations,ver18.asn", - "./testing/deps/101909/TS101909201.asn", - "./testing/deps/101909/TS101909202.asn", - "./testing/deps/101909/PCESP.asn", - "./testing/deps/301040/06132v203_C01.asn", - "./103462/ILHIPDU.asn", - "./102232-2/EmailPDU.asn", - "./102232-3/IPAccessPDU.asn", - "./102232-4/L2AccessPDU.asn", - "./102232-5/IPMultimediaPDU.asn", - "./102232-6/PstnIsdnPDU.asn" - ], - ["./102657/RDMessage.asn"] -] \ No newline at end of file diff --git a/testing/deps/.editorconfig b/testing/deps/.editorconfig new file mode 100644 index 0000000000000000000000000000000000000000..b9936750f79f5c2d6018db76720a6f84b3add978 --- /dev/null +++ b/testing/deps/.editorconfig @@ -0,0 +1,4 @@ +[**.*] +indent_style = unset +indent_size = unset +trim_trailing_whitespace = unset \ No newline at end of file diff --git a/testing/deps/old_400/TS_104_000.xsd b/testing/deps/old_400/TS_104_000.xsd new file mode 100644 index 0000000000000000000000000000000000000000..3364ef5d3b2e299b7467bc00482973ef119c9819 --- /dev/null +++ b/testing/deps/old_400/TS_104_000.xsd @@ -0,0 +1,279 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/testing/dockerfile_asn b/testing/dockerfiles/dockerfile_asn similarity index 100% rename from testing/dockerfile_asn rename to testing/dockerfiles/dockerfile_asn diff --git a/testing/dockerfile_xsd b/testing/dockerfiles/dockerfile_xsd similarity index 100% rename from testing/dockerfile_xsd rename to testing/dockerfiles/dockerfile_xsd diff --git a/testing/dockerfiles/forgeschema b/testing/dockerfiles/forgeschema new file mode 100644 index 0000000000000000000000000000000000000000..d3f9249d2036ee5ba12133410439df7b50ccc3e0 --- /dev/null +++ b/testing/dockerfiles/forgeschema @@ -0,0 +1,19 @@ +# docker login forge.etsi.org:5050 +# docker build -t forge.etsi.org:5050/li/schemas-definitions/forgeschema -f forgeschema . +# docker push forge.etsi.org:5050/li/schemas-definitions/forgeschema + +FROM python:3.12-alpine + +RUN apk add --no-cache \ + jq \ + libxml2-utils \ + libffi-dev \ + openssl-dev \ + gcc \ + musl-dev \ + python3-dev \ + build-base \ + editorconfig + +RUN pip install --upgrade pip && \ + pip install forgeschema \ No newline at end of file diff --git a/testing/json/lint_json.py b/testing/json/lint_json.py new file mode 100644 index 0000000000000000000000000000000000000000..783d53bf20770f3c86f6e270ff50f8c4f507cef5 --- /dev/null +++ b/testing/json/lint_json.py @@ -0,0 +1,81 @@ +from pathlib import Path +from difflib import * +import subprocess + +import colorama +from colorama import Fore, Style + +colorama.init() + +ignore_paths = [Path(x) for x in ["testing/deps"]] + + +def print_colorized_diff_line(line: str): + if line.startswith("-"): + print(f"{Fore.RED}{line}{Style.RESET_ALL}") + elif line.startswith("+"): + print(f"{Fore.GREEN}{line}{Style.RESET_ALL}") + else: + print(line) + + +def lint(file: Path): + completed = subprocess.run( + ["jq", ".", str(file)], capture_output=True, text=True, encoding="utf8" + ) + + if completed.returncode != 0: + print(f" {str(f)}: FAIL") + print(f" jq error code {completed.returncode}") + lines = completed.stderr.splitlines() + for line in lines: + print(f" {line}") + return len(lines) + + linted_xml = completed.stdout + orig_xml = file.read_text(encoding="utf8") + diff = list(unified_diff(orig_xml.splitlines(), linted_xml.splitlines())) + if len(diff) == 0: + print(f"✅ {str(f)}") + return 0 + else: + print(f"❌ {str(f)}: {len(diff)} linting errors") + # for d in diff: + # print("".join(d)) + for d in diff: + print_colorized_diff_line(d) + return len(diff) + + +if __name__ == "__main__": + root = Path("./") + files = list(root.rglob("*.json")) + + files_with_errors = 0 + errors = 0 + + print("───────────────────────────────────────────────────────────────────") + print(f"Linting JSON files...") + + for f in files: + if len(list(set(f.parents) & set(ignore_paths))) > 0: + print(f"(Ignoring {f})") + continue + new_errors = lint(f) + errors += new_errors + files_with_errors += 1 if new_errors > 0 else 0 + + print("───────────────────────────────────────────────────────────────────") + print( + f"Files: {len(files)} ({files_with_errors} with errors) Total errors: {errors}" + ) + if files_with_errors == 0: + print("✅ OK") + else: + print("❌ Fail") + print("───────────────────────────────────────────────────────────────────") + + if files_with_errors > 0: + exit(-1) + else: + exit(0) diff --git a/testing/json/ts_103120._json.json b/testing/json/ts_103120._json.json new file mode 100644 index 0000000000000000000000000000000000000000..bdf4c3985189a9d88f2d2236f06ae0459ee1f2c9 --- /dev/null +++ b/testing/json/ts_103120._json.json @@ -0,0 +1,11 @@ +{ + "coreSchema": "103120/schema/json/ts_103120_Core.schema.json", + "supportingSchemas": [ + "103120/schema/json", + "103120/dictionaries/ts_103120_Dictionaries.schema.json", + "103280/TS_103_280.schema.json" + ], + "instanceDocs": [ + "103120/examples/json" + ] +} diff --git a/testing/json/ts_103280._json.json b/testing/json/ts_103280._json.json new file mode 100644 index 0000000000000000000000000000000000000000..a00d98e54912980b9fe1b21bd45742d167e1b120 --- /dev/null +++ b/testing/json/ts_103280._json.json @@ -0,0 +1,5 @@ +{ + "coreSchema": "103120/dictionaries/ts_103120_Dictionaries.schema.json", + "supportingSchemas": [], + "instanceDocs": [] +} diff --git a/testing/json/ts_103705_ex1_json.json b/testing/json/ts_103705_ex1_json.json new file mode 100644 index 0000000000000000000000000000000000000000..c9ad6211f8bb0d528aef9c3dbb394a95453798cc --- /dev/null +++ b/testing/json/ts_103705_ex1_json.json @@ -0,0 +1,11 @@ +{ + "coreSchema": "103705/schema/response.schema.json", + "supportingSchemas": [ + "103705/schema/", + "103280/TS_103_280.schema.json", + "103705/examples/example1/csp_records.schema.json" + ], + "instanceDocs": [ + "103705/examples/example1/csp_results.json" + ] +} diff --git a/testing/json/ts_103976_json.json b/testing/json/ts_103976_json.json new file mode 100644 index 0000000000000000000000000000000000000000..3d12b02bd2f09effb15e97ed881faca12b9618ad --- /dev/null +++ b/testing/json/ts_103976_json.json @@ -0,0 +1,10 @@ +{ + "coreSchema": "103976/ts_103976.schema.json", + "supportingSchemas": [ + "103280/TS_103_280.schema.json", + "103120/schema/json/ts_103120_Common.schema.json" + ], + "instanceDocs": [ + "103976/examples/" + ] +} diff --git a/testing/merge_test.py b/testing/merge_test.py deleted file mode 100644 index b7a82b39c4958ea30d4ac9a96e100e3041fe73c0..0000000000000000000000000000000000000000 --- a/testing/merge_test.py +++ /dev/null @@ -1,68 +0,0 @@ -import os -import pprint -import requests -import json -import subprocess - -crCommitBranch = os.environ.get("CI_COMMIT_REF_NAME", "NOTFOUND") -apiUrl = os.environ.get("CI_API_V4_URL", "https://forge.3gpp.org/rep/api/v4") -projectId = os.environ.get("CI_PROJECT_ID", "13") - -def gapi (query): - url = f"{apiUrl}/projects/{projectId}/{query}" - r = requests.get(url) - return json.loads(r.text) - -def do (commandline): - #print (" Attempting: " + commandline) - completedProc = subprocess.run(commandline, capture_output=True, shell=True) - #print (" STDOUT > " + ("empty" if completedProc.stdout is None else completedProc.stdout.decode('utf-8'))) - #print (" STDERR > " + ("empty" if completedProc.stderr is None else completedProc.stderr.decode('utf-8'))) - #print (f" Completed with code {completedProc.returncode}") - return (completedProc.returncode == 0, completedProc.stdout.decode('utf-8')) - -print ("Searching for corresponding MR...") - -mrs = gapi(f"merge_requests?source_branch={crCommitBranch}&state=opened") -if len(mrs) == 0: - print ("No MR found... aborting") - exit() - -if len(mrs) > 1: - print (f"{len(mrs)} MRs found, 1 expected - aborting") - for m in mrs: - pprint.pprint(m) - exit(-1) - -mr = mrs[0] - -print (f"Found MR {mr['reference']} ({mr['title']})") -print (f"Target branch is {mr['target_branch']}") -print ("Searching for open MRs targeting same branch...") - -mrs = gapi(f"merge_requests?target_branch={mr['target_branch']}&state=opened") -mrs = [m for m in mrs if m['reference'] != mr['reference']] -print (f"{len(mrs)} MRs found") - -mergeConflicts = {} - -for mr in mrs: - source_branch = mr['source_branch'] - print (source_branch) - - try: - do(f"git fetch origin {source_branch}:{source_branch}") - success, errStr = do(f"git merge --no-commit {source_branch}") - if not success: - print ("Merge NOT OK") - mergeConflicts[source_branch] = errStr - else: - print ("Merge OK") - except Exception as ex: - mergeConflicts[source_branch] = str(ex) - raise - finally: - do("git merge --abort") - -print (f"Merge conflicts with following branches: {mergeConflicts}") -exit(len(mergeConflicts.keys())) \ No newline at end of file diff --git a/testing/xml/etsi_dictionaries.json b/testing/xml/etsi_dictionaries.json new file mode 100644 index 0000000000000000000000000000000000000000..d693f9e377d5906cb7ae46d72a8338f1b7c1c2d5 --- /dev/null +++ b/testing/xml/etsi_dictionaries.json @@ -0,0 +1,9 @@ +{ + "coreSchema": "103120/dictionaries/ts_103120_Dictionaries.xsd", + "supportingSchemas": [], + "instanceDocs": [ + "103120/dictionaries/ts_103120_ETSIDictionaryDefinitions.xml", + "104144/dictionaries/", + "103976/ts_103976_ETSIDictionaryDefinitions.xml" + ] +} diff --git a/testing/xml/lint_xml.py b/testing/xml/lint_xml.py new file mode 100644 index 0000000000000000000000000000000000000000..85365e36131fa1a1a492b1fdc5ea0eedc949613c --- /dev/null +++ b/testing/xml/lint_xml.py @@ -0,0 +1,79 @@ +from pathlib import Path +from difflib import * +import subprocess + +import colorama +from colorama import Fore, Style + +colorama.init() + +ignore_paths = [Path(x) for x in ["testing/deps"]] + + +def print_colorized_diff_line(line: str): + if line.startswith("-"): + print(f"{Fore.RED}{line}{Style.RESET_ALL}") + elif line.startswith("+"): + print(f"{Fore.GREEN}{line}{Style.RESET_ALL}") + else: + print(line) + + +def lint(file: Path): + completed = subprocess.run( + ["xmllint", str(file)], capture_output=True, text=True, encoding="utf8" + ) + + if completed.returncode != 0: + print(f" {str(f)}: FAIL") + print(f" xmlint error code {completed.returncode}") + lines = completed.stderr.splitlines() + for line in lines: + print(f" {line}") + return len(lines) + + linted_xml = completed.stdout + orig_xml = file.read_text(encoding="utf8") + diff = list(unified_diff(orig_xml.splitlines(), linted_xml.splitlines())) + if len(diff) == 0: + print(f"✅ {str(f)}") + return 0 + else: + print(f"❌ {str(f)}: {len(diff)} linting errors") + for d in diff: + print("".join(d)) + return len(diff) + + +if __name__ == "__main__": + root = Path("./") + files = list(root.rglob("*.xml")) + list(root.rglob("*.xsd")) + + files_with_errors = 0 + errors = 0 + + print("") + print(f"Linting XML / XSD files...") + + for f in files: + if len(list(set(f.parents) & set(ignore_paths))) > 0: + print(f"(Ignoring {f})") + continue + new_errors = lint(f) + errors += new_errors + files_with_errors += 1 if new_errors > 0 else 0 + + print("───────────────────────────────────────────────────────────────────") + print( + f"Files: {len(files)} ({files_with_errors} with errors) Total errors: {errors}" + ) + if files_with_errors == 0: + print("✅ OK") + else: + print("❌ Fail") + print("───────────────────────────────────────────────────────────────────") + + if files_with_errors > 0: + exit(-1) + else: + exit(0) diff --git a/testing/xml/ts_102657_xsd.json b/testing/xml/ts_102657_xsd.json new file mode 100644 index 0000000000000000000000000000000000000000..2201b45dfb9623a1bbe0f868d8eb372d88a7feeb --- /dev/null +++ b/testing/xml/ts_102657_xsd.json @@ -0,0 +1,5 @@ +{ + "coreSchema": "102657/RDMessage.xsd", + "supportingSchemas": [], + "instanceDocs": [] +} diff --git a/testing/xml/ts_103120_xsd.json b/testing/xml/ts_103120_xsd.json new file mode 100644 index 0000000000000000000000000000000000000000..822b65df217a1d8efb42fa58d05c49f953bd184b --- /dev/null +++ b/testing/xml/ts_103120_xsd.json @@ -0,0 +1,20 @@ +{ + "coreSchema": "103120/schema/xsd/ts_103120_Core.xsd", + "supportingSchemas": [ + "103120/schema/xsd/ts_103120_Authorisation.xsd", + "103120/schema/xsd/ts_103120_Common.xsd", + "103120/schema/xsd/ts_103120_Config.xsd", + "103120/schema/xsd/ts_103120_Delivery.xsd", + "103120/dictionaries/ts_103120_Dictionaries.xsd", + "103120/schema/xsd/ts_103120_Document.xsd", + "103120/schema/xsd/ts_103120_Notification.xsd", + "103120/schema/xsd/ts_103120_Task.xsd", + "103120/schema/xsd/ts_103120_TrafficPolicy.xsd", + "103280/TS_103_280.xsd", + "testing/deps/xmldsig/xmldsig-core-schema.xsd", + "103120/examples/xml/FooServiceSchema.xsd" + ], + "instanceDocs": [ + "103120/examples/xml" + ] +} diff --git a/testing/xml/ts_103221-1_xsd.json b/testing/xml/ts_103221-1_xsd.json new file mode 100644 index 0000000000000000000000000000000000000000..37409a36f98e3507f3e2d30d43c00f777d48dc67 --- /dev/null +++ b/testing/xml/ts_103221-1_xsd.json @@ -0,0 +1,22 @@ +{ + "coreSchema": "103221-1/TS_103_221_01.xsd", + "supportingSchemas": [ + "103221-1/TS_103_221_01.xsd", + "103221-1/TS_103_221_01_HashedID.xsd", + "103221-1/TS_103_221_01_Configuration.xsd", + "103221-1/TS_103_221_01_DestinationSet.xsd", + "103221-1/TS_103_221_01_TrafficPolicy.xsd", + "103280/TS_103_280.xsd", + "103221-1/examples/ExampleGenericObjects.xsd", + "103120/schema/xsd/ts_103120_Common.xsd", + "103120/schema/xsd/ts_103120_Config.xsd", + "103120/schema/xsd/ts_103120_Core.xsd", + "103120/dictionaries/ts_103120_Dictionaries.xsd", + "103120/schema/xsd/ts_103120_TrafficPolicy.xsd", + "testing/deps/xmldsig/xmldsig-core-schema.xsd", + "testing/deps/old_400/TS_104_000.xsd" + ], + "instanceDocs": [ + "103221-1/examples" + ] +} diff --git a/testing/xml/ts_103280_xsd.json b/testing/xml/ts_103280_xsd.json new file mode 100644 index 0000000000000000000000000000000000000000..3468dba20f1b1a54c08d3f34e8daedffe9278bdd --- /dev/null +++ b/testing/xml/ts_103280_xsd.json @@ -0,0 +1,5 @@ +{ + "coreSchema": "103280/TS_103_280.xsd", + "supportingSchemas": [], + "instanceDocs": [] +} diff --git a/testing/xml/ts_103707_xsd.json b/testing/xml/ts_103707_xsd.json new file mode 100644 index 0000000000000000000000000000000000000000..7cb681373c67f70b8288edee97d7a0053e319b5e --- /dev/null +++ b/testing/xml/ts_103707_xsd.json @@ -0,0 +1,19 @@ +{ + "coreSchema": "103707/TS_103_707.xsd", + "supportingSchemas": [ + "103280/TS_103_280.xsd", + "103120/schema/xsd/ts_103120_Common.xsd", + "103120/schema/xsd/ts_103120_Core.xsd", + "103120/schema/xsd/ts_103120_Config.xsd", + "103120/schema/xsd/ts_103120_Delivery.xsd", + "103120/dictionaries/ts_103120_Dictionaries.xsd", + "103120/schema/xsd/ts_103120_Task.xsd", + "testing/deps/xmldsig/xmldsig-core-schema.xsd", + "103707/examples/FooServiceSchema.xsd", + "104112/examples/xml/MessagingServiceSchema.xsd" + ], + "instanceDocs": [ + "103707/examples", + "104112/examples" + ] +} diff --git a/testing/xml/ts_104000_xsd.json b/testing/xml/ts_104000_xsd.json new file mode 100644 index 0000000000000000000000000000000000000000..b23e93d15571bf8a487cdb38c1842033a1dba4ee --- /dev/null +++ b/testing/xml/ts_104000_xsd.json @@ -0,0 +1,9 @@ +{ + "coreSchema": "104000/schema/TS_104_000.xsd", + "supportingSchemas": [ + "103280/TS_103_280.xsd" + ], + "instanceDocs": [ + "104000/examples/" + ] +} diff --git a/testing/xml/ts_104144_xsd.json b/testing/xml/ts_104144_xsd.json new file mode 100644 index 0000000000000000000000000000000000000000..2ae1b3056564b5a3f6e74c2bd0ac27bb062bd0f9 --- /dev/null +++ b/testing/xml/ts_104144_xsd.json @@ -0,0 +1,20 @@ +{ + "coreSchema": "103120/schema/xsd/ts_103120_Core.xsd", + "supportingSchemas": [ + "103120/schema/xsd/ts_103120_Authorisation.xsd", + "103120/schema/xsd/ts_103120_Common.xsd", + "103120/schema/xsd/ts_103120_Config.xsd", + "103120/schema/xsd/ts_103120_Delivery.xsd", + "103120/dictionaries/ts_103120_Dictionaries.xsd", + "103120/schema/xsd/ts_103120_Document.xsd", + "103120/schema/xsd/ts_103120_Notification.xsd", + "103120/schema/xsd/ts_103120_Task.xsd", + "103120/schema/xsd/ts_103120_TrafficPolicy.xsd", + "103280/TS_103_280.xsd", + "testing/deps/xmldsig/xmldsig-core-schema.xsd", + "103120/examples/xml/FooServiceSchema.xsd" + ], + "instanceDocs": [ + "104144/examples/" + ] +} diff --git a/testing/xsd_compile_targets.json b/testing/xsd_compile_targets.json deleted file mode 100644 index ee06c63e650bb14196ba4abaf97a599133d6f5a9..0000000000000000000000000000000000000000 --- a/testing/xsd_compile_targets.json +++ /dev/null @@ -1,93 +0,0 @@ -[ - { - "coreSchema" : "102657/RDMessage.xsd", - "supportingSchemas" : [], - "exampleFiles" : [] - }, - { - "coreSchema" : "104000/schema/TS_104_000.xsd", - "supportingSchemas" : [ - "103280/TS_103_280.xsd" - ], - "exampleFiles" : [] - }, - { - "coreSchema" : "103280/TS_103_280.xsd", - "supportingSchemas" : [], - "exampleFiles" : [] - }, - { - "coreSchema" : "103221-1/TS_103_221_01.xsd", - "supportingSchemas" : [ - "103221-1/TS_103_221_01.xsd", - "103221-1/TS_103_221_01_HashedID.xsd", - "103221-1/TS_103_221_01_Configuration.xsd", - "103221-1/TS_103_221_01_DestinationSet.xsd", - "103221-1/TS_103_221_01_TrafficPolicy.xsd", - "103280/TS_103_280.xsd", - "104000/schema/TS_104_000.xsd", - "103221-1/examples/ExampleGenericObjects.xsd", - "103120/schema/xsd/ts_103120_Common.xsd", - "103120/schema/xsd/ts_103120_Config.xsd", - "103120/schema/xsd/ts_103120_Core.xsd", - "103120/dictionaries/ts_103120_Dictionaries.xsd", - "103120/schema/xsd/ts_103120_TrafficPolicy.xsd", - "testing/deps/xmldsig/xmldsig-core-schema.xsd" - ], - "exampleFiles" : [ - "103221-1/examples" - ] - }, - { - "coreSchema" : "103120/dictionaries/ts_103120_Dictionaries.xsd", - "supportingSchemas" : [], - "exampleFiles" : [ - "103120/dictionaries/ts_103120_ETSIDictionaryDefinitions.xml" - ] - }, - { - "coreSchema" : "103120/schema/xsd/ts_103120_Core.xsd", - "supportingSchemas" : [ - "103120/schema/xsd/ts_103120_Authorisation.xsd", - "103120/schema/xsd/ts_103120_Common.xsd", - "103120/schema/xsd/ts_103120_Config.xsd", - "103120/schema/xsd/ts_103120_Delivery.xsd", - "103120/dictionaries/ts_103120_Dictionaries.xsd", - "103120/schema/xsd/ts_103120_Document.xsd", - "103120/schema/xsd/ts_103120_Notification.xsd", - "103120/schema/xsd/ts_103120_Task.xsd", - "103120/schema/xsd/ts_103120_TrafficPolicy.xsd", - "103280/TS_103_280.xsd", - "testing/deps/xmldsig/xmldsig-core-schema.xsd", - "103120/examples/xml/FooServiceSchema.xsd" - ], - "exampleFiles" : [ - "103120/examples/xml" - ] - }, - { - "coreSchema" : "103707/TS_103_707.xsd", - "supportingSchemas" : [ - "103280/TS_103_280.xsd", - "103120/schema/xsd/ts_103120_Common.xsd", - "103120/schema/xsd/ts_103120_Core.xsd", - "103120/schema/xsd/ts_103120_Config.xsd", - "103120/dictionaries/ts_103120_Dictionaries.xsd", - "103120/schema/xsd/ts_103120_Task.xsd", - "testing/deps/xmldsig/xmldsig-core-schema.xsd", - "103707/examples/FooServiceSchema.xsd" - ], - "exampleFiles" : [ - "103707/examples" - ] - }, - { - "coreSchema" : "104000/schema/TS_104_000.xsd", - "supportingSchemas" : [ - "103280/TS_103_280.xsd" - ], - "exampleFiles" : [ - "104000/examples" - ] - } -] diff --git a/testing/xsd_ignore.txt b/testing/xsd_ignore.txt deleted file mode 100644 index 90bfe5d59c3b61099ed6685d7ddd6023be91efe5..0000000000000000000000000000000000000000 --- a/testing/xsd_ignore.txt +++ /dev/null @@ -1,3 +0,0 @@ -deps -portal -temp \ No newline at end of file diff --git a/testing/xsd_process.py b/testing/xsd_process.py deleted file mode 100644 index 97dc2a883dd1f344811754a79ebfb328d829aa66..0000000000000000000000000000000000000000 --- a/testing/xsd_process.py +++ /dev/null @@ -1,222 +0,0 @@ -import json -import logging -from pathlib import Path - -from xmlschema import etree_tostring -from xmlschema import XMLSchema, XMLSchemaParseError - - -def BuildSchemaDictonary (fileList): - if len(fileList) == 0: - logging.info("No schema files provided") - return [] - - logging.info("Schema locations:") - schemaLocations = [] - for schemaFile in fileList: - try: - xs = XMLSchema(schemaFile, validation='skip') - schemaLocations.append((xs.default_namespace, str(Path(schemaFile).resolve()))) - logging.info(" [ {0} -> {1} ]".format(xs.default_namespace, schemaFile)) - except XMLSchemaParseError as ex: - logging.warning (" [ {0} failed to parse: {1} ]".format(schemaFile, ex)) - return schemaLocations - - -def BuildSchema (coreFile, fileList = None): - schemaLocations = [] - if fileList and len(fileList) > 0: - schemaLocations = BuildSchemaDictonary(fileList) - - coreSchema = XMLSchema(str(Path(coreFile)), locations=schemaLocations) - return coreSchema - - -def ValidateXSDFiles (fileList): - if len(fileList) == 0: - logging.info("No schema files provided") - return {} - - schemaLocations = BuildSchemaDictonary(fileList) - errors = {} - - logging.info("Schema validation:") - for schemaFile in fileList: - try: - schema = XMLSchema(schemaFile, locations = schemaLocations, validation="lax") - logging.info(schemaFile + ": OK") - errors[schemaFile] = [f"{etree_tostring(e.elem, e.namespaces, ' ', 20)} - {e.message}" for e in schema.all_errors] - except XMLSchemaParseError as ex: - logging.warning(schemaFile + ": Failed validation ({0})".format(ex.message)) - if (ex.schema_url) and (ex.schema_url != ex.origin_url): - logging.warning(" Error comes from {0}, suppressing".format(ex.schema_url)) - errors[schemaFile] = [] - else: - errors[schemaFile] = [ex] - return errors - - -def ValidateAllXSDFilesInPath (path): - schemaGlob = [str(f) for f in Path(path).rglob("*.xsd")] - return ValidateXSDFiles(schemaGlob) - - -def ValidateInstanceDocuments (coreFile, supportingSchemas, instanceDocs): - if (instanceDocs is None) or len(instanceDocs) == 0: - logging.warning ("No instance documents provided") - return [] - - schema = BuildSchema(coreFile, supportingSchemas) - errors = [] - for instanceDoc in instanceDocs: - try: - schema.validate(instanceDoc) - logging.info ("{0} passed validation".format(instanceDoc)) - except Exception as ex: - logging.error ("{0} failed validation: {1}".format(instanceDoc, ex)) - return errors - - -def processResults (results, stageName): - """ - Counts the number of errors and writes out the output per filename - - :param results: List of filenames (str or Pathlib Path) - :param stageName: Name to decorate the output with - :returns: The number of files which had errors - """ - print("") - errorCount = sum([1 for r in results.values() if not r['ok']]) - logging.info(f"{errorCount} {stageName} errors encountered") - - print(f"{'-':-<60}") - print(f"{stageName} results:") - print(f"{'-':-<60}") - for filename, result in results.items(): - print(f" {filename:.<55}{'..OK' if result['ok'] else 'FAIL'}") - if not result['ok']: - if isinstance(result['message'], list): - for thing in result['message']: - print(f" {thing['message']}") - else: - print(f" {result['message']}") - - print(f"{'-':-<60}") - print(f"{stageName} errors: {errorCount}") - print(f"{'-':-<60}") - - return errorCount - - -def syntaxCheckXSD (fileList): - results = {} - for file in fileList: - try: - logging.info(f"Syntax checking {str(file)}") - - schema = XMLSchema(str(file), validation="skip") - results[str(file)] = { - 'ok' : len(schema.all_errors) == 0, - 'message' : None if len(schema.all_errors) == 0 else [{'message' : f"{etree_tostring(e.elem, e.namespaces, ' ', 20)} - {e.message}"} for e in schema.all_errors] - } - except XMLSchemaParseError as ex: - logging.warning(str(file) + ": Failed validation ({0})".format(ex.message)) - results[str(file)] = { - 'ok' : False, - 'message' : f"{ex!r}" - } - return results - - -if __name__ == '__main__': - #logging.basicConfig(level=logging.DEBUG) - - compileTargets = json.loads(Path('testing/xsd_compile_targets.json').read_text()) - results = {} - for target in compileTargets: - coreFile = target['coreSchema'] - logging.info(f"Attempting to compile {coreFile}") - schemaLocations = [] - for supportSchema in target['supportingSchemas']: - logging.debug(f"Adding supporting schema {supportSchema}") - try: - xs = XMLSchema(supportSchema, validation='skip') - schemaLocations.append((xs.target_namespace, str(Path(supportSchema).resolve()))) - logging.info(" [ {0} -> {1} ]".format(xs.default_namespace, supportSchema)) - except Exception as ex: - logging.warning (" [ {0} exception parsing: {1} ]".format(supportSchema, ex)) - results[coreFile] = { - 'ok' : False, - 'message' : f"{ex!r}" - } - break - try: - schema = XMLSchema(coreFile, locations = schemaLocations, validation="strict") - results[coreFile] = { - 'ok' : len(schema.all_errors) == 0, - 'message' : None if len(schema.all_errors) == 0 else [{'message' : f"{etree_tostring(e.elem, e.namespaces, ' ', 20)} - {e.message}"} for e in schema.all_errors] - } - target["schemaInstance"] = schema - except Exception as ex: - results[coreFile] = { - 'ok' : False, - 'message' : f"{ex!r}" - } - continue - - if (processResults(results, "Compile") > 0): - exit(-1) - - results = {} - - for target in compileTargets: - schema = target["schemaInstance"] - testResults = {} - failureCount = 0 - logging.info (f"Validating example {len(target['exampleFiles'])} entries for {target['coreSchema']}") - for example in target["exampleFiles"]: - examplePath = Path(example) - if examplePath.is_dir(): - logging.debug (f"Expanding {str(examplePath)}") - testFiles = list(examplePath.rglob("./*.xml")) - else: - testFiles = [examplePath] - logging.debug(f"Found {len(testFiles)} test files") - for test in testFiles: - logging.debug(f"Validating {str(test)} against schema") - try: - errors = list(schema.iter_errors(str(test))) - testResults[test] = [f"{etree_tostring(e.elem, e.namespaces, ' ', 20)} - {e.message}" for e in errors] - failureCount += len(errors) - except Exception as ex: - testResults[test] = [f"{ex!r}"] - failureCount += 1 - results[target['coreSchema']] = { - 'ok' : failureCount == 0, - 'testResults' : testResults, - 'failureCount' : failureCount - } - - print(f"{'-':-<75}") - print(f"Validation results:") - print(f"{'-':-<75}") - - totalErrors = 0 - for filename, result in results.items(): - if len(result['testResults']) == 0: - print (f"{filename:.<70}SKIP (0)") - continue - else: - print (f"{filename:.<70}{'..OK' if result['ok'] else 'FAIL'} ({len(result['testResults'])})") - totalErrors += result['failureCount'] - if result['failureCount'] > 0: - for testFile, testResult in result['testResults'].items(): - print(f" {str(testFile):.<65}{'..OK' if len(testResult) == 0 else 'FAIL'}") - for tr in testResult: - print(f" {tr}") - - print(f"{'-':-<75}") - print(f"Validation errors: {totalErrors}") - print(f"{'-':-<75}") - - exit(totalErrors > 0) diff --git a/utils/json_to_xml.py b/utils/json_to_xml.py index 17764a7af097aae7a2020522a1ae45adafa7d26a..3f03901c732a010cda374b1ead00664122998141 100644 --- a/utils/json_to_xml.py +++ b/utils/json_to_xml.py @@ -11,8 +11,19 @@ import argparse if __name__ == "__main__": parser = argparse.ArgumentParser() - parser.add_argument('-v', '--verbose', action='count', help='Verbose logging (can be specified multiple times)') - parser.add_argument('-i', '--input', type=argparse.FileType('r'), default=sys.stdin, help="Path to input file (if absent, stdin is used)") + parser.add_argument( + "-v", + "--verbose", + action="count", + help="Verbose logging (can be specified multiple times)", + ) + parser.add_argument( + "-i", + "--input", + type=argparse.FileType("r"), + default=sys.stdin, + help="Path to input file (if absent, stdin is used)", + ) args = parser.parse_args() match args.verbose: @@ -31,5 +42,7 @@ if __name__ == "__main__": logging.debug(s) j = json.loads(s) - xml = xmltodict.unparse({'HI1Message' : j}, ) - print(xml) \ No newline at end of file + xml = xmltodict.unparse( + {"HI1Message": j}, + ) + print(xml) diff --git a/utils/json_validator.py b/utils/json_validator.py index e9ff0c03a2b121ba5f9a429221288158c0bdcd03..074201ff8d4ae4ac2e81890565babc1780cc4976 100644 --- a/utils/json_validator.py +++ b/utils/json_validator.py @@ -7,10 +7,11 @@ import logging import argparse from itertools import chain + class JsonValidator: - def __init__(self, core_schema: str, other_schemas : dict): + def __init__(self, core_schema: str, other_schemas: dict): self._core_schema = json.load(Path(core_schema).open()) - self._schema_dict = { self._core_schema['$id'] : self._core_schema } + self._schema_dict = {self._core_schema["$id"]: self._core_schema} self._supporting_paths = [] for thing in other_schemas: path = Path(thing) @@ -22,102 +23,186 @@ class JsonValidator: self._supporting_paths.append(path) logging.info(f"Supporting schema paths: {self._supporting_paths}") self._supporting_schemas = [json.load(p.open()) for p in self._supporting_paths] - self._schema_dict = self._schema_dict | { s['$id'] : s for s in self._supporting_schemas } + self._schema_dict = self._schema_dict | { + s["$id"]: s for s in self._supporting_schemas + } logging.info(f"Loaded schema IDs: {[k for k in self._schema_dict.keys()]}") - self._resolver = RefResolver(None, - referrer=None, - store=self._schema_dict) + self._resolver = RefResolver(None, referrer=None, store=self._schema_dict) logging.info("Created RefResolver") - self._validator = Draft202012Validator(self._core_schema, resolver=self._resolver) + self._validator = Draft202012Validator( + self._core_schema, resolver=self._resolver + ) logging.info("Created validator") def validate(self, instance_doc: str): errors = list(self._validator.iter_errors(instance_doc)) return errors - -class TS103120Validator (JsonValidator): - def __init__ (self, path_to_repo): + + +class TS103120Validator(JsonValidator): + def __init__(self, path_to_repo): repo_path = Path(path_to_repo) schema_dirs = [str(repo_path / "103120/schema/json"), str("103280/")] core_schema = str(repo_path / "103120/schema/json/ts_103120_Core.schema.json") JsonValidator.__init__(self, core_schema, schema_dirs) - request_fragment_schema = { "$ref" : "ts_103120_Core_2019_10#/$defs/RequestPayload" } - self._request_fragment_validator = Draft202012Validator(request_fragment_schema, resolver=self._resolver) - response_fragment_schema = { "$ref" : "ts_103120_Core_2019_10#/$defs/ResponsePayload" } - self._response_fragment_validator = Draft202012Validator(response_fragment_schema, resolver=self._resolver) - - def expand_request_response_exception (self, ex): - if list(ex.schema_path) == ['properties', 'Payload', 'oneOf']: - logging.info ("Error detected validating payload oneOf - attempting explicit validation...") - if 'RequestPayload' in instance_doc['Payload'].keys(): - ret_list = list(chain(*[self.expand_action_exception(x) for x in self._request_fragment_validator.iter_errors(instance_doc['Payload']['RequestPayload'])])) + request_fragment_schema = { + "$ref": "ts_103120_Core_2019_10#/$defs/RequestPayload" + } + self._request_fragment_validator = Draft202012Validator( + request_fragment_schema, resolver=self._resolver + ) + response_fragment_schema = { + "$ref": "ts_103120_Core_2019_10#/$defs/ResponsePayload" + } + self._response_fragment_validator = Draft202012Validator( + response_fragment_schema, resolver=self._resolver + ) + + def expand_request_response_exception(self, ex): + if list(ex.schema_path) == ["properties", "Payload", "oneOf"]: + logging.info( + "Error detected validating payload oneOf - attempting explicit validation..." + ) + if "RequestPayload" in instance_doc["Payload"].keys(): + ret_list = list( + chain( + *[ + self.expand_action_exception(x) + for x in self._request_fragment_validator.iter_errors( + instance_doc["Payload"]["RequestPayload"] + ) + ] + ) + ) for r in ret_list: r.path = ex.path + r.path return ret_list - elif 'ResponsePayload' in instance_doc['Payload'].keys(): - ret_list = list(chain(*[self.expand_action_exception(x) for x in self._request_fragment_validator.iter_errors(instance_doc['Payload']['ResponsePayload'])])) + elif "ResponsePayload" in instance_doc["Payload"].keys(): + ret_list = list( + chain( + *[ + self.expand_action_exception(x) + for x in self._request_fragment_validator.iter_errors( + instance_doc["Payload"]["ResponsePayload"] + ) + ] + ) + ) for r in ret_list: r.path = ex.path + r.path return ret_list else: - logging.error("No RequestPayload or ResponsePayload found - is the Payload malformed?") + logging.error( + "No RequestPayload or ResponsePayload found - is the Payload malformed?" + ) return [ex] else: return [ex] - - def expand_action_exception (self, ex): + + def expand_action_exception(self, ex): logging.error("Error detected in ActionRequests/ActionResponses") error_path = list(ex.schema_path) - if error_path != ['properties', 'ActionRequests', 'properties', 'ActionRequest', 'items', 'allOf', 1, 'oneOf'] and error_path != ['properties', 'ActionResponses', 'properties', 'ActionResponse', 'items', 'allOf', 1, 'oneOf']: + if error_path != [ + "properties", + "ActionRequests", + "properties", + "ActionRequest", + "items", + "allOf", + 1, + "oneOf", + ] and error_path != [ + "properties", + "ActionResponses", + "properties", + "ActionResponse", + "items", + "allOf", + 1, + "oneOf", + ]: logging.error("Error not in inner Request/Response allOf/oneOf constraint") - return[ex] + return [ex] j = ex.instance - j.pop('ActionIdentifier') # Remove ActionIdentifier - one remaining key will be the verb + j.pop( + "ActionIdentifier" + ) # Remove ActionIdentifier - one remaining key will be the verb verb = list(j.keys())[0] message = "Request" if error_path[1] == "ActionRequests" else "Response" - v = Draft202012Validator({"$ref" : f"ts_103120_Core_2019_10#/$defs/{verb}{message}"}, resolver=self._resolver) - ret_list = list(chain(*[self.expand_object_exception(x) for x in v.iter_errors(j[verb])])) + v = Draft202012Validator( + {"$ref": f"ts_103120_Core_2019_10#/$defs/{verb}{message}"}, + resolver=self._resolver, + ) + ret_list = list( + chain(*[self.expand_object_exception(x) for x in v.iter_errors(j[verb])]) + ) for r in ret_list: r.path = ex.path + r.path return ret_list - - def expand_object_exception (self, ex): + + def expand_object_exception(self, ex): logging.error("Error detected in verb") # The final level of validation is for the actual HI1Object validation - if list(ex.schema_path) != ['properties', 'HI1Object', 'oneOf']: + if list(ex.schema_path) != ["properties", "HI1Object", "oneOf"]: logging.error("Error not inside HI1Object") return [ex] - object_type = ex.instance['@xsi:type'].split('}')[-1] + object_type = ex.instance["@xsi:type"].split("}")[-1] object_ref = { - 'AuthorisationObject': 'ts_103120_Authorisation_2020_09#/$defs/AuthorisationObject', - 'LITaskObject': 'ts_103120_Task_2020_09#/$defs/LITaskObject', - 'LDTaskObject': 'ts_103120_Task_2020_09#/$defs/LDTaskObject', - 'LPTaskObject': 'ts_103120_Task_2020_09#/$defs/LPTaskObject', - 'DocumentObject': 'ts_103120_Document_2020_09#/$defs/DocumentObject', - 'NotificationObject': 'ts_103120_Notification_2016_02#/$defs/NotificationObject', - 'DeliveryObject': 'ts_103120_Delivery_2019_10#/$defs/DeliveryObject', - 'TrafficPolicyObject': 'ts_103120_TrafficPolicy_2022_07#/$defs/TrafficPolicyObject', - 'TrafficRuleObject': 'ts_103120_TrafficPolicy_2022_07#/$defs/TrafficRuleObject', + "AuthorisationObject": "ts_103120_Authorisation_2020_09#/$defs/AuthorisationObject", + "LITaskObject": "ts_103120_Task_2020_09#/$defs/LITaskObject", + "LDTaskObject": "ts_103120_Task_2020_09#/$defs/LDTaskObject", + "LPTaskObject": "ts_103120_Task_2020_09#/$defs/LPTaskObject", + "DocumentObject": "ts_103120_Document_2020_09#/$defs/DocumentObject", + "NotificationObject": "ts_103120_Notification_2016_02#/$defs/NotificationObject", + "DeliveryObject": "ts_103120_Delivery_2019_10#/$defs/DeliveryObject", + "TrafficPolicyObject": "ts_103120_TrafficPolicy_2022_07#/$defs/TrafficPolicyObject", + "TrafficRuleObject": "ts_103120_TrafficPolicy_2022_07#/$defs/TrafficRuleObject", }[object_type] - v = Draft202012Validator({"$ref" : object_ref}, resolver=self._resolver) + v = Draft202012Validator({"$ref": object_ref}, resolver=self._resolver) return list(v.iter_errors(ex.instance)) - + def validate(self, instance_doc: str): errors = JsonValidator.validate(self, instance_doc) - out_errors = list(chain(*[self.expand_request_response_exception(ex) for ex in errors])) + out_errors = list( + chain(*[self.expand_request_response_exception(ex) for ex in errors]) + ) return out_errors - if __name__ == "__main__": parser = argparse.ArgumentParser() - parser.add_argument('-s','--schemadir', action="append", help="Directory containing supporting schema files to use for validation") - parser.add_argument('-v', '--verbose', action="count", help="Verbose logging (can be specified multiple times)") - parser.add_argument('-i', '--input', type=argparse.FileType('r'), default=sys.stdin, help="Path to input file (if absent, stdin is used)") - parser.add_argument('--ts103120', action="store_true", help="Validate a TS 103 120 JSON document") - parser.add_argument('--schema', default=None, help="Primary schema to validate against") - parser.add_argument('-p', '--printerror', action="count", help="Controls how verbose validation error printing is (can be specified multiple times)") + parser.add_argument( + "-s", + "--schemadir", + action="append", + help="Directory containing supporting schema files to use for validation", + ) + parser.add_argument( + "-v", + "--verbose", + action="count", + help="Verbose logging (can be specified multiple times)", + ) + parser.add_argument( + "-i", + "--input", + type=argparse.FileType("r"), + default=sys.stdin, + help="Path to input file (if absent, stdin is used)", + ) + parser.add_argument( + "--ts103120", action="store_true", help="Validate a TS 103 120 JSON document" + ) + parser.add_argument( + "--schema", default=None, help="Primary schema to validate against" + ) + parser.add_argument( + "-p", + "--printerror", + action="count", + help="Controls how verbose validation error printing is (can be specified multiple times)", + ) args = parser.parse_args() match args.verbose: @@ -130,7 +215,7 @@ if __name__ == "__main__": logging.debug(f"Arguments: {args}") - if (args.ts103120): + if args.ts103120: v = TS103120Validator("./") else: v = JsonValidator(args.schema, args.schemadir) diff --git a/utils/sign_json.py b/utils/sign_json.py index 1ce0bba5b21d00ff86bcab7d680425451d0e24f8..96439d468fc42d0beb29699f4a37ab827f8a6109 100644 --- a/utils/sign_json.py +++ b/utils/sign_json.py @@ -1,4 +1,3 @@ - import argparse import logging import sys @@ -8,18 +7,31 @@ from pathlib import Path import json -def insert_sig_block (j): - j['Signature'] = { - 'protected' : '', - 'signature' : '' - } +def insert_sig_block(j): + j["Signature"] = {"protected": "", "signature": ""} return j + if __name__ == "__main__": parser = argparse.ArgumentParser() - parser.add_argument('-v', '--verbose', action='count', help='Verbose logging (can be specified multiple times)') - parser.add_argument('--pretty', action="store_true", help='Pretty-print the JSON document before signing') - parser.add_argument('-i', '--input', type=argparse.FileType('r'), default=sys.stdin, help="Path to input file (if absent, stdin is used)") + parser.add_argument( + "-v", + "--verbose", + action="count", + help="Verbose logging (can be specified multiple times)", + ) + parser.add_argument( + "--pretty", + action="store_true", + help="Pretty-print the JSON document before signing", + ) + parser.add_argument( + "-i", + "--input", + type=argparse.FileType("r"), + default=sys.stdin, + help="Path to input file (if absent, stdin is used)", + ) args = parser.parse_args() match args.verbose: @@ -34,24 +46,22 @@ if __name__ == "__main__": json_text = args.input.read() args.input.close() - + j = json.loads(json_text) j = insert_sig_block(j) - + indent = None if args.pretty: - indent = ' ' + indent = " " presigned_json_text = json.dumps(j, indent=indent) - Path('presigned.json').write_text(presigned_json_text) - presigned_json_bytes = presigned_json_text.encode('utf-8') - - signed = jws.sign(presigned_json_bytes, 'secret_key', algorithm="HS256") - components = signed.split('.') + Path("presigned.json").write_text(presigned_json_text) + presigned_json_bytes = presigned_json_text.encode("utf-8") + + signed = jws.sign(presigned_json_bytes, "secret_key", algorithm="HS256") + components = signed.split(".") - j['Signature']['protected'] = components[0] - j['Signature']['signature'] = components[2] + j["Signature"]["protected"] = components[0] + j["Signature"]["signature"] = components[2] signed_json_text = json.dumps(j, indent=indent) print(signed_json_text) - - diff --git a/utils/translate/ChoiceMapping.py b/utils/translate/ChoiceMapping.py index b477a3360e0a6a7b891f5854951eb4f37dce4b39..16c396247183e28a437e9204e1cacd6c93ab999e 100644 --- a/utils/translate/ChoiceMapping.py +++ b/utils/translate/ChoiceMapping.py @@ -10,38 +10,43 @@ from .ComplexTypeMapping import ComplexTypeMapping log = logging.getLogger() + class ChoiceMapping(ComplexTypeMapping): @classmethod - def process_choice(cls, choice: XsdGroup, current_ns : str, ns_to_id_map): - if choice.model != 'choice': + def process_choice(cls, choice: XsdGroup, current_ns: str, ns_to_id_map): + if choice.model != "choice": raise Exception(f"Wrong group type: {c.model}") oneOf = [] for c in choice.iter_model(): if not (type(c) is XsdElement): - raise Exception (f"Non-element {c} encountered in choice {choice}") + raise Exception(f"Non-element {c} encountered in choice {choice}") element_name = c.local_name if c.target_namespace in ns_to_id_map: ns = ns_to_id_map[c.target_namespace] - if 'prefix' in ns: - element_name = ns['prefix'] + ":" + element_name + if "prefix" in ns: + element_name = ns["prefix"] + ":" + element_name t = TypeMapping.get_type_from_elem(c, current_ns) - oneOf.append({ - "type" : "object", - "properties" : { - element_name : t - }, - "required" : [element_name] - }) - return oneOf + oneOf.append( + { + "type": "object", + "properties": {element_name: t}, + "required": [element_name], + } + ) + return oneOf - def map(self, xst : BaseXsdType): + def map(self, xst: BaseXsdType): log.debug(f"Attempting mapping of {xst} to choice") j = super().map(xst) if j is None: log.debug("Not a complex type, giving up") return None content = xst.content - if (content.model != 'choice'): + if content.model != "choice": log.debug("Not a choice, giving up") return None - return { 'oneOf' : ChoiceMapping.process_choice(content, xst.namespaces[''], self.ns_to_id_map)} + return { + "oneOf": ChoiceMapping.process_choice( + content, xst.namespaces[""], self.ns_to_id_map + ) + } diff --git a/utils/translate/ComplexTypeMapping.py b/utils/translate/ComplexTypeMapping.py index e18190901be2c3e0695c00a772be5364cce591d1..19064e2d5106c4098ac7f26524ed7cd6a12785e1 100644 --- a/utils/translate/ComplexTypeMapping.py +++ b/utils/translate/ComplexTypeMapping.py @@ -2,10 +2,9 @@ from xmlschema.validators.complex_types import * from .TypeMapping import TypeMapping + class ComplexTypeMapping(TypeMapping): def map(self, xst: BaseXsdType): if not (type(xst) is XsdComplexType): return None - return { - "type" : "object" - } + return {"type": "object"} diff --git a/utils/translate/SequenceMapping.py b/utils/translate/SequenceMapping.py index 68f76094121997a2960a9f6a507a542aaaedadce..c70e509bb20c97b721ea95f230e0ed60a3787d52 100644 --- a/utils/translate/SequenceMapping.py +++ b/utils/translate/SequenceMapping.py @@ -20,14 +20,14 @@ class SequenceMapping(ComplexTypeMapping): log.debug("Not a complex type, giving up") return None content = xst.content - if (content.model != 'sequence'): + if content.model != "sequence": log.debug("Not a sequence, giving up") return None mapped_type = { - 'type' : 'object', - 'properties' : {}, - 'required' : [], - 'additionalProperties' : False + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": False, } # Not going to try and do all of this automatically for now @@ -35,11 +35,11 @@ class SequenceMapping(ComplexTypeMapping): # HACK exception for ApproverContactDetails because it isn't abstract if (xst.base_type) and (xst.local_name != "ApproverContactDetails"): # mapped_type['__DESCENDENT_OF__'] = TypeMapping.get_ref_for(xst.base_type, xst.namespaces['']) - mapped_type['properties']['@xsi:type'] = { - "type" : "string", - "enum" : [xst.name] + mapped_type["properties"]["@xsi:type"] = { + "type": "string", + "enum": [xst.name], } - mapped_type['required'].append('@xsi:type') + mapped_type["required"].append("@xsi:type") # if xst.abstract: # mapped_type['__ABSTRACT__'] = True # pass @@ -51,41 +51,50 @@ class SequenceMapping(ComplexTypeMapping): element_name = c.local_name if c.target_namespace in self.ns_to_id_map: ns = self.ns_to_id_map[c.target_namespace] - if 'prefix' in ns: - element_name = ns['prefix'] + ":" + element_name + if "prefix" in ns: + element_name = ns["prefix"] + ":" + element_name if c.effective_max_occurs != 1: - mapped_type['properties'][element_name] = { - "type" : "array", - "items" : TypeMapping.get_type_from_elem(c, xst.namespaces['']) + mapped_type["properties"][element_name] = { + "type": "array", + "items": TypeMapping.get_type_from_elem(c, xst.namespaces[""]), } if c.effective_max_occurs: - mapped_type['properties'][element_name]['maxItems'] = c.effective_max_occurs + mapped_type["properties"][element_name]["maxItems"] = ( + c.effective_max_occurs + ) if c.effective_min_occurs > 0: - mapped_type['properties'][element_name]['minItems'] = c.effective_min_occurs + mapped_type["properties"][element_name]["minItems"] = ( + c.effective_min_occurs + ) else: - mapped_type['properties'][element_name] = TypeMapping.get_type_from_elem(c, xst.namespaces['']) + mapped_type["properties"][element_name] = ( + TypeMapping.get_type_from_elem(c, xst.namespaces[""]) + ) if c.effective_min_occurs == 1: - mapped_type['required'].append(element_name) + mapped_type["required"].append(element_name) elif type(c) is XsdGroup: if inner_choice: - raise Exception (f"Second group '{element_name}' encountered in {xst}") + raise Exception( + f"Second group '{element_name}' encountered in {xst}" + ) if c.model != "choice": - raise Exception (f"Don't know what to do with inner group {c} in {xst} - not a choice") - inner_choice = ChoiceMapping.process_choice(c, xst.namespaces[''], self.ns_to_id_map) + raise Exception( + f"Don't know what to do with inner group {c} in {xst} - not a choice" + ) + inner_choice = ChoiceMapping.process_choice( + c, xst.namespaces[""], self.ns_to_id_map + ) elif type(c) is XsdAnyElement: mapped_type = {} else: raise Exception(f"Unknown element type {c}") - if (inner_choice): + if inner_choice: for inner_thing in inner_choice: - inner_thing.pop('additionalProperties', None) - mapped_type.pop('additionalProperties', None) - return { - 'allOf' : [ - mapped_type, - {'oneOf' : inner_choice} - ], - 'unevaluatedProperties' : False + inner_thing.pop("additionalProperties", None) + mapped_type.pop("additionalProperties", None) + return { + "allOf": [mapped_type, {"oneOf": inner_choice}], + "unevaluatedProperties": False, } else: return mapped_type diff --git a/utils/translate/SimpleTypeMapping.py b/utils/translate/SimpleTypeMapping.py index 2e60f9ca06b321a28992c2a32235707671f95735..70edfb8ce0367c1046482f8056bbe78d67afe6fd 100644 --- a/utils/translate/SimpleTypeMapping.py +++ b/utils/translate/SimpleTypeMapping.py @@ -7,12 +7,11 @@ from .TypeMapping import TypeMapping log = logging.getLogger() + class SimpleTypeMapping(TypeMapping): def map(self, xst: BaseXsdType): log.debug(f"Attempting mapping of {xst} to simple type") if not (type(xst) is XsdAtomicRestriction): log.debug("Type is not an XsdAtomicRestriction, giving up") return None - return { - "$ref" : xst.base_type.name - } \ No newline at end of file + return {"$ref": xst.base_type.name} diff --git a/utils/translate/TypeMapping.py b/utils/translate/TypeMapping.py index 2b4b785ceeedb631c98ecf63df5c8d9754848b29..57a367f6f31935b31234b2d9759569dcf13455ee 100644 --- a/utils/translate/TypeMapping.py +++ b/utils/translate/TypeMapping.py @@ -8,63 +8,52 @@ from xmlschema.validators.facets import * log = logging.getLogger() + class TypeMapping(ABC): ns_to_id_map = {} XSD_NS = "http://www.w3.org/2001/XMLSchema" XSD_TYPE_MAP = { - "string" : { "type" : "string" }, - "normalizedString" : { "type" : "string"}, - "dateTime" : { "type" : "string"}, - "token" : { "type" : "string"}, - "anyURI" : { "type" : "string" }, - - "integer" : { "type" : "integer"}, - "nonNegativeInteger" : { "type" : "integer", "minimum" : 0}, - "positiveInteger" : { "type" : "integer", "minimum" : 1}, - - "boolean" : { "type" : "boolean" }, - - "hexBinary" : { "type" : "string", "pattern" : "^([a-fA-F0-9]{2})*$"}, - "base64Binary" : { "type" : "string", "pattern" : "^[A-Za-z0-9+\/]*={0,3}$"}, - - "anyType" : {} - } + "string": {"type": "string"}, + "normalizedString": {"type": "string"}, + "dateTime": {"type": "string"}, + "token": {"type": "string"}, + "anyURI": {"type": "string"}, + "integer": {"type": "integer"}, + "nonNegativeInteger": {"type": "integer", "minimum": 0}, + "positiveInteger": {"type": "integer", "minimum": 1}, + "boolean": {"type": "boolean"}, + "hexBinary": {"type": "string", "pattern": "^([a-fA-F0-9]{2})*$"}, + "base64Binary": {"type": "string", "pattern": "^[A-Za-z0-9+\/]*={0,3}$"}, + "anyType": {}, + } @abstractmethod - def map(self, xst : BaseXsdType): + def map(self, xst: BaseXsdType): return None @classmethod def extract_namespace(cls, qname: str): - match = re.search(r'^\{([^\{\}]+)\}(([^\{\}]+))$', qname) + match = re.search(r"^\{([^\{\}]+)\}(([^\{\}]+))$", qname) if match is None: return None return match.group(1) @classmethod - def get_ref_for(cls, xsd_type: XsdType, current_ns : str): + def get_ref_for(cls, xsd_type: XsdType, current_ns: str): ns = cls.extract_namespace(xsd_type.name) if ns == current_ns: - return { "$ref" : f"#/$defs/{xsd_type.local_name}" } + return {"$ref": f"#/$defs/{xsd_type.local_name}"} else: mapped_id = cls.ns_to_id_map[ns] - return { "$ref" : f"{mapped_id['id']}#/$defs/{xsd_type.local_name}"} + return {"$ref": f"{mapped_id['id']}#/$defs/{xsd_type.local_name}"} @classmethod - def get_type_from_elem(cls, elem: XsdElement, current_ns : str): + def get_type_from_elem(cls, elem: XsdElement, current_ns: str): ns = cls.extract_namespace(elem.type.name) - if (ns == TypeMapping.XSD_NS): + if ns == TypeMapping.XSD_NS: # this should be an XSD primitive type return dict(TypeMapping.XSD_TYPE_MAP[elem.type.local_name]) else: return cls.get_ref_for(elem.type, current_ns) - - - - - - - - diff --git a/utils/translate/XSDNativeSimpleTypeMapping.py b/utils/translate/XSDNativeSimpleTypeMapping.py index 772ac10b308d4c2128bcf1bac3271117d9bbe80e..bd4d2119bec8c73f8688b8b0c769a6df54ce9d98 100644 --- a/utils/translate/XSDNativeSimpleTypeMapping.py +++ b/utils/translate/XSDNativeSimpleTypeMapping.py @@ -10,8 +10,8 @@ from .SimpleTypeMapping import SimpleTypeMapping log = logging.getLogger() -class XSDNativeSimpleTypeMapping(SimpleTypeMapping): +class XSDNativeSimpleTypeMapping(SimpleTypeMapping): def map(self, xst: BaseXsdType): log.debug(f"Attempting mapping of {xst} to XSD native type") j = super().map(xst) @@ -25,48 +25,50 @@ class XSDNativeSimpleTypeMapping(SimpleTypeMapping): if mapped_type is None: ns = TypeMapping.extract_namespace(xst.base_type.name) if ns == XSDNativeSimpleTypeMapping.XSD_NS: - print (xst) - print (xst.base_type) - raise Exception (f"No mapping for xs:{xst.base_type.local_name}") + print(xst) + print(xst.base_type) + raise Exception(f"No mapping for xs:{xst.base_type.local_name}") if len(xst.facets) == 0: - mapped_type = TypeMapping.get_ref_for(xst.base_type, xst.namespaces['']) + mapped_type = TypeMapping.get_ref_for(xst.base_type, xst.namespaces[""]) else: - parent_type = TypeMapping.get_ref_for(xst.base_type, xst.namespaces['']) + parent_type = TypeMapping.get_ref_for(xst.base_type, xst.namespaces[""]) mapped_type = TypeMapping.XSD_TYPE_MAP.get(xst.root_type.local_name) if mapped_type is None: - raise Exception (f"Could not find mapping for root type xs:{xst.root_type.local_name}") + raise Exception( + f"Could not find mapping for root type xs:{xst.root_type.local_name}" + ) mapped_type = dict(mapped_type) - + for k, v in xst.facets.items(): log.debug(f"Mapping facet {v}") if type(v) is XsdMaxLengthFacet: - mapped_type['maxLength'] = v.value + mapped_type["maxLength"] = v.value continue if type(v) is XsdMinLengthFacet: - mapped_type['minLength'] = v.value + mapped_type["minLength"] = v.value continue if type(v) is XsdPatternFacets: if len(v.regexps) > 1: - raise Exception (f"Multiple patterns given in facet {v} of {xst}") + raise Exception(f"Multiple patterns given in facet {v} of {xst}") p = v.regexps[0] - if (not p.startswith('^')) and (not p.endswith('$')): + if (not p.startswith("^")) and (not p.endswith("$")): p = f"^{p}$" - mapped_type['pattern'] = p + mapped_type["pattern"] = p continue - if type (v) is XsdMinInclusiveFacet: - mapped_type['minimum'] = v.value + if type(v) is XsdMinInclusiveFacet: + mapped_type["minimum"] = v.value continue - if type (v) is XsdMaxInclusiveFacet: - mapped_type['maximum'] = v.value + if type(v) is XsdMaxInclusiveFacet: + mapped_type["maximum"] = v.value continue - if type (v) is XsdMinExclusiveFacet: - mapped_type['exclusiveMinimum'] = v.value + if type(v) is XsdMinExclusiveFacet: + mapped_type["exclusiveMinimum"] = v.value continue - if type (v) is XsdMaxExclusiveFacet: - mapped_type['exclusiveMaximum'] = v.value + if type(v) is XsdMaxExclusiveFacet: + mapped_type["exclusiveMaximum"] = v.value continue - raise Exception (f"Unhandled facet {v}") + raise Exception(f"Unhandled facet {v}") if parent_type: - return { 'allOf' : [parent_type, mapped_type] } + return {"allOf": [parent_type, mapped_type]} return mapped_type diff --git a/utils/translate/__init__.py b/utils/translate/__init__.py index 86a33468c8e281b7d9a745261fc96a1b7905e17f..bf2d08da8d0255fdfec576903308fbe701c260b0 100644 --- a/utils/translate/__init__.py +++ b/utils/translate/__init__.py @@ -17,30 +17,33 @@ mappings = [ SequenceMapping(), ] -def translate_schema (schema_path: str, ns_to_id_map: dict, schema_locations = []): + +def translate_schema(schema_path: str, ns_to_id_map: dict, schema_locations=[]): js = { - "$id" : "?", - "$schema" : "https://json-schema.org/draft/2020-12/schema", - "$defs" : {} + "$id": "?", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$defs": {}, } logging.info(f"Translating schema {schema_path}") - xs = XMLSchema(schema_path, validation='lax', locations=schema_locations) - logging.info(f"Schema namespace: {xs.target_namespace}" ) + xs = XMLSchema(schema_path, validation="lax", locations=schema_locations) + logging.info(f"Schema namespace: {xs.target_namespace}") schema_id = ns_to_id_map[xs.target_namespace]["id"] - js['$id'] = schema_id + js["$id"] = schema_id TypeMapping.ns_to_id_map = ns_to_id_map elementList = [] for elementName, element in xs.elements.items(): logging.info(f"Processing element {elementName} : {element}") - elementList.append(TypeMapping.get_ref_for(element.type, element.namespaces[''])) + elementList.append( + TypeMapping.get_ref_for(element.type, element.namespaces[""]) + ) if len(elementList) == 1: - js['$ref'] = elementList[0]['$ref'] + js["$ref"] = elementList[0]["$ref"] elif len(elementList) > 1: - js['oneOf'] = elementList + js["oneOf"] = elementList descendent_types = {} for type_name, xsd_type in xs.types.items(): @@ -57,9 +60,7 @@ def translate_schema (schema_path: str, ns_to_id_map: dict, schema_locations = [ if j is None: raise Exception(f"Unmapped type {type_name} ({xsd_type})") js["$defs"][xsd_type.local_name] = j - logging.debug (f"Mapped {type_name} to {j}") + logging.debug(f"Mapped {type_name} to {j}") - print (descendent_types) + print(descendent_types) return js - - diff --git a/utils/translate_spec.py b/utils/translate_spec.py index f78b8fffdaf6264eb36e3126e6e0a101f08292b3..6ce2f843a17646a88ffde26041a2068805955b8f 100644 --- a/utils/translate_spec.py +++ b/utils/translate_spec.py @@ -8,68 +8,68 @@ from xmlschema import * from translate import * -logging.basicConfig(level = logging.INFO) +logging.basicConfig(level=logging.INFO) json_signature_struct = { - "properties" : { - "protected" : { "type" : "string" }, - "signature" : { "type" : "string" } - }, - "required" : ["protected", "signature" ] + "properties": {"protected": {"type": "string"}, "signature": {"type": "string"}}, + "required": ["protected", "signature"], } -def build_schema_locations (paths): + +def build_schema_locations(paths): schema_locations = [] for schemaFile in paths: try: - xs = XMLSchema(schemaFile, validation='skip') - schema_locations.append((xs.target_namespace, str(Path(schemaFile).resolve()))) - logging.debug (" [ {0} -> {1} ]".format(xs.target_namespace, schemaFile)) + xs = XMLSchema(schemaFile, validation="skip") + schema_locations.append( + (xs.target_namespace, str(Path(schemaFile).resolve())) + ) + logging.debug(" [ {0} -> {1} ]".format(xs.target_namespace, schemaFile)) except XMLSchemaParseError as ex: - logging.debug (" [ {0} failed to parse: {1} ]".format(schemaFile, ex)) + logging.debug(" [ {0} failed to parse: {1} ]".format(schemaFile, ex)) return schema_locations + def get_json(filename): with open(filename) as f: j = json.load(f) return j -def convert_ns_to_id (ns): - if ns.startswith('http://uri.etsi.org'): + +def convert_ns_to_id(ns): + if ns.startswith("http://uri.etsi.org"): c = ns.split("/") return f"ts_1{c[3]}{'_' + c[7] if len(c) > 7 else ''}_{c[5]}_{c[6]}" else: - return ns.replace("http://","").replace("/","_") + return ns.replace("http://", "").replace("/", "_") + -def convert_xsd_to_filename (xsd): +def convert_xsd_to_filename(xsd): f = Path(xsd) - return f.name.replace('.xsd', '.schema.json') + return f.name.replace(".xsd", ".schema.json") + if __name__ == "__main__": if len(sys.argv) < 2: - logging.error ("Usage: translate_spec.py path_to_config_file") + logging.error("Usage: translate_spec.py path_to_config_file") exit(-1) config = get_json(sys.argv[1]) - logging.info("Bulding ns map...") ns_map = {} - for location, settings in config['schemas'].items(): - xs = XMLSchema(location, validation='skip') + for location, settings in config["schemas"].items(): + xs = XMLSchema(location, validation="skip") ns = xs.target_namespace id = convert_ns_to_id(ns) - ns_map[ns] = { - "id" : id, - "location" : str(Path(location).resolve()) - } | settings + ns_map[ns] = {"id": id, "location": str(Path(location).resolve())} | settings logging.debug(ns_map) - + logging.info("Building schema locations") - schema_locations = [(k, v["location"]) for k,v in ns_map.items()] + schema_locations = [(k, v["location"]) for k, v in ns_map.items()] logging.debug(schema_locations) - output_path = Path(config['output']) + output_path = Path(config["output"]) if not output_path.exists(): logging.info("Creating output directory") os.mkdir(str(output_path)) @@ -78,45 +78,56 @@ if __name__ == "__main__": json_schemas = {} for schema_tuple in schema_locations: logging.info(f" Translating {schema_tuple}") - if 'skip' in ns_map[schema_tuple[0]]: + if "skip" in ns_map[schema_tuple[0]]: logging.info(f" Skipping {schema_tuple[0]}...") continue js = translate_schema(schema_tuple[1], ns_map, schema_locations) # TODO - Special case, get rid of XML Dsig signature and insert JSON signature - if schema_tuple[0] == 'http://uri.etsi.org/03120/common/2019/10/Core': - logging.info ("Modifying signature elements") - js['$defs']['HI1Message']['patternProperties'] = { "^@" : { "type" : "string"}} - js['$defs']['HI1Message']['properties'].pop('xmldsig:Signature') - js['$defs']['HI1Message']['properties']['Signature'] = json_signature_struct - - - if 'output' in ns_map[schema_tuple[0]]: - js_path = Path(ns_map[schema_tuple[0]]['output']) / convert_xsd_to_filename(schema_tuple[1]) + if schema_tuple[0] == "http://uri.etsi.org/03120/common/2019/10/Core": + logging.info("Modifying signature elements") + js["$defs"]["HI1Message"]["patternProperties"] = {"^@": {"type": "string"}} + js["$defs"]["HI1Message"]["properties"].pop("xmldsig:Signature") + js["$defs"]["HI1Message"]["properties"]["Signature"] = json_signature_struct + + if "output" in ns_map[schema_tuple[0]]: + js_path = Path(ns_map[schema_tuple[0]]["output"]) / convert_xsd_to_filename( + schema_tuple[1] + ) else: js_path = output_path / convert_xsd_to_filename(schema_tuple[1]) # TODO - Special case - abstract HI1Object if "Core" in schema_tuple[1]: - js["$defs"]['ConcreteHI1Object'] = { - 'oneOf' : [ - {'$ref' : 'ts_103120_Authorisation_2020_09#/$defs/AuthorisationObject'}, - {'$ref' : 'ts_103120_Task_2020_09#/$defs/LITaskObject'}, - {'$ref' : 'ts_103120_Task_2020_09#/$defs/LPTaskObject'}, - {'$ref' : 'ts_103120_Task_2020_09#/$defs/LDTaskObject'}, - {'$ref' : 'ts_103120_Document_2020_09#/$defs/DocumentObject'}, - {'$ref' : 'ts_103120_Notification_2016_02#/$defs/NotificationObject'}, - {'$ref' : 'ts_103120_Delivery_2019_10#/$defs/DeliveryObject'}, - {'$ref' : 'ts_103120_TrafficPolicy_2022_07#/$defs/TrafficPolicyObject'}, - {'$ref' : 'ts_103120_TrafficPolicy_2022_07#/$defs/TrafficRuleObject'}, + js["$defs"]["ConcreteHI1Object"] = { + "oneOf": [ + { + "$ref": "ts_103120_Authorisation_2020_09#/$defs/AuthorisationObject" + }, + {"$ref": "ts_103120_Task_2020_09#/$defs/LITaskObject"}, + {"$ref": "ts_103120_Task_2020_09#/$defs/LPTaskObject"}, + {"$ref": "ts_103120_Task_2020_09#/$defs/LDTaskObject"}, + {"$ref": "ts_103120_Document_2020_09#/$defs/DocumentObject"}, + { + "$ref": "ts_103120_Notification_2016_02#/$defs/NotificationObject" + }, + {"$ref": "ts_103120_Delivery_2019_10#/$defs/DeliveryObject"}, + { + "$ref": "ts_103120_TrafficPolicy_2022_07#/$defs/TrafficPolicyObject" + }, + { + "$ref": "ts_103120_TrafficPolicy_2022_07#/$defs/TrafficRuleObject" + }, ] } json_string = json.dumps(js, indent=2) + "\n" if "Core" in schema_tuple[1]: - json_string = json_string.replace('"$ref": "#/$defs/HI1Object"', '"$ref": "#/$defs/ConcreteHI1Object"') + json_string = json_string.replace( + '"$ref": "#/$defs/HI1Object"', '"$ref": "#/$defs/ConcreteHI1Object"' + ) - with open(str(js_path), 'w', newline='\n') as f: + with open(str(js_path), "w", newline="\n") as f: f.write(json_string) - json_schemas[js['$id']] = json.loads(json_string) + json_schemas[js["$id"]] = json.loads(json_string) diff --git a/utils/ts103120_config.json b/utils/ts103120_config.json index 00043ffc2d594bc62e0304b99e9215364eb94a1a..6a89326662617d392906b85b6719b9203beaae44 100644 --- a/utils/ts103120_config.json +++ b/utils/ts103120_config.json @@ -1,43 +1,42 @@ { - "schemas" : { - "./103120/dictionaries/ts_103120_Dictionaries.xsd" : { - "prefix" : "dictionaries", - "output" : "./103120/dictionaries/" - }, - "./103120/schema/xsd/ts_103120_Authorisation.xsd" : { - "prefix" : "auth" - }, - "./103120/schema/xsd/ts_103120_Common.xsd" : { - "prefix" : "common" - }, - "./103120/schema/xsd/ts_103120_Config.xsd" : { - "prefix" : "config" - }, - "./103120/schema/xsd/ts_103120_Core.xsd" : { - }, - "./103120/schema/xsd/ts_103120_Delivery.xsd" : { - "prefix" : "delivery" - }, - "./103120/schema/xsd/ts_103120_Document.xsd" : { - "prefix" : "doc" - }, - "./103120/schema/xsd/ts_103120_Notification.xsd" : { - "prefix" : "notification" - }, - "./103120/schema/xsd/ts_103120_Task.xsd" : { - "prefix" : "task" - }, - "./103120/schema/xsd/ts_103120_TrafficPolicy.xsd" : { - "prefix" : "tp" - }, - "./103280/TS_103_280.xsd" : { - "prefix" : "etsi280", - "skip" : true - }, - "./testing/deps/xmldsig/xmldsig-core-schema.xsd" : { - "prefix" : "xmldsig", - "skip" : true - } - }, - "output" : "./103120/schema/json/" + "schemas": { + "./103120/dictionaries/ts_103120_Dictionaries.xsd": { + "prefix": "dictionaries", + "output": "./103120/dictionaries/" + }, + "./103120/schema/xsd/ts_103120_Authorisation.xsd": { + "prefix": "auth" + }, + "./103120/schema/xsd/ts_103120_Common.xsd": { + "prefix": "common" + }, + "./103120/schema/xsd/ts_103120_Config.xsd": { + "prefix": "config" + }, + "./103120/schema/xsd/ts_103120_Core.xsd": {}, + "./103120/schema/xsd/ts_103120_Delivery.xsd": { + "prefix": "delivery" + }, + "./103120/schema/xsd/ts_103120_Document.xsd": { + "prefix": "doc" + }, + "./103120/schema/xsd/ts_103120_Notification.xsd": { + "prefix": "notification" + }, + "./103120/schema/xsd/ts_103120_Task.xsd": { + "prefix": "task" + }, + "./103120/schema/xsd/ts_103120_TrafficPolicy.xsd": { + "prefix": "tp" + }, + "./103280/TS_103_280.xsd": { + "prefix": "etsi280", + "skip": true + }, + "./testing/deps/xmldsig/xmldsig-core-schema.xsd": { + "prefix": "xmldsig", + "skip": true + } + }, + "output": "./103120/schema/json/" } diff --git a/utils/ts103280_config.json b/utils/ts103280_config.json index d36a86ebc4c83efe4ce623e60f06d76c4beb7953..cdbb5199766e3457e87dcb9c8e8fad9a7fb41a58 100644 --- a/utils/ts103280_config.json +++ b/utils/ts103280_config.json @@ -1,8 +1,8 @@ { - "schemas" : { - "./103280/TS_103_280.xsd" : { - "prefix" : "etsi280" - } - }, - "output" : "./103280/" + "schemas": { + "./103280/TS_103_280.xsd": { + "prefix": "etsi280" + } + }, + "output": "./103280/" } diff --git a/utils/verify_json.py b/utils/verify_json.py index 329c0692499ee7fd5bc4c36b81e1cebabc3d9d68..5f7408017e872ff6f7c8f9c38ab557b45a41751f 100644 --- a/utils/verify_json.py +++ b/utils/verify_json.py @@ -1,4 +1,3 @@ - import argparse import sys import logging @@ -11,8 +10,19 @@ import json if __name__ == "__main__": parser = argparse.ArgumentParser() - parser.add_argument('-v', '--verbose', action='count', help='Verbose logging (can be specified multiple times)') - parser.add_argument('-i', '--input', type=argparse.FileType('r'), default=sys.stdin, help="Path to input file (if absent, stdin is used)") + parser.add_argument( + "-v", + "--verbose", + action="count", + help="Verbose logging (can be specified multiple times)", + ) + parser.add_argument( + "-i", + "--input", + type=argparse.FileType("r"), + default=sys.stdin, + help="Path to input file (if absent, stdin is used)", + ) args = parser.parse_args() match args.verbose: @@ -27,28 +37,30 @@ if __name__ == "__main__": signed_json_text = args.input.read() args.input.close() - + j = json.loads(signed_json_text) - - protected_header = j['Signature']['protected'] - signature = j['Signature']['signature'] + + protected_header = j["Signature"]["protected"] + signature = j["Signature"]["signature"] # TODO some safety checks needed here # Remove the newline that appears from the console - if signed_json_text.endswith('\n'): signed_json_text = signed_json_text[:-1] - signed_json_text = signed_json_text.replace(protected_header, "").replace(signature, "") - - payload_bytes = signed_json_text.encode('utf-8') - payload_token = base64.b64encode(payload_bytes).decode('ascii') + if signed_json_text.endswith("\n"): + signed_json_text = signed_json_text[:-1] + signed_json_text = signed_json_text.replace(protected_header, "").replace( + signature, "" + ) + + payload_bytes = signed_json_text.encode("utf-8") + payload_token = base64.b64encode(payload_bytes).decode("ascii") # Un-pad the token, as per RFC7515 annex C - payload_token = payload_token.split('=')[0] - payload_token = payload_token.replace('+','-') - payload_token = payload_token.replace('/','_') + payload_token = payload_token.split("=")[0] + payload_token = payload_token.replace("+", "-") + payload_token = payload_token.replace("/", "_") token = protected_header + "." + payload_token + "." + signature - result = jws.verify(token, key="secret_key", algorithms=['HS256']) - + result = jws.verify(token, key="secret_key", algorithms=["HS256"]) + print("Signature verified") - diff --git a/utils/xml_to_json.py b/utils/xml_to_json.py index 66f4fe1d707c5dada9daea1bdba0685f0ea69d7a..74c20f63184286ecd80c59e9b7f004db162bdb48 100644 --- a/utils/xml_to_json.py +++ b/utils/xml_to_json.py @@ -9,97 +9,99 @@ import xmltodict import argparse -def extract_prefixes (d): - return { k.split(':')[1]: d[k] for k in d.keys() if k.startswith("@xmlns:") } +def extract_prefixes(d): + return {k.split(":")[1]: d[k] for k in d.keys() if k.startswith("@xmlns:")} -def removePrefixes (o, prefixes): - if not isinstance(o, dict): return + +def removePrefixes(o, prefixes): + if not isinstance(o, dict): + return replacements = [] - for k,v in o.items(): + for k, v in o.items(): if isinstance(v, dict): removePrefixes(v, prefixes) if isinstance(v, list): for i in v: removePrefixes(i, prefixes) if ":" in k: - prefix = k.split(':')[0] + prefix = k.split(":")[0] if (prefix) in prefixes: - new_key = k.split(':')[1] - replacements.append( (k, new_key) ) + new_key = k.split(":")[1] + replacements.append((k, new_key)) for r in replacements: o[r[1]] = o.pop(r[0]) + object_namespaces = { - 'AuthorisationObject' : 'http://uri.etsi.org/03120/common/2020/09/Authorisation', - 'DeliveryObject' : 'http://uri.etsi.org/03120/common/2019/10/Delivery', - 'DocumentObject' : 'http://uri.etsi.org/03120/common/2020/09/Document', - 'NotificationObject' : 'http://uri.etsi.org/03120/common/2016/02/Notification', - 'LITaskObject' : 'http://uri.etsi.org/03120/common/2020/09/Task', - 'LPTaskObject' : 'http://uri.etsi.org/03120/common/2020/09/Task', - 'LDTaskObject' : 'http://uri.etsi.org/03120/common/2020/09/Task', - 'TrafficPolicyObject' : 'http://uri.etsi.org/03120/common/2022/07/TrafficPolicy', - 'TrafficRuleObject' : 'http://uri.etsi.org/03120/common/2022/07/TrafficPolicy' + "AuthorisationObject": "http://uri.etsi.org/03120/common/2020/09/Authorisation", + "DeliveryObject": "http://uri.etsi.org/03120/common/2019/10/Delivery", + "DocumentObject": "http://uri.etsi.org/03120/common/2020/09/Document", + "NotificationObject": "http://uri.etsi.org/03120/common/2016/02/Notification", + "LITaskObject": "http://uri.etsi.org/03120/common/2020/09/Task", + "LPTaskObject": "http://uri.etsi.org/03120/common/2020/09/Task", + "LDTaskObject": "http://uri.etsi.org/03120/common/2020/09/Task", + "TrafficPolicyObject": "http://uri.etsi.org/03120/common/2022/07/TrafficPolicy", + "TrafficRuleObject": "http://uri.etsi.org/03120/common/2022/07/TrafficPolicy", } coerce_to_list = [ - 'auth:AuthorisationApprovalDetails', - 'auth:AuthorisationFlag', - 'auth:CSPID', - 'common:ApproverContactDetails', - 'ActionRequest', - 'ActionResponse', - 'ListResponseRecord', - 'AssociatedObject', - 'doc:DocumentSignature', - 'doc:DocumentProperty', - 'notification:AssociatedObjectStatus', - 'task:ApprovalDetails', - 'task:TargetIdentifierValue', - 'task:DeliveryDestination', - 'task:TaskFlag', - 'task:AlternativePreservationReference', - 'task:ApprovalDetails', - 'task:ObservedTimes', - 'task:RequestValue', - 'task:RequestSubtype', - 'task:LDDeliveryDestination', - 'task:LDTaskFlag', - 'task:TrafficPolicyReference', - 'tp:TrafficRuleReference', - 'tp:Criteria', - 'common:DictionaryEntry', - 'dictionaries:Dictionary', - 'config:TargetFormatTypeDefinitionEntry', - 'config:SupportedLIWorkflowEndpoint', - 'config:SupportedLPWorkflowEndpoint', + "auth:AuthorisationApprovalDetails", + "auth:AuthorisationFlag", + "auth:CSPID", + "common:ApproverContactDetails", + "ActionRequest", + "ActionResponse", + "ListResponseRecord", + "AssociatedObject", + "doc:DocumentSignature", + "doc:DocumentProperty", + "notification:AssociatedObjectStatus", + "task:ApprovalDetails", + "task:TargetIdentifierValue", + "task:DeliveryDestination", + "task:TaskFlag", + "task:AlternativePreservationReference", + "task:ApprovalDetails", + "task:ObservedTimes", + "task:RequestValue", + "task:RequestSubtype", + "task:LDDeliveryDestination", + "task:LDTaskFlag", + "task:TrafficPolicyReference", + "tp:TrafficRuleReference", + "tp:Criteria", + "common:DictionaryEntry", + "dictionaries:Dictionary", + "config:TargetFormatTypeDefinitionEntry", + "config:SupportedLIWorkflowEndpoint", + "config:SupportedLPWorkflowEndpoint", ] coerce_to_int = [ - 'ActionIdentifier', - 'delivery:SequenceNumber', - 'task:Order', - 'ErrorCode', - 'Generation', - 'tp:Order' + "ActionIdentifier", + "delivery:SequenceNumber", + "task:Order", + "ErrorCode", + "Generation", + "tp:Order", ] -coerce_to_bool = [ - 'delivery:LastSequence' -] +coerce_to_bool = ["delivery:LastSequence"] -coerce_to_empty = [ - 'GETCSPCONFIG' -] +coerce_to_empty = ["GETCSPCONFIG"] coerce_null_to_empty = [ - 'SupportedLIWorkflowEndpoints', - 'SupportedLPWorkflowEndpoints', - 'config:AssociatedLDRequestSubtypes', - 'config:AssociatedLPRequestSubtypes', - 'config:AssociatedLIRequestSubtypes', + "SupportedLIWorkflowEndpoints", + "SupportedLPWorkflowEndpoints", + "config:AssociatedLDRequestTypes", + "config:AssociatedLDRequestSubtypes", + "config:AssociatedLPRequestTypes", + "config:AssociatedLPRequestSubtypes", + "config:AssociatedLIServiceTypes", ] -def postprocessor (path, key, value): + +def postprocessor(path, key, value): if key == "@xsi:type": object_name = value.split(":")[-1] if object_name in object_namespaces.keys(): @@ -116,26 +118,38 @@ def postprocessor (path, key, value): return key, {} return key, value + def recursively_fix_traffic_policy_criteria(d: dict): if isinstance(d, dict): - if ("tp:Criteria" in d + if ( + "tp:Criteria" in d and isinstance(d["tp:Criteria"], list) and len(d["tp:Criteria"]) == 1 - ): - d["tp:Criteria"] = d["tp:Criteria"][0] + ): + d["tp:Criteria"] = d["tp:Criteria"][0] else: - for k,v in d.items(): + for k, v in d.items(): recursively_fix_traffic_policy_criteria(v) elif isinstance(d, list): for d_item in d: recursively_fix_traffic_policy_criteria(d_item) - if __name__ == "__main__": parser = argparse.ArgumentParser() - parser.add_argument('-v', '--verbose', action='count', help='Verbose logging (can be specified multiple times)') - parser.add_argument('-i', '--input', type=argparse.FileType('r'), default=sys.stdin, help="Path to input file (if absent, stdin is used)") + parser.add_argument( + "-v", + "--verbose", + action="count", + help="Verbose logging (can be specified multiple times)", + ) + parser.add_argument( + "-i", + "--input", + type=argparse.FileType("r"), + default=sys.stdin, + help="Path to input file (if absent, stdin is used)", + ) args = parser.parse_args() match args.verbose: @@ -153,10 +167,9 @@ if __name__ == "__main__": logging.debug(s) - d = xmltodict.parse(s, - force_list=tuple(coerce_to_list), - postprocessor=postprocessor - )['HI1Message'] + d = xmltodict.parse( + s, force_list=tuple(coerce_to_list), postprocessor=postprocessor + )["HI1Message"] # HACK # Needed because TrafficPolicy.xsd has two nested fields both called tp:Criteria