Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How safe is lz-string? #130

Open
caracal7 opened this issue Mar 23, 2019 · 3 comments
Open

How safe is lz-string? #130

caracal7 opened this issue Mar 23, 2019 · 3 comments

Comments

@caracal7
Copy link

if I use server-side something like

let obj = lzString.decompressFromUint8Array( new Uint8Array( userData );

can it broke on random or broken data?

@JobLeonard
Copy link
Collaborator

You need to be more clear about "safe" and "breaking" here, as well as which version you are using. But TL;DR: no, not that we know of, unless you count breaking due to running out of memory on large objects. That is not exactly something that LZString can be held responsible for though.

For example, the 1.34 version throws every substring into one large dictionary. So if you throw a large enough string at it (I'm talking millions of characters), it will start to stutter simply because JS objects aren't made to hold millions of keys.

The 2.0RC version builds a trie of small objects instead. You risk running out of memory, but each individual node has at most 65k chars (because that is the number of char codes we can get out of UTF16) smaller so shouldn't have this issue.

If you use the 2.0 unsafe version, well, it says unsafe for a reason. It is trivial to build a string that freezes that one (not crash, just freeze), namely one that iterates over all 65k charcodes in sequence.

@caracal7
Copy link
Author

I interesting whats happened if I will try to decompress random Uint8Array.
Can random data broke lzString.decompressFromUint8Array execution?

@JobLeonard
Copy link
Collaborator

It will most likely return an empty string as it bails out, and in the unlikely worst case give you a garbage string instead. Hypothetically a null can also be returned, if you return try to decompress an empty array.

decompressFromUint8Array just treats pairs of 8-bit values from the Uint8Array as 16-bit UTF16 char codes, converts the array to a string that way, and then calls the regular decompression algorithm after that:

  //decompress from uint8array (UCS-2 big endian format)
  decompressFromUint8Array:function (compressed) {
    if (compressed===null || compressed===undefined){
        return LZString.decompress(compressed);
    } else {
        var buf=new Array(compressed.length/2); // 2 bytes per character
        for (var i=0, TotalLen=buf.length; i<TotalLen; i++) {
          buf[i]=compressed[i*2]*256+compressed[i*2+1];
        }

        var result = [];
        buf.forEach(function (c) {
          result.push(f(c));
        });
        return LZString.decompress(result.join(''));

    }
  decompress: function (compressed) {
    if (compressed == null) return "";
    if (compressed == "") return null;
    return LZString._decompress(compressed.length, 32768, function(index) { return compressed.charCodeAt(index); });
  },

Try it for yourself in your console:

randomString = (() => {let s = ''; for(let i = 0; i < 100; i++) s += String.fromCharCode(Math.random()*0x10000|0); return s})();
LZString.decompress(randomString); // Assumes you loaded LZString

This will almost always return ""

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants