package io.github.ibuildthecloud.gdapi.request.handler;
import io.github.ibuildthecloud.gdapi.exception.ClientVisibleException;
import io.github.ibuildthecloud.gdapi.model.Schema.Method;
import io.github.ibuildthecloud.gdapi.request.ApiRequest;
import io.github.ibuildthecloud.gdapi.util.RequestUtils;
import io.github.ibuildthecloud.gdapi.util.ResponseCodes;
import io.github.ibuildthecloud.gdapi.validation.ValidationErrorCodes;
import java.io.IOException;
import java.security.SecureRandom;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CSRFCookieHandler extends AbstractApiRequestHandler {
private static final Logger log = LoggerFactory.getLogger(CSRFCookieHandler.class);
private static final SecureRandom RANDOM = new SecureRandom();
public static final String CSRF = "CSRF";
public static final String HEADER = "X-API-CSRF";
@Override
public void handle(ApiRequest request) throws IOException {
HttpServletRequest httpRequest = request.getServletContext().getRequest();
HttpServletResponse response = request.getServletContext().getResponse();
if (!RequestUtils.isBrowser(httpRequest, false)) {
return;
}
Cookie csrf = null;
Cookie[] cookies = httpRequest.getCookies();
if (cookies != null) {
for (Cookie c : httpRequest.getCookies()) {
if (CSRF.equals(c.getName()) && c.getName() != null) {
csrf = c;
break;
}
}
}
if (csrf == null) {
byte[] bytes = new byte[5];
RANDOM.nextBytes(bytes);
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02X", b));
}
csrf = new Cookie(CSRF, sb.toString());
} else if (!Method.GET.isMethod(request.getMethod())) {
/*
* Very important to use request.getMethod() and not httpRequest.getMethod(). The client can override the HTTP method with _method
*/
if (csrf.getValue().equals(httpRequest.getHeader(HEADER))) {
// Good
} else if (csrf.getValue().equals(httpRequest.getParameter(CSRF))) {
// Good
} else {
log.warn("Request's CSRF header did not match cookie");
throw new ClientVisibleException(ResponseCodes.FORBIDDEN, ValidationErrorCodes.INVALID_CSRF_TOKEN);
}
}
csrf.setPath("/");
response.addCookie(csrf);
}
}