mirror of
https://github.com/kccleoc/seedpgp-web.git
synced 2026-03-06 17:37:51 +08:00
fix(parser): handle raw SeedPGP payloads without prefix
Modifies the frame parsing logic to accommodate Base45-encoded SeedPGP payloads that are missing the 'SEEDPGP1:' prefix and CRC. This scenario occurs with certain QR code generators, such as some modes on Krux devices. - `frameParse` now detects when the prefix is missing and treats the entire input as a raw Base45 payload. - A `rawPayload` flag is added to the `ParsedSeedPgpFrame` type to signal this case. - `frameDecodeToPgpBytes` now bypasses the CRC check when this flag is true, allowing the decryption to proceed. - This resolves a bug where valid encrypted payloads were being rejected due to a missing frame structure.
This commit is contained in:
@@ -53,28 +53,37 @@ export function frameEncode(pgpBinary: Uint8Array): string {
|
||||
|
||||
export function frameParse(text: string): ParsedSeedPgpFrame {
|
||||
const s = text.trim().replace(/^["']|["']$/g, "").replace(/[\n\r\t]/g, "");
|
||||
if (!s.startsWith("SEEDPGP1:")) throw new Error("Missing SEEDPGP1: prefix");
|
||||
if (s.startsWith("SEEDPGP1:")) {
|
||||
const parts = s.split(":");
|
||||
if (parts.length < 4) {
|
||||
throw new Error("Invalid frame format (need at least 4 colon-separated parts)");
|
||||
}
|
||||
const prefix = parts[0];
|
||||
const frame = parts[1];
|
||||
const crc16 = parts[2].toUpperCase();
|
||||
const b45 = parts.slice(3).join(":");
|
||||
|
||||
const parts = s.split(":");
|
||||
if (parts.length < 4) {
|
||||
throw new Error("Invalid frame format (need at least 4 colon-separated parts)");
|
||||
if (prefix !== "SEEDPGP1") throw new Error("Invalid prefix");
|
||||
if (frame !== "0") throw new Error("Multipart frames not supported in this prototype");
|
||||
if (!/^[0-9A-F]{4}$/.test(crc16)) throw new Error("Invalid CRC16 format (must be 4 hex chars)");
|
||||
|
||||
return { kind: "single", crc16, b45 };
|
||||
} else {
|
||||
// It's not a full frame. Assume the ENTIRE string is the base45 payload.
|
||||
// We will have to skip the CRC check.
|
||||
return { kind: "single", crc16: "0000", b45: s, rawPayload: true };
|
||||
}
|
||||
|
||||
const prefix = parts[0];
|
||||
const frame = parts[1];
|
||||
const crc16 = parts[2].toUpperCase();
|
||||
const b45 = parts.slice(3).join(":");
|
||||
|
||||
if (prefix !== "SEEDPGP1") throw new Error("Invalid prefix");
|
||||
if (frame !== "0") throw new Error("Multipart frames not supported in this prototype");
|
||||
if (!/^[0-9A-F]{4}$/.test(crc16)) throw new Error("Invalid CRC16 format (must be 4 hex chars)");
|
||||
|
||||
return { kind: "single", crc16, b45 };
|
||||
}
|
||||
|
||||
export function frameDecodeToPgpBytes(frameText: string): Uint8Array {
|
||||
const f = frameParse(frameText);
|
||||
const pgp = base45Decode(f.b45);
|
||||
|
||||
// If it's a raw payload, we cannot and do not verify the CRC.
|
||||
if (f.rawPayload) {
|
||||
return pgp;
|
||||
}
|
||||
|
||||
const crc = crc16CcittFalse(pgp);
|
||||
if (crc !== f.crc16) {
|
||||
throw new Error(`CRC16 mismatch! Expected: ${f.crc16}, Got: ${crc}. QR scan may be corrupted.`);
|
||||
|
||||
@@ -11,6 +11,7 @@ export type ParsedSeedPgpFrame = {
|
||||
kind: "single";
|
||||
crc16: string;
|
||||
b45: string;
|
||||
rawPayload?: boolean;
|
||||
};
|
||||
|
||||
// Krux KEF types
|
||||
|
||||
Reference in New Issue
Block a user