package com.airbnb.chancery; import com.airbnb.chancery.github.GithubAuthChecker; import com.airbnb.chancery.model.CallbackPayload; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.eventbus.EventBus; import com.yammer.metrics.annotation.ExceptionMetered; import com.yammer.metrics.annotation.Metered; import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.joda.time.DateTime; import javax.annotation.Nullable; import javax.ws.rs.*; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import java.io.IOException; @Slf4j @Path("/callback") @RequiredArgsConstructor public class CallbackResource { @Nullable private final GithubAuthChecker checker; @NonNull private final EventBus callbackBus; @NonNull private final ObjectMapper mapper = new ObjectMapper(); @ExceptionMetered @Metered @POST @Produces(MediaType.TEXT_PLAIN) @Consumes(MediaType.APPLICATION_JSON) public Response receiveHook(@HeaderParam("X-Hub-Signature") String signature, String payload) throws IOException, GithubFailure.forDownload { log.debug("Received {}", payload); CallbackPayload decodedPayload; try { decodedPayload = mapper.readValue(payload, CallbackPayload.class); } catch (Exception e) { log.warn("Couldn't parse payload {}", payload, e); throw new WebApplicationException(e, Response.Status.BAD_REQUEST); } log.debug("Decoded to {}", decodedPayload); decodedPayload.setTimestamp(new DateTime()); if (checker != null && !checker.checkSignature(signature, payload)) return Response. status(Response.Status.FORBIDDEN). build(); else callbackBus.post(decodedPayload); return Response.status(Response.Status.ACCEPTED).build(); } }