@binlebin/c2pa-ssl
Version:
Node.js wrapper for C2PA content authentication using Rust CLI backend
314 lines (244 loc) • 7.56 kB
Markdown
# Firebase Functions Deployment Guide
This guide explains how to deploy the C2PA-SSL service to Firebase Functions.
## Prerequisites
1. Firebase CLI installed (`npm install -g firebase-tools`)
2. A Firebase project with Functions enabled
3. The Linux binary built (`npm run build:linux`)
## Setup Steps
### 1. Create a Firebase Functions Project
```bash
mkdir my-c2pa-firebase-functions
cd my-c2pa-firebase-functions
firebase init functions
```
Choose:
- Language: JavaScript
- ESLint: No (optional)
- Install dependencies: Yes
### 2. Install the C2PA-SSL Package
```bash
cd functions
npm install /path/to/c2pa-ssl
# or if published to npm:
# npm install c2pa-ssl
```
### 3. Create the Function
Edit `functions/index.js`:
```javascript
const functions = require("firebase-functions");
const C2PAService = require("c2pa-ssl");
let serviceInstance = null;
// Initialize the service once
const getService = async () => {
if (!serviceInstance) {
serviceInstance = new C2PAService();
await serviceInstance.start();
}
return serviceInstance;
};
// Health check endpoint
exports.health = functions
.runWith({
memory: "1GB",
timeoutSeconds: 60,
})
.https.onRequest(async (req, res) => {
try {
await getService(); // Ensure service is started
res.json({
status: "healthy",
platform: process.platform,
timestamp: new Date().toISOString(),
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Sign endpoint
exports.sign = functions
.runWith({
memory: "2GB",
timeoutSeconds: 300,
secrets: ["C2PA_PRIVATE_KEY"],
})
.https.onRequest(async (req, res) => {
try {
const service = await getService();
// Forward the request to the internal service
// The service runs on port 8080 internally
const proxyReq = require("http").request({
host: "localhost",
port: 8080,
path: "/sign",
method: req.method,
headers: req.headers,
}, (proxyRes) => {
res.writeHead(proxyRes.statusCode, proxyRes.headers);
proxyRes.pipe(res);
});
req.pipe(proxyReq);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Verify endpoint
exports.verify = functions
.runWith({
memory: "1GB",
timeoutSeconds: 300,
secrets: ["C2PA_PRIVATE_KEY"],
})
.https.onRequest(async (req, res) => {
try {
const service = await getService();
// Similar proxy logic for verify
const proxyReq = require("http").request({
host: "localhost",
port: 8080,
path: "/verify",
method: req.method,
headers: req.headers,
}, (proxyRes) => {
res.writeHead(proxyRes.statusCode, proxyRes.headers);
proxyRes.pipe(res);
});
req.pipe(proxyReq);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
```
### 4. Configure Secrets
Set up the private key as a Firebase secret:
```bash
# Create the secret
firebase functions:secrets:create C2PA_PRIVATE_KEY
# When prompted, paste your private key content
```
### 5. Update firebase.json
Add the following to your `firebase.json`:
```json
{
"functions": {
"runtime": "nodejs18",
"source": "functions",
"ignore": [
"node_modules",
".git",
"firebase-debug.log",
"firebase-debug.*.log"
]
}
}
```
### 6. Deploy
```bash
firebase deploy --only functions
```
## Important Considerations
### Memory and Timeout Settings
- **Memory**: Minimum 1GB recommended, 2GB for video processing
- **Timeout**: 300 seconds for large file processing
- **Cold Start**: First request may take 10-20 seconds
### File Size Limits
Firebase Functions has the following limits:
- Request size: 10MB (HTTP trigger)
- Response size: 10MB
- Memory: Max 8GB
- Timeout: Max 540 seconds
For larger files, consider using Cloud Storage:
```javascript
exports.signFromStorage = functions
.runWith({
memory: "4GB",
timeoutSeconds: 540,
secrets: ["C2PA_PRIVATE_KEY"],
})
.storage.object().onFinalize(async (object) => {
// Process files uploaded to Cloud Storage
const bucket = admin.storage().bucket(object.bucket);
const file = bucket.file(object.name);
// Download, sign, and upload back to storage
});
```
### Environment Variables
The service expects:
- `C2PA_PRIVATE_KEY`: Set via Firebase secrets
- Certificate is embedded in the package
### Monitoring
View logs:
```bash
firebase functions:log
```
### Cost Optimization
1. Use minimum memory needed
2. Implement caching for repeated operations
3. Consider using Cloud Run for better control over instances
## Troubleshooting
### Binary not found
- Ensure the Linux binary exists in
`node_modules/c2pa-ssl/bin/c2pa-service-linux`
- Check that the package was built with `npm run build:linux`
### Certificate errors
- Verify the private key secret is properly set
- Check logs for detailed error messages
### Memory errors
- Increase memory allocation in `runWith` options
- For video files, use at least 4GB
### Timeout errors
- Increase timeout in `runWith` options
- Consider breaking large operations into chunks
## Example Client Usage
```javascript
const FormData = require("form-data");
const fs = require("fs");
const axios = require("axios");
async function signFile(filePath) {
const form = new FormData();
form.append("file", fs.createReadStream(filePath));
form.append("title", "My signed content");
const response = await axios.post(
"https://your-project.cloudfunctions.net/sign",
form,
{
headers: form.getHeaders(),
maxContentLength: Infinity,
maxBodyLength: Infinity,
},
);
// Response contains base64 encoded signed file
const signedData = Buffer.from(response.data.signed_data, "base64");
fs.writeFileSync("signed-output.jpg", signedData);
}
```
## Performance Tips
1. **Reuse Service Instance**: The example above reuses the service instance
across invocations
2. **Warm Functions**: Use Cloud Scheduler to ping the health endpoint every 5
minutes
3. **Regional Deployment**: Deploy to regions close to your users
4. **VPC Connector**: Not needed unless accessing private resources
## Security Best Practices
1. Use Firebase App Check to prevent abuse
2. Implement rate limiting
3. Validate file types and sizes
4. Use Cloud Armor for DDoS protection
5. Enable audit logging
## Alternative: Cloud Run
For more control and better performance, consider deploying to Cloud Run
instead:
```bash
# Build container
docker build -t gcr.io/YOUR_PROJECT/c2pa-service .
# Push to Container Registry
docker push gcr.io/YOUR_PROJECT/c2pa-service
# Deploy to Cloud Run
gcloud run deploy c2pa-service \
--image gcr.io/YOUR_PROJECT/c2pa-service \
--platform managed \
--region us-central1 \
--memory 2Gi \
--timeout 300 \
--set-env-vars "CERTIFICATE_PATH=/app/certs/anh_ec.pem" \
--set-secrets "PRIVATE_KEY_CONTENT=C2PA_PRIVATE_KEY:latest"
```