How to Store Uint8array in the browser with localstorage using javascript
Asked Answered
S

1

6

I've 16 bytes data I'm storing in Uint8Array. I need to store this data in the browser and must get it in some other class.

so my code looks like this:

const ivBytes = window.crypto.getRandomValues(new Uint8Array(16));
localStorage.setItem("iv",JSON.stringify(ivBytes))
console.log("content of ivBytes:" + ivBytes)

and in other class I try to get data like this but it doesnt work

let array = JSON.parse(localStorage.getItem("iv"))
console.log("the iv value we get is: " + ivBytes)

but when I try to get the content of array, it doesnt give me exactly the content of the ivBytes. the output is as follows: enter image description here

How can I store Uint8array in browser and get it the same way in other class using localStorage? thanks in advance.

String answered 20/9, 2018 at 7:21 Comment(3)
I can see the local storage data you saved and retrieved are the same when I tried in firefox. Please post your outputs as well.Stickybeak
@KrishnadasPC I just did! thanks for the input!String
Or use Base-64 which is specifically designed to store binary data as string in a compact form. The builtin atob and btoa functions unfortunately doesn't suffer here so a custom implementation is needed for this approach.Clancy
G
8

It's tough...

An Uint8Array is just a view over an ArrayBuffer which is binary data held in memory.
So my normal advice would be don't store binary data in localStorage, because localStorage can only store strings and that there are other storage APIs that can handle binary data, such as IndexedDB.



But, here what you want to store seems to only be the randomly generated numbers you got from the crypto API, and since it's a really small ArrayBuffer we're talking about, then...

To stringify your TypedArray so that it can be stored in localStorage, you'll need to extract all the values one by one and move them to an Array, or, if available, simply call Array.from(yourTypedArray) and then stringify this Array:

const typedArray = new Uint8Array(16);
crypto.getRandomValues(typedArray);
const arr = Array.from // if available
  ? Array.from(typedArray) // use Array#from
  : [].map.call(typedArray, (v => v)); // otherwise map()
// now stringify
const str = JSON.stringify(arr);
console.log(str);
// localStorage.setItem('foo', str);

// and to retrieve it...
// const str = localStorage.getItem('foo');
const retrievedArr = JSON.parse(str);
const retrievedTypedArray = new Uint8Array(retrievedArr);
console.log(retrievedTypedArray.byteLength);
Garrettgarrick answered 20/9, 2018 at 8:11 Comment(5)
thank you so much, can you please define what you did with this const array on line 3 and also when we and the str && Json parse (Str) steps? its a bit advanced for me.. thanks so muchString
for arr = part, it's a ternary operator. It first checks that Array.from exists and then use it, or use TypedArray.map otherwise. For str && JSON.parse(... it's actaully useless ;-) (was meant to avoid a possible JSON.parse(null), but that won't throw so I'll remove it.Garrettgarrick
This is less storage-efficient than translating it to hex, isn't it?Sisterinlaw
@Sisterinlaw yes hex should be more storage-efficient, base64 would be even better at this, but if you truly want to be storage-efficient then use IndexedDb to store your data as binary.Garrettgarrick
Just wanted to add - for people who find IndexedDB difficult to use, have a look at the idb-keyval NPM package. It offers an IndexedDB API very similar to localStorage, while still having that sweet IndexedDB binary support.Sardanapalus

© 2022 - 2024 — McMap. All rights reserved.