Remove EncodeUTF8 infavour of using attribute casting only. The implementation of EncodeUTF8 was not correct, essentially removing any previous casting causing issues when saving a record.

This commit is contained in:
Deon George 2024-06-01 10:46:02 +10:00
parent b5047c52f0
commit 73cf421739
10 changed files with 66 additions and 164 deletions

View File

@ -5,20 +5,19 @@ namespace App\Casts;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes; use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
class CompressedString implements CastsAttributes class CompressedStringOrNull implements CastsAttributes
{ {
/** /**
* Cast the given value. * Cast the given value.
* *
* For postgresl bytea columns the value is a resource stream
*
* @param Model $model * @param Model $model
* @param string $key * @param string $key
* @param mixed $value * @param mixed $value
* @param array $attributes * @param array $attributes
* @return string * @return string|null
* @note postgres bytea columns the value is a resource stream
*/ */
public function get($model,string $key,mixed $value,array $attributes): string public function get(Model $model,string $key,mixed $value,array $attributes): ?string
{ {
// For stream resources, we to fseek in case we've already read it. // For stream resources, we to fseek in case we've already read it.
if (is_resource($value)) if (is_resource($value))
@ -28,13 +27,7 @@ class CompressedString implements CastsAttributes
? stream_get_contents($value) ? stream_get_contents($value)
: $value; : $value;
// If we get an error decompressing, it might not be zstd (or its already been done) return $value ? zstd_uncompress(base64_decode($value)) : NULL;
try {
return $value ? zstd_uncompress(base64_decode($value)) : '';
} catch (\ErrorException $e) {
return $value;
}
} }
/** /**
@ -44,10 +37,10 @@ class CompressedString implements CastsAttributes
* @param string $key * @param string $key
* @param mixed $value * @param mixed $value
* @param array $attributes * @param array $attributes
* @return string * @return string|null
*/ */
public function set($model,string $key,$value,array $attributes): string public function set(Model $model,string $key,$value,array $attributes): ?string
{ {
return $value ? base64_encode(zstd_compress($value)) : ''; return $value ? base64_encode(zstd_compress($value)) : NULL;
} }
} }

View File

@ -0,0 +1,29 @@
<?php
namespace App\Casts;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Database\Eloquent\Model;
class UTF8StringOrNull implements CastsAttributes
{
/**
* Cast the given value.
*
* @param array<string, mixed> $attributes
*/
public function get(Model $model,string $key,mixed $value,array $attributes): ?string
{
return $value ? utf8_decode($value) : NULL;
}
/**
* Prepare the given value for storage.
*
* @param array<string, mixed> $attributes
*/
public function set(Model $model,string $key,mixed $value,array $attributes): ?string
{
return $value ? utf8_encode($value) : NULL;
}
}

View File

