npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

firs-irn-qr

v1.0.1

Published

IRN encryption + QR generation for FIRS e-Invoicing (Nigeria). Accepts public key + certificate strings, encrypts IRN+timestamp+certificate, outputs Base64 and QR PNG.

Readme

firs-irn-qr

A simple Node.js + TypeScript library and CLI for encrypting IRNs and generating QR codes based on the FIRS (Nigeria) e-Invoicing IRN Signing Guide.

This package implements the IRN signing and QR generation process described in the FIRS e-Invoicing documentation, providing a developer-friendly API for automation and integration.


✨ Features

  • 🔐 Encrypt IRN + certificate using FIRS public key (RSA PKCS#1 v1.5)
  • 🕒 Automatically appends UNIX timestamp to IRN (e.g. INV001-123ABC.1731618237)
  • 📦 Outputs expected artifacts:
    • public_key.pem
    • data.json
    • encrypted_data.bin
    • encrypted_data.txt
    • qr_code.png
  • 🧾 Generate QR codes from encrypted Base64 data
  • ⚙️ Works both as a CLI tool and as a Node.js library

📦 Installation

npm install firs-irn-qr

or

yarn add firs-irn-qr
# or
pnpm add firs-irn-qr

🚀 Usage

🖥️ CLI

The CLI lets you easily encrypt an IRN and generate a QR code.

Basic Example

export FIRS_PUBLIC_KEY="<Base64-of-PEM or full PEM string>"
export FIRS_CERTIFICATE="<Base64 certificate>"

npx firs-irn-qr sign   --public-key "$FIRS_PUBLIC_KEY"   --certificate "$FIRS_CERTIFICATE"   --irn INV001-345SFG-20241011   --outdir ./out

🗂 Output files in ./out/:

public_key.pem
data.json
encrypted_data.bin
encrypted_data.txt
qr_code.png

With a custom timestamp

npx firs-irn-qr sign   -p "$FIRS_PUBLIC_KEY"   -c "$FIRS_CERTIFICATE"   -i INV001-345SFG-20241011   -t 1731618237

Skip QR generation

npx firs-irn-qr sign   -p "$FIRS_PUBLIC_KEY"   -c "$FIRS_CERTIFICATE"   -i INV001-345SFG-20241011   --no-qr

Using a full IRN string that already includes the timestamp

npx firs-irn-qr sign   -p "$FIRS_PUBLIC_KEY"   -c "$FIRS_CERTIFICATE"   -i "INV001-345SFG-20241011.1731618237"

💻 Library API

Use the module in your Node.js/TypeScript project:

import { signAndEncode, writeQrPng } from 'firs-irn-qr';

const keys = {
  public_key: process.env.FIRS_PUBLIC_KEY!,    // Base64 or PEM string
  certificate: process.env.FIRS_CERTIFICATE!,  // Base64 string
};

const { encryptedBase64, irnWithTimestamp, publicKeyPem, dataJson } =
  await signAndEncode({
    keys,
    irn: 'INV001-345SFG-20241011',
  });

console.log('IRN:', irnWithTimestamp);
console.log('Encrypted data (Base64):', encryptedBase64);

// Optional: generate QR code
await writeQrPng(encryptedBase64, './qr_code.png');

🧩 API Reference

signAndEncode({ keys, irn, timestamp? })

| Param | Type | Description | | ------------------ | -------- | ---------------------------------------- | | keys.public_key | string | FIRS public key (Base64 or PEM) | | keys.certificate | string | Certificate (Base64 string) | | irn | string | IRN stem (e.g. INV001-345SFG-20241011) | | timestamp? | number | UNIX timestamp in seconds |

Returns:

{
  publicKeyPem: string;
  irnWithTimestamp: string;
  dataJson: string;
  encrypted: Buffer;
  encryptedBase64: string;
}

writeQrPng(base64CipherText, outFile)

Generates a QR code PNG from the Base64 encrypted string.

signAndQrDataUrl({ keys, irn, timestamp? })

| Param | Type | Description | | ------------------ | -------- | ---------------------------------------- | | keys.public_key | string | FIRS public key (Base64 or PEM) | | keys.certificate | string | Certificate (Base64 string) | | irn | string | IRN stem (e.g. INV001-345SFG-20241011) | | timestamp? | number | UNIX timestamp in seconds |

Returns:

{
  publicKeyPem: string;
  irnWithTimestamp: string;
  dataJson: string;
  encrypted: Buffer;
  encryptedBase64: string;
  qrDataUrl: string;
}

🔒 How it maps to the FIRS shell guide

| FIRS Step | Equivalent in this Package | |------------|----------------------------| | jq -r '.public_key' ... | openssl base64 -d -out public_key.pem | decodePublicKeyToPem() automatically decodes Base64 or PEM | | jq --arg irn ... '{ irn: $irn, certificate: .certificate }' | makeDataJson() constructs the JSON | | openssl pkeyutl -encrypt ... | Node crypto.publicEncrypt using RSA PKCS#1 v1.5 | | base64 -i encrypted_data.bin -o encrypted_data.txt | Built-in Base64 conversion | | qrencode -o qr_code.png -t PNG < encrypted_data.txt | writeQrPng() via the qrcode package |


⚠️ Notes & Assumptions

  • Uses RSA PKCS#1 v1.5 padding (same as openssl pkeyutl -encrypt)

  • Compatible with standard 2048-bit RSA public keys

  • Payload format:

    {
      "irn": "INV001-ABC123.1731618237",
      "certificate": "Base64string..."
    }
  • Timestamps use UNIX seconds (not milliseconds)

  • Only public key encryption — no private key or decryption logic included


🧾 Example output

After successful execution, your output directory contains:

public_key.pem
data.json
encrypted_data.bin
encrypted_data.txt
qr_code.png

Scan qr_code.png with your MBS360 app or FIRS verifier to validate.


🧠 Troubleshooting

| Error | Cause | Fix | |-------|--------|-----| | bad base64 | Invalid key or malformed string | Ensure your public key is valid Base64 or PEM | | data too large for key size | Payload exceeds RSA key capacity | Use shorter IRN/certificate or a larger key | | QR unreadable | Used binary instead of Base64 | Ensure you pass Base64 data to writeQrPng() |


📜 License

MIT © 2025 @itssadon


🌐 Links