package com.faforever.api.deployment;

import com.faforever.api.config.FafApiProperties;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.kohsuke.github.GHEventPayload;
import org.kohsuke.github.GHEventPayload.Deployment;
import org.kohsuke.github.GHEventPayload.Push;
import org.kohsuke.github.GitHub;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.jwt.crypto.sign.MacSigner;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;

@RestController
@RequestMapping(path = "/gitHub")
@Slf4j
public class GitHubController {

  private static final String HMAC_SHA1 = "HmacSHA1";
  private final GitHubDeploymentService gitHubDeploymentService;
  private final GitHub gitHub;
  private final FafApiProperties apiProperties;

  public GitHubController(GitHubDeploymentService gitHubDeploymentService, GitHub gitHub, FafApiProperties apiProperties) {
    this.gitHubDeploymentService = gitHubDeploymentService;
    this.gitHub = gitHub;
    this.apiProperties = apiProperties;
  }

  @Async
  @RequestMapping(path = "/webhook", method = RequestMethod.POST)
  @SneakyThrows
  public void onPush(@RequestBody String body,
                     @RequestHeader("X-Hub-Signature") String signature,
                     @RequestHeader("X-GitHub-Event") String eventType) {
    verifyRequest(body, signature);
    switch (eventType) {
      case "push":
        gitHubDeploymentService.createDeploymentIfEligible(parseEvent(body, Push.class));
        break;
      case "deployment":
        gitHubDeploymentService.deploy(parseEvent(body, Deployment.class));
        break;
      default:
        log.warn("Unhandled event: " + eventType);
    }
  }

  private <T extends GHEventPayload> T parseEvent(@RequestBody String body, Class<T> type) throws IOException {
    return gitHub.parseEventPayload(new StringReader(body), type);
  }

  private void verifyRequest(String payload, String signature) throws DecoderException {
    String secret = apiProperties.getGitHub().getWebhookSecret();
    MacSigner macSigner = new MacSigner(HMAC_SHA1, new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), HMAC_SHA1));

    byte[] content = payload.getBytes(StandardCharsets.UTF_8);
    // Signature starts with "sha1="
    macSigner.verify(content, Hex.decodeHex(signature.substring(5)));
  }
}

@@ -82,16 +82,103 @@
 erties;%0A
+import com.faforever.api.error.ApiException;%0Aimport com.faforever.api.error.ErrorCode;%0A
 import l
@@ -561,71 +561,8 @@
 nc;%0A
-import org.springframework.security.jwt.crypto.sign.MacSigner;%0A
 impo
@@ -868,16 +868,41 @@
 oller;%0A%0A
+import javax.crypto.Mac;%0A
 import j
@@ -1031,16 +1031,130 @@
 harsets;
+%0Aimport java.security.InvalidKeyException;%0Aimport java.security.NoSuchAlgorithmException;%0Aimport java.util.Arrays;
 %0A%0A@RestC
@@ -2054,25 +2054,19 @@
 e %22push%22
-:%0A       
+ -%3E
  gitHubD
@@ -2136,39 +2136,24 @@
 sh.class));%0A
-        break;%0A
       case %22
@@ -2163,25 +2163,19 @@
 loyment%22
-:%0A       
+ -%3E
  gitHubD
@@ -2245,39 +2245,18 @@
     
-  break;%0A      default:%0A       
+default -%3E
  log
@@ -2572,24 +2572,71 @@
 derException
+, NoSuchAlgorithmException, InvalidKeyException
  %7B%0A    Strin
@@ -2703,52 +2703,56 @@
  Mac
-Signer macSigner = new MacSigner(HMAC_SHA1, 
+ mac = Mac.getInstance(HMAC_SHA1);%0A    mac.init(
 new 
@@ -2819,17 +2819,16 @@
 SHA1));%0A
-%0A
     byte
@@ -2834,166 +2834,320 @@
 e%5B%5D 
-content = payload.getBytes(StandardCharsets.UTF_8);%0A    // Signature starts with %22sha1=%22%0A    macSigner.verify(content, Hex.decodeHex(signature.substring(5)));
+rawHmac = mac.doFinal(payload.getBytes());%0A    byte%5B%5D expected = Hex.decodeHex(signature.substring(5));%0A%0A    boolean isValid = Arrays.equals(rawHmac, expected);%0A%0A    if(!isValid) %7B%0A      throw ApiException.of(ErrorCode.VALIDATION_FAILED, %22X-Hub-Signature does not match calculated signature from payload%22);%0A    %7D
 %0A  %7D

Replace deprecated Spring MacSigner