ifabula/sevola-interceptor-helper

Laravel database interceptor for automatic field encryption/decryption using Sevola SDK

Installs: 2

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Forks: 0

pkg:composer/ifabula/sevola-interceptor-helper

v1.0.2 2025-11-12 15:35 UTC

This package is not auto-updated.

Last update: 2025-12-24 09:07:53 UTC


README

Zero-integration encryption/decryption for Laravel applications powered by the Sevola SDK.

Configure once in Sevola CMS, install this package, and every Eloquent model automatically honours the encryption rules—no traits, no code changes.

Latest Version License

Table of Contents

Why the Helper Exists

Enterprises often need to encrypt Personally Identifiable Information (PII) without rewriting existing Laravel codebases. The Sevola PHP Interceptor Helper reads field-level encryption rules from Sevola CMS, transparently encrypts data before it is written, and decrypts it again when read—so developers keep using Eloquent exactly as before.

Key Features

  • 🔐 True zero-integration – encryption happens automatically for every Eloquent model and query builder call; no traits or manual hooks.
  • 🧠 Configuration-driven – encryption rules live in Sevola CMS (mst_encryption_config table), not in source code.
  • Global interception – the service provider attaches framework-level listeners to saving and retrieved events.
  • 🎯 Column-level control – pick exactly which columns are encrypted, per-table, per-database.
  • 🧮 Algorithm aware – supports FF1 format-preserving encryption, AES-REST, transit keys, etc. (whichever the CMS configuration specifies).
  • 🗄️ Cache friendly – configuration is cached (TTL configurable) to minimise database lookups.
  • 🪵 Rich logging – optional structured logging for auditing and debugging.
  • 🛠️ Manual APIs still available – access ConfigService, EncryptionService, and ModelEncryptionManager for one-off jobs or raw queries.
  • 🎚️ Per-request ciphertext toggle – opt in to encrypted responses using SevolaContext.

Requirements

ComponentMinimum
PHP8.2
Laravel11.x (works with L10 via manual provider registration)
DatabaseAny connection supported by Laravel (MySQL, PostgreSQL, SQL Server, etc.)
Sevola SDKifabula/sevola-sdk-php (installed automatically)

Installation

  1. Require the package

    composer require ifabula/sevola-interceptor-helper
    
  2. (Optional) Publish the configuration file

    php artisan vendor:publish --tag=sevola-config
    

    This creates config/sevola.php. Publishing is recommended when you need to customise defaults (cache TTL, log channel, etc.).

  3. Ensure the Sevola SDK is available
    The helper already depends on ifabula/sevola-sdk-php, so the SDK will be installed automatically.

  4. Laravel service provider

    • Laravel 11+: auto-discovery registers the provider.
    • Laravel ≤ 10: add Ifabula\SevolaInterceptor\SevolaServiceProvider::class to the providers array in config/app.php.

Configuring the Helper

1. Environment variables

Add these entries to .env (or use your secrets manager):

# Required
SEVOLA_API_KEY=your-api-key
SEVOLA_BASE_URL=https://sevola.example.com
SEVOLA_CONFIG_DATABASE=amplio_encrypt_dev
SEVOLA_CONFIG_TABLE=mst_encryption_config

# Optional
SEVOLA_DB_CONNECTION=null          # Defaults to Laravel's default DB connection
SEVOLA_CACHE_TTL=300               # Seconds
SEVOLA_LOGGING=false               # Enable structured logs
SEVOLA_LOG_CHANNEL=stack           # Use any Laravel channel name
SEVOLA_DEBUG=false                 # Adds verbose debug logs
SEVOLA_ENABLE_QUERY_LISTENER=false # Experimental raw-query interceptor (disabled by default)

The helper uses the configured connection (or the default connection) to query the CMS configuration table.

2. Sevola CMS configuration

Encryption rules are managed centrally in Sevola CMS. For each table you want to protect:

  1. Open Encryption Config inside Sevola CMS.
  2. Create an entry specifying database, table, columns to encrypt, and the algorithm.
  3. Set the entry status to ACTIVE.

The helper reads this table (mst_encryption_config) on demand. Once the config is active, every Laravel query that touches that table automatically encrypts/decrypts the listed columns.

No code changes are needed in the Laravel project. As soon as the config exists and the helper is installed, the model data is protected.

Quick Start Checklist

  1. ✅ Install the package (composer require ifabula/sevola-interceptor-helper).
  2. ✅ Configure .env with Sevola API and CMS database credentials.
  3. ✅ Ensure the Sevola CMS entry exists for each table (status = ACTIVE).
  4. ✅ (Laravel ≤ 10) Register the service provider manually.
  5. ▶️ Use your Eloquent models and query builder exactly as before—encrypted columns are handled automatically.

To verify quickly, enable logging (SEVOLA_LOGGING=true, SEVOLA_DEBUG=true) and inspect storage/logs/laravel.log. You should see messages confirming encryption/decryption activity for configured tables.

How the Helper Works

  1. BootstrappingSevolaServiceProvider merges configuration, registers services, and attaches listeners to global Eloquent events.
  2. On Save – When a model is saved (create/update), Model::saving fires. The helper:
    • resolves the model’s connection/database/table;
      • queries the CMS configuration (cached);
      • encrypts only the columns listed as encrypted; and
      • writes the encrypted values back onto the model before the INSERT/UPDATE happens.
  3. On Retrieve – When a model is retrieved, Model::retrieved fires. The helper:
    • fetches the same configuration;
    • decrypts the relevant attributes on the model instance; and
    • calls syncOriginal() so Laravel treats the decrypted values as the original state.
  4. Query Builder & Raw Queries – Because the helper intercepts Eloquent events, all result sets constructed via models (relations, pagination, API resources, etc.) receive decrypted data transparently. For direct DB::select() usage, you can manually call EncryptionService to decrypt arrays if needed.

The helper never triggers encryption for tables that are not present (or not ACTIVE) in the CMS configuration. This keeps it safe to deploy broadly without code toggles.

Available Services

Although zero-integration is the default, you can resolve and use the internal services when needed:

ServiceClassResponsibilities
ConfigurationIfabula\SevolaInterceptor\Services\ConfigServiceFetch, cache, and clear CMS configuration entries.
EncryptionIfabula\SevolaInterceptor\Services\EncryptionServiceUse Sevola SDK to encrypt/decrypt associative arrays, respecting algorithm/templates.
Model ManagerIfabula\SevolaInterceptor\Services\ModelEncryptionManagerCore logic for handling model lifecycle events.
Query Interceptor (experimental)Ifabula\SevolaInterceptor\Interceptors\QueryInterceptorLow-level listener for query events. Disabled by default.

All services are bound in the container as singletons, so you can resolve them with app(ConfigService::class), etc.

Usage Examples

1. Plain Eloquent usage (no code changes)

// Controller or service code
$user = App\Models\User::create([
    'name'  => 'Jane Doe',
    'email' => 'jane@example.com',    // encrypted in DB
    'phone' => '555-1234',            // encrypted in DB
]);

// Later …
$user = App\Models\User::find($user->id);

$user->email; // "jane@example.com" (decrypted automatically)
$user->phone; // "555-1234"

2. Manual encryption/decryption for raw arrays

use Ifabula\SevolaInterceptor\Services\ConfigService;
use Ifabula\SevolaInterceptor\Services\EncryptionService;

$configService = app(ConfigService::class);
$encryptionService = app(EncryptionService::class);

$config = $configService->getConfig('amplio_encrypt_dev', 'users');

if ($config && $config->isActive()) {
    $payload = ['email' => 'john@example.com', 'phone' => '555-9999'];

    $encrypted = $encryptionService->encryptData($payload, $config);
    $decrypted = $encryptionService->decryptData($encrypted, $config);
}

3. Clearing configuration cache

app(ConfigService::class)->clearCache();                // all tables
app(ConfigService::class)->clearCache('db', 'table');   // specific table

4. Inspecting active configurations

$configs = app(ConfigService::class)->getAllActiveConfigs();

foreach ($configs as $config) {
    printf(
        "DB: %s | Table: %s | Columns: %s\n",
        $config->databaseName,
        $config->tableName,
        implode(', ', $config->encryptedColumns)
    );
}

5. Returning ciphertext for a specific query

use Ifabula\SevolaInterceptor\Support\SevolaContext;
use App\Models\TestEncryptionSmall;

// Default behaviour: decrypted values
$records = TestEncryptionSmall::all();            // plaintext attributes

// Optional: encrypted values for this call only
$encryptedRecords = SevolaContext::withReturnEncrypted(function () {
    return TestEncryptionSmall::all();            // ciphertext attributes
});