@ -14,21 +14,17 @@ use Illuminate\Support\Facades\Notification;
use App\Classes\FTN\Message; use App\Classes\FTN\Message;
use App\Models\{Echomail,Netmail,User}; use App\Models\{Echomail,Netmail,User};
use App\Notifications\Netmails\{EchoareaNotExist,EchoareaNotSubscribed,EchoareaNoWrite,NetmailForward,NetmailHubNoUser}; use App\Notifications\Netmails\{EchoareaNotExist,EchoareaNotSubscribed,EchoareaNoWrite,NetmailForward,NetmailHubNoUser};
use App\Traits\{EncodeUTF8,ParseAddresses}; use App\Traits\ParseAddresses;
class MessageProcess implements ShouldQueue class MessageProcess implements ShouldQueue
{ {
private const LOGKEY = 'JMP'; private const LOGKEY = 'JMP';
use Dispatchable,InteractsWithQueue,Queueable,SerializesModels,ParseAddresses,EncodeUTF8; use Dispatchable,InteractsWithQueue,Queueable,SerializesModels,ParseAddresses;
private Echomail|Netmail|string $mo; private Echomail|Netmail|string $mo;
private bool $skipbot; private bool $skipbot;
private const cast_utf8 = [
'mo',
];
/** /**
* Process a message from a packet * Process a message from a packet
* *
@ -54,16 +50,6 @@ class MessageProcess implements ShouldQueue
} }
} }
public function __serialize()
{
return $this->encode();
}
public function __unserialize(array $values)
{
$this->decode($values);
}
/** /**
* At this point, we know that the packet is from a system we know about, and the packet is to us: * At this point, we know that the packet is from a system we know about, and the packet is to us:
* + From a system that is configured with us, and the password has been validated * + From a system that is configured with us, and the password has been validated
@ -144,8 +130,8 @@ class MessageProcess implements ShouldQueue
// Check if the netmail is to a user, with netmail forwarding enabled // Check if the netmail is to a user, with netmail forwarding enabled
$uo = User::active() $uo = User::active()
->where(function($query) { ->where(function($query) {
return $query->whereRaw(sprintf("LOWER(name)='%s'",strtolower($this->mo->to))) return $query->whereRaw(sprintf("LOWER(name)='%s'",strtolower(utf8_encode($this->mo->to))))
->orWhereRaw(sprintf("LOWER(alias)='%s'",strtolower($this->mo->to))); ->orWhereRaw(sprintf("LOWER(alias)='%s'",strtolower(utf8_encode($this->mo->to))));
}) })
->whereNotNull('system_id') ->whereNotNull('system_id')
->single(); ->single();

View File

@ -139,7 +139,7 @@ class PacketProcess implements ShouldQueue
$count++; $count++;
} catch (\Exception $e) { } catch (\Exception $e) {
Log::error(sprintf('%s:! Got error dispatching message [%s] (%d:%s-%s).',self::LOGKEY,$msg->msgid,$e->getLine(),$e->getFile(),$e->getMessage())); Log::error(sprintf('%s:! Got error [%s] dispatching message [%s] (%d:%s-%s).',self::LOGKEY,get_class($e),$msg->msgid,$e->getLine(),$e->getFile(),$e->getMessage()));
} }
} }

View File

@ -11,7 +11,7 @@ use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use App\Casts\CompressedString; use App\Casts\CompressedStringOrNull;
use App\Traits\{QueryCacheableConfig,ScopeActive}; use App\Traits\{QueryCacheableConfig,ScopeActive};
class Domain extends Model class Domain extends Model
@ -22,7 +22,7 @@ class Domain extends Model
private const STATS_MONTHS = 6; private const STATS_MONTHS = 6;
protected $casts = [ protected $casts = [
'homepage' => CompressedString::class, 'homepage' => CompressedStringOrNull::class,
]; ];
/* SCOPES */ /* SCOPES */

View File

@ -9,7 +9,7 @@ use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use App\Casts\{CollectionOrNull,CompressedString}; use App\Casts\{CollectionOrNull,CompressedStringOrNull,UTF8StringOrNull};
use App\Classes\FTN\Message; use App\Classes\FTN\Message;
use App\Interfaces\Packet; use App\Interfaces\Packet;
use App\Traits\{MessageAttributes,MsgID,ParseAddresses,QueryCacheableConfig}; use App\Traits\{MessageAttributes,MsgID,ParseAddresses,QueryCacheableConfig};
@ -32,10 +32,16 @@ final class Echomail extends Model implements Packet
public Address $tftn; public Address $tftn;
protected $casts = [ protected $casts = [
'to' => UTF8StringOrNull::class,
'from' => UTF8StringOrNull::class,
'subject' => UTF8StringOrNull::class,
'origin' => UTF8StringOrNull::class,
'tearline' => UTF8StringOrNull::class,
'tagline' => UTF8StringOrNull::class,
'datetime' => 'datetime:Y-m-d H:i:s', 'datetime' => 'datetime:Y-m-d H:i:s',
'kludges' => CollectionOrNull::class, 'kludges' => CollectionOrNull::class,
'msg' => CompressedString::class, 'msg' => CompressedStringOrNull::class,
'msg_src' => CompressedString::class, 'msg_src' => CompressedStringOrNull::class,
'rogue_seenby' => CollectionOrNull::class, 'rogue_seenby' => CollectionOrNull::class,
'rogue_path' => CollectionOrNull::class, // @deprecated? 'rogue_path' => CollectionOrNull::class, // @deprecated?
]; ];

View File

@ -11,12 +11,11 @@ use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use App\Casts\{CollectionOrNull,CompressedString}; use App\Casts\{CollectionOrNull,CompressedStringOrNull};
use App\Traits\EncodeUTF8;
class File extends Model class File extends Model
{ {
use SoftDeletes,EncodeUTF8; use SoftDeletes;
private const LOGKEY = 'MF-'; private const LOGKEY = 'MF-';
private bool $no_export = FALSE; private bool $no_export = FALSE;
@ -28,18 +27,13 @@ class File extends Model
protected $casts = [ protected $casts = [
'kludges' => CollectionOrNull::class, 'kludges' => CollectionOrNull::class,
'datetime' => 'datetime:Y-m-d H:i:s', 'datetime' => 'datetime:Y-m-d H:i:s',
'desc' => CompressedString::class, 'desc' => CompressedStringOrNull::class,
'ldesc' => CompressedString::class, 'ldesc' => CompressedStringOrNull::class,
'rogue_seenby' => CollectionOrNull::class, 'rogue_seenby' => CollectionOrNull::class,
'rogue_path' => CollectionOrNull::class, 'rogue_path' => CollectionOrNull::class,
'size' => 'int', 'size' => 'int',
]; ];
private const cast_utf8 = [
'desc',
'ldesc',
];
public static function boot() public static function boot()
{ {
parent::boot(); parent::boot();

View File

@ -10,7 +10,7 @@ use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use App\Casts\{CollectionOrNull,CompressedString}; use App\Casts\{CollectionOrNull,CompressedStringOrNull,UTF8StringOrNull};
use App\Interfaces\Packet; use App\Interfaces\Packet;
use App\Pivots\ViaPivot; use App\Pivots\ViaPivot;
use App\Traits\{MessageAttributes,MsgID}; use App\Traits\{MessageAttributes,MsgID};
@ -32,10 +32,16 @@ final class Netmail extends Model implements Packet
]; ];
protected $casts = [ protected $casts = [
'to' => UTF8StringOrNull::class,
'from' => UTF8StringOrNull::class,
'subject' => UTF8StringOrNull::class,
'origin' => UTF8StringOrNull::class,
'tearline' => UTF8StringOrNull::class,
'tagline' => UTF8StringOrNull::class,
'datetime' => 'datetime:Y-m-d H:i:s', 'datetime' => 'datetime:Y-m-d H:i:s',
'kludges' => CollectionOrNull::class, 'kludges' => CollectionOrNull::class,
'msg' => CompressedString::class, 'msg' => CompressedStringOrNull::class,
'msg_src' => CompressedString::class, 'msg_src' => CompressedStringOrNull::class,
'sent_at' => 'datetime:Y-m-d H:i:s', 'sent_at' => 'datetime:Y-m-d H:i:s',
]; ];

View File

@ -1,99 +0,0 @@
<?php
/**
* Encode our data so that it can be serialised
*/
namespace App\Traits;
use Illuminate\Support\Arr;
trait EncodeUTF8
{
private array $_encoded = []; // Remember what we've decoded - when calling getAttribute()
private function decode(array $values): void
{
$properties = (new \ReflectionClass($this))->getProperties();
$class = get_class($this);
foreach ($properties as $property) {
if ($property->isStatic())
continue;
$name = $property->getName();
$decode = in_array($name,self::cast_utf8);
if ($property->isPrivate())
$name = "\0{$class}\0{$name}";
elseif ($property->isProtected())
$name = "\0*\0{$name}";
if (! array_key_exists($name,$values))
continue;
$property->setAccessible(true);
try {
$property->setValue(
$this,$decode ? utf8_decode($values[$name]) : $values[$name]
);
} catch (\Exception $e) {
dd(['e'=>$e->getMessage(),'name'=>$name,'values'=>$values[$name],'decode'=>$decode]);
}
}
}
private function encode(): array
{
$values = [];
$properties = (new \ReflectionClass($this))->getProperties();
$class = get_class($this);
foreach ($properties as $property) {
// Dont serialize the validation error
if (($property->name === 'errors') || $property->isStatic())
continue;
$property->setAccessible(true);
if (! $property->isInitialized($this))
continue;
$name = $property->getName();
$encode = in_array($name,self::cast_utf8);
if ($property->isPrivate())
$name = "\0{$class}\0{$name}";
elseif ($property->isProtected())
$name = "\0*\0{$name}";
$property->setAccessible(true);
$value = $property->getValue($this);
$values[$name] = $encode ? utf8_encode($value) : $value;
}
return $values;
}
public function getAttribute($key)
{
if (in_array($key,self::cast_utf8) && Arr::get($this->attributes,$key) && (! Arr::get($this->_encoded,$key))) {
// We need to get it from the parent first, taking into account any casting
$this->attributes[$key] = utf8_decode(parent::getAttribute($key));
$this->_encoded[$key] = TRUE;
return $this->attributes[$key];
}
return Arr::get($this->_encoded,$key) ? $this->attributes[$key] : parent::getAttribute($key);
}
public function setAttribute($key,$value)
{
return parent::setAttribute($key,in_array($key,self::cast_utf8) ? utf8_encode($value) : $value);
}
}

View File

@ -15,24 +15,11 @@ use App\Models\{Address,Echomail};
trait MessageAttributes trait MessageAttributes
{ {
use EncodeUTF8;
// Items we need to set when creating() // Items we need to set when creating()
public Collection $set; public Collection $set;
// Validation Errors // Validation Errors
public ?MessageBag $errors = NULL; public ?MessageBag $errors = NULL;
private const cast_utf8 = [
'to',
'from',
'subject',
'msg',
'msg_src',
'origin',
'tearline',
'tagline',
];
public function __construct() public function __construct()
{ {
parent::__construct(); parent::__construct();