Generic ASN.1 parser/decoder that can decode any valid ASN.1 DER or BER structures.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Browser-specific functionality for creating interactive ASN.1 structure visualizations with DOM elements and context menus.
Extended ASN.1 parser with DOM rendering capabilities for web browsers, providing interactive tree views of ASN.1 structures.
/**
* ASN.1 parser with DOM rendering capabilities
* Extends ASN1 class with browser-specific visualization methods
*/
class ASN1DOM extends ASN1 {
/**
* Generate DOM element representation of ASN.1 structure
* Creates an interactive tree view with expandable/collapsible nodes
* @param spaces - Indentation string for formatting (optional)
* @returns HTML list item element representing the ASN.1 structure
*/
toDOM(spaces?: string): HTMLLIElement;
/**
* Generate hexadecimal DOM display with formatting and highlighting
* @param start - Starting position for hex display (optional)
* @param trimmedHex - Whether to trim hex display for large content (optional)
* @returns HTML element containing formatted hex dump
*/
toHexDOM(start?: number, trimmedHex?: boolean): HTMLElement;
}Usage Examples:
import { ASN1DOM } from '@lapo/asn1js/dom.js';
import { Base64 } from '@lapo/asn1js/base64.js';
// Parse certificate and create DOM visualization
const certPem = `-----BEGIN CERTIFICATE-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA3YkQOL4OqPlzJGPbhUKZ
...
-----END CERTIFICATE-----`;
const certData = Base64.unarmor(certPem);
const cert = ASN1DOM.decode(certData);
// Create DOM tree view
const treeContainer = document.getElementById('asn1-tree');
const ul = document.createElement('ul');
ul.className = 'treecollapse';
ul.appendChild(cert.toDOM());
treeContainer.appendChild(ul);
// Create hex dump view
const hexContainer = document.getElementById('hex-dump');
hexContainer.appendChild(cert.toHexDOM(undefined, true));
// Access the ASN1 object from DOM elements
ul.addEventListener('click', (event) => {
const listItem = event.target.closest('li');
if (listItem && listItem.asn1) {
console.log('Clicked ASN.1 element:', listItem.asn1.typeName());
console.log('Content:', listItem.asn1.content(100));
}
});Utility function for binding context menus to ASN.1 DOM elements.
/**
* Bind context menu functionality to DOM nodes
* Adds right-click context menu with ASN.1-specific options
* @param node - DOM node to bind context menu to
*/
function bindContextMenu(node: HTMLElement): void;Usage Examples:
import { ASN1DOM } from '@lapo/asn1js/dom.js';
import { bindContextMenu } from '@lapo/asn1js/context.js';
import { Hex } from '@lapo/asn1js/hex.js';
// Create ASN.1 structure with context menu
const data = Hex.decode('300C06032B6570050000');
const asn1 = ASN1DOM.decode(data);
const domElement = asn1.toDOM();
bindContextMenu(domElement);
// Add to page
document.body.appendChild(domElement);
// Context menu will provide options like:
// - Copy hex value
// - Copy base64 value
// - Show OID description (for OID elements)
// - Export structureExample showing how to build a complete ASN.1 viewer web interface.
import { ASN1DOM } from '@lapo/asn1js/dom.js';
import { Base64 } from '@lapo/asn1js/base64.js';
import { Hex } from '@lapo/asn1js/hex.js';
import { bindContextMenu } from '@lapo/asn1js/context.js';
class ASN1Viewer {
constructor(containerElement) {
this.container = containerElement;
this.setupUI();
}
setupUI() {
this.container.innerHTML = `
<div class="asn1-viewer">
<div class="controls">
<textarea id="input" placeholder="Paste PEM, Base64, or Hex data here..."></textarea>
<button id="decode">Decode</button>
<button id="clear">Clear</button>
</div>
<div class="output">
<div id="tree-view" class="tree-container"></div>
<div id="hex-view" class="hex-container"></div>
</div>
</div>
`;
this.inputArea = this.container.querySelector('#input');
this.treeView = this.container.querySelector('#tree-view');
this.hexView = this.container.querySelector('#hex-view');
this.container.querySelector('#decode').onclick = () => this.decode();
this.container.querySelector('#clear').onclick = () => this.clear();
}
decode() {
try {
const input = this.inputArea.value.trim();
if (!input) return;
let binaryData;
// Auto-detect format
if (/^[0-9A-Fa-f\s]+$/.test(input)) {
binaryData = Hex.decode(input);
} else {
binaryData = Base64.unarmor(input);
}
const asn1 = ASN1DOM.decode(binaryData);
this.displayStructure(asn1);
} catch (error) {
this.showError(error.message);
}
}
displayStructure(asn1) {
// Clear previous content
this.treeView.innerHTML = '';
this.hexView.innerHTML = '';
// Create tree view
const ul = document.createElement('ul');
ul.className = 'treecollapse';
const li = asn1.toDOM();
bindContextMenu(li);
ul.appendChild(li);
this.treeView.appendChild(ul);
// Create hex view
const hexElement = asn1.toHexDOM(undefined, true);
this.hexView.appendChild(hexElement);
// Add click handlers for tree navigation
this.addTreeInteractivity(ul);
}
addTreeInteractivity(treeElement) {
treeElement.addEventListener('click', (event) => {
const target = event.target;
// Toggle collapse/expand
if (target.classList.contains('toggle')) {
const li = target.closest('li');
li.classList.toggle('collapsed');
event.stopPropagation();
return;
}
// Highlight selected element
treeElement.querySelectorAll('li.selected').forEach(el => {
el.classList.remove('selected');
});
const li = target.closest('li');
if (li && li.asn1) {
li.classList.add('selected');
this.showElementDetails(li.asn1);
}
});
}
showElementDetails(asn1) {
// Show detailed information about the selected element
const details = {
type: asn1.typeName(),
position: `${asn1.posStart()}-${asn1.posEnd()}`,
length: asn1.length,
content: asn1.content(200)
};
console.log('Selected ASN.1 element:', details);
// Could update a details panel in the UI
// this.updateDetailsPanel(details);
}
showError(message) {
this.treeView.innerHTML = `<div class="error">Error: ${message}</div>`;
this.hexView.innerHTML = '';
}
clear() {
this.inputArea.value = '';
this.treeView.innerHTML = '';
this.hexView.innerHTML = '';
}
}
// Usage
const viewerContainer = document.getElementById('asn1-viewer-container');
const viewer = new ASN1Viewer(viewerContainer);Recommended CSS classes for styling ASN.1 DOM visualizations.
/* Tree view styling */
.treecollapse {
font-family: monospace;
font-size: 12px;
list-style: none;
padding-left: 0;
}
.treecollapse li {
margin: 2px 0;
padding-left: 16px;
position: relative;
}
.treecollapse li:before {
content: "▼";
position: absolute;
left: 0;
cursor: pointer;
color: #666;
}
.treecollapse li.collapsed:before {
content: "▶";
}
.treecollapse li.collapsed > ul {
display: none;
}
/* ASN.1 element styling */
.head {
cursor: pointer;
}
.head:hover {
background-color: #f0f0f0;
}
.selected .head {
background-color: #e6f3ff;
}
/* Type and content styling */
.name.id {
color: #0066cc;
font-weight: bold;
}
.name.type {
color: #006600;
}
.preview {
color: #666;
font-style: italic;
}
.oid.description {
color: #8b4513;
font-size: 11px;
}
/* Hex view styling */
.hex-container {
font-family: monospace;
font-size: 11px;
white-space: pre;
background-color: #f8f8f8;
padding: 10px;
border: 1px solid #ddd;
overflow: auto;
}
.hex-address {
color: #666;
}
.hex-bytes {
color: #000;
}
.hex-ascii {
color: #0066cc;
}
/* Error styling */
.error {
color: #cc0000;
background-color: #ffe6e6;
padding: 10px;
border: 1px solid #cc0000;
border-radius: 4px;
}