Giter Club home page Giter Club logo

digitalfortress-tech / localstorage-slim Goto Github PK

View Code? Open in Web Editor NEW
134.0 3.0 12.0 688 KB

An ultra slim localstorage wrapper with optional support for ttl and encryption

Home Page: https://digitalfortress.tech/js/localstorage-with-ttl-time-to-expiry/

License: MIT License

JavaScript 81.70% Makefile 1.61% TypeScript 16.70%
localstorage localstorage-wrapper encryption localstorage-expire cryptojs localstorage-ttl secure-ls encrypt-localstorage localstorage-api

localstorage-slim's Introduction

⚡ localstorage-slim.js ⚡

npm version Build Status code style CDN hits Downloads maintained License Donate


An ultra slim localstorage wrapper with optional support for ttl and encryption

🌟 Highlights 🌟

  • 📦 A localStorage wrapper with 0 DEPENDENCIES in pure JS (Typescript)!
  • 🔥 A super light-weight library ~1kB minzipped
  • ⏰ Supports TTL (i.e. expiry of data in LocalStorage)
  • 🧬 Supports encryption/decryption
  • ⚜️ Store data in multiple formats (numbers, strings, objects, arrays, ...) with checks for cyclic references
  • 🌐 Works everywhere (falls back to an in-memory store when localStorage is unavailable/blocked due to a security policy, for example: within incognito mode)
  • ⚙️ Configurable to use with sessionStorage or even a custom store that implements the Storage interface.
  • 🎀 Framework agnostic!

➕ Install

# you can install typeahead with npm
$ npm install --save localstorage-slim

# Alternatively you can use Yarn
$ yarn add localstorage-slim

Then include the library in your App/Page.

As a module,

// using ES6 modules
import ls from 'localstorage-slim';

// using CommonJS modules
var ls = require('localstorage-slim');

In the browser context,

<!-- Include the library -->
<script src="./node_modules/localstorage-slim/dist/localstorage-slim.js"></script>

<!-- Alternatively, you can use a CDN with jsdelivr -->
<script src="https://cdn.jsdelivr.net/npm/localstorage-slim"></script>
<!-- or with unpkg.com -->
<script src="https://unpkg.com/[email protected]/dist/localstorage-slim.js"></script>

The library will be available as a global object at window.ls

🌱 Usage

Typical usage of localstorage-slim is as follows:

Javascript

/*** Store in localstorage ***/
const value = {
  a: new Date(),
  b: null,
  c: false,
  d: 'superman',
  e: 1234
}

ls.set('key1', value); // value can be anything (object, array, string, number, ...)
ls.get('key1');  // { a: "currentdate", b: "null", c: false, d: 'superman', e: 1234 }

/* with optional ttl in seconds */
ls.set('key2', value, { ttl: 5 });
ls.get('key2');  // within 5 secs => { a: "currentdate", b: "null", c: false, d: 'superman', e: 1234 }
ls.get('key2');  // after 5 secs => null

/* with optional encryption */
ls.set('key3', value, { encrypt: true }); // "mÆk¬�k§m®À½½°¹¿¯..."
ls.get('key3', { decrypt: true }); // { a: "currentdate", b: "null", c: false, d: 'superman', e: 1234 }

LocalStorage-slim provides you a config object (ls.config) which can be modified to suit your needs. The available config parameters are as follows and all of them are completely OPTIONAL

Parameter Description Default
ttl?: number|null Allows you to set a global TTL(time to live) in seconds which will be used for every item stored in the localStorage. Global ttl can be overriden with the ls.set()/ls.get() API. null
encrypt?: boolean Allows you to setup global encryption of the data stored in localStorage Details. It can be overriden with the ls.set()/ls.get() API false
decrypt?: boolean Allows you to decrypt encrypted data stored in localStorage. Used only by the ls.get() API undefined
encrypter?: (data: unknown, secret: string): string The encryption function to be used. A default implementation only obfuscates the value. This function can be overriden with the ls.set()/ls.get() API. Obfuscation
decrypter?: (encryptedString: string, secret: string): unknown A decryption function to be used. A default implementation only performs deobfuscation. This function can be overriden with the ls.set()/ls.get() API. deobfuscation
secret?: unknown Allows you to set a secret key that will be passed to the encrypter/decrypter functions as a parameter. The default implementation accepts a number. Global secret can be overriden with the ls.set()/ls.get() API.
storage?: Storage Allows you to define the Storage to use: localStorage, sessionStorage or even a custom store that implements the Storage interface. By default, localStorage is used and if localStorage is unavailable, then a fallback in-memory store is used localStorage

LocalStorage-slim allows you to encrypt the data that will be stored in your localStorage.

// enable encryption globally
ls.config.encrypt = true;

// optionally use a different secret key
ls.config.secret = 89;

Enabling encryption ensures that the data stored in your localStorage will be unreadable by majority of the users. Be aware of the fact that default implementation is not a true encryption but a mere obfuscation to keep the library light in weight. You can customize the encrypter/decrypter functions to write your own algorithm or to use a secure encryption algorithm like AES, TDES, RC4 or rabbit via CryptoJS to suit your needs.

