-
Notifications
You must be signed in to change notification settings - Fork 0
UI Components
- Introduction
- Credential Display Component
- JSON Editor Implementation
- MDS Browser Functionality
- Settings Navigation Component
- Decoder/Encoder Interface
- Component Integration Patterns
- Performance Considerations
- Accessibility Features
- Troubleshooting Guide
The PostQuantum WebAuthn Platform provides a comprehensive suite of UI components designed for advanced credential management, data visualization, and cryptographic operations. These components work together to create an intuitive interface for developers working with WebAuthn protocols, particularly focusing on post-quantum cryptography implementations.
The UI components are built with modern JavaScript ES6+ features, responsive design principles, and accessibility standards. They provide sophisticated data manipulation capabilities, real-time validation, and seamless integration with backend services for credential storage and metadata management.
The credential display component serves as the central hub for visualizing and managing WebAuthn credentials with comprehensive attestation information and metadata integration.
classDiagram
class CredentialDisplay {
+state : Object
+registrationDetailState : Object
+globalCursorApplyCount : Number
+applyGlobalCursor(cursorStyle) Function
+hydrateCredentialFromServer(cred) Promise
+deriveCredentialStatusIndicators(cred) Object
+composeRegistrationDetailHtml(options) Object
+updateCredentialsDisplay() void
+navigateToMdsAuthenticator(aaguid) Promise
}
class RegistrationDetailState {
+attestationObject : Object
+attestationCertificates : Array
+visibleAttestationCertificateIndices : Array
+authenticatorData : Object
+authenticatorDataHash : String
+authenticatorDataHex : String
}
class CredentialStatusIndicators {
+signatureStatus : Boolean
+rootStatus : Boolean
+rpidStatus : Boolean
+aaguidStatus : Boolean
+metadataAvailable : Boolean
+aaguidGuid : String
}
CredentialDisplay --> RegistrationDetailState : "manages"
CredentialDisplay --> CredentialStatusIndicators : "generates"
Diagram sources
- credential-display.js
The credential display component provides several key capabilities:
The component implements sophisticated cursor management for user feedback during long-running operations:
// Example usage pattern for global cursor management
const restoreCursor = applyGlobalCursor('progress');
try {
await hydrateCredentialFromServer(cred);
} finally {
restoreCursor();
}Each credential displays comprehensive status information including:
- Signature validation status
- Root certificate validation
- RPID hash verification
- AAGUID matching status
- Metadata availability
The component dynamically generates HTML content for credential details, including:
- Authenticator response data
- Parsed client data JSON
- Relying party information
- Attestation object details
- Certificate chain information
Section sources
- credential-display.js
- credential-display.js
The credential display integrates with the exclude credentials functionality to support advanced filtering scenarios:
The system supports creation and management of fake credential IDs for testing:
// Create fake credentials for testing
const fakeCredential = createFakeCredential('exclude', 32); // 32-byte credential
setFakeCredentials('allow', ['fake-credential-id-hex']);Credentials can be filtered based on:
- Algorithm type (PQC vs traditional)
- Authenticator attachment type
- Resident key capability
- Large blob support
- Custom metadata filters
Section sources
- credential-display.js
- exclude-credentials.js
The JSON editor provides sophisticated structured data manipulation capabilities with syntax highlighting, validation, and intelligent formatting.
classDiagram
class JsonEditor {
+state : Object
+KNOWN_REGISTRATION_PUBLIC_KEY_KEYS : Set
+KNOWN_AUTHENTICATION_PUBLIC_KEY_KEYS : Set
+validateRegistrationPublicKey(publicKey) void
+validateAuthenticationPublicKey(publicKey) void
+mergePublicKey(existing, latest, scope) Object
+pruneUnsupportedProperties(merged, scope) void
+buildOptionsForCurrentScope(scope) Object
}
class JsonEditorUtils {
+wrapSelectionWithPair(editor, opening, closing) void
+applyJsonEditorAutoIndent(editor) void
+applyTabIndentation(editor, isShift) void
+handleJsonEditorKeydown(event) void
}
class ValidationRules {
+KNOWN_RP_KEYS : Set
+KNOWN_USER_KEYS : Set
+KNOWN_AUTH_SELECTION_KEYS : Set
+KNOWN_REGISTRATION_EXTENSION_KEYS : Set
+KNOWN_AUTHENTICATION_EXTENSION_KEYS : Set
}
JsonEditor --> JsonEditorUtils : "uses"
JsonEditor --> ValidationRules : "validates against"
Diagram sources
- json-editor.js
- json-editor-utils.js
The JSON editor implements comprehensive validation rules for WebAuthn operations:
// Example validation for registration public key
validateRegistrationPublicKey({
rp: { name: 'Test RP', id: 'example.com' },
user: { id: 'user-id', name: 'Test User', displayName: 'Test User' },
challenge: 'challenge-data',
pubKeyCredParams: [{ type: 'public-key', alg: -7 }],
authenticatorSelection: {
authenticatorAttachment: 'cross-platform',
residentKey: 'discouraged',
userVerification: 'preferred'
}
});Similar validation applies to authentication requests with appropriate field restrictions.
The editor intelligently merges existing configurations with new data while preserving unknown properties:
// Merge existing options with new data
const mergedOptions = mergePublicKey(
existingPublicKey,
latestPublicKey,
'registration'
);
pruneUnsupportedProperties(mergedOptions, 'registration');Section sources
- json-editor.js
- json-editor.js
The editor provides advanced text editing capabilities:
Automatic indentation based on JSON structure:
- Opening braces
{and arrays[trigger auto-indentation - Closing braces handle proper dedentation
- Smart line wrapping maintains readability
- Tab key for indentation/de-indentation
- Enter key for automatic brace completion
- Ctrl/Cmd combinations for advanced editing
Intelligent selection wrapping for common JSON patterns:
// Wraps selected text with brackets or quotes
wrapSelectionWithPair(editor, '{', '}');Section sources
- json-editor-utils.js
The Metadata Service (MDS) browser provides efficient navigation and search capabilities for authenticator metadata with advanced lazy-loading and filtering systems.
classDiagram
class MdsBrowser {
+mdsState : Object
+mdsData : Array
+filteredData : Array
+isLoading : Boolean
+hasLoaded : Boolean
+initializeMdsBrowser() void
+filterMdsData(filters) Array
+navigateToMdsAuthenticator(aaguid) Promise
}
class MdsLazyLoader {
+allEntries : Array
+fullyParsedIndices : Set
+fullyParsedKeys : Map
+isBackgroundLoading : Boolean
+startBackgroundLoading(options) Promise
+getRawEntryByIndex(index) Object
+findEntriesWithCertificate(certificate) Array
}
class FilterDropdown {
+input : Element
+onSelect : Function
+options : Array
+filtered : Array
+activeIndex : Number
+open() void
+close() void
+filter(query) void
+render() void
}
MdsBrowser --> MdsLazyLoader : "uses"
MdsBrowser --> FilterDropdown : "creates"
MdsLazyLoader --> FilterDropdown : "integrates with"
Diagram sources
- mds.js
- mds-lazy-loader.js
- mds-dropdown.js
The MDS browser implements sophisticated lazy loading to handle large metadata datasets efficiently:
// Start background loading with progress tracking
await startBackgroundLoading({
onBatchProcessed: (batchIndices) => {
// Process batch of entries
processMdsEntries(batchIndices);
}
});- Progressive parsing of metadata entries
- Automatic cleanup of unused data
- Efficient caching of frequently accessed entries
- Configurable batch sizes for optimal performance
Advanced certificate-based searching:
// Find entries containing specific certificates
const matchingEntries = findEntriesWithCertificate(certificateBase64);Section sources
- mds-lazy-loader.js
The filter dropdown provides intuitive search and selection capabilities:
// Create filter dropdown with custom configuration
const dropdown = createFilterDropdown(inputElement, (value) => {
applyMdsFilter(value);
}, { expandDropdown: true });- Arrow keys for navigation
- Enter key for selection
- Escape key for dismissal
- Focus management for accessibility
Real-time option updates based on current dataset:
dropdown.setOptions(['Option 1', 'Option 2', 'Option 3']);Section sources
- mds-dropdown.js
Seamless navigation to authenticator metadata with status feedback:
// Navigate to authenticator metadata by AAGUID
const navigationResult = await navigateToMdsAuthenticator(aaguid);
if (navigationResult.highlighted) {
// Metadata found and highlighted
}Real-time status updates during navigation:
- Loading indicators
- Success/failure notifications
- Progress tracking
Section sources
- mds.js
The settings navigation component provides responsive, scroll-based navigation for advanced configuration panels with intersection observer integration.
classDiagram
class SettingsNav {
+state : Object
+navItems : Array
+observer : IntersectionObserver
+activeTarget : String
+initializeAdvancedSettingsNavigation() void
+observeSections() void
+setActive(targetId) void
}
class IntersectionObserver {
+root : Element
+rootMargin : String
+threshold : Array
+callback : Function
+disconnect() void
+observe(target) void
}
class NavItem {
+element : Element
+targetId : String
+scrollTarget : String
+addEventListener(type, handler) void
}
SettingsNav --> IntersectionObserver : "uses"
SettingsNav --> NavItem : "manages"
IntersectionObserver --> NavItem : "observes"
Diagram sources
- settings-nav.js
The settings navigation adapts to different screen sizes and content layouts:
// Initialize responsive navigation
initializeAdvancedSettingsNavigation();
// Automatically tracks visible sections
// Updates active state based on viewport positionSophisticated viewport monitoring:
const observer = new IntersectionObserver((entries) => {
const visible = entries
.filter(entry => entry.isIntersecting)
.sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top);
if (visible.length > 0) {
const topEntry = visible[0];
setActive(topEntry.target.id);
}
}, observerOptions);Enhanced user experience with smooth scrolling:
// Scroll to target with smooth behavior
targetElement.scrollIntoView({
behavior: 'smooth',
block: 'start'
});Section sources
- settings-nav.js
The component automatically manages navigation items based on content availability:
// Automatically discovers and observes sections
function observeSections() {
navItems.forEach(item => {
const targetId = getTargetId(item);
if (targetId) {
const sentinel = document.getElementById(targetId);
if (sentinel) {
observer.observe(sentinel);
}
}
});
}Responsive to dynamic content changes:
- Tab switching events
- Content loading events
- Window resize events
Section sources
- settings-nav.js
The codec component provides comprehensive CBOR/JSON conversion capabilities with syntax highlighting and validation for WebAuthn payloads.
classDiagram
class Codec {
+currentCodecMode : String
+MODE_CONFIG : Object
+processCodec(mode) Promise
+switchCodecMode(mode) void
+clearCodec(mode) void
+toggleRawCodec(mode) void
}
class DecodedResult {
+success : Boolean
+type : String
+data : Object
+malformed : Array
+renderDecodedResult(container, payload, mode) void
}
class FormatConverter {
+convertFormat(value, from, to) String
+getCurrentBinaryFormat() String
+currentFormatToJsonFormat(value) Object
}
Codec --> DecodedResult : "produces"
Codec --> FormatConverter : "uses"
DecodedResult --> FormatConverter : "utilizes"
Diagram sources
- codec.js
The codec supports multiple input/output formats for comprehensive WebAuthn payload handling:
- JSON: Standard JSON payloads
- JSON (Binary): Binary-encoded JSON
- CBOR: Canonical and CTAP/WebAuthn formats
- Binary: Raw binary data
- PEM: X.509 certificates
- DER: DER-encoded certificates
- CBOR: Canonical and CTAP/WebAuthn formats
- JSON: Formatted JSON output
- DER: DER-encoded output
- PEM: PEM-encoded output
- COSE: COSE format output
flowchart TD
Input["User Input"] --> Validation["Format Validation"]
Validation --> Processing["Backend Processing"]
Processing --> Success{"Processing<br/>Successful?"}
Success --> |Yes| Rendering["Render Results"]
Success --> |No| ErrorHandling["Error Handling"]
Rendering --> Display["Display Output"]
ErrorHandling --> ErrorMessage["Show Error Message"]
Display --> RawToggle["Raw Toggle"]
RawToggle --> RawModal["Raw Data Modal"]
Diagram sources
- codec.js
The codec supports seamless switching between decode and encode modes:
const MODE_CONFIG = {
decode: {
panelId: 'codec-decode-panel',
inputId: 'decoder-input',
outputId: 'decoder-output',
summaryId: 'decoded-content',
toggleRawId: 'decoder-toggle-raw',
statusKey: 'decoder',
progressId: 'decoder-progress'
},
encode: {
panelId: 'codec-encode-panel',
inputId: 'encoder-input',
outputId: 'encoder-output',
summaryId: 'encoded-content',
toggleRawId: 'encoder-toggle-raw',
statusKey: 'encoder',
progressId: 'encoder-progress',
formatSelectId: 'encoder-format'
}
};Smooth transitions between modes with visual feedback:
// Switch mode with animation
switchCodecMode('encode');
// Animation triggers visual transition
content.classList.add('codec-mode-animating');
content.addEventListener('animationend', () => {
content.classList.remove('codec-mode-animating');
}, { once: true });Section sources
- codec.js
Sophisticated rendering of decoded results with interactive features:
// Build sections for different data types
const sections = buildSections(type, data);
if (sections.length === 0) {
const emptySection = document.createElement('div');
emptySection.className = 'decoder-empty';
emptySection.textContent = 'No structured data available.';
sectionsWrapper.appendChild(emptySection);
}- Expandable sections
- Copy-to-clipboard functionality
- Raw data access
- Error highlighting
Section sources
- codec.js
The codec integrates seamlessly with the application template system:
<div id="codec-tab" class="tab-content">
<div class="codec-mode-tabs" role="tablist">
<button id="codec-mode-decode" class="codec-mode-tab active"
onclick="switchCodecMode('decode')">
Decode
</button>
<button id="codec-mode-encode" class="codec-mode-tab"
onclick="switchCodecMode('encode')">
Encode
</button>
</div>
<div id="codec-mode-content" class="codec-mode-content">
<!-- Decode Panel -->
<div id="codec-decode-panel" class="codec-panel is-active">
<!-- Input, buttons, output -->
</div>
<!-- Encode Panel -->
<div id="codec-encode-panel" class="codec-panel">
<!-- Format selector, input, buttons, output -->
</div>
</div>
</div>Section sources
- tab.html
The UI components work together through well-defined integration patterns that ensure consistency and reliability across the application.
Components share state through a centralized state management system:
// Shared state structure
const state = {
storedCredentials: [],
generatedExcludeCredentials: [],
generatedAllowCredentials: [],
currentSubTab: 'registration',
// ... other shared state
};Components communicate through standardized event patterns:
// Tab change notification
document.dispatchEvent(new CustomEvent('tab:changed', {
detail: { tab: 'advanced' }
}));
// Subtab change notification
document.dispatchEvent(new CustomEvent('advanced:subtab-changed'));// Register callbacks for state changes
registerHintsChangeCallback(() => updateJsonEditor());All components integrate with backend services for data persistence and processing:
// Fetch credential artifacts from server
const artifact = await fetchCredentialArtifact(storageId);
// Delete credentials
await deleteCredentialArtifact(storageId);// Load MDS metadata
const metadata = await fetchMdsMetadata();
// Upload custom metadata
const uploadResult = await uploadCustomMetadata(file);Section sources
- credential-display.js
- mds.js
The UI components are designed with performance optimization in mind, particularly for handling large datasets and complex operations.
- MDS browser uses progressive loading for large metadata sets
- Credential display implements virtual scrolling for large credential lists
- JSON editor uses streaming parsing for large payloads
// Efficient cleanup of unused data
function cleanupUnusedData() {
// Remove references to large objects
// Clear caches periodically
// Release DOM references
}// Debounce expensive operations
const debouncedUpdate = debounce(() => {
updateCredentialsDisplay();
}, 300);For large lists, components implement virtual scrolling to maintain performance:
// Only render visible items
const visibleItems = items.slice(startIndex, endIndex);Large operations are processed in batches to maintain UI responsiveness:
// Process in chunks to prevent blocking
async function processInBatches(items, batchSize = 100) {
for (let i = 0; i < items.length; i += batchSize) {
const batch = items.slice(i, i + batchSize);
await processBatch(batch);
await yieldToBrowser(); // Allow UI updates
}
}// Cache metadata responses
const metadataCache = new Map();
async function getCachedMetadata(url) {
if (metadataCache.has(url)) {
return metadataCache.get(url);
}
const response = await fetch(url);
const data = await response.json();
metadataCache.set(url, data);
return data;
}// Process multiple requests concurrently
const results = await Promise.allSettled([
fetchCredentialData(),
fetchMetadata(),
fetchCertificates()
]);All UI components implement comprehensive accessibility features to ensure usability for all users.
- Full keyboard navigation for all interactive elements
- Tab order follows logical flow
- Escape key support for modal dialogs
- Enter/Space key activation for buttons
// ARIA attributes for screen readers
<button
class="btn btn-small btn-secondary credential-mds-button"
data-aaguid="${escapeHtml(aaguidGuid.toLowerCase())}"
title="Open authenticator metadata"
aria-label="Open authenticator metadata for ${cred.userName}"
role="button"
tabindex="0">
FIDO MDS
</button>/* High contrast mode support */
@media (prefers-contrast: high) {
.credential-item {
border: 2px solid currentColor;
}
.credential-feature-tag {
background-color: var(--high-contrast-bg);
color: var(--high-contrast-text);
}
}/* Clear focus indicators */
.credential-item:focus {
outline: 2px solid var(--focus-color);
outline-offset: 2px;
}<!-- Proper heading hierarchy -->
<h3 style="color: #0072CE; margin-bottom: 0.75rem;">Attestation Information</h3>
<!-- Logical grouping -->
<section style="margin-bottom: 1.5rem;">
<h3 style="color: #0072CE; margin-bottom: 0.75rem;">Authenticator Response</h3>
<ol style="padding-left: 1.25rem; margin: 0;">
<li style="margin-bottom: 1rem;">
<div style="font-weight: 600; margin-bottom: 0.5rem;">Response for navigator.credentials.create()</div>
<!-- Content -->
</li>
</ol>
</section>Common issues and their solutions for the UI components.
Symptoms: Empty credential list despite having saved credentials Solution:
// Check if credentials are properly synced
await ensureAdvancedCredentialArtifactsSynced();
// Verify state is populated
console.log('Stored credentials:', state.storedCredentials);Symptoms: No attestation information displayed for credentials Solution:
// Force hydration of credential data
await hydrateCredentialFromServer(credential);
// Check for network errors
if (cred.__artifactHydrated === 'error') {
console.error('Failed to load credential artifact');
}Symptoms: Editor shows validation errors for valid data Solution:
// Check validation rules
const validationRules = {
KNOWN_REGISTRATION_PUBLIC_KEY_KEYS: new Set([
'rp', 'user', 'challenge', 'pubKeyCredParams',
'timeout', 'authenticatorSelection', 'attestation',
'extensions', 'excludeCredentials', 'hints'
])
};
// Verify data structure matches expected formatSymptoms: Manual indentation required for JSON formatting Solution:
// Check keyboard event handlers
document.getElementById('json-editor').addEventListener('keydown', handleJsonEditorKeydown);Symptoms: MDS tab shows loading indefinitely Solution:
// Check MDS initialization
const mdsState = getMdsLoadState();
if (!mdsState.hasLoaded) {
await waitForMdsLoad();
}
// Verify network connectivity
const metadata = await fetchMdsMetadata();Symptoms: Dropdown doesn't show options or responds to clicks Solution:
// Check dropdown initialization
const dropdown = createFilterDropdown(inputElement, onSelect);
dropdown.setOptions(['Option 1', 'Option 2']);
// Verify event listeners
inputElement.addEventListener('focus', () => dropdown.open());Symptoms: Payload processing fails with unclear errors Solution:
// Check input format
const input = document.getElementById('decoder-input').value;
if (!input.trim()) {
showStatus('decoder', 'Input is empty', 'error');
return;
}
// Verify backend service availability
try {
const response = await fetch('/api/codec', { method: 'POST' });
if (!response.ok) {
throw new Error(`Server responded with status ${response.status}`);
}
} catch (error) {
showStatus('decoder', 'Backend service unavailable', 'error');
}Symptoms: UI becomes unresponsive during operations Solution:
// Implement async processing
async function processLargeDataset(dataset) {
for (let i = 0; i < dataset.length; i += 100) {
const chunk = dataset.slice(i, i + 100);
await processChunk(chunk);
await new Promise(resolve => setTimeout(resolve, 0)); // Yield to browser
}
}
// Use requestIdleCallback for background tasks
if (typeof requestIdleCallback === 'function') {
requestIdleCallback(() => {
// Perform background processing
});
}// Add debug logging to components
function logDebug(message, data) {
if (process.env.NODE_ENV === 'development') {
console.log(`[DEBUG] ${message}`, data);
}
}
// Usage in components
logDebug('Credential display updated', { count: state.storedCredentials.length });// Inspect component state
function inspectComponentState(componentName) {
const state = window[componentName]?.getState?.();
console.log(`${componentName} state:`, state);
}Section sources
- credential-display.js
- json-editor.js
- mds.js
- codec.js