Files
promptfoo--promptfoo/examples/provider-http/auth-signature-pfx/app.js
T
wehub-resource-sync 0d3cb498a3
CI / Shell Format Check (push) Has been cancelled
CI / Check Ruby (3.4) (push) Has been cancelled
CI / CI Config (push) Has been cancelled
CI / Test on Node ${{ matrix.node }} and ${{ matrix.os }}${{ matrix.shard && format(' (shard {0}/3)', matrix.shard) || '' }} (push) Has been cancelled
CI / Build on Node ${{ matrix.node }} (push) Has been cancelled
CI / Style Check (push) Has been cancelled
CI / Generate Assets (push) Has been cancelled
CI / Check Python (3.14) (push) Has been cancelled
CI / Check Python (3.9) (push) Has been cancelled
CI / Build Docs (push) Has been cancelled
CI / Code Scan Action (push) Has been cancelled
CI / Site tests (push) Has been cancelled
CI / webui tests (push) Has been cancelled
CI / Run Integration Tests (push) Has been cancelled
CI / Run Smoke Tests (push) Has been cancelled
CI / Go Tests (push) Has been cancelled
CI / Share Test (push) Has been cancelled
CI / Redteam (Production API) (push) Has been cancelled
CI / Redteam (Staging API) (push) Has been cancelled
CI / GitHub Actions Lint (push) Has been cancelled
CI / Check Ruby (3.0) (push) Has been cancelled
release-please / release-please (push) Has been cancelled
release-please / build (push) Has been cancelled
release-please / publish-npm (push) Has been cancelled
release-please / publish-npm-backfill (push) Has been cancelled
release-please / docker (push) Has been cancelled
release-please / publish-code-scan-action (push) Has been cancelled
release-please / attest-code-scan-action (push) Has been cancelled
Deploy local.promptfoo.app / Deploy to Cloudflare Pages (push) Has been cancelled
Test and Publish Multi-arch Docker Image / test (push) Has been cancelled
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-amd64 platform:linux/amd64 runner:ubuntu-latest]) (push) Has been cancelled
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-arm64 platform:linux/arm64 runner:ubuntu-24.04-arm]) (push) Has been cancelled
Test and Publish Multi-arch Docker Image / merge-docker-digests (push) Has been cancelled
Test and Publish Multi-arch Docker Image / Attest Multi-arch Image (push) Has been cancelled
Validate Renovate Config / Validate Renovate Configuration (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:24:08 +08:00

147 lines
4.5 KiB
JavaScript

const express = require('express');
const https = require('https');
const fs = require('fs');
const crypto = require('crypto');
const pem = require('pem');
const rateLimit = require('express-rate-limit');
const app = express();
app.use(express.json());
const chatRateLimiter = rateLimit({
windowMs: 60 * 1000,
max: 30,
standardHeaders: true,
legacyHeaders: false,
});
// Add signature validation configuration for PFX
const SIGNATURE_CONFIG = {
pfxPath: './certificate.pfx',
pfxPassword: 'password', // In real apps, use environment variables
signatureHeader: 'signature',
timestampHeader: 'timestamp',
clientIdHeader: 'client-id',
signatureValidityMs: 300000, // 5 minutes
signatureDataTemplate: 'promptfoo-app{{timestamp}}',
signatureAlgorithm: 'SHA256',
};
// PFX certificate configuration for HTTPS
const HTTPS_OPTIONS = {
pfx: fs.readFileSync(SIGNATURE_CONFIG.pfxPath),
passphrase: SIGNATURE_CONFIG.pfxPassword,
};
// Load PFX certificate and extract public key
let publicKey;
async function loadPfxCertificate() {
return new Promise((resolve, reject) => {
pem.readPkcs12(
SIGNATURE_CONFIG.pfxPath,
{ p12Password: SIGNATURE_CONFIG.pfxPassword },
(err, result) => {
if (err) {
reject(new Error(`Error reading PKCS12/PFX: ${err.message}`));
return;
}
try {
// Create public key from the certificate
publicKey = crypto.createPublicKey(result.cert);
console.log(
'Successfully loaded PFX certificate and extracted public key using pem library',
);
resolve();
} catch (error) {
reject(new Error(`Error creating public key from certificate: ${error.message}`));
}
},
);
});
}
// Signature validation middleware
function validateSignature(req, res, next) {
try {
const signature = req.headers[SIGNATURE_CONFIG.signatureHeader];
const timestamp = req.headers[SIGNATURE_CONFIG.timestampHeader];
const clientId = req.headers[SIGNATURE_CONFIG.clientIdHeader];
// Check if all required headers are present
if (!signature || !timestamp || !clientId) {
console.warn('Request rejected: Missing signature headers');
return res.status(401).json({ error: 'Missing signature headers' });
}
// Check timestamp validity
const now = Date.now();
const requestTime = Number.parseInt(timestamp, 10);
if (Number.isNaN(requestTime) || now - requestTime > SIGNATURE_CONFIG.signatureValidityMs) {
console.warn('Request rejected: Signature expired or invalid timestamp');
return res.status(401).json({ error: 'Signature expired or invalid timestamp' });
}
// Generate signature data using the template
const signatureData = SIGNATURE_CONFIG.signatureDataTemplate.replace(
'{{timestamp}}',
timestamp,
);
// Verify signature using the public key from PFX
const verify = crypto.createVerify(SIGNATURE_CONFIG.signatureAlgorithm);
verify.update(signatureData);
const isValid = verify.verify(publicKey, signature, 'base64');
if (!isValid) {
console.warn('Request rejected: Invalid signature');
return res.status(401).json({ error: 'Invalid signature' });
}
console.log('PFX signature checks out... continuing');
next();
} catch (error) {
console.error('Error validating signature:', error);
return res.status(500).json({ error: 'Error validating signature' });
}
}
app.post('/chat', chatRateLimiter, validateSignature, async (req, res) => {
try {
return res.json({ message: 'hello from PFX authenticated endpoint' });
} catch (error) {
console.error('Error processing chat request:', error);
return res.status(500).json({ error: error.message });
}
});
const PORT = process.env.PORT || 2347;
// Initialize the server
async function startServer() {
try {
// Load PFX certificate first
await loadPfxCertificate();
// Create HTTPS server with PFX certificate
https.createServer(HTTPS_OPTIONS, app).listen(PORT, (error) => {
if (error) {
console.error(`Failed to start HTTPS server: ${error.message}`);
process.exit(1);
return;
}
console.info(`PFX HTTPS server is running on port ${PORT}`);
console.info('Server is using PFX certificate for SSL/TLS and signature validation');
});
} catch (error) {
console.error('Error loading PFX certificate:', error.message);
console.error('Make sure certificate.pfx exists and password is correct');
process.exit(1);
}
}
// Start the server
startServer();