Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pong2 #9775

Merged
merged 6 commits into from
Oct 25, 2023
Merged

Pong2 #9775

Show file tree
Hide file tree
Changes from 3 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
5 changes: 3 additions & 2 deletions .github/workflows/stage-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -347,15 +347,16 @@ jobs:
--set-env-vars="ORIGIN_PLAY=mdnyalp.dev" \
--set-env-vars="SOURCE_CONTENT=https://storage.googleapis.com/${{ vars.GCP_BUCKET_NAME }}/main/" \
--set-env-vars="SOURCE_API=https://api.developer.allizom.org/" \
--set-env-vars="BSA_ENABLED=true" \
--set-env-vars="BSA_URL_PREFIX=https://developer.allizom.org/fr/" \
--set-env-vars="SENTRY_DSN=${{ secrets.SENTRY_DSN_CLOUD_FUNCTION }}" \
--set-env-vars="SENTRY_ENVIRONMENT=stage" \
--set-env-vars="SENTRY_TRACES_SAMPLE_RATE=${{ vars.SENTRY_TRACES_SAMPLE_RATE }}" \
--set-env-vars="SENTRY_RELEASE=${{ github.sha }}" \
--set-secrets="KEVEL_SITE_ID=projects/${{ secrets.GCP_PROJECT_NAME }}/secrets/stage-kevel-site-id/versions/latest" \
--set-secrets="KEVEL_NETWORK_ID=projects/${{ secrets.GCP_PROJECT_NAME }}/secrets/stage-kevel-network-id/versions/latest" \
--set-secrets="SIGN_SECRET=projects/${{ secrets.GCP_PROJECT_NAME }}/secrets/stage-sign-secret/versions/latest" \
--set-secrets="CARBON_ZONE_KEY=projects/${{ secrets.GCP_PROJECT_NAME }}/secrets/stage-carbon-zone-key/versions/latest" \
--set-secrets="CARBON_FALLBACK_ENABLED=projects/${{ secrets.GCP_PROJECT_NAME }}/secrets/stage-fallback-enabled/versions/latest" \
--set-secrets="BSA_ZONE_KEYS=projects/${{ secrets.GCP_PROJECT_NAME }}/secrets/stage-bsa-zone-keys/versions/latest" \
2>&1 | sed "s/^/[$region] /" &
pids+=($!)
done
Expand Down
8 changes: 4 additions & 4 deletions cloud-function/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ The placement handler uses the following environment variables:
- `KEVEL_SITE_ID` (default: `0`) - Required for serving placements via Kevel.
- `KEVEL_NETWORK_ID` (default: `0`) - Required for serving placements via Kevel.
- `SIGN_SECRET` (default: `""`) - Required for serving placements.
- `CARBON_ZONE_KEY` (default: `""`) - Required for serving placements via
Carbon.
- `CARBON_FALLBACK_ENABLED` (default: `"false"`) - Whether fallback placements
should be served via Carbon.
- `BSA_ZONE_KEYS` (default: `""`) - Required for serving placements via BSA.
fiji-flo marked this conversation as resolved.
Show resolved Hide resolved
- `BSA_URL_PREFIX`(default: "https://localhost") - Where to show BSA placements
if enabled.
- `BSA_ENABLED` (default: `"false"`) - Whether to use placements via BSA.

You can override the defaults by adding a `.env` file with `KEY=value` lines.
6 changes: 3 additions & 3 deletions cloud-function/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

import { Origin } from "./env.js";
import { proxyContent } from "./handlers/proxy-content.js";
import { proxyKevel } from "./handlers/proxy-kevel.js";
import { proxyApi } from "./handlers/proxy-api.js";
import { handleStripePlans } from "./handlers/handle-stripe-plans.js";
import { proxyTelemetry } from "./handlers/proxy-telemetry.js";
Expand All @@ -22,6 +21,7 @@
import { resolveRunnerHtml } from "./middlewares/resolve-runner-html.js";
import { proxyRunner } from "./handlers/proxy-runner.js";
import { stripForwardedHostHeaders } from "./middlewares/stripForwardedHostHeaders.js";
import { proxyPong } from "./handlers/proxy-pong.js";

const router = Router();
router.use(stripForwardedHostHeaders);
Expand All @@ -37,8 +37,8 @@
proxyApi
);
router.all("/submit/mdn-yari/*", requireOrigin(Origin.main), proxyTelemetry);
router.all("/pong/*", requireOrigin(Origin.main), express.json(), proxyKevel);
router.all("/pimg/*", requireOrigin(Origin.main), proxyKevel);
router.all("/pong/*", requireOrigin(Origin.main), express.json(), proxyPong);

Check failure

Code scanning / CodeQL

Missing rate limiting High

