85b31e9528
Co-authored-by: ISMAIL MASSERAN <topaz@Mac.dlinkrouter.local> Co-authored-by: ISMAIL MASSERAN <topaz@ISMAILs-Macbook.local> Reviewed-on: #1
68 lines
1.7 KiB
TypeScript
68 lines
1.7 KiB
TypeScript
const DEFAULT_QR_SECRET = "qms-branch-qr-v1";
|
|
|
|
function getQrSecret() {
|
|
return process.env.QR_TOKEN_SECRET || DEFAULT_QR_SECRET;
|
|
}
|
|
|
|
function toBase64Url(bytes: Uint8Array) {
|
|
let binary = "";
|
|
bytes.forEach((byte) => {
|
|
binary += String.fromCharCode(byte);
|
|
});
|
|
return btoa(binary)
|
|
.replace(/\+/g, "-")
|
|
.replace(/\//g, "_")
|
|
.replace(/=+$/g, "");
|
|
}
|
|
|
|
function fromBase64Url(token: string) {
|
|
const padded = token.replace(/-/g, "+").replace(/_/g, "/");
|
|
const padLength = (4 - (padded.length % 4)) % 4;
|
|
const base64 = padded + "=".repeat(padLength);
|
|
const binary = atob(base64);
|
|
const bytes = new Uint8Array(binary.length);
|
|
for (let i = 0; i < binary.length; i += 1) {
|
|
bytes[i] = binary.charCodeAt(i);
|
|
}
|
|
return bytes;
|
|
}
|
|
|
|
function xorBytes(bytes: Uint8Array, secret: string) {
|
|
const key = new TextEncoder().encode(secret);
|
|
return bytes.map((byte, index) => byte ^ key[index % key.length]);
|
|
}
|
|
|
|
export type BranchQrPayload = {
|
|
tenantCode: string;
|
|
branchId: number;
|
|
};
|
|
|
|
export function encodeBranchQrToken(
|
|
tenantCode: string,
|
|
branchId: number,
|
|
secret = getQrSecret()
|
|
) {
|
|
const plain = `v1:${tenantCode.trim().toUpperCase()}:${Number(branchId)}`;
|
|
const plainBytes = new TextEncoder().encode(plain);
|
|
return toBase64Url(xorBytes(plainBytes, secret));
|
|
}
|
|
|
|
export function decodeBranchQrToken(
|
|
token: string,
|
|
secret = getQrSecret()
|
|
): BranchQrPayload | null {
|
|
try {
|
|
const plain = new TextDecoder().decode(
|
|
xorBytes(fromBase64Url(token), secret)
|
|
);
|
|
const match = /^v1:([^:]+):(\d+)$/.exec(plain);
|
|
if (!match) return null;
|
|
return {
|
|
tenantCode: match[1],
|
|
branchId: Number(match[2]),
|
|
};
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|