mirror of
https://github.com/feeddeck/feeddeck.git
synced 2026-04-28 09:57:47 -05:00
Instead of using an `import_map.json` file to define the versions for dependencies, they are now defined directly within the import. Since the `import_map.json` file should not be used anymore and instead a `deno.json` file per function should be used, we decided to define them directly with the code. The overhead compared to a `deno.json` file per function shouldn't be that large and it makes using functions in a self-hosted setup easier.
83 lines
1.8 KiB
TypeScript
83 lines
1.8 KiB
TypeScript
const base64URL = (value: string) => {
|
|
return globalThis
|
|
.btoa(value)
|
|
.replace(/[=]/g, "")
|
|
.replace(/[+]/g, "-")
|
|
.replace(/[\/]/g, "_");
|
|
};
|
|
|
|
const stringToArrayBuffer = (value: string): ArrayBuffer => {
|
|
const buf = new ArrayBuffer(value.length);
|
|
const bufView = new Uint8Array(buf);
|
|
for (let i = 0; i < value.length; i++) {
|
|
bufView[i] = value.charCodeAt(i);
|
|
}
|
|
return buf;
|
|
};
|
|
|
|
const arrayBufferToString = (buf: ArrayBuffer): string => {
|
|
return String.fromCharCode(...new Uint8Array(buf));
|
|
};
|
|
|
|
export const generateAppleSecretKey = async (
|
|
kid: string,
|
|
iss: string,
|
|
sub: string,
|
|
file: string,
|
|
): Promise<{ kid: string; jwt: string; exp: number }> => {
|
|
const contents = await Deno.readTextFile(file);
|
|
|
|
if (
|
|
!contents.match(/^\s*-+BEGIN PRIVATE KEY-+[^-]+-+END PRIVATE KEY-+\s*$/i)
|
|
) {
|
|
throw new Error(
|
|
`Chosen file does not appear to be a PEM encoded PKCS8 private key file.`,
|
|
);
|
|
}
|
|
|
|
// remove PEM headers and spaces
|
|
const pkcs8 = stringToArrayBuffer(
|
|
globalThis.atob(contents.replace(/-+[^-]+-+/g, "").replace(/\s+/g, "")),
|
|
);
|
|
|
|
const privateKey = await globalThis.crypto.subtle.importKey(
|
|
"pkcs8",
|
|
pkcs8,
|
|
{
|
|
name: "ECDSA",
|
|
namedCurve: "P-256",
|
|
},
|
|
true,
|
|
["sign"],
|
|
);
|
|
|
|
const iat = Math.floor(Date.now() / 1000);
|
|
const exp = iat + 180 * 24 * 60 * 60;
|
|
|
|
const jwt = [
|
|
base64URL(JSON.stringify({ typ: "JWT", kid, alg: "ES256" })),
|
|
base64URL(
|
|
JSON.stringify({
|
|
iss,
|
|
sub,
|
|
iat,
|
|
exp,
|
|
aud: "https://appleid.apple.com",
|
|
}),
|
|
),
|
|
];
|
|
|
|
const signature = await globalThis.crypto.subtle.sign(
|
|
{
|
|
name: "ECDSA",
|
|
hash: "SHA-256",
|
|
},
|
|
privateKey,
|
|
stringToArrayBuffer(jwt.join(".")),
|
|
);
|
|
|
|
jwt.push(base64URL(arrayBufferToString(signature)));
|
|
|
|
return { kid, jwt: jwt.join("."), exp };
|
|
};
|