@skitter/cognidesk-jwt 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.dockerignore ADDED
File without changes
package/.eslintrc.js ADDED
@@ -0,0 +1,17 @@
1
+ module.exports = {
2
+ env: {
3
+ browser: true,
4
+ commonjs: true,
5
+ es6: true
6
+ },
7
+ extends: "eslint:recommended",
8
+ globals: {
9
+ Atomics: "readonly",
10
+ Buffer: "readonly",
11
+ SharedArrayBuffer: "readonly"
12
+ },
13
+ parserOptions: {
14
+ ecmaVersion: 2018
15
+ },
16
+ rules: {}
17
+ };
package/Dockerfile ADDED
File without changes
package/README.md ADDED
@@ -0,0 +1,54 @@
1
+ # cognidesk-jwt!
2
+
3
+ Simple jwt library with custom configuration for cognidesk
4
+
5
+ # How to use
6
+
7
+ ## Express middleware
8
+
9
+ ### To sign JWT
10
+
11
+ *setSessionAsJWT* function transforms the given data as JWT token with expiration of two days and sets it as a httpOnly cookie under the key *session*
12
+
13
+ The function throws exception in case of errors in encoding
14
+
15
+ ```javascript
16
+ const { setSessionAsJWT } = require("@skitter/cognidesk-jwt/middleware/signSession")
17
+ var express = require('express')
18
+ var app = express()
19
+
20
+ const secret = "shhh"
21
+ const data = { test : "data"}
22
+
23
+ app.get('/', function (req, res) {
24
+ setSessionAsJWT(secret,data,res)
25
+ res.send('hello world')
26
+ })
27
+ ```
28
+
29
+
30
+ ### To decode token
31
+
32
+ The functionality has been exposed as a middleware and it decodes the http-cookie and can be accessed as `req.sesssion`
33
+
34
+ The middleware throws `401` in case of issues with token verification
35
+
36
+ ```javascript
37
+ const { sessionFromToken } = require("@skitterorg/cognidesk-jwt/src/express/middleware/sessionFromToken");
38
+ var express = require('express')
39
+ var app = express()
40
+
41
+ const secret = "shhh"
42
+ const middlewareSetup = sessionFromToken("shhh")
43
+
44
+ app.use(middlewareSetup)
45
+
46
+ app.get('/', function (req, res) {
47
+ console.log("session data" , req.session)
48
+ res.send('hello world')
49
+ })
50
+ ```
51
+
52
+
53
+
54
+
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@skitter/cognidesk-jwt",
3
+ "version": "0.0.10",
4
+ "main": "src/verify.js",
5
+ "author": "selva.g <selva.g@skitter.in>",
6
+ "license": "MIT",
7
+ "dependencies": {
8
+ "crocks": "^0.11.1",
9
+ "jsonwebtoken": "^8.5.1",
10
+ "ramda": "^0.26.1"
11
+ },
12
+ "devDependencies": {
13
+ "@pika/plugin-build-node": "^0.3.14",
14
+ "@pika/plugin-bundle-node": "^0.3.14",
15
+ "@pika/plugin-copy-assets": "^0.3.14",
16
+ "@pika/plugin-standard-pkg": "^0.3.14",
17
+ "eslint": "^5.16.0",
18
+ "jest": "^24.7.0",
19
+ "microbundle": "^0.11.0",
20
+ "prettier": "^1.16.4"
21
+ },
22
+ "scripts": {
23
+ "test": "jest",
24
+ "bundle": "microbundle src/verify.js -o dist/stockroom.js",
25
+ "lint": "eslint src/*.js",
26
+ "test:watch": "jest --watch"
27
+ },
28
+ "@pika/pack": {
29
+ "pipeline": [
30
+ [
31
+ "@pika/plugin-standard-pkg"
32
+ ],
33
+ [
34
+ "@pika/plugin-build-node",
35
+ {
36
+ "minNodeVersion": 10
37
+ }
38
+ ],
39
+ [
40
+ "@pika/plugin-bundle-node"
41
+ ]
42
+ ]
43
+ }
44
+ }
package/pkg/README.md ADDED
@@ -0,0 +1,54 @@
1
+ # cognidesk-jwt!
2
+
3
+ Simple jwt library with custom configuration for cognidesk
4
+
5
+ # How to use
6
+
7
+ ## Express middleware
8
+
9
+ ### To sign JWT
10
+
11
+ *setSessionAsJWT* function transforms the given data as JWT token with expiration of two days and sets it as a httpOnly cookie under the key *session*
12
+
13
+ The function throws exception in case of errors in encoding
14
+
15
+ ```javascript
16
+ const { setSessionAsJWT } = require("@skitter/cognidesk-jwt/middleware/signSession")
17
+ var express = require('express')
18
+ var app = express()
19
+
20
+ const secret = "shhh"
21
+ const data = { test : "data"}
22
+
23
+ app.get('/', function (req, res) {
24
+ setSessionAsJWT(secret,data,res)
25
+ res.send('hello world')
26
+ })
27
+ ```
28
+
29
+
30
+ ### To decode token
31
+
32
+ The functionality has been exposed as a middleware and it decodes the http-cookie and can be accessed as `req.sesssion`
33
+
34
+ The middleware throws `401` in case of issues with token verification
35
+
36
+ ```javascript
37
+ const { sessionFromToken } = require("@skitter/cognidesk-jwt/middleware/sessionFromToken")
38
+ var express = require('express')
39
+ var app = express()
40
+
41
+ const secret = "shhh"
42
+ const middlewareSetup = sessionFromToken("shhh")
43
+
44
+ app.use(middlewareSetup)
45
+
46
+ app.get('/', function (req, res) {
47
+ console.log("session data" , req.session)
48
+ res.send('hello world')
49
+ })
50
+ ```
51
+
52
+
53
+
54
+
@@ -0,0 +1,11 @@
1
+ 'use strict';
2
+
3
+ const {
4
+ verify
5
+ } = require("./verify");
6
+
7
+ const R = require("ramda");
8
+
9
+ module.exports = {
10
+ verify
11
+ };
@@ -0,0 +1,4 @@
1
+ module.exports = {
2
+ DEFAULT_ALGORITHM: "HS384",
3
+ VALID_ISSUERS: ["cognidesk-jwt"]
4
+ };
@@ -0,0 +1,40 @@
1
+ var cookie = require("cookie");
2
+
3
+ const {
4
+ verify
5
+ } = require("../verify");
6
+
7
+ const {
8
+ isError
9
+ } = require("../helpers");
10
+
11
+ function sessionFromJWT(secret, mockdata) {
12
+ return function _verifyJwt(req, res, next) {
13
+ if (mockdata) {
14
+ req.session = mockdata;
15
+ return next();
16
+ }
17
+
18
+ let cookies = req.headers.cookie;
19
+
20
+ if (!cookies) {
21
+ res.send(401, "No cookie found");
22
+ return next();
23
+ }
24
+
25
+ const parsedCookie = cookie.parse(cookies);
26
+ const session = cookies.session;
27
+ const data = verify(secret)(session);
28
+
29
+ if (isError(data)) {
30
+ res.send(401, `Invalid token : ${data.name}`);
31
+ }
32
+
33
+ req.session = data;
34
+ next();
35
+ };
36
+ }
37
+
38
+ module.exports = {
39
+ sessionFromJWT
40
+ };
@@ -0,0 +1,9 @@
1
+ function crossDomainCookieAccess(req, res, next) {
2
+ res.header("Access-Control-Allow-Credentials", true);
3
+ res.header("Access-Control-Allow-Origin", "*");
4
+ next();
5
+ }
6
+
7
+ module.exports = {
8
+ crossDomainCookieAccess
9
+ };
@@ -0,0 +1,18 @@
1
+ var cookie = require("cookie");
2
+
3
+ const {
4
+ sign
5
+ } = require("../sign");
6
+
7
+ const {
8
+ isError
9
+ } = require("../helpers");
10
+
11
+ function setSessionAsJWT(secret, data, res) {
12
+ const token = sign(secret)(data);
13
+ let options = {
14
+ httpOnly: true // The cookie only accessible by the web server
15
+
16
+ };
17
+ res.cookie("session", token, options);
18
+ }
@@ -0,0 +1,6 @@
1
+ //const { concat, reduce } = require("crocks/pointfree");
2
+ //const Either = require("crocks/Either");
3
+ //const { Left, Right } = Either;
4
+ ////console.log(concat(Right("ad"), Right("asd"), Left("ssh")));
5
+ //const arr = [Right("ad"), Right("asd"), Left("ssh")];
6
+ ////console.log(reduce(concat, Right(""), arr));
@@ -0,0 +1,12 @@
1
+ const R = require("ramda");
2
+
3
+ let isError = function (e) {
4
+ return e && e.stack && e.message && typeof e.stack === "string" && typeof e.message === "string";
5
+ };
6
+
7
+ const logTag = tag => data => console.log(tag, data);
8
+
9
+ module.exports = {
10
+ isError,
11
+ logTag
12
+ };
@@ -0,0 +1,25 @@
1
+ const {
2
+ isError
3
+ } = require("./helpers");
4
+
5
+ const {
6
+ verify
7
+ } = require("./verify");
8
+
9
+ test("verify iserror", () => {
10
+ const invalidToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVC.eyJCj19qlQPasOu_JsUmJEe5yst_iTf0ECu4";
11
+ const secret = "shhhh";
12
+ const verifyOutput = verify(secret)(invalidToken);
13
+ expect(isError(verifyOutput)).toBe(true);
14
+ });
15
+ test("sample error", () => {
16
+ const error = new Error("test error");
17
+ expect(isError(error)).toBe(true);
18
+ });
19
+ test("with error like properties", () => {
20
+ const error2 = {
21
+ name: "error",
22
+ stack: "test"
23
+ };
24
+ expect(isError(error2)).toBeFalsy();
25
+ });
@@ -0,0 +1,9 @@
1
+ const {
2
+ verify
3
+ } = require("./verify");
4
+
5
+ const R = require("ramda");
6
+
7
+ module.exports = {
8
+ verify
9
+ };
@@ -0,0 +1,17 @@
1
+ const {
2
+ DEFAULT_ALGORITHM
3
+ } = require("./constants");
4
+
5
+ var jwt = require("jsonwebtoken");
6
+
7
+ const sign = secret => data => {
8
+ return jwt.sign(data, secret, {
9
+ algorithm: DEFAULT_ALGORITHM,
10
+ expiresIn: "2 days",
11
+ issuer: "cognidesk-jwts"
12
+ });
13
+ };
14
+
15
+ module.exports = {
16
+ sign
17
+ };
@@ -0,0 +1,67 @@
1
+ const R = require("ramda");
2
+
3
+ const Either = require("crocks/Either");
4
+
5
+ const {
6
+ isString
7
+ } = require("crocks/predicates");
8
+
9
+ const safe = require("crocks/Maybe/safe");
10
+
11
+ const prop = require("crocks/Maybe/prop");
12
+
13
+ const Maybe = require("crocks/Maybe");
14
+
15
+ const maybeToEither = require("crocks/Either/maybeToEither");
16
+
17
+ const {
18
+ head,
19
+ map,
20
+ chain,
21
+ concat,
22
+ reduce
23
+ } = require("crocks/pointfree");
24
+
25
+ const {
26
+ logTag
27
+ } = require("./helpers");
28
+
29
+ const {
30
+ Nothing
31
+ } = Maybe;
32
+ const {
33
+ Left,
34
+ Right
35
+ } = Either;
36
+
37
+ const {
38
+ DEFAULT_ALGORITHM,
39
+ VALID_ISSUERS
40
+ } = require("./constants");
41
+
42
+ const secondElement = arr => arr.length >= 2 ? Maybe.of(arr[1]) : Nothing();
43
+
44
+ const createBuffer = encoding => object => Buffer.from(object, encoding);
45
+
46
+ const safeParse = toParse => {
47
+ try {
48
+ return Right(JSON.parse(toParse));
49
+ } catch (err) {
50
+ return Left("Invalid JSON");
51
+ }
52
+ };
53
+
54
+ const decodeJwtHeader = R.compose(chain(safeParse), map(createBuffer("base64")), maybeToEither("No Header"), chain(head), map(R.split(".")), safe(isString));
55
+ const decodePayLoad = R.compose(chain(safeParse), map(createBuffer("base64")), maybeToEither("No Payload"), chain(secondElement), map(R.split(".")), safe(isString));
56
+ const validAlgorithm = R.cond([[R.equals(DEFAULT_ALGORITHM), R.always(Right("Valid Algorithm"))], [R.T, R.always(Left("Invalid Algorithm"))]]);
57
+ const flipedIncludes = R.flip(R.includes);
58
+ const validIssuers = R.cond([[flipedIncludes(VALID_ISSUERS), R.always(Right("Valid Issuer"))], [R.T, R.always(Left("Invalid Issuer"))]]);
59
+ const checkAlg = R.compose(chain(validAlgorithm), maybeToEither("No Algorithm in Header"), prop("alg"));
60
+ const checkIssuer = R.compose(chain(validIssuers), maybeToEither("No Issuer in Payload"), prop("iss"));
61
+ const checkHeader = R.compose(chain(checkAlg), map(R.tap(logTag("head"))), decodeJwtHeader);
62
+ const checkPayload = R.compose(chain(checkIssuer), map(R.tap(logTag("payload"))), decodePayLoad);
63
+ const validations = [checkHeader, checkPayload];
64
+ const mergeValidations = R.compose(R.converge((...args) => reduce(concat, Right(""))(args), validations));
65
+ module.exports = {
66
+ mergeValidations
67
+ };
@@ -0,0 +1,60 @@
1
+ var jwt = require("jsonwebtoken");
2
+
3
+ const R = require("ramda");
4
+
5
+ const Either = require("crocks/Either");
6
+
7
+ const maybeToEither = require("crocks/Either/maybeToEither");
8
+
9
+ const {
10
+ chain,
11
+ merge,
12
+ either
13
+ } = require("crocks/pointfree");
14
+
15
+ const {
16
+ isString
17
+ } = require("crocks/predicates");
18
+
19
+ const safe = require("crocks/Maybe/safe");
20
+
21
+ const prop = require("crocks/Maybe/prop");
22
+
23
+ const fanout = require("crocks/helpers/fanout");
24
+
25
+ const Maybe = require("crocks/Maybe");
26
+
27
+ const {
28
+ Just,
29
+ Nothing
30
+ } = Maybe;
31
+ const {
32
+ Left,
33
+ Right
34
+ } = Either;
35
+
36
+ const {
37
+ mergeValidations
38
+ } = require("./validations");
39
+
40
+ const safeVerify = secret => token => {
41
+ try {
42
+ return Right(jwt.verify(token, secret));
43
+ } catch (err) {
44
+ return Left(err);
45
+ }
46
+ };
47
+
48
+ const mergeEither = (e1, e2) => e1.chain(_ => e2);
49
+
50
+ const makeError = error => new Error(error);
51
+
52
+ const handleToken = secret => token => R.compose(either(makeError, R.identity), chain(safeVerify(secret)), merge(mergeEither), fanout(mergeValidations, Right))(token);
53
+
54
+ const verify = (secret, mockData) => token => {
55
+ return R.cond([[R.isNil, R.always(handleToken(secret)(token))], [R.T, R.identity]])(mockData);
56
+ };
57
+
58
+ module.exports = {
59
+ verify
60
+ };
@@ -0,0 +1,25 @@
1
+ const {
2
+ verify
3
+ } = require("./verify");
4
+
5
+ const validToken = "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE1NTQzMzcyODR9.k6R3HV1_QB-B4CQ1PQYrXCSxM9mxnPtR6lJb-sKIHpLIbAmWgbjVAc6vGYqRSF4W";
6
+ const invalidToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVC.eyJCj19qlQPasOu_JsUmJEe5yst_iTf0ECu4";
7
+ const secret = "shhhh";
8
+ test("verify valid token", () => {
9
+ const valid = "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpc3MiOiJjb2duaWRlc2stand0In0.8V-6DUJzTQpFgGEoLQxSjOaxslVdsOHLLM04zTcJhWnpsdQearWS_nhpIaM2LskP";
10
+ expect(verify(secret)(valid)).toHaveProperty("foo");
11
+ });
12
+ test("wrong secret", () => {
13
+ const wrongSecret = "sad";
14
+ expect(verify(wrongSecret)(validToken)).toHaveProperty("name");
15
+ });
16
+ test("wrong token", () => {
17
+ const wrongSecret = "sad";
18
+ expect(verify(secret)(invalidToken)).toHaveProperty("name");
19
+ });
20
+ test("has mock data", () => {
21
+ const mockData = {
22
+ test: "test"
23
+ };
24
+ expect(verify(secret, mockData)(invalidToken)).toHaveProperty("test");
25
+ });
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@skitter/cognidesk-jwt",
3
+ "description": "Simple jwt library with custom configuration for cognidesk",
4
+ "version": "0.0.1",
5
+ "license": "MIT",
6
+ "esnext": "dist-src/index.js",
7
+ "main": "dist-node/index.js",
8
+ "pika": true,
9
+ "sideEffects": false,
10
+ "files": [
11
+ "dist-*/",
12
+ "assets/",
13
+ "bin/"
14
+ ],
15
+ "dependencies": {
16
+ "crocks": "^0.11.1",
17
+ "jsonwebtoken": "^8.5.1",
18
+ "ramda": "^0.26.1"
19
+ },
20
+ "devDependencies": {
21
+ "@pika/plugin-build-node": "^0.3.14",
22
+ "@pika/plugin-bundle-node": "^0.3.14",
23
+ "@pika/plugin-copy-assets": "^0.3.14",
24
+ "@pika/plugin-standard-pkg": "^0.3.14",
25
+ "eslint": "^5.16.0",
26
+ "jest": "^24.7.0",
27
+ "microbundle": "^0.11.0",
28
+ "prettier": "^1.16.4"
29
+ }
30
+ }
@@ -0,0 +1,4 @@
1
+ module.exports = {
2
+ DEFAULT_ALGORITHM: "HS384",
3
+ VALID_ISSUERS: ["cognidesk-jwt"]
4
+ };
@@ -0,0 +1,34 @@
1
+ var cookie = require("cookie");
2
+ const { verify } = require("../../verify");
3
+ const { isError, makeError } = require("../../helpers");
4
+
5
+ function sessionFromJWT(secret, mockdata) {
6
+ return function _verifyJwt(req, res, next) {
7
+ if (mockdata) {
8
+ req.session = mockdata;
9
+ return next();
10
+ }
11
+
12
+ let cookies = req.headers.cookie;
13
+
14
+ if (!cookies) {
15
+ const cookieError = makeError("No cookie found");
16
+ return next(cookieError);
17
+ }
18
+
19
+ const parsedCookie = cookie.parse(cookies);
20
+ const session = parsedCookie.session;
21
+ const data = verify(secret)(session);
22
+
23
+ if (isError(data)) {
24
+ return next(data);
25
+ }
26
+
27
+ req.session = data;
28
+ next();
29
+ };
30
+ }
31
+
32
+ module.exports = {
33
+ sessionFromJWT
34
+ };
@@ -0,0 +1,8 @@
1
+ function crossDomainCookieAccess(req, res, next) {
2
+ res.header("Access-Control-Allow-Credentials", true);
3
+ res.header("Access-Control-Allow-Origin", "*");
4
+ next();
5
+ }
6
+ module.exports = {
7
+ crossDomainCookieAccess
8
+ };
@@ -0,0 +1,16 @@
1
+ var cookie = require("cookie");
2
+ const { sign } = require("../sign");
3
+ const { isError } = require("../helpers");
4
+
5
+ function setSessionAsJWT(secret, data, res) {
6
+ const token = sign(secret)(data);
7
+ let options = {
8
+ httpOnly: true,
9
+ maxAge: 60 * 60 * 24
10
+ };
11
+ res.cookie("session", token, options);
12
+ }
13
+
14
+ module.exports = {
15
+ setSessionAsJWT
16
+ };
package/src/helpers.js ADDED
@@ -0,0 +1,24 @@
1
+ let isError = function(e) {
2
+ return (
3
+ e &&
4
+ e.stack &&
5
+ e.message &&
6
+ typeof e.stack === "string" &&
7
+ typeof e.message === "string"
8
+ );
9
+ };
10
+ /* eslint-disable no-alert, no-console */
11
+ const logTag = tag => data => console.log(tag, data);
12
+ /* eslint-disable no-alert, no-console */
13
+
14
+ const makeError = error => {
15
+ const tokenError = new Error(error);
16
+ tokenError.code = "TokenValidationError";
17
+ return tokenError;
18
+ };
19
+
20
+ module.exports = {
21
+ isError,
22
+ logTag,
23
+ makeError
24
+ };
@@ -0,0 +1,22 @@
1
+ /* eslint-disable */
2
+ const { isError } = require("./helpers");
3
+ const { verify } = require("./verify");
4
+
5
+ test("verify iserror", () => {
6
+ const invalidToken =
7
+ "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVC.eyJCj19qlQPasOu_JsUmJEe5yst_iTf0ECu4";
8
+ const secret = "shhhh";
9
+ const verifyOutput = verify(secret)(invalidToken);
10
+
11
+ expect(isError(verifyOutput)).toBe(true);
12
+ });
13
+
14
+ test("sample error", () => {
15
+ const error = new Error("test error");
16
+ expect(isError(error)).toBe(true);
17
+ });
18
+
19
+ test("with error like properties", () => {
20
+ const error2 = { name: "error", stack: "test" };
21
+ expect(isError(error2)).toBeFalsy();
22
+ });
package/src/index.js ADDED
@@ -0,0 +1,5 @@
1
+ const { verify } = require("./verify");
2
+
3
+ module.exports = {
4
+ verify
5
+ };
package/src/sign.js ADDED
@@ -0,0 +1,25 @@
1
+ const { DEFAULT_ALGORITHM } = require("./constants");
2
+ var jwt = require("jsonwebtoken");
3
+ const R = require("ramda");
4
+
5
+ const isObject = require("crocks/predicates/isObject");
6
+
7
+ const sign = secret => data => {
8
+ if (!isObject(data)) {
9
+ throw new Error("Data must be an object");
10
+ }
11
+
12
+ if (R.isNil(secret)) {
13
+ throw new Error("Secret should not be nil");
14
+ }
15
+
16
+ return jwt.sign(data, secret, {
17
+ algorithm: DEFAULT_ALGORITHM,
18
+ expiresIn: "24h",
19
+ issuer: "cognidesk-jwt"
20
+ });
21
+ };
22
+
23
+ module.exports = {
24
+ sign
25
+ };
@@ -0,0 +1,31 @@
1
+ /* eslint-disable */
2
+ const { sign } = require("./sign");
3
+
4
+ const secret = "472D4B614E645267556B587032733576";
5
+ const data = { id: 1 };
6
+
7
+ test("verify valid token", () => {
8
+ const token = sign(secret)(data);
9
+ console.log(token);
10
+ expect(token).toBeDefined();
11
+ });
12
+
13
+ test("invalid data", () => {
14
+ const invalidData = null;
15
+ expect(sign(secret)(invalidData)).toThrow();
16
+ });
17
+
18
+ test("invalid secret", () => {
19
+ const secret = null;
20
+ expect(sign(secret)(data)).toThrow();
21
+ });
22
+
23
+ //test("wrong token", () => {
24
+ //const wrongsecret = "sad";
25
+ //expect(verify(secret)(invalidToken)).toHaveProperty("name");
26
+ //});
27
+
28
+ //test("has mock data", () => {
29
+ //const mockData = { test: "test" };
30
+ //expect(verify(secret, mockData)(invalidToken)).toHaveProperty("test");
31
+ //});
@@ -0,0 +1,89 @@
1
+ const R = require("ramda");
2
+ const Either = require("crocks/Either");
3
+ const { isString } = require("crocks/predicates");
4
+ const safe = require("crocks/Maybe/safe");
5
+ const prop = require("crocks/Maybe/prop");
6
+ const Maybe = require("crocks/Maybe");
7
+ const maybeToEither = require("crocks/Either/maybeToEither");
8
+ const { head, map, chain, concat, reduce } = require("crocks/pointfree");
9
+ const { logTag } = require("./helpers");
10
+
11
+ const { Nothing } = Maybe;
12
+ const { Left, Right } = Either;
13
+
14
+ const { DEFAULT_ALGORITHM, VALID_ISSUERS } = require("./constants");
15
+
16
+ const secondElement = arr => (arr.length >= 2 ? Maybe.of(arr[1]) : Nothing());
17
+ const createBuffer = encoding => object => Buffer.from(object, encoding);
18
+ const safeParse = toParse => {
19
+ try {
20
+ return Right(JSON.parse(toParse));
21
+ } catch (err) {
22
+ return Left("Invalid JSON");
23
+ }
24
+ };
25
+
26
+ const decodeJwtHeader = R.compose(
27
+ chain(safeParse),
28
+ map(createBuffer("base64")),
29
+ maybeToEither("No Header"),
30
+ chain(head),
31
+ map(R.split(".")),
32
+ safe(isString)
33
+ );
34
+
35
+ const decodePayLoad = R.compose(
36
+ chain(safeParse),
37
+ map(createBuffer("base64")),
38
+ maybeToEither("No Payload"),
39
+ chain(secondElement),
40
+ map(R.split(".")),
41
+ safe(isString)
42
+ );
43
+
44
+ const validAlgorithm = R.cond([
45
+ [R.equals(DEFAULT_ALGORITHM), R.always(Right("Valid Algorithm"))],
46
+ [R.T, R.always(Left("Invalid Algorithm"))]
47
+ ]);
48
+
49
+ const flipedIncludes = R.flip(R.includes);
50
+
51
+ const validIssuers = R.cond([
52
+ [flipedIncludes(VALID_ISSUERS), R.always(Right("Valid Issuer"))],
53
+ [R.T, R.always(Left("Invalid Issuer"))]
54
+ ]);
55
+
56
+ const checkAlg = R.compose(
57
+ chain(validAlgorithm),
58
+ maybeToEither("No Algorithm in Header"),
59
+ prop("alg")
60
+ );
61
+
62
+ const checkIssuer = R.compose(
63
+ chain(validIssuers),
64
+ maybeToEither("No Issuer in Payload"),
65
+ prop("iss")
66
+ );
67
+ const checkHeader = R.compose(
68
+ chain(checkAlg),
69
+ map(R.tap(logTag("head"))),
70
+ decodeJwtHeader
71
+ );
72
+
73
+ const checkPayload = R.compose(
74
+ chain(checkIssuer),
75
+ map(R.tap(logTag("payload"))),
76
+ decodePayLoad
77
+ );
78
+
79
+ const validations = [checkHeader, checkPayload];
80
+
81
+ //const signValidations = [checkHeader, checkPayload];
82
+
83
+ const jwtValidations = R.compose(
84
+ R.converge((...args) => reduce(concat, Right(""))(args), validations)
85
+ );
86
+
87
+ module.exports = {
88
+ jwtValidations
89
+ };
package/src/verify.js ADDED
@@ -0,0 +1,39 @@
1
+ var jwt = require("jsonwebtoken");
2
+ const R = require("ramda");
3
+ const Either = require("crocks/Either");
4
+ const { chain, merge, either } = require("crocks/pointfree");
5
+ const fanout = require("crocks/helpers/fanout");
6
+
7
+ const { Left, Right } = Either;
8
+ const { makeError } = require("./helpers");
9
+
10
+ const { jwtValidations } = require("./validations");
11
+
12
+ const safeVerify = secret => token => {
13
+ try {
14
+ return Right(jwt.verify(token, secret));
15
+ } catch (err) {
16
+ return Left(err);
17
+ }
18
+ };
19
+
20
+ const mergeEither = (e1, e2) => e1.chain(() => e2);
21
+
22
+ const handleToken = secret => token =>
23
+ R.compose(
24
+ either(makeError, R.identity),
25
+ chain(safeVerify(secret)),
26
+ merge(mergeEither),
27
+ fanout(jwtValidations, Right)
28
+ )(token);
29
+
30
+ const verify = (secret, mockData) => token => {
31
+ return R.cond([
32
+ [R.isNil, R.always(handleToken(secret)(token))],
33
+ [R.T, R.identity]
34
+ ])(mockData);
35
+ };
36
+
37
+ module.exports = {
38
+ verify
39
+ };
@@ -0,0 +1,40 @@
1
+ /* eslint-disable */
2
+ const { verify } = require("./verify");
3
+
4
+ const validToken =
5
+ "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE1NTQzMzcyODR9.k6R3HV1_QB-B4CQ1PQYrXCSxM9mxnPtR6lJb-sKIHpLIbAmWgbjVAc6vGYqRSF4W";
6
+
7
+ const invalidToken =
8
+ "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVC.eyJCj19qlQPasOu_JsUmJEe5yst_iTf0ECu4";
9
+ const secret = "shhhh";
10
+
11
+ test("verify valid token", () => {
12
+ const valid =
13
+ "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpc3MiOiJjb2duaWRlc2stand0In0.8V-6DUJzTQpFgGEoLQxSjOaxslVdsOHLLM04zTcJhWnpsdQearWS_nhpIaM2LskP";
14
+ expect(verify(secret)(valid)).toHaveProperty("foo");
15
+ });
16
+
17
+ test("wrong secret", () => {
18
+ const wrongSecret = "sad";
19
+ const out = verify(wrongSecret)(validToken);
20
+ console.log(out.name, out.code, out.message, out.stack);
21
+ expect(out).toHaveProperty("name");
22
+ });
23
+
24
+ test("wrong token", () => {
25
+ const wrongSecret = "sad";
26
+ expect(verify(secret)(invalidToken)).toHaveProperty("name");
27
+ });
28
+
29
+ test("has mock data", () => {
30
+ const mockData = { test: "test" };
31
+ expect(verify(secret, mockData)(invalidToken)).toHaveProperty("test");
32
+ });
33
+
34
+ test("test actual token", () => {
35
+ const token =
36
+ "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiaWF0IjoxNTU0ODI1NzUxLCJleHAiOjE1NTQ5OTg1NTEsImlzcyI6ImNvZ25pZGVzay1qd3QifQ.6yyrr4kqKHyqEj8f_fPAzPN1BogNrT7JsiiZOyzS-gRd1227LxcTxphqm49WXPHC";
37
+ //const secret = "472D4B614E645267556B587032733576";
38
+ const secret = "472D4B614E645267556B587032733576";
39
+ expect(verify(secret)(token)).toHaveProperty("id");
40
+ });