webmarker-server/src/main/java/net/mindoverflow/webmarker/webserver/controllers/StorageController.java

163 lines
4.5 KiB
Java

package net.mindoverflow.webmarker.webserver.controllers;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import net.mindoverflow.webmarker.utils.FileUtils;
import net.mindoverflow.webmarker.utils.config.ConfigEntries;
import net.mindoverflow.webmarker.utils.security.SafetyCheck;
import net.mindoverflow.webmarker.utils.sql.MarkerSQLUtils;
import ro.pippo.controller.Controller;
import ro.pippo.controller.POST;
import ro.pippo.controller.Path;
import ro.pippo.core.route.RouteContext;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.UUID;
@Path("/api/v1/store")
public class StorageController extends Controller
{
private RouteContext routeContext;
@POST
public void store()
{
// Load RouteContext
routeContext = getRouteContext();
// Load JSON object from body
String body = routeContext.getRequest().getBody();
JsonObject jsonObject = FileUtils.stringToJson(body);
// Load JWT element
JsonElement jwtElement = getJwtFromJson(jsonObject);
if(jwtElement == null) return;
// Decrypt/Verify JWT
DecodedJWT jwt = decryptAndVerifyJwt(jwtElement);
if(jwt == null) return;
// Load username from JWT
String username = getFromJwt(jwt, "username");
if(username == null) return;
// Check some stuff about the user
if(!userCheckPassed(username)) return;
// Load UUID from username
UUID uuid = MarkerSQLUtils.getUserUUID(username);
if(uuid == null)
{
routeContext.send("Server error: missing UUID!");
return;
}
// Load url from Json body
String url = getFromJson(jsonObject, "url");
if(url == null) return;
// Verify url validity
URI confirmedUrl = verifyUrl(url);
if(confirmedUrl == null) return;
MarkerSQLUtils.addHistoryRecord(uuid, confirmedUrl.toString());
routeContext.send("OK!");
}
private JsonElement getJwtFromJson(JsonObject jsonObject)
{
JsonElement jwtElement = jsonObject.get("jwt");
if(jwtElement == null || jwtElement.isJsonNull())
{
routeContext.send("Invalid JWT!"); //todo: throw exception instead?
return null;
}
return jwtElement;
}
private DecodedJWT decryptAndVerifyJwt(JsonElement jwtElement)
{
String token = jwtElement.getAsString();
try {
Algorithm algorithm = Algorithm.HMAC256((String) ConfigEntries.JWT_SECRET.getValue());
JWTVerifier jwtVerifier = JWT.require(algorithm)
.build();
return jwtVerifier.verify(token);
}
catch (JWTVerificationException e)
{
routeContext.send("Invalid JWT!");
return null;
}
}
private String getFromJwt(DecodedJWT jwt, String claimName)
{
Claim claim = jwt.getClaim(claimName);
if(claim == null || claim.isNull())
{
routeContext.send("JWT missing '" + claimName + "' claim!");
return null;
}
return claim.asString();
}
private boolean userCheckPassed(String username)
{
if(!SafetyCheck.isSafeUsername(username))
{
routeContext.send("Invalid username!");
return false;
}
if(!MarkerSQLUtils.userExists(username))
{
routeContext.send("User does not exist!");
return false;
}
return true;
}
private String getFromJson(JsonObject jsonObject, String name)
{
JsonElement jsonElement = jsonObject.get(name);
if(jsonElement == null || jsonElement.isJsonNull())
{
routeContext.send("JSON body missing '" + name + "' entry!");
return null;
}
return jsonElement.getAsString();
}
private URI verifyUrl(String url)
{
try {
return new URL(url).toURI();
} catch (URISyntaxException e) {
routeContext.send("Invalid URI!");
}
catch (MalformedURLException e) {
routeContext.send("Invalid URL!");
}
return null;
}
}