86 lines
2.4 KiB
TypeScript

function arrBufToB64Url(buf: ArrayBuffer) {
const b64data = btoa(String.fromCharCode(...new Uint8Array(buf)));
return b64data.replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
}
function stringToBuffer(str: string) {
const buffer = new ArrayBuffer(str.length);
const ui8 = new Uint8Array(buffer);
for (let i = 0, bufLen = str.length; i < bufLen; i++) {
ui8[i] = str.charCodeAt(i);
}
return buffer;
}
export async function GetAccessToken(env: Env): Promise<string> {
const claimSet = btoa(
JSON.stringify({
aud: "https://oauth2.googleapis.com/token",
exp: Math.floor(Date.now() / 1000) + 120,
iat: Math.floor(Date.now() / 1000),
iss: env.WORKER_GSERVICEACCOUNT,
scope: "https://www.googleapis.com/auth/cloud-platform",
}),
)
.replaceAll("+", "-")
.replaceAll("/", "_")
.replaceAll("=", "");
const signingKey = await crypto.subtle.importKey(
"pkcs8",
stringToBuffer(atob(env.STORAGE_ACCOUNT_KEY.replace(/(\r\n|\n|\r)/gm, ""))),
{ name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
false,
["sign"],
);
const signature = await crypto.subtle.sign(
{ name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
signingKey,
stringToBuffer(`eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.${claimSet}`),
);
const assertion = `eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.${claimSet}.${arrBufToB64Url(
signature,
)}`;
const tokenRequest = await fetch("https://oauth2.googleapis.com/token", {
body: `grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=${assertion}`,
headers: {
"content-type": "application/x-www-form-urlencoded",
},
method: "POST",
});
if (!tokenRequest.ok)
throw new Error(`Failed to get access token: ${await tokenRequest.text()}`);
return ((await tokenRequest.json()) as { [k: string]: any }).access_token;
}
export async function sendPushNotification(
env: Env,
title: string,
body: string,
token: string,
) {
const message = {
notification: {
body,
title,
},
token,
};
const notifResp = await fetch(
"https://fcm.googleapis.com/v1/projects/car-crushers-mobile/messages:send",
{
body: JSON.stringify({ message }),
headers: {
authorization: `Bearer ${await GetAccessToken(env)}`,
"content-type": "application/json",
},
method: "POST",
},
);
if (!notifResp.ok) throw new Error(await notifResp.text());
}