diff --git a/zenoh_security_configuration/README.md b/zenoh_security_configuration/README.md
new file mode 100644
index 00000000..5ab09479
--- /dev/null
+++ b/zenoh_security_configuration/README.md
@@ -0,0 +1 @@
+# zenoh security configuration
diff --git a/zenoh_security_configuration/package.xml b/zenoh_security_configuration/package.xml
new file mode 100644
index 00000000..3f6c03c5
--- /dev/null
+++ b/zenoh_security_configuration/package.xml
@@ -0,0 +1,16 @@
+
+
+
+ zenoh_security_configuration
+ 0.3.0
+ This package generates zenoh secutiry configurations
+ Alejandro Hernanadez
+ Apache License 2.0
+
+ python3-jsonschema
+ python3-yaml
+
+
+ ament_python
+
+
diff --git a/zenoh_security_configuration/resource/zenoh_security_configuration b/zenoh_security_configuration/resource/zenoh_security_configuration
new file mode 100644
index 00000000..e69de29b
diff --git a/zenoh_security_configuration/setup.cfg b/zenoh_security_configuration/setup.cfg
new file mode 100644
index 00000000..40748208
--- /dev/null
+++ b/zenoh_security_configuration/setup.cfg
@@ -0,0 +1,4 @@
+[develop]
+script_dir=$base/lib/zenoh_security_configuration
+[install]
+install_scripts=$base/lib/zenoh_security_configuration
diff --git a/zenoh_security_configuration/setup.py b/zenoh_security_configuration/setup.py
new file mode 100644
index 00000000..35c02461
--- /dev/null
+++ b/zenoh_security_configuration/setup.py
@@ -0,0 +1,31 @@
+import os
+from glob import glob
+from setuptools import setup
+
+package_name = 'zenoh_security_configuration'
+
+setup(
+ name=package_name,
+ version='0.3.0',
+ packages=[package_name],
+ data_files=[
+ ('share/ament_index/resource_index/packages',
+ [os.path.join('resource', package_name)]),
+ (os.path.join('share', package_name), ['package.xml']),
+ (os.path.join('share', package_name, 'templates'),
+ glob('templates/*.json5')),
+ ],
+ install_requires=['setuptools'],
+ zip_safe=True,
+ maintainer='alejandro',
+ maintainer_email='alejandro@openrobotics.org',
+ description='This package generates zenoh secutiry configurations',
+ license='Apache License 2.0',
+ tests_require=['pytest'],
+ entry_points={
+ 'console_scripts': [
+ 'zenoh_security_configuration = \
+ zenoh_security_configuration.zenoh_security_configuration:main'
+ ],
+ },
+)
diff --git a/zenoh_security_configuration/templates/router.json5 b/zenoh_security_configuration/templates/router.json5
new file mode 100644
index 00000000..a9eaf935
--- /dev/null
+++ b/zenoh_security_configuration/templates/router.json5
@@ -0,0 +1,499 @@
+/// This file attempts to list and document available configuration elements.
+/// For a more complete view of the configuration's structure, check out `zenoh/src/config.rs`'s `Config` structure.
+/// Note that the values here are correctly typed, but may not be sensible, so copying this file to change only the parts that matter to you is not good practice.
+{
+ /// The identifier (as unsigned 128bit integer in hexadecimal lowercase - leading zeros are not accepted)
+ /// that zenoh runtime will use.
+ /// If not set, a random unsigned 128bit integer will be used.
+ /// WARNING: this id must be unique in your zenoh network.
+ // id: "1234567890abcdef",
+
+ /// The node's mode (router, peer or client)
+ mode: "router",
+
+ /// Which endpoints to connect to. E.g. tcp/localhost:7447.
+ /// By configuring the endpoints, it is possible to tell zenoh which router/peer to connect to at startup.
+ /// For TCP/UDP on Linux, it is possible additionally specify the interface to be connected to:
+ /// E.g. tcp/192.168.0.1:7447#iface=eth0, for connect only if the IP address is reachable via the interface eth0
+ connect: {
+ /// timeout waiting for all endpoints connected (0: no retry, -1: infinite timeout)
+ /// Accepts a single value (e.g. timeout_ms: 0)
+ /// or different values for router, peer and client (e.g. timeout_ms: { router: -1, peer: -1, client: 0 }).
+ timeout_ms: { router: -1, peer: -1, client: 0 },
+
+ /// The list of endpoints to connect to.
+ /// Accepts a single list (e.g. endpoints: ["tcp/10.10.10.10:7447", "tcp/11.11.11.11:7447"])
+ /// or different lists for router, peer and client (e.g. endpoints: { router: ["tcp/10.10.10.10:7447"], peer: ["tcp/11.11.11.11:7447"] }).
+ ///
+ /// See https://docs.rs/zenoh/latest/zenoh/config/struct.EndPoint.html
+ endpoints: [
+ // "/"
+ ],
+
+ /// Global connect configuration,
+ /// Accepts a single value or different values for router, peer and client.
+ /// The configuration can also be specified for the separate endpoint
+ /// it will override the global one
+ /// E.g. tcp/192.168.0.1:7447#retry_period_init_ms=20000;retry_period_max_ms=10000"
+
+ /// exit from application, if timeout exceed
+ exit_on_failure: { router: false, peer: false, client: true },
+ /// connect establishing retry configuration
+ retry: {
+ /// initial wait timeout until next connect try
+ period_init_ms: 1000,
+ /// maximum wait timeout until next connect try
+ period_max_ms: 4000,
+ /// increase factor for the next timeout until nexti connect try
+ period_increase_factor: 2,
+ },
+ },
+
+ /// Which endpoints to listen on. E.g. tcp/0.0.0.0:7447.
+ /// By configuring the endpoints, it is possible to tell zenoh which are the endpoints that other routers,
+ /// peers, or client can use to establish a zenoh session.
+ /// For TCP/UDP on Linux, it is possible additionally specify the interface to be listened to:
+ /// E.g. tcp/0.0.0.0:7447#iface=eth0, for listen connection only on eth0
+ listen: {
+ /// timeout waiting for all listen endpoints (0: no retry, -1: infinite timeout)
+ /// Accepts a single value (e.g. timeout_ms: 0)
+ /// or different values for router, peer and client (e.g. timeout_ms: { router: -1, peer: -1, client: 0 }).
+ timeout_ms: 0,
+
+ /// The list of endpoints to listen on.
+ /// Accepts a single list (e.g. endpoints: ["tcp/[::]:7447", "udp/[::]:7447"])
+ /// or different lists for router, peer and client (e.g. endpoints: { router: ["tcp/[::]:7447"], peer: ["tcp/[::]:0"] }).
+ ///
+ /// See https://docs.rs/zenoh/latest/zenoh/config/struct.EndPoint.html
+ endpoints: [
+ "tls/localhost:7447"
+ ],
+
+ /// Global listen configuration,
+ /// Accepts a single value or different values for router, peer and client.
+ /// The configuration can also be specified for the separate endpoint
+ /// it will override the global one
+ /// E.g. tcp/192.168.0.1:7447#exit_on_failure=false;retry_period_max_ms=1000"
+
+ /// exit from application, if timeout exceed
+ exit_on_failure: true,
+ /// listen retry configuration
+ retry: {
+ /// initial wait timeout until next try
+ period_init_ms: 1000,
+ /// maximum wait timeout until next try
+ period_max_ms: 4000,
+ /// increase factor for the next timeout until next try
+ period_increase_factor: 2,
+ },
+ },
+
+ /// Configure the scouting mechanisms and their behaviours
+ scouting: {
+ /// In client mode, the period in milliseconds dedicated to scouting for a router before failing.
+ timeout: 3000,
+ /// In peer mode, the maximum period in milliseconds dedicated to scouting remote peers before attempting other operations.
+ delay: 500,
+ /// The multicast scouting configuration.
+ multicast: {
+ /// Whether multicast scouting is enabled or not
+ ///
+ /// ROS setting: disable multicast discovery by default
+ enabled: false,
+ /// The socket which should be used for multicast scouting
+ address: "224.0.0.224:7446",
+ /// The network interface which should be used for multicast scouting
+ interface: "auto", // If not set or set to "auto" the interface if picked automatically
+ /// The time-to-live on multicast scouting packets
+ ttl: 1,
+ /// Which type of Zenoh instances to automatically establish sessions with upon discovery on UDP multicast.
+ /// Accepts a single value (e.g. autoconnect: ["router", "peer"])
+ /// or different values for router, peer and client (e.g. autoconnect: { router: [], peer: ["router", "peer"] }).
+ /// Each value is a list of: "peer", "router" and/or "client".
+ autoconnect: { router: [], peer: ["router", "peer"] },
+ /// Whether or not to listen for scout messages on UDP multicast and reply to them.
+ listen: true,
+ },
+ /// The gossip scouting configuration.
+ gossip: {
+ /// Whether gossip scouting is enabled or not
+ enabled: true,
+ /// When true, gossip scouting information are propagated multiple hops to all nodes in the local network.
+ /// When false, gossip scouting information are only propagated to the next hop.
+ /// Activating multihop gossip implies more scouting traffic and a lower scalability.
+ /// It mostly makes sense when using "linkstate" routing mode where all nodes in the subsystem don't have
+ /// direct connectivity with each other.
+ multihop: false,
+ /// Which type of Zenoh instances to automatically establish sessions with upon discovery on gossip.
+ /// Accepts a single value (e.g. autoconnect: ["router", "peer"])
+ /// or different values for router, peer and client (e.g. autoconnect: { router: [], peer: ["router", "peer"] }).
+ /// Each value is a list of: "peer", "router" and/or "client".
+ autoconnect: { router: [], peer: ["router", "peer"] },
+ },
+ },
+
+ /// Configuration of data messages timestamps management.
+ timestamping: {
+ /// Whether data messages should be timestamped if not already.
+ /// Accepts a single boolean value or different values for router, peer and client.
+ ///
+ /// ROS setting: PublicationCache which is required for transient_local durability
+ /// only works when time-stamping is enabled.
+ enabled: { router: true, peer: true, client: true },
+ /// Whether data messages with timestamps in the future should be dropped or not.
+ /// If set to false (default), messages with timestamps in the future are retimestamped.
+ /// Timestamps are ignored if timestamping is disabled.
+ drop_future_timestamp: false,
+ },
+
+ /// The default timeout to apply to queries in milliseconds.
+ queries_default_timeout: 10000,
+
+ /// The routing strategy to use and it's configuration.
+ routing: {
+ /// The routing strategy to use in routers and it's configuration.
+ router: {
+ /// When set to true a router will forward data between two peers
+ /// directly connected to it if it detects that those peers are not
+ /// connected to each other.
+ /// The failover brokering only works if gossip discovery is enabled.
+ /// ROS setting: disabled by default because it serves no purpose when each peer connects directly to all others,
+ /// and it introduces additional management overhead and extra messages during system startup.
+ peers_failover_brokering: false,
+ },
+ /// The routing strategy to use in peers and it's configuration.
+ peer: {
+ /// The routing strategy to use in peers. ("peer_to_peer" or "linkstate").
+ mode: "peer_to_peer",
+ },
+ },
+
+ // /// The declarations aggregation strategy.
+ // aggregation: {
+ // /// A list of key-expressions for which all included subscribers will be aggregated into.
+ // subscribers: [
+ // // key_expression
+ // ],
+ // /// A list of key-expressions for which all included publishers will be aggregated into.
+ // publishers: [
+ // // key_expression
+ // ],
+ // },
+
+ // /// The downsampling declaration.
+ // downsampling: [
+ // {
+ // /// A list of network interfaces messages will be processed on, the rest will be passed as is.
+ // interfaces: [ "wlan0" ],
+ // /// Data flow messages will be processed on. ("egress" or "ingress")
+ // flow: "egress",
+ // /// A list of downsampling rules: key_expression and the maximum frequency in Hertz
+ // rules: [
+ // { key_expr: "demo/example/zenoh-rs-pub", freq: 0.1 },
+ // ],
+ // },
+ // ],
+
+ // /// Configure access control (ACL) rules
+ // access_control: {
+ // /// [true/false] acl will be activated only if this is set to true
+ // "enabled": false,
+ // /// [deny/allow] default permission is deny (even if this is left empty or not specified)
+ // "default_permission": "deny",
+ // /// Rule set for permissions allowing or denying access to key-expressions
+ // "rules":
+ // [
+ // {
+ // /// Id has to be unique within the rule set
+ // "id": "rule1",
+ // "messages": [
+ // "put", "delete", "declare_subscriber",
+ // "query", "reply", "declare_queryable",
+ // ],
+ // "flows":["egress","ingress"],
+ // "permission": "allow",
+ // "key_exprs": [
+ // "test/demo"
+ // ],
+ // },
+ // {
+ // "id": "rule2",
+ // "messages": [
+ // "put", "delete", "declare_subscriber",
+ // "query", "reply", "declare_queryable",
+ // ],
+ // "flows":["ingress"],
+ // "permission": "allow",
+ // "key_exprs": [
+ // "**"
+ // ],
+ // },
+ // ],
+ // /// List of combinations of subjects.
+ // ///
+ // /// If a subject property (i.e. username, certificate common name or interface) is empty
+ // /// it is interpreted as a wildcard. Moreover, a subject property cannot be an empty list.
+ // "subjects":
+ // [
+ // {
+ // /// Id has to be unique within the subjects list
+ // "id": "subject1",
+ // /// Subjects can be interfaces
+ // "interfaces": [
+ // "lo0",
+ // "en0",
+ // ],
+ // /// Subjects can be cert_common_names when using TLS or Quic
+ // "cert_common_names": [
+ // "example.zenoh.io"
+ // ],
+ // /// Subjects can be usernames when using user/password authentication
+ // "usernames": [
+ // "zenoh-example"
+ // ],
+ // /// This instance translates internally to this filter:
+ // /// (interface="lo0" && cert_common_name="example.zenoh.io" && username="zenoh-example") ||
+ // /// (interface="en0" && cert_common_name="example.zenoh.io" && username="zenoh-example")
+ // },
+ // {
+ // "id": "subject2",
+ // "interfaces": [
+ // "lo0",
+ // "en0",
+ // ],
+ // "cert_common_names": [
+ // "example2.zenoh.io"
+ // ],
+ // /// This instance translates internally to this filter:
+ // /// (interface="lo0" && cert_common_name="example2.zenoh.io") ||
+ // /// (interface="en0" && cert_common_name="example2.zenoh.io")
+ // },
+ // {
+ // "id": "subject3",
+ // /// An empty subject combination is a wildcard
+ // },
+ // ],
+ // /// The policies list associates rules to subjects
+ // "policies":
+ // [
+ // /// Each policy associates one or multiple rules to one or multiple subject combinations
+ // {
+ // /// Rules and Subjects are identified with their unique IDs declared above
+ // "rules": ["rule1"],
+ // "subjects": ["subject1", "subject2"],
+ // },
+ // {
+ // "rules": ["rule2"],
+ // "subjects": ["subject3"],
+ // },
+ // ]
+ //},
+
+ /// Configure internal transport parameters
+ transport: {
+ unicast: {
+ /// Timeout in milliseconds when opening a link
+ accept_timeout: 10000,
+ /// Maximum number of zenoh session in pending state while accepting
+ accept_pending: 100,
+ /// Maximum number of sessions that can be simultaneously alive
+ max_sessions: 1000,
+ /// Maximum number of incoming links that are admitted per session
+ max_links: 1,
+ /// Enables the LowLatency transport
+ /// This option does not make LowLatency transport mandatory, the actual implementation of transport
+ /// used will depend on Establish procedure and other party's settings
+ ///
+ /// NOTE: Currently, the LowLatency transport doesn't preserve QoS prioritization.
+ /// NOTE: Due to the note above, 'lowlatency' is incompatible with 'qos' option, so in order to
+ /// enable 'lowlatency' you need to explicitly disable 'qos'.
+ /// NOTE: LowLatency transport does not support the fragmentation, so the message size should be
+ /// smaller than the tx batch_size.
+ lowlatency: false,
+ /// Enables QoS on unicast communications.
+ qos: {
+ enabled: true,
+ },
+ /// Enables compression on unicast communications.
+ /// Compression capabilities are negotiated during session establishment.
+ /// If both Zenoh nodes support compression, then compression is activated.
+ compression: {
+ enabled: false,
+ },
+ },
+ /// WARNING: multicast communication does not perform any negotiation upon group joining.
+ /// Because of that, it is important that all transport parameters are the same to make
+ /// sure all your nodes in the system can communicate. One common parameter to configure
+ /// is "transport/link/tx/batch_size" since its default value depends on the actual platform
+ /// when operating on multicast.
+ /// E.g., the batch size on Linux and Windows is 65535 bytes, on Mac OS X is 9216, and anything else is 8192.
+ multicast: {
+ /// JOIN message transmission interval in milliseconds.
+ join_interval: 2500,
+ /// Maximum number of multicast sessions.
+ max_sessions: 1000,
+ /// Enables QoS on multicast communication.
+ /// Default to false for Zenoh-to-Zenoh-Pico out-of-the-box compatibility.
+ qos: {
+ enabled: false,
+ },
+ /// Enables compression on multicast communication.
+ /// Default to false for Zenoh-to-Zenoh-Pico out-of-the-box compatibility.
+ compression: {
+ enabled: false,
+ },
+ },
+ link: {
+ /// An optional whitelist of protocols to be used for accepting and opening sessions. If not
+ /// configured, all the supported protocols are automatically whitelisted. The supported
+ /// protocols are: ["tcp" , "udp", "tls", "quic", "ws", "unixsock-stream", "vsock"] For
+ /// example, to only enable "tls" and "quic": protocols: ["tls", "quic"],
+ ///
+ /// Configure the zenoh TX parameters of a link
+ protocols: @(protocols),
+ tx: {
+ /// The resolution in bits to be used for the message sequence numbers.
+ /// When establishing a session with another Zenoh instance, the lowest value of the two instances will be used.
+ /// Accepted values: 8bit, 16bit, 32bit, 64bit.
+ sequence_number_resolution: "32bit",
+ /// Link lease duration in milliseconds to announce to other zenoh nodes
+ lease: 10000,
+ /// Number of keep-alive messages in a link lease duration. If no data is sent, keep alive
+ /// messages will be sent at the configured time interval.
+ /// NOTE: In order to consider eventual packet loss and transmission latency and jitter,
+ /// set the actual keep_alive interval to one fourth of the lease time: i.e. send
+ /// 4 keep_alive messages in a lease period. Changing the lease time will have the
+ /// keep_alive messages sent more or less often.
+ /// This is in-line with the ITU-T G.8013/Y.1731 specification on continuous connectivity
+ /// check which considers a link as failed when no messages are received in 3.5 times the
+ /// target interval.
+ keep_alive: 4,
+ /// Batch size in bytes is expressed as a 16bit unsigned integer.
+ /// Therefore, the maximum batch size is 2^16-1 (i.e. 65535).
+ /// The default batch size value is the maximum batch size: 65535.
+ batch_size: 65535,
+ /// Each zenoh link has a transmission queue that can be configured
+ queue: {
+ /// The size of each priority queue indicates the number of batches a given queue can contain.
+ /// NOTE: the number of batches in each priority must be included between 1 and 16. Different values will result in an error.
+ /// The amount of memory being allocated for each queue is then SIZE_XXX * BATCH_SIZE.
+ /// In the case of the transport link MTU being smaller than the ZN_BATCH_SIZE,
+ /// then amount of memory being allocated for each queue is SIZE_XXX * LINK_MTU.
+ /// If qos is false, then only the DATA priority will be allocated.
+ size: {
+ control: 1,
+ real_time: 1,
+ interactive_high: 1,
+ interactive_low: 1,
+ data_high: 2,
+ data: 4,
+ data_low: 4,
+ background: 4,
+ },
+ /// Congestion occurs when the queue is empty (no available batch).
+ congestion_control: {
+ /// Behavior pushing CongestionControl::Drop messages to the queue.
+ drop: {
+ /// The maximum time in microseconds to wait for an available batch before dropping a droppable message if still no batch is available.
+ wait_before_drop: 1000,
+ },
+ /// Behavior pushing CongestionControl::Block messages to the queue.
+ block: {
+ /// The maximum time in microseconds to wait for an available batch before closing the transport session when sending a blocking message
+ /// if still no batch is available.
+ wait_before_close: 5000000,
+ },
+ },
+ /// Perform batching of messages if they are smaller of the batch_size
+ batching: {
+ /// Perform adaptive batching of messages if they are smaller of the batch_size.
+ /// When the network is detected to not be fast enough to transmit every message individually, many small messages may be
+ /// batched together and sent all at once on the wire reducing the overall network overhead. This is typically of a high-throughput
+ /// scenario mainly composed of small messages. In other words, batching is activated by the network back-pressure.
+ enabled: true,
+ /// The maximum time limit (in ms) a message should be retained for batching when back-pressure happens.
+ time_limit: 1,
+ },
+ },
+ },
+ /// Configure the zenoh RX parameters of a link
+ rx: {
+ /// Receiving buffer size in bytes for each link
+ /// The default the rx_buffer_size value is the same as the default batch size: 65535.
+ /// For very high throughput scenarios, the rx_buffer_size can be increased to accommodate
+ /// more in-flight data. This is particularly relevant when dealing with large messages.
+ /// E.g. for 16MiB rx_buffer_size set the value to: 16777216.
+ buffer_size: 65535,
+ /// Maximum size of the defragmentation buffer at receiver end.
+ /// Fragmented messages that are larger than the configured size will be dropped.
+ /// The default value is 1GiB. This would work in most scenarios.
+ /// NOTE: reduce the value if you are operating on a memory constrained device.
+ max_message_size: 1073741824,
+ },
+ /// Configure TLS specific parameters
+ tls: {
+ /// Path to the certificate of the certificate authority used to validate either the server
+ /// or the client's keys and certificates, depending on the node's mode. If not specified
+ /// on router mode then the default WebPKI certificates are used instead.
+ root_ca_certificate: null,
+ /// Path to the TLS listening side private key
+ listen_private_key: "/home/ahcorde/sros2_demo/tls/localhost/key.pem",
+ /// Path to the TLS listening side public certificate
+ listen_certificate: "/home/ahcorde/sros2_demo/tls/localhost/cert.pem",
+ /// Enables mTLS (mutual authentication), client authentication
+ enable_mtls: false,
+ /// Path to the TLS connecting side private key
+ connect_private_key: null,
+ /// Path to the TLS connecting side certificate
+ connect_certificate: null,
+ // Whether or not to verify the matching between hostname/dns and certificate when connecting,
+ // if set to false zenoh will disregard the common names of the certificates when verifying servers.
+ // This could be dangerous because your CA can have signed a server cert for foo.com, that's later being used to host a server at baz.com.
+ // If you want your ca to verify that the server at baz.com is actually baz.com, let this be true (default).
+ verify_name_on_connect: true,
+ },
+ },
+ /// Shared memory configuration.
+ /// NOTE: shared memory can be used only if zenoh is compiled with "shared-memory" feature, otherwise
+ /// settings in this section have no effect.
+ shared_memory: {
+ /// A probing procedure for shared memory is performed upon session opening. To enable zenoh to operate
+ /// over shared memory (and to not fallback on network mode), shared memory needs to be enabled also on the
+ /// subscriber side. By doing so, the probing procedure will succeed and shared memory will operate as expected.
+ ///
+ /// ROS setting: disabled by default until fully tested
+ enabled: false,
+ },
+ auth: {
+ /// The configuration of authentication.
+ /// A password implies a username is required.
+ usrpwd: {
+ user: null,
+ password: null,
+ /// The path to a file containing the user password dictionary
+ dictionary_file: null,
+ },
+ pubkey: {
+ public_key_pem: null,
+ private_key_pem: null,
+ public_key_file: null,
+ private_key_file: null,
+ key_size: null,
+ known_keys_file: null,
+ },
+ },
+ },
+
+ /// Configure the Admin Space
+ /// Unstable: this configuration part works as advertised, but may change in a future release
+ adminspace: {
+ /// Enables the admin space
+ enabled: true,
+ /// read and/or write permissions on the admin space
+ permissions: {
+ read: true,
+ write: false,
+ },
+ },
+
+}
diff --git a/zenoh_security_configuration/zenoh_security_configuration/__init.py__ b/zenoh_security_configuration/zenoh_security_configuration/__init.py__
new file mode 100644
index 00000000..e69de29b
diff --git a/zenoh_security_configuration/zenoh_security_configuration/zenoh_security_configuration.py b/zenoh_security_configuration/zenoh_security_configuration/zenoh_security_configuration.py
new file mode 100644
index 00000000..02eaa248
--- /dev/null
+++ b/zenoh_security_configuration/zenoh_security_configuration/zenoh_security_configuration.py
@@ -0,0 +1,121 @@
+# Copyright 2025 Open Source Robotics Foundation, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import argparse
+import em
+from io import StringIO
+import os
+import pathlib
+import sys
+from ament_index_python.packages import get_package_share_directory
+
+class ZenohSecutiryConfigGenerator:
+ """ZenohSecutiryConfigGenerator generates Zenoh secutiry configurations."""
+
+ def __init__(self):
+ """
+ Construct NEXUSConfigGenerator.
+ """
+ self.zenoh_cfg_file_extension = "json5"
+
+ def generate_router_config(self, data):
+ try:
+ output = StringIO()
+ interpreter = em.Interpreter(
+ output=output,
+ options={
+ em.BUFFERED_OPT: True,
+ em.RAW_OPT: True,
+ },
+ )
+
+ template_path = pathlib.Path(os.path.join(
+ get_package_share_directory("zenoh_security_configuration"),
+ "templates",
+ "router.json5"
+ ))
+
+
+ with template_path.open('r') as h:
+ template_content = h.read()
+ interpreter.string(template_content, locals=data)
+ return output.getvalue()
+ except:
+ print('lol')
+ finally:
+ if interpreter is not None:
+ interpreter.shutdown()
+ interpreter = None
+
+ def generate_zenoh_config(self, output_dir, router_config, encoding: str = 'utf-8'):
+ """
+ Generate Zenoh bridge configs and output to directory 'output_dir'.
+
+ Parameters
+ ----------
+ output_dir : str
+ Output directory for Zenoh configurations
+
+ """
+ write_filepath = os.path.join(
+ output_dir, "router" + "."
+ + self.zenoh_cfg_file_extension,
+ )
+ output_file = pathlib.Path(write_filepath)
+ print(f"Generated Zenoh secutiry configuration at {write_filepath}")
+ if output_file.exists():
+ existing_content = output_file.read_text(encoding=encoding)
+ if existing_content == router_config:
+ return
+ elif output_file.parent:
+ os.makedirs(str(output_file.parent), exist_ok=True)
+
+ output_file.write_text(router_config, encoding=encoding)
+
+def main(argv=sys.argv):
+ """Entrypoint."""
+ parser = argparse.ArgumentParser(
+ description="Generate Zenoh configurations from a NEXUS Network \
+ and REDF Configuration",
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter,
+ )
+
+ parser.add_argument(
+ "-o",
+ "--output",
+ required=True,
+ type=str,
+ help="Output directory for Zenoh bridge configurations",
+ )
+
+ parser.add_argument(
+ "-p",
+ "--protocols",
+ nargs='*',
+ required=False,
+ choices=["tcp", "tls"],
+ default=['tls'],
+ help="Protocols chooices",
+ )
+
+ args = parser.parse_args(argv[1:])
+
+ data = {'protocols': args.protocols}
+
+ zenoh_sec_gen = ZenohSecutiryConfigGenerator()
+ router_config = zenoh_sec_gen.generate_router_config(data)
+ zenoh_sec_gen.generate_zenoh_config(args.output, router_config)
+
+if __name__ == "__main__":
+ main(sys.argv)