Skip to content
Snippets Groups Projects
Commit 48ea7af6 authored by Jono Wenger's avatar Jono Wenger
Browse files

Add prefix to all keynames saved to local storage by xxdk wasm and add...

Add prefix to all keynames saved to local storage by xxdk wasm and add function to delete local storage keys with prefixes
parent eb4eb7e5
No related branches found
No related tags found
1 merge request!18XX-4272 / Purge
......@@ -12,11 +12,19 @@ package utils
import (
"encoding/base64"
"os"
"strings"
"syscall/js"
)
// localStorageWasmPrefix is prefixed to every keyName saved to local storage by
// LocalStorage. It allows the identifications and deletion of keys only created
// by this WASM binary while ignoring keys made by other scripts on the same
// page.
const localStorageWasmPrefix = "xxdkWasmStorage/"
// LocalStorage contains the js.Value representation of localStorage.
type LocalStorage struct {
// The Javascript value containing the localStorage object
v js.Value
}
......@@ -41,8 +49,8 @@ func GetLocalStorage() *LocalStorage {
// https://html.spec.whatwg.org/multipage/webstorage.html#dom-storage-getitem-dev
// - Documentation:
// https://developer.mozilla.org/en-US/docs/Web/API/Storage/getItem
func (s *LocalStorage) GetItem(keyName string) ([]byte, error) {
keyValue := s.v.Call("getItem", keyName)
func (ls *LocalStorage) GetItem(keyName string) ([]byte, error) {
keyValue := ls.getItem(localStorageWasmPrefix + keyName)
if keyValue.IsNull() {
return nil, os.ErrNotExist
}
......@@ -62,9 +70,9 @@ func (s *LocalStorage) GetItem(keyName string) ([]byte, error) {
// https://html.spec.whatwg.org/multipage/webstorage.html#dom-storage-setitem-dev
// - Documentation:
// https://developer.mozilla.org/en-US/docs/Web/API/Storage/setItem
func (s *LocalStorage) SetItem(keyName string, keyValue []byte) {
func (ls *LocalStorage) SetItem(keyName string, keyValue []byte) {
encodedKeyValue := base64.StdEncoding.EncodeToString(keyValue)
s.v.Call("setItem", keyName, encodedKeyValue)
ls.setItem(localStorageWasmPrefix+keyName, encodedKeyValue)
}
// RemoveItem removes a key's value from local storage given its name. If there
......@@ -75,8 +83,8 @@ func (s *LocalStorage) SetItem(keyName string, keyValue []byte) {
// https://html.spec.whatwg.org/multipage/webstorage.html#dom-storage-removeitem-dev
// - Documentation:
// https://developer.mozilla.org/en-US/docs/Web/API/Storage/removeItem
func (s *LocalStorage) RemoveItem(keyName string) {
s.v.Call("removeItem", keyName)
func (ls *LocalStorage) RemoveItem(keyName string) {
ls.removeItem(localStorageWasmPrefix + keyName)
}
// Clear clears all the keys in storage. Underneath, it calls
......@@ -86,8 +94,35 @@ func (s *LocalStorage) RemoveItem(keyName string) {
// https://html.spec.whatwg.org/multipage/webstorage.html#dom-storage-clear-dev
// - Documentation:
// https://developer.mozilla.org/en-US/docs/Web/API/Storage/clear
func (s *LocalStorage) Clear() {
s.v.Call("clear")
func (ls *LocalStorage) Clear() {
ls.clear()
}
// ClearWASM clears all the keys in storage created by WASM.
// TODO: add test.
func (ls *LocalStorage) ClearWASM() {
for i := 0; i < ls.Length(); i++ {
v := ls.key(i)
if !v.IsNull() && strings.HasPrefix(v.String(), localStorageWasmPrefix) {
ls.RemoveItem(strings.TrimPrefix(v.String(), localStorageWasmPrefix))
// Decrement to account for reduced length from removed key
i--
}
}
}
// ClearPrefix clears all keys with the given prefix.
func (ls *LocalStorage) ClearPrefix(prefix string) {
for i := 0; i < ls.Length(); i++ {
keyName, err := ls.Key(i)
if err == nil && strings.HasPrefix(keyName, prefix) {
ls.RemoveItem(keyName)
// Decrement to account for reduced length from removed key
i--
}
}
}
// Key returns the name of the nth key in localStorage. Return os.ErrNotExist if
......@@ -99,13 +134,13 @@ func (s *LocalStorage) Clear() {
// https://html.spec.whatwg.org/multipage/webstorage.html#dom-storage-key-dev
// - Documentation:
// https://developer.mozilla.org/en-US/docs/Web/API/Storage/key
func (s *LocalStorage) Key(n int) (string, error) {
keyName := s.v.Call("key", n)
func (ls *LocalStorage) Key(n int) (string, error) {
keyName := ls.key(n)
if keyName.IsNull() {
return "", os.ErrNotExist
}
return keyName.String(), nil
return strings.TrimPrefix(keyName.String(), localStorageWasmPrefix), nil
}
// Length returns the number of keys in localStorage. Underneath, it accesses
......@@ -115,6 +150,14 @@ func (s *LocalStorage) Key(n int) (string, error) {
// https://html.spec.whatwg.org/multipage/webstorage.html#dom-storage-key-dev
// - Documentation:
// https://developer.mozilla.org/en-US/docs/Web/API/Storage/length
func (s *LocalStorage) Length() int {
return s.v.Get("length").Int()
func (ls *LocalStorage) Length() int {
return ls.length().Int()
}
// Wrappers for Javascript Storage methods and properties.
func (ls *LocalStorage) getItem(keyName string) js.Value { return ls.v.Call("getItem", keyName) }
func (ls *LocalStorage) setItem(keyName, keyValue string) { ls.v.Call("setItem", keyName, keyValue) }
func (ls *LocalStorage) removeItem(keyName string) { ls.v.Call("removeItem", keyName) }
func (ls *LocalStorage) clear() { ls.v.Call("clear") }
func (ls *LocalStorage) key(n int) js.Value { return ls.v.Call("key", n) }
func (ls *LocalStorage) length() js.Value { return ls.v.Get("length") }
......@@ -12,6 +12,7 @@ package utils
import (
"bytes"
"github.com/pkg/errors"
"math/rand"
"os"
"strconv"
"testing"
......@@ -84,10 +85,77 @@ func TestLocalStorage_Clear(t *testing.T) {
}
}
// Tests that LocalStorage.ClearWASM deletes all the WASM keys from storage and
// does not remove any others
func TestLocalStorage_ClearWASM(t *testing.T) {
jsStorage.clear()
prng := rand.New(rand.NewSource(11))
var yesPrefix, noPrefix []string
for i := 0; i < 10; i++ {
keyName := "keyNum" + strconv.Itoa(i)
if prng.Intn(2) == 0 {
yesPrefix = append(yesPrefix, keyName)
jsStorage.SetItem(keyName, []byte(strconv.Itoa(i)))
} else {
noPrefix = append(noPrefix, keyName)
jsStorage.setItem(keyName, strconv.Itoa(i))
}
}
jsStorage.ClearWASM()
for _, keyName := range noPrefix {
if v := jsStorage.getItem(keyName); v.IsNull() {
t.Errorf("Could not get keyName %q.", keyName)
}
}
for _, keyName := range yesPrefix {
keyValue, err := jsStorage.GetItem(keyName)
if err == nil || !errors.Is(err, os.ErrNotExist) {
t.Errorf("Found keyName %q: %q", keyName, keyValue)
}
}
}
// Tests that LocalStorage.ClearPrefix deletes only the keys with the given
// prefix.
func TestLocalStorage_ClearPrefix(t *testing.T) {
jsStorage.clear()
prng := rand.New(rand.NewSource(11))
var yesPrefix, noPrefix []string
prefix := "keyNamePrefix/"
for i := 0; i < 10; i++ {
keyName := "keyNum" + strconv.Itoa(i)
if prng.Intn(2) == 0 {
keyName = prefix + keyName
yesPrefix = append(yesPrefix, keyName)
} else {
noPrefix = append(noPrefix, keyName)
}
jsStorage.SetItem(keyName, []byte(strconv.Itoa(i)))
}
jsStorage.ClearPrefix(prefix)
for _, keyName := range noPrefix {
if _, err := jsStorage.GetItem(keyName); err != nil {
t.Errorf("Could not get keyName %q: %+v", keyName, err)
}
}
for _, keyName := range yesPrefix {
keyValue, err := jsStorage.GetItem(keyName)
if err == nil || !errors.Is(err, os.ErrNotExist) {
t.Errorf("Found keyName %q: %q", keyName, keyValue)
}
}
}
// Tests that LocalStorage.Key return all added keys when looping through all
// indexes.
func TestLocalStorage_Key(t *testing.T) {
jsStorage.v.Call("clear")
jsStorage.clear()
values := map[string][]byte{
"key1": []byte("key value"),
"key2": {0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
......@@ -119,7 +187,7 @@ func TestLocalStorage_Key(t *testing.T) {
// Tests that LocalStorage.Key returns the error os.ErrNotExist when the index
// is greater than or equal to the number of keys.
func TestLocalStorage_Key_NotExistError(t *testing.T) {
jsStorage.v.Call("clear")
jsStorage.clear()
jsStorage.SetItem("key", []byte("value"))
_, err := jsStorage.Key(1)
......@@ -138,7 +206,7 @@ func TestLocalStorage_Key_NotExistError(t *testing.T) {
// Tests that LocalStorage.Length returns the correct Length when adding and
// removing various keys.
func TestLocalStorage_Length(t *testing.T) {
jsStorage.v.Call("clear")
jsStorage.clear()
values := map[string][]byte{
"key1": []byte("key value"),
"key2": {0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment