jumbo-core
Advanced tools
Comparing version 1.0.3 to 1.0.4
@@ -7,2 +7,3 @@ /** | ||
const {Jumplate} = require("jumbo-template"); | ||
const {CSRF_KEY_NAME} = require("../application/Application"); | ||
@@ -69,5 +70,17 @@ //region Template setup | ||
Jumplate.registerBlockHelper("form", function (content) { | ||
return '<form method="POST" action="#" enctype="multipart/form-data">' + content + '</form>'; | ||
return '<form method="POST" action="#" enctype="multipart/form-data">' | ||
+ `<input type="hidden" name="${CSRF_KEY_NAME}" value="${this.csrfToken}">${content}</form>`; | ||
}); | ||
/** | ||
* CSRF helper | ||
* Create input with CSRF token | ||
*/ | ||
Jumplate.registerHelper("csrf", function () { | ||
return `<input type="hidden" name="${CSRF_KEY_NAME}" value="${this.csrfToken}">`; | ||
}); | ||
/** | ||
* JSON helper - convert object into JSON string | ||
*/ | ||
Jumplate.registerHelper("json", function (obj) { | ||
@@ -74,0 +87,0 @@ return JSON.stringify(obj); |
import * as $fs from "fs"; | ||
import * as $http from "http"; | ||
export declare const CSRF_KEY_NAME = "__forgery_token"; | ||
export declare class Application { | ||
@@ -19,2 +20,3 @@ private server; | ||
private templateAdapter; | ||
private csrf; | ||
serverIsRunning: boolean; | ||
@@ -43,2 +45,3 @@ getLocator(): Locator; | ||
private serverCallback(request, response); | ||
private setResponseHeaders(response); | ||
private checkStaticFileRequest(request, response); | ||
@@ -48,3 +51,12 @@ private checkEndingDelimiter(request, response); | ||
private checkRequestsLimit(response, clientIP); | ||
private verifyCsrfToken(jRequest, jResponse, session); | ||
getCsrfSecret(session: { | ||
[key: string]: any; | ||
}): string; | ||
generateCsrfSecret(session: { | ||
[key: string]: any; | ||
}): Promise<string>; | ||
generateCsrfTokenFor(secret: string): string; | ||
private processRequest(request, response, requestBeginTime); | ||
private prepareCsrf(session); | ||
private procUrlParseError(match, request, response, jResponse); | ||
@@ -56,3 +68,3 @@ private setClientSession(jRequest, jResponse); | ||
private collectBodyData(req, res); | ||
private createController(request, response); | ||
private createController(request, response, session); | ||
private initController(cntrll, req, res, session, scope); | ||
@@ -59,0 +71,0 @@ private callBeforeActions(ctrl, request); |
@@ -15,2 +15,3 @@ "use strict"; | ||
const uuid = require("uuid/v1"); | ||
const Tokens = require("csrf"); | ||
const Exception_1 = require("jumbo-core/exceptions/Exception"); | ||
@@ -33,2 +34,9 @@ const ViewResult_1 = require("jumbo-core/results/ViewResult"); | ||
const MAX_POST_DATA_SIZE = Jumbo.config.maxPostDataSize; | ||
const X_POWERED_BY_ENABLED = !Jumbo.config.security.hidePoweredBy; | ||
const X_FRAME_OPTION = Jumbo.config.security.xFrameOptions; | ||
const NO_SNIFF = !!Jumbo.config.security.noSniff; | ||
exports.CSRF_KEY_NAME = "__forgery_token"; | ||
const ONE_DAY_TIME = 24 * 60 * 60; | ||
const CSRF_REQUIRING_METHODS = ["POST", "PUT", "DELETE"]; | ||
const CSRF_ENABLED = !!Jumbo.config.security.csrf; | ||
const istanceKey = Symbol.for("Jumbo.Application.Application"); | ||
@@ -61,2 +69,3 @@ let instance = global[istanceKey] || null; | ||
this.templateAdapter = null; | ||
this.csrf = new Tokens(); | ||
this.serverIsRunning = false; | ||
@@ -239,3 +248,3 @@ if (new.target != ApplicationActivator) { | ||
let requestBeginTime = new Date().getTime(); | ||
response.setHeader("X-Powered-By", "JumboJS"); | ||
this.setResponseHeaders(response); | ||
let clientIP = this.getClientIP(request); | ||
@@ -265,2 +274,10 @@ try { | ||
} | ||
setResponseHeaders(response) { | ||
if (X_POWERED_BY_ENABLED) | ||
response.setHeader("X-Powered-By", "JumboJS"); | ||
if (X_FRAME_OPTION) | ||
response.setHeader("X-Frame-Options", X_FRAME_OPTION); | ||
if (NO_SNIFF) | ||
response.setHeader("X-Content-Type-Options", "nosniff"); | ||
} | ||
async checkStaticFileRequest(request, response) { | ||
@@ -354,2 +371,23 @@ if (request.method == "GET" && request.url.slice(0, 7) === "/public") { | ||
} | ||
async verifyCsrfToken(jRequest, jResponse, session) { | ||
let secret = await this.getCsrfSecret(session); | ||
if (CSRF_REQUIRING_METHODS.includes(jRequest.method)) { | ||
if (!this.csrf.verify(secret, jRequest.body.fields[exports.CSRF_KEY_NAME])) { | ||
this.plainResponse(jResponse.response, "Error 403, forbidden. Invalid token detected. ", 403); | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
getCsrfSecret(session) { | ||
return session[exports.CSRF_KEY_NAME]; | ||
} | ||
async generateCsrfSecret(session) { | ||
let secret = await this.csrf.secret(); | ||
session[exports.CSRF_KEY_NAME] = secret; | ||
return secret; | ||
} | ||
generateCsrfTokenFor(secret) { | ||
return this.csrf.create(secret); | ||
} | ||
async processRequest(request, response, requestBeginTime) { | ||
@@ -367,2 +405,9 @@ const jResponse = new Response_1.Response(response); | ||
jRequest.body = await this.collectBodyData(jRequest, jResponse); | ||
let session = await this.getClientSession(jRequest); | ||
if (CSRF_ENABLED) { | ||
await this.prepareCsrf(session); | ||
let csrfValid = await this.verifyCsrfToken(jRequest, jResponse, session); | ||
if (!csrfValid) | ||
return; | ||
} | ||
if (DEBUG_MODE) { | ||
@@ -372,3 +417,3 @@ console.log(`[DEBUG] Request target point Sub-App ${jRequest.subApp}, Controller ${jRequest.controllerFullName}, ` | ||
} | ||
let ctrl = await this.createController(jRequest, jResponse); | ||
let ctrl = await this.createController(jRequest, jResponse, session); | ||
let actionResult = await this.callBeforeActions(ctrl, jRequest); | ||
@@ -396,2 +441,7 @@ if (actionResult !== undefined) | ||
} | ||
async prepareCsrf(session) { | ||
if (!this.getCsrfSecret(session)) { | ||
await this.generateCsrfSecret(session); | ||
} | ||
} | ||
async procUrlParseError(match, request, response, jResponse) { | ||
@@ -496,6 +546,5 @@ if (match == null || !match.redirectTo) { | ||
} | ||
async createController(request, response) { | ||
async createController(request, response, session) { | ||
let scope = new Jumbo.Ioc.Scope(); | ||
let ctrl = this.controllerFactory.createController(this.controllerFactory.getControllerId(request.controller), this.controllerFactory.getSubAppId(request.subApp), scope); | ||
let session = await this.getClientSession(request); | ||
this.initController(ctrl, request, response, session, scope); | ||
@@ -502,0 +551,0 @@ return ctrl; |
@@ -8,5 +8,5 @@ import * as $http from "http"; | ||
constructor(response: $http.ServerResponse); | ||
setCookie(name: string, value: string, expire: number, domain: string, path: string): void; | ||
setCookie(name: string, value: string, expire?: number, domain?: string, path?: string): void; | ||
unsetCookie(name: string): void; | ||
redirectUrl(url: string, code?: number): void; | ||
} |
@@ -13,2 +13,3 @@ import { ErrorResult } from "../results/ErrorResult"; | ||
protected readonly url: Url; | ||
readonly csrfToken: string; | ||
_initController(request: Request, response: Response, session: { | ||
@@ -19,2 +20,3 @@ [key: string]: any; | ||
protected static createBaseViewResult(viewOrData: string | {}, data: {}): ViewResult; | ||
regenerateCsrfSecret(): Promise<void>; | ||
exit(): void; | ||
@@ -21,0 +23,0 @@ addMessage(message: string, messageType: any): void; |
@@ -31,2 +31,5 @@ "use strict"; | ||
} | ||
get csrfToken() { | ||
return Application_1.Application.instance.generateCsrfTokenFor(Application_1.Application.instance.getCsrfSecret(this.session)); | ||
} | ||
_initController(request, response, session, scope) { | ||
@@ -51,2 +54,5 @@ this.session = session; | ||
} | ||
async regenerateCsrfSecret() { | ||
await Application_1.Application.instance.generateCsrfSecret(this.session); | ||
} | ||
exit() { | ||
@@ -152,2 +158,3 @@ this.exited = true; | ||
const ViewResult_1 = require("jumbo-core/results/ViewResult"); | ||
const Application_1 = require("../application/Application"); | ||
if (Jumbo.config.jumboDebugMode) { | ||
@@ -154,0 +161,0 @@ console.log("[DEBUG] REQUIRE: Controller END"); |
@@ -233,3 +233,8 @@ const $cfg = require("jumbo-core/config-options"); | ||
*/ | ||
noSniff: false | ||
noSniff: false, | ||
/** | ||
* Enable CSRF validation | ||
*/ | ||
csrf: true | ||
} | ||
@@ -236,0 +241,0 @@ |
{ | ||
"name": "jumbo-core", | ||
"version": "1.0.3", | ||
"version": "1.0.4", | ||
"description": "Modern lightweight fast enterprise level MVW framework for Node.js", | ||
@@ -40,2 +40,3 @@ "keywords": [ | ||
"dependencies": { | ||
"csrf": "^3.0.6", | ||
"formidable": "^1.2.1", | ||
@@ -42,0 +43,0 @@ "uuid": "^3.2.1" |
@@ -58,3 +58,3 @@ # JumboJS | ||
Go to your project directory and run application. | ||
Go to your project directory, edit your config.js file (set up DB connection or remove whole `domains` property) and run application. | ||
``` | ||
@@ -61,0 +61,0 @@ npm start |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
372685
109
4881
3
+ Addedcsrf@^3.0.6
+ Addedcsrf@3.1.0(transitive)
+ Addedrandom-bytes@1.0.0(transitive)
+ Addedrndm@1.2.0(transitive)
+ Addedtsscmp@1.0.6(transitive)
+ Addeduid-safe@2.1.5(transitive)