anki/ts/lib/post.ts
Damien Elmes f73eb01047 More tweaks to API security
- Allow custom study methods in reviewer to prevent errors
- Ensure we 'fail closed' if referer header has been removed
- Ensure we ignore opaque POST requests from other origins

Thanks again to Daniel for the feedback.
2023-11-09 20:43:23 +10:00

49 lines
1.5 KiB
TypeScript

// Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
export interface PostProtoOptions {
/** True by default. Shows a dialog with the error message, then rethrows. */
alertOnError?: boolean;
}
export async function postProto<T>(
method: string,
input: { toBinary(): Uint8Array; getType(): { typeName: string } },
outputType: { fromBinary(arr: Uint8Array): T },
{ alertOnError = true }: PostProtoOptions,
): Promise<T> {
try {
const inputBytes = input.toBinary();
const path = `/_anki/${method}`;
const outputBytes = await postProtoInner(path, inputBytes);
return outputType.fromBinary(outputBytes);
} catch (err) {
if (alertOnError && !(err instanceof Error && err.message === "500: Interrupted")) {
alert(err);
}
throw err;
}
}
async function postProtoInner(url: string, body: Uint8Array): Promise<Uint8Array> {
const result = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/binary",
},
body,
});
if (!result.ok) {
let msg = "something went wrong";
try {
msg = await result.text();
} catch {
// ignore
}
throw new Error(`${result.status}: ${msg}`);
}
const blob = await result.blob();
const respBuf = await new Response(blob).arrayBuffer();
return new Uint8Array(respBuf);
}