Commit f390069308 for freeswitch.com

commit f3900693080eba3cd69864c5cf615955356ade4f
Author: Dmitry Verenitsin <morbit85@gmail.com>
Date:   Wed Aug 26 20:35:31 2026 +0500

    [mod_verto] Add enable-chat-api-proto to gate the api chat proto (#3136)

    A client message can select which chat proto handles it, and the `api` proto
    runs the address as a FreeSWITCH API command. That route does not pass through
    `verto.fsapi`, so the per-user fsapi permission does not apply to it. The new
    per-profile `enable-chat-api-proto` param controls the route and is off unless
    set; a message selecting the proto without it is refused and logged.

    The proto compare is case-insensitive, matching the chat interface registry,
    which is created with `switch_core_hash_init_nocase()`.

    Only the `api` proto is gated. A message carrying no proto selector, or one
    naming any other chat proto, routes exactly as before.

    The param ships commented out in both vanilla verto profiles.

diff --git a/conf/vanilla/autoload_configs/verto.conf.xml b/conf/vanilla/autoload_configs/verto.conf.xml
index 91f75f11e9..b65430471e 100644
--- a/conf/vanilla/autoload_configs/verto.conf.xml
+++ b/conf/vanilla/autoload_configs/verto.conf.xml
@@ -21,6 +21,11 @@
       <param name="userauth" value="true"/>
       <!-- setting this to true will allow anyone to register even with no account so use with care -->
       <param name="blind-reg" value="false"/>
+      <!-- lets a client message to api+<command> run FreeSWITCH API commands. Not
+           recommended: it is all or nothing and bypasses the per-user fsapi permission.
+           Prefer the fsapi method with jsonrpc-allowed-fsapi, which allow-lists commands
+           per user. This param is here for clients that already use api+<command>. -->
+      <!-- <param name="enable-chat-api-proto" value="true"/> -->
       <param name="mcast-ip" value="224.1.1.1"/>
       <param name="mcast-port" value="1337"/>
       <param name="rtp-ip" value="$${local_ip_v4}"/>
@@ -46,6 +51,7 @@
       <param name="userauth" value="true"/>
       <!-- setting this to true will allow anyone to register even with no account so use with care -->
       <param name="blind-reg" value="false"/>
+      <!-- <param name="enable-chat-api-proto" value="true"/> -->
       <param name="rtp-ip" value="$${local_ip_v6}"/>
       <!--  <param name="ext-rtp-ip" value=""/> -->
       <param name="outbound-codec-string" value="opus,h264,vp8"/>
diff --git a/src/mod/endpoints/mod_verto/mod_verto.c b/src/mod/endpoints/mod_verto/mod_verto.c
index 784a1379cb..5a625954a4 100644
--- a/src/mod/endpoints/mod_verto/mod_verto.c
+++ b/src/mod/endpoints/mod_verto/mod_verto.c
@@ -3986,6 +3986,20 @@ static switch_bool_t verto__info_func(const char *method, cJSON *params, jsock_t
 			}
 		}

+		if (!strcasecmp(proto, "api") && !jsock->profile->enable_chat_api_proto) {
+			/* Truncate: the rest of "to" comes straight from the client JSON and has no length bound. */
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
+							  "Profile [%s] rejected a message from %s (%s) addressed to the 'api' chat proto [%.256s]. "
+							  "Set enable-chat-api-proto=true on the profile to permit it.\n",
+							  jsock->profile->name, switch_str_nil(jsock->uid), switch_str_nil(jsock->name), switch_str_nil(to));
+
+			cJSON_AddItemToObject(*response, "message", cJSON_CreateString("The api chat proto is not permitted on this profile"));
+			switch_safe_free(pproto);
+			r = SWITCH_FALSE;
+
+			goto cleanup;
+		}
+
 		if (!zstr(to) && !zstr(body) && switch_event_create(&event, SWITCH_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) {
 			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", VERTO_CHAT_PROTO);

@@ -5343,6 +5357,8 @@ static switch_status_t parse_config(const char *cf)
 					profile->jb_msec = switch_core_strdup(profile->pool, val);
 				} else if (!strcasecmp(var, "blind-reg") && !zstr(val)) {
 					profile->blind_reg = switch_true(val);
+				} else if (!strcasecmp(var, "enable-chat-api-proto") && !zstr(val)) {
+					profile->enable_chat_api_proto = switch_true(val);
 				} else if (!strcasecmp(var, "userauth") && !zstr(val)) {
 					profile->userauth = switch_core_strdup(profile->pool, val);
 				} else if (!strcasecmp(var, "chop-domain") && !zstr(val)) {
diff --git a/src/mod/endpoints/mod_verto/mod_verto.h b/src/mod/endpoints/mod_verto/mod_verto.h
index f13e8ef2b9..e565447e7b 100644
--- a/src/mod/endpoints/mod_verto/mod_verto.h
+++ b/src/mod/endpoints/mod_verto/mod_verto.h
@@ -247,6 +247,7 @@ struct verto_profile_s {

 	int in_thread;
 	int blind_reg;
+	int enable_chat_api_proto;

 	char *userauth;
 	char *root_passwd;