import { hmac } from "https://deno.land/x/crypto@v0.10.1/hmac.ts";
const LINK_DOMAIN = "mux.link";
const token = Deno.env.get("DUB_API_KEY");
const dubWorkspaceId = Deno.env.get("DUB_WORKSPACE_ID");
const signingSecret = Deno.env.get("SLACK_MUX_LINK_SIGNING_SECRET");
const encoder = new TextEncoder();
function uint8ArrayToHexString(uint8Array: Uint8Array): string {
return Array.from(uint8Array)
.map(byte => byte.toString(16).padStart(2, "0"))
.join("");
}
function parseFormData(formDataString: string): Record<string, string> {
const params = new URLSearchParams(formDataString);
const formData: Record<string, string> = {};
for (const [key, value] of params.entries()) {
formData[key] = value;
}
return formData;
}
export default async function(req: Request): Promise<Response> {
if (req.method !== "POST") {
return Response.json({ message: "This val responds to POST requests." }, {
status: 400,
});
}
const rawBody = new Uint8Array(await req.arrayBuffer());
const bodyText = new TextDecoder("utf-8").decode(rawBody);
const timestamp = req.headers.get("x-slack-request-timestamp");
const reqSignature = req.headers.get("x-slack-signature");
const sigBaseString = "v0:" + timestamp + ":" + bodyText;
const digest = hmac("sha256", encoder.encode(signingSecret), encoder.encode(sigBaseString));
const sig = "v0=" + uint8ArrayToHexString(digest);
if (reqSignature !== sig) {
return Response.json({ message: "Invalid Slack signature" }, { status: 401 });
}
const payload = parseFormData(bodyText);
const [destination, slug, comments] = payload.text.split(" ");
if (destination === "list") {
const req = await fetch(`https://api.dub.co/links?workspaceId=${dubWorkspaceId}`, {
headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
});
const body = await req.json();
return Response.json({
mrkdown: true,
text: `No prob, friend. Here are the last 100 links created.
${body.map(link => `- ${link.shortLink} -> ${link.url} (last clicked: ${link.lastClicked})`).join("\n")}`,
});
}
const body = {
url: destination,
domain: LINK_DOMAIN,
key: slug,
comments,
};
const options = {
method: "POST",
headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
body: JSON.stringify(body),
};
try {
const resp = await fetch(`https://api.dub.co/links?workspaceId=${dubWorkspaceId}`, options).then(
response => response.json(),
);
console.log(resp);
if (resp.error) {
return Response.json({ ok: false, error: resp.error });
} else {
return Response.json({ ok: true, url: resp.shortLink });
}
} catch (err) {
console.error(err);
return Response.json({ ok: false });
}
}