Skip to content
This repository has been archived by the owner on Apr 24, 2022. It is now read-only.

Commit

Permalink
[TEAMMATES#9152] Add more SpotBugs rules (TEAMMATES#11580)
Browse files Browse the repository at this point in the history
  • Loading branch information
wkurniawan07 committed Feb 19, 2022
1 parent 4ec60a2 commit 693d6bf
Show file tree
Hide file tree
Showing 32 changed files with 312 additions and 56 deletions.
5 changes: 3 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ apply plugin: "cz.habarta.typescript-generator"

def checkstyleVersion = "8.33"
def pmdVersion = "6.24.0"
def spotbugsVersion = "4.0.6"
def spotbugsVersion = "4.5.3"
def jacocoVersion = "0.8.5"

buildscript {
Expand All @@ -21,7 +21,7 @@ buildscript {
}
dependencies {
classpath "com.google.cloud.tools:appengine-gradle-plugin:2.3.0"
classpath "gradle.plugin.com.github.spotbugs.snom:spotbugs-gradle-plugin:4.4.3"
classpath "com.github.spotbugs.snom:spotbugs-gradle-plugin:5.0.6"
classpath("cz.habarta.typescript-generator:typescript-generator-gradle-plugin:2.24.612") {
exclude group: "org.gradle"
}
Expand Down Expand Up @@ -57,6 +57,7 @@ dependencies {
implementation("com.google.guava:guava:30.1.1-jre")
implementation(objectify)
implementation("com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:20211018.2")
implementation("com.helger:ph-commons:9.5.1") // necessary to add SpotBugs suppression
implementation("com.mailjet:mailjet-client:4.5.0")
implementation("com.sendgrid:sendgrid-java:4.6.0")
implementation("com.sun.jersey:jersey-client:1.19.4")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ private DataBundleRegenerator() {

private static void regenerateDataBundleJson(File folder) throws IOException {
File[] listOfFiles = folder.listFiles();
if (listOfFiles == null) {
listOfFiles = new File[] {};
}
for (File file : listOfFiles) {
if (!file.getName().endsWith(".json") || NON_DATA_BUNDLE_JSON.contains(file.getName())) {
continue;
Expand Down Expand Up @@ -69,6 +72,9 @@ private static void saveFile(String filePath, String content) throws IOException

private static void regenerateWebsiteDataJson() throws IOException {
File[] listOfFiles = new File("./src/main/webapp/data").listFiles();
if (listOfFiles == null) {
listOfFiles = new File[] {};
}
for (File file : listOfFiles) {
if (!file.getName().endsWith(".json")) {
continue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.googlecode.objectify.cmd.Query;

import teammates.client.connector.DatastoreClient;
import teammates.common.util.Const;
import teammates.storage.entity.BaseEntity;
import teammates.test.FileHelper;

Expand Down Expand Up @@ -266,7 +267,7 @@ protected void log(String logLine) {
Path logPath = Paths.get(BASE_LOG_URI + this.getClass().getSimpleName() + ".log");
try (OutputStream logFile = Files.newOutputStream(logPath,
StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.APPEND)) {
logFile.write((logLine + System.lineSeparator()).getBytes());
logFile.write((logLine + System.lineSeparator()).getBytes(Const.ENCODING));
} catch (Exception e) {
System.err.println("Error writing log line: " + logLine);
System.err.println(e.getMessage());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import com.google.gson.stream.JsonWriter;

import teammates.common.util.Config;
import teammates.common.util.Const;
import teammates.common.util.StringHelper;
import teammates.test.FileHelper;

Expand Down Expand Up @@ -138,7 +139,7 @@ private static <T> void saveEncryptedJsonToFile(String fileName, T object, Type

try (OutputStream os = Files.newOutputStream(Paths.get(fileName))) {
CipherOutputStream out = new CipherOutputStream(os, cipher);
JsonWriter writer = new JsonWriter(new OutputStreamWriter(out));
JsonWriter writer = new JsonWriter(new OutputStreamWriter(out, Const.ENCODING));
getSerializer().toJson(object, typeOfObject, writer);
writer.close();
out.close();
Expand All @@ -152,7 +153,7 @@ private static <T> T parseEncryptedJsonFile(String fileName, CheckedFunction<Jso

try (InputStream is = Files.newInputStream(Paths.get(fileName))) {
CipherInputStream in = new CipherInputStream(is, cipher);
JsonReader reader = new JsonReader(new InputStreamReader(in));
JsonReader reader = new JsonReader(new InputStreamReader(in, Const.ENCODING));
T result = parser.apply(reader);
reader.close();
in.close();
Expand Down
4 changes: 2 additions & 2 deletions src/e2e/java/teammates/e2e/pageobjects/AdminSearchPage.java
Original file line number Diff line number Diff line change
Expand Up @@ -408,10 +408,10 @@ public void verifyAccountRequestRowContent(AccountRequestAttributes accountReque
assertEquals(accountRequest.getEmail(), actualEmail);
assertEquals(accountRequest.getInstitute(), actualInstitute);
assertFalse(actualCreatedAt.isBlank());
if (actualRegisteredAt == null) {
if (accountRequest.getRegisteredAt() == null) {
assertEquals("Not Registered Yet", actualRegisteredAt);
} else {
assertFalse(actualCreatedAt.isBlank());
assertFalse(actualRegisteredAt.isBlank());
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/e2e/java/teammates/e2e/util/GmailServiceMaker.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import com.google.api.services.gmail.Gmail;
import com.google.api.services.gmail.GmailScopes;

import teammates.common.util.Const;

/**
* Class that builds a Gmail service for use in Gmail API.
*/
Expand Down Expand Up @@ -87,7 +89,7 @@ private Credential authorizeAndCreateCredentials() throws IOException {

private GoogleClientSecrets loadClientSecretFromJson() throws IOException {
try (InputStream in = Files.newInputStream(Paths.get(TestProperties.TEST_GMAIL_API_FOLDER, "client_secret.json"))) {
return GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));
return GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in, Const.ENCODING));
} catch (FileNotFoundException e) {
throw new RuntimeException("You need to set up your Gmail API credentials." + System.lineSeparator()
+ "See docs/development.md section \"Deploying to a staging server\".", e);
Expand Down
7 changes: 7 additions & 0 deletions src/e2e/java/teammates/e2e/util/TestDataValidityTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import teammates.test.BaseTestCase;
import teammates.test.FileHelper;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

/**
* Checks for test data validity.
*
Expand All @@ -40,6 +42,8 @@
public class TestDataValidityTest extends BaseTestCase {

@Test
@SuppressFBWarnings("RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE")
// SpotBugs false positive: https://github.com/spotbugs/spotbugs/issues/1694
public void checkTestDataValidity() throws IOException {
Map<String, List<String>> errors = new HashMap<>();
try (Stream<Path> paths = Files.walk(Paths.get(TestProperties.TEST_DATA_FOLDER))) {
Expand All @@ -52,6 +56,9 @@ public void checkTestDataValidity() throws IOException {
errors.put(pathString, Collections.singletonList("Error reading file: " + e.getMessage()));
return;
}
if (path.getFileName() == null) {
return;
}

String testPage = path.getFileName().toString().replace("E2ETest.json", "");
DataBundle dataBundle = JsonUtils.fromJson(jsonString, DataBundle.class);
Expand Down
3 changes: 3 additions & 0 deletions src/lnp/java/teammates/lnp/cases/BaseLNPTestCase.java
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,9 @@ protected void cleanupResults() throws IOException {
.listFiles((d, s) -> {
return s.contains(this.getClass().getSimpleName());
});
if (fileList == null) {
fileList = new File[] {};
}
Arrays.sort(fileList, (a, b) -> {
return b.getName().compareTo(a.getName());
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ public class InstructorStudentCascadingUpdateLNPTest extends BaseLNPTestCase {
private static final double MEAN_RESP_TIME_LIMIT = 60;

// To generate multiple csv files for multiple sections
private static int csvTestDataIndex;
private static LNPTestData testData;
private int csvTestDataIndex;
private LNPTestData testData;

@Override
protected LNPTestData getTestData() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -373,5 +373,21 @@ public ContributionStatisticsEntry(int claimed, int perceived, Map<String, Integ
this.claimedOthers = claimedOthers;
this.perceivedOthers = perceivedOthers;
}

public int getClaimed() {
return claimed;
}

public int getPerceived() {
return perceived;
}

public Map<String, Integer> getClaimedOthers() {
return claimedOthers;
}

public int[] getPerceivedOthers() {
return perceivedOthers;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,8 @@ public List<String> validateResponsesDetails(List<FeedbackResponseDetails> respo
}

if (details.getAnswer().stream().anyMatch(choice ->
choice != RUBRIC_ANSWER_NOT_CHOSEN
choice == null
|| choice != RUBRIC_ANSWER_NOT_CHOSEN
&& (choice < 0 || choice >= rubricChoices.size()))) {
errors.add(RUBRIC_INVALID_ANSWER);
}
Expand Down
7 changes: 5 additions & 2 deletions src/main/java/teammates/common/util/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Properties;

Expand Down Expand Up @@ -124,8 +125,10 @@ public final class Config {
OAUTH2_CLIENT_SECRET = properties.getProperty("app.oauth2.client.secret");
ENABLE_DEVSERVER_LOGIN = Boolean.parseBoolean(properties.getProperty("app.enable.devserver.login", "true"));
CAPTCHA_SECRET_KEY = properties.getProperty("app.captcha.secretkey");
APP_ADMINS = Arrays.asList(properties.getProperty("app.admins", "").split(","));
APP_MAINTAINERS = Arrays.asList(properties.getProperty("app.maintainers", "").split(","));
APP_ADMINS = Collections.unmodifiableList(
Arrays.asList(properties.getProperty("app.admins", "").split(",")));
APP_MAINTAINERS = Collections.unmodifiableList(
Arrays.asList(properties.getProperty("app.maintainers", "").split(",")));
SUPPORT_EMAIL = properties.getProperty("app.crashreport.email");
EMAIL_SENDEREMAIL = properties.getProperty("app.email.senderemail");
EMAIL_SENDERNAME = properties.getProperty("app.email.sendername");
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/teammates/common/util/Const.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package teammates.common.util;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.Instant;

Expand Down Expand Up @@ -27,7 +29,7 @@ public final class Const {
public static final String UNKNOWN_INSTITUTION = "Unknown Institution";

public static final String DEFAULT_TIME_ZONE = "UTC";
public static final String ENCODING = "UTF8";
public static final Charset ENCODING = StandardCharsets.UTF_8;

public static final Duration FEEDBACK_SESSIONS_SEARCH_WINDOW = Duration.ofDays(30);
public static final Duration LOGS_RETENTION_PERIOD = Duration.ofDays(30);
Expand Down
10 changes: 1 addition & 9 deletions src/main/java/teammates/common/util/SanitizationHelper.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package teammates.common.util;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

import org.owasp.html.HtmlPolicyBuilder;
Expand Down Expand Up @@ -34,7 +33,6 @@ public final class SanitizationHelper {
.allowElements("quote", "ecode")
.allowStyling()
.toFactory();
private static final Logger log = Logger.getLogger();

private SanitizationHelper() {
// utility class
Expand Down Expand Up @@ -128,13 +126,7 @@ public static String sanitizeForHtml(String unsanitizedString) {
* Converts a string to be put in URL (replaces some characters).
*/
public static String sanitizeForUri(String uri) {
try {
return URLEncoder.encode(uri, Const.ENCODING).replaceAll("\\+", "%20");
} catch (UnsupportedEncodingException wontHappen) {
log.warning("Unexpected UnsupportedEncodingException in "
+ "SanitizationHelper.sanitizeForUri(" + uri + ", " + Const.ENCODING + ")");
return uri;
}
return URLEncoder.encode(uri, Const.ENCODING).replaceAll("\\+", "%20");
}

}
6 changes: 3 additions & 3 deletions src/main/java/teammates/common/util/StringHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public static String generateSignature(String data) {
new SecretKeySpec(hexStringToByteArray(Config.ENCRYPTION_KEY), "HmacSHA1");
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(signingKey);
byte[] value = mac.doFinal(data.getBytes());
byte[] value = mac.doFinal(data.getBytes(Const.ENCODING));
return byteArrayToHexString(value);
} catch (Exception e) {
assert false;
Expand Down Expand Up @@ -123,7 +123,7 @@ public static String encrypt(String value) {
SecretKeySpec sks = new SecretKeySpec(hexStringToByteArray(Config.ENCRYPTION_KEY), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, sks, cipher.getParameters());
byte[] encrypted = cipher.doFinal(value.getBytes());
byte[] encrypted = cipher.doFinal(value.getBytes(Const.ENCODING));
return byteArrayToHexString(encrypted);
} catch (Exception e) {
assert false;
Expand All @@ -145,7 +145,7 @@ public static String decrypt(String message) throws InvalidParametersException {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, sks);
byte[] decrypted = cipher.doFinal(hexStringToByteArray(message));
return new String(decrypted);
return new String(decrypted, Const.ENCODING);
} catch (NumberFormatException | IllegalBlockSizeException | BadPaddingException e) {
log.warning("Attempted to decrypt invalid ciphertext: " + message);
throw new InvalidParametersException(e);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package teammates.logic.core;

import java.io.IOException;
import java.nio.charset.Charset;
import java.time.Instant;

import com.google.cloud.tasks.v2.AppEngineHttpRequest;
Expand Down Expand Up @@ -49,7 +48,7 @@ public void addDeferredTask(TaskWrapper task, long countdownTime) {
String requestBody = JsonUtils.toCompactJson(task.getRequestBody());
requestBuilder.putHeaders("Content-Type", "application/json; charset=UTF-8")
.setRelativeUri(task.getWorkerUrl())
.setBody(ByteString.copyFrom(requestBody, Charset.forName(Const.ENCODING)));
.setBody(ByteString.copyFrom(requestBody, Const.ENCODING));
}

Task.Builder taskBuilder = Task.newBuilder().setAppEngineHttpRequest(requestBuilder.build());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -42,7 +41,7 @@ public void addDeferredTask(TaskWrapper task, long countdownTime) {

if (task.getRequestBody() != null) {
StringEntity entity = new StringEntity(
JsonUtils.toCompactJson(task.getRequestBody()), Charset.forName(Const.ENCODING));
JsonUtils.toCompactJson(task.getRequestBody()), Const.ENCODING);
post.setEntity(entity);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOExc
if (nextUrl == null) {
nextUrl = "/";
}
// Prevent HTTP response splitting
nextUrl = resp.encodeRedirectURL(nextUrl.replace("\r\n", ""));
if (!Config.isDevServerLoginEnabled()) {
resp.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
resp.setHeader("Location", Const.WebPageURIs.LOGIN + "?nextUrl=" + nextUrl.replace("&", "%26"));
Expand Down Expand Up @@ -66,6 +68,8 @@ public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOEx
if (nextUrl == null) {
nextUrl = "/";
}
// Prevent HTTP response splitting
nextUrl = resp.encodeRedirectURL(nextUrl.replace("\r\n", ""));
resp.sendRedirect(nextUrl);
}

Expand Down
2 changes: 2 additions & 0 deletions src/main/java/teammates/ui/servlets/LoginServlet.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOExc
if (nextUrl == null) {
nextUrl = "/";
}
// Prevent HTTP response splitting
nextUrl = resp.encodeRedirectURL(nextUrl.replace("\r\n", ""));
if (Config.isDevServerLoginEnabled()) {
resp.setStatus(HttpStatus.SC_MOVED_PERMANENTLY);
resp.setHeader("Location", "/devServerLogin?nextUrl=" + nextUrl.replace("&", "%26"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IO

Map<String, Object> parsedResponse =
JsonUtils.fromJson(userInfoResponse, new TypeToken<Map<String, Object>>(){}.getType());
String email = String.valueOf(parsedResponse.get("email"));
if (email != null) {
if (parsedResponse.containsKey("email")) {
String email = String.valueOf(parsedResponse.get("email"));
googleId = email.replaceFirst("@gmail\\.com$", "");
}
} catch (URISyntaxException | IOException | JsonSyntaxException e) {
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/teammates/ui/webapi/DatastoreBackupAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
Expand Down Expand Up @@ -64,12 +63,13 @@ public JsonResult execute() {
// Documentation is wrong; the param name is output_url_prefix instead of outputUrlPrefix
body.put("output_url_prefix", "gs://" + Config.BACKUP_GCS_BUCKETNAME + "/datastore-backups/" + timestamp);

StringEntity entity = new StringEntity(JsonUtils.toCompactJson(body), Charset.forName(Const.ENCODING));
StringEntity entity = new StringEntity(JsonUtils.toCompactJson(body), Const.ENCODING);
post.setEntity(entity);

try (CloseableHttpClient client = HttpClients.createDefault();
CloseableHttpResponse resp = client.execute(post);
BufferedReader br = new BufferedReader(new InputStreamReader(resp.getEntity().getContent()))) {
BufferedReader br = new BufferedReader(
new InputStreamReader(resp.getEntity().getContent(), Const.ENCODING))) {
String output = br.lines().collect(Collectors.joining(System.lineSeparator()));
if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
log.info("Backup request successful:" + System.lineSeparator() + output);
Expand Down
Loading

0 comments on commit 693d6bf

Please sign in to comment.