Skip to content

Commit

Permalink
so many changes
Browse files Browse the repository at this point in the history
  • Loading branch information
Aslemammad committed Mar 22, 2024
1 parent 90cb524 commit 37b783b
Show file tree
Hide file tree
Showing 12 changed files with 76 additions and 126 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/cr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ jobs:
cache: "pnpm"
- run: pnpm install
- run: pnpm build
- run: pnpm sb publish
- run: cd playground && pnpm sb publish
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ dist
.cache
.output
.env*
.wrangler
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@
"eslint-config-unjs": "^0.2.1",
"ohash": "^1.1.3",
"prettier": "^3.2.5",
"typescript": "^5.4.2"
"typescript": "^5.4.2",
"uncrypto": "^0.1.3"
},
"pnpm": {
"patchedDependencies": {
"[email protected]": "patches/[email protected]"
}
},
"dependencies": {
"stackblitz-cr": "workspace:^",
"wrangler": "^3.36.0"
}
}
20 changes: 16 additions & 4 deletions packages/backend/nitro.config.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import {fileURLToPath} from 'url'
import { DurableObject, R2Bucket } from '@cloudflare/workers-types';
import { KVNamespace, R2Bucket } from '@cloudflare/workers-types';
import ncb from 'nitro-cloudflare-dev'

declare module "nitro-cloudflare-dev" {
interface Env {
PKGS: R2Bucket
WORKFLOWS: DurableObject
WORKFLOWS: KVNamespace
}
}

