Files
opensourcepos/app/Libraries/Sms_lib.php
Ollama 48e3f948f5 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
2026-06-09 23:39:03 +02:00

70 lines
2.6 KiB
PHP

<?php
namespace app\Libraries;
use Config\OSPOS;
/**
* SMS library
*
* Library with utilities to send texts via SMS Gateway (requires proxy implementation)
*/
class Sms_lib
{
/**
* SMS sending function
* Example of use: $response = sendSMS('4477777777', 'My test message');
*/
public function sendSMS(int $phone, string $message): bool
{
$config = config(OSPOS::class)->settings;
$password = decryptValue($config['msg_pwd'] ?? null);
$username = $config['msg_uid'];
$originator = $config['msg_src'];
$response = false;
// If any of the parameters is empty return with a false
if (empty($username) || empty($password) || empty($phone) || empty($message) || empty($originator)) { // TODO: This if/else needs to be flipped. and shortened. No else needed in the code example below.
// $parameters = [$username, $password, $phone, $message, $originator];
// if (count(array_filter($parameters)) === 5) {
// $response = true;
// $message = rawurlencode($message);
// }
// echo $username . ' ' . $password . ' ' . $phone . ' ' . $message . ' ' . $originator;
} else {
$response = true;
// TODO: These comments should be moved to the documentation. As is, they tend to get out of date.
// make sure passed string is url encoded
$message = rawurlencode($message); // TODO: $message needs to be passed by reference if you want this line to actually do anything
// Add call to send a message via 3rd party API here
// Some examples
/*
* $url = "http://xxx.xxx.xxx.xxx/send_sms?username=$username&password=$password&src=$originator&dst=$phone&msg=$message&dr=1";
*
* $c = curl_init();
* curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
* curl_setopt($c, CURLOPT_URL, $url);
* $response = curl_exec($c);
* curl_close($c);
*/
// This is a textmarketer.co.uk API call, see: http://wiki.textmarketer.co.uk/display/DevDoc/Text+Marketer+Developer+Documentation+-+Wiki+Home
/*
* $url = 'https://api.textmarketer.co.uk/gateway/'."?username=$username&password=$password&option=xml";
* $url .= "&to=$phone&message=".urlencode($message).'&orig='.urlencode($originator);
* $fp = fopen($url, 'r');
* $response = fread($fp, 1024);
*/
}
return $response;
}
}