Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Persistent JavaScript objects and web forms using Web Storage.
Features
{...}
) to
localStorage
/ sessionStorage
.get()
/set()
API for direct (even nested) access, hiding the need
to convert from/to JSON.localStorage
/ sessionStorage
(deferred writing appears to be 10-15 times faster) and remote backends.Overview:
Requirements:
Download the latest persisto.js or include directly from CDN: or UNPKG:
<script src="//cdn.jsdelivr.net/npm/persisto@1/dist/persisto.min.js"></script>
then instantiate a PersistentObject
:
var store = PersistentObject("mySettings", {
defaults: {
theme: "default"
}
});
store
now contains the data that was stored in localStorage.mySettings
if
present. Otherwise, store
is initialized to the default values that we
passed with the .defaults
option.
We can access data using set
, get
, remove
, reset
:
store.get("theme"); // -> 'default'
store.set("owner", {name: "joe", age: 42});
store.set("owner.role", "manager");
store.get("owner.age"); // -> 42
store.remove("owner.age");
// -> store now holds {theme: "default", owner: {name: "joe", role: "manager"}}
Every modifying operation triggers a deferred commit, so that shortly afterwards
the data is serialized to JSON and written to localStorage.mySettings
.
More:
Form input elements can be synchronized with a PersistentObject
by using two
API calls.
Example:
// Maintain client's preferences and define some defaults:
var settingsStore = PersistentObject("mySettings", {
defaults: {
nickname: "anonymous",
theme: "default"
}
});
// Initialize form elements with current data
settingsStore.writeToForm("#settingsForm");
// Allow users to edit and save settings:
$("#settingsForm").submit(function(event){
// ... maybe some validations here ...
settingsStore.readFromForm(this);
event.preventDefault();
});
Supported elements are <input>
(type text, checkbox, or radio), <textarea>
,
and <select>
(single and multivalue).
By convention, the html form must use element names that match the data properties.
<form id="settingsForm" action="">
<label>Nickname:<input name="nickname" type="text" value="" /></label><br>
<label>Theme:
<fieldset>
<label> <input name="theme" type="radio" value="default" /> Standard </label><br>
<label> <input name="theme" type="radio" value="light" /> Light </label><br>
<label> <input name="theme" type="radio" value="dark" /> Dark </label>
</fieldset>
</label>
<button type="Submit">Submit</button>
</form>
Note also that only fields are synchronized, that already existed in the storage
data. Use the addNew
option if all form fields should be evaluated and create
new properties in the store object:
settingsStore.readFromForm(this, {
addNew: true
});
Any PersistentObject
instance is stored as one monolythic JSON string.
Persisto deferres and collates these updates, but modifying a single
property of a large data object still comes with some overhead.
Splitting data into several PersistentObject
s may remedy the problem.
But if your data model is more like a table with hundredth's of rows, a
responsive database backend may be a better choice.
Asynchronous operations bear the risk of potential conflicts. There is currently no builtin support for resolving those.
Arrays are only a special form of plain JavaScript objects, so we can store and access them as top level type like this:
var store = PersistentObject("mySettings", {
defaults: ["a", "b", "c"]
});
store.get("[0]"); // 'a'
store.set("[1]", "b2");
However if we use child properties, it is even easier:
var store = PersistentObject("mySettings", {
defaults: {
values: ["a", "b", "c"]
}
});
store.get("values")[0]; // 'a'
store.get("values[0]"); // 'a'
S.each(store.get("values"), function(idx, obj) { ... });
store.set("values[1]", "b2");
In general, performance costs of set()
and get()
calls should be
neglectable, compared to the resulting synchronization times, but in some cases
direct access of the internal data object may be preferred.
In this case modifications must be signalled by a call to setDirty()
.
store._data.owner = { name: "joe", age: 42 };
store._data.owner.role = "manager";
delete store._data.owner.age;
store.setDirty(); // schedule a commit
By default, changed values will be commited to webStorage after a small delay
(see .commitDelay
option). This allows to collate sequences of multiple changes
into one single write command.
However there are situations, where this is not desirable:
store.set("foo", "bar");
// Page reload would prevent the delayed commit from happen, so we force
// synchronization:
store.commit();
location.reload();
An alternative would be to disable delay completely by setting commitDelay: 0
.
Optionally, we may specify an endpoint URL that is used to synchronize the data with a web server using HTTP REST requests (GET and PUT):
var store = PersistentObject("mySettings", {
remote: "persist/settings"
});
$.when(
// Page must be loaded
$.ready,
// PersistentObject must be pulled
store.ready
).done(function(){
// Page was loaded and and store has pulled the data from the remote endpoint...
initPage();
}).fail(function(){
console.error("Error loading persistent objects", arguments);
});
The following options are available:
int
,
default: 500
milliseconds0
to force synchronous mode.
int
,
default: 1
object
,
default: {}
int
,
default: 3000
millisecondsint
,
default: 30000
millisecondsint
,
default: 5000
milliseconds0
to force synchronous mode.
string
,
default: null
object
,
default: window.localStorage
Following a list of available methods:
{addNew: false, coerce: true, trim: true}
.
{}
.
Events may be handled by passing a handler callback option:
store = PersistentObject("mySettings", {
[...]
change: function(hint){
alert("Store " + this + " was changed. Reason: " + hint);
}
});
Note: Events are not yet finally implemented and subject to change!
This is what we have so far:
{
change: $.noop,
commit: $.noop,
conflict: $.noop,
error: $.noop,
pull: $.noop,
push: $.noop,
ready: PROMISE
update: $.noop
}
1.2.0 / 2019-09-07
persisto = require('persisto')
).
FAQs
Persist JavaScript objects to localStorage and remote servers.
The npm package persisto receives a total of 15 weekly downloads. As such, persisto popularity was classified as not popular.
We found that persisto demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.