Skip to content

Commit

Permalink
fix(deps): remove dev dependency did-key-creator (#274)
Browse files Browse the repository at this point in the history
  • Loading branch information
nickreynolds authored Mar 15, 2023
1 parent f57acc8 commit fbe09e1
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 213 deletions.
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@
"@typescript-eslint/eslint-plugin": "5.52.0",
"@typescript-eslint/parser": "5.52.0",
"codecov": "3.8.3",
"did-key-creator": "^0.3.2",
"eslint": "8.34.0",
"eslint-config-prettier": "8.6.0",
"eslint-plugin-jest": "26.9.0",
Expand Down
291 changes: 148 additions & 143 deletions src/__tests__/JWT.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import { ES256Signer } from '../signers/ES256Signer'
import * as jwt from 'jsonwebtoken'
import * as u8a from 'uint8arrays'
import * as jwkToPem from 'jwk-to-pem'
import { encodeDIDfromHexString } from 'did-key-creator'

const NOW = 1485321133
MockDate.set(NOW * 1000 + 123)
Expand Down Expand Up @@ -121,151 +120,156 @@ const audDidDoc = {

describe('createJWT()', () => {
describe('ES256', () => {
const alg = 'ES256'
const privateKey = '736f625c9dda78a94bb16840c82779bb7bc18014b8ede52f0f03429902fc4ba8'
const publicKey = '0314c58e581c7656ba153195669fe4ce53ff78dd5ede60a4039771a90c58cb41de'
const publicKey_x = '14c58e581c7656ba153195669fe4ce53ff78dd5ede60a4039771a90c58cb41de'
const publicKey_y = 'ec41869995bd661849414c523c7dff9a96f1c8dbc2e5e78172118f91c7199869'
// construct did:key for secp256r1 (unlike did for secp256k1 which is for an Ethereum Address)
const multicodecName = 'p256-pub';
const did = encodeDIDfromHexString(multicodecName,publicKey)

const signer = ES256Signer(hexToBytes(privateKey))

interface privateJsonWebKey extends JsonWebKey {
d?: string
}

// verifyTokenFormAndValidity
function verifyTokenFormAndValidity(token: string, pemPublic: string): boolean {
let result = null
try {
jwt.verify(token, pemPublic)
result = true
} catch (e) {
console.error(e.name + ': ' + e.message)
result = false
}
return result
}

// input public key in hex, and export pem
function publicToJWK(
publicPointHex_x: string,
publicPointHex_y: string,
kty_value: string,
crv_value: string
): JsonWebKey {
if (publicPointHex_x.length % 2 != 0) {
publicPointHex_x = '0' + publicPointHex_x
}
if (publicPointHex_y.length % 2 != 0) {
publicPointHex_y = '0' + publicPointHex_y
}
const publicPointUint8_x = u8a.fromString(publicPointHex_x, 'hex')
const publicPointBase64URL_x = u8a.toString(publicPointUint8_x, 'base64url')
const publicPointUint8_y = u8a.fromString(publicPointHex_y, 'hex')
const publicPointBase64URL_y = u8a.toString(publicPointUint8_y, 'base64url')
return {
kty: kty_value,
crv: crv_value,
x: publicPointBase64URL_x,
y: publicPointBase64URL_y,
}
}
const alg = 'ES256'
const privateKey = '736f625c9dda78a94bb16840c82779bb7bc18014b8ede52f0f03429902fc4ba8'
const publicKey_x = '14c58e581c7656ba153195669fe4ce53ff78dd5ede60a4039771a90c58cb41de'
const publicKey_y = 'ec41869995bd661849414c523c7dff9a96f1c8dbc2e5e78172118f91c7199869'


// input private key in hex, and export pem
function privateToJWK(privatePointHex: string, kty_value: string, crv_value: string): privateJsonWebKey {
if (privatePointHex.length % 2 != 0) {
privatePointHex = '0' + privatePointHex
}
const privatePointUint8 = u8a.fromString(privatePointHex, 'hex')
const privatePointBase64URL = u8a.toString(privatePointUint8, 'base64url')
return {
kty: kty_value,
crv: crv_value,
d: privatePointBase64URL,
}
// construct did:key for secp256r1 (unlike did for secp256k1 which is for an Ethereum Address)
// This originally was constructed by `encodeDIDfromHextString` imported from `did-key-creator`
// package, but that dependency was removed, so now `did` is just hardcoded
// const multicodecName = 'p256-pub';
// const publicKey = '0314c58e581c7656ba153195669fe4ce53ff78dd5ede60a4039771a90c58cb41de'
// const did = encodeDIDfromHexString(multicodecName,publicKey)
const did = 'did:key:zDnaej4NHntda4rNW4FBUJgFzdcgEAXKGRVGE8LuVfRbuMuc1'

const signer = ES256Signer(hexToBytes(privateKey))

interface privateJsonWebKey extends JsonWebKey {
d?: string
}

// verifyTokenFormAndValidity
function verifyTokenFormAndValidity(token: string, pemPublic: string): boolean {
let result = null
try {
jwt.verify(token, pemPublic)
result = true
} catch (e) {
console.error(e.name + ': ' + e.message)
result = false
}
return result
}

it('creates a valid JWT', async () => {
expect.assertions(1)
const jwt = await createJWT({ requested: ['name', 'phone'] }, { issuer: did, signer },{alg: 'ES256'})
const pemPublic = jwkToPem.default(publicToJWK(publicKey_x,publicKey_y,'EC','P-256'))
expect(verifyTokenFormAndValidity(jwt,pemPublic)).toBe(true)
})
// input public key in hex, and export pem
function publicToJWK(
publicPointHex_x: string,
publicPointHex_y: string,
kty_value: string,
crv_value: string
): JsonWebKey {
if (publicPointHex_x.length % 2 != 0) {
publicPointHex_x = '0' + publicPointHex_x
}
if (publicPointHex_y.length % 2 != 0) {
publicPointHex_y = '0' + publicPointHex_y
}
const publicPointUint8_x = u8a.fromString(publicPointHex_x, 'hex')
const publicPointBase64URL_x = u8a.toString(publicPointUint8_x, 'base64url')
const publicPointUint8_y = u8a.fromString(publicPointHex_y, 'hex')
const publicPointBase64URL_y = u8a.toString(publicPointUint8_y, 'base64url')
return {
kty: kty_value,
crv: crv_value,
x: publicPointBase64URL_x,
y: publicPointBase64URL_y,
}
}

it('creates a valid JWT using a MNID', async () => {
expect.assertions(1)
const jwt = await createJWT({ requested: ['name', 'phone'] }, { issuer: address, signer },{alg: 'ES256'})
const pemPublic = jwkToPem.default(publicToJWK(publicKey_x,publicKey_y,'EC','P-256'))
expect(verifyTokenFormAndValidity(jwt,pemPublic)).toBe(true)
})

it('creates a JWT with correct format', async () => {
expect.assertions(1)
const jwt = await createJWT({ requested: ['name', 'phone'] }, { issuer: did, signer },{alg: 'ES256'})
return expect(decodeJWT(jwt)).toMatchSnapshot()
})

it('creates a JWT with correct legacy format', async () => {
expect.assertions(1)
const jwt = await createJWT({ requested: ['name', 'phone'] }, { issuer: address, signer },{alg: 'ES256'})
return expect(decodeJWT(jwt)).toMatchSnapshot()
})

it('creates a JWT with expiry in 10000 seconds', async () => {
expect.assertions(1)
const jwt = await createJWT(
{
requested: ['name', 'phone'],
nbf: Math.floor(new Date().getTime() / 1000),
},
{ issuer: did, signer, expiresIn: 10000 },
{alg: 'ES256'}
// input private key in hex, and export pem
function privateToJWK(privatePointHex: string, kty_value: string, crv_value: string): privateJsonWebKey {
if (privatePointHex.length % 2 != 0) {
privatePointHex = '0' + privatePointHex
}
const privatePointUint8 = u8a.fromString(privatePointHex, 'hex')
const privatePointBase64URL = u8a.toString(privatePointUint8, 'base64url')
return {
kty: kty_value,
crv: crv_value,
d: privatePointBase64URL,
}
}

it('creates a valid JWT', async () => {
expect.assertions(1)
const jwt = await createJWT({ requested: ['name', 'phone'] }, { issuer: did, signer },{alg: 'ES256'})
const pemPublic = jwkToPem.default(publicToJWK(publicKey_x,publicKey_y,'EC','P-256'))
expect(verifyTokenFormAndValidity(jwt,pemPublic)).toBe(true)
})

it('creates a valid JWT using a MNID', async () => {
expect.assertions(1)
const jwt = await createJWT({ requested: ['name', 'phone'] }, { issuer: address, signer },{alg: 'ES256'})
const pemPublic = jwkToPem.default(publicToJWK(publicKey_x,publicKey_y,'EC','P-256'))
expect(verifyTokenFormAndValidity(jwt,pemPublic)).toBe(true)
})

it('creates a JWT with correct format', async () => {
expect.assertions(1)
const jwt = await createJWT({ requested: ['name', 'phone'] }, { issuer: did, signer },{alg: 'ES256'})
return expect(decodeJWT(jwt)).toMatchSnapshot()
})

it('creates a JWT with correct legacy format', async () => {
expect.assertions(1)
const jwt = await createJWT({ requested: ['name', 'phone'] }, { issuer: address, signer },{alg: 'ES256'})
return expect(decodeJWT(jwt)).toMatchSnapshot()
})

it('creates a JWT with expiry in 10000 seconds', async () => {
expect.assertions(1)
const jwt = await createJWT(
{
requested: ['name', 'phone'],
nbf: Math.floor(new Date().getTime() / 1000),
},
{ issuer: did, signer, expiresIn: 10000 },
{alg: 'ES256'}
)
const { payload } = decodeJWT(jwt)
return expect(payload.exp).toEqual(payload.nbf + 10000)
})
it('Uses iat if nbf is not defined but expiresIn is included', async () => {
expect.assertions(1)
const { payload } = decodeJWT(
await createJWT({ requested: ['name', 'phone'] }, { issuer: did, signer, expiresIn: 10000 },{alg: 'ES256'})
)
return expect(payload.exp).toEqual(payload.iat + 10000)
})
it('sets iat to the current time by default', async () => {
expect.assertions(1)
const timestamp = Math.floor(Date.now() / 1000)
const { payload } = decodeJWT(await createJWT({ requested: ['name', 'phone'] }, { issuer: did, signer },{alg: 'ES256'}))
return expect(payload.iat).toEqual(timestamp)
})
it('sets iat to the value passed in payload', async () => {
expect.assertions(1)
const timestamp = 2000000
const { payload } = decodeJWT(
await createJWT({ requested: ['name', 'phone'], iat: timestamp }, { issuer: did, signer },{alg: 'ES256'})
)
return expect(payload.iat).toEqual(timestamp)
})
it('does not set iat if value in payload is undefined', async () => {
expect.assertions(1)
const { payload } = decodeJWT(
await createJWT({ requested: ['name', 'phone'], iat: undefined }, { issuer: did, signer },{alg: 'ES256'})
)
return expect(payload.iat).toBeUndefined()
})
it('throws an error if unsupported algorithm is passed in', async () => {
expect.assertions(1)
await expect(
createJWT({ requested: ['name', 'phone'] }, { issuer: did, signer, alg: 'BADALGO' })
).rejects.toThrowError('Unsupported algorithm BADALGO')
})
const { payload } = decodeJWT(jwt)
return expect(payload.exp).toEqual(payload.nbf + 10000)
})

it('Uses iat if nbf is not defined but expiresIn is included', async () => {
expect.assertions(1)
const { payload } = decodeJWT(
await createJWT({ requested: ['name', 'phone'] }, { issuer: did, signer, expiresIn: 10000 },{alg: 'ES256'})
)
return expect(payload.exp).toEqual(payload.iat + 10000)
})

it('sets iat to the current time by default', async () => {
expect.assertions(1)
const timestamp = Math.floor(Date.now() / 1000)
const { payload } = decodeJWT(await createJWT({ requested: ['name', 'phone'] }, { issuer: did, signer },{alg: 'ES256'}))
return expect(payload.iat).toEqual(timestamp)
})

it('sets iat to the value passed in payload', async () => {
expect.assertions(1)
const timestamp = 2000000
const { payload } = decodeJWT(
await createJWT({ requested: ['name', 'phone'], iat: timestamp }, { issuer: did, signer },{alg: 'ES256'})
)
return expect(payload.iat).toEqual(timestamp)
})

it('does not set iat if value in payload is undefined', async () => {
expect.assertions(1)
const { payload } = decodeJWT(
await createJWT({ requested: ['name', 'phone'], iat: undefined }, { issuer: did, signer },{alg: 'ES256'})
)
return expect(payload.iat).toBeUndefined()
})

it('throws an error if unsupported algorithm is passed in', async () => {
expect.assertions(1)
await expect(
createJWT({ requested: ['name', 'phone'] }, { issuer: did, signer, alg: 'BADALGO' })
).rejects.toThrowError('Unsupported algorithm BADALGO')
})

})
})
Expand Down Expand Up @@ -441,8 +445,9 @@ describe('verifyJWT() for ES256', () => {
const publicKey_x = '14c58e581c7656ba153195669fe4ce53ff78dd5ede60a4039771a90c58cb41de'
const publicKey_y = 'ec41869995bd661849414c523c7dff9a96f1c8dbc2e5e78172118f91c7199869'
// construct did:key for secp256r1 (unlike did for secp256k1 which is for an Ethereum Address)
const multicodecName = 'p256-pub';
const did = encodeDIDfromHexString(multicodecName,publicKey)
// const multicodecName = 'p256-pub';
// const did = encodeDIDfromHexString(multicodecName,publicKey)
const did = 'did:key:zDnaej4NHntda4rNW4FBUJgFzdcgEAXKGRVGE8LuVfRbuMuc1'

const didDoc = {
didDocument: {
Expand Down
Loading

0 comments on commit fbe09e1

Please sign in to comment.