Gutelaunetyp
Gutelaunetyp

Reputation: 1882

Gzip in frontend - equivalent to node-gzip

Let's assume I have the following in NodeJS:

import {
  gzip
} from "node-gzip";

const samlToken = fs.readFileSync(
  "./localDevToken.txt",
  "utf8",
);

const bufferSamlToken = Buffer.from(
  samlToken.replace("\r\n", ""),
  "utf8",
);

const gZipToken = await gzip(bufferSamlToken);
localDevToken = gZipToken
  .toString("base64")
  .replace(/\+/g, "-")
  .replace(/\//g, "_")
  .replace(/=+$/g, "");

And I want to do the same in the frontend. How can I achieve it ?

This is what I've tried using the Pako library from https://github.com/nodeca/pako

function convertSamlToken(input) {
  var samlToken = input.replace("\r\n", "");
  samlToken = pako.gzip(samlToken, {
    to: 'string'
  });
  samlToken = btoa(samlToken)
    .replace(/\+/g, "-")
    .replace(/\//g, "_")
    .replace(/=+$/g, "");

  return samlToken;
}

But the output is different. What is wrong ?

Upvotes: 0

Views: 639

Answers (1)

Wendelin
Wendelin

Reputation: 2401

You are using pako incorrectly, there is no {to: 'string'} option and so the output is a Uint8Array. Here is how your function should look:

function convertSamlToken(input) {
  const samlToken = input.replace("\r\n", "");
  const bytes = pako.gzip(samlToken);

  // Convert Uint8Array to base64 in a safe way
  // See https://stackoverflow.com/a/9458996/7448536
  let binary = "";
  for (let i = 0; i < bytes.byteLength; i++) {
    binary += String.fromCharCode(bytes[i]);
  }

  return btoa(binary)
    .replace(/\+/g, "-")
    .replace(/\//g, "_")
    .replace(/=+$/g, "");
}

I've tested this function on random UTF-8 data and it produces the exact same output except for the 10th byte since that is the OS ID. This is because node-gzip sets it to 0x0A/TOPS-20 and pako uses 0x03/Unix. If that is a problem then just add bytes[9] = 0x0a; after line 3.

Upvotes: 1

Related Questions