Skip to content

MinzNhat/Protected_QR

Repository files navigation

Protected QR Service

status: stable scope: protected-qr

Fixed-Geometry Physical-Digital QR Generator. This service creates a deterministic, copy-sensitive QR with an embedded center pattern and returns a Base64 PNG for client-side rendering or storage. The geometry is fixed to preserve Error Correction Level H compatibility.

Key Guarantees

  • Payload structure is fixed to 34 bytes.
  • Token length is ~81 chars: Base64Url(48) + "." + HMAC(32).
  • Output QR size is 600x600 px with border=1.
  • Center pattern crop for verification is 154x154 px.
  • Verification thresholds: authentic > 0.70, fake < 0.55.

Visual Demos

The service embeds a unique, copy-sensitive "Center Pattern" into a standard QR code. This pattern acts as a physical-digital fingerprint, distinguishing it from standard, easily copyable QRs.

Standard Standard QR Code
Figure 1A: Standard Generic QR
(Easily cloned)
Protected QR with Center Pattern
Figure 1B: Protected QR
(Copy-sensitive embedded pattern)

Architecture

  • Node.js API: REST interface, validation, token packing, audit storage.
  • Python Core: Stateless QR generator and verifier using Base64 I/O.
  • MongoDB: Audit and verification logs.

Project Layout

protected-qr-service/
    docker/
        Dockerfile.node
        Dockerfile.python
    python-core/
        app.py
        qr_center.py
        qr_decoder.py
        qr_protected.py
        requirements.txt
    src/
        config/
        controllers/
        dtos/
        middleware/
        routes/
        services/
        utils/
    docker-compose.yml
    swagger.yaml
    README.md

API Overview

  • POST /api/v1/qr/generate
  • POST /api/v1/qr/verify
  • GET /health

Swagger spec: swagger.yaml

Hex Input Format

All input fields must be hex strings of fixed length:

  • data_hash: 8 hex chars (4 bytes)
  • metadata_series: 16 hex chars (8 bytes)
  • metadata_issued: 16 hex chars (8 bytes)
  • metadata_expiry: 16 hex chars (8 bytes)

Example conversion guide:

  • 4 bytes (8 hex chars): a1b2c3d4
  • 8 bytes (16 hex chars): 1234567890abcdef

Generate Example

{
    "data_hash": "a1b2c3d4",
    "metadata_series": "1234567890abcdef",
    "metadata_issued": "0011223344556677",
    "metadata_expiry": "8899aabbccddeeff"
}

Verify Example

POST /api/v1/qr/verify with multipart form-data field image.

Response Shapes

Success response:

{
    "success": true,
    "data": {
        "token": "base64url.payload.hmac",
        "qr_image_base64": "iVBORw0..."
    }
}

Verification response:

{
    "is_authentic": true,
    "confidence_score": 0.85,
    "decoded_meta": {
        "data_hash": "a1b2c3d4",
        "metadata_series": "1234567890abcdef",
        "metadata_issued": "0011223344556677",
        "metadata_expiry": "8899aabbccddeeff"
    }
}

Error response:

{
    "success": false,
    "error": {
        "message": "Invalid request body",
        "details": {
            "errors": {
                "data_hash": ["Required"]
            }
        }
    }
}

Requirements

  • Docker + Docker Compose
  • Node.js 18+
  • Python 3.9+

Deployment

docker-compose up -d --build

Services:

Installation

cd protected-qr-service
npm install

Run (Production)

cd protected-qr-service
npm run build
npm run start

Run (Development)

Terminal 1 (Node API):

cd protected-qr-service
npm run dev

Terminal 2 (Python core):

cd protected-qr-service/python-core
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
uvicorn app:app --host 0.0.0.0 --port 8000

API Examples

Generate:

curl -X POST http://localhost:8080/api/v1/qr/generate \
    -H "Content-Type: application/json" \
    -d '{
        "data_hash": "a1b2c3d4",
        "metadata_series": "1234567890abcdef",
        "metadata_issued": "0011223344556677",
        "metadata_expiry": "8899aabbccddeeff"
    }'

Verify:

curl -X POST http://localhost:8080/api/v1/qr/verify \
    -F "image=@/path/to/qr.png"

Observability

  • Structured logs are emitted as JSON via Winston.
  • HTTP access logs use Morgan and flow into Winston.
  • Use your platform log aggregator (e.g., ELK, CloudWatch, Stackdriver) for indexing.

Environment Variables

See .env.example.

Name Required Description
PORT Yes API HTTP port.
MONGO_URI Yes MongoDB connection string.
MONGO_DB Yes MongoDB database name.
PYTHON_SERVICE_URL Yes Base URL for the Python core service.
HMAC_SECRET Yes HMAC secret for token signing.
LOG_LEVEL No Log level for structured output.
REQUEST_TIMEOUT_MS No Timeout for Python core requests.

Operational Notes

  • The QR geometry and thresholds are contract-bound and should not be modified.
  • The Python core is stateless and uses Base64 I/O only.
  • MongoDB stores audit logs and verification results for compliance.

Troubleshooting

  • If verification returns zero confidence, check image quality and ensure the QR is not cropped.
  • If the Python core fails to start, verify dependencies in python-core/requirements.txt.
  • If generate requests time out, increase REQUEST_TIMEOUT_MS in the environment.

Security Considerations

  • Rotate HMAC_SECRET regularly in production.
  • Place the API behind TLS and a rate limiter.
  • Use a private network for internal Python core access.

Bug Reports

Found a bug? Please report it using our Bug Report Form.

Feature Requests

Have an idea for a new feature? Submit a Feature Request Form.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support


Made with care by MinzNhat

Star us on GitHubVisit Website

Releases

No releases published

Packages

 
 
 

Contributors