package com.comandante.stickypunch.http.resource;
import com.google.common.base.Optional;
import com.comandante.stickypunch.api.model.PackageCreator;
import com.comandante.stickypunch.api.model.PackageZipEntry;
import com.comandante.stickypunch.api.model.WebPushStore;
import com.comandante.stickypunch.api.model.WebPushStoreAuth;
import com.comandante.stickypunch.api.model.WebPushUser;
import com.comandante.stickypunch.api.model.WebPushUserBuilder;
import com.comandante.stickypunch.http.inject.ManifestInjectionContext;
import com.comandante.stickypunch.http.model.jackson.WebPushLog;
import com.sun.jersey.api.core.HttpContext;
import com.sun.jersey.spi.resource.Singleton;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.codehaus.jackson.map.ObjectMapper;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
@Path("/push/v1/")
@Singleton
public class SafariPushResource {
private static final Logger log = LogManager.getLogger(SafariPushResource.class);
private final ObjectMapper mapper;
private final WebPushStore webPushStore;
private final WebPushStoreAuth webPushStoreAuth;
private final PackageCreator packageCreator;
public SafariPushResource(@ManifestInjectionContext ObjectMapper objectMapper,
@ManifestInjectionContext WebPushStore webPushStore,
@ManifestInjectionContext WebPushStoreAuth webPushStoreAuth,
@ManifestInjectionContext PackageCreator packageCreator) {
this.mapper = objectMapper;
this.webPushStore = webPushStore;
this.webPushStoreAuth = webPushStoreAuth;
this.packageCreator = packageCreator;
}
@POST
@Path("/pushPackages/{websitePushId}")
@Produces("application/zip")
public InputStream getPushPackage(@Context HttpContext context) throws Exception {
PackageZipEntry packageZipEntry = packageCreator.getPackage();
webPushStore.updateWebPushUser(new WebPushUserBuilder()
.setUserId(packageZipEntry.getId())
.setActive(false)
.setIsActiveTimestamp(System.currentTimeMillis())
.build());
return packageZipEntry.getInputStream();
}
@POST
@Path("/log")
@Produces(MediaType.APPLICATION_JSON)
public Response log(String logJson) throws IOException {
WebPushLog webPushLog = mapper.readValue(logJson, WebPushLog.class);
webPushLog.flush();
return Response.ok().build();
}
@POST
@Path("/devices/{deviceToken}/registrations/{websitePushId}")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response updateRegistration(@Context HttpHeaders headers,
@PathParam("deviceToken") String deviceToken,
@PathParam("websitePushId") String websitePushId) throws Exception {
Optional<String> userIdOptional = extractandUserId(headers);
if (!auth(userIdOptional, Optional.<String>absent())) {
return Response.status(Response.Status.FORBIDDEN).build();
}
updateUserId(userIdOptional, true, websitePushId, deviceToken);
return Response.ok().build();
}
@DELETE
@Path("/devices/{deviceToken}/registrations/{websitePushId}")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response disableRegistration(@Context HttpHeaders headers,
@PathParam("deviceToken") String deviceToken,
@PathParam("websitePushId") String websitePushId) throws Exception {
Optional<String> userIdOptional = extractandUserId(headers);
if (!auth(userIdOptional, Optional.of(deviceToken))) {
return Response.status(Response.Status.FORBIDDEN).build();
}
updateUserId(userIdOptional, false, websitePushId, deviceToken);
return Response.ok().build();
}
private void updateUserId(Optional<String> userId, boolean isActive, String websitePushId, String deviceToken) throws Exception {
if (!userId.isPresent()) {
throw new Exception("Missing AuthenticationToken in Auth header:");
}
String userIdStr = userId.get();
WebPushUser webPushUser = new WebPushUserBuilder()
.setUserId(userIdStr)
.setActive(isActive)
.setDeviceToken(deviceToken)
.setWebsitePushId(websitePushId)
.setIsActiveTimestamp(System.currentTimeMillis())
.build();
webPushStore.updateWebPushUser(webPushUser);
log.info(String.format("Received UPDATE isActive=" + isActive + " registration for websitePushId: %s deviceToken: %s", websitePushId, deviceToken));
}
private Optional<String> extractandUserId(HttpHeaders headers) {
Optional<String> userIdOpt = Optional.absent();
MultivaluedMap<String, String> requestHeaders = headers.getRequestHeaders();
log.debug("HEADERS:" + requestHeaders.toString());
List<String> authHeaders = requestHeaders.get("Authorization");
for (String auth : authHeaders) {
if (auth.startsWith("ApplePushNotifications ")) {
userIdOpt = Optional.of(auth.split(" ")[1]);
}
}
return userIdOpt;
}
private boolean auth(Optional<String> userIdOptional, Optional<String> deviceToken) {
if (userIdOptional.isPresent()) {
if (!webPushStoreAuth.authUserId(userIdOptional.get(), deviceToken)) {
return false;
}
} else {
return false;
}
return true;
}
}