Can embed any file in a PNG/WebM/GIF/JPEG and upload it to a third-party host through 4chan
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

48 lines
1.6 KiB

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;