refactor and add more test cases

This commit is contained in:
Sepehr Safari 2024-01-17 18:13:10 +03:30
parent 75eb08b170
commit 5ec136a365
1 changed files with 294 additions and 103 deletions

View File

@ -1,76 +1,83 @@
import { describe, test, expect } from 'bun:test'
import { getToken, unpackEventFromToken, validateEvent, validateToken } from './nip98.ts'
import { Event, finalizeEvent } from './pure.ts'
import { generateSecretKey, getPublicKey } from './pure.ts'
import { sha256 } from '@noble/hashes/sha256' import { sha256 } from '@noble/hashes/sha256'
import { utf8Encoder } from './utils.ts'
import { bytesToHex } from '@noble/hashes/utils' import { bytesToHex } from '@noble/hashes/utils'
import { HTTPAuth } from './kinds.ts' import { describe, expect, test } from 'bun:test'
const sk = generateSecretKey() import { HTTPAuth } from './kinds.ts'
import {
getToken,
hashPayload,
unpackEventFromToken,
validateEvent,
validateEventKind,
validateEventMethodTag,
validateEventPayloadTag,
validateEventTimestamp,
validateEventUrlTag,
validateToken,
} from './nip98.ts'
import { Event, finalizeEvent, generateSecretKey, getPublicKey } from './pure.ts'
import { utf8Encoder } from './utils.ts'
describe('getToken', () => { describe('getToken', () => {
test('getToken GET returns without authorization scheme', async () => { test('returns without authorization scheme for GET', async () => {
let result = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk)) const sk = generateSecretKey()
const token = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk))
const unpackedEvent: Event = await unpackEventFromToken(token)
const decodedResult: Event = await unpackEventFromToken(result) expect(unpackedEvent.created_at).toBeGreaterThan(0)
expect(unpackedEvent.content).toBe('')
expect(decodedResult.created_at).toBeGreaterThan(0) expect(unpackedEvent.kind).toBe(HTTPAuth)
expect(decodedResult.content).toBe('') expect(unpackedEvent.pubkey).toBe(getPublicKey(sk))
expect(decodedResult.kind).toBe(HTTPAuth) expect(unpackedEvent.tags).toStrictEqual([
expect(decodedResult.pubkey).toBe(getPublicKey(sk))
expect(decodedResult.tags).toStrictEqual([
['u', 'http://test.com'], ['u', 'http://test.com'],
['method', 'get'], ['method', 'get'],
]) ])
}) })
test('getToken POST returns token without authorization scheme', async () => { test('returns token without authorization scheme for POST', async () => {
let result = await getToken('http://test.com', 'post', e => finalizeEvent(e, sk)) const sk = generateSecretKey()
const token = await getToken('http://test.com', 'post', e => finalizeEvent(e, sk))
const unpackedEvent: Event = await unpackEventFromToken(token)
const decodedResult: Event = await unpackEventFromToken(result) expect(unpackedEvent.created_at).toBeGreaterThan(0)
expect(unpackedEvent.content).toBe('')
expect(decodedResult.created_at).toBeGreaterThan(0) expect(unpackedEvent.kind).toBe(HTTPAuth)
expect(decodedResult.content).toBe('') expect(unpackedEvent.pubkey).toBe(getPublicKey(sk))
expect(decodedResult.kind).toBe(HTTPAuth) expect(unpackedEvent.tags).toStrictEqual([
expect(decodedResult.pubkey).toBe(getPublicKey(sk))
expect(decodedResult.tags).toStrictEqual([
['u', 'http://test.com'], ['u', 'http://test.com'],
['method', 'post'], ['method', 'post'],
]) ])
}) })
test('getToken GET returns token WITH authorization scheme', async () => { test('returns token WITH authorization scheme for POST', async () => {
const authorizationScheme = 'Nostr ' const authorizationScheme = 'Nostr '
const sk = generateSecretKey()
const token = await getToken('http://test.com', 'post', e => finalizeEvent(e, sk), true)
const unpackedEvent: Event = await unpackEventFromToken(token)
let result = await getToken('http://test.com', 'post', e => finalizeEvent(e, sk), true) expect(token.startsWith(authorizationScheme)).toBe(true)
expect(unpackedEvent.created_at).toBeGreaterThan(0)
expect(result.startsWith(authorizationScheme)).toBe(true) expect(unpackedEvent.content).toBe('')
expect(unpackedEvent.kind).toBe(HTTPAuth)
const decodedResult: Event = await unpackEventFromToken(result) expect(unpackedEvent.pubkey).toBe(getPublicKey(sk))
expect(unpackedEvent.tags).toStrictEqual([
expect(decodedResult.created_at).toBeGreaterThan(0)
expect(decodedResult.content).toBe('')
expect(decodedResult.kind).toBe(HTTPAuth)
expect(decodedResult.pubkey).toBe(getPublicKey(sk))
expect(decodedResult.tags).toStrictEqual([
['u', 'http://test.com'], ['u', 'http://test.com'],
['method', 'post'], ['method', 'post'],
]) ])
}) })
test('getToken returns token with a valid payload tag when payload is present', async () => { test('returns token with a valid payload tag when payload is present', async () => {
const sk = generateSecretKey()
const payload = { test: 'payload' } const payload = { test: 'payload' }
const payloadHash = bytesToHex(sha256(utf8Encoder.encode(JSON.stringify(payload)))) const payloadHash = hashPayload(payload)
let result = await getToken('http://test.com', 'post', e => finalizeEvent(e, sk), true, payload) const token = await getToken('http://test.com', 'post', e => finalizeEvent(e, sk), true, payload)
const unpackedEvent: Event = await unpackEventFromToken(token)
const decodedResult: Event = await unpackEventFromToken(result) expect(unpackedEvent.created_at).toBeGreaterThan(0)
expect(unpackedEvent.content).toBe('')
expect(decodedResult.created_at).toBeGreaterThan(0) expect(unpackedEvent.kind).toBe(HTTPAuth)
expect(decodedResult.content).toBe('') expect(unpackedEvent.pubkey).toBe(getPublicKey(sk))
expect(decodedResult.kind).toBe(HTTPAuth) expect(unpackedEvent.tags).toStrictEqual([
expect(decodedResult.pubkey).toBe(getPublicKey(sk))
expect(decodedResult.tags).toStrictEqual([
['u', 'http://test.com'], ['u', 'http://test.com'],
['method', 'post'], ['method', 'post'],
['payload', payloadHash], ['payload', payloadHash],
@ -79,81 +86,265 @@ describe('getToken', () => {
}) })
describe('validateToken', () => { describe('validateToken', () => {
test('validateToken returns true for valid token without authorization scheme', async () => { test('returns true for valid token without authorization scheme', async () => {
const validToken = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk)) const sk = generateSecretKey()
const token = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk))
const result = await validateToken(validToken, 'http://test.com', 'get') const isTokenValid = await validateToken(token, 'http://test.com', 'get')
expect(result).toBe(true) expect(isTokenValid).toBe(true)
}) })
test('validateToken returns true for valid token with authorization scheme', async () => { test('returns true for valid token with authorization scheme', async () => {
const validToken = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk), true) const sk = generateSecretKey()
const token = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk), true)
const isTokenValid = await validateToken(token, 'http://test.com', 'get')
const result = await validateToken(validToken, 'http://test.com', 'get') expect(isTokenValid).toBe(true)
expect(result).toBe(true)
}) })
test('validateToken throws an error for invalid token', async () => { test('throws an error for invalid token', async () => {
const result = validateToken('fake', 'http://test.com', 'get') const isTokenValid = validateToken('fake', 'http://test.com', 'get')
expect(result).rejects.toThrow(Error)
expect(isTokenValid).rejects.toThrow(Error)
}) })
test('validateToken throws an error for missing token', async () => { test('throws an error for missing token', async () => {
const result = validateToken('', 'http://test.com', 'get') const isTokenValid = validateToken('', 'http://test.com', 'get')
expect(result).rejects.toThrow(Error)
expect(isTokenValid).rejects.toThrow(Error)
}) })
test('validateToken throws an error for a wrong url', async () => { test('throws an error for invalid event kind', async () => {
const validToken = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk)) const sk = generateSecretKey()
const invalidToken = await getToken('http://test.com', 'get', e => {
e.kind = 0
return finalizeEvent(e, sk)
})
const isTokenValid = validateToken(invalidToken, 'http://test.com', 'get')
const result = validateToken(validToken, 'http://wrong-test.com', 'get') expect(isTokenValid).rejects.toThrow(Error)
expect(result).rejects.toThrow(Error)
}) })
test('validateToken throws an error for a wrong method', async () => { test('throws an error for invalid event timestamp', async () => {
const validToken = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk)) const sk = generateSecretKey()
const invalidToken = await getToken('http://test.com', 'get', e => {
e.created_at = 0
return finalizeEvent(e, sk)
})
const isTokenValid = validateToken(invalidToken, 'http://test.com', 'get')
const result = validateToken(validToken, 'http://test.com', 'post') expect(isTokenValid).rejects.toThrow(Error)
expect(result).rejects.toThrow(Error)
}) })
test('validateEvent returns true for valid decoded token with authorization scheme', async () => { test('throws an error for invalid url', async () => {
const validToken = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk), true) const sk = generateSecretKey()
const decodedResult: Event = await unpackEventFromToken(validToken) const token = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk))
const isTokenValid = validateToken(token, 'http://wrong-test.com', 'get')
const result = await validateEvent(decodedResult, 'http://test.com', 'get') expect(isTokenValid).rejects.toThrow(Error)
expect(result).toBe(true)
}) })
test('validateEvent throws an error for a wrong url', async () => { test('throws an error for invalid method', async () => {
const validToken = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk), true) const sk = generateSecretKey()
const decodedResult: Event = await unpackEventFromToken(validToken) const token = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk))
const isTokenValid = validateToken(token, 'http://test.com', 'post')
const result = validateEvent(decodedResult, 'http://wrong-test.com', 'get') expect(isTokenValid).rejects.toThrow(Error)
expect(result).rejects.toThrow(Error) })
}) })
test('validateEvent throws an error for a wrong method', async () => { describe('validateEvent', () => {
const validToken = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk), true) test('returns true for valid decoded token with authorization scheme', async () => {
const decodedResult: Event = await unpackEventFromToken(validToken) const sk = generateSecretKey()
const token = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk), true)
const result = validateEvent(decodedResult, 'http://test.com', 'post') const unpackedEvent: Event = await unpackEventFromToken(token)
expect(result).rejects.toThrow(Error) const isEventValid = await validateEvent(unpackedEvent, 'http://test.com', 'get')
})
expect(isEventValid).toBe(true)
test('validateEvent returns true for valid payload tag hash', async () => { })
const validToken = await getToken('http://test.com', 'post', e => finalizeEvent(e, sk), true, { test: 'payload' })
const decodedResult: Event = await unpackEventFromToken(validToken) test('throws an error for invalid event kind', async () => {
const sk = generateSecretKey()
const result = await validateEvent(decodedResult, 'http://test.com', 'post', { test: 'payload' }) const token = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk), true)
expect(result).toBe(true) const unpackedEvent: Event = await unpackEventFromToken(token)
}) unpackedEvent.kind = 0
const isEventValid = validateEvent(unpackedEvent, 'http://test.com', 'get')
test('validateEvent returns false for invalid payload tag hash', async () => {
const validToken = await getToken('http://test.com', 'post', e => finalizeEvent(e, sk), true, { test: 'a-payload' }) expect(isEventValid).rejects.toThrow(Error)
const decodedResult: Event = await unpackEventFromToken(validToken) })
const result = validateEvent(decodedResult, 'http://test.com', 'post', { test: 'a-different-payload' }) test('throws an error for invalid event timestamp', async () => {
expect(result).rejects.toThrow(Error) const sk = generateSecretKey()
const token = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk), true)
const unpackedEvent: Event = await unpackEventFromToken(token)
unpackedEvent.created_at = 0
const isEventValid = validateEvent(unpackedEvent, 'http://test.com', 'get')
expect(isEventValid).rejects.toThrow(Error)
})
test('throws an error for invalid url tag', async () => {
const sk = generateSecretKey()
const token = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk), true)
const unpackedEvent: Event = await unpackEventFromToken(token)
const isEventValid = validateEvent(unpackedEvent, 'http://wrong-test.com', 'get')
expect(isEventValid).rejects.toThrow(Error)
})
test('throws an error for invalid method tag', async () => {
const sk = generateSecretKey()
const token = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk), true)
const unpackedEvent: Event = await unpackEventFromToken(token)
const isEventValid = validateEvent(unpackedEvent, 'http://test.com', 'post')
expect(isEventValid).rejects.toThrow(Error)
})
test('returns true for valid payload tag hash', async () => {
const sk = generateSecretKey()
const token = await getToken('http://test.com', 'post', e => finalizeEvent(e, sk), true, { test: 'payload' })
const unpackedEvent: Event = await unpackEventFromToken(token)
const isEventValid = await validateEvent(unpackedEvent, 'http://test.com', 'post', { test: 'payload' })
expect(isEventValid).toBe(true)
})
test('returns false for invalid payload tag hash', async () => {
const sk = generateSecretKey()
const token = await getToken('http://test.com', 'post', e => finalizeEvent(e, sk), true, { test: 'a-payload' })
const unpackedEvent: Event = await unpackEventFromToken(token)
const isEventValid = validateEvent(unpackedEvent, 'http://test.com', 'post', { test: 'a-different-payload' })
expect(isEventValid).rejects.toThrow(Error)
})
})
describe('validateEventTimestamp', () => {
test('returns true for valid timestamp', async () => {
const sk = generateSecretKey()
const token = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk), true)
const unpackedEvent: Event = await unpackEventFromToken(token)
const isEventTimestampValid = validateEventTimestamp(unpackedEvent)
expect(isEventTimestampValid).toBe(true)
})
test('returns false for invalid timestamp', async () => {
const sk = generateSecretKey()
const token = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk), true)
const unpackedEvent: Event = await unpackEventFromToken(token)
unpackedEvent.created_at = 0
const isEventTimestampValid = validateEventTimestamp(unpackedEvent)
expect(isEventTimestampValid).toBe(false)
})
})
describe('validateEventKind', () => {
test('returns true for valid kind', async () => {
const sk = generateSecretKey()
const token = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk), true)
const unpackedEvent: Event = await unpackEventFromToken(token)
const isEventKindValid = validateEventKind(unpackedEvent)
expect(isEventKindValid).toBe(true)
})
test('returns false for invalid kind', async () => {
const sk = generateSecretKey()
const token = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk), true)
const unpackedEvent: Event = await unpackEventFromToken(token)
unpackedEvent.kind = 0
const isEventKindValid = validateEventKind(unpackedEvent)
expect(isEventKindValid).toBe(false)
})
})
describe('validateEventUrlTag', () => {
test('returns true for valid url tag', async () => {
const sk = generateSecretKey()
const token = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk), true)
const unpackedEvent: Event = await unpackEventFromToken(token)
const isEventUrlTagValid = validateEventUrlTag(unpackedEvent, 'http://test.com')
expect(isEventUrlTagValid).toBe(true)
})
test('returns false for invalid url tag', async () => {
const sk = generateSecretKey()
const token = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk), true)
const unpackedEvent: Event = await unpackEventFromToken(token)
const isEventUrlTagValid = validateEventUrlTag(unpackedEvent, 'http://wrong-test.com')
expect(isEventUrlTagValid).toBe(false)
})
})
describe('validateEventMethodTag', () => {
test('returns true for valid method tag', async () => {
const sk = generateSecretKey()
const token = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk), true)
const unpackedEvent: Event = await unpackEventFromToken(token)
const isEventMethodTagValid = validateEventMethodTag(unpackedEvent, 'get')
expect(isEventMethodTagValid).toBe(true)
})
test('returns false for invalid method tag', async () => {
const sk = generateSecretKey()
const token = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk), true)
const unpackedEvent: Event = await unpackEventFromToken(token)
const isEventMethodTagValid = validateEventMethodTag(unpackedEvent, 'post')
expect(isEventMethodTagValid).toBe(false)
})
})
describe('validateEventPayloadTag', () => {
test('returns true for valid payload tag', async () => {
const sk = generateSecretKey()
const token = await getToken('http://test.com', 'post', e => finalizeEvent(e, sk), true, { test: 'payload' })
const unpackedEvent: Event = await unpackEventFromToken(token)
const isEventPayloadTagValid = validateEventPayloadTag(unpackedEvent, { test: 'payload' })
expect(isEventPayloadTagValid).toBe(true)
})
test('returns false for invalid payload tag', async () => {
const sk = generateSecretKey()
const token = await getToken('http://test.com', 'post', e => finalizeEvent(e, sk), true, { test: 'a-payload' })
const unpackedEvent: Event = await unpackEventFromToken(token)
const isEventPayloadTagValid = validateEventPayloadTag(unpackedEvent, { test: 'a-different-payload' })
expect(isEventPayloadTagValid).toBe(false)
})
test('returns false for missing payload tag', async () => {
const sk = generateSecretKey()
const token = await getToken('http://test.com', 'post', e => finalizeEvent(e, sk), true, { test: 'payload' })
const unpackedEvent: Event = await unpackEventFromToken(token)
const isEventPayloadTagValid = validateEventPayloadTag(unpackedEvent, {})
expect(isEventPayloadTagValid).toBe(false)
})
})
describe('hashPayload', () => {
test('returns hash for valid payload', async () => {
const payload = { test: 'payload' }
const computedPayloadHash = hashPayload(payload)
const expectedPayloadHash = bytesToHex(sha256(utf8Encoder.encode(JSON.stringify(payload))))
expect(computedPayloadHash).toBe(expectedPayloadHash)
})
test('returns hash for empty payload', async () => {
const payload = {}
const computedPayloadHash = hashPayload(payload)
const expectedPayloadHash = bytesToHex(sha256(utf8Encoder.encode(JSON.stringify(payload))))
expect(computedPayloadHash).toBe(expectedPayloadHash)
}) })
}) })