package controllers;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.JsonNodeCreator;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import play.*;
import play.db.DB;
import play.libs.WS;
import play.libs.WS.Response;
import play.mvc.*;
import play.mvc.Http.RequestBody;
import views.html.*;
public class Application extends Controller {
private static final String APP_ID = "582917605129839";
private static final String APP_SECRET = "86dcd6d4ad418ac5fcd84806eaeebfd3";
private static final long FB_TIMEOUT = 10000L;
public static Result index() {
return ok("hello world");
}
/**
* Helper function to convert query string to map
* @param stream stream of query
* @return the map
*/
public static Map<String, String> queryToMap(InputStream stream) {
try(Scanner in = new Scanner(stream)) {
Map<String, String> query = new HashMap<>();
in.useDelimiter("[=&]");
while(in.hasNext()) {
String key = in.next();
String val = in.next();
query.put(key, val);
}
return query;
}
}
public static Result login() {
RequestBody request = request().body();
//retrieve access token param
JsonNode obj = request.asJson();
String accessToken = null;
String userId = null;
if(obj.has("access_token") && obj.has("fb_user_id")) {
accessToken = obj.get("access_token").textValue();
userId = obj.get("fb_user_id").textValue();
}
else {
return ok("usage: json object with fb_user_id, access_token");
}
//retrieve user id, first name, last name
String firstName;
String lastName;
try {
JsonNode userInfo = WS.url("https://graph.facebook.com/me")
.setQueryParameter("fields", "id,first_name,last_name")
.setQueryParameter("access_token", accessToken)
.get()
.get(FB_TIMEOUT)
.asJson();
if(userInfo.has("id") && userInfo.has("first_name") && userInfo.has("last_name")) {
if(!userId.equals(userInfo.get("id").textValue())) {
return ok(JsonNodeFactory.instance.objectNode().put("error", "invalid user id for access token"));
}
firstName = userInfo.get("first_name").textValue();
lastName = userInfo.get("last_name").textValue();
}
else {
return ok(JsonNodeFactory.instance.objectNode().put("error", "invalid access token"));
}
}
catch(Exception e) {
e.printStackTrace();
return ok();
}
//token exchange - get long lived access token and time till it expires in seconds
Response accessTokenResp = WS.url("https://graph.facebook.com/oauth/access_token")
.setQueryParameter("grant_type", "fb_exchange_token")
.setQueryParameter("client_id", APP_ID)
.setQueryParameter("client_secret", APP_SECRET)
.setQueryParameter("fb_exchange_token", accessToken)
.get()
.get(FB_TIMEOUT);
long expires = 0;
try(InputStream in = accessTokenResp.getBodyAsStream()) {
Map<String, String >respVals = queryToMap(in);
if(!respVals.containsKey("access_token") || !respVals.containsKey("expires")) {
return ok();
}
else {
accessToken = respVals.get("access_token");
expires = Long.parseLong(respVals.get("expires"));
}
}
catch(IOException e) {
e.printStackTrace();
return ok();
}
//write new info or updated info to db
try(Connection connection = DB.getConnection()) {
PreparedStatement stmt = connection.prepareStatement("INSERT INTO User (fb_user_id, first_name, last_name, access_token, expires) VALUES (?, ?, ?, ?, FROM_UNIXTIME(?)) ON DUPLICATE KEY UPDATE access_token=?, expires=FROM_UNIXTIME(?)");
stmt.setString(1, userId);
stmt.setString(2, firstName);
stmt.setString(3, lastName);
stmt.setString(4, accessToken);
long expiresTime = expires + (System.currentTimeMillis() / 1000L);
stmt.setLong(5, expiresTime);
stmt.setString(6, accessToken);
stmt.setLong(7, expiresTime);
stmt.execute();
}
catch(SQLException e) {
e.printStackTrace();
return ok();
}
//return long lived access token to use as auth
JsonNode resp = JsonNodeFactory.instance.objectNode().put("access_token", accessToken);
return ok(resp);
}
public static void checkReqValid(JsonNode req) throws AuthorizationException, SQLException {
JsonNode auth = req.get("auth");
if(auth != null && auth.has("fb_user_id") && auth.has("access_token")) {
String userId = auth.get("fb_user_id").textValue();
String accessToken = auth.get("access_token").textValue();
try(Connection connection = DB.getConnection()) {
//try to retrieve expires given the user id and access token
PreparedStatement stmt = connection.prepareStatement("SELECT UNIX_TIMESTAMP(expires) FROM User WHERE fb_user_id = ? AND access_token = ?");
stmt.setString(1, userId);
stmt.setString(2, accessToken);
stmt.execute();
ResultSet rs = stmt.getResultSet();
//if there is a row with such a user id and access token
if(rs.next()) {
//check expires against the current time
long expires = rs.getLong("UNIX_TIMESTAMP(expires)");
if(expires <= System.currentTimeMillis() / 1000L) {
throw new AuthorizationException("Login expired");
}
}
else {
throw new AuthorizationException("No such login");
}
}
}
else {
throw new AuthorizationException("No auth");
}
}
/**
* Helper method to get user id from database using any authorized request
* @param req the request
* @return id of user who made the request, -1 if invalid request
*/
public static long getUserId(JsonNode req) {
JsonNode auth = req.get("auth");
if(auth != null && auth.has("fb_user_id")) {
String userId = auth.get("fb_user_id").textValue();
try(Connection conn = DB.getConnection()) {
PreparedStatement stmt = conn.prepareStatement("SELECT id FROM User WHERE fb_user_id = ?");
stmt.setString(1, userId);
stmt.execute();
ResultSet rs = stmt.getResultSet();
if(rs.next()) {
return rs.getLong("id");
}
else {
return -1;
}
}
catch(SQLException e) {
e.printStackTrace();
return -1;
}
}
else {
return -1;
}
}
public static Result invite() {
return redirect("https://www.dropbox.com/s/bq9c9jkhdh8g29z/MainActivity.apk");
}
}