Skip to content

Commit

Permalink
Update common, some info readme
Browse files Browse the repository at this point in the history
  • Loading branch information
huy97 committed Dec 21, 2020
1 parent 2d28ef1 commit 4fd3529
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 110 deletions.
33 changes: 23 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,27 +28,38 @@ $ npm install ncsrf --save

## Usage <a name = "usage"></a>

Import in *main.ts*
### Import in *main.ts* and enable

```javascript
import {nestCsrf, CsrfFilter} from 'ncsrf';
import cookieParser from 'cookie-parser';
```

Enable CSRF in global
import {nestCsrf, CsrfFilter} from 'ncsrf';
import cookieParser from 'cookie-parser';

```javascript
app.use(cookieParser());
app.use(nestCsrf());
```
### nestCsrf([options])
- signed - indicates if the cookie should be signed (defaults to false).
- key - the name of the cookie to use to store the token secret (defaults to '_csrf').
- ttl - The time to live of the cookie use to store the token secret (default 300s).

Custom exception
### Custom exception message

```javascript
app.useGlobalFilters(new CsrfFilter);
```

Generate token here
Or use your custom exception filter by catch 2 class
```javascript
CsrfInvalidException
```
And

```javascript
CsrfNotFoundException
```
## Example

### Generate token here

```javascript
@Get('/token')
Expand All @@ -59,9 +70,11 @@ Generate token here
}
```

Protected route with csrf
### Protected route with csrf

```javascript
import {Csrf} from "ncsrf";
...
@Post()
@Csrf()
needProtect(): string{
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@nestjs/csrf",
"version": "1.0.0",
"name": "ncsrf",
"version": "1.0.1",
"description": "Simple NestJS CSRF verify token",
"main": "dist/index.js",
"types": "dist/index.ts",
Expand Down
95 changes: 95 additions & 0 deletions src/common/csrf.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import Cookie from "cookie";
import Tokens from "csrf";
import { sign } from "cookie-signature";

type NestCsrfOptions = {
signed?: boolean;
key?: string;
ttl?: number;
};

const tokenProvider = new Tokens({
secretLength: 16,
saltLength: 16,
});

const nestCsrf = (options?: NestCsrfOptions) => {
const sessionKey = "session";
const cookieConfig = {
signed: false,
key: "_csrf",
path: "/",
httpOnly: true,
maxAge: options && options.ttl ? options.ttl : 300,
...options,
};
return function csrf(req, res, next) {
let csrfTokenValue = "";
let secret = getSecretFromRequest(req, sessionKey, cookieConfig);
if (!secret) {
secret = tokenProvider.secretSync();
setSecret(req, res, sessionKey, secret, cookieConfig);
}
req.cookieConfig = cookieConfig;
req.csrfToken = () => {
if (csrfTokenValue) return csrfTokenValue;
csrfTokenValue = tokenProvider.create(secret);
return csrfTokenValue;
};
next();
};
};

const getSecretFromRequest = (req, sessionKey, cookie) => {
var bag = getSecretBag(req, sessionKey, cookie);
var key = cookie ? cookie.key : "csrfSecret";
if (!bag) {
return false;
}
return bag[key];
};

const getCsrfFromRequest = (req) => {
return (
(req.body && req.body._csrf) ||
(req.query && req.query._csrf) ||
req.headers["csrf-token"] ||
req.headers["xsrf-token"] ||
req.headers["x-csrf-token"] ||
req.headers["x-xsrf-token"]
);
};

const verify = (secret, token) => {
return tokenProvider.verify(secret, token);
};

const setCookie = (res, name, value, options) => {
const data = Cookie.serialize(name, value, options);
const prev = res.getHeader("set-cookie") || [];
const header = Array.isArray(prev) ? prev.concat(data) : [prev, data];

res.setHeader("set-cookie", header);
};

const setSecret = (req, res, sessionKey, value, cookie) => {
if (cookie) {
if (cookie.signed) {
value = "s:" + sign(value, req.secret);
}
setCookie(res, cookie.key, value, cookie);
} else {
req[sessionKey].csrfSecret = value;
}
};

const getSecretBag = (req, sessionKey, cookie) => {
if (cookie) {
var cookieKey = cookie.signed ? "signedCookies" : "cookies";
return req[cookieKey];
} else {
return req[sessionKey];
}
};

export { nestCsrf, getSecretFromRequest, getCsrfFromRequest, verify };
96 changes: 1 addition & 95 deletions src/common/index.ts
Original file line number Diff line number Diff line change
@@ -1,95 +1 @@
import Cookie from "cookie";
import Tokens from "csrf";
import { sign } from "cookie-signature";

type NestCsrfOptions = {
signed?: boolean;
key?: string;
ttl?: number;
};

const tokenProvider = new Tokens({
secretLength: 16,
saltLength: 16,
});

const nestCsrf = (options?: NestCsrfOptions) => {
const sessionKey = "session";
const cookieConfig = {
signed: false,
key: "_csrf",
path: "/",
httpOnly: true,
maxAge: options && options.ttl ? options.ttl : 300,
...options,
};
return function csrf(req, res, next) {
let csrfTokenValue = "";
let secret = getSecretFromRequest(req, sessionKey, cookieConfig);
if (!secret) {
secret = tokenProvider.secretSync();
setSecret(req, res, sessionKey, secret, cookieConfig);
}
req.cookieConfig = cookieConfig;
req.csrfToken = () => {
if (csrfTokenValue) return csrfTokenValue;
csrfTokenValue = tokenProvider.create(secret);
return csrfTokenValue;
};
next();
};
};

const getSecretFromRequest = (req, sessionKey, cookie) => {
var bag = getSecretBag(req, sessionKey, cookie);
var key = cookie ? cookie.key : "csrfSecret";
if (!bag) {
return false;
}
return bag[key];
};

const getCsrfFromRequest = (req) => {
return (
(req.body && req.body._csrf) ||
(req.query && req.query._csrf) ||
req.headers["csrf-token"] ||
req.headers["xsrf-token"] ||
req.headers["x-csrf-token"] ||
req.headers["x-xsrf-token"]
);
};

const verify = (secret, token) => {
return tokenProvider.verify(secret, token);
};

const setCookie = (res, name, value, options) => {
const data = Cookie.serialize(name, value, options);
const prev = res.getHeader("set-cookie") || [];
const header = Array.isArray(prev) ? prev.concat(data) : [prev, data];

res.setHeader("set-cookie", header);
};

const setSecret = (req, res, sessionKey, value, cookie) => {
if (cookie) {
if (cookie.signed) {
value = "s:" + sign(value, req.secret);
}
setCookie(res, cookie.key, value, cookie);
} else {
req[sessionKey].csrfSecret = value;
}
};

const getSecretBag = (req, sessionKey, cookie) => {
if (cookie) {
var cookieKey = cookie.signed ? "signedCookies" : "cookies";
return req[cookieKey];
} else {
return req[sessionKey];
}
};

export { nestCsrf, getSecretFromRequest, getCsrfFromRequest, verify };
export * from "./csrf";
6 changes: 3 additions & 3 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
"target": "es2017",
"module": "commonjs",
"lib": ["es2017", "es7", "es6"],
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"declaration": false,
"declarationMap": false,
"sourceMap": false,
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
Expand Down

0 comments on commit 4fd3529

Please sign in to comment.