]> git.corax.cc Git - toolbox/commitdiff
include/ipc: Add JSON Schema-based data validation unstable
authorMatthias Kruk <m@m10k.eu>
Sat, 12 Aug 2023 05:13:52 +0000 (14:13 +0900)
committerMatthias Kruk <m@m10k.eu>
Sat, 12 Aug 2023 05:47:07 +0000 (14:47 +0900)
When an application receives a message from `ipc_endpoint_recv()',
it has to validate the contents of the message. It would be more
convenient if the validation could be performed by the ipc module,
so that the `ipc_endpoint_recv()' function only returns valid
messages to the caller.

This commit modifies the ipc module so that the user may set a
JSON Schema that is used by the ipc module to validate the data
of incoming messages. When a schema has been set, only messages
that passed validation will be returned by `ipc_endpoint_recv()'.

docs/ipc.md
include/ipc.sh

index ea6ce529117ea2b6301f97bcbd4991b5643b17e0..91010de7331a5785f79e84be8b462da8fd665a04 100644 (file)
@@ -22,11 +22,13 @@ sent by one module cannot be read by the other.
 | [ipc_encode()](#ipc_encode)                                         | Encode an IPC message                                    |
 | [ipc_endpoint_close()](#ipc_endpoint_close)                         | Close an IPC endpoint                                    |
 | [ipc_endpoint_foreach_message()](#ipc_endpoint_foreach_message)     | Iterate over an endpoint's message queue ]               |
+| [ipc_endpoint_get_data_schema()](#ipc_endpoint_get_data_schema)     | Get the JSON Schema used to validate message data        |
 | [ipc_endpoint_get_subscriptions()](#ipc_endpoint_get_subscriptions) | Get the list of topics that an endpoint is subscribed to |
 | [ipc_endpoint_open()](#ipc_endpoint_open)                           | Open an endpoint for IPC messaging                       |
 | [ipc_endpoint_publish()](#ipc_endpoint_publish)                     | Publish a message to a topic                             |
 | [ipc_endpoint_recv()](#ipc_endpoint_recv)                           | Receive a point-to-point or pub-sub message              |
 | [ipc_endpoint_send()](#ipc_endpoint_send)                           | Send a point-to-point message to another endpoint        |
+| [ipc_endpoint_set_data_schema()](#ipc_endpoint_set_data_schema)     | Set the JSON Schema used to validate message data        |
 | [ipc_endpoint_subscribe()](#ipc_endpoint_subscribe)                 | Subscribe an endpoint to one or more topics              |
 | [ipc_endpoint_unsubscribe()](#ipc_endpoint_unsubscribe)             | Unsubscribe an endpoint from one or more topics          |
 | [ipc_get_root()](#ipc_get_root)                                     | Return the path to the IPC directory                     |
@@ -40,6 +42,7 @@ sent by one module cannot be read by the other.
 | [ipc_msg_get_user()](#ipc_msg_get_user)                             | Get the user name of a message's sender                  |
 | [ipc_msg_get_version()](#ipc_msg_get_version)                       | Get the protocol version of a message                    |
 | [ipc_msg_new()](#ipc_msg_new)                                       | Generate a new IPC message                               |
+| [ipc_msg_validate_data()](#ipc_msg_validate_data)                   | Use a JSON Schema to validate the data in a message      |
 
 
 ## ipc_decode()
@@ -195,6 +198,41 @@ This function does not write to standard output.
 This function does not write to standard error.
 
 
+## ipc_endpoint_get_data_schema()
+
+Get the JSON Schema used to validate message data
+
+### Synopsis
+
+    ipc_endpoint_get_data_schema "$endpoint"
+
+### Description
+
+The `ipc_endpoint_get_data_schema()` function writes the URL of the JSON Schema that is used to validate
+message data received by `endpoint` to standard output. If no schema was set, no data will be written to
+standard output and an error will be returned.
+
+### Return value
+
+| Return value | Meaning                                                     |
+|--------------|-------------------------------------------------------------|
+| 0            | The URL of the schema was written to standard output        |
+| 1            | The endpoint does not use a schema to validate message data |
+
+### Standard input
+
+This function does not read from standard input.
+
+### Standard output
+
+If a data validation schema is set in the endpoint, the URL of that schema will be written to
+standard output.
+
+### Standard error
+
+This function does not write to standard error.
+
+
 ## ipc_endpoint_get_subscriptions()
 
 Get the list of topics that an endpoint is subscribed to
@@ -315,12 +353,18 @@ endpoint, it will wait for up to `timeout` seconds. If `timeout` is zero, the fu
 return immediately without waiting for messages. If `timeout` was omitted, the function
 will wait indefinitely.
 
+If a message data validation schema was set using `ipc_endpoint_set_data_schema()`, data
+in incoming messages will be validated against that schema. If a received message contains
+data that could not be validated, the message will be dropped and `ipc_endpoint_recv()` will
+return an error.
+
 ### Return value
 
-| Return value | Meaning            |
-|--------------|--------------------|
-| 0            | Success            |
-| 1            | A timeout occurred |
+| Return value | Meaning                                       |
+|--------------|-----------------------------------------------|
+| 0            | Success                                       |
+| 1            | A timeout occurred                            |
+| 2            | A message containing invalid data was dropped |
 
 ### Standard input
 
@@ -368,6 +412,42 @@ This function does not write to standard output.
 In case of an error, an error message will be written to standard error.
 
 
+## ipc_endpoint_set_data_schema()
+
+Set the JSON Schema used to validate message data
+
+### Synopsis
+
+    ipc_endpoint_set_data_schema "$endpoint" "$schema"
+
+### Description
+
+The `ipc_endpoint_set_data_schema()` function enables message data validation in the endpoint
+`endpoint` and assigns it the JSON Schema referenced by `schema`. Any successive calls to
+`ipc_endpoint_recv()` will use the JSON Schema in `schema` to validate the data portion of
+incoming messages, and drop incoming messages if the data could not be validated.
+
+
+### Return value
+
+| Return value | Meaning                                         |
+|--------------|-------------------------------------------------|
+| 0            | The data validation schema was successfully set |
+| 1            | The data validation schema could not be set     |
+
+### Standard input
+
+This function does not read from standard input.
+
+### Standard output
+
+This function does not write to standard output.
+
+### Standard error
+
+In case of an error, an error message is written to standard error.
+
+
 ## ipc_endpoint_subscribe()
 
 Subscribe an endpoint to one or more topics
@@ -805,3 +885,36 @@ Upon success, the generated message is written to standard output.
 ### Standard error
 
 An error is written to standard error if the message could not be generated.
+
+
+## ipc_msg_validate_data()
+
+Use a JSON Schema to validate the data in a message
+
+### Synopsis
+
+    ipc_msg_validate_data "$message" "$schema"
+
+### Description
+
+The `ipc_msg_validate_data()` function validates the data contained in the
+message `message` using the JSON Schema referenced by `schema`.
+
+### Return value
+
+| Return value | Meaning                           |
+|--------------|-----------------------------------|
+| 0            | The message contains valid data   |
+| 1            | The message contains invalid data |
+
+### Standard input
+
+This function does not read from standard input.
+
+### Standard output
+
+This function does not write to standard output.
+
+### Standard error
+
+An error is written to standard error if the message data could not be validated.
index 718312b02407c11f4b61ba55de6cab9bd8e2ce70..5bc11d7642f9d2f5b6716b078cd442913b92c0e8 100644 (file)
@@ -35,6 +35,7 @@ __init() {
                  "msg_get_timestamp"          \
                  "msg_get_data"               \
                  "msg_get_topic"              \
+                 "msg_validate_data"          \
                  "encode"                     \
                  "decode"                     \
                  "endpoint_open"              \
@@ -46,6 +47,8 @@ __init() {
                  "endpoint_get_subscriptions" \
                  "endpoint_publish"           \
                  "endpoint_foreach_message"   \
+                 "endpoint_set_data_schema"   \
+                 "endpoint_get_data_schema"
 
        return 0
 }
@@ -441,6 +444,20 @@ ipc_msg_get_topic() {
        return 0
 }
 
+ipc_msg_validate_data() {
+       local msg="$1"
+       local schema="$2"
+
+       local errors
+
+       if ! errors=$(toolbox-json-validate "$schema" <(ipc_msg_get_data "$msg") 2>&1); then
+               log_highlight "Invalid data in IPC message" <<< "$errors" | log_info
+               return 1
+       fi
+
+       return 0
+}
+
 ipc_msg_get_signature() {
        local msg="$1"
 
@@ -600,6 +617,7 @@ ipc_endpoint_recv() {
 
        local queue
        local msg
+       local schema
 
        queue="$(ipc_get_root)/$endpoint/queue"
 
@@ -607,6 +625,11 @@ ipc_endpoint_recv() {
                return 1
        fi
 
+       if schema=$(ipc_endpoint_get_data_schema "$endpoint") &&
+          ! ipc_msg_validate_data "$msg" "$schema"; then
+               return 2
+       fi
+
        echo "$msg"
        return 0
 }
@@ -792,3 +815,37 @@ ipc_endpoint_foreach_message() {
 
        return 0
 }
+
+ipc_endpoint_set_data_schema() {
+       local endpoint="$1"
+       local schema="$2"
+
+       local schema_file
+
+       schema_file="$(ipc_get_root)/$endpoint/schema"
+
+       if [[ -n "$schema" ]]; then
+               if ! printf '%s\n' "$schema" > "$schema_file"; then
+                       log_info "Could not set data validation schema in $schema_file"
+                       return 1
+               fi
+       elif ! rm -f "$schema_file"; then
+               return 2
+       fi
+
+       return 0
+}
+
+ipc_endpoint_get_data_schema() {
+       local endpoint="$1"
+
+       local schema_file
+
+       schema_file="$(ipc_get_root)/$endpoint/schema"
+
+       if ! cat "$schema_file" 2>/dev/null; then
+               return 1
+       fi
+
+       return 0
+}