azine/js-crypto-store-bundle
Install the Bundle
Add to composer.json:
"require": {
"azine/js-crypto-store-bundle": "dev-master"
}
Run:
composer require azine/js-crypto-store-bundle
Register the Bundle
Add to config/bundles.php:
return [
// ...
Azine\JsCryptoStoreBundle\AzineJsCryptoStoreBundle::class => ['all' => true],
];
Configure Routes & Services
Add to config/routes.yaml:
azine_js_crypto_store:
resource: "@AzineJsCryptoStoreBundle/Resources/config/routing.yml"
Configure Encryption & Storage
Add to config/packages/azine_js_crypto_store.yaml:
azine_js_crypto_store:
ownerProvider: Azine\JsCryptoStoreBundle\Service\DefaultOwnerProvider
encryptionCipher: aes
encryptionMode: gcm
defaultLifeTime: '14 days'
maxFileSize: 50000000
Set Up Database & Filesystem
Ensure your doctrine and framework configs include:
local, aws, etc.) for encrypted file storage.First Use Case: Client-Side Upload Include the bundle’s JS library in your frontend:
<script src="{{ asset('bundles/azinejscripstore/js/sjcl.min.js') }}"></script>
<script src="{{ asset('bundles/azinejscripstore/js/js-crypto-store.js') }}"></script>
Use the provided HTML form (or custom implementation) to upload encrypted files via the /upload endpoint.
Client-Side Encryption
sjcl (Stanford Javascript Crypto Library) to encrypt files in the browser before upload.// Encrypt file using sjcl
const encryptedData = sjcl.encrypt(
password,
fileContent,
{ ks: 256, iterations: 1000 }
);
/upload.Server-Side Storage
owner_id, expiry_date, file_hash) in the database.uploads/encrypted/).// src/Entity/EncryptedFile.php
class EncryptedFile {
// ...
private $ownerId;
private $filePath; // Path to encrypted file in filesystem
private $expiryDate;
private $metadata; // JSON-serialized (e.g., original filename)
}
Sharing Files
/share endpoint:
// Controller example
$file = $this->getDoctrine()->getRepository(EncryptedFile::class)->find($id);
$shareLink = $this->generateUrl('azine_js_crypto_store_download', ['token' => $file->getShareToken()]);
Download & Decryption
// Decrypt using sjcl
const decryptedData = sjcl.decrypt(password, encryptedData, { ks: 256 });
/download endpoint with the share token.Custom Owner Logic
Extend OwnerProviderInterface to dynamically assign files to users/groups:
// src/Service/CustomOwnerProvider.php
class CustomOwnerProvider implements OwnerProviderInterface {
public function getOwnerId(): int {
// Logic to fetch owner (e.g., current user, team lead, etc.)
return $this->userService->getCurrentUser()->getId();
}
}
Register as a service in services.yaml:
services:
Azine\JsCryptoStoreBundle\Service\OwnerProviderInterface: '@App\Service\CustomOwnerProvider'
Frontend Integration
{{ render(azine_js_crypto_store_upload_form()) }}
Cleanup Expired Files
Schedule the azine:js-crypto-store:cleanup command via cron:
php bin/console azine:js-crypto-store:cleanup
Configure retention policies in config/packages/azine_js_crypto_store.yaml:
azine_js_crypto_store:
cleanup:
dryRun: false # Set to true for testing
batchSize: 100
Validation & Error Handling
if (file.size > 50000000) {
alert('File too large (max 50MB)');
}
try {
$encryptedFile = $this->cryptoStore->upload($encryptedData, $metadata);
} catch (EncryptionException $e) {
// Log and notify user
}
Encryption Key Management
Filesystem Permissions
uploads/encrypted/ directory is writable by the web server:
chmod -R 775 var/uploads/encrypted/
chown -R www-data:www-data var/uploads/encrypted/
Database Locking
EncryptedFile entities.$entityManager->beginTransaction();
try {
$entityManager->persist($file);
$entityManager->flush();
$entityManager->commit();
} catch (\Exception $e) {
$entityManager->rollBack();
throw $e;
}
Cipher Configuration
encryptionCipher/encryptionMode settings may cause decryption failures.sjcl:
// Test cipher support in browser
console.log(sjcl.codec.utf8String.fromBits(sjcl.encrypt('test', 'data', { cipher: 'aes' })));
Token Security
// src/Service/CustomTokenGenerator.php
class CustomTokenGenerator {
public function generateToken(): string {
return bin2hex(random_bytes(16)); // 128-bit UUID
}
}
services:
Azine\JsCryptoStoreBundle\Service\TokenGeneratorInterface: '@App\Service\CustomTokenGenerator'
Enable Verbose Logging
Configure Monolog in config/packages/monolog.yaml:
monolog:
handlers:
main:
level: debug
channels: ["!event"]
Check logs for encryption/decryption errors:
grep -i "crypto" var/log/dev.log
Test Encryption Locally Use the bundle’s CLI tool to verify encryption/decryption:
php bin/console azine:js-crypto-store:test-encryption
Inspect Database Metadata
Query the encrypted_file table to verify metadata:
SELECT * FROM encrypted_file WHERE owner_id = 1;
Check for:
file_pathHow can I help you explore Laravel packages today?