{"_id":"@curia_/cg-plugin-lib-host","_rev":"4-b88a8df27aecd73cb779a5f83db25e9d","name":"@curia_/cg-plugin-lib-host","dist-tags":{"latest":"1.0.3"},"versions":{"1.0.0":{"name":"@curia_/cg-plugin-lib-host","version":"1.0.0","keywords":["plugin","iframe","common-ground","host","crypto","signing","verification","ecdsa","rsa","server","authentication","security"],"author":{"name":"Florian Glatz"},"license":"MIT","_id":"@curia_/cg-plugin-lib-host@1.0.0","maintainers":[{"name":"flotob","email":"florian@glatz-mahlberg.de"}],"dist":{"shasum":"503d9425772479719f6e7cd123ae4907347bd50b","tarball":"https://registry.npmjs.org/@curia_/cg-plugin-lib-host/-/cg-plugin-lib-host-1.0.0.tgz","fileCount":11,"integrity":"sha512-BGTmKmziB2aOjFXTU5qi8erFE/VV4G+l1Wh/dgEmc5XRSxSmwoZ2AN/x6y/8husi6FuZylxwz827nO6UdOMvCg==","signatures":[{"sig":"MEUCIQCNrbSH3A8ds2vCmFF9bL7qj4rL+/gK8iabGbdym7enaAIgdSlCBRTzKmkwbzfNZZFrCfdY+LtzX8f2ywUN/aRP2tU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":46012},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=16.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.js"}},"gitHead":"f2bb6228b6f9d42e74024b78c2ac54c446ab430e","scripts":{"dev":"tsc --watch","lint":"eslint src --ext .ts","test":"echo \"No tests yet\"","build":"tsc","clean":"rm -rf dist","prepublishOnly":"npm run clean && npm run build"},"_npmUser":{"name":"flotob","actor":{"name":"flotob","type":"user","email":"florian@glatz-mahlberg.de"},"email":"florian@glatz-mahlberg.de"},"_npmVersion":"11.2.0","description":"Drop-in replacement for Common Ground plugin host library with cryptographic signing and verification","directories":{},"_nodeVersion":"22.14.0","dependencies":{},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.0.0","@types/node":"^20.0.0"},"_npmOperationalInternal":{"tmp":"tmp/cg-plugin-lib-host_1.0.0_1752157577082_0.07810725917455308","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@curia_/cg-plugin-lib-host","version":"1.0.1","keywords":["plugin","iframe","common-ground","host","crypto","signing","verification","ecdsa","rsa","server","authentication","security"],"author":{"name":"Florian Glatz"},"license":"MIT","_id":"@curia_/cg-plugin-lib-host@1.0.1","maintainers":[{"name":"flotob","email":"florian@glatz-mahlberg.de"}],"dist":{"shasum":"41cdefe16d8cce6b999fcd490d986b7b9bd91cce","tarball":"https://registry.npmjs.org/@curia_/cg-plugin-lib-host/-/cg-plugin-lib-host-1.0.1.tgz","fileCount":15,"integrity":"sha512-bcztV8TdIqwDE+UanP60OCCn2D8XUzMzba3F11/qPD13kLIdsbD2IK0q7OQo5jc3Y8xzIOCvs9X7i5QYdQYLAg==","signatures":[{"sig":"MEYCIQD3c2XWihz7I38j4DyOVnic87J/HQqceEV/4Y/mGrDybwIhAJIiFn/q2rHZvgCra0/3pCdADq78qVsZghRRJuQHXHZf","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":52741},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=16.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.js"}},"gitHead":"f2bb6228b6f9d42e74024b78c2ac54c446ab430e","scripts":{"dev":"tsc --watch","lint":"eslint src --ext .ts","test":"echo \"No tests yet\"","build":"tsc","clean":"rm -rf dist","prepublishOnly":"npm run clean && npm run build"},"_npmUser":{"name":"flotob","actor":{"name":"flotob","type":"user","email":"florian@glatz-mahlberg.de"},"email":"florian@glatz-mahlberg.de"},"_npmVersion":"11.2.0","description":"Drop-in replacement for Common Ground plugin host library with cryptographic signing and verification","directories":{},"_nodeVersion":"22.14.0","dependencies":{},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.0.0","@types/node":"^20.0.0"},"_npmOperationalInternal":{"tmp":"tmp/cg-plugin-lib-host_1.0.1_1752158460720_0.292821071519739","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@curia_/cg-plugin-lib-host","version":"1.0.2","keywords":["plugin","iframe","common-ground","host","crypto","signing","verification","ecdsa","rsa","server","authentication","security"],"author":{"name":"Florian Glatz"},"license":"MIT","_id":"@curia_/cg-plugin-lib-host@1.0.2","maintainers":[{"name":"flotob","email":"florian@glatz-mahlberg.de"}],"dist":{"shasum":"d4d329e4392348af09c3c47984c7eb801a688700","tarball":"https://registry.npmjs.org/@curia_/cg-plugin-lib-host/-/cg-plugin-lib-host-1.0.2.tgz","fileCount":10,"integrity":"sha512-XNngK2zf8URN4Ncye4LZblsuvh3Qn36hBRtPY+WKSHVAZNsmubwmWxlNkX+qlJvgOzAaauGJFpC7JS8uFraaeQ==","signatures":[{"sig":"MEUCIH+oTaoLEnXKi86JVEGVXeiE2BEKDIPdgIcxQO+9kzMTAiEApX6lts8Pmq5d2462H05C7ruqibpYrKkj6zUzwy1x+og=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":43120},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=16.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.js"}},"gitHead":"2b2aae0335c2819ec67a4ba5b079461f27bb9c37","scripts":{"dev":"tsc --watch","lint":"eslint src --ext .ts","test":"echo \"No tests yet\"","build":"tsc","clean":"rm -rf dist","prepublishOnly":"npm run clean && npm run build"},"_npmUser":{"name":"flotob","email":"florian@glatz-mahlberg.de"},"_npmVersion":"11.2.0","description":"Drop-in replacement for Common Ground plugin host library with cryptographic signing and verification","directories":{},"_nodeVersion":"22.14.0","dependencies":{},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.0.0","@types/node":"^20.0.0"},"_npmOperationalInternal":{"tmp":"tmp/cg-plugin-lib-host_1.0.2_1753262882034_0.9605651324374171","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"@curia_/cg-plugin-lib-host","version":"1.0.3","description":"Drop-in replacement for Common Ground plugin host library with cryptographic signing and verification","author":{"name":"Florian Glatz"},"license":"MIT","main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.js"}},"scripts":{"build":"tsc","dev":"tsc --watch","clean":"rm -rf dist","prepublishOnly":"npm run clean && npm run build","test":"echo \"No tests yet\"","lint":"eslint src --ext .ts"},"keywords":["plugin","iframe","common-ground","host","crypto","signing","verification","ecdsa","rsa","server","authentication","security"],"dependencies":{},"devDependencies":{"typescript":"^5.0.0","@types/node":"^20.0.0"},"publishConfig":{"access":"public"},"engines":{"node":">=16.0.0"},"licenseText":"Copyright © 2025  Florian Glatz\n\nThis program is free software: you can redistribute it and/or modify\nit under the terms of the GNU Affero General Public License as\npublished by the Free Software Foundation, either version 3 of the\nLicense, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU Affero General Public License for more details.\n\nYou should have received a copy of the GNU Affero General Public License\nalong with this program. If not, see <https://www.gnu.org/licenses/>.\n\n----------------------------------------------------------------------\nALTERNATIVE COMMERCIAL LICENSING\n\nUse of this code outside the scope permitted by the AGPL‑3.0 (for\nexample, in proprietary or closed-source products) requires a separate\ncommercial licence.  The author is open to purchase or licence offers.\n\nTo discuss commercial terms, please contact:\n\n    Florian Glatz  <fg@blockchain.lawyer>\n----------------------------------------------------------------------","_id":"@curia_/cg-plugin-lib-host@1.0.3","dist":{"shasum":"0597322edce4f24f328cbe99e333753d62134adc","integrity":"sha512-kzljLwS8cqg16xOC0C+LoWRfEsClAP5jaS1bb1Egty92QiVxA3ro6jjDgyhBaFOIq6ZdjJ5VsTbikoZ27hojhg==","tarball":"https://registry.npmjs.org/@curia_/cg-plugin-lib-host/-/cg-plugin-lib-host-1.0.3.tgz","fileCount":12,"unpackedSize":43507,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCBQ1QFQV5YTbHgXFez0BgSI0LlOXm3ofbw25WsF6woJwIhAPG4oiI2px+4JUo1/HAVDBWVuOwhfqhDdHYEvm/vZFPb"}]},"_npmUser":{"name":"flotob","email":"florian@glatz-mahlberg.de"},"directories":{},"maintainers":[{"name":"flotob","email":"florian@glatz-mahlberg.de"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/cg-plugin-lib-host_1.0.3_1754598817663_0.5936184320360598"},"_hasShrinkwrap":false}},"time":{"created":"2025-07-10T14:26:16.949Z","modified":"2025-08-07T20:33:38.111Z","1.0.0":"2025-07-10T14:26:17.265Z","1.0.1":"2025-07-10T14:41:00.909Z","1.0.2":"2025-07-23T09:28:02.194Z","1.0.3":"2025-08-07T20:33:37.915Z"},"author":{"name":"Florian Glatz"},"license":"MIT","keywords":["plugin","iframe","common-ground","host","crypto","signing","verification","ecdsa","rsa","server","authentication","security"],"description":"Drop-in replacement for Common Ground plugin host library with cryptographic signing and verification","maintainers":[{"name":"flotob","email":"florian@glatz-mahlberg.de"}],"readme":"# @common-ground-dao/cg-plugin-lib-host\n\n**Drop-in replacement** for Common Ground's server-side plugin library. This package provides cryptographic signing capabilities for plugins that need to authenticate requests to the host application.\n\n## 🎯 Purpose\n\nThis library handles the **server-side cryptographic signing** that Common Ground plugins require. It provides the exact same API as the original `@common-ground-dao/cg-plugin-lib-host` but works with our custom host system.\n\n## 📦 Installation\n\n```bash\n# Replace the original CG host library with ours\nnpm install @common-ground-dao/cg-plugin-lib-host\n\n# Or with yarn\nyarn add @common-ground-dao/cg-plugin-lib-host\n```\n\n## 🚀 Usage\n\n### Basic Signing (Exactly like original CG)\n\n```typescript\nimport { CgPluginLibHost } from '@common-ground-dao/cg-plugin-lib-host';\n\n// Initialize with your plugin's key pair\nconst host = await CgPluginLibHost.initialize(\n  privateKey,  // Your plugin's private key (base64 encoded)\n  publicKey    // Your plugin's public key (base64 encoded)\n);\n\n// Sign a request\nconst { request, signature } = await host.signRequest(requestData);\n```\n\n### Next.js API Route Example\n\n```typescript\n// app/api/sign/route.ts\nimport { CgPluginLibHost } from '@common-ground-dao/cg-plugin-lib-host';\n\nconst privateKey = process.env.NEXT_PRIVATE_PRIVKEY as string;\nconst publicKey = process.env.NEXT_PUBLIC_PUBKEY as string;\n\nexport async function POST(req: Request) {\n  const body = await req.json();\n\n  const host = await CgPluginLibHost.initialize(privateKey, publicKey);\n  const { request, signature } = await host.signRequest(body);\n\n  return Response.json({ request, signature });\n}\n```\n\n### Express.js Example\n\n```typescript\nimport express from 'express';\nimport { CgPluginLibHost } from '@common-ground-dao/cg-plugin-lib-host';\n\nconst app = express();\napp.use(express.json());\n\napp.post('/api/sign', async (req, res) => {\n  try {\n    const host = await CgPluginLibHost.initialize(\n      process.env.PRIVATE_KEY,\n      process.env.PUBLIC_KEY\n    );\n    \n    const { request, signature } = await host.signRequest(req.body);\n    res.json({ request, signature });\n  } catch (error) {\n    res.status(500).json({ error: error.message });\n  }\n});\n```\n\n## 🔧 API Reference\n\n### `CgPluginLibHost.initialize(privateKey, publicKey)`\n\nInitialize the host library with your plugin's key pair.\n\n**Parameters:**\n- `privateKey: string` - Plugin's private key (base64 encoded PKCS#8 format)\n- `publicKey: string` - Plugin's public key (base64 encoded SPKI format)\n\n**Returns:** `Promise<CgPluginLibHost>` - Initialized instance\n\n**Example:**\n```typescript\nconst host = await CgPluginLibHost.initialize(\n  'MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg...',\n  'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...'\n);\n```\n\n### `signRequest(requestData)`\n\nSign a request using the plugin's private key.\n\n**Parameters:**\n- `requestData: any` - Data to be signed (typically the API request payload)\n\n**Returns:** `Promise<{ request: any, signature: string }>`\n\n**Example:**\n```typescript\nconst requestData = {\n  method: 'getUserInfo',\n  iframeUid: 'iframe_12345',\n  requestId: 'req_67890',\n  timestamp: Date.now()\n};\n\nconst { request, signature } = await host.signRequest(requestData);\n// request: normalized request data\n// signature: base64 encoded ECDSA signature\n```\n\n### `verifySignature(data, signature)` \n\nVerify a signature (utility method for testing).\n\n**Parameters:**\n- `data: any` - Original data that was signed\n- `signature: string` - Base64 encoded signature to verify\n\n**Returns:** `Promise<boolean>` - Whether the signature is valid\n\n**Example:**\n```typescript\nconst isValid = await host.verifySignature(requestData, signature);\nconsole.log('Signature valid:', isValid);\n```\n\n### `CgPluginLibHost.generateKeyPair()` (Static Method)\n\nGenerate a new ECDSA key pair for plugin development.\n\n**Returns:** `Promise<{ privateKey: string, publicKey: string }>` - Base64 encoded key pair\n\n**Example:**\n```typescript\nconst { privateKey, publicKey } = await CgPluginLibHost.generateKeyPair();\nconsole.log('Private Key:', privateKey);\nconsole.log('Public Key:', publicKey);\n```\n\n## 🔐 Cryptographic Details\n\n### Algorithm\n- **Signature Algorithm**: ECDSA with P-256 curve\n- **Hash Function**: SHA-256\n- **Key Format**: PKCS#8 (private), SPKI (public)\n- **Encoding**: Base64\n\n### Security Features\n\n1. **Deterministic Signing**: Same input always produces same signature\n2. **Timestamp Inclusion**: Prevents replay attacks\n3. **Data Normalization**: Consistent object key ordering\n4. **Error Handling**: Comprehensive validation and error messages\n\n### Request Signing Process\n\n1. **Normalize Data**: Sort object keys recursively for consistency\n2. **Add Timestamp**: Include timestamp if not present\n3. **Serialize**: Convert to JSON string\n4. **Sign**: Create ECDSA signature using SHA-256\n5. **Encode**: Convert signature to base64 for transmission\n\n## 🔄 Migration from Original CG\n\n### No Code Changes Required!\n\nIf you have an existing Common Ground plugin using the host library:\n\n1. **Update package source**: Point to our npm registry or local packages\n2. **Update dependencies**: `yarn add @common-ground-dao/cg-plugin-lib-host`\n3. **Test**: Your signing endpoints should work exactly the same\n\n### Environment Variables\n\nMake sure your plugin has the required environment variables:\n\n```bash\n# .env (Next.js example)\nNEXT_PRIVATE_PRIVKEY=MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg...\nNEXT_PUBLIC_PUBKEY=MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...\n\n# .env (Node.js example)\nPRIVATE_KEY=MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg...\nPUBLIC_KEY=MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...\n```\n\n## 🛠️ Development Setup\n\n### Generating Development Keys\n\n```typescript\nimport { CgPluginLibHost } from '@common-ground-dao/cg-plugin-lib-host';\n\n// Generate a new key pair for development\nconst keys = await CgPluginLibHost.generateKeyPair();\n\nconsole.log('Add these to your .env file:');\nconsole.log(`NEXT_PRIVATE_PRIVKEY=${keys.privateKey}`);\nconsole.log(`NEXT_PUBLIC_PUBKEY=${keys.publicKey}`);\n```\n\n### Key Pair Management\n\n**⚠️ Important Security Notes:**\n\n1. **Private Key Security**: Never expose private keys in client-side code\n2. **Environment Variables**: Store keys in secure environment variables\n3. **Key Rotation**: Regularly rotate keys in production\n4. **Backup**: Securely backup your key pairs\n\n### Testing Your Implementation\n\n```typescript\n// Test your signing endpoint\nconst testData = {\n  method: 'getUserInfo',\n  iframeUid: 'test_iframe',\n  requestId: 'test_request',\n  timestamp: Date.now()\n};\n\nconst host = await CgPluginLibHost.initialize(privateKey, publicKey);\nconst { request, signature } = await host.signRequest(testData);\n\n// Verify the signature\nconst isValid = await host.verifySignature(request, signature);\nconsole.log('Signature verification:', isValid ? 'PASS' : 'FAIL');\n```\n\n## 🐛 Error Handling\n\nCommon errors and solutions:\n\n```typescript\ntry {\n  const host = await CgPluginLibHost.initialize(privateKey, publicKey);\n  const result = await host.signRequest(data);\n} catch (error) {\n  if (error.message.includes('Invalid key format')) {\n    // Check that your keys are properly base64 encoded\n    console.error('Key format error - check your environment variables');\n  } else if (error.message.includes('Failed to sign request')) {\n    // Signing operation failed\n    console.error('Signing failed - check your private key');\n  } else {\n    console.error('Unexpected error:', error.message);\n  }\n}\n```\n\n## 🏗️ Architecture Integration\n\n### How It Fits in the System\n\n```\nPlugin Frontend (Browser)\n    ↓\nClient Library (@common-ground-dao/cg-plugin-lib)\n    ↓\nHTTP Request to /api/sign\n    ↓\nHost Library (@common-ground-dao/cg-plugin-lib-host) ← YOU ARE HERE\n    ↓\nSigned Request via postMessage\n    ↓\nHost Application validates and responds\n```\n\n### Server Requirements\n\n- **Node.js**: 18+ (for WebCrypto API support)\n- **TypeScript**: 5+ (recommended)\n- **Framework**: Any (Next.js, Express, Fastify, etc.)\n\n## 📊 Performance\n\n### Benchmarks\n\n- **Key Generation**: ~50ms\n- **Request Signing**: ~5ms\n- **Signature Verification**: ~3ms\n- **Memory Usage**: <1MB per instance\n\n### Optimization Tips\n\n1. **Reuse Instances**: Initialize once, reuse the same instance\n2. **Key Caching**: Keys are cached after import for performance\n3. **Async Operations**: All operations are async and non-blocking\n\n## 🔧 Building the Library\n\n```bash\n# Build TypeScript to JavaScript\nyarn build\n\n# Watch for changes during development\nyarn dev\n\n# Clean build artifacts\nyarn clean\n```\n\n## 🧪 Testing\n\n### Unit Tests (Example)\n\n```typescript\nimport { CgPluginLibHost } from './src';\n\ndescribe('CgPluginLibHost', () => {\n  test('should generate valid key pairs', async () => {\n    const keys = await CgPluginLibHost.generateKeyPair();\n    expect(keys.privateKey).toBeDefined();\n    expect(keys.publicKey).toBeDefined();\n  });\n\n  test('should sign and verify requests', async () => {\n    const keys = await CgPluginLibHost.generateKeyPair();\n    const host = await CgPluginLibHost.initialize(keys.privateKey, keys.publicKey);\n    \n    const data = { test: 'data' };\n    const { request, signature } = await host.signRequest(data);\n    \n    const isValid = await host.verifySignature(request, signature);\n    expect(isValid).toBe(true);\n  });\n});\n```\n\n### Integration Testing\n\nTest with the complete system:\n\n```bash\n# Start the host application\ncd ../host-app && yarn dev\n\n# Test your plugin with signing\n# Load plugin in host application and verify API calls work\n```\n\n## 📊 Compatibility Matrix\n\n| Original CG Version | Our Implementation | Status |\n|--------------------|--------------------|---------|\n| 0.9.6 | 0.9.6 | ✅ Fully compatible |\n| Earlier versions | 0.9.6 | ✅ Forward compatible |\n\n## 🤝 Contributing\n\nThis package is part of the standalone embed system. See the [root README](../../README.md) for contribution guidelines.\n\n## 📄 License\n\nMIT License\n\n---\n\n**Note**: This library handles sensitive cryptographic operations. Always follow security best practices when deploying to production. ","readmeFilename":"README.md"}