feat(alerting): HmacSigner for webhook signature

HmacSHA256 signer returning sha256=<lowercase-hex>. 5 unit tests covering
known vector, prefix, hex casing, and different secrets/bodies.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-19 20:24:39 +02:00
parent bf178ba141
commit 6f1feaa4b0
2 changed files with 90 additions and 0 deletions

View File

@@ -0,0 +1,55 @@
package com.cameleer.server.app.alerting.notify;
import org.junit.jupiter.api.Test;
import java.nio.charset.StandardCharsets;
import static org.assertj.core.api.Assertions.assertThat;
class HmacSignerTest {
private final HmacSigner signer = new HmacSigner();
/**
* Pre-computed:
* secret = "test-secret-key"
* body = "hello world"
* result = sha256=b3df71b4790eb32b24c2f0bbb20f215d82b0da5e921caa880c74acfc97cf7e5b
*
* Verified with: python3 -c "import hmac,hashlib; print('sha256='+hmac.new(b'test-secret-key',b'hello world',hashlib.sha256).hexdigest())"
*/
@Test
void knownVector() {
String result = signer.sign("test-secret-key", "hello world".getBytes(StandardCharsets.UTF_8));
assertThat(result).isEqualTo("sha256=b3df71b4790eb32b24c2f0bbb20f215d82b0da5e921caa880c74acfc97cf7e5b");
}
@Test
void outputStartsWithSha256Prefix() {
String result = signer.sign("any-secret", "body".getBytes(StandardCharsets.UTF_8));
assertThat(result).startsWith("sha256=");
}
@Test
void outputIsLowercaseHex() {
String result = signer.sign("key", "data".getBytes(StandardCharsets.UTF_8));
// After "sha256=" every char must be a lowercase hex digit
String hex = result.substring("sha256=".length());
assertThat(hex).matches("[0-9a-f]{64}");
}
@Test
void differentSecretsProduceDifferentSignatures() {
byte[] body = "payload".getBytes(StandardCharsets.UTF_8);
String sig1 = signer.sign("secret-a", body);
String sig2 = signer.sign("secret-b", body);
assertThat(sig1).isNotEqualTo(sig2);
}
@Test
void differentBodiesProduceDifferentSignatures() {
String sig1 = signer.sign("secret", "body1".getBytes(StandardCharsets.UTF_8));
String sig2 = signer.sign("secret", "body2".getBytes(StandardCharsets.UTF_8));
assertThat(sig1).isNotEqualTo(sig2);
}
}