Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,22 @@
import uk.co.compendiumdev.challenge.apimodel.ChallengeApiModel;
import uk.co.compendiumdev.challenge.challengers.Challengers;
import uk.co.compendiumdev.thingifier.Thingifier;
import uk.co.compendiumdev.thingifier.adapter.spark.MainImplementation;
import uk.co.compendiumdev.thingifier.adapter.spark.ThingifierHttpApiRoutings;
import uk.co.compendiumdev.thingifier.adapter.httpserver.MainImplementation;
import uk.co.compendiumdev.thingifier.adapter.httpserver.ThingifierHttpApiRoutings;
import uk.co.compendiumdev.thingifier.core.repository.ThingStoreProviderConfig;

public class ChallengeMain {

static ChallengeRouteHandler challenger;
static MainImplementation app;

public static void main(String[] args) {

Logger logger = LoggerFactory.getLogger(ChallengeMain.class);

logger.info("Starting Challenger");

MainImplementation app = new MainImplementation();
app = new MainImplementation();
ThingStoreProviderConfig repositoryConfig = ThingStoreProviderConfig.fromArgs(args);
logger.info("Using Thingifier repository {}", repositoryConfig.describe());
Thingifier thingifier = new ChallengeApiModel().get(repositoryConfig.createProvider());
Expand Down Expand Up @@ -125,6 +126,10 @@ public static void stop() {
if (challenger != null) {
challenger.close();
}
if (app != null) {
app.close();
}
challenger = null;
app = null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import uk.co.compendiumdev.challenge.practicemodes.simpleapi.SimpleApiRoutes;
import uk.co.compendiumdev.challenge.practicemodes.simulation.SimulationRoutes;
import uk.co.compendiumdev.thingifier.Thingifier;
import uk.co.compendiumdev.thingifier.adapter.spark.ThingifierHttpApiRoutings;
import uk.co.compendiumdev.thingifier.adapter.httpserver.ThingifierHttpApiRoutings;
import uk.co.compendiumdev.thingifier.api.docgen.ThingifierApiDocumentationDefn;
import uk.co.compendiumdev.thingifier.htmlgui.htmlgen.DefaultGUIHTML;

Expand Down Expand Up @@ -130,20 +130,21 @@ public ChallengeRouteHandler configureRoutes() {
return this;
}

public void addHooks(final ThingifierHttpApiRoutings restServer) {
public void addHooks(final ThingifierHttpApiRoutings apiRoutings) {

// TODO: this is wrong - rethink this - we need SparkLevel, InternalHttp level (pre-post
// these hooks are registered at a spark before and after level so run on every request,
// regardless of thingifier used - this is wrong
restServer.registerInternalHttpResponseHook(
// TODO: these internal HTTP hooks are registered through server-level before/after hooks.
// They can run for every HTTP request handled by the server, not just requests for this
// Thingifier API routing. Prefer route-scoped internal HTTP hooks or move this behavior
// into the API bridge boundary when it only applies to this Thingifier.
apiRoutings.registerInternalHttpResponseHook(
new ChallengerInternalHTTPResponseHook(challengers));
restServer.registerInternalHttpRequestHook(
apiRoutings.registerInternalHttpRequestHook(
new ChallengerInternalHTTPRequestHook(challengers));

// add hooks at the API bridge pre and post level so they only work in the specific
// thingifier
restServer.registerHttpApiRequestHook(new ChallengerApiRequestHook(challengers));
restServer.registerHttpApiResponseHook(
// These hooks run inside the Thingifier API bridge for this routing instance, so they are
// scoped to this Thingifier's API request/response processing.
apiRoutings.registerHttpApiRequestHook(new ChallengerApiRequestHook(challengers));
apiRoutings.registerHttpApiResponseHook(
new ChallengerApiResponseHook(challengers, thingifier));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public ChallengerAuthData(Collection<CHALLENGE> definedChallenges) {
this.xChallenger = UUID.randomUUID().toString();
this.xAuthToken = UUID.randomUUID().toString();
this.expiresin = 600000; // 10 * 60 * 1000; // 10 minutes
this.extratime = 30000; // 30 * 1000 - extra time on each request
this.extratime = 30000; // 30 * 1000 - extra time on each HttpServerRequest
touch();
this.secretNote = "";
resetChallengesStatus(definedChallenges);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import java.util.function.BiConsumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import spark.Route;
import spark.Spark;
import uk.co.compendiumdev.thingifier.adapter.httpserver.HttpRouteHandler;
import uk.co.compendiumdev.thingifier.adapter.httpserver.ServerRoutes;

public class IndexNowRouteHandler {

Expand All @@ -15,16 +15,19 @@ public class IndexNowRouteHandler {

private final String keyLocation;
private final String key;
private final BiConsumer<String, Route> getRouteRegistrar;
private final BiConsumer<String, HttpRouteHandler> getRouteRegistrar;

public IndexNowRouteHandler() {
this(System.getenv(INDEX_NOW_KEY_LOCATION), System.getenv(INDEX_NOW_KEY), Spark::get);
this(
System.getenv(INDEX_NOW_KEY_LOCATION),
System.getenv(INDEX_NOW_KEY),
ServerRoutes::get);
}

IndexNowRouteHandler(
final String keyLocation,
final String key,
final BiConsumer<String, Route> getRouteRegistrar) {
final BiConsumer<String, HttpRouteHandler> getRouteRegistrar) {
this.keyLocation = normalize(keyLocation);
this.key = normalize(key);
this.getRouteRegistrar = getRouteRegistrar;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,8 @@ && collate(response.apiResponse().getErrorMessages())
&& request.getPath().matches("todos")
&& response.getStatusCode() == 413
&& collate(response.apiResponse().getErrorMessages())
.contains("Error: Request body too large, max allowed is 5000 bytes")) {
.toLowerCase()
.contains("request body too large")) {
challengers.pass(challenger, CHALLENGE.POST_TODOS_TOO_LONG_PAYLOAD_SIZE);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
import uk.co.compendiumdev.challenge.CHALLENGE;
import uk.co.compendiumdev.challenge.ChallengerAuthData;
import uk.co.compendiumdev.challenge.challengers.Challengers;
import uk.co.compendiumdev.thingifier.adapter.httpserver.messagehooks.InternalHttpRequestHook;
import uk.co.compendiumdev.thingifier.adapter.internalhttp.InternalHttpMethod;
import uk.co.compendiumdev.thingifier.adapter.internalhttp.InternalHttpRequest;
import uk.co.compendiumdev.thingifier.adapter.internalhttp.InternalHttpResponse;
import uk.co.compendiumdev.thingifier.adapter.spark.messagehooks.InternalHttpRequestHook;

/*
This is an Internal HTTP Request because it covers functionality for endpoints that do not
This is an Internal HTTP request because it covers functionality for endpoints that do not
go through the normal API process i.e. heartbeat, challenges, challenger
*/
public class ChallengerInternalHTTPRequestHook implements InternalHttpRequestHook {
Expand Down Expand Up @@ -71,20 +71,17 @@ public InternalHttpResponse run(final InternalHttpRequest request) {
challengers.pass(challenger, CHALLENGE.TRACE_HEARTBEAT_501);
}

if (method == InternalHttpMethod.POST
&& path.equals("heartbeat")
if (path.equals("heartbeat")
&& request.getHeader("x-http-method-override").equalsIgnoreCase("patch")) {
Comment on lines +74 to 75

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Guard heartbeat overrides by method and header

For any normal /heartbeat request with a tracked challenger but no X-HTTP-Method-Override header (including the documented GET /heartbeat flow), getHeader(...) returns null and this dereference throws. The Javalin runtime exception handler then returns 400 instead of the route's intended 204 response, and the heartbeat challenge cannot complete. Retain the POST guard and/or compare against a null-safe value.

Useful? React with 👍 / 👎.

challengers.pass(challenger, CHALLENGE.OVERRIDE_PATCH_HEARTBEAT_500);
}

if (method == InternalHttpMethod.POST
&& path.equals("heartbeat")
if (path.equals("heartbeat")
&& request.getHeader("x-http-method-override").equalsIgnoreCase("delete")) {
challengers.pass(challenger, CHALLENGE.OVERRIDE_DELETE_HEARTBEAT_405);
}

if (method == InternalHttpMethod.POST
&& path.equals("heartbeat")
if (path.equals("heartbeat")
&& request.getHeader("x-http-method-override").equalsIgnoreCase("trace")) {
challengers.pass(challenger, CHALLENGE.OVERRIDE_TRACE_HEARTBEAT_501);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
import uk.co.compendiumdev.challenge.ChallengerState;
import uk.co.compendiumdev.challenge.challengers.Challengers;
import uk.co.compendiumdev.challenge.challengesrouting.XChallengerHeader;
import uk.co.compendiumdev.thingifier.adapter.httpserver.messagehooks.InternalHttpResponseHook;
import uk.co.compendiumdev.thingifier.adapter.internalhttp.InternalHttpRequest;
import uk.co.compendiumdev.thingifier.adapter.internalhttp.InternalHttpResponse;
import uk.co.compendiumdev.thingifier.adapter.spark.messagehooks.InternalHttpResponseHook;
import uk.co.compendiumdev.thingifier.api.http.headers.headerparser.BearerAuthHeaderParser;

public class ChallengerInternalHTTPResponseHook implements InternalHttpResponseHook {
Expand Down Expand Up @@ -178,7 +178,7 @@ public void run(final InternalHttpRequest request, final InternalHttpResponse re
}
}

// No endpoint defined so this 404 created by Spark routing
// No endpoint defined so this 404 created by HTTP server routing
if (request.getVerb() == GET
&& request.getPath().contentEquals("todo")
&& response.getStatusCode() == 404) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public static ChallengeDefinitionData overridePostToPatchFor500(int challengeOrd
"POST /heartbeat as PATCH (500)",
"Issue a POST request on the `/heartbeat` end point and receive 500 when you override the Method Verb to a PATCH");

aChallenge.addHint("Use a normal POST Request, but add an X-HTTP-Method-Override header");
aChallenge.addHint("Use a normal POST request, but add an X-HTTP-Method-Override header");

aChallenge.addSolutionLink(
"Add a header 'X-HTTP-Method-Override: PATCH' to a POST /heartbeat request",
Expand All @@ -100,7 +100,7 @@ public static ChallengeDefinitionData overridePostToDeleteFor405(int challengeOr
"POST /heartbeat as DELETE (405)",
"Issue a POST request on the `/heartbeat` end point and receive 405 when you override the Method Verb to a DELETE");

aChallenge.addHint("Use a normal POST Request, but add an X-HTTP-Method-Override header");
aChallenge.addHint("Use a normal POST request, but add an X-HTTP-Method-Override header");

aChallenge.addSolutionLink(
"Add a header 'X-HTTP-Method-Override: DELETE' to a POST /heartbeat request",
Expand All @@ -121,7 +121,7 @@ public static ChallengeDefinitionData overridePostToTraceFor501(int challengeOrd
ChallengeRenderer.renderChallengeNumber(challengeOrder),
"POST /heartbeat as Trace (501)",
"Issue a POST request on the `/heartbeat` end point and receive 501 (Not Implemented) when you override the Method Verb to a TRACE");
aChallenge.addHint("Use a normal POST Request, but add an X-HTTP-Method-Override header");
aChallenge.addHint("Use a normal POST request, but add an X-HTTP-Method-Override header");

aChallenge.addSolutionLink(
"Add a header 'X-HTTP-Method-Override: TRACE' to a POST /heartbeat request",
Expand Down
Loading
Loading