Created
February 7, 2021 07:25
-
-
Save renzihui/c44c296114712cd9a7101a82a5404146 to your computer and use it in GitHub Desktop.
Facebook Data Deletion Request Callback in Java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.fasterxml.jackson.core.type.TypeReference; | |
import com.fasterxml.jackson.databind.ObjectMapper; | |
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
import org.springframework.beans.factory.annotation.Autowired; | |
import org.springframework.beans.factory.annotation.Value; | |
import org.springframework.stereotype.Controller; | |
import org.springframework.web.bind.annotation.RequestMapping; | |
import org.springframework.web.bind.annotation.RequestMethod; | |
import org.springframework.web.bind.annotation.RequestParam; | |
import org.springframework.web.bind.annotation.ResponseBody; | |
import javax.crypto.Mac; | |
import javax.crypto.spec.SecretKeySpec; | |
import java.nio.charset.StandardCharsets; | |
import java.security.Key; | |
import java.util.Arrays; | |
import java.util.Base64; | |
import java.util.Map; | |
@Controller | |
public class FacebookDataDeletionCallbackController { | |
private static final Logger LOGGER = LoggerFactory.getLogger(FacebookDataDeletionCallbackController.class); | |
private final ObjectMapper objectMapper = new ObjectMapper(); | |
private String facebookAppSecret; | |
private String URL = "https://example.com"; | |
/** | |
* https://developers.facebook.com/docs/development/create-an-app/app-dashboard/data-deletion-callback | |
*/ | |
@Autowired | |
public FacebookDataDeletionCallbackController(@Value("${facebook.app.secret}") String facebookSecret) { | |
this.facebookAppSecret = facebookSecret; | |
} | |
@RequestMapping(value = "/remove_fb_data", method = RequestMethod.POST, produces = "application/json") | |
@ResponseBody | |
public Object removeApp(@RequestParam(value = "signed_request") String signedRequest) throws Exception { | |
String status_url = "https://www.<your_website>.com/deletion?id=abc123"; // URL to track the deletion | |
String confirmation_code = "abc123"; // unique code for the deletion request | |
Map<String, Object> data = parseSignedRequest(signedRequest); | |
String user_id = (String) data.get("user_id"); | |
// Start data deletion | |
return Map.of("url", status_url, "confirmation_code", confirmation_code); | |
} | |
private Map<String, Object> parseSignedRequest(String signedRequest) throws Exception { | |
int split = signedRequest.indexOf('.'); | |
String encoded_sig = signedRequest.substring(0, split); | |
String payload = signedRequest.substring(split + 1); | |
// decode the data | |
byte[] sig = Base64.getUrlDecoder().decode(encoded_sig); | |
Map<String, Object> data = objectMapper.readValue(Base64.getUrlDecoder().decode(payload), new TypeReference<Map<String, Object>>() { | |
}); | |
// confirm the signature | |
byte[] expected_sig = hash_hmac(payload.getBytes(StandardCharsets.UTF_8)); | |
if (!Arrays.equals(sig, expected_sig)) { | |
LOGGER.error("Bad Signed JSON signature!"); | |
return Map.of(); | |
} | |
return data; | |
} | |
public byte[] hash_hmac(byte[] bytes) throws Exception { | |
Key sk = new SecretKeySpec(facebookAppSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"); | |
Mac mac = Mac.getInstance(sk.getAlgorithm()); | |
mac.init(sk); | |
return mac.doFinal(bytes); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment