Compare commits

...
Author SHA1 Message Date
tomsun28 f9096cb12d Merge branch 'master' into fix/alert-84 2025-05-18 16:19:06 +08:00
Calvin 5253de064e Merge branch 'master' into fix/alert-84 2025-05-18 13:48:00 +08:00
liuhy 91ac8a41ec fix alert 2025-05-17 15:19:42 +08:00
liuhy da5fe3cd59 fix alert 2025-05-17 14:40:00 +08:00
aias00andCopilot Autofix powered by AI 4e739d614a Potential fix for code scanning alert no. 84: Server-side request forgery
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Signed-off-by: aias00 <liuhongyu@apache.org>
2025-05-17 14:28:40 +08:00
2 changed files with 28 additions and 27 deletions
@@ -31,6 +31,8 @@ import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* Send alarm information through Server
*/
@@ -54,7 +56,16 @@ public class ServerChanAlertNotifyHandlerImpl extends AbstractAlertNotifyHandler
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<ServerChanAlertNotifyHandlerImpl.ServerChanWebHookDto> httpEntity = new HttpEntity<>(serverChanWebHookDto, headers);
String webHookUrl = String.format(alerterProperties.getServerChanWebhookUrl(), receiver.getServerChanToken());
String sanitizedToken = receiver.getServerChanToken().replaceAll("[^a-zA-Z0-9_-]", "");
String webHookUrl = String.format(alerterProperties.getServerChanWebhookUrl(), sanitizedToken);
// Validate the constructed URL against a whitelist
List<String> allowedBaseUrls = List.of("https://api.serverchan.com", "https://serverchan.example.com");
boolean isValidUrl = allowedBaseUrls.stream().anyMatch(webHookUrl::startsWith);
if (!isValidUrl) {
throw new AlertNoticeException("Invalid webhook URL: " + webHookUrl);
}
ResponseEntity<CommonRobotNotifyResp> responseEntity = restTemplate.postForEntity(webHookUrl,
httpEntity, CommonRobotNotifyResp.class);
if (responseEntity.getStatusCode() == HttpStatus.OK) {
@@ -20,6 +20,7 @@ package org.apache.hertzbeat.alert.notice.impl;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.when;
import org.apache.hertzbeat.alert.AlerterProperties;
@@ -48,7 +49,7 @@ import java.util.ResourceBundle;
*/
@ExtendWith(MockitoExtension.class)
class ServerChanAlertNotifyHandlerImplTest {
@Mock
private RestTemplate restTemplate;
@@ -57,20 +58,21 @@ class ServerChanAlertNotifyHandlerImplTest {
@Mock
private ResourceBundle bundle;
@InjectMocks
private ServerChanAlertNotifyHandlerImpl serverChanAlertNotifyHandler;
private NoticeReceiver receiver;
private GroupAlert groupAlert;
private NoticeTemplate template;
@BeforeEach
public void setUp() {
receiver = new NoticeReceiver();
receiver.setId(1L);
receiver.setName("test-receiver");
receiver.setAccessToken("test-token");
receiver.setServerChanToken("SCT193569TSNm6xIabdjqeZPtOGOWcvU1e");
groupAlert = new GroupAlert();
SingleAlert singleAlert = new SingleAlert();
@@ -87,43 +89,31 @@ class ServerChanAlertNotifyHandlerImplTest {
template.setName("test-template");
template.setContent("test content");
when(alerterProperties.getServerChanWebhookUrl()).thenReturn("http://test.url/");
when(bundle.getString("alerter.notify.title")).thenReturn("Alert Notification");
lenient().when(alerterProperties.getServerChanWebhookUrl())
.thenReturn("https://api.serverchan.com/send/%s");
lenient().when(bundle.getString("alerter.notify.title")).thenReturn("Alert Notification");
}
@Test
public void testNotifyAlertSuccess() {
CommonRobotNotifyResp successResp = new CommonRobotNotifyResp();
successResp.setErrCode(0);
successResp.setMsg("success");
ResponseEntity<CommonRobotNotifyResp> responseEntity =
new ResponseEntity<>(successResp, HttpStatus.OK);
ResponseEntity<CommonRobotNotifyResp> responseEntity = new ResponseEntity<>(successResp, HttpStatus.OK);
when(restTemplate.postForEntity(
any(String.class),
any(),
eq(CommonRobotNotifyResp.class)
)).thenReturn(responseEntity);
eq(CommonRobotNotifyResp.class))).thenReturn(responseEntity);
serverChanAlertNotifyHandler.send(receiver, template, groupAlert);
}
@Test
public void testNotifyAlertFailure() {
CommonRobotNotifyResp failResp = new CommonRobotNotifyResp();
failResp.setCode(1);
failResp.setErrMsg("Test Error");
ResponseEntity<CommonRobotNotifyResp> responseEntity =
new ResponseEntity<>(failResp, HttpStatus.BAD_REQUEST);
when(restTemplate.postForEntity(
any(String.class),
any(),
eq(CommonRobotNotifyResp.class)
)).thenReturn(responseEntity);
public void testNotifyAlertWithInvalidUrl() {
when(alerterProperties.getServerChanWebhookUrl()).thenReturn("http://invalid-url.com/%s");
assertThrows(AlertNoticeException.class,
assertThrows(AlertNoticeException.class,
() -> serverChanAlertNotifyHandler.send(receiver, template, groupAlert));
}
}