| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114 |
- // box-nestjs-monorepo/libs/common/src/utils/image-lib.ts
- // You can extend this array with more headers if needed.
- export const ENCRYPTED_HEADERS: Uint8Array[] = [
- // Header from the Dart code: [0x88, 0xA8, 0x30, 0xCB, 0x10, 0x76]
- new Uint8Array([0x88, 0xa8, 0x30, 0xcb, 0x10, 0x76]),
- // Example: add more if their system uses multiple variants.
- // new Uint8Array([0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC]),
- ];
- /**
- * Pick a header index:
- * - if headerIndex is provided, use that
- * - otherwise pick one randomly from ENCRYPTED_HEADERS
- */
- function pickHeaderIndex(headerIndex?: number): number {
- if (
- typeof headerIndex === 'number' &&
- headerIndex >= 0 &&
- headerIndex < ENCRYPTED_HEADERS.length
- ) {
- return headerIndex;
- }
- if (ENCRYPTED_HEADERS.length === 0) {
- throw new Error(
- 'ENCRYPTED_HEADERS is empty; configure at least one header.',
- );
- }
- return Math.floor(Math.random() * ENCRYPTED_HEADERS.length);
- }
- /**
- * Encrypt image bytes by prefixing a chosen header.
- *
- * This is *obfuscation*, not real cryptography.
- *
- * @param imageBytes - original image content as Uint8Array
- * @param headerIndex - optional index into ENCRYPTED_HEADERS; if omitted, random header is used
- */
- export function encryptImageWithHeader(
- imageBytes: Uint8Array,
- headerIndex?: number,
- ): Uint8Array {
- if (!imageBytes || imageBytes.length === 0) {
- return imageBytes;
- }
- const idx = pickHeaderIndex(headerIndex);
- const header = ENCRYPTED_HEADERS[idx];
- // Allocate new array: [HEADER][IMAGE]
- const result = new Uint8Array(header.length + imageBytes.length);
- // Copy header
- result.set(header, 0);
- // Copy original image bytes after header
- result.set(imageBytes, header.length);
- return result;
- }
- /**
- * Try to detect which header (if any) the given bytes start with.
- *
- * @returns { headerIndex: number; header: Uint8Array } if matched, otherwise null.
- */
- function detectHeaderPrefix(
- bytes: Uint8Array,
- ): { headerIndex: number; header: Uint8Array } | null {
- if (!bytes || bytes.length === 0) return null;
- for (let i = 0; i < ENCRYPTED_HEADERS.length; i++) {
- const header = ENCRYPTED_HEADERS[i];
- if (bytes.length < header.length) continue;
- let match = true;
- for (let j = 0; j < header.length; j++) {
- if (bytes[j] !== header[j]) {
- match = false;
- break;
- }
- }
- if (match) {
- return { headerIndex: i, header };
- }
- }
- return null;
- }
- /**
- * Decrypt image bytes by stripping a known header if present.
- *
- * If no known header is found, the original bytes are returned unchanged.
- *
- * @param encryptedBytes - stored bytes (possibly with header)
- */
- export function decryptImageWithHeader(encryptedBytes: Uint8Array): Uint8Array {
- if (!encryptedBytes || encryptedBytes.length === 0) {
- return encryptedBytes;
- }
- const detected = detectHeaderPrefix(encryptedBytes);
- if (!detected) {
- // Not "encrypted" with our header scheme → return as-is.
- return encryptedBytes;
- }
- const { header } = detected;
- const start = header.length;
- // Slice bytes after the header, preserving the original image content.
- return encryptedBytes.subarray(start);
- }
|