// Manual push/pop when you cannot use the helper
SevolaContext::pushReturnEncrypted();
try {
    $cipherRecords = TestEncryptionSmall::all();
} finally {
    SevolaContext::pop();
}

Configuration Data Model

The helper expects a table (default mst_encryption_config) with the following structure. You normally maintain this via Sevola CMS, but the schema matters when you self-host the CMS database.

CREATE TABLE mst_encryption_config (
    id INT PRIMARY KEY AUTO_INCREMENT,
    config_name VARCHAR(255) NOT NULL,
    database_name VARCHAR(255) NOT NULL,
    table_name VARCHAR(255) NOT NULL,
    encrypted_columns JSON NOT NULL,
    status VARCHAR(50) NOT NULL DEFAULT 'ACTIVE',
    encryption_algorithm VARCHAR(50) NOT NULL DEFAULT 'FF1',
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    INDEX idx_db_table (database_name, table_name)
);

Example row:

{
  "id": 7,
  "config_name": "User PII",
  "database_name": "amplio_encrypt_dev",
  "table_name": "users",
  "encrypted_columns": ["email", "phone", "ssn"],
  "status": "ACTIVE",
  "encryption_algorithm": "FF1"
}

Set status to INACTIVE to disable encryption for a table without removing it from the CMS.

Advanced Topics

Logging & Observability

  • SEVOLA_LOGGING=true enables informational logs (provider loaded, response payload preview, etc.).
  • SEVOLA_DEBUG=true adds granular debug logs (config cache hits, attribute lists, encryption/decryption payloads).
  • Use SEVOLA_LOG_CHANNEL to route logs to dedicated channels (Stack, daily file, Slack, etc.).

Cache Strategy

  • Configuration entries are cached per (database, table) key.
  • Default TTL is 300 seconds. Increase it for noisy tables: SEVOLA_CACHE_TTL=1800 (30 minutes).
  • Call ConfigService::clearCache() after editing entries in CMS to invalidate cache immediately.

Query Listener (experimental)

  • Flip SEVOLA_ENABLE_QUERY_LISTENER=true to activate QueryInterceptor.
  • Currently logs executed SQL statements and checks if a config exists for the table.
  • Intended as the staging point for deeper driver-level interception.

Working with Query Builder / Raw SQL

  • Eloquent models auto-decrypt attributes. If you use raw DB::select() calls, decrypt arrays manually via EncryptionService.
  • Bulk CSV imports can pre-encrypt columns using the same service before calling insert().

Troubleshooting

SymptomPossible CauseSuggested Fix
Values remain encrypted when retrievedCMS entry missing or inactiveVerify in Sevola CMS; clear helper cache
No encryption on saveCMS entry missing; event listeners not runningCheck logs with debug mode enabled; ensure provider registered
SEVOLA_API_KEY is not configured exception.env missing keyAdd key and run php artisan config:clear
Slow responsesConfig cache TTL too low; logging too verboseIncrease SEVOLA_CACHE_TTL; disable debug logging
Need to force refresh after CMS changeCache still holds old configCall ConfigService::clearCache()

Enable debug logging and watch storage/logs/laravel.log to diagnose issues quickly. You will see entries such as:

[2025-11-12 04:21:58] local.DEBUG: [Sevola] Global saving listener triggered {"model":"App\\Models\\User"}
[2025-11-12 04:21:58] local.DEBUG: [Sevola] Encrypting attributes during saving {"attributes":["email","phone"]}
[2025-11-12 04:21:58] local.DEBUG: [Sevola] Attributes decrypted {"model":"App\\Models\\User"}

FAQ

Do I need to modify my Eloquent models?

No. The helper intercepts Eloquent lifecycle events globally. Keep your models exactly as they are.

How do I disable encryption temporarily?

Mark the CMS entry as INACTIVE and clear the helper cache. Existing ciphertext stays encrypted in the database.

Can I encrypt new tables without deploying code?

Yes. Add the table to Sevola CMS, ensure the database user has access, and the helper will pick it up.

What about queue workers or scheduled jobs?

As long as the job boots Laravel normally (e.g., via Artisan commands), the service provider runs and encryption stays active.

Does this helper change database schemas?

No. The helper only transforms values going into/out of the database. Schema migrations are unchanged.

Contributing & Support

Issues and feature requests are welcome on GitLab. If you’re integrating into a large environment and need commercial support, please contact Ifabula directly.

Made with ❤️ by Ifabula.