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.
bem-node [![Build Status](https://travis-ci.org/bem-node/bem-node.png?branch=master)](https://travis-ci.org/bem-node/bem-node) ===
Single-page web application with node.js, BEM
Use bem-node with our project-stub
The main principle of bem-node is presenting page layout as bemjson (russian ref) object. Block templates apply on bemjson tree to produce complete layout with data. Then bemjson is serialising to html.
https://github.com/delfrrr/bem-node-hello-world/commits/demo
####js
Browser code
####common.js
Common (client/server) code
####priv.js
Private (server) code
####server.js
Builded node.js application (server)
####bemdecl.js
Application declaration
// application declaration example
exports.blocks = [
// bem-node part
{block: 'i-console'}, //colorful console log
{block: 'i-enb'}, //output static files
{block: 'i-bem-node'}, //bem-node api
// pages
{block: 'hello-world'}
];
####deps.js
Block dependencies
//block dependencies example
({
shouldDeps: [
{block: 'depended-block'}
],
mustdDeps: [
{block: 'must-dependeded-block'} //should be included before target block
]
})
Block constructor. It creates i-bem (russian guide, english guide) blocks with static and dom declarations, and bh (russian ref) templates.
Returns link on BEM block static methods and properties.
Creates block generator.
Inherits block declaration from base block.
Adds static methods and properties (i-bem).
BN.addDecl('example').staticProp({
someProp: 'a',
someMethod: function(){
return this.someProp + 'b';
}
}).done();
BN('example').someMethod(); //returns 'ab'
BN.addDecl('example').staticProp({
someMethod: function(){
return this.__base() + 'c';
}
}).done();
BN('example').someMethod(); //returns 'abc'
this
– inherits i-bem
this.__instances
– array of block dom instances (only for client side code)
this.__lastInstance
– last created block instances (only for client side code)
Adds methods and properties for block dom instance (i-bem.dom)
Creates bh templates (see bh) for block, elements and it's modifications.
/**
* Example of block with element
*/
BN.addDecl('example').blockTemplate(function (ctx) {
//block template
ctx.content([
{elem: 'item', url: 'item-1', text: 'item 1'},
{elem: 'item', url: 'item-1', text: 'item 2'}
]);
}).elemTemplate({
'item': function (ctx) {
//element template
var json = ctx.json();
ctx.content({
block: 'b-link',
url: json.url,
content: json.text
});
}
});
ctx
is instances of bh.Ctx
decl
can return promise (see Vow.promise). If promise is fulfilled, other block templates will be applied. If promise is rejected, block will be removed.
BN.addDecl('example').dataTemplate(function(ctx){
return BN('some-ajax-block').get().then(function(data){
ctx.param('data', data) //set data to block property
return Vow.fulfill();
}).blockTemplate(function(ctx){
ctx.content(ctx.json().data.text); //ouput data
});
})
ctx
is instance of bh.Ctx
Creates i-bem block from generator and adds bh matchers. All blocks will be created automatically on next event loop. Use this methods only to force block creation.
Page block are controllers for pages.
/**
* Hello world page
*/
BN.addDecl('hello-world', 'page', {
route: /^\/$/
}).staticProp({
init: function () {
return this.out('hello world');
}
});
All pages are extended from i-page
block.
BN.addDecl('usual-page', 'page', {
route: /^\/$/ //page route
}).staticProp({
init: function (matchers) {
//...
return this.out(/*bemjson*/);
},
update: function(matchers, prevPath, newPath) {
//...
return Vow.fulfill();
},
destruct: function() {
//...
return Vow.fulfill();
}
});
route
is {RegExp} or {String} which can be matched to request url.
init
is called when page route match to request url. Init should return fulfilled promise. Otherwise page returns error.
update
is called when page should be updated on client (new url matched with the same route). By default update
calls init
destruct
is called on client side before current page is going to be replaced with other page.
Page blocks are extended from i-page block.
Ajax blocks are kind of models (or data blocks). They can provide data to view blocks with common interface between client and server.
On server: get → _request (server implementation) → REST API
On client: get → _request (client implementation) → ajax request → _request (server implementation) → REST API
// example-ajax-block.common.js
BN.addDecl('example-ajax-block', 'ajax', {
apiHost: 'http://api.example.com/v1/' //json api provider
});
//get data from http://api.example.com/v1/some/resource?count=10
BN('example-ajax-block').get('some/resource', {
params: {
count: 10
}
}).then(function(result){
console.log(result);
});
Ajax blocks are inheriting from 'i-api-request' block. You can extend block methods to provide additional input params and output data processing:
/**
* Fetching data from node.js doc api
*/
BN.addDecl('node-doc-api', 'ajax', {
apiHost: 'http://nodejs.org/api/'
}).staticProp({
/**
* Add .json to resources
* @overide
*/
get: function (resource) {
resource = resource + '.json';
return this.__base(resource);
}
});
By default ajax blocks have only GET
method. To provide POST
PUTand
DELETE` you should declare them:
// ajax block supporting post
BN.addDecl('example-ajax-block', 'ajax', {
apiHost: 'http://api.example.com/v1/' //json api provider
}).staticProp({
post: function (resource, options) {
return this._request('post', resource, options)
}
});
You are able to extend ajax block to fetch data from any source (like database).
Bem-node includes some visual blocks from bem-bl library
Power of BEM is ability to override almost any method, template or style of block:
//change content of b-page by adding block b-head
BN.addDecl('b-page').blockTemplate(function (ctx) {
ctx.content([
{block: 'b-head'},
ctx.content()
], true);
});
This is a base block for page blocks. But some of the static methods can be called from other blocks (issue).
Setting page <title/>
on client and on server
Setting page description meta tag on client and on server
<meta/>
<meta/>
Setting page <meta/>
tags
Adds to page <head/>
any content
This method is called when page route match to url. Redefine this method to output your page layout. See example in page blocks and i-page.out method. By default page outputs empty string.
This method is called when page should be updated on client (new url matched with the same route). By default it calls `this.init(). You can setup selective block updates by redefining this method.
/**
* Node docs page
*/
BN.addDecl('node-doc', 'page', {
route: /^\/node-doc\/?(.+)?$/
}).staticProp({
//calls on page render
init: function (matches) {
var section = this._getSectionName(matches);
this.setTitle(section + ' – node.js api'); //set page title
//output page layout
return this.out({
block: 'node-doc',
content: [
{elem: 'toc', content: {block: 'node-doc-toc'}},
{elem: 'section', content: {block: 'node-doc-section', section: section}}
]
});
},
_getSectionName: function (matches) {
return matches[1] || 'documentation'; //set section from url
},
//update page on client
update: function (matches) {
var section = this._getSectionName(matches);
return BN('node-doc-section').updateSection(section);
}
});
Is called when user leaves page on client and page should be destructed. Extend this method for custom calls on destruct.
On server:
getPageJson()
; page content should be placed in i-content
block;200 OK
with resulting htmlOn client:
i-content
block content with resulting htmli-content
Use it to output page layout from page blocks. Do not call BN('i-page').out(bemjson)
, use only this.out(bemjson)
/**
* Node docs page
*/
BN.addDecl('node-doc', 'page', {
route: /^\/node-doc\/?(.+)?$/
}).staticProp({
init: function () {
return this.out({ //this works on client and server
block: 'node-doc',
content: [
{elem: 'toc', content: {block: 'node-doc-toc'}},
{elem: 'section', content: {block: 'node-doc-section'}}
]
});
}
});
This block is a container for pages content. Content inside i-content
can be automatically updated on client.
Block has api to manipulate content inside pages.
Applies all supported templates (bh, bem.json, bemhtml) to bemjson tree and then serialises it to html.
By setting isSync = true
you will get error when rendering blocks with defined dataTemplate
.
Update dom with new content.
BN.addDecl('example').blockTemplate(function(ctx){
//.. adding some content
}).dataTemplate(function(ctx){
/.. adding some data to params
}).staticProp({
updateBlock: function(param) {
return BN('i-content').update(this.__lastInstance.domElem.parent(), {
block: this._name,
param: param
});
}
});
Manages error pages (404, 50x), http redirect and responses.
Sends http response.
Responses with json.
Redirects to path with 302 status.
Responses with 404 status.
Responses with error (503 or status, defined in HttpError) and log error.
//block sends error when data fetching fails
BN.addDecl('example').dataTemplate(function(ctx){
var resource = ctx.json().resourceParam; //geting block param
return BN('ajax-block').get(resource).then(function(dataJson){ //get data from ajax block
ctx.param('data', dataJson); //setup data in block param
Vow.fulfill(); //continue render
}).fail(function(err){ // if data fails
BN('i-response').error(err); //send error to user
return Vow.reject(err); // stop render
});
})
Create user errors
Constructor for user errors
Https error.
var Errors = BN('i-errors');
var ApiError = function (status, debugInfo) {
HttpError.call(this, status);
this.name = 'ApiError';
this.debugInfo = debugInfo;
}
ApiError.prototype = new HttpError();
ApiError.prototype.constructor = ApiError;
//to properly serialize
Errors.ApiError = ApiError;
ApiError.prototype.serialize = function () {
var errorObj = HttpError.prototype.serialize.call(this);
errorObj.args = [this.status, this.debugInfo];
return errorObj;
}
var err = new ApiError(404, 'fail');
Errors.isHttpError(err);//true
err instanceof Error; //true
err.message; //Not Found
err.debugInfo; //fail
Returns instance of object with error properties. Can be serialised to JSON
Returns error.
//node
var Errors = BEM.blocks['i-errors'];
BEM.blocks['i-response'].json({
error: Errors.serialize(new Errors.HttpError(404))
});
//browser
var Errors = BEM.blocks['i-errors'];
var data = JSON.parse(xhr.responseText);
var err = Errors.createError(data.error);
Errors.isHttpError(err);//true
Manages page blocks and transitions between urls.
Changes url path.
On server: redirects with 302.
On client: destructs current page and inits new page. setPath
uses history.pushState
; replacePath
uses history.replaceState
.
Returns url path
Returns full uri (i.e. protocol, domain, path, query)
Changes url params.
On server: redirects with 302.
On client: setParams
uses history.pushState
; replaceParams
uses history.replaceState
.
Returns url host.
DEPRECATED — use BN('i-content').escapeHTML | unescapeHTML instead
Escapes user content to prevent XSS.
GET or POST params.
Node http.IncomingMessage
Node http.ServerResponse
Request cookies. See node-cookie api;
Getting regexp matchers from current router
Use it to update static page content on client:
//example of static header that updates when page changing
BN.addDecl('app-header').instanceProp({
init: function () { //fires when block inits on client
BN('i-router').on('update', this._onPageUpdate); //listen to page updates
},
_onPageUpdate: function () {
this.elem('search-input').val( //change value of search input element
BN.escapeHTML( //escape to prevent XSS
BN('i-router').getParams().q //get param from url
)
);
}
});
Base block for ajax blocks.
Calls this._request('get', resource, options)
;
On server: makes request to rest api host, defined by this._apiHost
.
On client: makes remote call (through xhr) of server implementation.
Triggered on client before and after xhr request.
BN('i-api-request').on('beforerequest', function () {
//show ajax loader
});
BN('i-api-request').on('afterrequest', function () {
//hide ajax loader
});
Triggered on client on xhr error.
####run tests
git clone git@github.com:bem-node/bem-node.git
cd bem-node
npm test
####quick tests
./tests.sh -c #client tests only
./tests.sh -s #server tests only
./tests.sh -s -n simple #run server tests only for 'simple' set
./tests.sh -s -n simple -g i-router #grep i-router tests
./tests.sh -b #rebuild tests
./tests.sh -b -s -c #rebuild, server, client
####create tests
You should use .common.test.js
for tests common for client and server, .priv.tests.js
for server tests only, and .tests.js
for client tests only.
Typical test looks like this
describe('whatever', function () {
it ('testing someting', function (done) {
return expect(env('/some-url?param-name=param-value', function () {
return <promise or not>
})).eventually.equal(<some value>)
});
});
describe('i-api-request', function () {
it('get with full path', function () {
return expect(env(function () {
return BEM.blocks['i-api-request'].get('http://nodejs.org/api/index.json')
})).eventually.have.property('source')
});
});
You should use global env
function to create page context
FAQs
bem-node [![Build Status](https://travis-ci.org/bem-node/bem-node.png?branch=master)](https://travis-ci.org/bem-node/bem-node) ===
The npm package bem-node receives a total of 6 weekly downloads. As such, bem-node popularity was classified as not popular.
We found that bem-node demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 4 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.