diff --git a/apps/emqx/i18n/emqx_schema_i18n.conf b/apps/emqx/i18n/emqx_schema_i18n.conf
index c1df430db..1112fef09 100644
--- a/apps/emqx/i18n/emqx_schema_i18n.conf
+++ b/apps/emqx/i18n/emqx_schema_i18n.conf
@@ -990,4 +990,1294 @@ NOTE: This is a cluster-wide configuration. It requires all nodes to be stopped
zh: """是否开启客户端已成功取消订阅主题事件消息。"""
}
}
+
+
+fields_authorization_no_match {
+ desc {
+ en: """
+Default access control action if the user or client matches no ACL rules,
+or if no such user or client is found by the configurable authorization
+sources such as built_in_database, an HTTP API, or a query against PostgreSQL.
+Find more details in 'authorization.sources' config.
+"""
+ zh: """
+如果用户或客户端不匹配ACL规则,或者从可配置授权源(比如内置数据库、HTTP API 或 PostgreSQL 等。)内未找
+到此类用户或客户端时,模式的认访问控制操作。
+在“授权”中查找更多详细信息。
+"""
+ }
+ label: {
+ en: "Authorization no match"
+ zh: "未匹时的默认授权动作"
+ }
+}
+
+fields_authorization_deny_action {
+ desc {
+ en: """
+The action when the authorization check rejects an operation.
+"""
+ zh: """
+授权检查拒绝操作时的操作。
+"""
+ }
+ label: {
+ en: "Authorization deny action"
+ zh: "授权检查拒绝操作时的操作"
+ }
+}
+
+fields_cache_enable {
+ desc {
+ en: """
+Enable or disable the authorization cache.
+"""
+ zh: """
+启用或禁用授权缓存。
+"""
+ }
+ label: {
+ en: "Enable or disable the authorization cache."
+ zh: "启用或禁用授权缓存"
+ }
+}
+
+fields_cache_max_size {
+ desc {
+ en: """
+Maximum number of cached items.
+"""
+ zh: """
+缓存项的最大数量。
+"""
+ }
+ label: {
+ en: "Maximum number of cached items."
+ zh: "缓存项的最大数量"
+ }
+}
+
+fields_cache_ttl {
+ desc {
+ en: """
+Time to live for the cached data.
+"""
+ zh: """
+缓存数据的生存时间。
+"""
+ }
+ label: {
+ en: "Time to live for the cached data."
+ zh: "缓存数据的生存时间。"
+ }
+}
+
+fields_deflate_opts_level {
+ desc {
+ en: """
+Compression level.
+"""
+ zh: """压缩级别"""
+ }
+ label: {
+ en: "Compression level"
+ zh: "压缩级别"
+ }
+}
+
+fields_deflate_opts_mem_level {
+ desc {
+ en: """
+Specifies the size of the compression state.
+Lower values decrease memory usage per connection.
+"""
+ zh: """
+指定压缩状态的大小
+较低的值会减少每个连接的内存使用。
+"""
+ }
+ label: {
+ en: "Size of the compression state"
+ zh: "压缩状态大小"
+ }
+}
+
+fields_deflate_opts_strategy {
+ desc {
+ en: """
+Specifies the compression strategy.
+"""
+ zh: """
+指定压缩策略。
+"""
+ }
+ label: {
+ en: "compression strategy"
+ zh: "指定压缩策略"
+ }
+}
+
+fields_deflate_opts_server_context_takeover {
+ desc {
+ en: """
+Takeover means the compression state is retained between server messages.
+"""
+ zh: """接管意味着在服务器消息之间保留压缩状态。"""
+ }
+ label: {
+ en: "Server context takeover"
+ zh: "服务上下文接管"
+ }
+}
+
+fields_deflate_opts_client_context_takeover {
+ desc {
+ en: """
+Takeover means the compression state is retained between client messages.
+"""
+ zh: """
+接管意味着在客户端消息之间保留压缩状态。
+"""
+ }
+ label: {
+ en: "Client context takeover"
+ zh: "客户端上下文接管"
+ }
+}
+
+fields_deflate_opts_server_max_window_bits {
+ desc {
+ en: """
+Specifies the size of the compression context for the server.
+"""
+ zh: """
+指定服务器压缩上下文的大小。
+"""
+ }
+ label: {
+ en: "Server compression max window size"
+ zh: "服务器压缩窗口大小"
+ }
+}
+
+fields_deflate_opts_client_max_window_bits {
+ desc {
+ en: """
+Specifies the size of the compression context for the client.
+"""
+ zh: """
+指定客户端压缩上下文的大小。
+"""
+ }
+ label: {
+ en: "Client compression max window size"
+ zh: "压缩窗口大小"
+ }
+}
+
+common_ssl_opts_schema_enable {
+ desc {
+ en: """
+Enable TLS.
+"""
+ zh: """启用 TLS"""
+ }
+ label: {
+ en: "Enable TLS."
+ zh: "启用 TLS"
+ }
+}
+
+common_ssl_opts_schema_cacertfile {
+ desc {
+ en: """
+Trusted PEM format CA certificates bundle file.
+The certificates in this file are used to verify the TLS peer's certificates.
+Append new certificates to the file if new CAs are to be trusted.
+There is no need to restart EMQX to have the updated file loaded, because
+the system regularly checks if file has been updated (and reload).
+NOTE: invalidating (deleting) a certificate from the file will not affect
+already established connections.
+"""
+ zh: """
+受信任的PEM格式CA证书捆绑文件
+此文件中的证书用于验证TLS对等方的证书。
+如果要信任新CA,请将新证书附加到文件中。
+无需重启EMQX即可加载更新的文件,因为系统会定期检查文件是否已更新(并重新加载)
+注意:从文件中失效(删除)证书不会影响已建立的连接。
+"""
+ }
+ label: {
+ en: "CACertfile"
+ zh: "CA 证书文件"
+ }
+}
+
+common_ssl_opts_schema_certfile {
+ desc {
+ en: """
+PEM format certificates chain file.
+The certificates in this file should be in reversed order of the certificate
+issue chain. That is, the host's certificate should be placed in the beginning
+of the file, followed by the immediate issuer certificate and so on.
+Although the root CA certificate is optional, it should be placed at the end of
+the file if it is to be added.
+"""
+ zh: """
+PEM格式证书链文件
+此文件中的证书应与证书颁发链的顺序相反。也就是说,主机的证书应该放在文件的开头,然后是直接颁发者证书,依此类推。
+虽然根CA证书是可选的,但它应该放在
+如果要添加文件,请将其删除。
+"""
+ }
+ label: {
+ en: "Certfile"
+ zh: "证书文件"
+ }
+}
+
+common_ssl_opts_schema_keyfile {
+ desc {
+ en: """
+PEM format private key file.
+"""
+ zh: """
+PEM格式的私钥文件。
+"""
+ }
+ label: {
+ en: "Keyfile"
+ zh: "私钥文件"
+ }
+}
+
+common_ssl_opts_schema_verify {
+ desc {
+ en: """
+Enable or disable peer verification.
+"""
+ zh: """
+启用或禁用对等验证。
+"""
+ }
+ label: {
+ en: "Verify peer"
+ zh: "对等验证"
+ }
+}
+
+common_ssl_opts_schema_reuse_sessions {
+ desc {
+ en: """
+Enable TLS session reuse.
+"""
+ zh: """
+启用 TLS 会话重用。
+"""
+ }
+ label: {
+ en: "TLS session reuse"
+ zh: "TLS 会话重用"
+ }
+}
+
+common_ssl_opts_schema_depth {
+ desc {
+ en: """
+Maximum number of non-self-issued intermediate certificates that can follow the peer certificate in a valid certification path. So, if depth is 0 the PEER must be signed by the trusted ROOT-CA directly; if 1 the path can be PEER, CA, ROOT-CA; if 2 the path can be PEER, CA, CA, ROOT-CA, and so on. The default value is 10.
+"""
+ zh: """
+在有效的证书路径中,可以跟随对等证书的非自颁发中间证书的最大数量。因此,如果深度为0,则对等方必须由受信任的根CA直接签名;如果1,路径可以是PEER、CA、ROOT-CA;如果是2,则路径可以是PEER、CA、CA、ROOT-CA等等。默认值为10。
+"""
+ }
+ label: {
+ en: "CACert Depth"
+ zh: "CA 证书深度"
+ }
+}
+
+common_ssl_opts_schema_password {
+ desc {
+ en: """
+String containing the user's password.
+Only used if the private key file is password-protected.
+"""
+ zh: """
+包含用户密码的字符串。
+仅在私钥文件受密码保护时使用。
+"""
+ }
+ label: {
+ en: "Keyfile passphrase"
+ zh: "秘钥文件密码"
+ }
+}
+
+common_ssl_opts_schema_versions {
+ desc {
+ en: """
+All TLS/DTLS versions to be supported.
+NOTE: PSK ciphers are suppressed by 'tlsv1.3' version config.
+In case PSK cipher suites are intended, make sure to configured
+['tlsv1.2', 'tlsv1.1']
here.
+"""
+ zh: """
+支持所有TLS/DTLS版本
+注:PSK密码被“tlsv1”抑制。3'版本配置
+如果打算使用PSK密码套件,请确保这里已配置
+['tlsv1.2','tlsv1.1']
。
+"""
+ }
+ label: {
+ en: "SSL versions"
+ zh: "SSL 版本"
+ }
+}
+
+ciphers_schema_0 {
+ desc {
+ en: """
+This config holds TLS cipher suite names separated by comma,
+or as an array of strings. e.g.
+"TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256"
or
+["TLS_AES_256_GCM_SHA384","TLS_AES_128_GCM_SHA256"]
.
+
+Ciphers (and their ordering) define the way in which the
+client and server encrypts information over the network connection.
+Selecting a good cipher suite is critical for the
+application's data security, confidentiality and performance.
+
+The names should be in OpenSSL string format (not RFC format).
+All default values and examples provided by EMQX config
+documentation are all in OpenSSL format.
+
+NOTE: Certain cipher suites are only compatible with
+specific TLS versions
('tlsv1.1', 'tlsv1.2' or 'tlsv1.3')
+incompatible cipher suites will be silently dropped.
+For instance, if only 'tlsv1.3' is given in the versions
,
+configuring cipher suites for other versions will have no effect.
+
+
+NOTE: PSK ciphers are suppressed by 'tlsv1.3' version config
+If PSK cipher suites are intended, 'tlsv1.3' should be disabled from versions
.
+PSK cipher suites: "RSA-PSK-AES256-GCM-SHA384,RSA-PSK-AES256-CBC-SHA384,
+RSA-PSK-AES128-GCM-SHA256,RSA-PSK-AES128-CBC-SHA256,
+RSA-PSK-AES256-CBC-SHA,RSA-PSK-AES128-CBC-SHA,
+RSA-PSK-DES-CBC3-SHA,RSA-PSK-RC4-SHA"
+"""
+ zh: """
+此配置保存由逗号分隔的 TLS 密码套件名称,或作为字符串数组。例如
+“TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256”
或
+[“TLS_AES_256_GCM_SHA384”、“TLS_AES_128_GCM_SHA256”]
。
+
+密码(及其顺序)定义了客户端和服务器通过网络连接加密信息的方式。
+选择一个好的密码套件对于应用程序的数据安全性、机密性和性能至关重要。
+
+名称应为 OpenSSL 字符串格式(而不是 RFC 格式)。
+EMQX 配置文档提供的所有默认值和示例都是 OpenSSL 格式
+注意:某些密码套件仅与特定的 TLS 版本
兼容('tlsv1.1'、'tlsv1.2'或'tlsv1.3')。
+不兼容的密码套件将被自动删除。
+
+例如,如果只有“tlsv1.3”。在版本
中给出,为其他版本配置密码套件将无效。
+
+
+注:PSK密码被“tlsv1.3”抑制。版本配置
+如果打算使用PSK密码套件,“tlsv1.3”。应在版本
中禁用。
+
+
+PSK密码套件:
+"RSA-PSK-AES256-GCM-SHA384,RSA-PSK-AES256-CBC-SHA384,
+RSA-PSK-AES128-GCM-SHA256,RSA-PSK-AES128-CBC-SHA256,
+RSA-PSK-AES256-CBC-SHA,RSA-PSK-AES128-CBC-SHA,
+RSA-PSK-DES-CBC3-SHA,RSA-PSK-RC4-SHA"
+"""
+ }
+ label: {
+ en: ""
+ zh: ""
+ }
+}
+
+common_ssl_opts_schema_user_lookup_fun {
+ desc {
+ en: """
+EMQX-internal callback that is used to lookup pre-shared key (PSK) identity.
+"""
+ zh: """
+用于查找预共享密钥(PSK)标识的 EMQX 内部回调。
+"""
+ }
+ label: {
+ en: "SSL PSK user lookup fun"
+ zh: "SSL PSK 用户回调"
+ }
+}
+
+common_ssl_opts_schema_secure_renegotiate {
+ desc {
+ en: """
+SSL parameter renegotiation is a feature that allows a client and a server
+to renegotiate the parameters of the SSL connection on the fly.
+RFC 5746 defines a more secure way of doing this. By enabling secure renegotiation,
+you drop support for the insecure renegotiation, prone to MitM attacks.
+"""
+ zh: """
+SSL 参数重新协商是一种允许客户端和服务器动态重新协商 SSL 连接参数的功能。
+RFC 5746 定义了一种更安全的方法。通过启用安全的重新协商,您就失去了对不安全的重新协商的支持,从而容易受到 MitM 攻击。
+"""
+ }
+ label: {
+ en: "SSL renegotiate"
+ zh: "SSL 重新协商"
+ }
+}
+
+server_ssl_opts_schema_dhfile {
+ desc {
+ en: """
+Path to a file containing PEM-encoded Diffie-Hellman parameters
+to be used by the server if a cipher suite using Diffie-Hellman
+key exchange is negotiated. If not specified, default parameters
+are used.
+NOTE: The dhfile
option is not supported by TLS 1.3.
+"""
+ zh: """
+如果协商使用Diffie-Hellman密钥交换的密码套件,则服务器将使用包含PEM编码的Diffie-Hellman参数的文件的路径。如果未指定,则使用默认参数
+
+注意:TLS 1.3不支持dhfile
选项。
+"""
+ }
+ label: {
+ en: "SSL dhfile"
+ zh: "SSL dhfile"
+ }
+}
+
+server_ssl_opts_schema_fail_if_no_peer_cert {
+ desc {
+ en: """
+Used together with {verify, verify_peer} by an TLS/DTLS server.
+If set to true, the server fails if the client does not have a
+certificate to send, that is, sends an empty certificate.
+If set to false, it fails only if the client sends an invalid
+certificate (an empty certificate is considered valid).
+"""
+ zh: """
+TLS/DTLS 服务器与 {verify,verify_peer} 一起使用。
+如果设置为true,则如果客户端没有要发送的证书,即发送空证书,服务器将失败。
+如果设置为false,则仅当客户端发送无效证书(空证书被视为有效证书)时才会失败。
+"""
+ }
+ label: {
+ en: "SSL fail if no peer cert"
+ zh: "没有证书则 SSL 失败"
+ }
+}
+
+server_ssl_opts_schema_honor_cipher_order {
+ desc {
+ en: """
+An important security setting, it forces the cipher to be set based
+ on the server-specified order instead of the client-specified order,
+ hence enforcing the (usually more properly configured) security
+ ordering of the server administrator.
+"""
+ zh: """
+一个重要的安全设置,它强制根据服务器指定的顺序而不是客户机指定的顺序设置密码,从而强制服务器管理员执行(通常配置得更正确)安全顺序。
+"""
+ }
+ label: {
+ en: "SSL honor cipher order"
+ zh: "SSL honor cipher order"
+ }
+}
+
+server_ssl_opts_schema_client_renegotiation {
+ desc {
+ en: """
+In protocols that support client-initiated renegotiation,
+the cost of resources of such an operation is higher for the server than the client.
+This can act as a vector for denial of service attacks.
+The SSL application already takes measures to counter-act such attempts,
+but client-initiated renegotiation can be strictly disabled by setting this option to false.
+The default value is true. Note that disabling renegotiation can result in
+long-lived connections becoming unusable due to limits on
+the number of messages the underlying cipher suite can encipher.
+"""
+ zh: """
+在支持客户机发起的重新协商的协议中,这种操作的资源成本对于服务器来说高于客户机。
+这可能会成为拒绝服务攻击的载体。
+SSL 应用程序已经采取措施来反击此类尝试,但通过将此选项设置为 false,可以严格禁用客户端发起的重新协商。
+默认值为 true。请注意,由于基础密码套件可以加密的消息数量有限,禁用重新协商可能会导致长期连接变得不可用。
+"""
+ }
+ label: {
+ en: "SSL client renegotiation"
+ zh: "SSL 客户端冲协商"
+ }
+}
+
+server_ssl_opts_schema_handshake_timeout {
+ desc {
+ en: """
+Maximum time duration allowed for the handshake to complete
+"""
+ zh: """
+握手完成所允许的最长时间
+"""
+ }
+ label: {
+ en: "Handshake timeout"
+ zh: "握手超时时间"
+ }
+}
+
+fields_listeners_tcp {
+ desc {
+ en: """
+TCP listeners
+"""
+ zh: """TCP 监听器"""
+ }
+ label: {
+ en: "TCP listeners"
+ zh: "TCP 监听器"
+ }
+}
+
+fields_listeners_ssl {
+ desc {
+ en: """
+SSL listeners
+"""
+ zh: """SSL 监听器"""
+ }
+ label: {
+ en: "SSL listeners"
+ zh: "SSL 监听器"
+ }
+}
+
+fields_listeners_ws {
+ desc {
+ en: """
+HTTP websocket listeners
+"""
+ zh: """HTTP websocket 监听器"""
+ }
+ label: {
+ en: "HTTP websocket listeners"
+ zh: "HTTP websocket 监听器"
+ }
+}
+
+fields_listeners_wss {
+ desc {
+ en: """
+HTTPS websocket listeners
+"""
+ zh: """HTTPS websocket 监听器"""
+ }
+ label: {
+ en: "HTTPS websocket listeners"
+ zh: "HTTPS websocket 监听器"
+ }
+}
+
+fields_listeners_quic {
+ desc {
+ en: """
+QUIC listeners
+"""
+ zh: """QUIC 监听器"""
+ }
+ label: {
+ en: "QUIC listeners"
+ zh: "QUIC 监听器"
+ }
+}
+
+fields_mqtt_quic_listener_enabled {
+ desc {
+ en: """
+Enable QUIC listener.
+"""
+ zh: """启用 QUIC 监听器"""
+ }
+ label: {
+ en: "Enable QUIC listener"
+ zh: "启用 QUIC 监听器"
+ }
+}
+
+fields_mqtt_quic_listener_certfile {
+ desc {
+ en: """
+Path to the certificate file.
+"""
+ zh: """证书文件"""
+ }
+ label: {
+ en: "Certificate file"
+ zh: "证书文件"
+ }
+}
+
+fields_mqtt_quic_listener_keyfile {
+ desc {
+ en: """
+Path to the secret key file.
+"""
+ zh: """私钥文件"""
+ }
+ label: {
+ en: "Key file"
+ zh: "私钥文件"
+ }
+}
+
+fields_mqtt_quic_listener_idle_timeout {
+ desc {
+ en: """
+Close transport-layer connections from the clients that have not sent MQTT CONNECT
+message within this interval.
+"""
+ zh: """
+关闭在此间隔内未发送 MQTT CONNECT 消息的客户端的传输层连接。
+"""
+ }
+ label: {
+ en: "Idle Timeout"
+ zh: "发呆超时时间"
+ }
+}
+
+base_listener_bind {
+ desc {
+ en: """
+IP address and port for the listening socket.
+"""
+ zh: """
+监听套接字的 IP 地址和端口。
+"""
+ }
+ label: {
+ en: "IP address and port"
+ zh: "IP 地址和端口"
+ }
+}
+
+base_listener_acceptors {
+ desc {
+ en: """
+The size of the listener's receiving pool.
+"""
+ zh: """监听器接收池的大小。"""
+ }
+ label: {
+ en: "Acceptors Num"
+ zh: "接收器数量"
+ }
+}
+
+base_listener_max_connections {
+ desc {
+ en: """
+The maximum number of concurrent connections allowed by the listener.
+"""
+ zh: """
+监听器允许的最大并发连接数。
+"""
+ }
+ label: {
+ en: "Max connections"
+ zh: "最大并发连接数"
+ }
+}
+
+base_listener_mountpoint {
+ desc {
+ en: """
+When publishing or subscribing, prefix all topics with a mountpoint string.
+ The prefixed string will be removed from the topic name when the message
+ is delivered to the subscriber. The mountpoint is a way that users can use
+ to implement isolation of message routing between different listeners.
+ For example if a client A subscribes to `t` with `listeners.tcp..mountpoint`
+ set to `some_tenant`, then the client actually subscribes to the topic
+ `some_tenant/t`. Similarly, if another client B (connected to the same listener
+ as the client A) sends a message to topic `t`, the message is routed
+ to all the clients subscribed `some_tenant/t`, so client A will receive the
+ message, with topic name `t`.
+ Set to `""` to disable the feature.
+
+ Variables in mountpoint string:
+ - ${clientid}
: clientid
+ - ${username}
: username
+"""
+ zh: """
+发布或订阅时,请在所有主题前面加上 mountpoint 字符串。
+
+将消息传递给订阅者时,将从主题名称中删除带前缀的字符串。挂载点是一种用户可以用来实现不同侦听器之间消息路由隔离的方法。
+
+例如,如果客户机a使用`侦听器订阅` t'。tcp<名称>。mountpoint`设置为'some_tenant',那么客户端实际上订阅了主题'some_tenant/t'。类似地,如果另一个客户端B(与客户端A连接到同一个侦听器)向主题“t”发送消息,该消息将路由到所有订阅了“some_租户/t”的客户端,因此客户端A将接收主题名为“t”的消息
+
+设置为“”“”以禁用该功能
+
+mountpoint 字符串中的变量:
+- ${clientid}
: clientid
+- ${username}
: username
+"""
+ }
+ label: {
+ en: "mountpoint"
+ zh: "mountpoint"
+ }
+}
+
+base_listener_zone {
+ desc {
+ en: """
+The configuration zone to which the listener belongs.
+"""
+ zh: """
+监听器所属的配置组。
+"""
+ }
+ label: {
+ en: "Zone"
+ zh: "配置组"
+ }
+}
+
+base_listener_limiter {
+ desc {
+ en: """
+Type of the rate limit.
+"""
+ zh: """
+速率限制类型
+"""
+ }
+ label: {
+ en: "Type of the rate limit."
+ zh: "速率限制类型"
+ }
+}
+
+mqtt_listener_access_rules {
+ desc {
+ en: """
+The access control rules for this listener.
See: https://github.com/emqtt/esockd#allowdeny
+"""
+ zh: """此监听器的访问控制规则。"""
+ }
+ label: {
+ en: "Access rules"
+ zh: "访问控制规则"
+ }
+}
+
+mqtt_listener_proxy_protocol {
+ desc {
+ en: """
+Enable the Proxy Protocol V1/2 if the EMQX cluster is deployed behind HAProxy or Nginx.
+See: https://www.haproxy.com/blog/haproxy/proxy-protocol/
+"""
+ zh: """
+如果EMQX集群部署在 HAProxy 或 Nginx 之后,请启用代理协议 V1/2
+详情见: https://www.haproxy.com/blog/haproxy/proxy-protocol/
+"""
+ }
+ label: {
+ en: "Proxy protocol"
+ zh: "Proxy protocol"
+ }
+}
+
+mqtt_listener_proxy_protocol_timeout {
+ desc {
+ en: """
+Timeout for proxy protocol. EMQX will close the TCP connection if proxy protocol packet is not received within the timeout.
+"""
+ zh: """
+代理协议超时。如果在超时时间内未收到代理协议数据包,EMQX将关闭TCP连接。
+"""
+ }
+ label: {
+ en: "Proxy protocol timeout"
+ zh: "Proxy protocol 超时时间"
+ }
+}
+
+authentication_0 {
+ desc {
+ en: """
+Per-listener authentication override.
+Authentication can be one single authenticator instance or a chain of authenticators as an array.
+When authenticating a login (username, client ID, etc.) the authenticators are checked in the configured order.
+
+"""
+ zh: """
+每侦听器身份验证覆盖。
+身份验证可以是单个身份验证程序实例,也可以是一个数组形式的身份验证程序链。
+验证登录名(用户名、客户端ID等)时,将按配置的顺序检查验证器
+"""
+ }
+ label: {
+ en: "Per-listener authentication override"
+ zh: "每个监听器的认证覆盖"
+ }
+}
+
+fields_rate_limit_max_conn_rate {
+ desc {
+ en: """
+Maximum connections per second.
+"""
+ zh: """
+每秒最大连接数。
+"""
+ }
+ label: {
+ en: "Max connection rate"
+ zh: "每秒最大连接数"
+ }
+}
+
+fields_rate_limit_conn_messages_in {
+ desc {
+ en: """
+Message limit for the external MQTT connections.
+"""
+ zh: """
+外部 MQTT 连接的消息限制。
+"""
+ }
+ label: {
+ en: "connecting messages in"
+ zh: "外部 MQTT 连接的消息限制"
+ }
+}
+
+fields_rate_limit_conn_bytes_in {
+ desc {
+ en: """
+Limit the rate of receiving packets for a MQTT connection.
+The rate is counted by bytes of packets per second.
+"""
+ zh: """
+限制 MQTT 连接接收数据包的速率。
+速率以每秒的数据包字节数计算。
+"""
+ }
+ label: {
+ en: "Connection bytes in"
+ zh: "数据包速率"
+ }
+}
+
+client_ssl_opts_schema_server_name_indication {
+ desc {
+ en: """
+Specify the host name to be used in TLS Server Name Indication extension.
+For instance, when connecting to "server.example.net", the genuine server
+which accepts the connection and performs TLS handshake may differ from the
+host the TLS client initially connects to, e.g. when connecting to an IP address
+or when the host has multiple resolvable DNS records
+If not specified, it will default to the host name string which is used
+to establish the connection, unless it is IP addressed used.
+The host name is then also used in the host name verification of the peer
+certificate.
The special value 'disable' prevents the Server Name
+Indication extension from being sent and disables the hostname
+verification check.
+"""
+ zh: """
+指定要在 TLS 服务器名称指示扩展中使用的主机名
+例如,当连接到“server.example.net”时,接受连接并执行TLS握手的真正服务器可能与TLS客户端最初连接到的主机不同,例如,当连接到IP地址时,或者当主机具有多个可解析的DNS记录时
+如果未指定,它将默认为使用的主机名字符串
+建立连接,除非使用IP地址
+然后,主机名也用于对等机的主机名验证
+证书
特殊值“disable”阻止发送服务器名称指示扩展,并禁用主机名验证检查。
+"""
+ }
+ label: {
+ en: "Server Name Indication"
+ zh: "服务器名称指示"
+ }
+}
+
+fields_tcp_opts_active_n {
+ desc {
+ en: """
+Specify the {active, N} option for this Socket.
+See: https://erlang.org/doc/man/inet.html#setopts-2
+"""
+ zh: """
+为此套接字指定{active,N}选项
+See: https://erlang.org/doc/man/inet.html#setopts-2
+"""
+ }
+ label: {
+ en: "active_n"
+ zh: "active_n"
+ }
+}
+
+fields_tcp_opts_backlog {
+ desc {
+ en: """
+TCP backlog defines the maximum length that the queue of
+ pending connections can grow to.
+"""
+ zh: """
+TCP backlog 定义了挂起连接队列可以增长到的最大长度。
+"""
+ }
+ label: {
+ en: "TCP backlog length"
+ zh: "TCP 连接队列长度"
+ }
+}
+
+fields_tcp_opts_send_timeout {
+ desc {
+ en: """
+The TCP send timeout for the connections.
+"""
+ zh: """
+连接的TCP发送超时。
+"""
+ }
+ label: {
+ en: "TCP send timeout"
+ zh: "TCP 发送超时"
+ }
+}
+
+fields_tcp_opts_send_timeout_close {
+ desc {
+ en: """
+Close the connection if send timeout.
+"""
+ zh: """
+如果发送超时,则关闭连接。
+"""
+ }
+ label: {
+ en: "TCP send timeout close"
+ zh: "TCP 发送超时关闭连接"
+ }
+}
+
+fields_tcp_opts_recbuf {
+ desc {
+ en: """
+The TCP receive buffer (OS kernel) for the connections.
+"""
+ zh: """
+连接的 TCP 接收缓冲区(OS内核)。
+"""
+ }
+ label: {
+ en: "TCP receive buffer"
+ zh: "TCP 接收缓冲区"
+ }
+}
+
+fields_tcp_opts_sndbuf {
+ desc {
+ en: """
+The TCP send buffer (OS kernel) for the connections.
+"""
+ zh: """
+连接的 TCP 发送缓冲区(OS内核)。
+"""
+ }
+ label: {
+ en: "TCP send buffer"
+ zh: "TCP 发送缓冲区"
+ }
+}
+
+fields_tcp_opts_buffer {
+ desc {
+ en: """
+The size of the user-space buffer used by the driver.
+"""
+ zh: """
+驱动程序使用的用户空间缓冲区的大小。
+"""
+ }
+ label: {
+ en: "TCP user-space buffer"
+ zh: "TCP 用户态缓冲区"
+ }
+}
+
+fields_tcp_opts_high_watermark {
+ desc {
+ en: """
+The socket is set to a busy state when the amount of data queued internally
+ by the VM socket implementation reaches this limit.
+"""
+ zh: """
+当 VM 套接字实现内部排队的数据量达到此限制时,套接字将设置为忙碌状态。
+"""
+ }
+ label: {
+ en: "TCP 高水位线"
+ zh: ""
+ }
+}
+
+fields_tcp_opts_nodelay {
+ desc {
+ en: """
+The TCP_NODELAY flag for the connections.
+"""
+ zh: """
+连接的 TCP_NODELAY 标识
+"""
+ }
+ label: {
+ en: "TCP_NODELAY"
+ zh: "TCP_NODELAY"
+ }
+}
+
+fields_tcp_opts_reuseaddr {
+ desc {
+ en: """
+The SO_REUSEADDR flag for the connections.
+"""
+ zh: """
+连接的 SO_REUSEADDR 标识
+"""
+ }
+ label: {
+ en: "SO_REUSEADDR"
+ zh: "SO_REUSEADDR"
+ }
+}
+
+fields_trace_payload_encode {
+ desc {
+ en: """
+Determine the format of the payload format in the trace file.
+`text`: Text-based protocol or plain text protocol.
+ It is recommended when payload is JSON encoded.
+`hex`: Binary hexadecimal encode. It is recommended when payload is a custom binary protocol.
+`hidden`: payload is obfuscated as `******`
+
+"""
+ zh: """
+确定跟踪文件中有效负载格式的格式
+`text`:基于文本的协议或纯文本协议。
+建议在有效负载为JSON编码时使用
+`hex`:二进制十六进制编码。当有效负载是自定义二进制协议时,建议使用此选项
+`hidden`:有效负载被模糊化为 `******`
+"""
+ }
+ label: {
+ en: "Payload encode"
+ zh: "有效负载编码"
+ }
+}
+
+fields_ws_opts_mqtt_path {
+ desc {
+ en: """
+WebSocket's MQTT protocol path. So the address of EMQX Broker's WebSocket is:
+ws://{ip}:{port}/mqtt
+"""
+ zh: """
+WebSocket 的 MQTT 协议路径。因此,EMQX Broker的WebSocket地址为:
+ws://{ip}:{port}/mqtt
+"""
+ }
+ label: {
+ en: "WS MQTT Path"
+ zh: "WS MQTT 路径"
+ }
+}
+
+fields_ws_opts_mqtt_piggyback {
+ desc {
+ en: """
+Whether a WebSocket message is allowed to contain multiple MQTT packets.
+"""
+ zh: """
+WebSocket消息是否允许包含多个 MQTT 数据包。
+"""
+ }
+ label: {
+ en: "MQTT Piggyback"
+ zh: "MQTT Piggyback"
+ }
+}
+
+fields_ws_opts_compress {
+ desc {
+ en: """
+If true
, compress WebSocket messages using zlib
.
+The configuration items under deflate_opts
belong to the compression-related parameter configuration.
+"""
+ zh: """
+如果 true
,则使用zlib
压缩 WebSocket 消息
+deflate_opts
下的配置项属于压缩相关参数配置。
+"""
+ }
+ label: {
+ en: "Ws compress"
+ zh: "Ws 压缩"
+ }
+}
+
+fields_ws_opts_idle_timeout {
+ desc {
+ en: """
+Close transport-layer connections from the clients that have not sent MQTT CONNECT
+message within this interval.
+"""
+ zh: """
+关闭在此间隔内未发送 MQTT CONNECT 消息的客户端的传输层连接。
+"""
+ }
+ label: {
+ en: "WS idle timeout"
+ zh: "WS 发呆时间"
+ }
+}
+
+fields_ws_opts_max_frame_size {
+ desc {
+ en: """
+The maximum length of a single MQTT packet.
+"""
+ zh: """
+单个 MQTT 数据包的最大长度。
+"""
+ }
+ label: {
+ en: "Max frame size"
+ zh: "最大数据包长度"
+ }
+}
+
+fields_ws_opts_fail_if_no_subprotocol {
+ desc {
+ en: """
+If true
, the server will return an error when
+ the client does not carry the Sec-WebSocket-Protocol
field.
+
Note: WeChat applet needs to disable this verification.
+"""
+ zh: """
+如果true
,当客户端未携带Sec WebSocket Protocol
字段时,服务器将返回一个错误。
+
注意:微信小程序需要禁用此验证。
+"""
+ }
+ label: {
+ en: "Fail if no subprotocol"
+ zh: "无 subprotocol 则失败"
+ }
+}
+
+fields_ws_opts_supported_subprotocols {
+ desc {
+ en: """
+Comma-separated list of supported subprotocols.
+"""
+ zh: """
+逗号分隔的 subprotocols 支持列表。
+"""
+ }
+ label: {
+ en: "Supported subprotocols"
+ zh: "Subprotocols 支持列表"
+ }
+}
+
+fields_ws_opts_check_origin_enable {
+ desc {
+ en: """
+If true
, origin
HTTP header will be
+ validated against the list of allowed origins configured in check_origins
+ parameter.
+"""
+ zh: """
+如果true
,origin
HTTP 头将根据check_origins
参数中配置的允许来源列表进行验证。
+"""
+ }
+ label: {
+ en: "Check origin"
+ zh: "检查 origin"
+ }
+}
+
+fields_ws_opts_allow_origin_absence {
+ desc {
+ en: """
+If false
and check_origin_enable
is
+ true
, the server will reject requests that don't have origin
+ HTTP header.
+"""
+ zh: """
+If false
and check_origin_enable
is true
, the server will reject requests that don't have origin
HTTP header.
+"""
+ }
+ label: {
+ en: "Allow origin absence"
+ zh: "允许 origin 缺失"
+ }
+}
+
+fields_ws_opts_check_origins {
+ desc {
+ en: """
+List of allowed origins.
See check_origin_enable
.
+"""
+ zh: """
+允许的 origins 列表
+"""
+ }
+ label: {
+ en: "Allowed origins"
+ zh: "允许的 origins"
+ }
+}
+
+fields_ws_opts_proxy_address_header {
+ desc {
+ en: """
+HTTP header used to pass information about the client IP address.
+Relevant when the EMQX cluster is deployed behind a load-balancer.
+"""
+ zh: """
+HTTP 头,用于传递有关客户端 IP 地址的信息。
+当 EMQX 集群部署在负载平衡器后面时,这一点非常重要。
+"""
+ }
+ label: {
+ en: "Proxy address header"
+ zh: "客户端地址头"
+ }
+}
+
+fields_ws_opts_proxy_port_header {
+ desc {
+ en: """
+HTTP header used to pass information about the client port.
+Relevant when the EMQX cluster is deployed behind a load-balancer.
+"""
+ zh: """
+HTTP 头,用于传递有关客户端端口的信息。
+当 EMQX 集群部署在负载平衡器后面时,这一点非常重要。
+"""
+ }
+ label: {
+ en: "Proxy port header"
+ zh: "客户端端口头"
+ }
+}
+
}
diff --git a/apps/emqx/src/emqx_schema.erl b/apps/emqx/src/emqx_schema.erl
index a4a1c8598..7e72f52df 100644
--- a/apps/emqx/src/emqx_schema.erl
+++ b/apps/emqx/src/emqx_schema.erl
@@ -102,11 +102,6 @@
-elvis([{elvis_style, god_modules, disable}]).
--define(IDLE_TIMOUT_DESC,
- "Close transport-layer connections from the clients that have not sent MQTT CONNECT\n"
- "message within this interval."
-).
-
namespace() -> undefined.
roots() ->
@@ -295,11 +290,7 @@ fields("authorization") ->
default => allow,
required => true,
%% TODO: make sources a reference link
- desc =>
- "Default access control action if the user or client matches no ACL rules,\n"
- "or if no such user or client is found by the configurable authorization\n"
- "sources such as built_in_database, an HTTP API, or a query against PostgreSQL.\n"
- "Find more details in 'authorization.sources' config."
+ desc => ?DESC(fields_authorization_no_match)
}
)},
{"deny_action",
@@ -308,7 +299,7 @@ fields("authorization") ->
#{
default => ignore,
required => true,
- desc => "The action when the authorization check rejects an operation."
+ desc => ?DESC(fields_authorization_deny_action)
}
)},
{"cache",
@@ -324,7 +315,7 @@ fields("cache") ->
boolean(),
#{
default => true,
- desc => "Enable or disable the authorization cache."
+ desc => ?DESC(fields_cache_enable)
}
)},
{"max_size",
@@ -332,7 +323,7 @@ fields("cache") ->
range(1, 1048576),
#{
default => 32,
- desc => "Maximum number of cached items."
+ desc => ?DESC(fields_cache_max_size)
}
)},
{"ttl",
@@ -340,7 +331,7 @@ fields("cache") ->
duration(),
#{
default => "1m",
- desc => "Time to live for the cached data."
+ desc => ?DESC(fields_cache_ttl)
}
)}
];
@@ -581,7 +572,7 @@ fields("rate_limit") ->
hoconsc:union([infinity, integer()]),
#{
default => 1000,
- desc => "Maximum connections per second."
+ desc => ?DESC(fields_rate_limit_max_conn_rate)
}
)},
{"conn_messages_in",
@@ -589,7 +580,7 @@ fields("rate_limit") ->
hoconsc:union([infinity, comma_separated_list()]),
#{
default => infinity,
- desc => "Message limit for the external MQTT connections."
+ desc => ?DESC(fields_rate_limit_conn_messages_in)
}
)},
{"conn_bytes_in",
@@ -597,9 +588,7 @@ fields("rate_limit") ->
hoconsc:union([infinity, comma_separated_list()]),
#{
default => infinity,
- desc =>
- "Limit the rate of receiving packets for a MQTT connection.\n"
- "The rate is counted by bytes of packets per second."
+ desc => ?DESC(fields_rate_limit_conn_bytes_in)
}
)}
];
@@ -758,7 +747,7 @@ fields("listeners") ->
sc(
map(name, ref("mqtt_tcp_listener")),
#{
- desc => "TCP listeners",
+ desc => ?DESC(fields_listeners_tcp),
required => {false, recursively}
}
)},
@@ -766,7 +755,7 @@ fields("listeners") ->
sc(
map(name, ref("mqtt_ssl_listener")),
#{
- desc => "SSL listeners",
+ desc => ?DESC(fields_listeners_ssl),
required => {false, recursively}
}
)},
@@ -774,7 +763,7 @@ fields("listeners") ->
sc(
map(name, ref("mqtt_ws_listener")),
#{
- desc => "HTTP websocket listeners",
+ desc => ?DESC(fields_listeners_ws),
required => {false, recursively}
}
)},
@@ -782,7 +771,7 @@ fields("listeners") ->
sc(
map(name, ref("mqtt_wss_listener")),
#{
- desc => "HTTPS websocket listeners",
+ desc => ?DESC(fields_listeners_wss),
required => {false, recursively}
}
)},
@@ -790,7 +779,7 @@ fields("listeners") ->
sc(
map(name, ref("mqtt_quic_listener")),
#{
- desc => "QUIC listeners",
+ desc => ?DESC(fields_listeners_quic),
required => {false, recursively}
}
)}
@@ -852,24 +841,30 @@ fields("mqtt_quic_listener") ->
{"enabled",
sc(
boolean(),
- #{default => true, desc => "Enable QUIC listener."}
+ #{
+ default => true,
+ desc => ?DESC(fields_mqtt_quic_listener_enabled)
+ }
)},
%% TODO: ensure cacertfile is configurable
{"certfile",
sc(
string(),
- #{desc => "Path to the certificate file."}
+ #{desc => ?DESC(fields_mqtt_quic_listener_certfile)}
)},
{"keyfile",
sc(
string(),
- #{desc => "Path to the secret key file."}
+ #{desc => ?DESC(fields_mqtt_quic_listener_keyfile)}
)},
{"ciphers", ciphers_schema(quic)},
{"idle_timeout",
sc(
duration(),
- #{default => "15s", desc => ?IDLE_TIMOUT_DESC}
+ #{
+ default => "15s",
+ desc => ?DESC(fields_mqtt_quic_listener_idle_timeout)
+ }
)}
] ++ base_listener();
fields("ws_opts") ->
@@ -879,9 +874,7 @@ fields("ws_opts") ->
string(),
#{
default => "/mqtt",
- desc =>
- "WebSocket's MQTT protocol path. So the address of\n"
- " EMQX Broker's WebSocket is: ws://{ip}:{port}/mqtt
"
+ desc => ?DESC(fields_ws_opts_mqtt_path)
}
)},
{"mqtt_piggyback",
@@ -889,8 +882,7 @@ fields("ws_opts") ->
hoconsc:enum([single, multiple]),
#{
default => multiple,
- desc =>
- "Whether a WebSocket message is allowed to contain multiple MQTT packets."
+ desc => ?DESC(fields_ws_opts_mqtt_piggyback)
}
)},
{"compress",
@@ -898,10 +890,7 @@ fields("ws_opts") ->
boolean(),
#{
default => false,
- desc =>
- "If true
, compress WebSocket messages using zlib
.
\n"
- "The configuration items under deflate_opts
"
- "belong to the compression-related parameter configuration."
+ desc => ?DESC(fields_ws_opts_compress)
}
)},
{"idle_timeout",
@@ -909,7 +898,7 @@ fields("ws_opts") ->
duration(),
#{
default => "15s",
- desc => ?IDLE_TIMOUT_DESC
+ desc => ?DESC(fields_mqtt_quic_listener_idle_timeout)
}
)},
{"max_frame_size",
@@ -917,7 +906,7 @@ fields("ws_opts") ->
hoconsc:union([infinity, integer()]),
#{
default => infinity,
- desc => "The maximum length of a single MQTT packet."
+ desc => ?DESC(fields_ws_opts_max_frame_size)
}
)},
{"fail_if_no_subprotocol",
@@ -925,10 +914,7 @@ fields("ws_opts") ->
boolean(),
#{
default => true,
- desc =>
- "If true
, the server will return an error when\n"
- " the client does not carry the Sec-WebSocket-Protocol
field.\n"
- "
Note: WeChat applet needs to disable this verification."
+ desc => ?DESC(fields_ws_opts_fail_if_no_subprotocol)
}
)},
{"supported_subprotocols",
@@ -936,7 +922,7 @@ fields("ws_opts") ->
comma_separated_list(),
#{
default => "mqtt, mqtt-v3, mqtt-v3.1.1, mqtt-v5",
- desc => "Comma-separated list of supported subprotocols."
+ desc => ?DESC(fields_ws_opts_supported_subprotocols)
}
)},
{"check_origin_enable",
@@ -944,10 +930,7 @@ fields("ws_opts") ->
boolean(),
#{
default => false,
- desc =>
- "If true
, origin
HTTP header will be\n"
- " validated against the list of allowed origins configured in check_origins
\n"
- " parameter."
+ desc => ?DESC(fields_ws_opts_check_origin_enable)
}
)},
{"allow_origin_absence",
@@ -955,10 +938,7 @@ fields("ws_opts") ->
boolean(),
#{
default => true,
- desc =>
- "If false
and check_origin_enable
is\n"
- " true
, the server will reject requests that don't have origin
\n"
- " HTTP header."
+ desc => ?DESC(fields_ws_opts_allow_origin_absence)
}
)},
{"check_origins",
@@ -966,7 +946,7 @@ fields("ws_opts") ->
hoconsc:array(binary()),
#{
default => [],
- desc => "List of allowed origins.
See check_origin_enable
."
+ desc => ?DESC(fields_ws_opts_check_origins)
}
)},
{"proxy_address_header",
@@ -974,9 +954,7 @@ fields("ws_opts") ->
string(),
#{
default => "x-forwarded-for",
- desc =>
- "HTTP header used to pass information about the client IP address.\n"
- " Relevant when the EMQX cluster is deployed behind a load-balancer."
+ desc => ?DESC(fields_ws_opts_proxy_address_header)
}
)},
{"proxy_port_header",
@@ -984,9 +962,7 @@ fields("ws_opts") ->
string(),
#{
default => "x-forwarded-port",
- desc =>
- "HTTP header used to pass information about the client port.\n"
- " Relevant when the EMQX cluster is deployed behind a load-balancer."
+ desc => ?DESC(fields_ws_opts_proxy_port_header)
}
)},
{"deflate_opts",
@@ -1002,9 +978,7 @@ fields("tcp_opts") ->
integer(),
#{
default => 100,
- desc =>
- "Specify the {active, N} option for this Socket.
\n"
- " See: https://erlang.org/doc/man/inet.html#setopts-2"
+ desc => ?DESC(fields_tcp_opts_active_n)
}
)},
{"backlog",
@@ -1012,9 +986,7 @@ fields("tcp_opts") ->
integer(),
#{
default => 1024,
- desc =>
- "TCP backlog defines the maximum length that the queue of\n"
- " pending connections can grow to."
+ desc => ?DESC(fields_tcp_opts_backlog)
}
)},
{"send_timeout",
@@ -1022,7 +994,7 @@ fields("tcp_opts") ->
duration(),
#{
default => "15s",
- desc => "The TCP send timeout for the connections."
+ desc => ?DESC(fields_tcp_opts_send_timeout)
}
)},
{"send_timeout_close",
@@ -1030,32 +1002,30 @@ fields("tcp_opts") ->
boolean(),
#{
default => true,
- desc => "Close the connection if send timeout."
+ desc => ?DESC(fields_tcp_opts_send_timeout_close)
}
)},
{"recbuf",
sc(
bytesize(),
- #{desc => "The TCP receive buffer (OS kernel) for the connections."}
+ #{desc => ?DESC(fields_tcp_opts_recbuf)}
)},
{"sndbuf",
sc(
bytesize(),
- #{desc => "The TCP send buffer (OS kernel) for the connections."}
+ #{desc => ?DESC(fields_tcp_opts_sndbuf)}
)},
{"buffer",
sc(
bytesize(),
- #{desc => "The size of the user-space buffer used by the driver."}
+ #{desc => ?DESC(fields_tcp_opts_buffer)}
)},
{"high_watermark",
sc(
bytesize(),
#{
default => "1MB",
- desc =>
- "The socket is set to a busy state when the amount of data queued internally\n"
- " by the VM socket implementation reaches this limit."
+ desc => ?DESC(fields_tcp_opts_high_watermark)
}
)},
{"nodelay",
@@ -1063,7 +1033,7 @@ fields("tcp_opts") ->
boolean(),
#{
default => false,
- desc => "The TCP_NODELAY flag for the connections."
+ desc => ?DESC(fields_tcp_opts_nodelay)
}
)},
{"reuseaddr",
@@ -1071,7 +1041,7 @@ fields("tcp_opts") ->
boolean(),
#{
default => true,
- desc => "The SO_REUSEADDR flag for the connections."
+ desc => ?DESC(fields_tcp_opts_reuseaddr)
}
)}
];
@@ -1095,62 +1065,56 @@ fields("listener_wss_opts") ->
},
true
);
-fields(ssl_client_opts) ->
+fields("ssl_client_opts") ->
client_ssl_opts_schema(#{});
fields("deflate_opts") ->
[
{"level",
sc(
hoconsc:enum([none, default, best_compression, best_speed]),
- #{desc => "Compression level."}
+ #{desc => ?DESC(fields_deflate_opts_level)}
)},
{"mem_level",
sc(
range(1, 9),
#{
default => 8,
- desc =>
- "Specifies the size of the compression state.
\n"
- " Lower values decrease memory usage per connection."
+ desc => ?DESC(fields_deflate_opts_mem_level)
}
)},
{"strategy",
sc(
hoconsc:enum([default, filtered, huffman_only, rle]),
- #{desc => "Specifies the compression strategy."}
+ #{desc => ?DESC(fields_deflate_opts_strategy)}
)},
{"server_context_takeover",
sc(
hoconsc:enum([takeover, no_takeover]),
#{
- desc =>
- "Takeover means the compression state is retained\n"
- " between server messages."
+ desc => ?DESC(fields_deflate_opts_server_context_takeover)
}
)},
{"client_context_takeover",
sc(
hoconsc:enum([takeover, no_takeover]),
#{
- desc =>
- "Takeover means the compression state is retained\n"
- " between client messages."
+ desc => ?DESC(fields_deflate_opts_client_context_takeover)
}
)},
{"server_max_window_bits",
sc(
range(8, 15),
#{
- default => 15,
- desc => "Specifies the size of the compression context for the server."
+ desc => ?DESC(fields_deflate_opts_server_max_window_bits),
+ default => 15
}
)},
{"client_max_window_bits",
sc(
range(8, 15),
#{
- default => 15,
- desc => "Specifies the size of the compression context for the client."
+ desc => ?DESC(fields_deflate_opts_client_max_window_bits),
+ default => 15
}
)}
];
@@ -1526,13 +1490,7 @@ fields("trace") ->
{"payload_encode",
sc(hoconsc:enum([hex, text, hidden]), #{
default => text,
- desc =>
- "Determine the format of the payload format in the trace file.
\n"
- "`text`: Text-based protocol or plain text protocol.\n"
- " It is recommended when payload is JSON encoded.
\n"
- "`hex`: Binary hexadecimal encode. It is recommended when payload is "
- "a custom binary protocol.
\n"
- "`hidden`: payload is obfuscated as `******`\n"
+ desc => ?DESC(fields_trace_payload_encode)
})}
].
@@ -1543,9 +1501,7 @@ mqtt_listener() ->
sc(
hoconsc:array(string()),
#{
- desc =>
- "The access control rules for this listener.
"
- "See: https://github.com/emqtt/esockd#allowdeny",
+ desc => ?DESC(mqtt_listener_access_rules),
default => [<<"allow all">>]
}
)},
@@ -1553,20 +1509,15 @@ mqtt_listener() ->
sc(
boolean(),
#{
- default => false,
- desc =>
- "Enable the Proxy Protocol V1/2 if the EMQX cluster is deployed\n"
- " behind HAProxy or Nginx.
"
- "See: https://www.haproxy.com/blog/haproxy/proxy-protocol/"
+ desc => ?DESC(mqtt_listener_proxy_protocol),
+ default => false
}
)},
{"proxy_protocol_timeout",
sc(
duration(),
#{
- desc =>
- "Timeout for proxy protocol. EMQX will close the TCP connection "
- "if proxy protocol packet is not received within the timeout.",
+ desc => ?DESC(mqtt_listener_proxy_protocol_timeout),
default => "3s"
}
)},
@@ -1580,8 +1531,8 @@ base_listener() ->
sc(
hoconsc:union([ip_port(), integer()]),
#{
- required => true,
- desc => "IP address and port for the listening socket."
+ desc => ?DESC(base_listener_bind),
+ required => true
}
)},
{"acceptors",
@@ -1589,7 +1540,7 @@ base_listener() ->
integer(),
#{
default => 16,
- desc => "The size of the listener's receiving pool."
+ desc => ?DESC(base_listener_acceptors)
}
)},
{"max_connections",
@@ -1597,7 +1548,7 @@ base_listener() ->
hoconsc:union([infinity, integer()]),
#{
default => infinity,
- desc => "The maximum number of concurrent connections allowed by the listener."
+ desc => ?DESC(base_listener_max_connections)
}
)},
{"mountpoint",
@@ -1605,38 +1556,23 @@ base_listener() ->
binary(),
#{
default => <<>>,
- desc =>
- "When publishing or subscribing, prefix all topics with a mountpoint string.\n"
- " The prefixed string will be removed from the topic name when the message\n"
- " is delivered to the subscriber. The mountpoint is a way that users can use\n"
- " to implement isolation of message routing between different listeners.\n"
- " For example if a client A subscribes to `t` with `listeners.tcp..mountpoint`\n"
- " set to `some_tenant`, then the client actually subscribes to the topic\n"
- " `some_tenant/t`. Similarly, if another client B (connected to the same listener\n"
- " as the client A) sends a message to topic `t`, the message is routed\n"
- " to all the clients subscribed `some_tenant/t`, so client A will receive the\n"
- " message, with topic name `t`.
\n"
- " Set to `\"\"` to disable the feature.
\n"
- "\n"
- " Variables in mountpoint string:\n"
- " - ${clientid}
: clientid\n"
- " - ${username}
: username"
+ desc => ?DESC(base_listener_mountpoint)
}
)},
{"zone",
sc(
atom(),
#{
- default => 'default',
- desc => "The configuration zone to which the listener belongs."
+ desc => ?DESC(base_listener_zone),
+ default => 'default'
}
)},
{"limiter",
sc(
map("ratelimit's type", emqx_limiter_schema:bucket_name()),
#{
- default => #{},
- desc => "Type of the rate limit."
+ desc => ?DESC(base_listener_limiter),
+ default => #{}
}
)}
].
@@ -1738,7 +1674,7 @@ desc("listener_ssl_opts") ->
"Socket options for SSL connections.";
desc("listener_wss_opts") ->
"Socket options for WebSocket/SSL connections.";
-desc(ssl_client_opts) ->
+desc("ssl_client_opts") ->
"Socket options for SSL clients.";
desc("deflate_opts") ->
"Compression options.";
@@ -1814,7 +1750,7 @@ common_ssl_opts_schema(Defaults) ->
boolean(),
#{
default => Df("enable", false),
- desc => "Enable TLS."
+ desc => ?DESC(common_ssl_opts_schema_enable)
}
)},
{"cacertfile",
@@ -1823,14 +1759,7 @@ common_ssl_opts_schema(Defaults) ->
#{
default => D("cacertfile"),
required => false,
- desc =>
- "Trusted PEM format CA certificates bundle file.
\n"
- "The certificates in this file are used to verify the TLS peer's certificates.\n"
- "Append new certificates to the file if new CAs are to be trusted.\n"
- "There is no need to restart EMQX to have the updated file loaded, because\n"
- "the system regularly checks if file has been updated (and reload).
\n"
- "NOTE: invalidating (deleting) a certificate from the file will not affect\n"
- "already established connections.\n"
+ desc => ?DESC(common_ssl_opts_schema_cacertfile)
}
)},
{"certfile",
@@ -1839,13 +1768,7 @@ common_ssl_opts_schema(Defaults) ->
#{
default => D("certfile"),
required => false,
- desc =>
- "PEM format certificates chain file.
\n"
- "The certificates in this file should be in reversed order of the certificate\n"
- "issue chain. That is, the host's certificate should be placed in the beginning\n"
- "of the file, followed by the immediate issuer certificate and so on.\n"
- "Although the root CA certificate is optional, it should be placed at the end of\n"
- "the file if it is to be added."
+ desc => ?DESC(common_ssl_opts_schema_certfile)
}
)},
{"keyfile",
@@ -1854,8 +1777,7 @@ common_ssl_opts_schema(Defaults) ->
#{
default => D("keyfile"),
required => false,
- desc =>
- "PEM format private key file."
+ desc => ?DESC(common_ssl_opts_schema_keyfile)
}
)},
{"verify",
@@ -1863,8 +1785,7 @@ common_ssl_opts_schema(Defaults) ->
hoconsc:enum([verify_peer, verify_none]),
#{
default => Df("verify", verify_none),
- desc =>
- "Enable or disable peer verification."
+ desc => ?DESC(common_ssl_opts_schema_verify)
}
)},
{"reuse_sessions",
@@ -1872,8 +1793,7 @@ common_ssl_opts_schema(Defaults) ->
boolean(),
#{
default => Df("reuse_sessions", true),
- desc =>
- "Enable TLS session reuse."
+ desc => ?DESC(common_ssl_opts_schema_reuse_sessions)
}
)},
{"depth",
@@ -1881,12 +1801,7 @@ common_ssl_opts_schema(Defaults) ->
integer(),
#{
default => Df("depth", 10),
- desc =>
- "Maximum number of non-self-issued intermediate certificates that can follow "
- "the peer certificate in a valid certification path. "
- "So, if depth is 0 the PEER must be signed by the trusted ROOT-CA directly; "
- "if 1 the path can be PEER, CA, ROOT-CA; if 2 the path can be PEER, CA, CA, ROOT-CA, "
- "and so on. The default value is 10."
+ desc => ?DESC(common_ssl_opts_schema_depth)
}
)},
{"password",
@@ -1895,9 +1810,7 @@ common_ssl_opts_schema(Defaults) ->
#{
sensitive => true,
required => false,
- desc =>
- "String containing the user's password. Only used if the private\n"
- "key file is password-protected."
+ desc => ?DESC(common_ssl_opts_schema_password)
}
)},
{"versions",
@@ -1905,23 +1818,18 @@ common_ssl_opts_schema(Defaults) ->
hoconsc:array(typerefl:atom()),
#{
default => default_tls_vsns(maps:get(versions, Defaults, tls_all_available)),
- desc =>
- "All TLS/DTLS versions to be supported.
\n"
- "NOTE: PSK ciphers are suppressed by 'tlsv1.3' version config
\n"
- "In case PSK cipher suites are intended, make sure to configured\n"
- "['tlsv1.2', 'tlsv1.1']
here.",
+ desc => ?DESC(common_ssl_opts_schema_versions),
validator => fun validate_tls_versions/1
}
)},
{"ciphers", ciphers_schema(D("ciphers"))},
- {user_lookup_fun,
+ {"user_lookup_fun",
sc(
typerefl:alias("string", any()),
#{
default => <<"emqx_tls_psk:lookup">>,
converter => fun ?MODULE:parse_user_lookup_fun/1,
- desc =>
- "EMQX-internal callback that is used to lookup pre-shared key (PSK) identity."
+ desc => ?DESC(common_ssl_opts_schema_user_lookup_fun)
}
)},
{"secure_renegotiate",
@@ -1929,11 +1837,7 @@ common_ssl_opts_schema(Defaults) ->
boolean(),
#{
default => Df("secure_renegotiate", true),
- desc =>
- "SSL parameter renegotiation is a feature that allows a client and a server\n"
- "to renegotiate the parameters of the SSL connection on the fly.\n"
- "RFC 5746 defines a more secure way of doing this. By enabling secure renegotiation,\n"
- "you drop support for the insecure renegotiation, prone to MitM attacks."
+ desc => ?DESC(common_ssl_opts_schema_secure_renegotiate)
}
)}
].
@@ -1958,12 +1862,7 @@ server_ssl_opts_schema(Defaults1, IsRanchListener) ->
#{
default => D("dhfile"),
required => false,
- desc =>
- "Path to a file containing PEM-encoded Diffie-Hellman parameters\n"
- "to be used by the server if a cipher suite using Diffie-Hellman\n"
- "key exchange is negotiated. If not specified, default parameters\n"
- "are used.
\n"
- "NOTE: The dhfile
option is not supported by TLS 1.3."
+ desc => ?DESC(server_ssl_opts_schema_dhfile)
}
)},
{"fail_if_no_peer_cert",
@@ -1971,12 +1870,7 @@ server_ssl_opts_schema(Defaults1, IsRanchListener) ->
boolean(),
#{
default => Df("fail_if_no_peer_cert", false),
- desc =>
- "Used together with {verify, verify_peer} by an TLS/DTLS server.\n"
- "If set to true, the server fails if the client does not have a\n"
- "certificate to send, that is, sends an empty certificate.\n"
- "If set to false, it fails only if the client sends an invalid\n"
- "certificate (an empty certificate is considered valid)."
+ desc => ?DESC(server_ssl_opts_schema_fail_if_no_peer_cert)
}
)},
{"honor_cipher_order",
@@ -1984,11 +1878,7 @@ server_ssl_opts_schema(Defaults1, IsRanchListener) ->
boolean(),
#{
default => Df("honor_cipher_order", true),
- desc =>
- "An important security setting, it forces the cipher to be set based\n"
- " on the server-specified order instead of the client-specified order,\n"
- " hence enforcing the (usually more properly configured) security\n"
- " ordering of the server administrator."
+ desc => ?DESC(server_ssl_opts_schema_honor_cipher_order)
}
)},
{"client_renegotiation",
@@ -1996,17 +1886,7 @@ server_ssl_opts_schema(Defaults1, IsRanchListener) ->
boolean(),
#{
default => Df("client_renegotiation", true),
- desc =>
- "In protocols that support client-initiated renegotiation,\n"
- "the cost of resources of such an operation is higher for the "
- "server than the client.\n"
- "This can act as a vector for denial of service attacks.\n"
- "The SSL application already takes measures to counter-act such attempts,\n"
- "but client-initiated renegotiation can be strictly disabled by setting "
- "this option to false.\n"
- "The default value is true. Note that disabling renegotiation can result in\n"
- "long-lived connections becoming unusable due to limits on\n"
- "the number of messages the underlying cipher suite can encipher."
+ desc => ?DESC(server_ssl_opts_schema_client_renegotiation)
}
)}
| [
@@ -2015,7 +1895,7 @@ server_ssl_opts_schema(Defaults1, IsRanchListener) ->
duration(),
#{
default => Df("handshake_timeout", "15s"),
- desc => "Maximum time duration allowed for the handshake to complete"
+ desc => ?DESC(server_ssl_opts_schema_handshake_timeout)
}
)}
|| IsRanchListener
@@ -2040,18 +1920,7 @@ client_ssl_opts_schema(Defaults1) ->
hoconsc:union([disable, string()]),
#{
required => false,
- desc =>
- "Specify the host name to be used in TLS Server Name Indication extension.
\n"
- "For instance, when connecting to \"server.example.net\", the genuine server\n"
- "which accepts the connection and performs TLS handshake may differ from the\n"
- "host the TLS client initially connects to, e.g. when connecting to an IP address\n"
- "or when the host has multiple resolvable DNS records
\n"
- "If not specified, it will default to the host name string which is used\n"
- "to establish the connection, unless it is IP addressed used.
\n"
- "The host name is then also used in the host name verification of the peer\n"
- "certificate.
The special value 'disable' prevents the Server Name\n"
- "Indication extension from being sent and disables the hostname\n"
- "verification check."
+ desc => ?DESC(client_ssl_opts_schema_server_name_indication)
}
)}
].
@@ -2080,7 +1949,12 @@ ciphers_schema(Default) ->
true -> undefined;
false -> fun validate_ciphers/1
end,
- desc =>
+ desc_id => "ciphers_schema_" ++
+ case Default of
+ quic -> "quic";
+ _ -> "0"
+ end,
+ desc_en =>
"This config holds TLS cipher suite names separated by comma,\n"
"or as an array of strings. e.g.\n"
"\"TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256\"
or\n"
@@ -2345,6 +2219,7 @@ authentication(Desc) ->
undefined -> Default;
Module -> hoconsc:lazy(Module:root_type())
end,
+ desc_id => authentication_0,
desc => iolist_to_binary([
Desc,
"\nAuthentication can be one single authenticator instance or a chain of "
diff --git a/apps/emqx_conf/src/emqx_conf_schema.erl b/apps/emqx_conf/src/emqx_conf_schema.erl
index 0fcbc7b32..4c8916835 100644
--- a/apps/emqx_conf/src/emqx_conf_schema.erl
+++ b/apps/emqx_conf/src/emqx_conf_schema.erl
@@ -251,7 +251,7 @@ fields(cluster_etcd) ->
, desc => ?DESC(cluster_etcd_node_ttl)
})}
, {"ssl",
- sc(hoconsc:ref(emqx_schema, ssl_client_opts),
+ sc(hoconsc:ref(emqx_schema, "ssl_client_opts"),
#{ desc => ?DESC(cluster_etcd_ssl)
, 'readOnly' => true
})}
diff --git a/apps/emqx_conf/test/emqx_conf_schema_tests.erl b/apps/emqx_conf/test/emqx_conf_schema_tests.erl
index b222a49ae..af70d2a94 100644
--- a/apps/emqx_conf/test/emqx_conf_schema_tests.erl
+++ b/apps/emqx_conf/test/emqx_conf_schema_tests.erl
@@ -7,8 +7,22 @@
-include_lib("eunit/include/eunit.hrl").
doc_gen_test() ->
- Dir = "tmp",
- ok = filelib:ensure_dir(filename:join("tmp", foo)),
- I18nFile = filename:join(["_build", "test", "lib", "emqx_dashboard", "etc", "i18n.conf.all"]),
- _ = emqx_conf:dump_schema(Dir, emqx_conf_schema, I18nFile),
- ok.
+ %% the json file too large to encode.
+ {
+ timeout,
+ 60,
+ fun() ->
+ Dir = "tmp",
+ ok = filelib:ensure_dir(filename:join("tmp", foo)),
+ I18nFile = filename:join([
+ "_build",
+ "test",
+ "lib",
+ "emqx_dashboard",
+ "etc",
+ "i18n.conf.all"
+ ]),
+ _ = emqx_conf:dump_schema(Dir, emqx_conf_schema, I18nFile),
+ ok
+ end
+ }.
diff --git a/apps/emqx_connector/src/emqx_connector_schema_lib.erl b/apps/emqx_connector/src/emqx_connector_schema_lib.erl
index 5398ac9fe..8600253c6 100644
--- a/apps/emqx_connector/src/emqx_connector_schema_lib.erl
+++ b/apps/emqx_connector/src/emqx_connector_schema_lib.erl
@@ -53,7 +53,7 @@ roots() -> [].
fields(_) -> [].
ssl_fields() ->
- [ {ssl, #{type => hoconsc:ref(emqx_schema, ssl_client_opts),
+ [ {ssl, #{type => hoconsc:ref(emqx_schema, "ssl_client_opts"),
default => #{<<"enable">> => false},
desc => ?DESC("ssl")
}
diff --git a/apps/emqx_exhook/src/emqx_exhook_schema.erl b/apps/emqx_exhook/src/emqx_exhook_schema.erl
index f865faef4..9e40e8507 100644
--- a/apps/emqx_exhook/src/emqx_exhook_schema.erl
+++ b/apps/emqx_exhook/src/emqx_exhook_schema.erl
@@ -100,7 +100,7 @@ fields(server) ->
];
fields(ssl_conf) ->
Schema = emqx_schema:client_ssl_opts_schema(#{}),
- lists:keydelete(user_lookup_fun, 1, Schema).
+ lists:keydelete("user_lookup_fun", 1, Schema).
desc(exhook) ->
"External hook (exhook) configuration.";
diff --git a/apps/emqx_gateway/src/emqx_gateway_schema.erl b/apps/emqx_gateway/src/emqx_gateway_schema.erl
index c862baf58..686ba1cc7 100644
--- a/apps/emqx_gateway/src/emqx_gateway_schema.erl
+++ b/apps/emqx_gateway/src/emqx_gateway_schema.erl
@@ -348,7 +348,7 @@ fields(exproto_grpc_handler) ->
{address, sc(binary(), #{required => true, desc => ?DESC(exproto_grpc_handler_address)})},
{ssl,
sc(
- ref(emqx_schema, ssl_client_opts),
+ ref(emqx_schema, "ssl_client_opts"),
#{
required => {false, recursively},
desc => ?DESC(exproto_grpc_handler_ssl)
diff --git a/lib-ee/emqx_enterprise_conf/test/emqx_enterprise_conf_schema_tests.erl b/lib-ee/emqx_enterprise_conf/test/emqx_enterprise_conf_schema_tests.erl
index 10c5998db..94d180377 100644
--- a/lib-ee/emqx_enterprise_conf/test/emqx_enterprise_conf_schema_tests.erl
+++ b/lib-ee/emqx_enterprise_conf/test/emqx_enterprise_conf_schema_tests.erl
@@ -7,8 +7,22 @@
-include_lib("eunit/include/eunit.hrl").
doc_gen_test() ->
- Dir = "tmp",
- ok = filelib:ensure_dir(filename:join("tmp", foo)),
- I18nFile = filename:join(["_build", "test", "lib", "emqx_dashboard", "etc", "i18n.conf.all"]),
- _ = emqx_conf:dump_schema(Dir, emqx_enterprise_conf_schema, I18nFile),
- ok.
+ %% the json file too large to encode.
+ {
+ timeout,
+ 60,
+ fun() ->
+ Dir = "tmp",
+ ok = filelib:ensure_dir(filename:join("tmp", foo)),
+ I18nFile = filename:join([
+ "_build",
+ "test",
+ "lib",
+ "emqx_dashboard",
+ "etc",
+ "i18n.conf.all"
+ ]),
+ _ = emqx_conf:dump_schema(Dir, emqx_enterprise_conf_schema, I18nFile),
+ ok
+ end
+ }.