UNPKG

bam-ticketing-sdk

Version:

SDK for B.A.M Ticketing API

128 lines (118 loc) 3.91 kB
import base45 from 'base45' import { KJUR } from 'jsrsasign' import { parseTicketId } from '../blockchain/utils' import { sign, verify } from '../utils/certificate' import { createInvalidateCall, createInvalidatePayload, TickedIds } from '..' /** * Encodes the payload and the signature into the expected QR code payload * * @param payload JSON stringified payload * @param signatureHex Hex encoded signature of the payload * @returns base 45 encoded string */ export function encodeQrPayload(payload: string, signatureHex: string) { const payloadBuffer = Buffer.from(payload) const signatureBuffer = Buffer.from(signatureHex, 'hex') const payloadEncoded = base45.encode(payloadBuffer) const signatureEncoded = base45.encode(signatureBuffer) return `${payloadEncoded}:::${signatureEncoded}` } /** * Decode a base 45 encoded QR code payload * * @param encodedPayload what you scanned from the QR code * @returns payload and its signature */ export function decodeQrPayload(encodedPayload: string) { const [payloadEncoded, signatureEncoded] = encodedPayload.split(':::') const payloadBuffer = base45.decode(payloadEncoded) const signatureBuffer = base45.decode(signatureEncoded) const payload = payloadBuffer.toString() const signature = signatureBuffer.toString('hex') return { payload, signature, } } type TicketQrContent = { id: string } /** * Signs and encodes ticket data into the string which will be put in the QR code * * @param eventId event to which the ticket belongs * @param ticketConfigId ticket config of the ticket * @param sequenceNumber the serial number of the ticket * @param privateKey the private key which is used to sign the ticket * @returns string to display as a tickets QR code */ export function createQrPayloadForTicket( eventId: number, ticketConfigId: number, sequenceNumber: number, privateKey: string | KJUR.crypto.ECDSA ): string { // Encode the ticket ID const ticketId = `E${eventId}TC${ticketConfigId}T${sequenceNumber}` const payload = JSON.stringify({ id: ticketId, }) const signature = sign(payload, privateKey) return encodeQrPayload(payload, signature) } /** * Decodes, verifies the signature of the QR code payload and constructs the blockchain * function call to invalidate the ticket * * @param qrCodePayload content of the QR code * @param invalidationDate the time at which the ticket was scanned * @param publicKey key used to verify the ticket signature, if specified * @returns blockchain function call for ticket invalidation * @throws Error if the signature does not match the payload */ export function qrToTicketInvalidateCall( qrCodePayload: string, invalidationDate: Date, publicKey?: string | KJUR.crypto.ECDSA ) { const qrContent = decodeQrPayload(qrCodePayload) if (publicKey) { const signatureValid = verify( qrContent.payload, qrContent.signature, publicKey ) if (!signatureValid) { throw new Error('Invalid ticket signature') } } const payload = JSON.parse(qrContent.payload) as TicketQrContent const args = createInvalidatePayload(payload.id, invalidationDate) return createInvalidateCall(args) } /** * Decodes and verifies the signature of the QR code payload and returns the IDs * * @param qrCodePayload content of the QR code * @param publicKey key used to verify the ticket signature, if specified * @returns ticket IDs * @throws Error if the signature does not match the payload */ export function qrToTicketData( qrCodePayload: string, publicKey?: string | KJUR.crypto.ECDSA ): TickedIds { const qrContent = decodeQrPayload(qrCodePayload) if (publicKey) { const signatureValid = verify( qrContent.payload, qrContent.signature, publicKey ) if (!signatureValid) { throw new Error('Invalid ticket signature') } } const payload = JSON.parse(qrContent.payload) as TicketQrContent return parseTicketId(payload.id) }