Files
blackcanyontickets/reactrebuild0825/scripts/qr-system-demo.js
dzinesco aa81eb5adb feat: add advanced analytics and territory management system
- Add comprehensive analytics components with export functionality
- Implement territory management with manager performance tracking
- Add seatmap components for venue layout management
- Create customer management features with modal interface
- Add advanced hooks for dashboard flags and territory data
- Implement seat selection and venue management utilities
- Add type definitions for ticketing and seatmap systems

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-26 09:25:10 -06:00

312 lines
10 KiB
JavaScript

/**
* QR System Demonstration Script
* Shows QR validation, backup code generation, and manual entry flow
*/
// Import the QR validator and generator (simplified for demo)
function createMockQRValidator() {
return {
validateQR: (qrString) => {
if (!qrString || typeof qrString !== 'string') {
return { valid: false, format: 'unknown', errorReason: 'invalid_format' };
}
const trimmed = qrString.trim();
if (trimmed.startsWith('BCT.v')) {
const parts = trimmed.split('.');
if (parts.length === 4) {
return {
valid: true,
format: 'signed',
ticketId: '550e8400-e29b-41d4-a716-446655440000',
eventId: 'evt_789012345',
metadata: {
version: 2,
issuedAt: Math.floor(Date.now() / 1000),
expiresAt: Math.floor(Date.now() / 1000) + 30 * 24 * 60 * 60,
zone: 'GA',
seat: 'A12'
}
};
}
}
if (trimmed.startsWith('TICKET_')) {
const ticketId = trimmed.substring(7);
if (/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(ticketId)) {
return { valid: true, format: 'simple', ticketId };
}
}
if (/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(trimmed)) {
return { valid: true, format: 'simple', ticketId: trimmed };
}
return { valid: false, format: 'unknown', errorReason: 'invalid_format' };
},
validateBackupCode: (code) => {
if (!code || typeof code !== 'string') {
return { valid: false };
}
const normalized = code.replace(/[^a-zA-Z0-9]/g, '').toUpperCase();
if (normalized.length !== 8) {
return { valid: false };
}
if (!/^[0-9A-F]{8}$/.test(normalized)) {
return { valid: false };
}
return { valid: true, normalizedCode: normalized };
},
extractTicketId: (qrString) => {
const result = this.validateQR(qrString);
return result.valid ? result.ticketId : null;
},
generateBackupCode: (ticketId) => {
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(ticketId)) {
throw new Error('Invalid ticket ID format');
}
const cleanId = ticketId.replace(/-/g, '');
return cleanId.slice(-8).toUpperCase();
}
};
}
function getQRErrorMessage(result) {
if (result.valid) {
return 'Valid ticket';
}
switch (result.errorReason) {
case 'invalid_format': return 'Invalid QR code format';
case 'expired': return 'Ticket has expired';
case 'signature_invalid': return 'Invalid or tampered ticket';
case 'malformed': return 'Corrupted QR code data';
case 'missing_data': return 'Incomplete ticket information';
default: return 'Unknown error occurred';
}
}
function formatBackupCode(code) {
if (code.length !== 8) {
return code;
}
return `${code.substring(0, 4)}-${code.substring(4)}`;
}
console.log('🎫 Black Canyon Tickets - QR System Demonstration\\n');
// Sample ticket data
const sampleTicketData = {
ticketId: '550e8400-e29b-41d4-a716-446655440000',
eventId: 'evt_789012345',
zone: 'GA',
seat: 'A12',
expiresInDays: 30
};
console.log('1. QR Code Validation');
console.log('====================');
const validator = createMockQRValidator();
// Test different QR formats
const testQRs = [
// Simple format
`TICKET_${sampleTicketData.ticketId}`,
// Signed token format (simulated)
'BCT.v2.eyJraWQiOiIxMjMiLCJlaWQiOiI0NTYifQ.abc123signature',
// Legacy UUID only
sampleTicketData.ticketId,
// Invalid formats
'INVALID_QR_CODE',
'BCT.v2.invalid.signature',
'TICKET_not-a-uuid'
];
testQRs.forEach((qr, index) => {
console.log(`Test ${index + 1}: ${qr.substring(0, 40)}${qr.length > 40 ? '...' : ''}`);
const result = validator.validateQR(qr);
console.log(` ✅ Valid: ${result.valid}`);
console.log(` 📱 Format: ${result.format}`);
if (result.ticketId) {
console.log(` 🎫 Ticket ID: ${result.ticketId}`);
}
if (result.eventId) {
console.log(` 🎪 Event ID: ${result.eventId}`);
}
if (!result.valid) {
console.log(` ❌ Error: ${getQRErrorMessage(result)}`);
}
if (result.metadata) {
if (result.metadata.expiresAt) {
const expires = new Date(result.metadata.expiresAt * 1000);
console.log(` ⏰ Expires: ${expires.toLocaleString()}`);
}
if (result.metadata.zone) {
console.log(` 🏟️ Zone: ${result.metadata.zone}`);
}
if (result.metadata.seat) {
console.log(` 💺 Seat: ${result.metadata.seat}`);
}
}
console.log();
});
console.log('2. Backup Code Validation');
console.log('=========================');
const testBackupCodes = [
'55440000', // Valid (last 8 chars of ticket ID)
'1234ABCD', // Valid hex format
'12345', // Too short
'123456789', // Too long
'1234GHIJ', // Invalid characters
'' // Empty
];
testBackupCodes.forEach((code, index) => {
console.log(`Test ${index + 1}: "${code}"`);
const result = validator.validateBackupCode(code);
console.log(` ✅ Valid: ${result.valid}`);
if (result.valid && result.normalizedCode) {
console.log(` 🔢 Normalized: ${formatBackupCode(result.normalizedCode)}`);
}
console.log();
});
console.log('3. Backup Code Generation');
console.log('========================');
const testTicketIds = [
sampleTicketData.ticketId,
'123e4567-e89b-12d3-a456-426614174000',
'invalid-uuid'
];
testTicketIds.forEach((ticketId, index) => {
console.log(`Test ${index + 1}: ${ticketId}`);
try {
const backupCode = validator.generateBackupCode(ticketId);
console.log(` 🔢 Backup Code: ${formatBackupCode(backupCode)}`);
} catch (error) {
console.log(` ❌ Error: ${error.message}`);
}
console.log();
});
console.log('4. QR Format Detection');
console.log('======================');
const mixedQRs = [
'TICKET_550e8400-e29b-41d4-a716-446655440000',
'BCT.v2.eyJ0aWQiOiIxMjMiLCJlaWQiOiI0NTYifQ.signature',
'550e8400-e29b-41d4-a716-446655440000', // Legacy UUID only
'MANUAL_55440000'
];
mixedQRs.forEach((qr, index) => {
console.log(`QR ${index + 1}: ${qr}`);
const ticketId = validator.extractTicketId(qr);
if (ticketId) {
console.log(` 🎫 Extracted Ticket ID: ${ticketId}`);
try {
const backupCode = validator.generateBackupCode(ticketId);
console.log(` 🔢 Backup Code: ${formatBackupCode(backupCode)}`);
} catch (error) {
console.log(` ❌ Backup Code Error: ${error.message}`);
}
} else {
console.log(` ❌ Could not extract ticket ID`);
}
console.log();
});
console.log('5. Manual Entry Flow Simulation');
console.log('===============================');
console.log('Simulating gate staff manual entry scenarios:');
console.log();
// Scenario 1: Perfect entry
console.log('Scenario 1: Gate staff enters backup code correctly');
const perfectCode = '55440000';
console.log(`Staff enters: "${perfectCode}"`);
const result1 = validator.validateBackupCode(perfectCode);
if (result1.valid) {
console.log(`✅ Code accepted: ${formatBackupCode(result1.normalizedCode)}`);
console.log(`🚪 Entry granted`);
} else {
console.log(`❌ Code rejected`);
}
console.log();
// Scenario 2: Entry with hyphens
console.log('Scenario 2: Gate staff enters code with formatting');
const formattedCode = '5544-0000';
console.log(`Staff enters: "${formattedCode}"`);
const result2 = validator.validateBackupCode(formattedCode);
if (result2.valid) {
console.log(`✅ Code accepted: ${formatBackupCode(result2.normalizedCode)}`);
console.log(`🚪 Entry granted`);
} else {
console.log(`❌ Code rejected`);
}
console.log();
// Scenario 3: Invalid entry
console.log('Scenario 3: Gate staff makes typing error');
const errorCode = '5544000'; // Missing digit
console.log(`Staff enters: "${errorCode}"`);
const result3 = validator.validateBackupCode(errorCode);
if (result3.valid) {
console.log(`✅ Code accepted`);
} else {
console.log(`❌ Code rejected - ask customer to show physical ticket`);
console.log(`💡 Suggestion: Check last 8 characters on ticket bottom`);
}
console.log();
console.log('6. Security Features');
console.log('===================');
console.log('✅ Signed tokens prevent counterfeiting');
console.log('✅ UUID ticket IDs prevent enumeration attacks');
console.log('✅ Backup codes are last 8 characters (not sequential)');
console.log('✅ HMAC signatures detect tampering');
console.log('✅ Time-based expiration prevents replay attacks');
console.log('✅ Offline validation available for signed tokens');
console.log();
console.log('7. Production Recommendations');
console.log('=============================');
console.log('✅ Use signed tokens (BCT.v2.{payload}.{signature}) for security');
console.log('✅ Implement proper HMAC-SHA256 signatures in production');
console.log('✅ Rotate signing keys quarterly');
console.log('✅ Use Error Correction Level M (15%) for most use cases');
console.log('✅ Use Error Correction Level H (30%) for thermal printers');
console.log('✅ Include backup codes on all printed tickets');
console.log('✅ Train gate staff on manual entry procedures');
console.log('✅ Test QR codes across different devices and lighting conditions');
console.log('✅ Monitor QR scan success rates and manual entry frequency');
console.log();
console.log('🚀 QR System Demo Complete!');
console.log('Visit /scanner?eventId=test-event-123 to test the scanner interface');
console.log(`Development server: http://localhost:5174`);
console.log();
console.log('📱 Manual Entry Instructions for Gate Staff:');
console.log('============================================');
console.log('1. If QR code won\'t scan, click the # button');
console.log('2. Enter the last 8 characters from bottom of ticket');
console.log('3. Characters can be numbers 0-9 or letters A-F');
console.log('4. System will show XXXX-XXXX format as you type');
console.log('5. Press Submit when all 8 characters entered');
console.log('6. Green checkmark = valid ticket, allow entry');
console.log('7. Red X = invalid code, ask to see physical ticket');
console.log();