-
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f84bef9
commit b7e8c31
Showing
7 changed files
with
784 additions
and
765 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import { base64URLEncode } from "../src/index.js"; | ||
import crypto from "crypto"; | ||
import { expect } from "./index.js"; | ||
|
||
describe("#base64URLEncode()", function () { | ||
context("when string literal is used", function () { | ||
it("correctly base64url encodes the input", function () { | ||
const rndBytes = crypto.randomBytes(128); | ||
const rndBytesHexString = rndBytes.toString("hex"); | ||
const base64URLEncoded = base64URLEncode(rndBytesHexString); | ||
const base64URLEncodedFromBuffer = base64URLEncode(rndBytes); | ||
const bufferTransformed = Buffer.from( | ||
rndBytesHexString, | ||
"ascii" | ||
).toString("base64url"); | ||
const bufferTransformedFromBuffer = Buffer.from( | ||
rndBytes, | ||
"ascii" | ||
).toString("base64url"); | ||
expect( | ||
base64URLEncoded, | ||
"base64URLEncode returns the same thing as transforming with Buffer" | ||
).to.be.equal(bufferTransformed); | ||
expect( | ||
base64URLEncodedFromBuffer, | ||
"encodes from Buffer object" | ||
).to.be.equal(bufferTransformedFromBuffer); | ||
}); | ||
}); | ||
|
||
context("when Buffer is used", function () { | ||
it("correctly base64url encodes the input", function () { | ||
const rndBytes = crypto.randomBytes(128); | ||
const rndBytesHexString = rndBytes.toString("hex"); | ||
const base64URLEncoded = base64URLEncode(rndBytesHexString); | ||
const base64URLEncodedFromBuffer = base64URLEncode(rndBytes); | ||
const bufferTransformed = Buffer.from( | ||
rndBytesHexString, | ||
"ascii" | ||
).toString("base64url"); | ||
const bufferTransformedFromBuffer = Buffer.from( | ||
rndBytes, | ||
"ascii" | ||
).toString("base64url"); | ||
expect( | ||
base64URLEncoded, | ||
"base64URLEncode returns the same thing as transforming with Buffer" | ||
).to.be.equal(bufferTransformed); | ||
expect( | ||
base64URLEncodedFromBuffer, | ||
"encodes from Buffer object" | ||
).to.be.equal(bufferTransformedFromBuffer); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import { | ||
jwtDecode, | ||
jwtEncode, | ||
hs256Sign, | ||
createHeaderPayload, | ||
} from "../src/index.js"; | ||
import { expect } from "./index.js"; | ||
|
||
describe("#jwtEncode() and #jwtDecode()", function () { | ||
describe("JWT encoding then decoding", function () { | ||
context("when alg is HS256", function () { | ||
context("when deep equal used", function () { | ||
it("the decoding is equal when encoding then re-decoding", function () { | ||
const decodedHeader = { typ: "JWT", alg: "HS256" }; | ||
const decodedPayload = { | ||
"iss": "joe", | ||
"exp": 1300819380, | ||
"http://example.com/is_root": true, | ||
}; | ||
const passphrase = | ||
"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"; | ||
|
||
const expectedJWT = | ||
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.lliDzOlRAdGUCfCHCPx_uisb6ZfZ1LRQa0OJLeYTTpY"; | ||
const encoded = jwtEncode(decodedHeader, decodedPayload, passphrase); | ||
|
||
expect(encoded).to.equal(expectedJWT); | ||
|
||
const headerPayload = createHeaderPayload( | ||
decodedHeader, | ||
decodedPayload | ||
); | ||
const sig = hs256Sign(headerPayload, passphrase); | ||
const objOutput = { | ||
header: decodedHeader, | ||
payload: decodedPayload, | ||
signature: sig, | ||
}; | ||
const decoded = jwtDecode(encoded); | ||
expect(decoded).to.deep.equal(objOutput); | ||
}); | ||
}); | ||
}); | ||
}); | ||
|
||
describe("JWT decoding then encoding", function () { | ||
context("when alg is HS256", function () { | ||
context("when deep equal used", function () { | ||
it("the encoding is equal when decoding then re-encoding", function () { | ||
const decodedHeader = { typ: "JWT", alg: "HS256" }; | ||
const decodedPayload = { | ||
"iss": "joe", | ||
"exp": 1300819380, | ||
"http://example.com/is_root": true, | ||
}; | ||
const passphrase = | ||
"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"; | ||
|
||
const encodedJWT = | ||
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.lliDzOlRAdGUCfCHCPx_uisb6ZfZ1LRQa0OJLeYTTpY"; | ||
const decoded = jwtDecode(encodedJWT); | ||
|
||
const headerPayload = createHeaderPayload( | ||
decodedHeader, | ||
decodedPayload | ||
); | ||
const sig = hs256Sign(headerPayload, passphrase); | ||
const objOutput = { | ||
header: decodedHeader, | ||
payload: decodedPayload, | ||
signature: sig, | ||
}; | ||
expect(decoded).to.deep.equal(objOutput); | ||
|
||
const encoded = jwtEncode( | ||
objOutput.header, | ||
objOutput.payload, | ||
passphrase | ||
); | ||
|
||
expect(encoded).to.equal(encodedJWT); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,212 @@ | ||
import { base64URLEncode } from "../src/index.js"; | ||
import crypto from "crypto"; | ||
import cli, { HELP_TEXT } from "../cli/index.js"; | ||
import sinon from "sinon"; | ||
import { expect } from "./index.js"; | ||
|
||
describe("#cli()", function () { | ||
let sandbox; | ||
before(function () { | ||
sandbox = sinon.createSandbox(); | ||
}); | ||
beforeEach(function () { | ||
sandbox.restore(); | ||
}); | ||
|
||
describe("using help", function () { | ||
context("when argument is -h", function () { | ||
it("shows the help screen", function () { | ||
const log = sandbox.spy(console, "log"); | ||
// Mock process.argv | ||
const processArgv = [0, 0, "-h"]; | ||
cli(null, [0, 0, "-h"]); | ||
expect(log.calledOnceWith(HELP_TEXT)).to.be.true; | ||
}); | ||
}); | ||
|
||
context("when argument is --help", function () { | ||
it("shows the help screen", function () { | ||
const log = sandbox.spy(console, "log"); | ||
// Mock process.argv | ||
const processArgv = [0, 0, "-h"]; | ||
cli(null, [0, 0, "-h"]); | ||
expect(log.calledOnceWith(HELP_TEXT)).to.be.true; | ||
}); | ||
}); | ||
}); | ||
|
||
describe("mock using clipboard", function () { | ||
context("when 'clipboard' contains a jwt", function () { | ||
it("decodes the jwt", async function () { | ||
const log = sandbox.spy(console, "log"); | ||
const myCli = cli; | ||
const spy = sandbox.spy(myCli); | ||
|
||
const clipboard = | ||
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; | ||
const expectedOutput = { | ||
header: { alg: "HS256", typ: "JWT" }, | ||
payload: { sub: "1234567890", name: "John Doe", iat: 1516239022 }, | ||
signature: "SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c", | ||
}; | ||
const cliOutput = await spy(clipboard, null); | ||
|
||
expect( | ||
spy.calledOnceWith( | ||
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" | ||
) | ||
).to.be.true; | ||
expect(log.calledWith("Decoding: ")).to.be.true; | ||
expect( | ||
log.calledWith( | ||
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" | ||
) | ||
).to.be.true; | ||
expect( | ||
log.getCall(2).firstArg, | ||
"decoded jwt was logged to the console" | ||
).to.be.deep.equal(expectedOutput); | ||
expect(expectedOutput).to.be.deep.equal(cliOutput); | ||
}); | ||
}); | ||
|
||
context("when 'clipboard' doesn't contain a jwt", function () { | ||
context("when it's not an actual JWT", function () { | ||
it("throws a SyntaxError", async function () { | ||
const err = sandbox.spy(console, "error"); | ||
const clipboard = "abc.abc.abc"; | ||
let syntaxErr; | ||
|
||
await cli(clipboard, null); | ||
expect(err.called).to.be.true; | ||
|
||
expect(err.calledWith("I found an error :(")).to.be.true; | ||
}); | ||
}); | ||
|
||
context("when it doesn't contain a '.'", function () { | ||
it("logs an error: \"Need at least one '.'\"", async function () { | ||
const err = sandbox.spy(console, "error"); | ||
const spy = sandbox.spy(cli); | ||
const clipboard = "abc"; | ||
|
||
await spy(clipboard, null); | ||
|
||
expect(spy.called).to.be.true; | ||
expect(err.calledWith(" ", "Need at least one '.'")).to.be.true; | ||
}); | ||
}); | ||
}); | ||
}); | ||
|
||
describe("#base64urlEncode()", function () { | ||
context("when first given argument is -b", function () { | ||
it("properly base64url encodes the input", async function () { | ||
const log = sandbox.spy(console, "log"); | ||
const spy = sandbox.spy(cli); | ||
|
||
const b64u = | ||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; | ||
const rndBytes = crypto.randomBytes(128); | ||
const rndBytesHexString = rndBytes.toString("hex"); | ||
|
||
// Mock process.argv | ||
const processArgv = [0, 0, "-b", rndBytesHexString]; | ||
|
||
// call the command line function. it's an async function so wait for | ||
// result. | ||
const cliOut = await spy(null, processArgv); | ||
|
||
const base64urlified = base64URLEncode(rndBytesHexString); | ||
const bufferTransform = Buffer.from( | ||
rndBytesHexString, | ||
"ascii" | ||
).toString("base64url"); | ||
|
||
// Only called cli function once | ||
expect(spy.calledOnce, "cli function should be called once").to.be.true; | ||
expect( | ||
spy.calledOnceWith(null, processArgv), | ||
"cli should be called with -b and a string: " + processArgv | ||
).to.be.true; | ||
|
||
// Expect return value of cli function to be equal to using Buffer's transformation | ||
expect( | ||
cliOut, | ||
"cli output is equal to Buffer's conversion to a base64url string" | ||
).to.be.equal(bufferTransform); | ||
|
||
// Expect return value of cli function to be equal to directly calling base64URLEncode | ||
expect( | ||
cliOut, | ||
"cli output is equal to using the base64URLEncode function" | ||
).to.be.equal(base64urlified); | ||
|
||
// Cli outputs to console | ||
expect( | ||
log.calledOnceWith(cliOut), | ||
"the encoded string was output to the console" | ||
).to.be.true; | ||
|
||
// Make sure it's not just base64 encoded | ||
expect(cliOut.includes("+"), "no + symbols").to.be.false; | ||
expect(cliOut.includes("/"), "no / symbols").to.be.false; | ||
|
||
// Make sure all characters are part of the base64url char set | ||
for (let i = 0; i < cliOut.length; i++) { | ||
expect(b64u.includes(cliOut.charAt(i))).to.be.true; | ||
} | ||
}); | ||
}); | ||
|
||
context("when first given argument is --base64url", function () { | ||
it("properly base64url encodes the input", async function () { | ||
const log = sandbox.spy(console, "log"); | ||
const spy = sandbox.spy(cli); | ||
|
||
const b64u = | ||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; | ||
const rndBytes = crypto.randomBytes(128); | ||
const rndBytesHexString = rndBytes.toString("hex"); | ||
|
||
// Mock process.argv | ||
const processArgv = [0, 0, "-b", rndBytesHexString]; | ||
|
||
// call the command line function. it's an async function so wait for | ||
// result. | ||
const cliOut = await spy(null, processArgv); | ||
|
||
const base64urlified = base64URLEncode(rndBytesHexString); | ||
const bufferTransform = Buffer.from( | ||
rndBytesHexString, | ||
"ascii" | ||
).toString("base64url"); | ||
|
||
expect(spy.calledOnce, "cli function should be called once").to.be.true; | ||
expect( | ||
spy.calledWith(null, processArgv), | ||
"cli should be called with -b and a string: " + processArgv | ||
).to.be.true; | ||
expect( | ||
cliOut, | ||
"cli output is equal to Buffer's conversion to a base64url string" | ||
).to.be.equal(bufferTransform); | ||
expect( | ||
cliOut, | ||
"cli output is equal to using the base64URLEncode function" | ||
).to.be.equal(base64urlified); | ||
expect( | ||
log.calledWith(cliOut), | ||
"the encoded string was output to the console" | ||
).to.be.true; | ||
expect(cliOut.includes("+"), "no + symbols").to.be.false; | ||
expect(cliOut.includes("/"), "no / symbols").to.be.false; | ||
|
||
// Make sure all characters are part of the base64url char set | ||
for (let i = 0; i < cliOut.length; i++) { | ||
expect(b64u.includes(cliOut.charAt(i))).to.be.true; | ||
} | ||
}); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.