Skip to content

func-api-devices-backup-post ​

Description ​

Stores an encrypted configuration backup for a device. The caller (the FireFly Controller firmware) supplies the raw FFCE-format ciphertext blob produced on-device by AES-256-GCM with key_backup (HKDF-derived from the eFuse master key with label firefly-backup-v1). The Lambda validates the device-identity headers, then stores the blob in S3 keyed by the device UUID and records last_backup_date in DynamoDB.

This endpoint has no Cognito JWT authorizer — it is authenticated solely by the device's cryptographic signature.

Invocation ​

Invoked by API Gateway on an HTTP POST /devices/{uuid}/backup request (no JWT authorizer).

Sequence Diagram ​

Sequence Diagram

API Endpoints ​

MethodPathAuthDescription
POST/devices/{uuid}/backupDevice signature (headers)Store encrypted configuration backup

Request Headers ​

HeaderRequiredDescription
X-Device-UUIDYesMust match the {uuid} path parameter
X-Device-NonceYesBase64-encoded 32-byte random nonce
X-Device-TimestampYesISO 8601 UTC timestamp (e.g. 2025-05-09T12:00:00Z)
X-Device-SignatureYesBase64-encoded DER ECDSA P-256 signature over SHA-256(nonce || timestamp)
Content-TypeYesMust be application/octet-stream
ETagNoPlaintext SHA-256 hex digest of the backup content (read from /backup.etag on the device). Stored as S3 object metadata and returned by GET /devices/{uuid}/backup so the controller can restore /backup.etag after a restore. When absent, the 304 check is skipped.
If-None-MatchNoPlaintext SHA-256 ETag of the backup the client believes is already stored (as returned by a previous POST or GET). Only evaluated when the ETag request header is also present; returns 304 if it matches the stored S3 metadata ETag.

Request Body ​

Raw FFCE-format encrypted binary blob (max 512 KB). The blob starts with the 4-byte magic FFCE and contains the AES-256-GCM encrypted configuration.

Response Body ​

json
{
  "message": "Backup stored",
  "last_backup_date": "2025-05-09T12:00:00Z"
}

Response Codes ​

CodeReason
200 OKBackup stored successfully
304 Not ModifiedBackup content identical to existing — only returned when both ETag and If-None-Match request headers are present and If-None-Match matches the stored plaintext SHA-256 ETag
400 Bad RequestMissing/invalid headers, invalid Base64, or body not valid FFCE format
401 UnauthorizedDevice UUID not found, signature invalid, or timestamp outside the acceptance window
403 ForbiddenX-Device-UUID header does not match {uuid} path parameter
413 Payload Too LargeBody exceeds 512 KB limit
500 Internal Server ErrorUnhandled exception

See the API Reference for full schema documentation.

Deployment ​

See the deployment workflow documentation for workflow steps, infrastructure dependencies, and failure scenarios.