113 lines
2.8 KiB
TypeScript
113 lines
2.8 KiB
TypeScript
import isEqual from "lodash/isEqual";
|
|
import { base64url } from "rfc4648";
|
|
import { reverseString } from "./misc";
|
|
|
|
const DEFAULT_README_FOR_METADATAONREMOTE =
|
|
"Do NOT edit or delete the file manually. This file is for the plugin remotely-save to store some necessary meta data on the remote services. Its content is slightly obfuscated.";
|
|
|
|
const DEFAULT_VERSION_FOR_METADATAONREMOTE = "20220220";
|
|
|
|
export const DEFAULT_FILE_NAME_FOR_METADATAONREMOTE =
|
|
"_remotely-save-metadata-on-remote.json";
|
|
|
|
export const DEFAULT_FILE_NAME_FOR_METADATAONREMOTE2 =
|
|
"_remotely-save-metadata-on-remote.bin";
|
|
|
|
export interface DeletionOnRemote {
|
|
key: string;
|
|
actionWhen: number;
|
|
}
|
|
|
|
export interface MetadataOnRemote {
|
|
version?: string;
|
|
generatedWhen?: number;
|
|
deletions?: DeletionOnRemote[];
|
|
}
|
|
|
|
export const isEqualMetadataOnRemote = (
|
|
a: MetadataOnRemote | undefined,
|
|
b: MetadataOnRemote | undefined
|
|
) => {
|
|
const m1 = a === undefined ? { deletions: [] } : a;
|
|
const m2 = b === undefined ? { deletions: [] } : b;
|
|
|
|
// we only need to compare deletions
|
|
const d1 = m1.deletions === undefined ? [] : m1.deletions;
|
|
const d2 = m2.deletions === undefined ? [] : m2.deletions;
|
|
return isEqual(d1, d2);
|
|
};
|
|
|
|
export const serializeMetadataOnRemote = (x: MetadataOnRemote) => {
|
|
const y = x;
|
|
|
|
if (y["version"] === undefined) {
|
|
y["version"] === DEFAULT_VERSION_FOR_METADATAONREMOTE;
|
|
}
|
|
if (y["generatedWhen"] === undefined) {
|
|
y["generatedWhen"] = Date.now();
|
|
}
|
|
if (y["deletions"] === undefined) {
|
|
y["deletions"] = [];
|
|
}
|
|
|
|
const z = {
|
|
readme: DEFAULT_README_FOR_METADATAONREMOTE,
|
|
d: reverseString(
|
|
base64url.stringify(Buffer.from(JSON.stringify(x), "utf-8"), {
|
|
pad: false,
|
|
})
|
|
),
|
|
};
|
|
|
|
return JSON.stringify(z, null, 2);
|
|
};
|
|
|
|
export const deserializeMetadataOnRemote = (x: string | ArrayBuffer) => {
|
|
let y1 = "";
|
|
if (typeof x === "string") {
|
|
y1 = x;
|
|
} else {
|
|
y1 = new TextDecoder().decode(x);
|
|
}
|
|
|
|
let y2: any;
|
|
try {
|
|
y2 = JSON.parse(y1);
|
|
} catch (e) {
|
|
throw new Error(
|
|
`invalid remote meta data file with first few chars: ${y1.slice(0, 5)}`
|
|
);
|
|
}
|
|
|
|
if (!("readme" in y2 && "d" in y2)) {
|
|
throw new Error(
|
|
'invalid remote meta data file (no "readme" or "d" fields)!'
|
|
);
|
|
}
|
|
|
|
let y3: string;
|
|
try {
|
|
y3 = (
|
|
base64url.parse(reverseString(y2["d"]), {
|
|
out: Buffer.allocUnsafe as any,
|
|
loose: true,
|
|
}) as Buffer
|
|
).toString("utf-8");
|
|
} catch (e) {
|
|
throw new Error('invalid remote meta data file (invalid "d" field)!');
|
|
}
|
|
|
|
let y4: MetadataOnRemote;
|
|
try {
|
|
y4 = JSON.parse(y3) as MetadataOnRemote;
|
|
} catch (e) {
|
|
throw new Error(
|
|
`invalid remote meta data file with \"d\" field with first few chars: ${y3.slice(
|
|
0,
|
|
5
|
|
)}`
|
|
);
|
|
}
|
|
return y4;
|
|
};
|