diff --git a/CHANGELOG.md b/CHANGELOG.md index c2ad715..1579df6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,11 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## Next release + +- Add `options` object to `Handler`'s constructor +- Make `verify` method's return value generic + ## 2.0.0 2017.08.09 - Complete reimplementation in TypeScript diff --git a/README.md b/README.md index ea8c53f..9c0ae08 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,14 @@ function privkeyResolver (keyId) { const jwtHandler = new jwt.JwtHandler('myproject', pubkeyResolver, privkeyResolver) +// or with options object + +const jwtHandler = new jwt.JwtHandler({ + debugNamePrefix: 'myproject', + pubkeyResolver: pubkeyResolver, + privkeyResolver: privkeyResolver, +}) + // Verifying JWT tokens jwtHandler.verify(jwtRaw) .then(jwtBody => { diff --git a/index.ts b/index.ts index 56812ba..c57a5c9 100644 --- a/index.ts +++ b/index.ts @@ -1,4 +1,4 @@ -export {TokenExpiredError, NotBeforeError, JsonWebTokenError } from "jsonwebtoken" +export {TokenExpiredError, NotBeforeError, JsonWebTokenError} from "jsonwebtoken" export {JwtHandler, PubkeyResolver, PrivkeyResolver, PubkeyData, PrivkeyData} from "./src/JwtHandler" export {MissingKeyIdError} from "./src/MissingKeyIdError" export {UnknownKeyIdError} from "./src/UnknownKeyIdError" diff --git a/src/JwtHandler.spec.ts b/src/JwtHandler.spec.ts index b3165e3..1f00975 100644 --- a/src/JwtHandler.spec.ts +++ b/src/JwtHandler.spec.ts @@ -1,183 +1,187 @@ import * as chai from "chai" import * as chaiAsPromised from "chai-as-promised" import * as jwt from "jsonwebtoken" -chai.use(chaiAsPromised) -const { expect } = chai - import "mocha" -import { JwtHandler, PrivkeyData, PubkeyData } from "./JwtHandler" -import { MissingKeyIdError } from "./MissingKeyIdError" -import { UnknownKeyIdError } from "./UnknownKeyIdError" +import {JwtHandler, PrivkeyData, PubkeyData} from "./JwtHandler" +import {MissingKeyIdError} from "./MissingKeyIdError" +import {UnknownKeyIdError} from "./UnknownKeyIdError" + +chai.use(chaiAsPromised) +const {expect} = chai const debugNamePrefix = "test" // fixtures const keyId = "abc1234" const tokenBody = { - iat: Math.floor(Date.now() / 1000), - dummy: "dummy", - iss: "issuer1", - aud: "audience1", + iat: Math.floor(Date.now() / 1000), + dummy: "dummy", + iss: "issuer1", + aud: "audience1", } + function pubkeyResolver(pubkeyId: string): PubkeyData { - return (pubkeyId === keyId) ? {cert, alg: "RS256"} : null + return (pubkeyId === keyId) ? {cert, alg: "RS256"} : null } + function privkeyResolver(privkeyId: string): PrivkeyData { - return (privkeyId === keyId) ? {key: privateKey, passphrase: privateKeyPass, alg: "RS256"} : null + return (privkeyId === keyId) ? {key: privateKey, passphrase: privateKeyPass, alg: "RS256"} : null } describe("JwtHandler", () => { - describe("extractKeyId", () => { - const jwtHandler = new JwtHandler(debugNamePrefix, pubkeyResolver, privkeyResolver) - it("should return the correct key id from the given JWT", () => { - const jwtRaw = generateJwt(keyId, tokenBody) - expect(jwtHandler.extractKeyId(jwtRaw)).to.equal(keyId) - }) - - it("should be rejected with MissingKeyIdError if the JWT does not contain a kid property in the header", () => { - const jwtRaw = generateJwt(null, tokenBody) - expect(() => jwtHandler.extractKeyId(jwtRaw)).to.throw(MissingKeyIdError) - }) - - it("should be rejected with JsonWebTokenError if the JWT header is not JSON", () => { - // tslint:disable-next-line:max-line-length - const jwtRaw = "76576576werwerwterertertert.7868765348765zurtiueziuerziutziuzeriuziuwtzuizi34986349.345765347654376543765735765tzreztwrwueruz" - expect(() => jwtHandler.extractKeyId(jwtRaw)).to.throw(jwt.JsonWebTokenError) - }) - - it("should be rejected with JsonWebTokenError if the JWT is complete garbage", () => { - // tslint:disable-next-line:max-line-length - const jwtRaw = "!\\76576576w!!--///erwerwterertertertöüóAAŐÚÉÁŰ<<7868765348765>> zurtiueziuerz{ }iutziuzer*****iuziuwtzuizi34986349345765347654376543765735765+++====tzreztwrwueruz" - expect(() => jwtHandler.extractKeyId(jwtRaw)).to.throw(jwt.JsonWebTokenError) - }) - }) - - describe("verify", () => { - const jwtHandler = new JwtHandler(debugNamePrefix, pubkeyResolver, privkeyResolver) - it("should return the JWT body if passed a valid JWT", (done) => { - const jwtRaw = generateJwt(keyId, tokenBody) - expect( - jwtHandler.verify(jwtRaw) - ).to.eventually.deep.equal(tokenBody).notify(done) - }) - - it("should return the JWT body if passed a valid JWT and validation options that matches the JWT", (done) => { - const jwtRaw = generateJwt(keyId, tokenBody) - expect( - jwtHandler.verify(jwtRaw, {issuer: tokenBody.iss}) - ).to.eventually.deep.equal(tokenBody).notify(done) - }) - - it("should be rejected with JsonWebTokenError if the validation options do not match", (done) => { - const jwtRaw = generateJwt(keyId, tokenBody) - expect( - jwtHandler.verify(jwtRaw, {issuer: "expected_issuer"}) - ).to.eventually.rejectedWith(jwt.JsonWebTokenError).notify(done) - }) - - it("should be rejected with TokenExpiredError if the JWT is already expired", (done) => { - const tokenBodyExpired = { - iat: Math.floor(Date.now() / 1000), - dummy: "dummy", - exp: Math.floor(Date.now() / 1000) - 5000, - } - const jwtRaw = generateJwt(keyId, tokenBodyExpired) - expect( - jwtHandler.verify(jwtRaw) - ).to.eventually.rejectedWith(jwt.TokenExpiredError).notify(done) - }) - - it("should be rejected with NotBeforeError if the is not yet valid", (done) => { - const tokenBodyNbf = { - iat: Math.floor(Date.now() / 1000), - dummy: "dummy", - nbf: Math.floor(Date.now() / 1000) + 1000, - } - const jwtRaw = generateJwt(keyId, tokenBodyNbf) - expect( - jwtHandler.verify(jwtRaw) - ).to.eventually.rejectedWith(jwt.NotBeforeError).notify(done) - }) - - it("should be rejected with JsonWebTokenError if the JWT is empty", (done) => { - expect( - jwtHandler.verify("") - ).to.be.rejectedWith(jwt.JsonWebTokenError).notify(done) - }) - - it("should be rejected with JsonWebTokenError if the JWT is null", (done) => { - expect( - jwtHandler.verify(null as any) - ).to.be.rejectedWith(jwt.JsonWebTokenError).notify(done) - }) - - it("should be rejected with JsonWebTokenError if the JWT is undefined", (done) => { - expect( - jwtHandler.verify(undefined as any) - ).to.be.rejectedWith(jwt.JsonWebTokenError).notify(done) - }) - - it("should be rejected with MissingKeyIdError if the JWT does not contain a kid property in the header", (done) => { - const jwtRaw = generateJwt(null, tokenBody) - expect( - jwtHandler.verify(jwtRaw) - ).to.eventually.rejectedWith(MissingKeyIdError).notify(done) - }) - - it("should be rejected with UnknownKeyIdError if the key id is unknown", (done) => { - const jwtRaw = generateJwt("unknown-key-id", tokenBody) - expect( - jwtHandler.verify(jwtRaw) - ).to.eventually.rejectedWith(UnknownKeyIdError).notify(done) - }) - - it("should be throw an Error if no pubkey resolver is specified", (done) => { - const jwtHandlerNoPubkeyResolver = new JwtHandler(debugNamePrefix, null, privkeyResolver) - const jwtRaw = generateJwt(keyId, tokenBody) - expect( - jwtHandlerNoPubkeyResolver.verify(jwtRaw) - ).to.eventually.rejectedWith(Error).notify(done) - }) - }) - - describe("create", () => { - const jwtHandler = new JwtHandler(debugNamePrefix, pubkeyResolver, privkeyResolver) - it("should create a valid JWT if called with a key id that exists", (done) => { - jwtHandler.create(tokenBody, keyId) + describe("extractKeyId", () => { + const jwtHandler = new JwtHandler(debugNamePrefix, pubkeyResolver, privkeyResolver) + it("should return the correct key id from the given JWT", () => { + const jwtRaw = generateJwt(keyId, tokenBody) + expect(jwtHandler.extractKeyId(jwtRaw)).to.equal(keyId) + }) + + it("should be rejected with MissingKeyIdError if the JWT does not contain a kid property in the header", () => { + const jwtRaw = generateJwt(null, tokenBody) + expect(() => jwtHandler.extractKeyId(jwtRaw)).to.throw(MissingKeyIdError) + }) + + it("should be rejected with JsonWebTokenError if the JWT header is not JSON", () => { + // tslint:disable-next-line:max-line-length + const jwtRaw = "76576576werwerwterertertert.7868765348765zurtiueziuerziutziuzeriuziuwtzuizi34986349.345765347654376543765735765tzreztwrwueruz" + expect(() => jwtHandler.extractKeyId(jwtRaw)).to.throw(jwt.JsonWebTokenError) + }) + + it("should be rejected with JsonWebTokenError if the JWT is complete garbage", () => { + // tslint:disable-next-line:max-line-length + const jwtRaw = "!\\76576576w!!--///erwerwterertertertöüóAAŐÚÉÁŰ<<7868765348765>> zurtiueziuerz{ }iutziuzer*****iuziuwtzuizi34986349345765347654376543765735765+++====tzreztwrwueruz" + expect(() => jwtHandler.extractKeyId(jwtRaw)).to.throw(jwt.JsonWebTokenError) + }) + }) + + describe("verify", () => { + const jwtHandler = new JwtHandler(debugNamePrefix, pubkeyResolver, privkeyResolver) + it("should return the JWT body if passed a valid JWT", (done) => { + const jwtRaw = generateJwt(keyId, tokenBody) + expect( + jwtHandler.verify(jwtRaw) + ).to.eventually.deep.equal(tokenBody).notify(done) + }) + + it("should return the JWT body if passed a valid JWT and validation options that matches the JWT", (done) => { + const jwtRaw = generateJwt(keyId, tokenBody) + expect( + jwtHandler.verify(jwtRaw, {issuer: tokenBody.iss}) + ).to.eventually.deep.equal(tokenBody).notify(done) + }) + + it("should be rejected with JsonWebTokenError if the validation options do not match", (done) => { + const jwtRaw = generateJwt(keyId, tokenBody) + expect( + jwtHandler.verify(jwtRaw, {issuer: "expected_issuer"}) + ).to.eventually.rejectedWith(jwt.JsonWebTokenError).notify(done) + }) + + it("should be rejected with TokenExpiredError if the JWT is already expired", (done) => { + const tokenBodyExpired = { + iat: Math.floor(Date.now() / 1000), + dummy: "dummy", + exp: Math.floor(Date.now() / 1000) - 5000, + } + const jwtRaw = generateJwt(keyId, tokenBodyExpired) + expect( + jwtHandler.verify(jwtRaw) + ).to.eventually.rejectedWith(jwt.TokenExpiredError).notify(done) + }) + + it("should be rejected with NotBeforeError if the is not yet valid", (done) => { + const tokenBodyNbf = { + iat: Math.floor(Date.now() / 1000), + dummy: "dummy", + nbf: Math.floor(Date.now() / 1000) + 1000, + } + const jwtRaw = generateJwt(keyId, tokenBodyNbf) + expect( + jwtHandler.verify(jwtRaw) + ).to.eventually.rejectedWith(jwt.NotBeforeError).notify(done) + }) + + it("should be rejected with JsonWebTokenError if the JWT is empty", (done) => { + expect( + jwtHandler.verify("") + ).to.be.rejectedWith(jwt.JsonWebTokenError).notify(done) + }) + + it("should be rejected with JsonWebTokenError if the JWT is null", (done) => { + expect( + jwtHandler.verify(null as any) + ).to.be.rejectedWith(jwt.JsonWebTokenError).notify(done) + }) + + it("should be rejected with JsonWebTokenError if the JWT is undefined", (done) => { + expect( + jwtHandler.verify(undefined as any) + ).to.be.rejectedWith(jwt.JsonWebTokenError).notify(done) + }) + + // tslint:disable-next-line:max-line-length + it("should be rejected with MissingKeyIdError if the JWT does not contain a kid property in the header", (done) => { + const jwtRaw = generateJwt(null, tokenBody) + expect( + jwtHandler.verify(jwtRaw) + ).to.eventually.rejectedWith(MissingKeyIdError).notify(done) + }) + + it("should be rejected with UnknownKeyIdError if the key id is unknown", (done) => { + const jwtRaw = generateJwt("unknown-key-id", tokenBody) + expect( + jwtHandler.verify(jwtRaw) + ).to.eventually.rejectedWith(UnknownKeyIdError).notify(done) + }) + + it("should be throw an Error if no pubkey resolver is specified", (done) => { + const jwtHandlerNoPubkeyResolver = new JwtHandler(debugNamePrefix, null, privkeyResolver) + const jwtRaw = generateJwt(keyId, tokenBody) + expect( + jwtHandlerNoPubkeyResolver.verify(jwtRaw) + ).to.eventually.rejectedWith(Error).notify(done) + }) + }) + + describe("create", () => { + const jwtHandler = new JwtHandler(debugNamePrefix, pubkeyResolver, privkeyResolver) + it("should create a valid JWT if called with a key id that exists", (done) => { + jwtHandler.create(tokenBody, keyId) .then((result) => { - expect( - result.match(/^[a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?\.([a-zA-Z0-9\-_]+)?$/) - ).to.be.instanceof(Array) - done() + expect( + result.match(/^[a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?\.([a-zA-Z0-9\-_]+)?$/) + ).to.be.instanceof(Array) + done() }) + }) + it("should be rejected with UnknownKeyIdError with a key id that does not exist", (done) => { + const keyIdUnknown = "unknown-key-id" + expect( + jwtHandler.create(tokenBody, keyIdUnknown) + ).to.be.rejectedWith(UnknownKeyIdError).notify(done) + }) + it("should be rejected with Error if no privkey resolver is specified", (done) => { + const jwtHandlerNoPrivkeyResolver = new JwtHandler(debugNamePrefix, pubkeyResolver, null) + expect( + jwtHandlerNoPrivkeyResolver.create(tokenBody, keyId) + ).to.be.rejectedWith(Error).notify(done) + }) + // it("should be rejected with UnknownKeyIdError with a null key id", (done) => { + // expect( + // jwtHandler.create(tokenBody, null) + // ).to.be.rejectedWith(UnknownKeyIdError).notify(done) + // }) }) - it("should be rejected with UnknownKeyIdError with a key id that does not exist", (done) => { - const keyIdUnknown = "unknown-key-id" - expect( - jwtHandler.create(tokenBody, keyIdUnknown) - ).to.be.rejectedWith(UnknownKeyIdError).notify(done) - }) - it("should be rejected with Error if no privkey resolver is specified", (done) => { - const jwtHandlerNoPrivkeyResolver = new JwtHandler(debugNamePrefix, pubkeyResolver, null) - expect( - jwtHandlerNoPrivkeyResolver.create(tokenBody, keyId) - ).to.be.rejectedWith(Error).notify(done) - }) - // it("should be rejected with UnknownKeyIdError with a null key id", (done) => { - // expect( - // jwtHandler.create(tokenBody, null) - // ).to.be.rejectedWith(UnknownKeyIdError).notify(done) - // }) - }) }) function generateJwt(kid: string | null, body: object) { - const header = kid ? {kid} : undefined - return jwt.sign(body, { - key: privateKey, passphrase: privateKeyPass}, {algorithm: "RS256", header} - ) + const header = kid ? {kid} : undefined + return jwt.sign(body, { + key: privateKey, passphrase: privateKeyPass, + }, {algorithm: "RS256", header} + ) } const cert = ` diff --git a/src/JwtHandler.ts b/src/JwtHandler.ts index 340c87e..8c9d9bd 100644 --- a/src/JwtHandler.ts +++ b/src/JwtHandler.ts @@ -5,102 +5,119 @@ import * as jwt from "jsonwebtoken" import * as util from "util" import {shim} from "util.promisify" -import { MissingKeyIdError } from "./MissingKeyIdError" -import { UnknownKeyIdError } from "./UnknownKeyIdError" +import {MissingKeyIdError} from "./MissingKeyIdError" +import {UnknownKeyIdError} from "./UnknownKeyIdError" -export type PubkeyData = { cert: string, alg: string } | undefined | null +export type PubkeyData = { cert: string, alg?: string } | undefined | null export type PrivkeyData = { key: string, passphrase: string, alg: string } | undefined | null export type PubkeyResolver = (keyId: string) => PubkeyData | Promise export type PrivkeyResolver = (keyId: string) => PrivkeyData | Promise -type JwtVerifyAsync = (token: string, publicKey: string, options?: jwt.VerifyOptions) => Promise -type JwtSignAsync = (payload: object, privateKey: {}, options?: jwt.SignOptions) => Promise +// tslint:disable-next-line:max-line-length +type JwtVerifyAsync = (token: string, publicKey: string | Buffer, options?: jwt.VerifyOptions) => Promise +type JwtSignAsync = (payload: string | Buffer | object, privateKey: {}, options?: jwt.SignOptions) => Promise + +export interface JwtHandlerOptions { + debugNamePrefix: string + pubkeyResolver?: PubkeyResolver + privkeyResolver?: PrivkeyResolver +} shim() // util.promisify shim export class JwtHandler { - private debug: debug.IDebugger - - private pubkeyResolver: PubkeyResolver | null - private privkeyResolver: PrivkeyResolver | null - - private jwtVerifyAsync = util.promisify(jwt.verify) as JwtVerifyAsync - private jwtSignAsync = util.promisify(jwt.sign) as JwtSignAsync - - public constructor(debugNamePrefix: string, - pubkeyResolver: PubkeyResolver | null, - privkeyResolver: PrivkeyResolver | null) { - this.debug = debug(debugNamePrefix + ":jwt.handler") - this.pubkeyResolver = pubkeyResolver - this.privkeyResolver = privkeyResolver - } - - /** - * Extract key ID from the given JWT - * - * @param {type} jwtRaw The JWT in raw form, i.e. Base64 coded parts separated with dots - * @return {Promise} Promise to the key id - */ - public extractKeyId(jwtRaw: string): string { - try { - const jwtHeaderBase64 = jwtRaw.split(".", 1) - const jwtHeader = JSON.parse(base64url.decode(jwtHeaderBase64[0])) - if (jwtHeader.kid) { - return jwtHeader.kid - } - throw new MissingKeyIdError() - } catch (err) { - if (!(err instanceof MissingKeyIdError)) { - throw new jwt.JsonWebTokenError("JWT header parsing error", err) - } - throw err + private debug: debug.IDebugger + + private pubkeyResolver: PubkeyResolver | null + private privkeyResolver: PrivkeyResolver | null + + private jwtVerifyAsync = util.promisify(jwt.verify) as JwtVerifyAsync + private jwtSignAsync = util.promisify(jwt.sign) as JwtSignAsync + + public constructor(options: JwtHandlerOptions) + public constructor(debugNamePrefix: string, + pubkeyResolver?: PubkeyResolver | null, + privkeyResolver?: PrivkeyResolver | null) + public constructor(arg1: string | JwtHandlerOptions, arg2?: PubkeyResolver | null, arg3?: PrivkeyResolver | null) { + if (typeof arg1 === "object") { + arg2 = arg1.pubkeyResolver + arg3 = arg1.privkeyResolver + arg1 = arg1.debugNamePrefix + } + + arg2 = arg2 || null + arg3 = arg3 || null + + this.debug = debug(arg1 + ":jwt.handler") + this.pubkeyResolver = arg2 + this.privkeyResolver = arg3 } - } - - /** - * Validates the given JWT - * - * @param {string} jwtRaw The JWT in raw form, i.e. Base64 coded parts separated with dots - * @param {Object} options Validation options (jsonwebtoken module options) - * @return {Promise} Promise to the JWT body - */ - public async verify(jwtRaw: string, options?: jwt.VerifyOptions): Promise { - if (!jwtRaw) { - throw new jwt.JsonWebTokenError("Empty JWT") + + /** + * Extract key ID from the given JWT + * + * @param {type} jwtRaw The JWT in raw form, i.e. Base64 coded parts separated with dots + * @return {Promise} Promise to the key id + */ + public extractKeyId(jwtRaw: string): string { + try { + const jwtHeaderBase64 = jwtRaw.split(".", 1) + const jwtHeader = JSON.parse(base64url.decode(jwtHeaderBase64[0])) + if (jwtHeader.kid) { + return jwtHeader.kid + } + } catch (err) { + throw new jwt.JsonWebTokenError("JWT header parsing error", err) + } + + throw new MissingKeyIdError() } - const keyId = await this.extractKeyId(jwtRaw) - debug("verify, key id: " + keyId) - if (this.pubkeyResolver) { - const certData = await this.pubkeyResolver(keyId) - if (!certData) { - throw new UnknownKeyIdError(keyId) - } - debug("cert found") - return this.jwtVerifyAsync(jwtRaw, certData.cert, options) + + /** + * Validates the given JWT + * + * @param {string} jwtRaw The JWT in raw form, i.e. Base64 coded parts separated with dots + * @param {Object} options Validation options (jsonwebtoken module options) + * @return {Promise} Promise to the JWT body + */ + public async verify(jwtRaw: string, + options?: jwt.VerifyOptions): Promise { + if (!jwtRaw) { + throw new jwt.JsonWebTokenError("Empty JWT") + } + const keyId = await this.extractKeyId(jwtRaw) + debug("verify, key id: " + keyId) + if (this.pubkeyResolver) { + const certData = await this.pubkeyResolver(keyId) + if (!certData) { + throw new UnknownKeyIdError(keyId) + } + debug("cert found") + return this.jwtVerifyAsync(jwtRaw, certData.cert, options) + } + throw new Error("No public key resolver specified") } - throw new Error("No public key resolver specified") - } - - /** - * Creates a new JWT with the given body and signs it with the given key - * - * @param {string} tokenBody The body of the JWT token - * @param {string} keyId The ID of the signing key - * @return {Promise} Promise to the JWT body - */ - public async create(tokenBody: object, keyId: string): Promise { - debug("create, key id: " + keyId) - if (this.privkeyResolver) { - const signingKey = await this.privkeyResolver(keyId) - if (!signingKey) { - throw new UnknownKeyIdError("Unknown key id") - } - debug("priv key found") - return this.jwtSignAsync(tokenBody, signingKey, { algorithm: signingKey.alg, header: { kid: keyId } }) + + /** + * Creates a new JWT with the given body and signs it with the given key + * + * @param {string} tokenBody The body of the JWT token + * @param {string} keyId The ID of the signing key + * @return {Promise} Promise to the JWT body + */ + public async create(tokenBody: string | Buffer | { [key: string]: any }, keyId: string): Promise { + debug("create, key id: " + keyId) + if (this.privkeyResolver) { + const signingKey = await this.privkeyResolver(keyId) + if (!signingKey) { + throw new UnknownKeyIdError("Unknown key id") + } + debug("priv key found") + return this.jwtSignAsync(tokenBody, signingKey, {algorithm: signingKey.alg, header: {kid: keyId}}) + } + throw new Error("No private key resolver specified") } - throw new Error("No private key resolver specified") - } } diff --git a/src/MissingKeyIdError.spec.ts b/src/MissingKeyIdError.spec.ts index 0ef8946..74a6498 100644 --- a/src/MissingKeyIdError.spec.ts +++ b/src/MissingKeyIdError.spec.ts @@ -1,27 +1,28 @@ import * as chai from "chai" import * as jwt from "jsonwebtoken" -const { expect } = chai import "mocha" -import { MissingKeyIdError } from "./MissingKeyIdError" +import {MissingKeyIdError} from "./MissingKeyIdError" + +const {expect} = chai function throwMissingKeyIdError() { - throw new MissingKeyIdError() + throw new MissingKeyIdError() } describe("MissingKeyIdError", () => { - it("a new instance should have the appropriate properties", () => { - try { - throwMissingKeyIdError() - } catch (err) { - expect(err.name).to.equal("MissingKeyIdError") - expect(err instanceof jwt.JsonWebTokenError).to.equal(true) - expect(err instanceof Error).to.equal(true) - expect(err.stack).to.not.equal(null) - expect(err.stack).to.not.equal(undefined) - expect(err.toString()).to.equal(`MissingKeyIdError: missing key id`) - expect(err.stack.split("\n")[0]).to.equal(`MissingKeyIdError: missing key id`) - expect(err.stack.split("\n")[1].indexOf("throwMissingKeyIdError")).to.equal(7) - } - }) + it("a new instance should have the appropriate properties", () => { + try { + throwMissingKeyIdError() + } catch (err) { + expect(err.name).to.equal("MissingKeyIdError") + expect(err instanceof jwt.JsonWebTokenError).to.equal(true) + expect(err instanceof Error).to.equal(true) + expect(err.stack).to.not.equal(null) + expect(err.stack).to.not.equal(undefined) + expect(err.toString()).to.equal(`MissingKeyIdError: missing key id`) + expect(err.stack.split("\n")[0]).to.equal(`MissingKeyIdError: missing key id`) + expect(err.stack.split("\n")[1].indexOf("throwMissingKeyIdError")).to.equal(7) + } + }) }) diff --git a/src/MissingKeyIdError.ts b/src/MissingKeyIdError.ts index 6ee6b35..3e44f07 100644 --- a/src/MissingKeyIdError.ts +++ b/src/MissingKeyIdError.ts @@ -1,12 +1,12 @@ -import { JsonWebTokenError } from "jsonwebtoken" +import {JsonWebTokenError} from "jsonwebtoken" /** * Error subclass for signaling that the kid field is not present in the JWT header */ export class MissingKeyIdError extends JsonWebTokenError { - constructor() { - super("missing key id") - this.name = this.constructor.name - Error.captureStackTrace(this, this.constructor) - } + constructor() { + super("missing key id") + this.name = this.constructor.name + Error.captureStackTrace(this, this.constructor) + } } diff --git a/src/UnknownKeyIdError.spec.ts b/src/UnknownKeyIdError.spec.ts index e6427c9..151d5f1 100644 --- a/src/UnknownKeyIdError.spec.ts +++ b/src/UnknownKeyIdError.spec.ts @@ -1,32 +1,33 @@ import * as chai from "chai" import * as jwt from "jsonwebtoken" -const { expect } = chai import "mocha" -import { UnknownKeyIdError } from "./UnknownKeyIdError" +import {UnknownKeyIdError} from "./UnknownKeyIdError" + +const {expect} = chai const keyId = "keyid_1" function throwUnknownKeyIdError() { - throw new UnknownKeyIdError(keyId) + throw new UnknownKeyIdError(keyId) } describe("UnknownKeyIdError", () => { - it("a new instance should have the appropriate properties", () => { - try { - throwUnknownKeyIdError() - } catch (err) { - expect(err.name).to.equal("UnknownKeyIdError") - expect(err instanceof UnknownKeyIdError).to.equal(true) - expect(err instanceof jwt.JsonWebTokenError).to.equal(true) - expect(err instanceof Error).to.equal(true) - expect(err.stack).to.not.equal(null) - expect(err.stack).to.not.equal(undefined) - expect(err.toString()).to.equal(`UnknownKeyIdError: unknown key id: ${keyId}`) - expect(err.keyId).to.equal(keyId) - expect(err.message).to.equal(`unknown key id: ${keyId}`) - expect(err.stack.split("\n")[0]).to.equal(`UnknownKeyIdError: unknown key id: ${keyId}`) - expect(err.stack.split("\n")[1].indexOf("throwUnknownKeyIdError")).to.equal(7) - } - }) + it("a new instance should have the appropriate properties", () => { + try { + throwUnknownKeyIdError() + } catch (err) { + expect(err.name).to.equal("UnknownKeyIdError") + expect(err instanceof UnknownKeyIdError).to.equal(true) + expect(err instanceof jwt.JsonWebTokenError).to.equal(true) + expect(err instanceof Error).to.equal(true) + expect(err.stack).to.not.equal(null) + expect(err.stack).to.not.equal(undefined) + expect(err.toString()).to.equal(`UnknownKeyIdError: unknown key id: ${keyId}`) + expect(err.keyId).to.equal(keyId) + expect(err.message).to.equal(`unknown key id: ${keyId}`) + expect(err.stack.split("\n")[0]).to.equal(`UnknownKeyIdError: unknown key id: ${keyId}`) + expect(err.stack.split("\n")[1].indexOf("throwUnknownKeyIdError")).to.equal(7) + } + }) }) diff --git a/src/UnknownKeyIdError.ts b/src/UnknownKeyIdError.ts index 70fcedf..f5f147e 100644 --- a/src/UnknownKeyIdError.ts +++ b/src/UnknownKeyIdError.ts @@ -1,20 +1,20 @@ -import { JsonWebTokenError } from "jsonwebtoken" +import {JsonWebTokenError} from "jsonwebtoken" /** * Error subclass for signaling that the given key id is not known */ export class UnknownKeyIdError extends JsonWebTokenError { - public keyId: string + public keyId: string - /** - * Creates a new instance with the specified key id - * @param {string} keyId The key id - */ - constructor(keyId: string) { - super("unknown key id: " + keyId) - this.name = this.constructor.name - Error.captureStackTrace(this, this.constructor) - this.keyId = keyId - } + /** + * Creates a new instance with the specified key id + * @param {string} keyId The key id + */ + constructor(keyId: string) { + super("unknown key id: " + keyId) + this.name = this.constructor.name + Error.captureStackTrace(this, this.constructor) + this.keyId = keyId + } } diff --git a/types/index.d.ts b/types/index.d.ts deleted file mode 100644 index e9d89da..0000000 --- a/types/index.d.ts +++ /dev/null @@ -1,25 +0,0 @@ -import * as Promise from "bluebird" -import {JsonWebTokenError, VerifyOptions} from "jsonwebtoken" - -export {TokenExpiredError, NotBeforeError, JsonWebTokenError} from "jsonwebtoken" - -type PublicKeyResolver = (keyId: string) => { cert: string, alg: string } | Promise<{ cert: string, alg: string }>; -type PrivateKeyResolver = (keyId: string) => { key: string, passphrase: string, alg: string } | Promise<{ key: string, passphrase: string, alg: string }>; - -export class MissingKeyIdError extends JsonWebTokenError { - constructor() -} - -export class UnknownKeyIdError extends JsonWebTokenError { - constructor(keyId: string) -} - -export interface HandlerObject { - extractKeyId(jwtRaw: string): Promise; - - verify(jwtRaw: string, options: VerifyOptions): Promise; - - create(tokenBody: string | Buffer | object, keyId: string): Promise; -} - -export function Handler(debugNamePrefix: string, publicKeyResolver?: PublicKeyResolver, privateKeyResolver?: PrivateKeyResolver): HandlerObject;