The check_encryption() function now properly handles Docker/container
environments where ROOTPATH/.env may be read-only or ephemeral.
Changes:
- Returns false when key persistence fails instead of always returning true
- Removes error suppression (@) to properly detect write failures
- Adds fallback to WRITEPATH/config/encryption.key for container volumes
- Splits logic into separate functions for clarity and testability
Fixes encryption key being lost on container restarts, which caused
stored passwords to become undecryptable.
GitHub-Issue: #4554
Add fallback key loading from WRITEPATH in Encryption config
When encryption key is not available from .env or environment variables,
the config now attempts to load from WRITEPATH/config/encryption.key.
This supports Docker environments where:
- .env file is read-only or ephemeral
- Key was persisted to the writable volume via check_encryption()
GitHub-Issue: #4554
Handle encryption unavailability gracefully in controllers
Changed EncrypterInterface property to nullable and added proper error
handling for cases where encryption key is not available.
Changes:
- Config controller: nullable encrypter property, try/catch around encryption
- Email_lib: check encryption before using encrypter
- Return meaningful error messages when encryption fails
- Log warnings when passwords saved without encryption
Users will now see clear error messages instead of unhandled exceptions
when encryption key cannot be initialized.
GitHub-Issue: #4554
Add encryption_failed error message to language file
Added localization string for encryption failure error messages.
GitHub-Issue: #4554
Add decrypt_value() and encrypt_value() helper functions
Extracts the recurring decryption/encryption pattern into reusable helper
functions with consistent error handling:
- decrypt_value(): Safely decrypts encrypted values with try/catch
- encrypt_value(): Safely encrypts values with error handling
Both functions handle:
- Empty/null values gracefully
- Missing encryption key (logs warning)
- Encryption/decryption failures (logs error, returns default)
This pattern appears in 8+ locations across the codebase.
GitHub-Issue: #4554
Refactor all encryption/decryption to use helper functions
Replaces direct encrypter calls with decrypt_value() and encrypt_value()
helpers throughout the codebase for consistent error handling:
- Config controller: SMTP, SMS, Mailchimp credential encryption
- Email_lib: SMTP password decryption
- Sms_lib: SMS password decryption
- Mailchimp_lib: API key decryption
- Customers controller: Mailchimp list ID decryption
Removes nullable EncrypterInterface property from Config controller as
encryption is now handled via helper functions.
GitHub-Issue: #4554
Address CodeRabbit feedback: validate key length, clarify encryption failure handling
- loadKeyFromWritable() now validates key length >= 64 before accepting
- encrypt_value() renamed param, defaults to failing encryption required
- Clearer error message when credentials not saved
GitHub-Issue: #4554
fix: address CodeRabbit review comments for encryption key persistence
- Always mirror encryption key to both .env and WRITEPATH (Docker safety)
- Guard array key access with isset() before reading in Encryption.php
- Fix encrypt_value() to not treat string '0' as empty
- Improve error logging for failed encryption attempts
refactor: PSR-compliant naming and address objecttothis review comments
- Rename functions to camelCase: checkEncryption, writeEncryptionKeyToEnv, writeEncryptionKeyToWritable, loadEncryptionKeyFromWritable, abortEncryptionConversion, removeBackup, decryptValue, encryptValue
- Update all callers in Config.php, Customers.php, Migrations, Email_lib.php, Sms_lib.php, Mailchimp_lib.php
- Add EncryptionException import in security_helper.php (removed FQN)
- Use camelCase variables: $smtpPass, $emailConfig, $batchSaveData in affected files
- Remove unnecessary inline comments (code is self-documenting)
- Keep necessary docstrings for public API documentation
Address remaining CodeRabbit review comments
- Fix decryptValue() to use explicit null/empty check instead of empty()
(handles string "0" correctly)
- Guard checkEncryption() result in migration before proceeding
- Check read success before writing backup restoration
- Consistent DIRECTORY_SEPARATOR usage in paths
GitHub-Issue: #4554
* fix: Add missing $img_tag variable in Sales::getSendPdf()
The receipt_email.php view expects $img_tag but getSendPdf() wasn't passing it.
This caused 'Undefined variable $img_tag' error when sending receipt emails.
Closes#4514
* refactor: Extract img_tag building into helper method
Refactored duplicate img_tag building code into _build_img_tag helper method.
Both getSendPdf and getSendReceipt now use this shared method.
* refactor: Move logo-related methods to Email_lib
Moved buildLogoImgTag and getLogoMimeType methods to Email_lib library
where they logically belong alongside email-related functionality.
This removes duplicate code and centralizes email-related helpers.
Sales controller now uses email_lib->buildLogoImgTag() and
email_lib->getLogoMimeType() instead of private methods.
* fix: Address CodeRabbit review comments
- buildLogoImgTag now uses getLogoMimeType for actual MIME type instead of hardcoding image/png
- getLogoMimeType returns empty string instead of false for consistency
- Consolidated logo path/exists check logic between both methods
---------
Co-authored-by: Ollama <ollama@steganos.dev>
* Add attachment cid when sending emails (#4308)
Also check if an encryption key is set before decrypting the SMTP
password.
* Upgrade to CI 4.6.3 (#4308)
* Fix for changing invoice id in email (#4308)
* `execute_script()` now returns a boolean for error handling.
* Added transaction to `Migration_MissingConfigKeys.up()`.
* Added logging to various migrations.
* Added transaction to `Migration_MissingConfigKeys.up()`.
* Added logging to various migrations.
* Formatting and function call fixes
Fixed a minor formatting issue in the migration helper.
Replaced a few remaining error_log() calls.
Updated executeScriptWithTransaction() to use log_message()
* Function call fix
Replaced the last error_log() calls with log_message().
---------
Co-authored-by: Joe Williams <hey-there-joe@outlook.com>
* Improve code style and PSR-12 compliance
- refactored code formatting to adhere to PSR-12 guidelines
- standardized coding conventions across the codebase
- added missing framework files and reverted markup changes
- reformatted arrays for enhanced readability
- updated language files for consistent styling and clarity
- minor miscellaneous improvements
- Replaced TRUE/FALSE constants with true/false keywords
- Replaced NULL constant with null keyword
- Replaced `<?php echo` in views with shortened `<?=`
- Added missing variable declaration
- Added missing function return type in declaration
- replaced `== true`, `== false`, `=== true` and `=== false` in if statements with simplified forms
- PHP 8.2 deprecates dynamically declared class properties. Adding these declarations removes deprecation warnings and makes the code PHP 8.3 compatible.
- Add Elvis operator to set search string to an empty string when it's value is null to get rid of an error in the search function call.
- Imported class for OSPOS config
- Replaced private with protected in parent controller's property.
- Removed unneeded TODO
- Refactored local variables
- Replaced ternary notation
- Removed unneeded comments
- Removed unneeded class property
- Removed unneeded @property declarations
- Fixed database version
- when the payments array was folded into sale_data there was an earlier payments[] reference in the foreach loop that didn't get folded in.
- Update PHPdoc
- Added ::class to remove polymorphic call warning
- Removed unreachable 'break;' statement after return statement.
- Added missing return type
- fixed missing assignment of mailchimp_api_key