DEV Community

Cover image for How I Built a Zero-Server Archive Extractor for MDM-Locked Laptops with WebAssembly
UNPK
UNPK

Posted on

How I Built a Zero-Server Archive Extractor for MDM-Locked Laptops with WebAssembly

A few weeks ago, I needed to open a .tar.zst database dump on a company laptop.

Since the laptop was locked down by corporate MDM policies, I couldn't install 7-Zip or WinRAR without submitting an IT request for admin rights.

I didn't want to upload a private database archive to a random online converter, so I checked if the browser could handle decompression locally.

I ended up building unpk.app, a browser tool that unpacks archives 100% client-side using WebAssembly. Here is how the technical architecture works and the memory issues I had to solve.


1. Offloading Work to Web Workers

Decompressing a 500MB .rar or .7z archive takes heavy CPU work. Running it on V8's main UI thread freezes the tab.

To keep the interface responsive, all decompression logic runs inside Web Workers using comlink:

// utils/extractor.worker.ts
import * as Comlink from "comlink";

const MAX_MEMORY_SIZE = 300 * 1024 * 1024; // 300 MB

export class ExtractionWorker {
  async extractTarStreaming(file: File, compressionType?: "gzip" | "zstd") {
    let inputStream = file.stream();

    if (compressionType === "zstd") {
      inputStream = inputStream.pipeThrough(createZstdDecompressionStream());
    }

    return parseTarStream(inputStream);
  }
}

Comlink.expose(ExtractionWorker);
Enter fullscreen mode Exit fullscreen mode

2. Streaming Decompression with WebAssembly

For formats like .tar.gz and .zst, loading the entire file into memory array buffers causes browser crashes on large files.

Instead, I used zstd-wasm-decoder with a custom TransformStream. It pipes binary chunks directly from File.stream() through WASM memory buffers without loading the full archive into RAM:

import { ZstdDecompressionStream } from "zstd-wasm-decoder";

export function createZstdDecompressionStream(): TransformStream<Uint8Array, Uint8Array> {
  return new ZstdDecompressionStream() as any;
}
Enter fullscreen mode Exit fullscreen mode

For .rar and .7z files, I compiled libarchive and node-unrar-js C/C++ libraries into WebAssembly modules.


3. Handling Memory Limits with OPFS

The main bottleneck was handling large extracted outputs. Saving extracted files as blob URLs in RAM works for small archives, but extracting a multi-gigabyte ISO image triggers Chrome out-of-memory crashes.

To fix this, I used the Origin Private File System (OPFS) API. Worker threads stream extracted chunks straight to local disk storage instead of keeping them in JavaScript RAM.


Live Demo

The tool runs locally on locked corporate laptops, Chromebooks, and mobile browsers without uploading any data to a server.

You can try it out at unpk.app. It supports RAR, ZST, TAR.ZST, and ISO archives.

Top comments (0)