diff --git a/103705/config.json b/103705/config.json new file mode 100644 index 0000000000000000000000000000000000000000..6d4bac9703d396adc0b9d8c421bfa314d370e169 --- /dev/null +++ b/103705/config.json @@ -0,0 +1,58 @@ +[{ + "coreSchema" : "schema/response.schema.json", + "supportingSchemas" : [ + "../103280/TS_103_280.schema.json", + "examples/example1/csp_records.schema.json", + "schema/etsi_types.schema.json" + ], + "exampleFiles" : [ + "examples/example1/csp_results.json" + ] +}, +{ + "coreSchema" : "schema/response.schema.json", + "supportingSchemas" : [ + "../103280/TS_103_280.schema.json", + "examples/example2/csp_records.schema.json", + "examples/example2/csp_types.schema.json", + "schema/etsi_types.schema.json" + ], + "exampleFiles" : [ + "examples/example2/csp_results.json" + ] +}, +{ + "coreSchema" : "schema/response.schema.json", + "supportingSchemas" : [ + "../103280/TS_103_280.schema.json", + "examples/example3/csp_records.schema.json", + "examples/example3/csp_types.schema.json", + "schema/etsi_types.schema.json" + ], + "exampleFiles" : [ + "examples/example3/csp_results.json" + ] +}, +{ + "coreSchema" : "schema/response.schema.json", + "supportingSchemas" : [ + "../103280/TS_103_280.schema.json", + "examples/example4/csp_records.schema.json", + "examples/example4/csp_types.schema.json", + "schema/etsi_types.schema.json" + ], + "exampleFiles" : [ + "examples/example4/csp_results.json" + ] +}, +{ + "coreSchema" : "schema/response.schema.json", + "supportingSchemas" : [ + "../103280/TS_103_280.schema.json", + "examples/example5/csp_records.schema.json", + "schema/etsi_types.schema.json" + ], + "exampleFiles" : [ + "examples/example5/csp_results.json" + ] +}] \ No newline at end of file diff --git a/103705/examples/example1/csp_records.schema.json b/103705/examples/example1/csp_records.schema.json new file mode 100644 index 0000000000000000000000000000000000000000..344b4e39147a078eff78a10c72d521cd3680b01b --- /dev/null +++ b/103705/examples/example1/csp_records.schema.json @@ -0,0 +1,25 @@ +{ + "$id": "urn:etsi:li:103705:record-schema-id:v1.1.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)", + "cspSchemaID" : "csp.example_1", + "cspName" : "csp.example.com", + "dateIssued" : "2024-04-024T09:00:01Z", + "version" : "1.1.1", + "$defs": { + "record" : { + "oneOf" : [{ + "allOf" : [ + { "$ref" : "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/CallRecord" }, + { "properties" : { "type" : { "const" : "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/CallRecord"}}} + ]}, + { + "allOf" : [ + { "$ref" : "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/MessagingRecord" }, + { "properties" : { "type" : { "const" : "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/MessagingRecord"}}} + ]} + ] + } + } +} \ No newline at end of file diff --git a/103705/examples/example1/csp_results.json b/103705/examples/example1/csp_results.json new file mode 100644 index 0000000000000000000000000000000000000000..52dbe6fa744b1061b2c61b9d72bfbdf5bdde4f31 --- /dev/null +++ b/103705/examples/example1/csp_results.json @@ -0,0 +1,47 @@ +{ + "recordSetDescription": { + "etsiSchemaId": "urn:etsi:li:103705:response-schema-id:v1.1.1", + "etsiSpecificationVersion": "0.3.0", + "cspName" : "csp.example.com", + "cspSchemaId" : "csp.example_1", + "cspSchemaVersion" : "1.0.0", + "resultSetId": "9a25db0c-d0f3-4ae5-b618-bd1a9a0056c2", + "requestReference": "LDID", + "created": "2024-04-25T09:31:56.000000Z" + }, + "recordSet": [ + { + "id": "3da91ade-f526-4e55-b5da-0c8178f25c24", + "type": "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/CallRecord", + "timeBegin": "2024-04-20T10:04:00.000000Z", + "timeEnd": "2024-04-20T10:05:00.000000Z", + "endReason": 16, + "parties": [ + { + "identity": {"phoneNumber": "491713920067"}, + "role": "originating", + "initialAccessTechnology" : "5G" + }, + { + "identity": {"phoneNumber": "441632960123"}, + "role": "terminating" + } + ] + }, + { + "id": "8be3fc6b-a2dd-4104-9af1-d6b1f70081a0", + "type": "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/MessagingRecord", + "eventTime": "2024-04-18T10:04:00.000000Z", + "parties": [ + { + "identity": {"phoneNumber": "441632960123"}, + "role": "sender" + }, + { + "identity": {"phoneNumber": "491713920067"}, + "role": "receiver" + } + ] + } + ] +} \ No newline at end of file diff --git a/103705/examples/example1/description.txt b/103705/examples/example1/description.txt new file mode 100644 index 0000000000000000000000000000000000000000..1e567ac986b6950a401c97ec01708e9741c57c9a --- /dev/null +++ b/103705/examples/example1/description.txt @@ -0,0 +1,6 @@ +CSP elects to use only ETSI-standard types in their responses + +CSP imports the following types in their CSP record schema + +- InformationCall +- InformationMessaging diff --git a/103705/examples/example2/csp_records.schema.json b/103705/examples/example2/csp_records.schema.json new file mode 100644 index 0000000000000000000000000000000000000000..e5082c754250db03968366e6d0980c3575173819 --- /dev/null +++ b/103705/examples/example2/csp_records.schema.json @@ -0,0 +1,25 @@ +{ + "$id": "urn:etsi:li:103705:record-schema-id:v1.1.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)", + "cspSchemaID" : "csp.example_2", + "cspName" : "csp.example.com", + "dateIssued" : "2024-04-024T09:00:01Z", + "version" : "1.1.1", + "$defs": { + "record" : { + "oneOf" : [{ + "allOf" : [ + { "$ref" : "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/CallRecord" }, + { "properties" : { "type" : { "const" : "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/CallRecord"}}} + ]}, + { + "allOf" : [ + { "$ref" : "csp_example_types#/$defs/CSPMessagingRecord" }, + { "properties" : { "type" : { "const" : "csp_example_types#/$defs/CSPMessagingRecord"}}} + ]} + ] + } + } +} \ No newline at end of file diff --git a/103705/examples/example2/csp_results.json b/103705/examples/example2/csp_results.json new file mode 100644 index 0000000000000000000000000000000000000000..c4ff7c003080f2e33b344c7fb3d6d20e486a6c5f --- /dev/null +++ b/103705/examples/example2/csp_results.json @@ -0,0 +1,47 @@ +{ + "recordSetDescription": { + "etsiSchemaId": "urn:etsi:li:103705:response-schema-id:v1.1.1", + "etsiSpecificationVersion": "0.3.0", + "cspName" : "csp.example.com", + "cspSchemaId" : "csp.example_2", + "cspSchemaVersion" : "1.0.0", + "resultSetId": "9a25db0c-d0f3-4ae5-b618-bd1a9a0056c2", + "requestReference": "LDID", + "created": "2024-04-25T09:31:56.000000Z" + }, + "recordSet": [ + { + "id": "3da91ade-f526-4e55-b5da-0c8178f25c24", + "type": "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/CallRecord", + "timeBegin": "2024-04-20T10:04:00.000000Z", + "timeEnd": "2024-04-20T10:05:00.000000Z", + "endReason": 16, + "parties": [ + { + "identity": {"phoneNumber": "491713920067"}, + "role": "originating" + }, + { + "identity": {"phoneNumber": "441632960123"}, + "role": "terminating" + } + ] + }, + { + "id": "8be3fc6b-a2dd-4104-9af1-d6b1f70081a0", + "type": "csp_example_types#/$defs/CSPMessagingRecord", + "eventTime": "2024-04-18T10:04:00.000000Z", + "parties": [ + { + "identity": {"phoneNumber": "441632960123"}, + "role": "sender" + }, + { + "identity": {"phoneNumber": "491713920067"}, + "role": "receiver" + } + ], + "CSPMessagingReference" : "0608972c-9080-4bb1-bc30-35b7cb731bbf" + } + ] +} \ No newline at end of file diff --git a/103705/examples/example2/csp_types.schema.json b/103705/examples/example2/csp_types.schema.json new file mode 100644 index 0000000000000000000000000000000000000000..4cf437d4ab5b4de387e17e58df0996866abcceb5 --- /dev/null +++ b/103705/examples/example2/csp_types.schema.json @@ -0,0 +1,14 @@ +{ + "$id": "csp_example_types", + "$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)", + "$defs": { + "CSPMessagingRecord" : { + "allOf" : [{ "$ref" : "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/MessagingRecord"}], + "properties" : { + "CSPMessagingReference" : { "$ref" : "ts_103280_2017_07#/$defs/UUID"} + } + } + } +} \ No newline at end of file diff --git a/103705/examples/example2/description.txt b/103705/examples/example2/description.txt new file mode 100644 index 0000000000000000000000000000000000000000..1b22fdf05b1a63328e1239ab9b68cb6a79372ad7 --- /dev/null +++ b/103705/examples/example2/description.txt @@ -0,0 +1,8 @@ +CSP uses the standard ETSI InformationCall record. + +For messaging the CSP can use the ETSI standard messaging format, +but they can also always provide a unique CSP-specific UUID for every message event. +The CSP extends the ETSI standard Messaging record by adding a single field + +- InformationCall +- CSPInformationMessaging diff --git a/103705/examples/example3/csp_records.schema.json b/103705/examples/example3/csp_records.schema.json new file mode 100644 index 0000000000000000000000000000000000000000..fca8fa5fdee56486697f186203b1da4eaaf4a95f --- /dev/null +++ b/103705/examples/example3/csp_records.schema.json @@ -0,0 +1,25 @@ +{ + "$id": "urn:etsi:li:103705:record-schema-id:v1.1.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)", + "cspSchemaID" : "csp.example_3", + "cspName" : "csp.example.com", + "dateIssued" : "2024-04-024T09:00:01Z", + "version" : "1.1.1", + "$defs": { + "record" : { + "oneOf" : [{ + "allOf" : [ + { "$ref" : "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/CallRecord" }, + { "properties" : { "type" : { "const" : "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/CallRecord"}}} + ]}, + { + "allOf" : [ + { "$ref" : "csp_example_types#/$defs/CSPServiceRecord" }, + { "properties" : { "type" : { "const" : "csp_example_types#/$defs/CSPServiceRecord"}}} + ]} + ] + } + } +} \ No newline at end of file diff --git a/103705/examples/example3/csp_results.json b/103705/examples/example3/csp_results.json new file mode 100644 index 0000000000000000000000000000000000000000..8f2f9edb52f81aec15eb2c3d37eeb1837c5cbca3 --- /dev/null +++ b/103705/examples/example3/csp_results.json @@ -0,0 +1,38 @@ +{ + "recordSetDescription": { + "etsiSchemaId": "urn:etsi:li:103705:response-schema-id:v1.1.1", + "etsiSpecificationVersion": "0.3.0", + "cspName" : "csp.example.com", + "cspSchemaId" : "csp.example_3", + "cspSchemaVersion" : "1.0.0", + "resultSetId": "9a25db0c-d0f3-4ae5-b618-bd1a9a0056c2", + "requestReference": "LDID", + "created": "2024-04-25T09:31:56.000000Z" + }, + "recordSet": [ + { + "id": "3da91ade-f526-4e55-b5da-0c8178f25c24", + "type": "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/CallRecord", + "timeBegin": "2024-04-20T10:04:00.000000Z", + "timeEnd": "2024-04-20T10:05:00.000000Z", + "endReason": 16, + "parties": [ + { + "identity": {"phoneNumber": "491713920067"}, + "role": "originating" + }, + { + "identity": {"phoneNumber": "441632960123"}, + "role": "terminating" + } + ] + }, + { + "id": "8be3fc6b-a2dd-4104-9af1-d6b1f70081a0", + "type": "csp_example_types#/$defs/CSPServiceRecord", + "timeOfService": "2024-04-18T10:04:00.000000Z", + "numberOfService" : 7, + "serviceEnum" : "Foo" + } + ] +} \ No newline at end of file diff --git a/103705/examples/example3/csp_types.schema.json b/103705/examples/example3/csp_types.schema.json new file mode 100644 index 0000000000000000000000000000000000000000..fde0bf8c21b806d885bb9f77c28445a50cd080e3 --- /dev/null +++ b/103705/examples/example3/csp_types.schema.json @@ -0,0 +1,38 @@ +{ + "$id": "csp_example_types", + "$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)", + "$defs": { + "CSPServiceRecord" : { + "type" : "object", + "title" : "CSP Service Record", + "description" : "Information about some new fictional service that this CSP provides", + "properties" : { + "timeOfService" : { + "description" : "Time at which something happened (using an ETSI TS 103 280 type)", + "$ref" : "ts_103280_2017_07#/$defs/QualifiedMicrosecondDateTime" + }, + "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" + }, + "numberOfService" : { + "description" : "Some number associated with this service record (using a native JSON type)", + "type" : "integer" + }, + "serviceEnum" : { + "description" : "A field using a type defined elsewhere in this schema", + "$ref" : "#/$defs/CSPDefinedEnum" + } + } + }, + "CSPDefinedEnum" : { + "enum" : [ + "Foo", + "Bar", + "Baz" + ] + } + } +} \ No newline at end of file diff --git a/103705/examples/example3/description.txt b/103705/examples/example3/description.txt new file mode 100644 index 0000000000000000000000000000000000000000..a72d3ca455d41b46e806583614cd6d4233f6feb7 --- /dev/null +++ b/103705/examples/example3/description.txt @@ -0,0 +1,8 @@ +CSP uses the standard ETSI InformationCall record. + +The CSP has some novel service which is not well described by any of the standard +ETSI records; the CSP defines a completely new record, but can still re-use components +from TS 103 705 and TS 103 280. + +- InformationCall +- CSPServiceRecord diff --git a/103705/examples/example4/csp_records.schema.json b/103705/examples/example4/csp_records.schema.json new file mode 100644 index 0000000000000000000000000000000000000000..a17867055747a328e128fa6093540d0529cd3ba6 --- /dev/null +++ b/103705/examples/example4/csp_records.schema.json @@ -0,0 +1,24 @@ +{ + "$id": "urn:etsi:li:103705:record-schema-id:v1.1.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)", + "cspSchemaID" : "csp.example_4", + "cspName" : "csp.example.com", + "dateIssued" : "2024-04-024T09:00:01Z", + "version" : "1.1.1", + "$defs": { + "record" : { + "oneOf" : [{ + "allOf" : [ + { "$ref" : "csp_example_types#/$defs/CSPSubscriberRecord" }, + { "properties" : { "type" : { "const" : "csp_example_types#/$defs/CSPSubscriberRecord"}}} + ]},{ + "allOf" : [ + { "$ref" : "csp_example_types#/$defs/CSPAddressRecord" }, + { "properties" : { "type" : { "const" : "csp_example_types#/$defs/CSPAddressRecord"}}} + ]} + ] + } + } +} \ No newline at end of file diff --git a/103705/examples/example4/csp_results.json b/103705/examples/example4/csp_results.json new file mode 100644 index 0000000000000000000000000000000000000000..fd290b155bc18ab7a33f9e1a2a32160e2ea2ceb3 --- /dev/null +++ b/103705/examples/example4/csp_results.json @@ -0,0 +1,31 @@ +{ + "recordSetDescription": { + "etsiSchemaId": "urn:etsi:li:103705:response-schema-id:v1.1.1", + "etsiSpecificationVersion": "0.3.0", + "cspName" : "csp.example.com", + "cspSchemaId" : "csp.example_4", + "cspSchemaVersion" : "1.0.0", + "resultSetId": "9a25db0c-d0f3-4ae5-b618-bd1a9a0056c2", + "requestReference": "LDID", + "created": "2024-04-25T09:31:56.000000Z" + }, + "recordSet": [ + { + "id": "3da91ade-f526-4e55-b5da-0c8178f25c24", + "type": "csp_example_types#/$defs/CSPSubscriberRecord", + "subscriberName" : "Max Mustermann", + "registeredAddress" : { "destination" : "8be3fc6b-a2dd-4104-9af1-d6b1f70081a0" }, + "deliveryAddress" : { "destination" : "8be3fc6b-a2dd-4104-9af1-d6b1f70081a0" }, + "billingAddress" : { "destination" : "8be3fc6b-a2dd-4104-9af1-d6b1f70081a0" }, + "contactAddress" : { "destination" : "8be3fc6b-a2dd-4104-9af1-d6b1f70081a0" } + }, + { + "id": "8be3fc6b-a2dd-4104-9af1-d6b1f70081a0", + "type": "csp_example_types#/$defs/CSPAddressRecord", + "line1" : "First Line Of Address", + "line2" : "Secoond Line Of Address", + "postalCode" : "postal code", + "country" : "country code" + } + ] +} \ No newline at end of file diff --git a/103705/examples/example4/csp_types.schema.json b/103705/examples/example4/csp_types.schema.json new file mode 100644 index 0000000000000000000000000000000000000000..8fee961b7654929e0f25df7277a02cf26bc00c41 --- /dev/null +++ b/103705/examples/example4/csp_types.schema.json @@ -0,0 +1,46 @@ +{ + "$id": "csp_example_types", + "$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)", + "$defs": { + "CSPSubscriberRecord" : { + "type" : "object", + "title" : "CSP Subscriber Record", + "description" : "A CSP's subscriber record. May contain four different addresses, which are often set to the same value", + "properties" : { + "subscriberName" : { + "description" : "Name of subscriber (obviously a real definition would be more complex", + "type" : "string" + }, + "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" + }, + "deliveryAddress" : { + "description" : "Points to the address used for delivery", + "$ref" : "urn:etsi:li:103705:type-schema-id:v1.1.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" + }, + "contactAddress" : { + "description" : "Points to the address used for mailing purposes", + "$ref" : "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/Pointer" + } + } + }, + "CSPAddressRecord" : { + "type" : "object", + "title" : "CSP Address Record", + "description" : "A simple address structure (for example purporses - a standard ETSI one is needed, FFS)", + "properties" : { + "line1" : { "type" : "string"}, + "line2" : { "type" : "string"}, + "postalCode" : { "type" : "string"}, + "country" : { "type" : "string"} + } + } + } +} \ No newline at end of file diff --git a/103705/examples/example4/description.txt b/103705/examples/example4/description.txt new file mode 100644 index 0000000000000000000000000000000000000000..ae4259c054a33d5a54a496edef30d3d0c6916e00 --- /dev/null +++ b/103705/examples/example4/description.txt @@ -0,0 +1,12 @@ +CSP wants to create a simple subsciber record structure +(side note - at the moment we don't have that in the standard schema, but it is likely to come later) +The subscriber can have a number of different addresses (e.g. contact, billing, delivery, installed) +but they are often all set to the same value. To reduce the amount of repetition, +the CSP uses the Pointer record + +- CSPSubscriberRecord +- CSPAddressRecord + + +Number for reply LS? from 40408 5GSAT_Ph3_Arch +477 \ No newline at end of file diff --git a/103705/examples/example5/csp_records.schema.json b/103705/examples/example5/csp_records.schema.json new file mode 100644 index 0000000000000000000000000000000000000000..0e8ffaf20f665a2b51a72d610dc672d35ff98313 --- /dev/null +++ b/103705/examples/example5/csp_records.schema.json @@ -0,0 +1,25 @@ +{ + "$id": "urn:etsi:li:103705:record-schema-id:v1.1.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)", + "cspSchemaID" : "csp.example_5", + "cspName" : "csp.example.com", + "dateIssued" : "2024-06-20 09:42:37", + "version" : "1.1.1", + "$defs": { + "record" : { + "oneOf" : [{ + "allOf" : [ + { "$ref" : "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/CallRecord" }, + { "properties" : { "type" : { "const" : "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/CallRecord"}}} + ]}, + { + "allOf" : [ + { "$ref" : "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/MessagingRecord" }, + { "properties" : { "type" : { "const" : "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/MessagingRecord"}}} + ]} + ] + } + } +} \ No newline at end of file diff --git a/103705/examples/example5/csp_results.json b/103705/examples/example5/csp_results.json new file mode 100644 index 0000000000000000000000000000000000000000..f8c81d9aaa76e0281bef317fca2cd437475e4292 --- /dev/null +++ b/103705/examples/example5/csp_results.json @@ -0,0 +1 @@ +{"recordSetDescription": {"etsiSchemaId": "urn:etsi:li:103705:response-schema-id:v1.1.1", "etsiSpecificationVersion": "0.3.0", "cspName" : "csp.example.com", "cspSchemaId": "csp.example_1", "cspSchemaVersion": "1.0.0", "resultSetId": "9a25db0c-d0f3-4ae5-b618-bd1a9a0056c2", "requestReference": "LDID", "created": "2024-04-25T09:31:56.000000Z"}, "recordSet": [{"id": "3da91ade-f526-4e55-b5da-0c8178f25c24", "type": "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/CallRecord", "timeBegin": "2024-04-20T10:04:00.000000Z", "timeEnd": "2024-04-20T10:05:00.000000Z", "endReason": 16, "parties": [{"identity": {"phoneNumber": "491713920067"}, "role": "originating"}, {"identity": {"phoneNumber": "441632960123"}, "role": "terminating"}]}, {"id": "8be3fc6b-a2dd-4104-9af1-d6b1f70081a0", "type": "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/MessagingRecord", "eventTime": "2024-04-18T10:04:00.000000Z", "parties": [{"identity": {"phoneNumber": "441632960123"}, "role": "sender"}, {"identity": {"phoneNumber": "491713920067"}, "role": "receiver"}]}], "Signature": {"protected": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9", "signature": "yvPyjRDAS7dSld9inyVfLpz02En47_AMq0J8cP82BCU"}} diff --git a/103705/examples/example5/description.txt b/103705/examples/example5/description.txt new file mode 100644 index 0000000000000000000000000000000000000000..9e8da6beced9b152914550e48dd1c56c38e5d925 --- /dev/null +++ b/103705/examples/example5/description.txt @@ -0,0 +1,6 @@ +CSP elects to use only ETSI-standard types in their responses, but includes a signature + +CSP imports the following types in their CSP record schema + +- InformationCall +- InformationMessaging diff --git a/103705/schema/etsi_types.schema.json b/103705/schema/etsi_types.schema.json new file mode 100644 index 0000000000000000000000000000000000000000..1854183d6941dd2888dd27a9f88cad1a8197b0c9 --- /dev/null +++ b/103705/schema/etsi_types.schema.json @@ -0,0 +1,411 @@ +{ + "$id": "urn:etsi:li:103705:type-schema-id:v1.1.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)", + "$defs": { + "Pointer": { + "type": "object", + "title": "Pointer", + "description": "Allows one Record in a RecordSet to point to data in another Record in the same Recordset. See clause 5.4 and Annex A.2.2", + "properties": { + "destination": { + "type": "string", + "title": "Pointer Destination", + "description": "Identifies the Record in the RecordSet containined the referred-to data (see clause 5.3.2 and A.2.2)" + }, + "relationship": { + "type": "string", + "title": "Relationship", + "description": "Indicates the nature of the relationship. Valid values and their meaning should be provided by the CSP" + } + }, + "required": [ + "destination" + ] + }, + "CallRecord": { + "type": "object", + "title": "Information about call details", + "description": "Details about a record or event related to a call", + "required": [ + "timeBegin", "parties" + ], + "properties": { + "sessionRefId": { + "type": "string", + "description": "A reference identifier to uniquely identify the telephony call" + }, + "timeBegin": { + "$ref": "ts_103280_2017_07#/$defs/QualifiedMicrosecondDateTime", + "description": "Time at which the call began" + }, + "timeEnd": { + "$ref": "ts_103280_2017_07#/$defs/QualifiedMicrosecondDateTime", + "description": "Time at which the call ended" + }, + "callDuration": { + "type": "integer", + "description": "Chargeable duration of the call in seconds" + }, + "ringingDuration": { + "type": "integer", + "description": "Non-chargeable duration of the call in seconds" + }, + "parties": { + "type": "array", + "items": { + "$ref": "#/$defs/CallPartyInformation" + } + }, + "endReason": { + "type": "integer", + "description": "ITU Q.850" + } + } + }, + "MessagingRecord": { + "type": "object", + "title": "Information about messaging details", + "description": "Details about a record or event related to a message", + "required": [ + "eventTime", "parties" + ], + "properties": { + "sessionRefId": { + "type": "string", + "description": "A reference identifier to uniquely identify the message" + }, + "eventTime": { + "$ref": "ts_103280_2017_07#/$defs/QualifiedMicrosecondDateTime", + "description": "Time at which the event happened" + }, + "parties": { + "type": "array", + "items": { + "$ref": "#/$defs/MessagingPartyInformation" + } + } + } + }, + "EmailRecord": { + "type": "object", + "title": "Information about email details", + "description": "Details about a record or event related to an email", + "required": [ + "eventTime", "parties" + ], + "properties": { + "sessionRefId": { + "type": "string", + "description": "A reference identifier to uniquely identify the message" + }, + "eventTime": { + "$ref": "ts_103280_2017_07#/$defs/QualifiedMicrosecondDateTime", + "description": "Time at which the event happened" + }, + "parties": { + "type": "array", + "items": { + "$ref": "#/$defs/EmailPartyInformation" + } + } + } + }, + "DataAccessRecord": { + "type": "object", + "title": "Data Record", + "description": "Information about a data access session (e.g. a mobile data session)", + "required": [ + "timeBegin", "parties" + ], + "properties": { + "sessionRefId": { + "type": "string", + "description": "A reference identifier to uniquely identify the message" + }, + "timeBegin": { + "$ref": "ts_103280_2017_07#/$defs/QualifiedMicrosecondDateTime", + "description": "Time at which the data access session began" + }, + "timeEnd": { + "$ref": "ts_103280_2017_07#/$defs/QualifiedMicrosecondDateTime", + "description": "Time at which the data access session ended" + }, + "parties": { + "type": "array", + "items": { + "$ref": "#/$defs/DataAccessPartyInformation" + } + }, + "volume": { + "$ref": "#/$defs/DataVolume" + } + } + }, + "CallPartyInformation": { + "type": "object", + "description" : "Information about the participants and technologies related to the call", + "properties": { + "identity": { + "$ref": "#/$defs/CallPartyId" + }, + "role": { + "enum": [ + "originating", + "terminating", + "forwarding", + "unknown" + ] + }, + "initialAccessTechnology": { + "$ref": "#/$defs/AccessTechnology", + "description": "Access technology used at the start of the call" + }, + "locations": { + "type": "array", + "items": { + "$ref": "#/$defs/Location" + } + } + } + }, + "MessagingPartyInformation": { + "type": "object", + "description": "Information about the participants and technologies related to the messages", + "properties": { + "identity": { + "$ref": "#/$defs/MessagingPartyId" + }, + "role": { + "enum": [ + "sender", + "receiver" + ] + }, + "accessTechnology": { + "$ref": "#/$defs/AccessTechnology", + "description": "Access technology used" + }, + "locations": { + "type": "array", + "items": { + "$ref": "#/$defs/Location" + } + } + } + }, + "EmailPartyInformation": { + "type": "object", + "description": "Information about the participants and technologies related to the messages", + "properties": { + "identity": { + "$ref": "#/$defs/EmailPartyId" + }, + "role": { + "enum": [ + "sender", + "receiver" + ] + }, + "accessTechnology": { + "$ref": "#/$defs/AccessTechnology", + "description": "Access technology used" + }, + "locations": { + "type": "array", + "items": { + "$ref": "#/$defs/Location" + } + } + } + }, + "DataAccessPartyInformation": { + "type": "object", + "description": "Information about the participants and technologies related to the data service", + "properties": { + "identity": { + "$ref": "#/$defs/DataAccessPartyId" + }, + "aPNDNN": { + "description" : "APN or DNN associated with the data access", + "$ref": "ts_103280_2017_07#/$defs/DNN" + }, + "initialAccessTechnology": { + "$ref": "#/$defs/AccessTechnology", + "description": "Access technology used at the start of the data access session" + }, + "locations": { + "type": "array", + "items": { + "$ref": "#/$defs/Location" + } + } + } + }, + "CallPartyId": { + "type": "object", + "description": "Identifier of the party related to the call", + "properties": { + "phoneNumber": { + "$ref": "ts_103280_2017_07#/$defs/InternationalE164" + }, + "iMSI": { + "$ref": "ts_103280_2017_07#/$defs/IMSI" + }, + "iMEI": { + "$ref": "ts_103280_2017_07#/$defs/IMEI" + }, + "sIPURI": { + "$ref": "ts_103280_2017_07#/$defs/SIPURI" + }, + "tELURI": { + "$ref": "ts_103280_2017_07#/$defs/TELURI" + }, + "unstructuredPhoneNumber": { + "type": "string" + } + } + }, + "MessagingPartyId": { + "type": "object", + "description": "Identifier of the party related to the message", + "properties": { + "phoneNumber": { + "$ref": "ts_103280_2017_07#/$defs/InternationalE164" + }, + "iMSI": { + "$ref": "ts_103280_2017_07#/$defs/IMSI" + }, + "iMEI": { + "$ref": "ts_103280_2017_07#/$defs/IMEI" + }, + "sIPURI": { + "$ref": "ts_103280_2017_07#/$defs/SIPURI" + }, + "tELURI": { + "$ref": "ts_103280_2017_07#/$defs/TELURI" + }, + "unstructuredPhoneNumber": { + "type": "string" + } + } + }, + "EmailPartyId": { + "type": "object", + "description": "Identifier of the party related to the message", + "properties": { + "emailAddress": { + "$ref": "ts_103280_2017_07#/$defs/EmailAddress" + }, + "iPv4Address": { + "$ref": "ts_103280_2017_07#/$defs/IPv4Address" + }, + "iPv6Address": { + "$ref": "ts_103280_2017_07#/$defs/IPv6Address" + } + } + }, + "DataAccessPartyId": { + "type": "object", + "description": "Identifier of the party related to the data service", + "properties": { + "phoneNumber": { + "$ref": "ts_103280_2017_07#/$defs/InternationalE164" + }, + "iMSI": { + "$ref": "ts_103280_2017_07#/$defs/IMSI" + }, + "iMEI": { + "$ref": "ts_103280_2017_07#/$defs/IMEI" + }, + "sUPIIMSI": { + "$ref": "ts_103280_2017_07#/$defs/SUPIIMSI" + }, + "sUPINAI": { + "$ref": "ts_103280_2017_07#/$defs/SUPINAI" + }, + "sUCI": { + "$ref": "ts_103280_2017_07#/$defs/SUCI" + }, + "pEIIMEI": { + "$ref": "ts_103280_2017_07#/$defs/PEIIMEI" + }, + "iPv4Address": { + "$ref": "ts_103280_2017_07#/$defs/IPv4Address" + }, + "iPv4CIDR": { + "$ref": "ts_103280_2017_07#/$defs/IPv4CIDR" + }, + "iPv6Address": { + "$ref": "ts_103280_2017_07#/$defs/IPv6Address" + }, + "iPv6CIDR": { + "$ref": "ts_103280_2017_07#/$defs/IPv6CIDR" + }, + "mACAddress": { + "$ref": "ts_103280_2017_07#/$defs/MACAddress" + }, + "unstructuredPhoneNumber": { + "type": "string" + } + } + }, + "DataVolume": { + "type": "object", + "description": "quantification of the bytes exchanged", + "properties": { + "bytesUpload": { + "type": "integer" + }, + "bytesDownload": { + "type": "integer" + }, + "bytesTotal": { + "type": "integer" + } + } + }, + "AccessTechnology": { + "description": "Access technology used", + "enum": [ + "2G", + "3G", + "4G", + "5G", + "fiber", + "cable", + "wifi", + "xDSL", + "pstn" + ] + }, + "Location": { + "type": "object", + "description": "Location information", + "properties": { + "cGI": { + "$ref": "ts_103280_2017_07#/$defs/CGI" + }, + "eCGI": { + "$ref": "ts_103280_2017_07#/$defs/ECGI" + }, + "nCGI": { + "$ref": "ts_103280_2017_07#/$defs/NCGI" + }, + "modemMAC": { + "$ref": "ts_103280_2017_07#/$defs/MACAddress" + }, + "coord": { + "$ref": "ts_103280_2017_07#/$defs/WGS84CoordinateDecimal" + }, + "coordPolygon": { + "type": "array", + "items": { + "$ref": "ts_103280_2017_07#/$defs/WGS84CoordinateDecimal" + } + } + } + } + } +} diff --git a/103705/schema/records.schema.json b/103705/schema/records.schema.json new file mode 100644 index 0000000000000000000000000000000000000000..ab5970117df471170162867931cda99cffad9e03 --- /dev/null +++ b/103705/schema/records.schema.json @@ -0,0 +1,23 @@ +{ + "$id": "urn:etsi:li:103705:record-schema-id:v1.1.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)", + "cspName" : "{replace with assigned CSP name - see ETSI TS 103 705 Table 6.2.4-1", + "cspSchemaID" : "{replace with assigned ID - see ETSI TS 103 705 Table 6.2.4-1}", + "dateIssued" : "{replace with date issued - see ETSI TS 103 705 Table 6.2.4-1}", + "cspSchemaVersion" : "{Replace with version - see ETSI TS 103 705 Table 6.2.4-1}", + "$defs": { + "record" : { + "oneOf" : [ + { + "$comment" : "This is an example", + "allOf" : [ + { "$ref" : "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/CallRecord" }, + { "properties" : { "type" : { "const" : "urn:etsi:li:103705:type-schema-id:v1.1.1#/$defs/CallRecord"}}} + ] + } + ] + } + } +} \ No newline at end of file diff --git a/103705/schema/response.schema.json b/103705/schema/response.schema.json new file mode 100644 index 0000000000000000000000000000000000000000..2d6f8a0e0d4507cda3d9a589c55c5e14addb2440 --- /dev/null +++ b/103705/schema/response.schema.json @@ -0,0 +1,129 @@ +{ + "$id": "urn:etsi:li:103705:response-schema-id:v1.1.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)", + "type": "object", + "properties": { + "recordSetDescription": { + "$ref": "#/$defs/recordSetDescription" + }, + "recordSet": { + "$ref": "#/$defs/recordSet" + }, + "Signature": { + "$ref" : "#/$defs/Signature" + } + }, + "required": [ + "recordSetDescription", + "recordSet" + ], + "$defs": { + "recordSetDescription": { + "type": "object", + "title": "RecordSetDescription", + "description": "Provides metadata about the records being delivered (see clause 5.2)", + "properties": { + "etsiSchemaId": { + "description" : "ID of the ETSI JSON schema used by the Response (see clause 5.2.2)", + "$ref": "#/$defs/schemaId" + }, + "etsiSpecificationVersion": { + "description" : "Version of ETSI TS 103 705 used by the Response (see clause 5.2.3)", + "$ref": "#/$defs/version" + }, + "cspName" : { + "description" : "Identifies the CSP generating the Response (see clause 5.2.4)", + "$ref": "#/$defs/schemaId" + }, + "cspSchemaId" : { + "description" : "ID of CSP Record Schema used by the Response (see clause 5.2.5)", + "$ref": "#/$defs/schemaId" + }, + "cspSchemaVersion" : { + "description" : "Version number assigned by the CSP to the CSP Record Schema identified by the cspSchemaId (see clause 5.2.6)", + "$ref": "#/$defs/version" + }, + "resultSetId": { + "description" : "Unique identifier for this result set (see clause 5.2.7)", + "$ref": "#/$defs/resultSetId" + }, + "requestReference": { + "description" : "Reference to the original request (see clause 5.2.8)", + "$ref": "#/$defs/requestReference" + }, + "created": { + "description" : "Timestamp showing the creation time of the Response (see clause 5.2.9)", + "$ref": "ts_103280_2017_07#/$defs/QualifiedMicrosecondDateTime" + } + }, + "required": [ + "etsiSchemaId", + "etsiSpecificationVersion", + "cspName", + "cspSchemaId", + "cspSchemaVersion", + "resultSetId", + "requestReference", + "created" + ] + }, + "schemaId": { + "type": "string" + }, + "version": { + "type" : "string", + "pattern" : "^[0-9]+\\.[0-9]+\\.[0-9]+$" + }, + "resultSetId": { + "type": "string" + }, + "requestReference": { + "type": "string" + }, + "recordSet": { + "type": "array", + "title": "RecordSet", + "description": "RecordSet (see clause 5.3). Contains a set of Records.", + "items": { + "$ref": "#/$defs/record" + } + }, + "record": { + "allOf" : [{ "$ref" : "urn:etsi:li:103705:record-schema-id:v1.1.1#/$defs/record"}], + "type": "object", + "title": "Record", + "description": "Response record (see clause 5.3)", + "properties": { + "id": { + "title": "id", + "description": "Unique identifier for the Record within the RecordSet (see clause 5.3.2).", + "type": "string" + }, + "type": { + "title": "type", + "description": "A JSON Pointer to the schema definition that defines the type (see clause 5.3.3)" + } + }, + "required": [ + "id", + "type" + ] + }, + "Signature": { + "properties": { + "protected": { + "type": "string" + }, + "signature": { + "type": "string" + } + }, + "required": [ + "protected", + "signature" + ] + } + } +} diff --git a/103705/validate.py b/103705/validate.py new file mode 100644 index 0000000000000000000000000000000000000000..fa5490974ca2b5e4c1dea110df7a5d6de24c0a72 --- /dev/null +++ b/103705/validate.py @@ -0,0 +1,95 @@ +import sys +from jsonschema import validate, RefResolver, Draft202012Validator +import json +from pathlib import Path +import logging +import argparse + + + +# filename = sys.argv[1] + +# def load_json (path): +# with open(path) as f: +# s = json.load(f) +# return s + +# schema_store = {} + +# json_instance = load_json(filename) +# print (json_instance) + +# etsi_schema = load_json('response.schema.json') +# ext_schema = load_json('extended.schema.json') +# ext_ent_schema = load_json("extended_entities.schema.json") +# schema_store = { +# etsi_schema['$id'] : etsi_schema, +# ext_schema['$id'] : ext_schema, +# ext_ent_schema['$id'] : ext_ent_schema +# } + +# resolver = RefResolver(None, referrer=None, store=schema_store) + +# print (etsi_schema) + +# v = Draft202012Validator(ext_schema, resolver=resolver) +# v.validate(json_instance) + +# validate(json_instance, ext_schema) +# print ("OK") + +def handle_uri(u): + print(u) + +def load_json(path : str): + with open(path) as f: + return json.load(f) + +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('schema', help="Primary schema to validate against") + + args = parser.parse_args() + + match args.verbose: + case v if v and v >= 2: + logging.basicConfig(level=logging.DEBUG) + case 1: + logging.basicConfig(level=logging.INFO) + case _: + logging.basicConfig(level=logging.WARNING) + + logging.debug(f"Arguments: {args}") + + instance_doc = json.loads(args.input.read()) + args.input.close() + main_schema = load_json(args.schema) + schema_dict = { main_schema['$id'] : main_schema } + + if args.schemadir: + schema_paths = [] + for d in args.schemadir: + schema_paths += [f for f in Path(d).rglob("*.schema.json")] + logging.info(f"Schema files loaded: {schema_paths}") + + schemas_json = [json.load(p.open()) for p in schema_paths] + schema_dict = schema_dict | { s['$id'] : s for s in schemas_json } + + logging.info(f"Schema IDs loaded: {[k for k in schema_dict.keys()]}") + + logging.debug (f"Instance doc: {instance_doc}") + logging.debug (f"Main schema: {main_schema}") + + resolver = RefResolver(None, + referrer=None, + store=schema_dict) + + v = Draft202012Validator(main_schema, resolver=resolver) + + v.validate(instance_doc) + + logging.info("Done") \ No newline at end of file diff --git a/103705/validation/validate_705.py b/103705/validation/validate_705.py new file mode 100644 index 0000000000000000000000000000000000000000..bb6913d2a2e5ce032b1b0f6ce39413cef1b5036e --- /dev/null +++ b/103705/validation/validate_705.py @@ -0,0 +1,97 @@ +import sys +from jsonschema import validate, RefResolver, Draft202012Validator +import json +from pathlib import Path +import logging +import argparse + +def handle_uri(u): + print(u) + +def load_json(path : str): + with open(path) as f: + return json.load(f) + + +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)") + + args = parser.parse_args() + + match args.verbose: + case v if v and v >= 2: + logging.basicConfig(level=logging.DEBUG) + case 1: + logging.basicConfig(level=logging.INFO) + case _: + logging.basicConfig(level=logging.WARNING) + + logging.debug(f"Arguments: {args}") + + instance_doc = json.loads(args.input.read()) + args.input.close() + + config = { + 'schema_include_dirs' : [ + '../schema/', + '../../103280/', + ], + 'main_schema_doc' : '../schema/response.schema.json' + } + + rootPath = Path(sys.argv[0]).parent + main_schema = load_json(str(rootPath / config['main_schema_doc'])) + schema_dict = { main_schema['$id'] : main_schema } + + schema_paths = [] + for d in config['schema_include_dirs']: + schema_paths += [f for f in (rootPath / Path(d)).rglob("*.schema.json")] + logging.info(f"Core schema files loaded: {schema_paths}") + if args.schemadir: + for d in args.schemadir: + schema_paths += [f for f in Path(d).rglob("*.schema.json")] + logging.info(f"CSP schema files loaded: {schema_paths}") + else: + logging.info(f"No CSP schema files loaded") + schemas_json = [json.load(p.open()) for p in schema_paths] + schema_dict = schema_dict | { s['$id'] : s for s in schemas_json } + + logging.info(f"Schema IDs loaded: {[k for k in schema_dict.keys()]}") + + logging.debug (f"Instance doc: {instance_doc}") + logging.debug (f"Main schema: {main_schema}") + + resolver = RefResolver(None, + referrer=None, + store=schema_dict) + + logging.info("Performing ETSI validation") + v = Draft202012Validator(main_schema, resolver=resolver) + v.validate(instance_doc) + + logging.info("Building record type dictionary") + type_dict = instance_doc['recordSetDescription']['recordTypes'] + logging.debug(type_dict) + ref_dict = { k : {"$ref" : v} for k,v in type_dict.items()} + validator_dict = { k : Draft202012Validator(ref_dict[k], resolver=resolver) for k,v in ref_dict.items()} + logging.debug(ref_dict) + + logging.info("Validating records") + for r in instance_doc['recordSet']: + type_key = r['type'] + if type_key not in type_dict.keys(): + logging.error(f"Record {r['id']} has type {type_key}, not in recordType dict") + type_ref = type_dict[type_key] + type_schema_id = type_ref.split('#')[0] + logging.info(f"Using {type_schema_id} to validate {type_ref} in record {r['id']}") + if not (type_key in validator_dict.keys()): + logging.error(f'Type key {type_key} from type {type_ref} in record {r["id"]} not in validator dictionary') + print(ref_dict) + v = validator_dict[type_key] + v.validate(r) + + logging.info("Done") \ No newline at end of file