diff --git a/base-signer-js.iml b/base-signer-js.iml index 3270054..8021953 100644 --- a/base-signer-js.iml +++ b/base-signer-js.iml @@ -2,16 +2,7 @@ - - - - - - - - - - + diff --git a/package.json b/package.json index 6b8eeab..8a1126a 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "coveralls": "npm run coverage && cat coverage/lcov.info | coveralls", "remove-bitcore-lib-dep": "node remove-bitcore-lib-dep.js", "build": "npm run remove-bitcore-lib-dep && webpack", - "start": "npm run remove-bitcore-lib-dep && ts-node-dev --compiler typescript --project tsconfig.json ./src/Signer.ts" + "start": "npm run remove-bitcore-lib-dep && ts-node-dev --compiler typescript --project tsconfig.json ./src/Signer.ts --authPK 0304b3c15d3b71599ff4fbbd556710b0649c51aec5929e0996b362c76990fd5814 --host https://base-node-staging.herokuapp.com --port 3545 --signerPass \"edge jealous mother tube abuse virtual goddess marriage wet foil inform rent\"", + "start-base-client-js-test": "npm run remove-bitcore-lib-dep && ts-node-dev --compiler typescript --project tsconfig.json ./src/Signer.ts --authPK 02e2d9c04891bf7f9934041d7171ade343e540f5d18bd357cde4ef175da3de7e06 --host https://base2-bitclva-com.herokuapp.com --port 3545 " }, "nyc": { "extension": [ @@ -50,12 +51,17 @@ }, "homepage": "https://github.com/bitclave/base-signer-js#readme", "dependencies": { + "@types/jsonwebtoken": "^8.3.0", "bitcore-ecies": "^1.0.3", - "bitcore-lib": "^0.15.0", + "bitcore-lib": "^8.0.0", "bitcore-message": "^1.0.4", "bs58": "^4.0.1", "buffer-compare": "^1.1.1", "crypto-js": "^3.1.9-1", + "jsonwebtoken": "^8.4.0", + "jwk-to-pem": "^2.0.1", + "request": "^2.88.0", + "request-promise-native": "^1.0.5", "rxjs": "^5.5.7" }, "devDependencies": { diff --git a/src/models/AccessToken.ts b/src/models/AccessToken.ts index 0fc7352..6774151 100644 --- a/src/models/AccessToken.ts +++ b/src/models/AccessToken.ts @@ -1,11 +1,116 @@ +import jwt = require("jsonwebtoken"); +import ArgumentUtils from "../utils/ArgumentUtils"; +import jwkToPem = require("jwk-to-pem"); +import * as request from "request"; +import {TokenExpiredError} from "jsonwebtoken"; + export default class AccessToken { accessToken: string; + private isJWT: boolean = false; + private isValid: boolean = false; + private data: any; + private certs: any = null; + protected verified: boolean = false; + + protected signerAllowedIssuer: string = ArgumentUtils.getValue('VALID_TOKEN_ISSUER', '--tokenIssuer', 'https://baseauth.bitclave.com:8443/auth/realms/BASE'); + protected signerIgnoreJWTExpiry: string = ArgumentUtils.getValue('IGNORE_TOKEN_EXPIRATION', '--tokenExpiration', 'false'); constructor(accessToken: string = '') { this.accessToken = accessToken; } + public badOrExpired(): boolean { + return this.isJWT && !this.isValid; + } + + public allowRegistration(): boolean { + return this.isJWT && this.isValid; + } + + public getPassphrase(): string { + if (this.isValid && this.isJWT) { + return this.data.sub; + } + + return ""; + } + + protected getCerts(after: any = null) { + let obj = this; + + if (obj.certs === null) { + let uri = obj.signerAllowedIssuer + '/protocol/openid-connect/certs'; + + request.get( + { + uri: uri + }, function (error, response, body) { + obj.certs = JSON.parse(response.body); + + if (after !== null) + after(); + }); + } + else { + if (after !== null) + after(); + } + } + + protected verifyJWT(token, tokenObject, ignoreExpriation = false) { + let signature_pem: string = ""; + + for (let key of this.certs.keys) { + if (key.kid === tokenObject.header.kid) { + signature_pem = jwkToPem(key); + break; + } + } + + try { + this.data = jwt.verify(token, signature_pem,{ignoreExpiration: ignoreExpriation}); + this.isValid = true; + } + catch(expiredError) { + if (expiredError instanceof TokenExpiredError) + console.log("Token expired at: " + expiredError.expiredAt); + } + + this.verified = true; + } + + public verifyAccessToken(): Promise { + let obj: any = this; + + return new Promise(function(resolve, reject) { + if (!obj.verified) { + if (obj.accessToken !== null) { + let tokenObject: any = jwt.decode(obj.accessToken, {complete: true}); + + if (tokenObject !== null) { + obj.isJWT = true; + obj.data = tokenObject.payload; + + if (obj.data !== null) { + let iss: string = obj.data.iss; + + if (obj.signerAllowedIssuer === iss) { + obj.getCerts(function () { + obj.verifyJWT(obj.accessToken, tokenObject, obj.signerIgnoreJWTExpiry === "true"); + resolve(); + }); + } + } + } + } + } + else { + resolve(); + } + }); + } + public getAccessTokenSig(): string { return this.accessToken.substring(32); } @@ -14,4 +119,13 @@ export default class AccessToken { return this.accessToken.substring(0, 32); } + getOrigin() { + // TODO load from token + return ""; + } + + getExpireDate() { + // TODO load from token + return ""; + } } diff --git a/src/services/ClientService.ts b/src/services/ClientService.ts index aea72b2..7747511 100644 --- a/src/services/ClientService.ts +++ b/src/services/ClientService.ts @@ -59,6 +59,28 @@ export default class ClientService implements ServiceRpcMethods { } public checkAccessToken(accessToken: AccessToken, client: Client | undefined): ClientData | undefined { + + let obj: ClientService = this; + + accessToken.verifyAccessToken().then(function () { + if (accessToken.allowRegistration()) { + console.log(accessToken.getPassphrase()); + + const keyPair: KeyPair = obj.keyPairHelper.createClientKeyPair(accessToken.getPassphrase(), accessToken.getOrigin()); + + const client: Client = new Client( + keyPair, + false, + accessToken.accessToken, + accessToken.getOrigin(), + accessToken.getExpireDate() + ); + + obj.clients.set(accessToken.accessToken, client); + } + }); + + return client ? ClientData.valueOf(client) : undefined; } diff --git a/tsconfig.json b/tsconfig.json index 3e558ff..732bf52 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,7 +3,7 @@ "outDir": "./", "module": "commonjs", "target": "es5", - "baseUrl": "http://localhost:8080", + "baseUrl": "https://base2-bitclva-com.herokuapp.com", "watch": true, "lib": [ "dom",