This route handler performs
authorization
, but is not rate-limited.
This route handler performs
authorization
, but is not rate-limited.
router.all("/pimg/*", requireOrigin(Origin.main), proxyPong);
Dismissed Show dismissed Hide dismissed
router.get(
["/[^/]+/docs/*/runner.html", "/[^/]+/blog/*/runner.html", "/runner.html"],
requireOrigin(Origin.play),
Expand Down
10 changes: 7 additions & 3 deletions cloud-function/src/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,13 @@ export function sourceUri(source: Source): string {
export const KEVEL_SITE_ID = Number(process.env["KEVEL_SITE_ID"] ?? 0);
export const KEVEL_NETWORK_ID = Number(process.env["KEVEL_NETWORK_ID"] ?? 0);
export const SIGN_SECRET = process.env["SIGN_SECRET"] ?? "";
export const CARBON_ZONE_KEY = process.env["CARBON_ZONE_KEY"] ?? "";
export const CARBON_FALLBACK_ENABLED = Boolean(
JSON.parse(process.env["CARBON_FALLBACK_ENABLED"] || "false")
export const BSA_ZONE_KEYS = Object.fromEntries(
(process.env["BSA_ZONE_KEYS"] ?? "").split(";").map((k) => k.split(":"))
);
export const BSA_URL_PREFIX =
process.env["BSA_URL_PREFIX"] ?? "https://localhost/en-US/play";
fiji-flo marked this conversation as resolved.
Show resolved Hide resolved
export const BSA_ENABLED = Boolean(
JSON.parse(process.env["BSA_ENABLED"] || "false")
);

// HTTPS.
Expand Down
94 changes: 94 additions & 0 deletions cloud-function/src/handlers/proxy-bsa.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import * as url from "node:url";

import type { Request, Response } from "express";

import { Coder } from "../internal/pong/index.js";
import {
createPong2GetHandler,
createPong2ClickHandler,
createPong2ViewedHandler,
fetchImage,
} from "../internal/pong/index.js";

import * as env from "../env.js";

import { getRequestCountry } from "../utils.js";

const { SIGN_SECRET, BSA_ZONE_KEYS } = env;

const coder = new Coder(SIGN_SECRET);
const handleGet = createPong2GetHandler(BSA_ZONE_KEYS, coder, env);
const handleClick = createPong2ClickHandler(coder);
const handleViewed = createPong2ViewedHandler(coder);

export async function proxyBSA(req: Request, res: Response) {
const countryCode = getRequestCountry(req);

const userAgent = req.headers["user-agent"] ?? "";

const parsedUrl = url.parse(req.url);
const pathname = parsedUrl.pathname ?? "";
const search = parsedUrl.search ?? "";

if (pathname === "/pong/get") {
if (req.method !== "POST") {
return res.sendStatus(405).end();
}

const { body } = req;
const { statusCode: status, payload } = await handleGet(
body,
countryCode,
userAgent
);

return res
.status(status)
.setHeader("cache-control", "no-store")
.setHeader("content-type", "application/json")
.end(JSON.stringify(payload));
} else if (req.path === "/pong/click") {
if (req.method !== "GET") {
return res.sendStatus(405).end();
}
const params = new URLSearchParams(search);
try {
const { status, location } = await handleClick(params);
if (location && (status === 301 || status === 302)) {
return res.redirect(location);
} else {
return res.sendStatus(502).end();
}
} catch (e) {
console.error(e);
}
} else if (pathname === "/pong/viewed") {
if (req.method !== "POST") {
return res.sendStatus(405).end();
}
const params = new URLSearchParams(search);
try {
await handleViewed(params);
return res.sendStatus(201).end();
} catch (e) {
console.error(e);
}
} else if (pathname.startsWith("/pimg/")) {
const src = coder.decodeAndVerify(
decodeURIComponent(pathname.substring("/pimg/".length))
);
if (!src) {
return res.sendStatus(400).end();
}
const { buf, contentType } = await fetchImage(src);
return res
.status(200)
.set({
"cache-control": "max-age=86400",
"content-type": contentType,
})
.end(Buffer.from(buf));
}

return res.status(204).end();
}
15 changes: 15 additions & 0 deletions cloud-function/src/handlers/proxy-pong.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { BSA_ENABLED, BSA_URL_PREFIX } from "../env.js";
import { proxyBSA } from "./proxy-bsa.js";
import { proxyKevel } from "./proxy-kevel.js";

import type { Request, Response } from "express";

export async function proxyPong(req: Request, res: Response) {
if (BSA_ENABLED) {
const referrer = req.get("referrer") || "";
if (referrer.startsWith(BSA_URL_PREFIX)) {
return proxyBSA(req, res);
}
}
return proxyKevel(req, res);
}
Loading
Loading