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.
smartobject
Advanced tools
A Smart Object Class that helps you with creating IPSO Smart Objects in your JavaScript applications
A Smart Object Class that helps you with creating IPSO Smart Objects in your JavaScript applications
smartobject is a Smart Object Class that helps you with creating IPSO Smart Objects in your JavaScript applications. If you like to use the IPSO data model in your projects or products, you can use smartobject as the base class to abstract your hardware, sensor modules, or gadgets into plugins (node.js packages) for users convenience. Here is an example of hardware abstraction with mraa on Linkit Smart 7688 in our wiki. In addition, this module is isomorphic and you can use it at server-side as well to generate the smart objects.
IPSO defines a hierarchical data model to describe real-world gadgets, such as temperature sensors and light controllers.
oid
) defined by IPSO, e.g., 3303 for the Temperature Sensor Object. Here is the list of oids.oid
is like a namespace to manage all the same kind of IPSO Object Instances.[Note]
$ npm install smartobject --save
Here is a quick example to show you how to create your Smart Object with only few steps:
Step 1: Import the SmartObject Class and create an instance from it
var SmartObject = require('smartobject');
var so = new SmartObject(); // so can hold many Object Instances in it
Step 2: Initialize a temperature sensor in your smart object so
(ref: code templates)
so.init(
'temperature', // 'temperature' is the IPSO-defined Object Identifier (oid, 3303).
0, // 0 is the unique Object Instance Id (iid) assigned by you.
{ // This object contains all Resources (attributes) this sensor has.
sensorValue: 31, // 'sensorValue' is the IPSO-defined Resource Id (rid, 5700)
units : 'C' // 'units' is the IPSO-defined Resource Id (rid, 5701)
}
);
Step 3: Initialize more Object Instances. Finally, we have 3 temperature sensors, 1 magnetometer, and 4 digital inputs in our so
// Init more temperature sensors (each with an unique iid)
so.init('temperature', 1, {
sensorValue: 28,
units : 'C'
});
so.init('temperature', 2, {
sensorValue: 72.6,
units : 'F'
});
// Init other gadgets
so.init('magnetometer', 0, {
xValue: 18,
yValue: 21,
zValue: 231
});
so.init('dIn', 0, { dInState: 1 });
so.init('dIn', 1, { dInState: 0 });
so.init('dIn', 6, { dInState: 0 });
so.init('dIn', 7, {
// if dInState should be read from by certain operation
dInState: {
read: function (cb) {
var hal = this.parent.hal; // see SmartObject constructor
hal.digitalPin0.read(function (err, val) {
cb(null, val);
});
}
}
});
The great benefit of using smartobject in your application is that you almost need not to tackle the allocation of Resources by yourself. It provides a scheme to help you with management of reading/writing your hardware or executing a procedure on the machine. All you have to do is to plan and define your Resources well, and then use smartobject methods to do your jobs. You can use smartobject to abstract your hardware, sensor modules, or gadgets into plugins (node.js packages).
Imagine that you have to read the temperature value from a sensor with one-wire interface:
Please refer to Resources Planning Tutorial for more details. It will show you how to initialize your Resources and how to abstract your hardware with IPSO Resources as well. In addition, here are some code templates for your convenience to create smart objects.
[Note]
new SmartObject()
, init()
, read()
, and write()
. It's not that complicated as it looks like.Exposed by require('smartobject')
.
Create an instance of SmartObject class. This document will use so
to indicate this kind of instance.
A so
can hold many IPSO Object Instances in it. The so
itself has an accessible but un-enumerable boolean property 'ipsoOnly'
to define if this so
only accepts IPSO-defined oid
and rid
. Default value for so.ipsoOnly
is false
. You can set it to true
in the setup
function.
If so.ipsoOnly == true
, then the given oid
must be an IPSO-defined Object Id, iid
must be a number, and all keys within resrcs
object must be IPSO-defined Resource Ids, or so.init()
will throw Errors.
Arguments:
hal
(Object): Optional. A component or controller of the hardware abstraction layer. It will be assigned to this.hal
at creation of a so
. Noted that so.hal
is accessible but un-enumerable.setup
(Function): Optional. A setup function allows you to do some initializing work, for example, setting gpio direction. In the setup function, this
will be bound to the so
itself, thus you can use this.hal
to access your hardware.Returns:
Examples:
hal
.var SmartObject = require('smartobject');
var so = new SmartObject();
so
accept only IPSO-defined identifiers.var SmartObject = require('smartobject');
var so = new SmartObject(function () {
this.ipsoOnly = true;
});
mraa
. This is a typical example at client-side (machine).var m = require('mraa');
var SmartObject = require('smartobject');
var myHardware = {
led1: new m.Gpio(44),
led2: new m.Gpio(44),
onOffSwitch: new m.Gpio(45),
foo: 'bar'
};
var so = new SmartObject(myHardware, function () {
var hal = this.hal;
// hardware initialization
hal.led1.dir(m.DIR_OUT);
hal.led2.dir(m.DIR_OUT);
hal.onOffSwitch.dir(m.DIR_IN);
hal.foo = 'initialized';
this.ipsoOnly = true;
});
Create and initialize an Object Instance in so
, where oid
is the IPSO Object Id to indicate what kind of your gadget is, iid
is the Object Instance Id, and resrcs
is an object that wraps up all the Resources.
init()
against an existing Object Instance will firstly wipe out all its Resources and inner _state
and then put the new Resources into it. Thus, it is better to initialize your Instance only once throughout your code._state
is a special Resource that is an accesible but un-enumerable protected member in the Object Instance. It is an object where you can maintain some private information or inner state within the Object Instance. We will talk about it more later.Arguments:
oid
(String | Number): IPSO Object Id, for example, 'temperature'
or 3303
. so
will internally turn the id into its string version, say 'temperature'
, as the key if given with a numeric id.iid
(String | Number): Object Instance Id. It would be nice to use numbers, i.e., 0
, 1
, 2
to strictly meet the IPSO definition. But strings are also accepted, e.g., 'sen01'
, 'sen02'
, 'sen03'
, it is just like a handle to help you distinguish different Instances that share the same Object class.resrcs
(Object): IPSO Resources, which is an object with rid-value pairs to describe the Resources. Each key in resrcs
is a Resource Id that can be a string or a number. And each value can be a primitive, an data object, or an object with specific methods, i.e. read(), write(), exec(). The Resources Planning Tutorial will give you some hints. You can have your private information or inner states within an object assigned to the resrc._state
property, for example resrc = { _state: { foo: 'bar' } }
.setup
(Function): Optional. A setup function allows you to set some things up, for example, setting some flags or states for inner use. In this function, this
will be bound to the Object Instance itself, thus you can use this._state
to access your inner state. Further more, you can use this.parent
to get the so
that owns this Object Instance, and use this.parent.hal
to access your hardware.Returns:
objInst
, the initialized Object Instance.Examples:
var so = new SmartObject();
so.init('temperature', 0, {
sensorValue: 31,
units : 'C'
});
so.init('temperature', 1, {
_state: { // inner state
foo: 'bar'
},
sensorValue: 75,
units : 'F'
});
so.init(3303, 18, {
sensorValue: 301,
units : 'K'
}, function () {
// this._state is an empty object by default
// you can attach things to it
this._state.foo = 'bar';
});
// Dumped data of the so will look like:
// (inner _state will not be dumped)
/*
{
temperature: {
'0': {
sensorValue: 31,
units : 'C'
},
'1': {
sensorValue: 75,
units : 'F'
},
'18': {
sensorValue: 301,
units : 'K'
}
}
}
*/
mraa
.var m = require('mraa');
var SmartObject = require('smartobject');
var so = new SmartObject({
led: new m.Gpio(44),
onOffSwitch: new m.Gpio(45)
}, function () {
var hal = this.hal;
// hardware initialization
hal.led.dir(m.DIR_OUT);
hal.onOffSwitch.dir(m.DIR_IN);
this.ipsoOnly = true;
});
// led
so.init('lightCtrl', 0 , {
_state: { // protected resource to maintain inner states
readCounts: 0, // to record times of read
writeCounts: 0 // to record times of written
},
onOff: {
read: function (cb) {
// 'this' is bound to Object Instance itself
// this.parent === so
var hal = this.parent.hal;
var ledState = hal.led.read();
this._state.readCounts += 1; // inner record
cb(null, ledState);
},
write: function (val, cb) {
var hal = this.parent.hal;
hal.led.write(val);
this._state.writeCounts += 1; // inner record
cb(null, hal.led.read());
}
}
});
Remove an Object Instance in so
, where oid
is the IPSO Object Id to indicate what kind of your gadget is, iid
is the Object Instance Id.
Arguments:
oid
(String | Number): IPSO Object Id, for example, 'temperature'
or 3303
. so
will internally turn the id into its string version, say 'temperature'
, as the key if given with a numeric id.iid
(String | Number): Object Instance Id. It would be nice to use numbers, i.e., 0
, 1
, 2
to strictly meet the IPSO definition. But strings are also accepted, e.g., 'sen01'
, 'sen02'
, 'sen03'
, it is just like a handle to help you distinguish different Instances that share the same Object class.Returns:
true
if remove successfully, else returns false
if the Object Instance does not exist.Examples:
so.remove('temperature', 0)
Returns the list of Objects and Object Instances with their identifiers. If an Id is an IPSO-defined one, it will be returned as a number. If you're using LWM2M interface, you may need this method to generate the Object List when registering to a server.
Arguments:
Returns:
{ oid: 3301, iid: [ 0, 1, 2, 3 ] }
.Examples:
var so = new SmartObject();
so.init('temperature', 0, {
sensorValue: 31,
units : 'C'
});
so.init('temperature', 18, {
sensorValue: 301,
units : 'K'
});
so.init('illuminance', 0, {
sensorValue: 128.6
});
so.initResrc('presence', 6, {
dInState: 0
});
so.initResrc('myGadget', 'gad72', {
myResource: 'hello_world'
});
so.objectList();
/*
[
{ oid: 3303, iid: [ 0, 18 ] },
{ oid: 3301, iid: [ 0 ] },
{ oid: 3302, iid: [ 6 ] },
{ oid: 'myGadget', iid: [ 'gad72' ] } // not IPSO-defined
]
*/
To see if so
has the specified Object, Object Instance, or Resource.
Arguments:
oid
(String | Number): Object Id of the target.iid
(String | Number): Object Instance Id of the target.rid
(String | Number): Resource Id of the target.Returns:
true
if target exists, otherwise false
.Examples:
// Checks if so has the 'humidity' Object
so.has('humidity'); // true
// Checks if so has the 'foo' Object Instance with iid = 0
so.has('foo', 0); // false
// Checks if so has the 'sensorValue' Resource in temperature sensor 8
so.has('temperature', 8, 'sensorValue'); // true
Synchronously get the specified Resource.
get()
method is usually used to get the raw Resource which may be an object with read/write/exec callbacks. If you like to read the exact value of a Resource, you should use the asynchronous read()
method. Since reading something from somewhere may require some special and asynchronous operations, such as reading data from a wire, and reading from a database.get()
to get the stored value of a Resource on the server is no problem.Arguments:
oid
(String | Number): Object Id of the target.iid
(String | Number): Object Instance Id of the target.rid
(String | Number): Resource Id of the target.Returns:
undefined
if Resource does not exist.Examples:
so.get('temperature', 2, 'sensorValue'); // 26.4
// If the Resource is an object with read/write/exec method(s)
so.get('temperature', 1, 'sensorValue');
/*
{
read: function (cb) { ... }
}
*/
// If you do like to read the exact value from the temperature sensor, please use read()
so.read('temperature', 1, 'sensorValue', function (err, data) {
if (!err)
console.log(data); // 18.4
});
Synchronously set a value to the specified Resource.
set()
method is usually used to initialize a Resource, but not to write a value to a Resource. You should use the asynchronous write()
method if you like to write a value to the Resource. Since writing something to somewhere may require some special and asynchronous operations, such as writing data to a wire, and writing data to a database.set()
to store the value of a Resource on the server is no problem. For example, when your request of reading a Resource from a remote machine has responded back, you can use set()
to store that Resource value on the server.Arguments:
oid
(String | Number): Object Id of the target.iid
(String | Number): Object Instance Id of the target.rid
(String | Number): Resource Id of the target.value
(Primitives | Object): Resource data or an object with read/write/exec method(s). This method will throw if value
is given with a function.Returns:
true
if set successfully, else returns false
if the Object Instance does not exist (Resource cannot be set).Examples:
so.set('dIn', 0, 'dInState', 1); // true
so.set('dOut', 1, 'dOutState', 0); // true
so.set('dOut', 2, 'dOutState', {
read: function (cb) {
gpioA3.read(function (state) { // assume gpioA3 is a handle to your hardware
cb(null, state);
});
}
}); // true
so.set('dOut', 2, 'dOutState', function (cb) {
gpioA3.read(function (state) {
cb(null, state);
});
}); // throw Error, value cannot be a function
Asynchronously read the specified Resource value.
Arguments:
oid
(String | Number): Object Id of the target.iid
(String | Number): Object Instance Id of the target.rid
(String | Number): Resource Id of the target.opt
(Object): An option used to read Resources in restrict mode, default is { restrict: false }
. If it is given with { restrict: true }
, this method will follow the access control specification defined by IPSO. This option may be set to true
to respond to a remote read request (access from outside world should be under control).callback
(Function): function (err, data) { ... }
. Will be called when reading is done or any error occurs, where data
is the Resource value. (When an error occurs, so
will pass you a string like '_notfound_'
with data
, you can use it as a hint to choose a status code to respond back to the requester.)err | data | Description |
---|---|---|
Error object | '_notfound_' | Resource not found. |
Error object | '_unreadable_' | Resource is unreadable. |
Error object | '_exec_' | Resource is unreadable (Because it is an executable Resource). |
null | Depends | Resource is successfully read. |
Returns:
Examples:
so.read('temperature', 1, 'sensorValue', function (err, data) {
if (!err)
console.log(data); // 18.4
});
so.read('actuation', 0, 'dimmer', function (err, data) {
if (!err)
console.log(data); // 62
});
so.read('illuminance', 1, 'maxMeaValue', function (err, data) {
if (err) {
console.log(err); // Error: 'Resource is unreadable.'
console.log(data); // '_unreadable_'
}
});
so.read('accelerometer', 2, 'minRangeValue', function (err, data) {
if (err) {
console.log(err); // Error: 'Resource not found.'
console.log(data); // '_notfound_'
}
});
so.read('barometer', 6, 'resetMinMaxMeaValues', function (err, data) {
if (err) {
console.log(err); // Error: 'Resource is unreadable.'
console.log(data); // '_exec_'
}
});
Asynchronously write a value to the specified Resource.
Arguments:
oid
(String | Number): Object Id of the target.iid
(String | Number): Object Instance Id of the target.rid
(String | Number): Resource Id of the target.value
(Depends): The value to write to the specified Resource.opt
(Object): An option used to write Resources in restrict mode. Default is { restrict: false }
if not given.callback
(Function): function (err, data) { ... }
. Will be called when writing is done or any error occurs, where data
is the Resource value written. (When an error occurs, so
will pass you a string like '_notfound_'
with data
, you can use it as a hint to choose a status code to respond back to the requester.)err | data | Description |
---|---|---|
Error object | '_notfound_' | Resource not found. |
Error object | '_unwritable_' | Resource is unwritable. |
Error object | '_exec_' | Resource is unwritable (Because it is an executable Resource). |
null | Depends | Resource is successfully write. |
Returns:
Examples:
so.write('actuation', 0, 'onOff', 1, function (err, data) {
if (!err)
console.log(data); // 1
});
so.write('temperature', 1, 'sensorValue', 26, function (err, data) {
if (err) {
console.log(err); // Error: 'Resource is unwritable.'
console.log(data); // _unwritable_
}
});
so.write('presence', 3, 'busyToClearDelay', function (err, data) {
if (err) {
console.log(err); // Error: 'Resource not found.'
console.log(data); // '_notfound_'
}
});
so.write('barometer', 6, 'resetMinMaxMeaValues', function (err, data) {
if (err) {
console.log(err); // Error: 'Resource is unwritable.'
console.log(data); // '_exec_'
}
});
Execute the specified Resource. The executable Resource is a procedure you've defined, for example, blinking a led for N times when the Resource is invoked.
Arguments:
oid
(String | Number): Object Id of the target.iid
(String | Number): Object Instance Id of the target.rid
(String | Number): Resource Id of the target.args
(Array): The parameters required by the procedure.callback
(Function): function (err, data) { ... }
. Will be called when execution is performed or any error occurs, where data
is anything your procedure like to return back. For example, when a blinking led procedure starts, you may like to return an object { status: 'ok', led: 6, times: 10 }
to the callback to tell something about this execution.err | data | Description |
---|---|---|
Error object | '_notfound_' | Resource not found. |
Error object | '_unexecutable_' | Resource is unexecutable. |
Error object | '_badarg_' | Input arguments is not an array. |
null | Depends | Resource is successfully executed, data depends on your will. |
Returns:
Examples:
// Assume we have initialized an Object Instance like this:
so.init('foo_object', 0, {
foo: 60,
bar: 'hello',
blink: {
exec: function (args, cb) {
var ledPin = args[0],
times = args[1];
myHardwareController.blinkLed(ledPin, times, function (err) {
if (err)
cb(err);
else
cb(null, { status: 'ok', led: ledPin, times: times });
});
}
}
});
// Execute the blink Resource on it
so.exec('foo_object', 0, 'blink', [ 3, 10 ], function (err, data) {
if (!err)
console.log(data); // { status: 'ok', led: 3, times: 10 }
});
// Execute a Resource that doesn't exist
so.exec('foo_object', 0, 'show', [], function (err, data) {
if (err) {
console.log(err); // Error: 'Resource not found.'
console.log(data); // '_notfound_'
}
});
Asynchronously dump data from so
. This method uses the asynchronous read()
under the hood.
oid
, iid
, and a callback
to dump data of an Object Instance.
dump(oid, iid, function (err, data) {})
dump(oid, iid, { restrict: true }, function (err, data) {})
oid
and a callback
to dump data of an Object.
dump(oid, function (err, data) {})
dump(oid, { restrict: true }, function (err, data) {})
callback
to dump data of whole smart object.
dump(function (err, data) {})
dump({ restrict: true }, function (err, data) {})
Arguments:
oid
(String | Number): Object Id of the target.iid
(String | Number): Object Instance Id of the target.opt
(Object): An option used to dump Resources in restrict mode. Default is { restrict: false }
if not given.callback
(Function): function (err, data) { }
.Returns:
Examples:
// Dump Object Instance: 'temperature' sensor with iid = 18
so.dump('temperature', 18, function (err, data) {
if (!err)
console.log(data);
/*
{
sensorValue: 301,
units : 'K'
}
*/
});
// Dump Object: all 'temperature' sensors
so.dump('temperature', function (err, data) {
if (!err)
console.log(data);
/*
{
'0': {
sensorValue: 31,
units : 'C'
},
'1': {
sensorValue: 75,
units : 'F'
},
'18': {
sensorValue: 301,
units : 'K'
}
}
*/
});
// Dump whole smart object
so.dump(function (err, data) {
if (!err)
console.log(data);
/*
{
temperature: {
'0': {
sensorValue: 31,
units : 'C'
},
'1': {
sensorValue: 75,
units : 'F'
},
'18': {
sensorValue: 301,
units : 'K'
}
}
}
*/
});
Synchronously dump data from so
. This method uses the synchronous get()
under the hood. This method should only be used at server-side (since at server-side, all stored Objects are simply data pieces).
oid
and iid
to dump data of an Object Instance.oid
to dump data of an Object.Arguments:
oid
(String | Number): Object Id of the target.iid
(String | Number): Object Instance Id of the target.Returns:
Examples:
// Dump Object: all 'temperature' sensors
so.dumpSync('temperature');
/*
{
'0': {
sensorValue: 31,
units : 'C'
},
'1': {
sensorValue: {
read: '_read_' // a read method will be dumped to a string '_read_'
},
units : 'F'
},
'18': {
sensorValue: 301,
units : 'K'
}
}
*/
// Assume we are at server-side.
var myDevice = myController.find('0x12AE3B4D77886644'); // find the device
var so = myDevice.getSmartObject(); // get the smart object on the device
// Dump Object Instance: 'temperature' sensor with iid = 18
so.dumpSync('temperature', 18);
/*
{
sensorValue: 301,
units : 'K'
}
*/
// Dump Object: all 'temperature' sensors
so.dumpSync('temperature');
/*
{
'0': {
sensorValue: 31,
units : 'C'
},
'1': {
sensorValue: 75,
units : 'F'
},
'18': {
sensorValue: 301,
units : 'K'
}
}
*/
// Dump whole smart object
so.dumpSync();
/*
{
temperature: {
'0': {
sensorValue: 31,
units : 'C'
},
'1': {
sensorValue: 75,
units : 'F'
},
'18': {
sensorValue: 301,
units : 'K'
}
},
...
}
*/
To see if a Resource is readable.
Arguments:
oid
(String | Number): Object Id of the target.iid
(String | Number): Object Instance Id of the target.rid
(String | Number): Resource Id of the target.Returns:
true
if the Resource is readable, otherwise false
.Examples:
so.isReadable('temperature', 8, 'sensorValue'); // true
To see if a Resource is writable.
Arguments:
oid
(String | Number): Object Id of the target.iid
(String | Number): Object Instance Id of the target.rid
(String | Number): Resource Id of the target.Returns:
true
if the Resource is writable, otherwise false
.Examples:
so.isWritable('temperature', 8, 'sensorValue'); // false
To see if a Resource is executable.
Arguments:
oid
(String | Number): Object Id of the target.iid
(String | Number): Object Instance Id of the target.rid
(String | Number): Resource Id of the target.Returns:
true
if the Resource is executable, otherwise false
.Examples:
so.isExecutable('temperature', 8, 'sensorValue'); // false
FAQs
A Smart Object Class that helps you with creating IPSO Smart Objects in your JavaScript applications
We found that smartobject demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 2 open source maintainers 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.