Skip to content

Commit fa2c292

Browse files
committed
Increase test coverage on sonar for unit tests
1 parent 4269361 commit fa2c292

File tree

5 files changed

+593
-38
lines changed

5 files changed

+593
-38
lines changed

src/main/java/org/red5/server/plugin/PluginDeployer.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,12 +714,27 @@ static Attributes readManifestAttributes(File jarFile) {
714714
}
715715
}
716716

717+
// Zip bomb protection limits
718+
static final long MAX_TOTAL_EXTRACT_SIZE = 500 * 1024 * 1024; // 500 MB
719+
static final int MAX_ENTRY_COUNT = 500;
720+
static final long MAX_SINGLE_FILE_SIZE = 200 * 1024 * 1024; // 200 MB
721+
717722
File extractZip(File zipFile) {
718723
try {
719724
java.nio.file.Path tempDir = Files.createTempDirectory("ams-plugin-");
725+
long totalSize = 0;
726+
int entryCount = 0;
727+
720728
try (ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(zipFile)))) {
721729
ZipEntry entry;
722730
while ((entry = zis.getNextEntry()) != null) {
731+
entryCount++;
732+
if (entryCount > MAX_ENTRY_COUNT) {
733+
log.error("Zip bomb suspected: too many entries (>{})", MAX_ENTRY_COUNT);
734+
deleteDirectory(tempDir.toFile());
735+
return null;
736+
}
737+
723738
File outFile = new File(tempDir.toFile(), entry.getName());
724739
if (!outFile.getCanonicalPath().startsWith(tempDir.toFile().getCanonicalPath())) {
725740
log.error("Zip slip detected: {}", entry.getName());
@@ -730,10 +745,23 @@ File extractZip(File zipFile) {
730745
outFile.mkdirs();
731746
} else {
732747
outFile.getParentFile().mkdirs();
748+
long fileSize = 0;
733749
try (OutputStream os = new FileOutputStream(outFile)) {
734750
byte[] buf = new byte[4096];
735751
int len;
736752
while ((len = zis.read(buf)) > 0) {
753+
fileSize += len;
754+
totalSize += len;
755+
if (fileSize > MAX_SINGLE_FILE_SIZE) {
756+
log.error("Zip bomb suspected: single file exceeds {} bytes", MAX_SINGLE_FILE_SIZE);
757+
deleteDirectory(tempDir.toFile());
758+
return null;
759+
}
760+
if (totalSize > MAX_TOTAL_EXTRACT_SIZE) {
761+
log.error("Zip bomb suspected: total extracted size exceeds {} bytes", MAX_TOTAL_EXTRACT_SIZE);
762+
deleteDirectory(tempDir.toFile());
763+
return null;
764+
}
737765
os.write(buf, 0, len);
738766
}
739767
}

src/test/java/io/antmedia/test/console/AdminApplicationPluginTest.java

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,4 +172,109 @@ public void testBuildPluginDownloadURI() {
172172
assertTrue(uri.contains("/rest/v2/plugins/"));
173173
assertTrue(uri.contains("/download"));
174174
}
175+
176+
@Test
177+
public void testDeployPlugin_saveReturnsNull() {
178+
when(pluginDeployer.getPluginNames()).thenReturn(java.util.Collections.emptySet());
179+
doReturn(null).when(adminApp).savePluginZip(anyString(), any(InputStream.class));
180+
181+
boolean result = adminApp.deployPlugin("test-plugin", new ByteArrayInputStream(new byte[]{1}));
182+
assertFalse(result);
183+
}
184+
185+
@Test
186+
public void testUndeployPlugin_deletesZipFile() throws Exception {
187+
when(pluginDeployer.unloadPluginFromZip(eq("test-plugin"), any(File.class)))
188+
.thenReturn(new Result(true, "removed"));
189+
190+
// Create a fake zip so the delete path is exercised
191+
File pluginsDir = adminApp.getPluginsDir();
192+
File fakeZip = new File(pluginsDir, "test-plugin.zip");
193+
fakeZip.createNewFile();
194+
assertTrue(fakeZip.exists());
195+
196+
boolean result = adminApp.undeployPlugin("test-plugin");
197+
assertTrue(result);
198+
199+
// The zip should be deleted
200+
assertFalse("ZIP file should be deleted after undeploy", fakeZip.exists());
201+
}
202+
203+
@Test
204+
public void testGetAllPluginNames_combinesRegistryAndDeployer() {
205+
when(pluginDeployer.getPluginNames()).thenReturn(
206+
new java.util.HashSet<>(java.util.Arrays.asList("hot-loaded-plugin")));
207+
208+
java.util.List<String> names = adminApp.getAllPluginNames();
209+
assertNotNull(names);
210+
assertTrue(names.contains("hot-loaded-plugin"));
211+
}
212+
213+
@Test
214+
public void testGetAllPluginNames_noDeployer() {
215+
adminApp.setPluginDeployer(null);
216+
java.util.List<String> names = adminApp.getAllPluginNames();
217+
assertNotNull(names);
218+
}
219+
220+
@Test
221+
public void testGetPluginsDir_createsIfNotExists() {
222+
// Reset spy to use real getPluginsDir
223+
AdminApplication realApp = new AdminApplication();
224+
System.setProperty("red5.root", System.getProperty("java.io.tmpdir") + "/ams-dir-test-" + System.nanoTime());
225+
File dir = realApp.getPluginsDir();
226+
assertNotNull(dir);
227+
assertTrue(dir.exists());
228+
assertTrue(dir.isDirectory());
229+
dir.delete();
230+
new File(System.getProperty("red5.root")).delete();
231+
}
232+
233+
@Test
234+
public void testDeployPluginWithURL_invalidName() {
235+
boolean result = adminApp.deployPluginWithURL("../bad", "http://example.com/test.zip", "key");
236+
assertFalse(result);
237+
}
238+
239+
@Test
240+
public void testDeployPluginWithURL_downloadFails() throws Exception {
241+
doReturn(null).when(adminApp).downloadPluginZip(anyString(), anyString(), anyString());
242+
boolean result = adminApp.deployPluginWithURL("test-plugin", "http://example.com/test.zip", "key");
243+
assertFalse(result);
244+
}
245+
246+
@Test
247+
public void testDeployPluginWithURL_loadFails() throws Exception {
248+
File fakeZip = new File(adminApp.getPluginsDir(), "test.zip");
249+
fakeZip.createNewFile();
250+
doReturn(fakeZip).when(adminApp).downloadPluginZip(anyString(), anyString(), anyString());
251+
when(pluginDeployer.loadPluginFromZip(any(File.class), any(File.class)))
252+
.thenReturn(new Result(false, "bad manifest"));
253+
254+
boolean result = adminApp.deployPluginWithURL("test-plugin", "http://example.com/test.zip", "key");
255+
assertFalse(result);
256+
fakeZip.delete();
257+
}
258+
259+
@Test
260+
public void testDeployPluginWithURL_success() throws Exception {
261+
File fakeZip = new File(adminApp.getPluginsDir(), "test.zip");
262+
fakeZip.createNewFile();
263+
doReturn(fakeZip).when(adminApp).downloadPluginZip(anyString(), anyString(), anyString());
264+
when(pluginDeployer.loadPluginFromZip(any(File.class), any(File.class)))
265+
.thenReturn(new Result(true, "ok"));
266+
267+
boolean result = adminApp.deployPluginWithURL("test-plugin", "http://example.com/test.zip", "key");
268+
assertTrue(result);
269+
fakeZip.delete();
270+
}
271+
272+
@Test
273+
public void testDeployPluginWithURL_exceptionHandled() throws Exception {
274+
doThrow(new RuntimeException("network error")).when(adminApp)
275+
.downloadPluginZip(anyString(), anyString(), anyString());
276+
277+
boolean result = adminApp.deployPluginWithURL("test-plugin", "http://example.com/test.zip", "key");
278+
assertFalse(result);
279+
}
175280
}

0 commit comments

Comments
 (0)