To use a library like CryptoJS, update the following config options -

// enable encryption
ls.config.encrypt = true;
// set a global secret
ls.config.secret = 'secret-password';

// override encrypter function
ls.config.encrypter = (data: unknown, secret: string): string => 'encrypted string';
// override decrypter function
ls.config.decrypter = (encryptedString: string, secret: string): unknown => 'original data';

As seen, you can easily override the encrypter and decrypter functions with your own implementation of encryption/decryption logic to secure your data. Some examples can be found here.

/* After updating the config, use ls as you normally would */
ls.set(...); // internally calls ls.config.encrypter(...);
ls.get(...); // internally calls ls.config.decrypter(...);

/* you can encrypt a particular LS item by providing a different secret as well. */
ls.set("key", "value", { secret: 'xyz'});
ls.get("key", { secret: 'xyz'});

⚠️ Note: It is recommended that you do not save user passwords or credit card details in LocalStorage (whether they be encrypted or not).


⚙️ Using sessionStorage/custom store

By configuring the storage config option, you can easily use another storage instead of the default localStorage.

/* use sessionStorage */
ls.config.storage = sessionStorage;

/* OR a custom store/storage via an IIFE */
ls.config.storage = (() => {
  const store = {
    // your storage's implementation...
  };

  return store;
})()

Note: If you use custom storage, it must implement the Storage interface.


✨ API

The Api is very similar to that of the native LocalStorage API.


Sets an item in the LocalStorage. It can accept 3 arguments

  1. key: string [Required] - The key with which the value should be associated
  2. value: string|Date|Number|Object|Boolean|Null [Required] - The value to be stored
  3. config: Config [Optional] - This argument accepts the same properties (except storage property) as the global config object. Defaults to an empty object

Returns false if there was an error, else returns undefined.

const res = ls.set('key', 'value');
console.log('Value =>', res); // returns undefined if successful or false if there was a problem

// with ttl
ls.config.ttl = 3;      // global ttl set to 3 seconds
ls.set('key', 'value'); // value expires after 3s
ls.set('key', 'value', { ttl: 5 }); // value expires after 5s (overrides global ttl)

// with encryption (to encrypt particular fields)
ls.set('key', 'value', { encrypt: true });

Retrieves the Data associated with the key stored in the LocalStorage. It accepts 2 arguments -

  1. key: string [Required] - The key with which the value is associated
  2. config: Config [Optional] - This argument accepts the same properties (except storage property) as the global config object. Defaults to an empty object

If the passed key does not exist, it returns null.

const value = ls.get('key');
console.log('Value =>', value); // value retrieved from LS

// if ttl was set
ls.get('key'); // returns the value if ttl has not expired, else returns null

// when a particular field is encrypted, and it needs decryption
ls.get('key', { decrypt: true });

// get decrypted value when global encryption is enabled
ls.config.encrypt = true;
ls.get('key'); // returns decrypted value

Flushes expired items in the localStorage. This function is called once automatically on initialization. It can accept an optional argument force: boolean that defaults to false. If set to true, it force-flushes all items including the ones that haven't expired yet. Note that doing flush(true) only affects items that were due to expire sometime in future (i.e. they had a TTL set on them). To remove data, whether or not it has a TTL, use remove() or clear().

// removes all expired data (i.e. ttl has expired)
ls.flush();
// removes all data that has a ttl (i.e. even if the ttl has not expired yet)
ls.flush(true);

Accepts the key: string as an argument to remove the data associated with it.

// delete data from the LS
ls.remove('key'); // returns undefined if successful, false otherwise

🔸 5.ls.clear()

Clears the entire localstorage linked to the current domain.

// removes all data from the LS
ls.clear(); // returns undefined if successful, false otherwise

💠 Screenshot


❕ Gotchas

When localStorage is not supported by a browser, we fallback to MemoryStorage. For websites that don't do full page loads, like SPA's, this is a perfect fallback. But for MPA's, though page crashes get prevented, data is not persisted between page loads.


🧑‍💻 Contribute

Interested in contributing features and fixes?

Read more on contributing.

📝 Changelog

See the Changelog

📄 License

MIT © Digital Fortress

localstorage-slim's People

Contributors

cdauth avatar lc-soft avatar niketpathak avatar res260 avatar rostow avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

localstorage-slim's Issues

Uncaught SyntaxError: Unexpected token e in JSON at position 0

If the value is a string i am getting this error on ls.get using the package as browser context
Uncaught SyntaxError: Unexpected token e in JSON at position 0

Browser: Version 96.0.4664.93 (Official Build) (64-bit)
OS: windows 10

NB: I am using the value as a string with double quote

Support for Server Side Rendering?

A small question, does localstorage-slim support Server Side Rendering with NextJS? It works fine in development but I'm not sure about production.

Callback on timeout

Could you add a feature to allow for a callback function to be passed into the set() method, and this callback would be fired when the ttl is reached?

Thanks
Justin

Setting secret key from env variable

I am trying to set the secret key from environment variable but I cannot do that.

// env
REACT_APP_LSKEY=123456789101112

