Skip to content

Commit

Permalink
rm node:crypto
Browse files Browse the repository at this point in the history
  • Loading branch information
nichoth committed Oct 27, 2024
1 parent 0e48d99 commit ceb820c
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 29 deletions.
64 changes: 41 additions & 23 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const SESSION_COOKIE_NAME_DEFAULT = 'session'
* Length of the signature digest, in characters.
* Used to separate signature from data in the raw session cookie.
*/
const SIGNATURE_DIGEST_LENGTH = 27
const SIGNATURE_DIGEST_LENGTH = 43

/**
* Parse the given cookie string into an object of key - values.
Expand Down Expand Up @@ -81,13 +81,13 @@ export function setCookie (
* @param name The name for the cookie; defaults to `session`
* @returns {string} The cookie as string
*/
export function createCookie (
export async function createCookie (
sessionData:Record<string, string>,
secretKey:string,
name?:string,
env?:CookieEnv,
):string {
const session = createSession(sessionData, secretKey)
):Promise<string> {
const session = await createSession(sessionData, secretKey)
const newCookie = serializeCookie(
name || SESSION_COOKIE_NAME_DEFAULT,
session,
Expand All @@ -105,17 +105,18 @@ export function createCookie (
* environment variables if it is not passed in.
* @returns {string} Signature + JSON session data encoded as base64
*/
export function createSession (
export async function createSession (
newSessionData:Record<string, string>,
secretKey:string
):string {
):Promise<string> {
const key = secretKey
const sessionAsJSON:string = stringify(newSessionData)

const arrFromString = fromString(sessionAsJSON, 'utf-8')
const base64Json = toString(arrFromString, 'base64')
const sig = await sign(sessionAsJSON, key)
// sig + base64SessionValue
const session = sign(sessionAsJSON, key) + base64Json
const session = sig + base64Json

return session
}
Expand All @@ -135,9 +136,6 @@ export async function verifySessionString (
SIGNATURE_DIGEST_LENGTH
)

console.log('session string', session)
console.log('signature string', signature)

try {
let data:string = session.substring(SIGNATURE_DIGEST_LENGTH)
// data = Buffer.from(data, 'base64').toString('utf-8')
Expand All @@ -160,28 +158,48 @@ export async function verifySessionString (
*/
async function verify (
key:string,
data:Buffer|string,
data:Uint8Array|string,
signature:string
):Promise<boolean> {
return await compare(signature, sign(data, key))
return await compare(signature, await sign(
typeof data === 'string' ? fromString(data) : data,
key
))
}

/**
* Sign the given data and return the signature as a string.
*
* @returns {string}
*/
export function sign (data:Buffer|string, key:string, opts?:Partial<{
algorithm:'sha1'|'sha256'|'sha512';
}>):string {
const algorithm = opts?.algorithm || 'sha1'

return crypto
.createHmac(algorithm, key)
.update(data).digest('base64')
.replace(/\/|\+|=/g, (x) => {
return ({ '/': '_', '+': '-', '=': '' })[x] as string
})
export async function sign (data:string|Uint8Array, key:string, opts?:Partial<{
algorithm:'sha-256'|'sha-512';
}>):Promise<string> {
const algorithm = opts?.algorithm || 'sha-256'

// this gets called with `sessionDataAsJSON` for data param,
// so if string, it is not base64 encoded

const signingKey = await webcrypto.subtle.importKey(
'raw',
fromString(key, 'base64'),
{ name: 'HMAC', hash: algorithm },
false,
['sign', 'verify']
)

const sig = await webcrypto.subtle.sign(
'HMAC',
signingKey,
typeof data === 'string' ? fromString(data) : data
)
const sigString = toString(new Uint8Array(sig), 'base64')

const str = sigString.replace(/\/|\+|=/g, (x) => {
return ({ '/': '_', '+': '-', '=': '' })[x] as string
})

return str
}

/**
Expand Down
13 changes: 7 additions & 6 deletions test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const SECRET_KEY = '/pQCobVcOc+ru0WVTx24+MlCL7fIAPcPTsgGqXvV8M0='

let session:string
test('create a session', async t => {
session = createSession({ hello: 'world' }, SECRET_KEY)
session = await createSession({ hello: 'world' }, SECRET_KEY)
t.equal(typeof session, 'string', 'should return a new session string')
})

Expand All @@ -28,9 +28,8 @@ test('verify an invalid session', async t => {
})

let cookie
test('create a cookie', t => {
cookie = createCookie({ hello: 'world' }, SECRET_KEY)
console.log('**cookie**', cookie)
test('create a cookie', async t => {
cookie = await createCookie({ hello: 'world' }, SECRET_KEY)
t.equal(typeof cookie, 'string', 'should return a string')
t.ok(cookie.includes('session='), 'should include the default session name')
})
Expand All @@ -56,9 +55,11 @@ test('Cookie in the headers', t => {

let parsed:ReturnType<typeof parseCookie>
test('parse a cookie', async t => {
parsed = parseCookie('session=vTAHUs4nBS65UPy4AdnIMVdh-5MeyJoZWxsbyI6IndvcmxkIn0; Max-Age=604800; Path=/; HttpOnly; Secure; SameSite=Lax')
t.plan(2)
parsed = parseCookie('session=N6bimY9qCPv7HdQ8NX1w6gUpuCU4tNawWwY0EvL3smAeyJoZWxsbyI6IndvcmxkIn0; Max-Age=604800; Path=/; HttpOnly; Secure; SameSite=Lax')

t.deepEqual(parsed, {
session: 'vTAHUs4nBS65UPy4AdnIMVdh-5MeyJoZWxsbyI6IndvcmxkIn0',
session: 'N6bimY9qCPv7HdQ8NX1w6gUpuCU4tNawWwY0EvL3smAeyJoZWxsbyI6IndvcmxkIn0',
'Max-Age': '604800',
Path: '/',
HttpOnly: true,
Expand Down

0 comments on commit ceb820c

Please sign in to comment.