Skip to content

Commit

Permalink
api security update
Browse files Browse the repository at this point in the history
  • Loading branch information
mastercoms committed Jul 11, 2024
1 parent 4892b85 commit 7ccca3d
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 7 deletions.
9 changes: 8 additions & 1 deletion src/endpoints/hudDownloadStat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
OpenAPIRouteSchema,
} from "@cloudflare/itty-router-openapi";
import anonymize from "ip-anonymize";
import { authenticate, validate } from "utils";
import { HudCount, HudStat } from "../types";

export class HudDownloadStat extends OpenAPIRoute {
Expand All @@ -26,6 +27,12 @@ export class HudDownloadStat extends OpenAPIRoute {
context: any,
data: Record<string, any>
) {
if (!validate(request)) {
return {
success: false,
};
}

// Retrieve the validated request body
const stat = data.body;

Expand Down Expand Up @@ -78,7 +85,7 @@ export class HudDownloadGet extends OpenAPIRoute {
context: any,
data: Record<string, any>
) {
if (request.headers.get("Authorization") !== `Bearer ${env.API_TOKEN}`) {
if (!authenticate(request, env.API_TOKEN)) {
return {
count: -2,
};
Expand Down
10 changes: 6 additions & 4 deletions src/endpoints/quickplay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
OpenAPIRouteSchema,
} from "@cloudflare/itty-router-openapi";
import geodesic from "geographiclib-geodesic";
import { authenticate, validate } from "utils";
import { ServerListData, ServerListRequest } from "../types";

const geod = geodesic.Geodesic.WGS84;
Expand Down Expand Up @@ -102,6 +103,10 @@ export class ServerListQuery extends OpenAPIRoute {
context: any,
data: Record<string, any>
) {
if (!validate(request)) {
return { servers: [], until: 0 };
}

const cfLon = request.cf.longitude as string | undefined;
const cfLat = request.cf.latitude as string | undefined;
if (!cfLat || !cfLon) {
Expand Down Expand Up @@ -195,10 +200,7 @@ export class ServerListUpdate extends OpenAPIRoute {
context: any,
data: Record<string, any>
) {
if (
false &&
request.headers.get("Authorization") !== `Bearer ${env.API_TOKEN}`
) {
if (!authenticate(request, env.API_TOKEN)) {
return {
success: false,
};
Expand Down
6 changes: 5 additions & 1 deletion src/endpoints/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
OpenAPIRoute,
OpenAPIRouteSchema,
} from "@cloudflare/itty-router-openapi";
import { authenticate, validate } from "utils";
import { SchemaData } from "../types";

export class SchemaGet extends OpenAPIRoute {
Expand All @@ -24,6 +25,9 @@ export class SchemaGet extends OpenAPIRoute {
context: any,
data: Record<string, any>
) {
if (!validate(request)) {
return {};
}
const schema = await env.QUICKPLAY.get("schema");
return new Response(schema);
}
Expand All @@ -50,7 +54,7 @@ export class SchemaUpdate extends OpenAPIRoute {
context: any,
data: Record<string, any>
) {
if (request.headers.get("Authorization") !== `Bearer ${env.API_TOKEN}`) {
if (!authenticate(request, env.API_TOKEN)) {
return {
success: false,
};
Expand Down
9 changes: 8 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,14 @@ export interface Env {
DB: D1Database;
}

const { preflight, corsify } = createCors();
const { preflight, corsify } = createCors({
origins: ["https://comfig.app"],
methods: ["GET", "HEAD", "POST"],
maxAge: 900,
headers: {
"Cross-Origin-Resource-Policy": "same-site",
},
});

export const router = OpenAPIRouter({
docs_url: "/",
Expand Down
73 changes: 73 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
export function authenticate(request: Request, key: string) {
const auth = request.headers.get("Authorization") || "";

// If not authenticated, it's an automatic rejection. The user already knows it is an authenticated resource.
if (!auth) {
return false;
}

// If there is no key, it cannot be authenticated.
if (!key) {
return false;
}

let realBearer = `Bearer ${key}`;
// If the auth and bearer token are not equal length, encode the user's auth as the key so they always get back a result with an encoding time which matches their key.
let falseSet = false;
if (auth.length !== realBearer.length) {
realBearer = auth;
falseSet = true;
}

const encoder = new TextEncoder();

// a and b must be equal length, or else the encoding time can be used as an attack vector.
const a = encoder.encode(auth);
const b = encoder.encode(realBearer);

if (!crypto.subtle.timingSafeEqual(a, b)) {
return false;
}

if (falseSet) {
return false;
}

return true;
}

const allowedFetchSites = new Set(["same-origin", "same-site"]);
const allowedFetchModes = new Set(["cors", "no-cors", "same-origin"]);
const disallowedFetchDests = new Set(["frame", "iframe", "embed", "object"]);

export function validate(request: Request) {
const fetchSite = request.headers.get("Sec-Fetch-Site");
const fetchMode = request.headers.get("Sec-Fetch-Mode");
const fetchDest = request.headers.get("Sec-Fetch-Dest");

if (!fetchSite) {
return true;
}

if (!fetchMode) {
return true;
}

if (!fetchDest) {
return true;
}

if (!allowedFetchSites.has(fetchSite)) {
return false;
}

if (!allowedFetchModes.has(fetchMode)) {
return false;
}

if (disallowedFetchDests.has(fetchDest)) {
return false;
}

return true;
}

0 comments on commit 7ccca3d

Please sign in to comment.