//global setting
let key = Number(process.env.REACT_APP_LSKEY); //converting string to number
ls.config.encrypt = true;
ls.config.secret = key;

NOTE: I tried using secret key as string, still same issue hence I converted it into NUMBER.

//setting data in local storage
ls.set("foo", { bar: "baz" });

//getting data from local storage
let key = Number(process.env.REACT_APP_LSKEY);
let lsData= ls.get("foo", { secret: key });
console.log(lsData) // o/p: (empty)

Screenshot_9

If I set ls.config.secret = 50 then it is working fine but I want my secret key from env variable. Please help. Thank You.

Exceptions thrown when used in a third-party iframe with third-party cookies disabled

What happened?

I'm using the library in a cross-origin iframe while having third-party cookies disabled in Chrome.

In this situation, attempting to access the localStorage global variable results in the following exception: Uncaught DOMException: Failed to read the 'localStorage' property from 'Window': Access is denied for this document.

This library does not catch this exception. The fallback to memory store is never reached, because that is only enabled on an exception during localStorage.getItem(), which is never reached. Furthermore, isInit is set to true before the exception is thrown, causing storage to be undefined, resulting in subsequent exceptions such as Cannot read properties of undefined (reading 'getItem').

Affected version

Latest

Reproduction URL

https://codepen.io/niketpathak/pen/WNMKzoJ

How to reproduce?

Can be reproduced with the default Codepen while having third-party cookies disabled in Chrome. Typing something into the text field will raise errors in the browser console, and the value never makes it into the storage.

Browsers

Chrome

Relevant log output

No response

Additional context

No response

A SyntaxError occurs during JSON parsing if the input parameter hasn't been stringified.

What happened?

When a key's value pre-exists as a string or has been previously set using the localStorage.setItem() method in local storage, a JSON parsing error arises upon invoking the ls.get() method.

Affected version

Latest

Reproduction URL

https://jsfiddle.net/j3qhtv28/5/

How to reproduce?

  1. Go to the provided reproduction link
  2. Click on 'Console'
  3. See the error

Browsers

Chrome

Relevant log output

Uncaught SyntaxError: Unexpected token 'd', "d" is not valid JSON
    at JSON.parse (<anonymous>)
    at <anonymous>:1:6

Additional context

I observed that this issue was addressed in the commit. Do you plan to merge it into the main branch soon? If not, I'm willing to submit another request to expedite the fix, as it's crucial to resolve this promptly. This is a common scenario many front-end developers might encounter when launching a new app on the default port, especially if there's a residual "token" value in the local storage not set by the ls Object. Addressing this will prevent potential confusion.

Support sessionStorage?

Not a bug, a feature request.

Expected Behavior

It'd be nice to be able to use sessionStorage instead of localStorage in certain cases. Obviously localStorage should remain the default, but some way to configure this module would be useful.

Current Behavior

localStorage is always used.

Possible Solution

ls.config.storage = sessionStorage

ls.get('...') // use as normal, but will now read/write from `sessionStorage` instead

The nice thing about this is it'd allow for setting storage to other values with the same interface too - which could be useful for testing or for writing a low-level wrapper for localStorage or sessionStorage.

Context

Not having this means we get lots of nice features for using localStorage like better type-safety, rich object storage, and encyrption (also ttl/expiry, although obviously that's less of a concern for sessionStorage), but we have to use the raw API or find a similar library for sessionStorage. Given the tiny change that would be needed in this library to support sessionStorage, it seems worth doing.

The supportLS function returns incorrect value for browsers that do not support localstorage

Expected Behavior

The supportLS function should return false when a browser doesn't support localstorage.

Current Behavior

The supportLS function always return true, as the hasLS = true assignment happens after the try/catch block, which overwrites the value of hasLS when it is false.

Steps to Reproduce (for bugs)

Not provided, but bug is obvious by looking at the code.

SessionStorage is ignored when used in localoptions object.

What happened?

If one sets the storage option as sessionStorage in localoptions object it will be ignored and localStorage will be used instead.

Example:

ls.set("testItem", "123", {storage: sessionStorage});

It will save testItem in localStorage and not in sessionStorage. It can be observed on browser dev tools.

Also, when retrieving data, the library also ignores the storage option:

ls.get("testItem", {storage: sessionStorage});

It will retrieve the object not only in sessionStorage but also in localStorage. Not sure if the last behavior is intended though.

I provided a codepen project that shows both local and session behavior.

Affected version

v2.7.0

Reproduction URL

https://codepen.io/gurgelff/pen/OJdoyxr

How to reproduce?

1 - Go to the provided codepen link
2 - Write some value in input field, like 123 (the code is already set to use sessionStorage in localconfig object).
3 - Notice that "Get from sessionStorage (native API):" returns nothing from SessionStorage.
4 - Notice also that both session and local storage using the library return some values, even though the saved value is only present in session, and not in localStorage.

Browsers

Firefox, Brave

Relevant log output

No response

Additional context

On Codepen, when using global config the issue seems resolved. But a localconfig scope is something useful that needs to be solved.

There is also an issue when used in Angular, that even with a global config it still doesn't use sessionStorage, but that is a matter for another issue.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.