Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unforking our ClamAVJ #9

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ target
*.war
*.ear
.idea
/.classpath
/.project
/.settings
/.settings/**
8 changes: 8 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
language: java
before_install:
- "sudo apt-get update -qq"
- sudo apt-get install clamav-daemon -qq
- sudo freshclam
- sudo clamd --config-file $TRAVIS_BUILD_DIR/clamd.conf
script: mvn test -B -DtestClamavj
2 changes: 2 additions & 0 deletions clamd.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
TCPSocket 3310
TCPAddr 127.0.0.1
33 changes: 27 additions & 6 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<project>
<name>clamavj</name>
<name>ClamAV Daemon Java API</name>
<modelVersion>4.0.0</modelVersion>
<groupId>com.philvarner.clamavj</groupId>
<groupId>edu.unc.lib.cdr</groupId>
<artifactId>clamavj</artifactId>
<version>0.2</version>
<description>A library to interact with clamd for virus scanning.</description>
<url>http://philvarner.com/clamavj/</url>
<version>0.3</version>
<description>A fork or the Phil Varner library to interact with clamd for virus scanning.</description>
<licenses>
<license>
<name>Apache Software License, 2.0</name>
Expand All @@ -32,6 +31,28 @@
</plugin>
</plugins>
</reporting>
<profiles>
<profile>
<id>skip-clamavj-tests</id>
<activation>
<property>
<name>!testClamavj</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<build>
<pluginManagement>
<plugins>
Expand Down Expand Up @@ -63,4 +84,4 @@
<scope>test</scope>
</dependency>
</dependencies>
</project>
</project>
86 changes: 80 additions & 6 deletions src/main/java/com/philvarner/clamavj/ClamScan.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
package com.philvarner.clamavj;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.ByteArrayInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import static com.philvarner.clamavj.ScanResult.STREAM_PATH;

public class ClamScan {

private static Log log = LogFactory.getLog(ClamScan.class);
Expand Down Expand Up @@ -109,14 +112,16 @@ public String cmd(byte[] cmd) {
int read = CHUNK_SIZE;
byte[] buffer = new byte[CHUNK_SIZE];

while (read == CHUNK_SIZE) {
while (read != -1) {
try {
read = is.read(buffer);
} catch (IOException e) {
log.error("error reading result from socket", e);
break;
}
response.append(new String(buffer, 0, read));
if (read > 0) {
response.append(new String(buffer, 0, read));
}
}

} finally {
Expand Down Expand Up @@ -147,6 +152,75 @@ public String cmd(byte[] cmd) {
public ScanResult scan(byte[] in) throws IOException {
return scan(new ByteArrayInputStream(in));
}

/**
* The method to call if you have the content in a file.
*
* @param in the file to scan
* @return the result of the scan
*/
public ScanResult scan(File in) {

Socket socket = new Socket();

try {
socket.connect(new InetSocketAddress(getHost(), getPort()));
} catch (IOException e) {
log.error("could not connect to clamd server", e);
return new ScanResult(e);
}

try {
socket.setSoTimeout(getTimeout());
} catch (SocketException e) {
log.error("Could not set socket timeout to " + getTimeout() + "ms", e);
}

DataOutputStream dos = null;
String response = "";
try { // finally to close resources

try {
dos = new DataOutputStream(socket.getOutputStream());
} catch (IOException e) {
log.error("could not open socket OutputStream", e);
return new ScanResult(e);
}

try {
dos.write(("SCAN " + in.getAbsolutePath() + "\n").getBytes());
dos.flush();
} catch (IOException e) {
log.debug("error writing SCAN command", e);
return new ScanResult(e);
}

int read = CHUNK_SIZE;
byte[] buffer = new byte[CHUNK_SIZE];
try {
read = socket.getInputStream().read(buffer);
} catch (IOException e) {
log.debug("error reading result from socket", e);
read = 0;
}

if (read > 0) response = new String(buffer, 0, read);

} finally {
if (dos != null) try {
dos.close();
} catch (IOException e) {
log.debug("exception closing DOS", e);
}
try {
socket.close();
} catch (IOException e) {
log.debug("exception closing socket", e);
}
}
if (log.isDebugEnabled()) log.debug("Response: " + response);
return new ScanResult(response.trim(), in.getAbsolutePath());
}

