Fix encryption key persistence for Docker environments

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
This commit is contained in:
Ollama
2026-05-21 21:43:14 +02:00
committed by jekkos
parent 84aeeb52fe
commit 48e3f948f5
9 changed files with 406 additions and 163 deletions

View File

@@ -106,4 +106,54 @@ class Encryption extends BaseConfig
* by CI3 Encryption default configuration.
*/
public string $cipher = 'AES-256-CTR';
/**
* Constructor - loads encryption key from fallback location if not set.
*
* This supports Docker/container environments where ROOTPATH/.env may be
* read-only or ephemeral. The fallback key file is stored in WRITEPATH/config/.
*/
public function __construct()
{
parent::__construct();
// If key not set from .env or environment, try WRITEPATH fallback
if (empty($this->key) || strlen($this->key) < 64) {
$fallbackKey = $this->loadKeyFromWritable();
if ($fallbackKey !== null) {
$this->key = $fallbackKey;
}
}
}
/**
* Loads encryption key from WRITEPATH/config/encryption.key.
*
* @return string|null The encryption key if found, null otherwise
*/
private function loadKeyFromWritable(): ?string
{
$keyFile = WRITEPATH . 'config' . DIRECTORY_SEPARATOR . 'encryption.key';
if (!file_exists($keyFile) || !is_readable($keyFile)) {
return null;
}
$content = file_get_contents($keyFile);
if ($content === false) {
return null;
}
$data = json_decode($content, true);
if (
!is_array($data)
|| !isset($data['key'])
|| !is_string($data['key'])
|| strlen($data['key']) < 64
) {
return null;
}
return $data['key'];
}
}

View File

@@ -17,11 +17,9 @@ use App\Models\Enums\Rounding_mode;
use App\Models\Stock_location;
use App\Models\Tax;
use CodeIgniter\Database\BaseConnection;
use CodeIgniter\Encryption\EncrypterInterface;
use CodeIgniter\HTTP\ResponseInterface;
use Config\Database;
use Config\OSPOS;
use Config\Services;
use DirectoryIterator;
use NumberFormatter;
use ReflectionException;
@@ -30,7 +28,6 @@ class Config extends Secure_Controller
{
protected $helpers = ['security'];
private BaseConnection $db;
private EncrypterInterface $encrypter;
private Barcode_lib $barcode_lib;
private Sale_lib $sale_lib;
private Receiving_lib $receiving_lib;
@@ -62,13 +59,6 @@ class Config extends Secure_Controller
$this->tax = model(Tax::class);
$this->config = config(OSPOS::class)->settings;
$this->db = Database::connect();
helper('security');
if (check_encryption()) {
$this->encrypter = Services::encrypter();
} else {
log_message('alert', 'Error preparing encryption key');
}
}
/**
@@ -256,25 +246,11 @@ class Config extends Secure_Controller
// Integrations Related fields
$data['mailchimp'] = [];
if (check_encryption()) { // TODO: Hungarian notation
if (!isset($this->encrypter)) {
helper('security');
$this->encrypter = Services::encrypter();
}
$data['mailchimp']['api_key'] = decryptValue($this->config['mailchimp_api_key'] ?? null);
$data['mailchimp']['list_id'] = decryptValue($this->config['mailchimp_list_id'] ?? null);
$data['mailchimp']['api_key'] = (isset($this->config['mailchimp_api_key']) && !empty($this->config['mailchimp_api_key']))
? $this->encrypter->decrypt($this->config['mailchimp_api_key'])
: '';
$data['mailchimp']['list_id'] = (isset($this->config['mailchimp_list_id']) && !empty($this->config['mailchimp_list_id']))
? $this->encrypter->decrypt($this->config['mailchimp_list_id'])
: '';
// Remove any backup of .env created by check_encryption()
remove_backup();
} else {
$data['mailchimp']['api_key'] = '';
$data['mailchimp']['list_id'] = '';
if (checkEncryption()) {
removeBackup();
}
$data['mailchimp']['lists'] = $this->_mailchimp();
@@ -512,15 +488,23 @@ class Config extends Secure_Controller
public function postSaveEmail(): ResponseInterface
{
$password = '';
$passwordInput = $this->request->getPost('smtp_pass');
if (check_encryption() && !empty($this->request->getPost('smtp_pass'))) {
$password = $this->encrypter->encrypt($this->request->getPost('smtp_pass'));
if (!empty($passwordInput)) {
$password = encryptValue($passwordInput);
if (empty($password)) {
log_message('error', 'SMTP password encryption failed - credentials not saved');
return $this->response->setJSON([
'success' => false,
'message' => lang('Config.encryption_failed'),
]);
}
}
$protocol = $this->request->getPost('protocol');
$mailpath = $this->request->getPost('mailpath');
// Validate mailpath: required for sendmail, optional for others but must be safe if provided
$isMailpathRequired = ($protocol === 'sendmail');
$isMailpathProvided = !empty($mailpath);
$isMailpathValid = $isMailpathProvided && preg_match('/^[a-zA-Z0-9_\-\/.]+$/', $mailpath);
@@ -528,7 +512,7 @@ class Config extends Secure_Controller
if (($isMailpathRequired && !$isMailpathProvided) || ($isMailpathProvided && !$isMailpathValid)) {
return $this->response->setJSON([
'success' => false,
'message' => lang('Config.mailpath_invalid')
'message' => lang('Config.mailpath_invalid'),
]);
}
@@ -540,7 +524,7 @@ class Config extends Secure_Controller
'smtp_pass' => $password,
'smtp_port' => $this->request->getPost('smtp_port', FILTER_SANITIZE_NUMBER_INT),
'smtp_timeout' => $this->request->getPost('smtp_timeout', FILTER_SANITIZE_NUMBER_INT),
'smtp_crypto' => $this->request->getPost('smtp_crypto')
'smtp_crypto' => $this->request->getPost('smtp_crypto'),
];
$success = $this->appconfig->batch_save($batch_save_data);
@@ -558,16 +542,25 @@ class Config extends Secure_Controller
public function postSaveMessage(): ResponseInterface
{
$password = '';
$passwordInput = $this->request->getPost('msg_pwd');
if (check_encryption() && !empty($this->request->getPost('msg_pwd'))) {
$password = $this->encrypter->encrypt($this->request->getPost('msg_pwd'));
if (!empty($passwordInput)) {
$password = encryptValue($passwordInput);
if (empty($password)) {
log_message('error', 'SMS password encryption failed');
return $this->response->setJSON([
'success' => false,
'message' => lang('Config.encryption_failed'),
]);
}
}
$batch_save_data = [
'msg_msg' => $this->request->getPost('msg_msg'),
'msg_uid' => $this->request->getPost('msg_uid'),
'msg_pwd' => $password,
'msg_src' => $this->request->getPost('msg_src')
'msg_src' => $this->request->getPost('msg_src'),
];
$success = $this->appconfig->batch_save($batch_save_data);
@@ -623,24 +616,38 @@ class Config extends Secure_Controller
*/
public function postSaveMailchimp(): ResponseInterface
{
$api_key = '';
$list_id = '';
$apiKey = '';
$listId = '';
if (check_encryption()) {
$api_key_unencrypted = $this->request->getPost('mailchimp_api_key');
if (!empty($api_key_unencrypted)) {
$api_key = $this->encrypter->encrypt($api_key_unencrypted);
}
$apiKeyInput = $this->request->getPost('mailchimp_api_key');
if (!empty($apiKeyInput)) {
$apiKey = encryptValue($apiKeyInput);
if (empty($apiKey)) {
log_message('error', 'Mailchimp API key encryption failed');
$list_id_unencrypted = $this->request->getPost('mailchimp_list_id');
if (!empty($list_id_unencrypted)) {
$list_id = $this->encrypter->encrypt($list_id_unencrypted);
return $this->response->setJSON([
'success' => false,
'message' => lang('Config.encryption_failed'),
]);
}
}
$batch_save_data = ['mailchimp_api_key' => $api_key, 'mailchimp_list_id' => $list_id];
$listIdInput = $this->request->getPost('mailchimp_list_id');
if (!empty($listIdInput)) {
$listId = encryptValue($listIdInput);
if (empty($listId)) {
log_message('error', 'Mailchimp list ID encryption failed');
$success = $this->appconfig->batch_save($batch_save_data);
return $this->response->setJSON([
'success' => false,
'message' => lang('Config.encryption_failed'),
]);
}
}
$batchSaveData = ['mailchimp_api_key' => $apiKey, 'mailchimp_list_id' => $listId];
$success = $this->appconfig->batch_save($batchSaveData);
return $this->response->setJSON(['success' => $success, 'message' => lang('Config.saved_' . ($success ? '' : 'un') . 'successfully')]);
}

View File

@@ -31,13 +31,7 @@ class Customers extends Persons
$this->tax_code = model(Tax_code::class);
$this->config = config(OSPOS::class)->settings;
$encrypter = Services::encrypter();
if (!empty($this->config['mailchimp_list_id'])) {
$this->_list_id = $encrypter->decrypt($this->config['mailchimp_list_id']);
} else {
$this->_list_id = '';
}
$this->_list_id = decryptValue($this->config['mailchimp_list_id'] ?? null);
}
/**

View File

@@ -33,10 +33,12 @@ class Convert_to_ci4 extends Migration
if (!empty(config('Encryption')->key)) {
$this->convert_ci3_encrypted_data();
} else {
check_encryption();
if (!checkEncryption()) {
throw new \RuntimeException('Unable to persist encryption key. Migration cannot proceed without encryption.');
}
}
remove_backup();
removeBackup();
}
/**
@@ -66,15 +68,19 @@ class Convert_to_ci4 extends Migration
$decrypted_data = $this->decrypt_ci3_data($ci3_encrypted_data);
check_encryption();
if (!checkEncryption()) {
abortEncryptionConversion();
removeBackup();
throw new RedirectException('login');
}
try {
$ci4_encrypted_data = $this->encrypt_data($decrypted_data);
$success = empty(array_diff_assoc($decrypted_data, $this->decrypt_data($ci4_encrypted_data)));
if (!$success) {
abort_encryption_conversion();
remove_backup();
abortEncryptionConversion();
removeBackup();
throw new RedirectException('login');
}

View File

@@ -1,95 +1,312 @@
<?php
use CodeIgniter\Encryption\Encryption;
use CodeIgniter\Encryption\Exceptions\EncryptionException;
use Config\Services;
/**
* @return bool
* Checks and initializes encryption key.
*
* This function ensures a valid encryption key exists for the application.
* It tries multiple storage locations to support different deployment scenarios:
* 1. ROOTPATH/.env - Standard location for non-containerized deployments
* 2. WRITEPATH/config/encryption.key - Fallback for Docker/container environments where .env is read-only
*
* @return bool True if encryption key is available, false if key generation/persistence failed
*/
function check_encryption(): bool
function checkEncryption(): bool
{
$old_key = config('Encryption')->key;
$oldKey = config('Encryption')->key;
if ((empty($old_key)) || (strlen($old_key) < 64)) {
$encryption = new Encryption();
$key = bin2hex($encryption->createKey());
config('Encryption')->key = $key;
if (!empty($oldKey) && strlen($oldKey) >= 64) {
return true;
}
$config_path = ROOTPATH . '.env';
$backup_path = WRITEPATH . '/backup/.env.bak';
$backup_folder = WRITEPATH . '/backup';
$encryption = new Encryption();
$key = bin2hex($encryption->createKey());
config('Encryption')->key = $key;
if (!file_exists($backup_folder)) {
@mkdir($backup_folder, 0750, true);
}
$envPersisted = writeEncryptionKeyToEnv($key, $oldKey);
$writablePersisted = writeEncryptionKeyToWritable($key, $oldKey);
$persisted = $envPersisted || $writablePersisted;
if (!file_exists($config_path)) {
$example_path = ROOTPATH . '.env.example';
if (file_exists($example_path)) {
@copy($example_path, $config_path);
} else {
@file_put_contents($config_path, "# OSPOS Configuration\n\n");
}
@chmod($config_path, 0640);
}
if ($persisted) {
log_message('info', 'Encryption key initialized successfully');
} else {
log_message('error', 'Failed to persist encryption key to any location. Encryption may not survive container restarts.');
}
if (file_exists($config_path)) {
@copy($config_path, $backup_path);
@chmod($backup_path, 0640);
@chmod($config_path, 0640);
return $persisted;
}
$config_file = file_get_contents($config_path);
/**
* Writes encryption key to ROOTPATH/.env file.
*
* @param string $key The new encryption key (hex-encoded)
* @param string|null $oldKey The previous key to preserve for key rotation
*
* @return bool True if key was written successfully, false otherwise
*/
function writeEncryptionKeyToEnv(string $key, ?string $oldKey = null): bool
{
$configPath = ROOTPATH . '.env';
$backupPath = WRITEPATH . 'backup' . DIRECTORY_SEPARATOR . '.env.bak';
$backupFolder = WRITEPATH . 'backup';
if (preg_match('/^\s*encryption\.key\s*=/m', $config_file)) {
$config_file = preg_replace("/^(\s*encryption\.key\s*=\s*).*/m", "\$1'$key'", $config_file, 1);
} else {
$config_file .= "\nencryption.key = '$key'\n";
}
if (!empty($old_key)) {
$old_line = "# encryption.key = '$old_key' REMOVE IF UNNEEDED\r\n";
if (preg_match('/^encryption\.key\s*=/m', $config_file, $matches, PREG_OFFSET_CAPTURE)) {
$config_file = substr_replace($config_file, $old_line, $matches[0][1], 0);
}
}
@file_put_contents($config_path, $config_file);
@chmod($config_path, 0640);
log_message('info', "Updated encryption key in $config_path");
if (!file_exists($backupFolder)) {
if (!@mkdir($backupFolder, 0750, true)) {
log_message('debug', 'Could not create backup directory');
}
}
if (!file_exists($configPath)) {
$examplePath = ROOTPATH . '.env.example';
if (file_exists($examplePath)) {
if (!@copy($examplePath, $configPath)) {
log_message('debug', 'Could not copy .env.example to .env');
}
} else {
if (!@file_put_contents($configPath, "# OSPOS Configuration\n\n") !== false) {
log_message('debug', 'Could not create .env file');
}
}
@chmod($configPath, 0640);
}
if (!is_writable($configPath)) {
log_message('debug', '.env file is not writable');
return false;
}
if (file_exists($configPath)) {
@copy($configPath, $backupPath);
@chmod($backupPath, 0640);
}
$configFile = file_get_contents($configPath);
if ($configFile === false) {
log_message('debug', 'Could not read .env file');
return false;
}
if (strpos($configFile, 'encryption.key') !== false) {
$configFile = preg_replace("/(encryption\.key.*=.*)(['\"])([^'\"]*)\\2/", "$1'$key'", $configFile);
} else {
$configFile .= "\nencryption.key = '$key'\n";
}
if (!empty($oldKey)) {
$oldLine = "# encryption.key = '$oldKey' REMOVE IF UNNEEDED\r\n";
$insertionPoint = stripos($configFile, 'encryption.key');
if ($insertionPoint !== false) {
$configFile = substr_replace($configFile, $oldLine, $insertionPoint, 0);
}
}
$result = file_put_contents($configPath, $configFile);
if ($result === false) {
log_message('debug', 'Could not write to .env file');
return false;
}
@chmod($configPath, 0640);
log_message('info', "Updated encryption key in $configPath");
return true;
}
/**
* @return void
* Writes encryption key to WRITEPATH/config/encryption.key file.
*
* This is the fallback location for Docker/container environments where
* the ROOTPATH/.env file may be read-only or ephemeral.
*
* @param string $key The new encryption key (hex-encoded)
* @param string|null $oldKey The previous key to preserve for key rotation
*
* @return bool True if key was written successfully, false otherwise
*/
function abort_encryption_conversion(): void
function writeEncryptionKeyToWritable(string $key, ?string $oldKey = null): bool
{
$config_path = ROOTPATH . '.env';
$backup_path = WRITEPATH . '/backup/.env.bak';
$keyFile = WRITEPATH . 'config' . DIRECTORY_SEPARATOR . 'encryption.key';
$keyDir = dirname($keyFile);
if (!file_exists($backup_path)) {
return;
if (!is_dir($keyDir)) {
if (!@mkdir($keyDir, 0750, true)) {
log_message('error', 'Could not create config directory: ' . $keyDir);
return false;
}
}
@chmod($config_path, 0640);
$config_file = file_get_contents($backup_path);
@file_put_contents($config_path, $config_file);
log_message('info', "Restored $config_path from backup");
if (!is_writable($keyDir)) {
log_message('error', 'Config directory is not writable: ' . $keyDir);
return false;
}
$data = [
'key' => $key,
'previous_keys' => [],
'generated_at' => date('c'),
'generated_by' => 'checkEncryption()',
];
if (!empty($oldKey)) {
$data['previous_keys'][] = $oldKey;
}
$content = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
$result = file_put_contents($keyFile, $content);
if ($result === false) {
log_message('error', 'Could not write encryption key file');
return false;
}
@chmod($keyFile, 0640);
log_message('info', "Stored encryption key in $keyFile");
return true;
}
/**
* Loads encryption key from WRITEPATH/config/encryption.key file.
*
* This is the fallback key loader for Docker/container environments.
*
* @return string|null The encryption key if found, null otherwise
*/
function loadEncryptionKeyFromWritable(): ?string
{
$keyFile = WRITEPATH . 'config' . DIRECTORY_SEPARATOR . 'encryption.key';
if (!file_exists($keyFile)) {
return null;
}
if (!is_readable($keyFile)) {
log_message('error', 'Encryption key file exists but is not readable: ' . $keyFile);
return null;
}
$content = file_get_contents($keyFile);
if ($content === false) {
log_message('error', 'Could not read encryption key file');
return null;
}
$data = json_decode($content, true);
if (!is_array($data) || empty($data['key'])) {
log_message('error', 'Encryption key file has invalid format');
return null;
}
log_message('info', 'Loaded encryption key from WRITEPATH config');
return $data['key'];
}
/**
* Restores .env from backup (used by migration rollback).
*
* @return void
*/
function remove_backup(): void
function abortEncryptionConversion(): void
{
$backup_path = WRITEPATH . '/backup/.env.bak';
if (!file_exists($backup_path)) {
$configPath = ROOTPATH . '.env';
$backupPath = WRITEPATH . 'backup' . DIRECTORY_SEPARATOR . '.env.bak';
if (!file_exists($backupPath)) {
return;
}
@unlink($backup_path);
log_message('info', "Removed $backup_path");
$configFile = file_get_contents($backupPath);
if ($configFile === false) {
log_message('error', 'Could not read backup file for restoration');
return;
}
if (file_put_contents($configPath, $configFile) !== false) {
@chmod($configPath, 0640);
log_message('info', "Restored $configPath from backup");
} else {
log_message('error', "Failed to restore $configPath from backup");
}
}
/**
* Removes backup file (used after successful migration).
*
* @return void
*/
function removeBackup(): void
{
$backupPath = WRITEPATH . 'backup' . DIRECTORY_SEPARATOR . '.env.bak';
if (file_exists($backupPath)) {
unlink($backupPath);
}
}
/**
* Decrypts an encrypted value with proper error handling.
*
* This function provides a consistent decryption pattern across the codebase,
* handling cases where encryption key may not be available or decryption fails.
*
* @param string|null $encryptedValue The encrypted value to decrypt
* @param string $default Default value to return if decryption fails
*
* @return string The decrypted value, or default if decryption fails
*/
function decryptValue(?string $encryptedValue, string $default = ''): string
{
if ($encryptedValue === null || $encryptedValue === '') {
return $default;
}
if (!checkEncryption()) {
log_message('warning', 'Cannot decrypt value: encryption key not available');
return $default;
}
try {
$encrypter = Services::encrypter();
return $encrypter->decrypt($encryptedValue);
} catch (EncryptionException $e) {
log_message('error', 'Decryption failed: ' . $e->getMessage());
return $default;
}
}
/**
* Encrypts a value with proper error handling.
*
* This function provides a consistent encryption pattern across the codebase,
* handling cases where encryption key may not be available.
*
* @param string|null $value The value to encrypt
* @param bool $require Whether encryption is required (returns empty string on failure)
* If false, returns original value on failure
*
* @return string The encrypted value, or empty string/original value if encryption fails
*/
function encryptValue(?string $value, bool $require = true): string
{
if ($value === null || $value === '') {
return '';
}
if (!checkEncryption()) {
log_message('error', 'Cannot encrypt value: encryption key not available');
return $require ? '' : $value;
}
try {
$encrypter = Services::encrypter();
return $encrypter->encrypt($value);
} catch (EncryptionException $e) {
log_message('error', 'Encryption failed: ' . $e->getMessage());
return $require ? '' : $value;
}
}

View File

@@ -122,6 +122,7 @@ return [
"email_smtp_port" => "SMTP Port",
"email_smtp_timeout" => "SMTP Timeout (s)",
"email_smtp_user" => "SMTP Username",
"encryption_failed" => "Failed to encrypt data. Please check encryption configuration.",
"enable_avatar" => "",
"enable_avatar_tooltip" => "",
"enable_dropdown_tooltip" => "",

View File

@@ -3,11 +3,7 @@
namespace app\Libraries;
use CodeIgniter\Email\Email;
use CodeIgniter\Encryption\Encryption;
use CodeIgniter\Encryption\EncrypterInterface;
use CodeIgniter\Encryption\Exceptions\EncryptionException;
use Config\OSPOS;
use Config\Services;
/**
@@ -26,21 +22,9 @@ class Email_lib
$this->email = new Email();
$this->config = config(OSPOS::class)->settings;
$encrypter = Services::encrypter();
$smtpPass = decryptValue($this->config['smtp_pass'] ?? null);
$smtp_pass = $this->config['smtp_pass'];
if (!empty($smtp_pass) && check_encryption()) {
try {
$smtp_pass = $encrypter->decrypt($smtp_pass);
} catch (\EncryptionException $e) {
// Decryption failed, use the original value
log_message('error', 'SMTP password decryption failed: ' . $e->getMessage());
$smtp_pass = '';
}
}
$email_config = [
$emailConfig = [
'mailType' => 'html',
'userAgent' => 'OSPOS',
'validate' => true,
@@ -48,12 +32,12 @@ class Email_lib
'mailPath' => $this->config['mailpath'],
'SMTPHost' => $this->config['smtp_host'],
'SMTPUser' => $this->config['smtp_user'],
'SMTPPass' => $smtp_pass,
'SMTPPass' => $smtpPass,
'SMTPPort' => (int)$this->config['smtp_port'],
'SMTPTimeout' => (int)$this->config['smtp_timeout'],
'SMTPCrypto' => $this->config['smtp_crypto']
'SMTPCrypto' => $this->config['smtp_crypto'],
];
$this->email->initialize($email_config);
$this->email->initialize($emailConfig);
}
/**

View File

@@ -2,9 +2,7 @@
namespace app\Libraries;
use CodeIgniter\Encryption\EncrypterInterface;
use Config\OSPOS;
use Config\Services;
/**
* MailChimp API v3 REST client Connector
@@ -14,8 +12,6 @@ use Config\Services;
* Inspired by the work of:
* - Rajitha Bandara: https://github.com/rajitha-bandara/ci-mailchimp-v3-rest-client
* - Stefan Ashwell: https://github.com/stef686/codeigniter-mailchimp-api-v3
*
* @property encrypterinterface encrypter
*/
class MailchimpConnector
{
@@ -40,23 +36,19 @@ class MailchimpConnector
{
$config = config(OSPOS::class)->settings;
$encrypter = Services::encrypter();
$mailchimp_api_key = (isset($this->config['mailchimp_api_key']) && !empty($this->config['mailchimp_api_key']))
? $this->config['mailchimp_api_key']
: '';
$mailchimp_api_key = $config['mailchimp_api_key'] ?? '';
if (!empty($mailchimp_api_key)) {
$this->_api_key = empty($api_key)
? $encrypter->decrypt($mailchimp_api_key) // TODO: Hungarian notation
: $api_key; // TODO: Hungarian notation
? decryptValue($mailchimp_api_key)
: $api_key;
}
if (!empty($this->_api_key)) { // TODO: Hungarian notation
if (!empty($this->_api_key)) {
// Replace <dc> with correct datacenter obtained from the last part of the api key
$strings = explode('-', $this->_api_key); // TODO: Hungarian notation
$strings = explode('-', $this->_api_key);
if (is_array($strings) && !empty($strings[1])) {
$this->_api_endpoint = str_replace('<dc>', $strings[1], $this->_api_endpoint); // TODO: Hungarian notation
$this->_api_endpoint = str_replace('<dc>', $strings[1], $this->_api_endpoint);
}
}
}

View File

@@ -2,10 +2,7 @@
namespace app\Libraries;
use CodeIgniter\Encryption\Encryption;
use CodeIgniter\Encryption\EncrypterInterface;
use Config\OSPOS;
use Config\Services;
/**
@@ -24,12 +21,7 @@ class Sms_lib
{
$config = config(OSPOS::class)->settings;
$encrypter = Services::encrypter();
$password = $config['msg_pwd'];
if (!empty($password)) {
$password = $encrypter->decrypt($password);
}
$password = decryptValue($config['msg_pwd'] ?? null);
$username = $config['msg_uid'];
$originator = $config['msg_src'];