import { Buffer } from "buffer"; import type { ImageProcessor } from "./processor.worker"; import { f5stego } from './f5stego'; import { settings } from "./stores"; import { decodeCoom3Payload } from "./utils"; const key = Buffer.from("CUNNYCUNNYCUNNY"); const f5inst = new f5stego(key); const inject = async (b: File, links: string[]) => { // TODO: maybe do a lossless crop/embed/concat? if (b.size / 20 < links.join(' ').length) throw "Image too small to embed."; const arr = new Uint8Array(new Uint8Array(await b.arrayBuffer())); const buff = f5inst.embed(arr, new TextEncoder().encode(links.join(' ')), 1); return Buffer.from(buff); }; // unfortunately, because of the way f5 work, we can't determine // if there's an embedded message until we have the complete file // but the way PEE was designed forces us to just try to extract something until it works const has_embed = (b: Uint8Array) => { try { const res = f5inst.extract(b); if (!res) return false; // unsure if (res.length > 1024) // probably garbage, allows for ~20 links from take-me-to.space, should be enough return false; // unsure const str = Buffer.from(res).toString(); if (!str.match(/^[a-zA-Z0-9:/.\-_ ]+$/)) return false; // unsure return str; // sure } catch { return false; // unsure } }; const extract = (b: Uint8Array, ex: string) => { // if we reached here then ex is heckin cute and valid return decodeCoom3Payload(Buffer.from(ex)); }; export default { match: fn => !!fn.match(/\.jpe?g$/), has_embed, extract, inject } as ImageProcessor;