Skip to content

Commit

Permalink
Support GitHub-style (HmacSHA256 signature) git hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
sealexan committed Dec 20, 2023
1 parent 150d0cb commit 264fcf7
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 6 deletions.
16 changes: 13 additions & 3 deletions src/main/kotlin/ch/uzh/ifi/access/controller/CourseController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,20 @@ class WebhooksController(
private val logger = KotlinLogging.logger {}

@PostMapping("/courses/{course}/update/gitlab")
fun updateCourse(@PathVariable("course") course: String,
fun hookGitlab(@PathVariable("course") course: String,
@RequestHeader("X-Gitlab-Token") secret: String) {
logger.debug { "webhook triggered for $course"}
courseService.webhookUpdateCourse(course, secret)
logger.debug { "webhook (secret) triggered for $course"}
courseService.webhookUpdateWithSecret(course, secret)
}
@PostMapping("/courses/{course}/update/github")
fun hookGithub(@PathVariable("course") course: String,
@RequestHeader("X-Hub-Signature-256") signature: String,
@RequestBody body: String
) {
logger.debug { "webhook (signature) triggered for $course"}
val sig = signature.substringAfter("sha256=")
logger.debug { "PAYLOAD: ((($body))) SIG: ((($sig)))"}
courseService.webhookUpdateWithSignature(course, sig, body)
}

}
Expand Down
30 changes: 27 additions & 3 deletions src/main/kotlin/ch/uzh/ifi/access/service/CourseService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import com.github.dockerjava.api.model.Bind
import com.github.dockerjava.api.model.HostConfig
import io.github.oshai.kotlinlogging.KotlinLogging
import jakarta.transaction.Transactional
import jakarta.xml.bind.DatatypeConverter
import org.apache.commons.collections4.ListUtils
import org.apache.commons.io.FileUtils
import org.apache.logging.log4j.util.Strings
Expand All @@ -35,6 +36,7 @@ import java.nio.charset.Charset
import java.nio.file.Files
import java.nio.file.NoSuchFileException
import java.nio.file.Path
import java.security.MessageDigest
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.util.*
Expand All @@ -43,6 +45,9 @@ import java.util.concurrent.TimeUnit
import java.util.function.Consumer
import java.util.stream.Collectors
import java.util.stream.Stream
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
import kotlin.math.sign

@Service
class CourseServiceForCaching(
Expand Down Expand Up @@ -554,10 +559,29 @@ fi
}

@Transactional
fun webhookUpdateCourse(courseSlug: String, secret: String): Course? {
fun webhookUpdateWithSecret(courseSlug: String, secret: String?): Course? {
val existingCourse = getCourseBySlug(courseSlug)
if (existingCourse.webhookSecret != null && existingCourse.webhookSecret == secret) {
return updateCourse(courseSlug)
if (existingCourse.webhookSecret != null && secret != null) {
if (existingCourse.webhookSecret == secret) {
return updateCourse(courseSlug)
}
}
logger.debug { "Provided webhook secret does not match secret of course $courseSlug"}
throw ResponseStatusException(HttpStatus.FORBIDDEN)
}

fun webhookUpdateWithSignature(courseSlug: String, signature: String?, body: String): Course? {
val existingCourse = getCourseBySlug(courseSlug)
if (existingCourse.webhookSecret != null && signature != null) {
val signingKey = SecretKeySpec(existingCourse.webhookSecret!!.toByteArray(Charsets.UTF_8), "HmacSHA256")
val mac = Mac.getInstance("HmacSHA256")
mac.init(signingKey)
val hash = mac.doFinal(body.toByteArray(Charsets.UTF_8))
val expected = DatatypeConverter.printHexBinary(hash)
logger.info{"Expected: ${expected} based on secret ${existingCourse.webhookSecret}, actual: ${signature}"}
if (expected.equals(signature, ignoreCase = true)) {
return updateCourse(courseSlug)
}
}
logger.debug { "Provided webhook secret does not match secret of course $courseSlug"}
throw ResponseStatusException(HttpStatus.FORBIDDEN)
Expand Down

0 comments on commit 264fcf7

Please sign in to comment.