This is an automated email from the ASF dual-hosted git repository.

solomax pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/openmeetings.git


The following commit(s) were added to refs/heads/master by this push:
     new f9a95c9ef [OPENMEETINGS-2832] SIP extension number is sanitized
f9a95c9ef is described below

commit f9a95c9efd1f5cecb99f26b33da1655a124e8793
Author: Maxim Solodovnik <[email protected]>
AuthorDate: Mon Sep 7 20:51:50 2026 +0700

    [OPENMEETINGS-2832] SIP extension number is sanitized
---
 openmeetings-core/pom.xml                          |   4 +
 .../apache/openmeetings/core/sip/SipManager.java   |  10 +-
 .../openmeetings/core/sip/TestSipMocked.java       | 101 +++++++++++++++++++++
 3 files changed, 113 insertions(+), 2 deletions(-)

diff --git a/openmeetings-core/pom.xml b/openmeetings-core/pom.xml
index 2849dd33e..69c4b93eb 100644
--- a/openmeetings-core/pom.xml
+++ b/openmeetings-core/pom.xml
@@ -78,5 +78,9 @@
                        <groupId>org.junit.jupiter</groupId>
                        <artifactId>junit-jupiter-params</artifactId>
                </dependency>
+               <dependency>
+                       <groupId>org.apache.openmeetings</groupId>
+                       <artifactId>openmeetings-tests</artifactId>
+               </dependency>
        </dependencies>
 </project>
diff --git 
a/openmeetings-core/src/main/java/org/apache/openmeetings/core/sip/SipManager.java
 
b/openmeetings-core/src/main/java/org/apache/openmeetings/core/sip/SipManager.java
index 7c3881916..b3aef555b 100644
--- 
a/openmeetings-core/src/main/java/org/apache/openmeetings/core/sip/SipManager.java
+++ 
b/openmeetings-core/src/main/java/org/apache/openmeetings/core/sip/SipManager.java
@@ -134,7 +134,8 @@ public class SipManager implements ISipManager {
                }
        }
 
-       private ManagerResponse exec(ManagerAction action) {
+       // package private for tests
+       ManagerResponse exec(ManagerAction action) {
                if (factory == null) {
                        log.warn("There is no Asterisk configured");
                        return null;
@@ -236,11 +237,16 @@ public class SipManager implements ISipManager {
                        log.warn("Failed to get SIP number for room: {}", r);
                        return;
                }
+               String ext = 
Optional.ofNullable(number).orElse("").lines().findFirst().orElse(null);
+               if (Strings.isEmpty(ext)) {
+                       log.warn("Got empty extention number out of '{}'", 
number);
+                       return;
+               }
 
                OriginateAction oa = new OriginateAction();
                oa.setChannel(String.format("Local/%s@rooms-originate", 
sipNumber));
                oa.setContext("rooms-out");
-               oa.setExten(number);
+               oa.setExten(ext);
                oa.setPriority(1);
                oa.setTimeout(managerTimeout);
 
diff --git 
a/openmeetings-core/src/test/java/org/apache/openmeetings/core/sip/TestSipMocked.java
 
b/openmeetings-core/src/test/java/org/apache/openmeetings/core/sip/TestSipMocked.java
new file mode 100644
index 000000000..4c05ea50d
--- /dev/null
+++ 
b/openmeetings-core/src/test/java/org/apache/openmeetings/core/sip/TestSipMocked.java
@@ -0,0 +1,101 @@
+/*
+
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.openmeetings.core.sip;
+
+import static org.apache.openmeetings.test.Utils.getTestCoordinates;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.openmeetings.db.entity.room.Room;
+import org.asteriskjava.manager.ManagerConnection;
+import org.asteriskjava.manager.ManagerConnectionFactory;
+import org.asteriskjava.manager.ManagerConnectionState;
+import org.asteriskjava.manager.action.ManagerAction;
+import org.asteriskjava.manager.internal.ManagerWriterImpl;
+import org.asteriskjava.util.SocketConnectionFacade;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInfo;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TestSipMocked {
+       private static final Logger log = 
LoggerFactory.getLogger(TestSipMocked.class);
+       @Mock
+       private ManagerConnection con;
+       @Mock
+       private ManagerConnectionFactory factory;
+       @Mock
+       private SocketConnectionFacade sock;
+       @InjectMocks
+       private ManagerWriterImpl writerImpl;
+
+       @BeforeEach
+       void setup(TestInfo testInfo) {
+               log.info("Test started: {} ---", getTestCoordinates(testInfo));
+               MockitoAnnotations.openMocks(this);
+               Mockito.reset();
+               doReturn(ManagerConnectionState.CONNECTED).when(con).getState();
+       }
+
+       @AfterEach
+       void tearDown(TestInfo testInfo) {
+               log.info(" --- test finished: {}", 
getTestCoordinates(testInfo));
+       }
+
+       @Test
+       void testCallExternalNumber() throws Exception {
+               Room r = new Room();
+               r.setConfno("test-conf-no");
+
+               SipManager sip = spy(new SipManager());
+
+               ArgumentCaptor<ManagerAction> actionCaptor = 
ArgumentCaptor.forClass(ManagerAction.class);
+               when(sip.exec(actionCaptor.capture())).thenReturn(null); // we 
need argument
+
+               sip.callExternalNumber("12345\r\nAction: Command\r\nActionID: 
injected\r\nCommand: sip show peers", r);
+               List<String> actionStrings = new ArrayList<>();
+               doAnswer(new Answer<Void>() {
+                       @Override
+                       public Void answer(InvocationOnMock invocation) throws 
Throwable {
+                               actionStrings.add(invocation.getArgument(0));
+                               return null;
+                       }}).when(sock).write(anyString());
+               writerImpl.sendAction(actionCaptor.getValue(), "some-id");
+               assertEquals(1, actionStrings.size(), "Exctly one message 
should be written");
+               assertFalse(actionStrings.get(0).contains("injected"), 
"External number should be sanitized");
+       }
+}

Reply via email to