# 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"
```