Expand All @@ -22,7 +21,20 @@ export default defineNitroConfig({
preset: 'cloudflare-pages',
modules: [ncb],
srcDir: "server",
entry: fileURLToPath(new URL('./preset/entry.ts', import.meta.url)),
storage: {
'workflows': {
driver: 'cloudflare-kv-binding',
base: 'workflows',
binding: 'WORKFLOWS'
},
},
devStorage: {
'workflows': {
driver: 'cloudflare-kv-binding',
base: 'workflows',
binding: 'WORKFLOWS'
}
},

runtimeConfig: {
appId: "",
Expand Down
4 changes: 0 additions & 4 deletions packages/backend/preset/entry.ts

This file was deleted.

7 changes: 0 additions & 7 deletions packages/backend/preset/nitro.config.ts

This file was deleted.

123 changes: 32 additions & 91 deletions packages/backend/server/routes/webhook.post.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import {objectHash} from 'ohash'
import type { HandlerFunction } from "@octokit/webhooks/dist-types/types";
import { objectHash, sha256 } from "ohash";
import { App } from "octokit";
import { useWorkflows } from "../../utils/workflows";

export default eventHandler(async (event) => {
const { appId, privateKey, webhookSecret } = useRuntimeConfig(event);
Expand All @@ -10,110 +12,49 @@ export default eventHandler(async (event) => {
secret: webhookSecret,
},
});
app.webhooks.on("workflow_job.queued", ({ octokit, payload }) => {
const token = {
const { setItem, removeItem } = useWorkflows();

const workflowHandler: HandlerFunction<"workflow_job", unknown> = async ({
payload,
}) => {
const metadata = {
url: payload.workflow_job.url,
attempt: payload.workflow_job.run_attempt,
actor: payload.sender.id
actor: payload.sender.id,
};
const key = sha256(objectHash(metadata));
if (payload.action === 'queued') {
// Publishing is only available throughout the lifetime of a worklow_job
await setItem(key, {});
} else if (payload.action === 'completed') {
// Publishing is not available anymore
await removeItem(key);
}
const hashedToken = objectHash(token)
console.log(token)
console.log(hashedToken)
});

type EmitterWebhookEvent = Parameters<typeof app.webhooks.receive>[0]
const id: EmitterWebhookEvent['id'] = event.headers.get("x-github-delivery");
const name = event.headers.get("x-github-event") as EmitterWebhookEvent['name'];
};

app.webhooks.on("workflow_job", workflowHandler)

type EmitterWebhookEvent = Parameters<typeof app.webhooks.receive>[0];
const id: EmitterWebhookEvent["id"] = event.headers.get("x-github-delivery");
const name = event.headers.get(
"x-github-event"
) as EmitterWebhookEvent["name"];
const signature = event.headers.get("x-hub-signature-256") ?? "";
const payloadString = await readRawBody(event);
const payload = await readBody<EmitterWebhookEvent['payload']>(event);

// Verify webhook signature
try {
await verifyWebhookSignature(payloadString, signature, webhookSecret);
} catch (error) {
app.log.warn(error.message);
return new Response(`{ "error": "${error.message}" }`, {
status: 400,
headers: { "content-type": "application/json" },
});
}
const payload = await readRawBody(event);

// Now handle the request
try {
await app.webhooks.receive({
id,
name,
payload,
} as EmitterWebhookEvent);
await app.webhooks.verifyAndReceive({ id, name, payload, signature });

return new Response(`{ "ok": true }`, {
headers: { "content-type": "application/json" },
});
} catch (error) {
app.log.error(error);

app.log.error(error.message);
return new Response(`{ "error": "${error.message}" }`, {
status: 500,
headers: { "content-type": "application/json" },
});
} finally {
app.webhooks.removeListener("workflow_job", workflowHandler)
}
});

// https://github.com/gr2m/cloudflare-worker-github-app-example/blob/main/lib/verify.js
export async function verifyWebhookSignature(
payload: string,
signature: string,
secret: string
) {
if (!signature) {
throw new Error("Signature is missing");
} else if (!signature.startsWith("sha256=")) {
throw new Error("Invalid signature format");
}

const algorithm = { name: "HMAC", hash: "SHA-256" };
const enc = new TextEncoder();
const key = await crypto.subtle.importKey(
"raw",
enc.encode(secret),
algorithm,
false,
["sign", "verify"]
);

const signed = await crypto.subtle.sign(
algorithm.name,
key,
enc.encode(payload)
);
const expectedSignature = "sha256=" + array2hex(signed);
if (!safeCompare(expectedSignature, signature)) {
throw new Error("Signature does not match event payload and secret");
}

// All good!
}

function array2hex(arr: ArrayBuffer) {
return [...new Uint8Array(arr)]
.map((x) => x.toString(16).padStart(2, "0"))
.join("");
}

/** Constant-time string comparison */
function safeCompare(expected: string, actual: string) {
const lenExpected = expected.length;
let result = 0;

if (lenExpected !== actual.length) {
actual = expected;
result = 1;
}

for (let i = 0; i < lenExpected; i++) {
result |= expected.charCodeAt(i) ^ actual.charCodeAt(i);
}

return result === 0;
}
7 changes: 7 additions & 0 deletions packages/backend/utils/workflows.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
interface Workflow {

}

export function useWorkflows() {
return useStorage<Workflow>('workflows')
}
12 changes: 4 additions & 8 deletions packages/backend/wrangler.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,12 @@ compatibility_date = "2024-03-14"
# [site]
# bucket = ".output/public"

kv_namespaces = [
{ binding = "WORKFLOWS", id = "Workflows" }
]

[[r2_buckets]]
binding = 'PKGS' # <~ valid JavaScript variable name
bucket_name = 'Packages'

[durable_objects]
bindings = [
{ name = "WORKFLOWS", class_name = "Workflows" }
]

[[migrations]]
tag = "v1" # Should be unique for each entry
new_classes = ["Workflows"]

11 changes: 6 additions & 5 deletions packages/cli/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { defineCommand, runMain } from "citty";
// import { createRequire } from "module";
import { version } from "./package.json";
import {objectHash} from 'ohash'
import {objectHash, sha256} from 'ohash'
import { Octokit } from "@octokit/action";
import "./environments";

Expand All @@ -11,23 +11,24 @@ if (process.env.GITHUB_ACTIONS !== 'true') {
}

const {GITHUB_SERVER_URL, GITHUB_REPOSITORY, GITHUB_RUN_ID, GITHUB_RUN_ATTEMPT, GITHUB_ACTOR_ID} = process.env
// const octokit = new Octokit();
const octokit = new Octokit();
// const eventPayload = await import(process.env.GITHUB_EVENT_PATH, {
// with: { type: "json" },
// });

// Note: If you need to use a workflow run's URL from within a job, you can combine these variables: $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID
const url = `${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}`

const token = {
const metadata = {
url,
attempt: GITHUB_RUN_ATTEMPT,
actor: GITHUB_ACTOR_ID
}

const hashedToken = objectHash(token)
const key = sha256(objectHash(metadata))

console.log(hashedToken)
console.log(key)
fetch('/',{body})

// console.log(octokit)
// console.log(eventPayload)
Expand Down
5 changes: 4 additions & 1 deletion playground/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,8 @@
},
"keywords": [],
"author": "",
"license": "ISC"
"license": "ISC",
"devDependencies": {
"stackblitz-cr": "workspace:^"
}
}
6 changes: 3 additions & 3 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 37b783b

Please sign in to comment.