/**
* The preferred method to call. This streams the contents of the InputStream to clamd, so
Expand Down Expand Up @@ -242,7 +316,7 @@ public ScanResult scan(InputStream in) {

if (log.isDebugEnabled()) log.debug("Response: " + response);

return new ScanResult(response.trim());
return new ScanResult(response.trim(), STREAM_PATH);
}

public String getHost() {
Expand Down
21 changes: 14 additions & 7 deletions src/main/java/com/philvarner/clamavj/ScanResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,19 @@ public class ScanResult {

public enum Status {PASSED, FAILED, ERROR}

public static final String STREAM_PREFIX = "stream: ";
public static final String RESPONSE_OK = "stream: OK";
public static final String STREAM_PATH = "stream";
public static final String OK_SUFFIX = "OK";
public static final String FOUND_SUFFIX = "FOUND";
public static final String ERROR_SUFFIX = "ERROR";

public static final String RESPONSE_SIZE_EXCEEDED = "INSTREAM size limit exceeded. ERROR";

public ScanResult(String result) {
setResult(result);
public static String getPrefix(String path) {
return path + ": ";
}

public ScanResult(String result, String path) {
setResult(result, path);
}

public ScanResult(Exception ex) {
Expand All @@ -37,15 +41,18 @@ public String getResult() {
return result;
}

public void setResult(String result) {
public void setResult(String result, String path) {

this.result = result;

String prefix = getPrefix(path);

if (result == null) {
setStatus(Status.ERROR);
} else if (RESPONSE_OK.equals(result)) {
} else if (result.equals(prefix + OK_SUFFIX)) {
setStatus(Status.PASSED);
} else if (result.endsWith(FOUND_SUFFIX)) {
setSignature(result.substring(STREAM_PREFIX.length(), result.lastIndexOf(FOUND_SUFFIX) - 1));
setSignature(result.substring(prefix.length(), result.lastIndexOf(FOUND_SUFFIX) - 1));
} else if (result.endsWith(ERROR_SUFFIX)) {
setStatus(Status.ERROR);
}
Expand Down
14 changes: 7 additions & 7 deletions src/test/java/com/philvarner/clamavj/test/ClamScanTestCase.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
import java.io.FileInputStream;
import java.io.InputStream;

import static com.philvarner.clamavj.ScanResult.OK_SUFFIX;
import static com.philvarner.clamavj.ScanResult.STREAM_PATH;
import static org.junit.Assert.*;

import static com.philvarner.clamavj.ScanResult.RESPONSE_OK;

public class ClamScanTestCase {

private ClamScan scanner;
Expand All @@ -36,7 +36,7 @@ public void testSuccess() throws Exception {
assertNotNull(is);
ScanResult result = scanner.scan(is);
assertEquals(Status.PASSED, result.getStatus());
assertEquals(RESPONSE_OK, result.getResult());
assertEquals(ScanResult.getPrefix(STREAM_PATH) + OK_SUFFIX, result.getResult());
}

@Test
Expand All @@ -46,7 +46,7 @@ public void testVirus() throws Exception {
assertNotNull(is);
ScanResult result = scanner.scan(is);
assertEquals(Status.FAILED, result.getStatus());
assertEquals("stream: Eicar-Test-Signature FOUND", result.getResult());
assertEquals(ScanResult.getPrefix(STREAM_PATH) + "Eicar-Test-Signature FOUND", result.getResult());
assertEquals("Eicar-Test-Signature", result.getSignature());
}

Expand All @@ -55,7 +55,7 @@ public void testVirusAsByteArray() throws Exception {
byte[] bytes = "X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*".getBytes();
ScanResult result = scanner.scan(bytes);
assertEquals(Status.FAILED, result.getStatus());
assertEquals("stream: Eicar-Test-Signature FOUND", result.getResult());
assertEquals(ScanResult.getPrefix(STREAM_PATH) + "Eicar-Test-Signature FOUND", result.getResult());
assertEquals("Eicar-Test-Signature", result.getSignature());
}

Expand Down Expand Up @@ -95,7 +95,7 @@ public void testNoArgConstructor() throws Exception {
byte[] bytes = "X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*".getBytes();
ScanResult result = scanner.scan(bytes);
assertEquals(Status.FAILED, result.getStatus());
assertEquals("stream: Eicar-Test-Signature FOUND", result.getResult());
assertEquals(ScanResult.getPrefix(STREAM_PATH) + "Eicar-Test-Signature FOUND", result.getResult());
assertEquals("Eicar-Test-Signature", result.getSignature());
}

Expand All @@ -105,7 +105,7 @@ public void testMultipleOfChunkSize() throws Exception {
assertNotNull(is);
ScanResult result = scanner.scan(is);
assertEquals(Status.PASSED, result.getStatus());
assertEquals(RESPONSE_OK, result.getResult());
assertEquals(ScanResult.getPrefix(STREAM_PATH) + OK_SUFFIX, result.getResult());
}

@Test
Expand Down
56 changes: 56 additions & 0 deletions src/test/java/com/philvarner/clamavj/test/ScanFileTestCase.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.philvarner.clamavj.test;

import com.philvarner.clamavj.ClamScan;
import com.philvarner.clamavj.ScanResult;
import com.philvarner.clamavj.ScanResult.Status;
import junit.framework.TestCase;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.net.URL;

import static com.philvarner.clamavj.ScanResult.OK_SUFFIX;

public class ScanFileTestCase extends TestCase {

ClamScan scanner;

public void setUp() {
scanner = new ClamScan("localhost", 3310, 60000);
}

public void testSuccess() throws Exception {

File f = File.createTempFile("clean", ".txt");
f.deleteOnExit();

FileOutputStream s = new FileOutputStream(f);
s.write("test".getBytes());
s.close();

ScanResult result = scanner.scan(f);

assertEquals(ScanResult.getPrefix(f.getAbsolutePath()) + OK_SUFFIX, result.getResult());
assertEquals(Status.PASSED, result.getStatus());

}

public void testVirus() throws Exception {

File f = File.createTempFile("eicar", ".com");
f.deleteOnExit();

FileOutputStream s = new FileOutputStream(f);
s.write("X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*".getBytes());
s.close();

ScanResult result = scanner.scan(f);

assertEquals(ScanResult.getPrefix(f.getAbsolutePath()) + "Eicar-Test-Signature FOUND", result.getResult());
assertEquals("Eicar-Test-Signature", result.getSignature());
assertEquals(Status.FAILED, result.getStatus());

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class ScanResultTestCase {
@Test
public void testErrorDetection() {
String response = "Error writing to temporary file ERROR";
ScanResult scanResult = new ScanResult(response);
ScanResult scanResult = new ScanResult(response, "stream");

assertEquals(ScanResult.Status.ERROR, scanResult.getStatus());
}
Expand Down