Skip to content
Snippets Groups Projects
Commit 3099f411 authored by Richard T. Carback III's avatar Richard T. Carback III
Browse files

Merge branch 'project/base32768' into 'release'

Project/base32768

See merge request !2
parents a43b2c14 22c46f9d
No related branches found
No related tags found
2 merge requests!3Release,!2Project/base32768
...@@ -10,19 +10,18 @@ ...@@ -10,19 +10,18 @@
package storage package storage
import ( import (
"encoding/base64"
"os" "os"
"strings" "strings"
"syscall/js" "syscall/js"
// "github.com/Max-Sum/base32768" "github.com/Max-Sum/base32768"
"gitlab.com/elixxir/wasm-utils/exception" "gitlab.com/elixxir/wasm-utils/exception"
"gitlab.com/elixxir/wasm-utils/utils" "gitlab.com/elixxir/wasm-utils/utils"
) )
// localStorageWasmPrefix is prefixed to every keyName saved to local storage by // localStorageWasmPrefix is prefixed to every keyName saved to local storage by
// LocalStorage. It allows the identification and deletion of keys only created // localStorage. It allows the identification and deletion of keys only created
// by this WASM binary while ignoring keys made by other scripts on the same // by this WASM binary while ignoring keys made by other scripts on the same
// page. // page.
// //
...@@ -32,8 +31,22 @@ const localStorageWasmPrefix = "xxdkWasmStorage/" ...@@ -32,8 +31,22 @@ const localStorageWasmPrefix = "xxdkWasmStorage/"
// const localStorageWasmPrefix = "🞮🞮" // const localStorageWasmPrefix = "🞮🞮"
// LocalStorage contains the js.Value representation of localStorage. // LocalStorage defines an interface for setting persistent state in a KV format
type LocalStorage struct { // specifically for web-based implementations.
type LocalStorage interface {
Get(key string) ([]byte, error)
Set(key string, value []byte) error
RemoveItem(keyName string)
Clear() int
ClearPrefix(prefix string) int
Key(n int) (string, error)
Keys() []string
Length() int
LocalStorageUNSAFE() *LocalStorageJS
}
// localStorage contains the js.Value representation of localStorage.
type localStorage struct {
// The Javascript value containing the localStorage object // The Javascript value containing the localStorage object
v *LocalStorageJS v *LocalStorageJS
...@@ -46,49 +59,47 @@ type LocalStorage struct { ...@@ -46,49 +59,47 @@ type LocalStorage struct {
// jsStorage is the global that stores Javascript as window.localStorage. // jsStorage is the global that stores Javascript as window.localStorage.
// //
// Doc: https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage // Doc: https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage
var jsStorage = newLocalStorage(localStorageWasmPrefix) var jsStorage LocalStorage = newLocalStorage(localStorageWasmPrefix)
// newLocalStorage creates a new LocalStorage object with the specified prefix. // newLocalStorage creates a new localStorage object with the specified prefix.
func newLocalStorage(prefix string) *LocalStorage { func newLocalStorage(prefix string) *localStorage {
return &LocalStorage{ return &localStorage{
v: &LocalStorageJS{js.Global().Get("localStorage")}, v: &LocalStorageJS{js.Global().Get("localStorage")},
prefix: prefix, prefix: prefix,
} }
} }
// GetLocalStorage returns Javascript's local storage. // GetLocalStorage returns Javascript's local storage.
func GetLocalStorage() *LocalStorage { func GetLocalStorage() LocalStorage {
return jsStorage return jsStorage
} }
// Get decodes and returns the value from the local storage given its key // Get decodes and returns the value from the local storage given its key
// name. Returns os.ErrNotExist if the key does not exist. // name. Returns os.ErrNotExist if the key does not exist.
func (ls *LocalStorage) Get(keyName string) ([]byte, error) { func (ls *localStorage) Get(keyName string) ([]byte, error) {
value, err := ls.v.GetItem(ls.prefix + keyName) value, err := ls.v.GetItem(ls.prefix + keyName)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// return base32768.SafeEncoding.DecodeString(value) return base32768.SafeEncoding.DecodeString(value)
return base64.StdEncoding.DecodeString(value)
} }
// Set encodes the bytes to a string and adds them to local storage at the // Set encodes the bytes to a string and adds them to local storage at the
// given key name. Returns an error if local storage quota has been reached. // given key name. Returns an error if local storage quota has been reached.
func (ls *LocalStorage) Set(keyName string, keyValue []byte) error { func (ls *localStorage) Set(keyName string, keyValue []byte) error {
// encoded := base32768.SafeEncoding.EncodeToString(keyValue) encoded := base32768.SafeEncoding.EncodeToString(keyValue)
encoded := base64.StdEncoding.EncodeToString(keyValue)
return ls.v.SetItem(ls.prefix+keyName, encoded) return ls.v.SetItem(ls.prefix+keyName, encoded)
} }
// RemoveItem removes a key's value from local storage given its name. If there // RemoveItem removes a key's value from local storage given its name. If there
// is no item with the given key, this function does nothing. // is no item with the given key, this function does nothing.
func (ls *LocalStorage) RemoveItem(keyName string) { func (ls *localStorage) RemoveItem(keyName string) {
ls.v.RemoveItem(ls.prefix + keyName) ls.v.RemoveItem(ls.prefix + keyName)
} }
// Clear clears all the keys in storage. Returns the number of keys cleared. // Clear clears all the keys in storage. Returns the number of keys cleared.
func (ls *LocalStorage) Clear() int { func (ls *localStorage) Clear() int {
// Get a copy of all key names at once // Get a copy of all key names at once
keys := ls.v.KeysPrefix(ls.prefix) keys := ls.v.KeysPrefix(ls.prefix)
...@@ -102,7 +113,7 @@ func (ls *LocalStorage) Clear() int { ...@@ -102,7 +113,7 @@ func (ls *LocalStorage) Clear() int {
// ClearPrefix clears all keys with the given prefix. Returns the number of // ClearPrefix clears all keys with the given prefix. Returns the number of
// keys cleared. // keys cleared.
func (ls *LocalStorage) ClearPrefix(prefix string) int { func (ls *localStorage) ClearPrefix(prefix string) int {
// Get a copy of all key names at once // Get a copy of all key names at once
keys := ls.v.KeysPrefix(ls.prefix + prefix) keys := ls.v.KeysPrefix(ls.prefix + prefix)
...@@ -116,7 +127,7 @@ func (ls *LocalStorage) ClearPrefix(prefix string) int { ...@@ -116,7 +127,7 @@ func (ls *LocalStorage) ClearPrefix(prefix string) int {
// Key returns the name of the nth key in localStorage. Return [os.ErrNotExist] // Key returns the name of the nth key in localStorage. Return [os.ErrNotExist]
// if the key does not exist. The order of keys is not defined. // if the key does not exist. The order of keys is not defined.
func (ls *LocalStorage) Key(n int) (string, error) { func (ls *localStorage) Key(n int) (string, error) {
keyName, err := ls.v.Key(n) keyName, err := ls.v.Key(n)
if err != nil { if err != nil {
return "", err return "", err
...@@ -125,12 +136,12 @@ func (ls *LocalStorage) Key(n int) (string, error) { ...@@ -125,12 +136,12 @@ func (ls *LocalStorage) Key(n int) (string, error) {
} }
// Keys returns a list of all key names in local storage. // Keys returns a list of all key names in local storage.
func (ls *LocalStorage) Keys() []string { func (ls *localStorage) Keys() []string {
return ls.v.KeysPrefix(ls.prefix) return ls.v.KeysPrefix(ls.prefix)
} }
// Length returns the number of keys in localStorage. // Length returns the number of keys in localStorage.
func (ls *LocalStorage) Length() int { func (ls *localStorage) Length() int {
return ls.v.Length() return ls.v.Length()
} }
...@@ -142,7 +153,7 @@ func (ls *LocalStorage) Length() int { ...@@ -142,7 +153,7 @@ func (ls *LocalStorage) Length() int {
// decode/sanitize the inputs/outputs or track entries using the prefix system. // decode/sanitize the inputs/outputs or track entries using the prefix system.
// If using it, make sure all key names and values can be converted to valid // If using it, make sure all key names and values can be converted to valid
// UCS-2 strings. // UCS-2 strings.
func (ls *LocalStorage) LocalStorageUNSAFE() *LocalStorageJS { func (ls *localStorage) LocalStorageUNSAFE() *LocalStorageJS {
return ls.v return ls.v
} }
......
...@@ -21,7 +21,7 @@ import ( ...@@ -21,7 +21,7 @@ import (
// Unit test of GetLocalStorage. // Unit test of GetLocalStorage.
func TestGetLocalStorage(t *testing.T) { func TestGetLocalStorage(t *testing.T) {
expected := &LocalStorage{ expected := &localStorage{
v: &LocalStorageJS{js.Global().Get("localStorage")}, v: &LocalStorageJS{js.Global().Get("localStorage")},
prefix: localStorageWasmPrefix, prefix: localStorageWasmPrefix,
} }
...@@ -29,13 +29,13 @@ func TestGetLocalStorage(t *testing.T) { ...@@ -29,13 +29,13 @@ func TestGetLocalStorage(t *testing.T) {
ls := GetLocalStorage() ls := GetLocalStorage()
if !reflect.DeepEqual(expected, ls) { if !reflect.DeepEqual(expected, ls) {
t.Errorf("Did not receive expected LocalStorage."+ t.Errorf("Did not receive expected localStorage."+
"\nexpected: %+v\nreceived: %+v", expected, ls) "\nexpected: %+v\nreceived: %+v", expected, ls)
} }
} }
// Tests that a value set with LocalStorage.Set and retrieved with // Tests that a value set with localStorage.Set and retrieved with
// LocalStorage.Get matches the original. // localStorage.Get matches the original.
func TestLocalStorage_Get_Set(t *testing.T) { func TestLocalStorage_Get_Set(t *testing.T) {
values := map[string][]byte{ values := map[string][]byte{
"key1": []byte("key value"), "key1": []byte("key value"),
...@@ -64,7 +64,7 @@ func TestLocalStorage_Get_Set(t *testing.T) { ...@@ -64,7 +64,7 @@ func TestLocalStorage_Get_Set(t *testing.T) {
} }
} }
// Tests that LocalStorage.Get returns the error os.ErrNotExist when the key // Tests that localStorage.Get returns the error os.ErrNotExist when the key
// does not exist in storage. // does not exist in storage.
func TestLocalStorage_Get_NotExistError(t *testing.T) { func TestLocalStorage_Get_NotExistError(t *testing.T) {
_, err := jsStorage.Get("someKey") _, err := jsStorage.Get("someKey")
...@@ -74,7 +74,7 @@ func TestLocalStorage_Get_NotExistError(t *testing.T) { ...@@ -74,7 +74,7 @@ func TestLocalStorage_Get_NotExistError(t *testing.T) {
} }
} }
// Tests that LocalStorage.RemoveItem deletes a key from the store and that it // Tests that localStorage.RemoveItem deletes a key from the store and that it
// cannot be retrieved. // cannot be retrieved.
func TestLocalStorage_RemoveItem(t *testing.T) { func TestLocalStorage_RemoveItem(t *testing.T) {
keyName := "key" keyName := "key"
...@@ -89,10 +89,10 @@ func TestLocalStorage_RemoveItem(t *testing.T) { ...@@ -89,10 +89,10 @@ func TestLocalStorage_RemoveItem(t *testing.T) {
} }
} }
// Tests that LocalStorage.Clear deletes all the WASM keys from storage and // Tests that localStorage.Clear deletes all the WASM keys from storage and
// does not remove any others // does not remove any others
func TestLocalStorage_Clear(t *testing.T) { func TestLocalStorage_Clear(t *testing.T) {
jsStorage.v.Clear() jsStorage.LocalStorageUNSAFE().Clear()
const numKeys = 10 const numKeys = 10
var yesPrefix, noPrefix []string var yesPrefix, noPrefix []string
...@@ -106,7 +106,7 @@ func TestLocalStorage_Clear(t *testing.T) { ...@@ -106,7 +106,7 @@ func TestLocalStorage_Clear(t *testing.T) {
} }
} else { } else {
noPrefix = append(noPrefix, keyName) noPrefix = append(noPrefix, keyName)
err := jsStorage.v.SetItem(keyName, strconv.Itoa(i)) err := jsStorage.LocalStorageUNSAFE().SetItem(keyName, strconv.Itoa(i))
if err != nil { if err != nil {
t.Errorf("Failed to set with no prefix %q: %+v", keyName, err) t.Errorf("Failed to set with no prefix %q: %+v", keyName, err)
} }
...@@ -120,7 +120,7 @@ func TestLocalStorage_Clear(t *testing.T) { ...@@ -120,7 +120,7 @@ func TestLocalStorage_Clear(t *testing.T) {
} }
for _, keyName := range noPrefix { for _, keyName := range noPrefix {
if _, err := jsStorage.v.GetItem(keyName); err != nil { if _, err := jsStorage.LocalStorageUNSAFE().GetItem(keyName); err != nil {
t.Errorf("Could not get keyName %q: %+v", keyName, err) t.Errorf("Could not get keyName %q: %+v", keyName, err)
} }
} }
...@@ -132,10 +132,10 @@ func TestLocalStorage_Clear(t *testing.T) { ...@@ -132,10 +132,10 @@ func TestLocalStorage_Clear(t *testing.T) {
} }
} }
// Tests that LocalStorage.ClearPrefix deletes only the keys with the given // Tests that localStorage.ClearPrefix deletes only the keys with the given
// prefix. // prefix.
func TestLocalStorage_ClearPrefix(t *testing.T) { func TestLocalStorage_ClearPrefix(t *testing.T) {
jsStorage.v.Clear() jsStorage.LocalStorageUNSAFE().Clear()
const numKeys = 10 const numKeys = 10
var yesPrefix, noPrefix []string var yesPrefix, noPrefix []string
prefix := "keyNamePrefix/" prefix := "keyNamePrefix/"
...@@ -173,10 +173,10 @@ func TestLocalStorage_ClearPrefix(t *testing.T) { ...@@ -173,10 +173,10 @@ func TestLocalStorage_ClearPrefix(t *testing.T) {
} }
} }
// Tests that LocalStorage.Key return all added keys when looping through all // Tests that localStorage.Key return all added keys when looping through all
// indexes. // indexes.
func TestLocalStorage_Key(t *testing.T) { func TestLocalStorage_Key(t *testing.T) {
jsStorage.v.Clear() jsStorage.LocalStorageUNSAFE().Clear()
values := map[string][]byte{ values := map[string][]byte{
"key1": []byte("key value"), "key1": []byte("key value"),
"key2": {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, "key2": {0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
...@@ -207,10 +207,10 @@ func TestLocalStorage_Key(t *testing.T) { ...@@ -207,10 +207,10 @@ func TestLocalStorage_Key(t *testing.T) {
} }
} }
// Tests that LocalStorage.Key returns the error os.ErrNotExist when the index // Tests that localStorage.Key returns the error os.ErrNotExist when the index
// is greater than or equal to the number of keys. // is greater than or equal to the number of keys.
func TestLocalStorage_Key_NotExistError(t *testing.T) { func TestLocalStorage_Key_NotExistError(t *testing.T) {
jsStorage.v.Clear() jsStorage.LocalStorageUNSAFE().Clear()
if err := jsStorage.Set("key", []byte("value")); err != nil { if err := jsStorage.Set("key", []byte("value")); err != nil {
t.Errorf("Failed to set: %+v", err) t.Errorf("Failed to set: %+v", err)
} }
...@@ -228,10 +228,10 @@ func TestLocalStorage_Key_NotExistError(t *testing.T) { ...@@ -228,10 +228,10 @@ func TestLocalStorage_Key_NotExistError(t *testing.T) {
} }
} }
// Tests that LocalStorage.Length returns the correct Length when adding and // Tests that localStorage.Length returns the correct Length when adding and
// removing various keys. // removing various keys.
func TestLocalStorage_Length(t *testing.T) { func TestLocalStorage_Length(t *testing.T) {
jsStorage.v.Clear() jsStorage.LocalStorageUNSAFE().Clear()
values := map[string][]byte{ values := map[string][]byte{
"key1": []byte("key value"), "key1": []byte("key value"),
"key2": {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, "key2": {0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
...@@ -263,9 +263,9 @@ func TestLocalStorage_Length(t *testing.T) { ...@@ -263,9 +263,9 @@ func TestLocalStorage_Length(t *testing.T) {
} }
} }
// Tests that LocalStorage.Keys return a list that contains all the added keys. // Tests that localStorage.Keys return a list that contains all the added keys.
func TestLocalStorage_Keys(t *testing.T) { func TestLocalStorage_Keys(t *testing.T) {
jsStorage.v.Clear() jsStorage.LocalStorageUNSAFE().Clear()
values := map[string][]byte{ values := map[string][]byte{
"key1": []byte("key value"), "key1": []byte("key value"),
"key2": {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, "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