Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
2 changes: 1 addition & 1 deletion .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ jobs:
uses: actions/setup-java@v5
with:
java-version: "23"
distribution: "oracle"
distribution: "temurin"
- name: run mvn clean package
run: ./mvnw clean package -Ddependency-check.skip=true -Dmaven.test.skip=true
- name: Perform CodeQL Analysis
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/container_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
uses: actions/setup-java@v5
with:
java-version: "23"
distribution: "oracle"
distribution: "temurin"
cache: "maven"
- name: Navigate to test script and run
run: cd .github/scripts && bash docker-create.sh -t
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/dast-zap-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
uses: actions/setup-java@v5
with:
java-version: "23"
distribution: "oracle"
distribution: "temurin"
- name: Clean install
run: ./mvnw --no-transfer-progress clean install -DskipTests -Ddependency-check.skip -Dcyclonedx.skip=true -Dexec.skip
- name: Start wrongsecrets
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/github-pages-preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
uses: actions/setup-java@v5
with:
java-version: "23"
distribution: "oracle"
distribution: "temurin"
cache: "maven"

- name: Build application (JAR only)
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/java_swagger_doc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
uses: actions/setup-java@v5
with:
java-version: "23"
distribution: "oracle"
distribution: "temurin"
- name: Clean install
run: ./mvnw --no-transfer-progress clean install -DskipTests -Ddependency-check.skip -Dcyclonedx.skip=true -Dexec.skip
- name: Compile javadoc
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
uses: actions/setup-java@v5
with:
java-version: "23"
distribution: "oracle"
distribution: "temurin"
cache: "maven"
- name: checkstyle with Maven
run: ./mvnw --no-transfer-progress checkstyle:check
Expand All @@ -43,7 +43,7 @@ jobs:
uses: actions/setup-java@v5
with:
java-version: "23"
distribution: "oracle"
distribution: "temurin"
cache: "maven"
- name: spotbugs with Maven
run: ./mvnw --no-transfer-progress package -DskipTests spotbugs:check
Expand All @@ -59,7 +59,7 @@ jobs:
uses: actions/setup-java@v5
with:
java-version: "23"
distribution: "oracle"
distribution: "temurin"
cache: "maven"
- name: Test with Maven
run: ./mvnw --no-transfer-progress test
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/master-container-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
uses: actions/setup-java@v5
with:
java-version: "23"
distribution: "oracle"
distribution: "temurin"
cache: "maven"

- name: Extract version from pom.xml
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/pr-preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
uses: actions/setup-java@v5
with:
java-version: "23"
distribution: "oracle"
distribution: "temurin"
cache: "maven"

- name: Extract version from pom.xml
Expand Down Expand Up @@ -249,7 +249,7 @@ jobs:
uses: actions/setup-java@v5
with:
java-version: "23"
distribution: "oracle"
distribution: "temurin"
cache: "maven"

- name: Extract PR version
Expand Down Expand Up @@ -278,7 +278,7 @@ jobs:
uses: actions/setup-java@v5
with:
java-version: "23"
distribution: "oracle"
distribution: "temurin"
cache: "maven"

- name: Extract main version
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pre-commit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
cache: "npm"
- uses: actions/setup-java@v5
with:
distribution: "oracle"
distribution: "temurin"
java-version: "23"
- name: Install npm dependencies
run: npm install
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/version-sync-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
uses: actions/setup-java@v5
with:
java-version: "23"
distribution: "oracle"
distribution: "temurin"
cache: "maven"

- name: Validate version consistency
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/visual-diff.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
uses: actions/setup-java@v5
with:
java-version: "23"
distribution: "oracle"
distribution: "temurin"
cache: "maven"

- name: Extract PR version
Expand Down Expand Up @@ -53,7 +53,7 @@ jobs:
uses: actions/setup-java@v5
with:
java-version: "23"
distribution: "oracle"
distribution: "temurin"
cache: "maven"

- name: Extract main version
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.google.common.base.Strings;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
Expand Down Expand Up @@ -203,7 +204,10 @@ public String reset(
@PostMapping(value = "/challenge/{name}", params = "action=submit")
@Operation(description = "Post your answer to the challenge for a given challenge")
public String postController(
@ModelAttribute ChallengeForm challengeForm, Model model, @PathVariable String name) {
@ModelAttribute ChallengeForm challengeForm,
Model model,
@PathVariable String name,
HttpServletRequest request) {
var challengeDefinition = findByShortName(name);

if (!isChallengeEnabled(challengeDefinition)) {
Expand All @@ -223,8 +227,9 @@ public String postController(
scoreCard.completeChallenge(challengeDefinition);
// Send Slack notification for challenge completion
if (slackNotificationService != null) {
String userAgent = request.getHeader("User-Agent");
slackNotificationService.notifyChallengeCompletion(
challengeDefinition.name().shortName(), null);
challengeDefinition.name().shortName(), null, userAgent);
}
// TODO extract this to a separate method probably have separate handler classes in the
// configuration otherwise this is not maintainable, probably give the challenge a CTF
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ public SlackNotificationService(
*
* @param challengeName The name of the completed challenge
* @param userName Optional username of the person who completed the challenge
* @param userAgent Optional user agent string from the HTTP request
*/
public void notifyChallengeCompletion(String challengeName, String userName) {
public void notifyChallengeCompletion(String challengeName, String userName, String userAgent) {
if (!isSlackConfigured()) {
logger.debug("Slack not configured, skipping notification for challenge: {}", challengeName);
return;
Expand All @@ -49,6 +50,11 @@ public void notifyChallengeCompletion(String challengeName, String userName) {

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);

// Add User-Agent header if provided
if (userAgent != null && !userAgent.trim().isEmpty()) {
headers.set("User-Agent", userAgent);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot can you instead add the useragent string to the challengemessage. No need to forward the useragent itself.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Modified the implementation to include the user agent string in the Slack message content instead of as an HTTP header. The user agent now appears in the message as "(User-Agent: browser/tool info)" when available. Updated tests accordingly. See commit 26f9097.

}

HttpEntity<SlackMessage> request = new HttpEntity<>(slackMessage, headers);

Expand All @@ -62,6 +68,16 @@ public void notifyChallengeCompletion(String challengeName, String userName) {
}
}

/**
* Sends a Slack notification when a challenge is completed (backward compatibility method).
*
* @param challengeName The name of the completed challenge
* @param userName Optional username of the person who completed the challenge
*/
public void notifyChallengeCompletion(String challengeName, String userName) {
notifyChallengeCompletion(challengeName, userName, null);
}

private boolean isSlackConfigured() {
return challenge59.isPresent()
&& challenge59.get().getSlackWebhookUrl() != null
Expand Down
1 change: 1 addition & 0 deletions src/test/e2e/cypress.config.arcane.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module.exports = defineConfig({
reporterOptions: {
configFile: 'reporter-config.json'
},
userAgent: 'Cypress WrongSecrets E2E Tests (Arcane)',
setupNodeEvents (on, config) {
// implement node event listeners here
}
Expand Down
1 change: 1 addition & 0 deletions src/test/e2e/cypress.config.heroku.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module.exports = defineConfig({
reporterOptions: {
configFile: 'reporter-config.json'
},
userAgent: 'Cypress WrongSecrets E2E Tests (Heroku)',
setupNodeEvents (on, config) {
// implement node event listeners here
}
Expand Down
1 change: 1 addition & 0 deletions src/test/e2e/cypress.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module.exports = defineConfig({
reporterOptions: {
configFile: 'reporter-config.json'
},
userAgent: 'Cypress WrongSecrets E2E Tests',
setupNodeEvents (on, config) {
// implement node event listeners here
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

Expand All @@ -28,6 +30,75 @@ void setUp() {
objectMapper = new ObjectMapper();
}

@Test
void shouldSendNotificationWithUserAgentWhenSlackIsConfigured() {
// Given
String webhookUrl = "https://hooks.slack.com/services/T123456789/B123456789/abcdef123456";
String userAgent = "Mozilla/5.0 (Test Browser)";
when(challenge59.getSlackWebhookUrl()).thenReturn(webhookUrl);
when(restTemplate.postForEntity(anyString(), any(HttpEntity.class), eq(String.class)))
.thenReturn(ResponseEntity.ok("ok"));

slackNotificationService =
new SlackNotificationService(restTemplate, objectMapper, challenge59);

// When
slackNotificationService.notifyChallengeCompletion("challenge-1", "testuser", userAgent);

// Then
verify(restTemplate, times(1))
.postForEntity(eq(webhookUrl), any(HttpEntity.class), eq(String.class));
}

@Test
void shouldSetUserAgentHeaderWhenProvided() {
// Given
String webhookUrl = "https://hooks.slack.com/services/T123456789/B123456789/abcdef123456";
String userAgent = "Cypress WrongSecrets E2E Tests";
when(challenge59.getSlackWebhookUrl()).thenReturn(webhookUrl);
when(restTemplate.postForEntity(anyString(), any(HttpEntity.class), eq(String.class)))
.thenReturn(ResponseEntity.ok("ok"));

slackNotificationService =
new SlackNotificationService(restTemplate, objectMapper, challenge59);

// When
slackNotificationService.notifyChallengeCompletion("challenge-1", "testuser", userAgent);

// Then
ArgumentCaptor<HttpEntity> entityCaptor = ArgumentCaptor.forClass(HttpEntity.class);
verify(restTemplate, times(1))
.postForEntity(eq(webhookUrl), entityCaptor.capture(), eq(String.class));

HttpEntity capturedEntity = entityCaptor.getValue();
HttpHeaders headers = capturedEntity.getHeaders();
assertEquals(userAgent, headers.getFirst("User-Agent"));
}

@Test
void shouldNotSetUserAgentHeaderWhenNotProvided() {
// Given
String webhookUrl = "https://hooks.slack.com/services/T123456789/B123456789/abcdef123456";
when(challenge59.getSlackWebhookUrl()).thenReturn(webhookUrl);
when(restTemplate.postForEntity(anyString(), any(HttpEntity.class), eq(String.class)))
.thenReturn(ResponseEntity.ok("ok"));

slackNotificationService =
new SlackNotificationService(restTemplate, objectMapper, challenge59);

// When
slackNotificationService.notifyChallengeCompletion("challenge-1", "testuser", null);

// Then
ArgumentCaptor<HttpEntity> entityCaptor = ArgumentCaptor.forClass(HttpEntity.class);
verify(restTemplate, times(1))
.postForEntity(eq(webhookUrl), entityCaptor.capture(), eq(String.class));

HttpEntity capturedEntity = entityCaptor.getValue();
HttpHeaders headers = capturedEntity.getHeaders();
assertNull(headers.getFirst("User-Agent"));
}

@Test
void shouldSendNotificationWhenSlackIsConfigured() {
// Given
Expand Down
Loading