clrghouz/app/Jobs/MessageProcess.php
Deon George 81f59dcbb8
All checks were successful
Create Docker Image / Build Docker Image (x86_64) (push) Successful in 42s
Create Docker Image / Build Docker Image (arm64) (push) Successful in 1m50s
Create Docker Image / Final Docker Image Manifest (push) Successful in 11s
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.
2024-06-01 10:46:02 +10:00

335 lines
10 KiB
PHP

<?php
namespace App\Jobs;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Notification;
use App\Classes\FTN\Message;
use App\Models\{Echomail,Netmail,User};
use App\Notifications\Netmails\{EchoareaNotExist,EchoareaNotSubscribed,EchoareaNoWrite,NetmailForward,NetmailHubNoUser};
use App\Traits\ParseAddresses;
class MessageProcess implements ShouldQueue
{
private const LOGKEY = 'JMP';
use Dispatchable,InteractsWithQueue,Queueable,SerializesModels,ParseAddresses;
private Echomail|Netmail|string $mo;
private bool $skipbot;
/**
* Process a message from a packet
*
* @param Echomail|Netmail $mo The message object
* @param bool $skipbot Dont trigger bot actions
*/
public function __construct(Echomail|Netmail $mo,bool $skipbot=FALSE)
{
// @todo We need to serialize this model here, because laravel has an error unserializing it (Model Not Found)
$this->mo = serialize($mo);
$this->skipbot = $skipbot;
}
public function __get($key): mixed
{
switch ($key) {
case 'jobname':
$mo = unserialize($this->mo);
return sprintf('%s-%s-%s',$mo->set->get('set_pkt'),$mo->set->get('set_sender')->ftn,$mo->msgid);
default:
return NULL;
}
}
/**
* 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 not configured with us, and it may have netmails for us
*/
public function handle()
{
$this->mo = unserialize($this->mo);
// Load our details
$ftns = our_address();
// If we are a netmail
if ($this->mo instanceof Netmail) {
// @todo generate exception when netmail to system that doesnt exist (node/point) and its this host's responsibility
Log::info(sprintf('%s:- Processing Netmail [%s] to (%s) [%s] from (%s) [%s].',
self::LOGKEY,
$this->mo->msgid,
$this->mo->to,$this->mo->tftn->ftn,
$this->mo->from,$this->mo->fftn->ftn,
));
// @todo Enable checks to reject old messages
// Check for duplicate messages
// FTS-0009.001
if ($this->mo->msgid) {
Log::debug(sprintf('%s:- Checking for duplicate from host [%s].',self::LOGKEY,$this->mo->fftn->ftn));
$o = Netmail::where('msgid',$this->mo->msgid)
->where('fftn_id',$this->mo->fftn->id)
->where('datetime','>',Carbon::now()->subYears(3))
->single();
if ($o) {
Log::alert(sprintf('%s:! Duplicate netmail #%d [%s] from (%s) [%s] to (%s) - ignoring.',
self::LOGKEY,
$o->id,
$this->mo->msgid,
$this->mo->from,$this->mo->fftn->ftn,
$this->mo->to,
));
return;
}
}
// @todo Enable checks to see if this is a file request or file send
// Strip any local/transit flags
$this->mo->flags &= ~(Message::FLAG_LOCAL|Message::FLAG_INTRANSIT);
// Determine if the message is to this system, or in transit
if ($ftns->contains($this->mo->tftn)) {
$processed = FALSE;
// If the message is to a bot, we'll process it
if (! $this->skipbot)
foreach (config('process.robots') as $class) {
if ($processed=$class::handle($this->mo)) {
$this->mo->flags |= Message::FLAG_RECD;
$this->mo->save();
Log::info(sprintf('%s:= Netmail [%s] from (%s:%s) - was processed by us internally [%d]',
self::LOGKEY,
$this->mo->msgid,
$this->mo->from,
$this->mo->fftn->ftn,
$this->mo->id,
));
break;
}
}
if (! $processed) {
// Check if the netmail is to a user, with netmail forwarding enabled
$uo = User::active()
->where(function($query) {
return $query->whereRaw(sprintf("LOWER(name)='%s'",strtolower(utf8_encode($this->mo->to))))
->orWhereRaw(sprintf("LOWER(alias)='%s'",strtolower(utf8_encode($this->mo->to))));
})
->whereNotNull('system_id')
->single();
if ($uo && ($ao=$uo->system->match($this->mo->tftn->zone)?->pop())) {
$note = "+--[ FORWARDED MESSAGE ]----------------------------------+\r";
$note .= "+ This message has been forwarded to you, it was originally sent to you\r";
$note .= sprintf("+ at [%s]\r",$this->mo->tftn->ftn);
$note .= "+---------------------------------------------------------+\r\r";
$this->mo->msg = $note.$this->mo->content;
$this->mo->tftn_id = $ao->id;
$this->mo->flags |= Message::FLAG_INTRANSIT;
$this->mo->save();
$processed = TRUE;
// Dont send an advisement to an areabot
if (! in_array(strtolower($this->mo->from),config('fido.areabots')))
Notification::route('netmail',$this->mo->fftn)->notify(new NetmailForward($this->mo,$ao));
// We'll ignore messages from *fix users
} elseif (in_array(strtolower($this->mo->from),config('fido.areabots'))) {
$this->mo->flags |= Message::FLAG_RECD;
$this->mo->save();
Log::alert(sprintf('%s:! Ignoring Netmail [%s] to the Hub from (%s:%s) - its from a bot [%d]',
self::LOGKEY,
$this->mo->msgid,
$this->mo->from,
$this->mo->fftn->ftn,
$this->mo->id,
));
$processed = TRUE;
}
}
// If not processed, no users here!
if (! $processed) {
Log::alert(sprintf('%s:! Netmail to the Hub from (%s) [%s] but no users here.',self::LOGKEY,$this->mo->from,$this->mo->fftn->ftn));
Notification::route('netmail',$this->mo->fftn)->notify(new NetmailHubNoUser($this->mo));
}
// If in transit, store for collection
} else {
// @todo In transit loop checking
// @todo In transit TRACE response
$this->mo->flags |= Message::FLAG_INTRANSIT;
$this->mo->save();
Log::info(sprintf('%s:= Netmail [%s] in transit to (%s:%s) from (%s:%s) [%d].',
self::LOGKEY,
$this->mo->msgid,
$this->mo->to,$this->mo->tftn->ftn,
$this->mo->from,$this->mo->fftn->ftn,
$this->mo->id,
));
}
// Else we are echomail
} else {
// The packet sender
$sender = $this->mo->set->get('set_sender');
// @todo Check that this does evaulate to true if a message has been rescanned
$rescanned = $this->mo->kludges->get('RESCANNED',FALSE);
// Echoarea doesnt exist, cant import the message
if (! $this->mo->echoarea) {
Log::alert(sprintf('%s:! Echoarea [%s] doesnt exist for zone [%d@%s]',self::LOGKEY,$this->mo->set->get('set_echoarea'),$sender->zone->zone_id,$sender->zone->domain->name));
Notification::route('netmail',$sender)->notify(new EchoareaNotExist($this->mo));
return;
}
Log::debug(sprintf('%s:- Processing echomail [%s] in [%s] from [%s].',self::LOGKEY,$this->mo->msgid,$this->mo->echoarea->name,$sender->ftn));
// Message from zone is incorrect for echoarea
if (! $this->mo->echoarea->domain->zones->contains($this->mo->fftn->zone)) {
Log::alert(sprintf('%s:! The message [%s] is from a different zone [%d] than the packet sender [%d] - not importing',
self::LOGKEY,
$this->mo->msgid,
$this->mo->fftn->zone->zone_id,
$this->mo->fftn->zone->zone_id));
return;
}
// Check for duplicate messages
// FTS-0009.001
if ($this->mo->msgid) {
$o = Echomail::where('msgid',$this->mo->msgid)
->where('fftn_id',$this->mo->fftn->id)
->where('datetime','>=',$this->mo->date->subYears(3))
->where('datetime','<=',$this->mo->date)
->single();
Log::debug(sprintf('%s:- Checking for duplicate from host id [%d].',self::LOGKEY,$this->mo->fftn->id));
if ($o) {
// @todo Actually update seenby
Log::alert(sprintf('%s:! Duplicate echomail [%s] in [%s] from (%s) [%s] to (%s) - updating seenby.',
self::LOGKEY,
$this->mo->msgid,
$this->mo->echoarea->name,
$this->mo->from,$this->mo->fftn->ftn,
$this->mo->to,
));
//$o->save();
// @todo This duplicate message may have gone via a different path, be nice to record it.
/*
// If we didnt get the path on the original message, we'll override it
if (! $o->path->count()) {
$dummy = collect();
$path = $this->parseAddresses('path',$this->mo->path,$sender->zone,$dummy);
$ppoid = NULL;
foreach ($path as $aoid) {
$po = DB::select('INSERT INTO echomail_path (echomail_id,address_id,parent_id) VALUES (?,?,?) RETURNING id',[
$o->id,
$aoid,
$ppoid,
]);
$ppoid = $po[0]->id;
}
}
*/
// @todo if we have an export for any of the seenby addresses, remove it
//$seenby = $this->parseAddresses('seenby',$this->mo->seenby,$sender->zone,$o->rogue_seenby);
//$this->mo->seenby()->syncWithoutDetaching($seenby);
// In case our rogue_seenby changed
//$this->mo->save();
return;
}
}
// Find another message with the same msg_crc
if ($this->mo->msg_crc) {
$o = Echomail::where('msg_crc',$xx=md5($this->mo->msg_crc))
->where('fftn_id',$this->mo->fftn->id)
->where('datetime','>',Carbon::now()->subWeek())
->get();
if ($o->count())
Log::alert(sprintf('%s:! Duplicate message CRC [%s] in [%s].',
self::LOGKEY,
$xx,
$o->pluck('id')->join('|')
));
}
// Can the system send messages to this area?
if (! $this->mo->echoarea->can_write($sender->security)) {
Log::alert(sprintf('%s:! FTN [%s] is not allowed to post [%s] to [%s].',self::LOGKEY,$sender->ftn,$this->mo->msgid,$this->mo->echoarea->name));
if (! $rescanned)
Notification::route('netmail',$sender)->notify(new EchoareaNoWrite($this->mo));
return;
}
// If the node is not subscribed, we'll accept it, but let them know
if (! $sender->echoareas->contains($this->mo->echoarea)) {
Log::alert(sprintf('%s:! FTN [%s] is not subscribed to [%s] for [%s].',self::LOGKEY,$sender->ftn,$this->mo->echoarea->name,$this->mo->msgid));
if (! $rescanned)
Notification::route('netmail',$sender)->notify(new EchoareaNotSubscribed($this->mo));
}
// We know about this area, store it
$this->mo->save();
Log::info(sprintf('%s:= Echomail [%s] in [%s] from (%s) [%s] to (%s) - [%s].',
self::LOGKEY,
$this->mo->msgid,
$this->mo->echoarea->name,
$this->mo->from,$this->mo->fftn->ftn,
$this->mo->to,
$this->mo->id,
));
// If the message is to a bot, but not rescanned, or purposely skipbot set, we'll process it
if ((! $this->skipbot) && (! $rescanned))
foreach (config('process.echomail') as $class) {
if ($class::handle($this->mo)) {
break;
}
}
}
}
}