docs: add Javadoc for GitLabWebhookInterceptor

This commit is contained in:
2026-05-28 15:22:36 +08:00
parent 6240ec1016
commit 72ec875802
@@ -18,6 +18,14 @@ import java.nio.charset.StandardCharsets;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.util.Base64; import java.util.Base64;
/**
* Verifies GitLab webhook requests by validating the {@code webhook-id},
* {@code webhook-timestamp}, and {@code webhook-signature} headers against
* a configured signing token using HMAC-SHA256.
*
* <p>Supports GitLab's v1 signature scheme. Verification is skipped when no
* signing token is configured.
*/
@Component @Component
public class GitLabWebhookInterceptor implements HandlerInterceptor { public class GitLabWebhookInterceptor implements HandlerInterceptor {
@@ -26,10 +34,28 @@ public class GitLabWebhookInterceptor implements HandlerInterceptor {
private final WebhookProperties webhookProperties; private final WebhookProperties webhookProperties;
/**
* Creates a new interceptor with the given webhook configuration.
*
* @param webhookProperties the webhook configuration properties
*/
public GitLabWebhookInterceptor(WebhookProperties webhookProperties) { public GitLabWebhookInterceptor(WebhookProperties webhookProperties) {
this.webhookProperties = webhookProperties; this.webhookProperties = webhookProperties;
} }
/**
* Validates the GitLab webhook signature headers on the incoming request.
* Reads {@code webhook-id}, {@code webhook-timestamp}, and
* {@code webhook-signature} headers and verifies the signature against the
* configured signing token. If no token is configured, verification is skipped.
*
* @param request the incoming HTTP request (must be a {@link RepeatedlyReadRequestWrapper})
* @param response the HTTP response
* @param handler the chosen handler to execute
* @return {@code true} if the request is authentic
* @throws BizException with {@code 401} if headers are missing or the signature is invalid,
* with {@code 500} if verification fails unexpectedly
*/
@Override @Override
public boolean preHandle( public boolean preHandle(
@NonNull HttpServletRequest request, @NonNull HttpServletRequest request,
@@ -90,6 +116,14 @@ public class GitLabWebhookInterceptor implements HandlerInterceptor {
return true; return true;
} }
/**
* Decodes a GitLab-format signing token by stripping the {@code whsec_} prefix
* and Base64-decoding the remainder.
*
* @param token the prefixed signing token
* @return the raw key bytes
* @throws BizException if the token does not start with {@code whsec_}
*/
private byte[] decodeSigningToken(String token) { private byte[] decodeSigningToken(String token) {
if (!token.startsWith(TOKEN_PREFIX)) { if (!token.startsWith(TOKEN_PREFIX)) {
throw new BizException(HttpStatus.INTERNAL_SERVER_ERROR, throw new BizException(HttpStatus.INTERNAL_SERVER_ERROR,
@@ -99,6 +133,14 @@ public class GitLabWebhookInterceptor implements HandlerInterceptor {
return Base64.getDecoder().decode(encoded); return Base64.getDecoder().decode(encoded);
} }
/**
* Computes the Base64-encoded HMAC-SHA256 digest for the given data.
*
* @param key the secret key bytes
* @param data the content to sign
* @return Base64-encoded HMAC-SHA256 digest
* @throws Exception if the HMAC algorithm is unavailable
*/
private String computeHmacSha256(byte[] key, String data) throws Exception { private String computeHmacSha256(byte[] key, String data) throws Exception {
var mac = Mac.getInstance("HmacSHA256"); var mac = Mac.getInstance("HmacSHA256");
var secretKey = new SecretKeySpec(key, "HmacSHA256"); var secretKey = new SecretKeySpec(key, "HmacSHA256");