UNPKG

@eventcatalog/license

Version:

License verification for EventCatalog

282 lines (205 loc) 8.65 kB
# @eventcatalog/license License verification library for EventCatalog supporting both offline JWT verification and online license key validation. ## Features - **Dual verification modes** - Offline JWT tokens and online license keys - **Ed25519 signatures** - Using industry-standard elliptic curve cryptography for offline verification - **JWT-based offline licensing** - Standard token format with custom EventCatalog claims - **Online license key validation** - Real-time verification with EventCatalog API - **Input validation** - Secure license key format validation - **Caching** - Verification results cached for performance - **Machine binding** - Optional fingerprint-based license binding (offline mode) - **Enhanced error handling** - Structured error codes for different failure scenarios - **TypeScript** - Full type safety and IntelliSense support ## Installation ```bash npm install @eventcatalog/license ``` ## Quick Start ### Offline JWT Verification ```typescript import { verifyOfflineLicense, isFeatureEnabled } from '@eventcatalog/license'; // Verify offline JWT license (auto-locates license file) try { const entitlements = await verifyOfflineLicense(); console.log('License valid for:', entitlements.org); } catch (error) { console.error('License verification failed:', error.message); } // Check if a plugin is enabled if (isFeatureEnabled('@eventcatalog/generator-asyncapi')) { console.log('AsyncAPI generator is licensed'); } ``` ### Online License Key Verification ```typescript import { verifyOnlineLicense } from '@eventcatalog/license'; // Verify online license key try { const isValid = await verifyOnlineLicense('XXXX-XXXX-XXXX-XXXX-XXXX-XXXX', '@eventcatalog/eventcatalog-scale'); if (isValid) { console.log('License key is valid'); } } catch (error) { console.error('License key verification failed:', error.message); } ``` ## API Reference ### `verifyOfflineLicense(opts?: VerifyOptions): Promise<Entitlements>` Verifies an offline JWT license and returns entitlements. Results are cached after first successful verification. **Options:** - `licensePath?: string` - Custom path to license file (overrides auto-discovery) - `audience?: string` - Expected JWT audience (default: "EventCatalog") - `issuer?: string` - Expected JWT issuer (default: "EventCatalog Ltd") - `clockTolerance?: string` - Clock skew tolerance (default: "12h") - `currentVersion?: string` - EventCatalog version for range validation - `fingerprintProvider?: () => string | null` - Machine fingerprint provider **Example with options:** ```typescript const entitlements = await verifyOfflineLicense({ licensePath: '/custom/path/license.jwt', audience: 'MyEventCatalog', clockTolerance: '24h', fingerprintProvider: () => getMachineId(), }); ``` ### `verifyOnlineLicense(key: string, plugin: string): Promise<boolean>` Verifies a license key online using the EventCatalog API. **Parameters:** - `key: string` - License key in format `XXXX-XXXX-XXXX-XXXX-XXXX-XXXX` - `plugin: string` - Plugin identifier to verify against **Supported plugins:** - `@eventcatalog/eventcatalog-starter` - `@eventcatalog/eventcatalog-scale` - `@eventcatalog/eventcatalog-enterprise` **Example:** ```typescript const isValid = await verifyOnlineLicense('XXXX-XXXX-XXXX-XXXX-XXXX-XXXX', '@eventcatalog/eventcatalog-scale'); ``` ### `isFeatureEnabled(name: string): boolean` Checks if a plugin or feature is enabled in the current license. ```typescript // Check string plugin names if (isFeatureEnabled('@eventcatalog/generator-openapi')) { // Enable OpenAPI generator } // Also works with object-style plugin specs in license ``` ### `getEntitlements(): Entitlements | null` Returns currently cached entitlements without re-verification. ```typescript const entitlements = getEntitlements(); if (entitlements?.org) { console.log(`License for: ${entitlements.org}`); } ``` ## License Discovery License files are located in this order: 1. `EC_LICENSE` environment variable (file path) 2. `./license.jwt` (current directory) 3. `/etc/eventcatalog/license.jwt` (system-wide) ## Environment Variables ### `EC_LICENSE` Path to license file (overrides auto-discovery). ```bash export EC_LICENSE="/path/to/my/license.jwt" ``` ### `EC_PUBLIC_KEY_PATH` Path to custom public key PEM file (overrides bundled key). ```bash export EC_PUBLIC_KEY_PATH="/path/to/custom/public.pem" ``` ## License Format Licenses are JWT tokens with standard and EventCatalog-specific claims: **Standard Claims:** - `iss` - Issuer ("EventCatalog Ltd") - `aud` - Audience ("EventCatalog") - `iat` - Issued at timestamp - `nbf` - Not before timestamp - `exp` - Expiration timestamp **EventCatalog Claims:** - `licenseId` - Unique license identifier - `org` - Organization name - `plugins` - Enabled plugins array - `fingerprint` - Machine binding fingerprint (optional) **Example payload:** ```json { "iss": "EventCatalog Ltd", "aud": "EventCatalog", "iat": 1672531200, "nbf": 1672531200, "exp": 1735689600, "licenseId": "ec_2025_000001", "org": "Acme Corp", "plugins": [ "@eventcatalog/generator-asyncapi", { "name": "@eventcatalog/generator-openapi", "versionRange": "^1.0.0" } ] } ``` ### Offline License Errors | Error Code | Message | Description | | ------------------------------ | ---------------------------------------------------------------------- | -------------------------------------------- | | `LICENSE_EXPIRED` | License has expired | JWT token past expiration time | | `LICENSE_NOT_YET_VALID` | License is not yet valid | JWT token not yet active | | `LICENSE_VALIDATION_FAILED` | License validation failed - invalid issuer or audience | JWT claims validation failed | | `LICENSE_SIGNATURE_INVALID` | License signature verification failed - invalid or tampered license | Digital signature verification failed | | `LICENSE_FILE_NOT_FOUND` | License file not found | No license file found in discovery locations | | `LICENSE_FILE_EMPTY` | License file is empty | License file exists but contains no content | | `LICENSE_FINGERPRINT_MISMATCH` | License fingerprint mismatch - license is bound to a different machine | Machine binding violation | ### Online License Errors | Error Code | Message | Description | | ---------------------------- | -------------------------------------------------------------------------- | ----------------------------------------- | | `INVALID_LICENSE_KEY_FORMAT` | Invalid license key format. Expected format: XXXX-XXXX-XXXX-XXXX-XXXX-XXXX | License key doesn't match required format | ## Building ```bash # Install dependencies npm install # Build TypeScript npm run build # The compiled package will be in ./dist/ ``` ## Development The package structure: ``` eventcatalog-license/ ├── src/ │ ├── index.ts # Public API exports │ ├── types.ts # TypeScript type definitions │ ├── key.ts # Public key loading & validation │ └── verify.ts # Verification logic (offline & online) ├── assets/ │ └── ec-ed25519-public.pem # Public key for offline verification └── dist/ # Compiled output ``` ### Testing License Verification #### Offline JWT Testing 1. Create a test license file: ```bash echo "your.jwt.token.here" > license.jwt ``` 2. Test programmatically: ```typescript import { verifyOfflineLicense } from '@eventcatalog/license'; try { const entitlements = await verifyOfflineLicense(); console.log('✓ Valid license:', entitlements); } catch (error) { console.error('✗ Invalid license:', error.message); } ``` #### Online License Key Testing ```typescript import { verifyOnlineLicense } from '@eventcatalog/license'; try { const isValid = await verifyOnlineLicense('XXXX-XXXX-XXXX-XXXX-XXXX-XXXX', '@eventcatalog/eventcatalog-scale'); console.log('✓ License key valid:', isValid); } catch (error) { console.error('✗ License key invalid:', error.message); } ``` ## License MIT