Plugin System

Extend the verification pipeline with custom logic. Plugins run in a fixed order — parser, crypto, trust, verifier — and each type has a clear contract.

Architecture

Plugins execute in a sandwich order. Each stage receives the output of the previous stage and enriches the verification result:

Parser
Extract data from file
→
Crypto
Verify signatures
→
Trust
Resolve anchors
→
Verifier
Identity & level

Plugin types

Type Stage Purpose Example
parser 1st Extract structured data from the file. Receives raw bytes, returns metadata. XML invoice parser, image EXIF extractor
crypto 2nd Verify cryptographic signatures. Receives parsed data, returns signature validity. PGP verifier, JWS validator, XMLDSig checker
trust 3rd Resolve trust anchors. Receives verified signatures, returns trust chain status. Blockchain anchor lookup, CA bundle resolver, DID trust registry
verifier 4th Determine identity and final trust level. Receives trust data, returns verification result. DID resolver, vLEI credential checker, eIDAS validator

Registering a plugin (npm)

register.js
 import { attesttoPlugins } from '@attestto/verify'

attesttoPlugins.register({
  name: 'my-trust-registry',
  type: 'trust',
  version: '1.0.0',

  // Called for each signature that needs trust resolution
  async execute(context) {
    const { signature, certificates } = context

    // Check your trust registry
    const isTrusted = await checkRegistry(certificates[0].issuer)

    return {
      trusted: isTrusted,
      registry: 'my-org-registry',
      detail: isTrusted
        ? 'Signer is in the corporate trust registry'
        : 'Signer not found in registry'
    }
  }
}) 

Registering a plugin (CDN)

When using the CDN build, plugins register through the global window.Attestto object:

cdn-plugin.html
 <script type="module"
  src="https://unpkg.com/@attestto/[email protected]/dist/attestto-verify.js"
  integrity="sha384-v5irXGJ3QL+rHxekFY6LC4PsECPYYAtLt4L7qA30edAvB+/Ah+ZS8IvSXoxqmctW"
  crossorigin="anonymous"
></script>

<script>
  window.addEventListener('attestto-ready', () => {
    window.Attestto.registerPlugin({
      name: 'blockchain-anchor',
      type: 'trust',
      version: '1.0.0',
      async execute(context) {
        // Look up hash on Solana
        const anchor = await findAnchor(context.hash)
        return {
          trusted: !!anchor,
          chain: 'solana',
          slot: anchor?.slot
        }
      }
    })
  })
</script> 

Plugin execution context

Each plugin's execute function receives a context object with data from previous stages:

Field Type Available in Description
file File All The original file object.
hash string All SHA-256 hex hash of the file.
bytes Uint8Array parser Raw file bytes.
parsed object crypto, trust, verifier Combined output from all parser plugins.
signatures Signature[] trust, verifier Verified signatures from crypto stage.
certificates Certificate[] trust, verifier Signer certificates.
trustResults TrustResult[] verifier Results from all trust plugins.

Result schema

The final verification result follows the AttesttoVerificationResult interface:

AttesttoVerificationResult
 interface AttesttoVerificationResult {
  hash: string                     // SHA-256 hex
  fileName: string                 // Original file name
  fileSize: number                 // Bytes
  trustLevel: TrustLevel           // 'detected' | 'signed' | 'trusted' | 'qualified'
  signatures: Signature[]          // Verified signatures
  audit: AuditResult               // Forensic audit findings
  plugins: PluginResult[]          // Results from each plugin
  timestamp: string               // ISO 8601
}

interface Signature {
  signerName: string
  did?: string                     // If resolved by a verifier plugin
  algorithm: string
  signedAt: string                 // ISO 8601
  valid: boolean
  trustLevel: TrustLevel
  certificate?: CertificateInfo
}

interface PluginResult {
  pluginName: string
  type: 'parser' | 'crypto' | 'trust' | 'verifier'
  data: Record<string, unknown>
} 
💡
Plugin isolation: Each plugin runs independently. A failing plugin does not block the pipeline — its error is captured in the plugins array and the remaining plugins continue executing.

See also