Added failed delivery notification

This commit is contained in:
Will Browning 2021-08-20 15:40:36 +01:00
parent 55373af6ed
commit 9ff1fdf478
13 changed files with 1063 additions and 674 deletions

View file

@ -12,6 +12,7 @@ use App\Models\EmailData;
use App\Models\PostfixQueueId;
use App\Models\Recipient;
use App\Models\User;
use App\Notifications\FailedDeliveryNotification;
use App\Notifications\NearBandwidthLimit;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Cache;
@ -331,6 +332,33 @@ class ReceiveEmail extends Command
if ($undeliveredMessage) {
$undeliveredMessageHeaders = $this->parseDeliveryStatus($undeliveredMessage->getMimePartStr());
if (isset($undeliveredMessageHeaders['Feedback-id'])) {
$parts = explode(':', $undeliveredMessageHeaders['Feedback-id']);
if (in_array($parts[0], ['F', 'R', 'S']) && !isset($alias)) {
$alias = Alias::find($parts[1]);
// Find the user from the alias if we don't have it from the recipient
if (!isset($user) && isset($alias)) {
$user = $alias->user;
}
}
// Check if failed delivery notification or Alias deactivated notification and if so do not notify the user again
if (! in_array($parts[0], ['FDN'])) {
if (isset($recipient)) {
// Notify recipient of failed delivery, check that $recipient address is verified
if ($recipient->email_verified_at) {
$recipient->notify(new FailedDeliveryNotification($alias->email ?? null, $undeliveredMessageHeaders['X-anonaddy-original-sender'] ?? null, $undeliveredMessageHeaders['Subject'] ?? null));
}
} elseif (in_array($parts[0], ['R', 'S']) && isset($user)) {
if ($user->email_verified_at) {
$user->defaultRecipient->notify(new FailedDeliveryNotification($alias->email ?? null, $undeliveredMessageHeaders['X-anonaddy-original-sender'] ?? null, $undeliveredMessageHeaders['Subject'] ?? null));
}
}
}
}
}
if (isset($user)) {

View file

@ -7,6 +7,7 @@ use App\Helpers\OpenPGPSigner;
use App\Models\Alias;
use App\Models\EmailData;
use App\Models\Recipient;
use App\Notifications\FailedDeliveryNotification;
use App\Notifications\GpgKeyExpired;
use App\Traits\CheckUserRules;
use Illuminate\Bus\Queueable;
@ -45,6 +46,7 @@ class ForwardEmail extends Mailable implements ShouldQueue, ShouldBeEncrypted
protected $listUnsubscribe;
protected $inReplyTo;
protected $references;
protected $recipientId;
/**
* Create a new message instance.
@ -69,6 +71,7 @@ class ForwardEmail extends Mailable implements ShouldQueue, ShouldBeEncrypted
$this->inReplyTo = $emailData->inReplyTo;
$this->references = $emailData->references;
$this->encryptedParts = $emailData->encryptedParts ?? null;
$this->recipientId = $recipient->id;
$fingerprint = $recipient->should_encrypt && !$this->isAlreadyEncrypted() ? $recipient->fingerprint : null;
@ -133,6 +136,9 @@ class ForwardEmail extends Mailable implements ShouldQueue, ShouldBeEncrypted
->withSwiftMessage(function ($message) use ($returnPath) {
$message->setReturnPath($returnPath);
$message->getHeaders()
->addTextHeader('Feedback-ID', 'F:' . $this->alias->id . ':anonaddy');
// This header is used to set the To: header as the alias just before sending.
$message->getHeaders()
->addTextHeader('Alias-To', $this->alias->email);
@ -152,9 +158,6 @@ class ForwardEmail extends Mailable implements ShouldQueue, ShouldBeEncrypted
->addTextHeader('List-Unsubscribe', base64_decode($this->listUnsubscribe));
}
/* $message->getHeaders()
->addTextHeader('List-Unsubscribe', '<mailto:' . $this->alias->id . '@unsubscribe.' . config('anonaddy.domain') . '?subject=unsubscribe>, <' . $this->deactivateUrl . '>'); */
if ($this->inReplyTo) {
$message->getHeaders()
->addTextHeader('In-Reply-To', base64_decode($this->inReplyTo));
@ -225,6 +228,32 @@ class ForwardEmail extends Mailable implements ShouldQueue, ShouldBeEncrypted
return $this->email;
}
/**
* Handle a job failure.
*
* @param \Throwable $exception
* @return void
*/
public function failed()
{
// Send user failed delivery notification, add to failed deliveries table
$recipient = Recipient::find($this->recipientId);
$recipient->notify(new FailedDeliveryNotification($this->alias->email, $this->sender, base64_decode($this->emailSubject)));
$this->user->failedDeliveries()->create([
'recipient_id' => $this->recipientId,
'alias_id' => $this->alias->id,
'bounce_type' => null,
'remote_mta' => null,
'sender' => $this->sender,
'email_type' => 'F',
'status' => null,
'code' => 'An error has occurred, please check the logs.',
'attempted_at' => now()
]);
}
private function isAlreadyEncrypted()
{
return $this->encryptedParts || preg_match('/^-----BEGIN PGP MESSAGE-----([A-Za-z0-9+=\/\n]+)-----END PGP MESSAGE-----$/', base64_decode($this->emailText));

View file

@ -6,6 +6,7 @@ use App\Helpers\AlreadyEncryptedSigner;
use App\Models\Alias;
use App\Models\EmailData;
use App\Models\User;
use App\Notifications\FailedDeliveryNotification;
use App\Traits\CheckUserRules;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
@ -89,6 +90,9 @@ class ReplyToEmail extends Mailable implements ShouldQueue, ShouldBeEncrypted
->withSwiftMessage(function ($message) use ($returnPath) {
$message->setReturnPath($returnPath);
$message->getHeaders()
->addTextHeader('Feedback-ID', 'R:' . $this->alias->id . ':anonaddy');
// Message-ID is replaced on replies as it can leak parts of the real email
$message->setId(bin2hex(random_bytes(16)).'@'.$this->alias->domain);
@ -146,4 +150,28 @@ class ReplyToEmail extends Mailable implements ShouldQueue, ShouldBeEncrypted
return $this->email;
}
/**
* Handle a job failure.
*
* @param \Throwable $exception
* @return void
*/
public function failed()
{
// Send user failed delivery notification, add to failed deliveries table
$this->user->defaultRecipient->notify(new FailedDeliveryNotification($this->alias->email, $this->sender, base64_decode($this->emailSubject)));
$this->user->failedDeliveries()->create([
'recipient_id' => null,
'alias_id' => $this->alias->id,
'bounce_type' => null,
'remote_mta' => null,
'sender' => $this->sender,
'email_type' => 'R',
'status' => null,
'code' => 'An error has occurred, please check the logs.',
'attempted_at' => now()
]);
}
}

View file

@ -6,6 +6,7 @@ use App\Helpers\AlreadyEncryptedSigner;
use App\Models\Alias;
use App\Models\EmailData;
use App\Models\User;
use App\Notifications\FailedDeliveryNotification;
use App\Traits\CheckUserRules;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
@ -85,6 +86,9 @@ class SendFromEmail extends Mailable implements ShouldQueue, ShouldBeEncrypted
->withSwiftMessage(function ($message) use ($returnPath) {
$message->setReturnPath($returnPath);
$message->getHeaders()
->addTextHeader('Feedback-ID', 'S:' . $this->alias->id . ':anonaddy');
// Message-ID is replaced on send from as it can leak parts of the real email
$message->setId(bin2hex(random_bytes(16)).'@'.$this->alias->domain);
@ -132,4 +136,28 @@ class SendFromEmail extends Mailable implements ShouldQueue, ShouldBeEncrypted
return $this->email;
}
/**
* Handle a job failure.
*
* @param \Throwable $exception
* @return void
*/
public function failed()
{
// Send user failed delivery notification, add to failed deliveries table
$this->user->defaultRecipient->notify(new FailedDeliveryNotification($this->alias->email, $this->sender, base64_decode($this->emailSubject)));
$this->user->failedDeliveries()->create([
'recipient_id' => null,
'alias_id' => $this->alias->id,
'bounce_type' => null,
'remote_mta' => null,
'sender' => $this->sender,
'email_type' => 'S',
'status' => null,
'code' => 'An error has occurred, please check the logs.',
'attempted_at' => now()
]);
}
}

View file

@ -2,11 +2,13 @@
namespace App\Notifications;
use App\Helpers\OpenPGPSigner;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use Swift_SwiftException;
class DomainMxRecordsInvalid extends Notification implements ShouldQueue, ShouldBeEncrypted
{
@ -43,11 +45,37 @@ class DomainMxRecordsInvalid extends Notification implements ShouldQueue, Should
*/
public function toMail($notifiable)
{
$openpgpsigner = null;
$recipient = $notifiable->defaultRecipient;
$fingerprint = $recipient->should_encrypt ? $recipient->fingerprint : null;
if ($fingerprint) {
try {
$openpgpsigner = OpenPGPSigner::newInstance(config('anonaddy.signing_key_fingerprint'), [], "~/.gnupg");
$openpgpsigner->addRecipient($fingerprint);
} catch (Swift_SwiftException $e) {
info($e->getMessage());
$openpgpsigner = null;
$recipient->update(['should_encrypt' => false]);
$recipient->notify(new GpgKeyExpired);
}
}
return (new MailMessage)
->subject("Your domain's MX records no longer point to AnonAddy")
->markdown('mail.domain_mx_records_invalid', [
'domain' => $this->domain
]);
])
->withSwiftMessage(function ($message) use ($openpgpsigner) {
$message->getHeaders()
->addTextHeader('Feedback-ID', 'DMI:anonaddy');
if ($openpgpsigner) {
$message->attachSigner($openpgpsigner);
}
});
}
/**

View file

@ -2,11 +2,13 @@
namespace App\Notifications;
use App\Helpers\OpenPGPSigner;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use Swift_SwiftException;
class DomainUnverifiedForSending extends Notification implements ShouldQueue, ShouldBeEncrypted
{
@ -45,12 +47,38 @@ class DomainUnverifiedForSending extends Notification implements ShouldQueue, Sh
*/
public function toMail($notifiable)
{
$openpgpsigner = null;
$recipient = $notifiable->defaultRecipient;
$fingerprint = $recipient->should_encrypt ? $recipient->fingerprint : null;
if ($fingerprint) {
try {
$openpgpsigner = OpenPGPSigner::newInstance(config('anonaddy.signing_key_fingerprint'), [], "~/.gnupg");
$openpgpsigner->addRecipient($fingerprint);
} catch (Swift_SwiftException $e) {
info($e->getMessage());
$openpgpsigner = null;
$recipient->update(['should_encrypt' => false]);
$recipient->notify(new GpgKeyExpired);
}
}
return (new MailMessage)
->subject("Your domain has been unverified for sending on AnonAddy")
->markdown('mail.domain_unverified_for_sending', [
'domain' => $this->domain,
'reason' => $this->reason
]);
])
->withSwiftMessage(function ($message) use ($openpgpsigner) {
$message->getHeaders()
->addTextHeader('Feedback-ID', 'DUS:anonaddy');
if ($openpgpsigner) {
$message->attachSigner($openpgpsigner);
}
});
}
/**

View file

@ -0,0 +1,98 @@
<?php
namespace App\Notifications;
use App\Helpers\OpenPGPSigner;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use Swift_SwiftException;
class FailedDeliveryNotification extends Notification implements ShouldQueue, ShouldBeEncrypted
{
use Queueable;
protected $aliasEmail;
protected $originalSender;
protected $originalSubject;
/**
* Create a new notification instance.
*
* @return void
*/
public function __construct($aliasEmail, $originalSender, $originalSubject)
{
$this->aliasEmail = $aliasEmail;
$this->originalSender = $originalSender;
$this->originalSubject = $originalSubject;
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable)
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
$openpgpsigner = null;
$fingerprint = $notifiable->should_encrypt ? $notifiable->fingerprint : null;
if ($fingerprint) {
try {
$openpgpsigner = OpenPGPSigner::newInstance(config('anonaddy.signing_key_fingerprint'), [], "~/.gnupg");
$openpgpsigner->addRecipient($fingerprint);
} catch (Swift_SwiftException $e) {
info($e->getMessage());
$openpgpsigner = null;
$notifiable->update(['should_encrypt' => false]);
$notifiable->notify(new GpgKeyExpired);
}
}
return (new MailMessage)
->subject("New failed delivery on AnonAddy")
->markdown('mail.failed_delivery_notification', [
'aliasEmail' => $this->aliasEmail,
'originalSender' => $this->originalSender,
'originalSubject' => $this->originalSubject
])
->withSwiftMessage(function ($message) use ($openpgpsigner) {
$message->getHeaders()
->addTextHeader('Feedback-ID', 'FDN:anonaddy');
if ($openpgpsigner) {
$message->attachSigner($openpgpsigner);
}
});
}
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
* @return array
*/
public function toArray($notifiable)
{
return [
//
];
}
}

View file

@ -2,11 +2,13 @@
namespace App\Notifications;
use App\Helpers\OpenPGPSigner;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use Swift_SwiftException;
class NearBandwidthLimit extends Notification implements ShouldQueue, ShouldBeEncrypted
{
@ -45,6 +47,24 @@ class NearBandwidthLimit extends Notification implements ShouldQueue, ShouldBeEn
*/
public function toMail($notifiable)
{
$openpgpsigner = null;
$recipient = $notifiable->defaultRecipient;
$fingerprint = $recipient->should_encrypt ? $recipient->fingerprint : null;
if ($fingerprint) {
try {
$openpgpsigner = OpenPGPSigner::newInstance(config('anonaddy.signing_key_fingerprint'), [], "~/.gnupg");
$openpgpsigner->addRecipient($fingerprint);
} catch (Swift_SwiftException $e) {
info($e->getMessage());
$openpgpsigner = null;
$recipient->update(['should_encrypt' => false]);
$recipient->notify(new GpgKeyExpired);
}
}
return (new MailMessage)
->subject("You're close to your bandwidth limit for ".$this->month)
->markdown('mail.near_bandwidth_limit', [
@ -52,7 +72,15 @@ class NearBandwidthLimit extends Notification implements ShouldQueue, ShouldBeEn
'bandwidthLimit' => $notifiable->getBandwidthLimitMb(),
'month' => $this->month,
'reset' => $this->reset
]);
])
->withSwiftMessage(function ($message) use ($openpgpsigner) {
$message->getHeaders()
->addTextHeader('Feedback-ID', 'NBL:anonaddy');
if ($openpgpsigner) {
$message->attachSigner($openpgpsigner);
}
});
}
/**

View file

@ -2,11 +2,13 @@
namespace App\Notifications;
use App\Helpers\OpenPGPSigner;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use Swift_SwiftException;
class UsernameReminder extends Notification implements ShouldQueue, ShouldBeEncrypted
{
@ -31,14 +33,35 @@ class UsernameReminder extends Notification implements ShouldQueue, ShouldBeEncr
*/
public function toMail($notifiable)
{
$openpgpsigner = null;
$fingerprint = $notifiable->should_encrypt ? $notifiable->fingerprint : null;
if ($fingerprint) {
try {
$openpgpsigner = OpenPGPSigner::newInstance(config('anonaddy.signing_key_fingerprint'), [], "~/.gnupg");
$openpgpsigner->addRecipient($fingerprint);
} catch (Swift_SwiftException $e) {
info($e->getMessage());
$openpgpsigner = null;
$notifiable->update(['should_encrypt' => false]);
$notifiable->notify(new GpgKeyExpired);
}
}
return (new MailMessage)
->subject("AnonAddy Username Reminder")
->markdown('mail.username_reminder', [
'username' => $notifiable->user->username
])
->withSwiftMessage(function ($message) {
->withSwiftMessage(function ($message) use ($openpgpsigner) {
$message->getHeaders()
->addTextHeader('Feedback-ID', 'UR:anonaddy');
if ($openpgpsigner) {
$message->attachSigner($openpgpsigner);
}
});
}

310
composer.lock generated
View file

@ -273,16 +273,16 @@
},
{
"name": "brick/math",
"version": "0.9.2",
"version": "0.9.3",
"source": {
"type": "git",
"url": "https://github.com/brick/math.git",
"reference": "dff976c2f3487d42c1db75a3b180e2b9f0e72ce0"
"reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/brick/math/zipball/dff976c2f3487d42c1db75a3b180e2b9f0e72ce0",
"reference": "dff976c2f3487d42c1db75a3b180e2b9f0e72ce0",
"url": "https://api.github.com/repos/brick/math/zipball/ca57d18f028f84f777b2168cd1911b0dee2343ae",
"reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae",
"shasum": ""
},
"require": {
@ -292,7 +292,7 @@
"require-dev": {
"php-coveralls/php-coveralls": "^2.2",
"phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0",
"vimeo/psalm": "4.3.2"
"vimeo/psalm": "4.9.2"
},
"type": "library",
"autoload": {
@ -317,15 +317,19 @@
],
"support": {
"issues": "https://github.com/brick/math/issues",
"source": "https://github.com/brick/math/tree/0.9.2"
"source": "https://github.com/brick/math/tree/0.9.3"
},
"funding": [
{
"url": "https://github.com/BenMorel",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/brick/math",
"type": "tidelift"
}
],
"time": "2021-01-20T22:51:39+00:00"
"time": "2021-08-15T20:50:18+00:00"
},
{
"name": "clue/stream-filter",
@ -581,16 +585,16 @@
},
{
"name": "dflydev/dot-access-data",
"version": "v3.0.0",
"version": "v3.0.1",
"source": {
"type": "git",
"url": "https://github.com/dflydev/dflydev-dot-access-data.git",
"reference": "e04ff030d24a33edc2421bef305e32919dd78fc3"
"reference": "0992cc19268b259a39e86f296da5f0677841f42c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/dflydev/dflydev-dot-access-data/zipball/e04ff030d24a33edc2421bef305e32919dd78fc3",
"reference": "e04ff030d24a33edc2421bef305e32919dd78fc3",
"url": "https://api.github.com/repos/dflydev/dflydev-dot-access-data/zipball/0992cc19268b259a39e86f296da5f0677841f42c",
"reference": "0992cc19268b259a39e86f296da5f0677841f42c",
"shasum": ""
},
"require": {
@ -650,9 +654,9 @@
],
"support": {
"issues": "https://github.com/dflydev/dflydev-dot-access-data/issues",
"source": "https://github.com/dflydev/dflydev-dot-access-data/tree/v3.0.0"
"source": "https://github.com/dflydev/dflydev-dot-access-data/tree/v3.0.1"
},
"time": "2021-01-01T22:08:42+00:00"
"time": "2021-08-13T13:06:58+00:00"
},
{
"name": "doctrine/cache",
@ -2009,16 +2013,16 @@
},
{
"name": "laravel/framework",
"version": "v8.53.0",
"version": "v8.55.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
"reference": "4b2e3e7317da82dd9f5b88d477abd93444748b43"
"reference": "997e2aa23e9103137715018ae926c52f8a1703f2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/4b2e3e7317da82dd9f5b88d477abd93444748b43",
"reference": "4b2e3e7317da82dd9f5b88d477abd93444748b43",
"url": "https://api.github.com/repos/laravel/framework/zipball/997e2aa23e9103137715018ae926c52f8a1703f2",
"reference": "997e2aa23e9103137715018ae926c52f8a1703f2",
"shasum": ""
},
"require": {
@ -2091,7 +2095,7 @@
"illuminate/view": "self.version"
},
"require-dev": {
"aws/aws-sdk-php": "^3.186.4",
"aws/aws-sdk-php": "^3.189.0",
"doctrine/dbal": "^2.6|^3.0",
"filp/whoops": "^2.8",
"guzzlehttp/guzzle": "^6.5.5|^7.0.1",
@ -2104,7 +2108,7 @@
"symfony/cache": "^5.1.4"
},
"suggest": {
"aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage and SES mail driver (^3.186.4).",
"aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage and SES mail driver (^3.189.0).",
"brianium/paratest": "Required to run tests in parallel (^6.0).",
"doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.6|^3.0).",
"ext-ftp": "Required to use the Flysystem FTP driver.",
@ -2173,7 +2177,7 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"time": "2021-08-03T14:36:33+00:00"
"time": "2021-08-17T14:13:34+00:00"
},
{
"name": "laravel/passport",
@ -2515,21 +2519,21 @@
},
{
"name": "league/commonmark",
"version": "2.0.1",
"version": "2.0.2",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/commonmark.git",
"reference": "0d57f20aa03129ee7ef5f690e634884315d4238c"
"reference": "2df87709f44b0dd733df86aef0830dce9b1f0f13"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/commonmark/zipball/0d57f20aa03129ee7ef5f690e634884315d4238c",
"reference": "0d57f20aa03129ee7ef5f690e634884315d4238c",
"url": "https://api.github.com/repos/thephpleague/commonmark/zipball/2df87709f44b0dd733df86aef0830dce9b1f0f13",
"reference": "2df87709f44b0dd733df86aef0830dce9b1f0f13",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"league/config": "^1.1",
"league/config": "^1.1.1",
"php": "^7.4 || ^8.0",
"psr/event-dispatcher": "^1.0",
"symfony/polyfill-php80": "^1.15"
@ -2622,24 +2626,24 @@
"type": "tidelift"
}
],
"time": "2021-07-31T19:15:22+00:00"
"time": "2021-08-14T14:06:04+00:00"
},
{
"name": "league/config",
"version": "v1.1.0",
"version": "v1.1.1",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/config.git",
"reference": "20d42d88f12a76ff862e17af4f14a5a4bbfd0925"
"reference": "a9d39eeeb6cc49d10a6e6c36f22c4c1f4a767f3e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/config/zipball/20d42d88f12a76ff862e17af4f14a5a4bbfd0925",
"reference": "20d42d88f12a76ff862e17af4f14a5a4bbfd0925",
"url": "https://api.github.com/repos/thephpleague/config/zipball/a9d39eeeb6cc49d10a6e6c36f22c4c1f4a767f3e",
"reference": "a9d39eeeb6cc49d10a6e6c36f22c4c1f4a767f3e",
"shasum": ""
},
"require": {
"dflydev/dot-access-data": "^3.0",
"dflydev/dot-access-data": "^3.0.1",
"nette/schema": "^1.2",
"php": "^7.4 || ^8.0"
},
@ -2704,7 +2708,7 @@
"type": "github"
}
],
"time": "2021-06-19T15:52:37+00:00"
"time": "2021-08-14T12:15:32+00:00"
},
{
"name": "league/event",
@ -2762,16 +2766,16 @@
},
{
"name": "league/flysystem",
"version": "1.1.4",
"version": "1.1.5",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/flysystem.git",
"reference": "f3ad69181b8afed2c9edf7be5a2918144ff4ea32"
"reference": "18634df356bfd4119fe3d6156bdb990c414c14ea"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/f3ad69181b8afed2c9edf7be5a2918144ff4ea32",
"reference": "f3ad69181b8afed2c9edf7be5a2918144ff4ea32",
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/18634df356bfd4119fe3d6156bdb990c414c14ea",
"reference": "18634df356bfd4119fe3d6156bdb990c414c14ea",
"shasum": ""
},
"require": {
@ -2844,7 +2848,7 @@
],
"support": {
"issues": "https://github.com/thephpleague/flysystem/issues",
"source": "https://github.com/thephpleague/flysystem/tree/1.1.4"
"source": "https://github.com/thephpleague/flysystem/tree/1.1.5"
},
"funding": [
{
@ -2852,7 +2856,7 @@
"type": "other"
}
],
"time": "2021-06-23T21:56:05+00:00"
"time": "2021-08-17T13:49:42+00:00"
},
{
"name": "league/mime-type-detection",
@ -3166,16 +3170,16 @@
},
{
"name": "maatwebsite/excel",
"version": "3.1.32",
"version": "3.1.33",
"source": {
"type": "git",
"url": "https://github.com/Maatwebsite/Laravel-Excel.git",
"reference": "9dc29b63a77fb7f2f514ef754af3a1b57e83cadf"
"reference": "b2de5ba92c5c1ad9415f0eb7c72838fb3eaaa5b8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Maatwebsite/Laravel-Excel/zipball/9dc29b63a77fb7f2f514ef754af3a1b57e83cadf",
"reference": "9dc29b63a77fb7f2f514ef754af3a1b57e83cadf",
"url": "https://api.github.com/repos/Maatwebsite/Laravel-Excel/zipball/b2de5ba92c5c1ad9415f0eb7c72838fb3eaaa5b8",
"reference": "b2de5ba92c5c1ad9415f0eb7c72838fb3eaaa5b8",
"shasum": ""
},
"require": {
@ -3228,7 +3232,7 @@
],
"support": {
"issues": "https://github.com/Maatwebsite/Laravel-Excel/issues",
"source": "https://github.com/Maatwebsite/Laravel-Excel/tree/3.1.32"
"source": "https://github.com/Maatwebsite/Laravel-Excel/tree/3.1.33"
},
"funding": [
{
@ -3240,7 +3244,7 @@
"type": "github"
}
],
"time": "2021-07-08T10:11:21+00:00"
"time": "2021-08-12T15:52:25+00:00"
},
{
"name": "maennchen/zipstream-php",
@ -3713,16 +3717,16 @@
},
{
"name": "nesbot/carbon",
"version": "2.51.1",
"version": "2.52.0",
"source": {
"type": "git",
"url": "https://github.com/briannesbitt/Carbon.git",
"reference": "8619c299d1e0d4b344e1f98ca07a1ce2cfbf1922"
"reference": "369c0e2737c56a0f39c946dd261855255a6fccbe"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/8619c299d1e0d4b344e1f98ca07a1ce2cfbf1922",
"reference": "8619c299d1e0d4b344e1f98ca07a1ce2cfbf1922",
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/369c0e2737c56a0f39c946dd261855255a6fccbe",
"reference": "369c0e2737c56a0f39c946dd261855255a6fccbe",
"shasum": ""
},
"require": {
@ -3803,7 +3807,7 @@
"type": "tidelift"
}
],
"time": "2021-07-28T13:16:28+00:00"
"time": "2021-08-14T19:10:52+00:00"
},
{
"name": "nette/schema",
@ -3869,16 +3873,16 @@
},
{
"name": "nette/utils",
"version": "v3.2.2",
"version": "v3.2.3",
"source": {
"type": "git",
"url": "https://github.com/nette/utils.git",
"reference": "967cfc4f9a1acd5f1058d76715a424c53343c20c"
"reference": "5c36cc1ba9bb6abb8a9e425cf054e0c3fd5b9822"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nette/utils/zipball/967cfc4f9a1acd5f1058d76715a424c53343c20c",
"reference": "967cfc4f9a1acd5f1058d76715a424c53343c20c",
"url": "https://api.github.com/repos/nette/utils/zipball/5c36cc1ba9bb6abb8a9e425cf054e0c3fd5b9822",
"reference": "5c36cc1ba9bb6abb8a9e425cf054e0c3fd5b9822",
"shasum": ""
},
"require": {
@ -3948,9 +3952,9 @@
],
"support": {
"issues": "https://github.com/nette/utils/issues",
"source": "https://github.com/nette/utils/tree/v3.2.2"
"source": "https://github.com/nette/utils/tree/v3.2.3"
},
"time": "2021-03-03T22:53:25+00:00"
"time": "2021-08-16T21:05:00+00:00"
},
{
"name": "nikic/php-parser",
@ -4848,16 +4852,16 @@
},
{
"name": "phpseclib/phpseclib",
"version": "3.0.9",
"version": "3.0.10",
"source": {
"type": "git",
"url": "https://github.com/phpseclib/phpseclib.git",
"reference": "a127a5133804ff2f47ae629dd529b129da616ad7"
"reference": "62fcc5a94ac83b1506f52d7558d828617fac9187"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/a127a5133804ff2f47ae629dd529b129da616ad7",
"reference": "a127a5133804ff2f47ae629dd529b129da616ad7",
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/62fcc5a94ac83b1506f52d7558d828617fac9187",
"reference": "62fcc5a94ac83b1506f52d7558d828617fac9187",
"shasum": ""
},
"require": {
@ -4939,7 +4943,7 @@
],
"support": {
"issues": "https://github.com/phpseclib/phpseclib/issues",
"source": "https://github.com/phpseclib/phpseclib/tree/3.0.9"
"source": "https://github.com/phpseclib/phpseclib/tree/3.0.10"
},
"funding": [
{
@ -4955,7 +4959,7 @@
"type": "tidelift"
}
],
"time": "2021-06-14T06:54:45+00:00"
"time": "2021-08-16T04:24:45+00:00"
},
{
"name": "pragmarx/google2fa",
@ -5758,20 +5762,21 @@
},
{
"name": "ramsey/collection",
"version": "1.1.4",
"version": "1.2.1",
"source": {
"type": "git",
"url": "https://github.com/ramsey/collection.git",
"reference": "ab2237657ad99667a5143e32ba2683c8029563d4"
"reference": "eaca1dc1054ddd10cbd83c1461907bee6fb528fa"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ramsey/collection/zipball/ab2237657ad99667a5143e32ba2683c8029563d4",
"reference": "ab2237657ad99667a5143e32ba2683c8029563d4",
"url": "https://api.github.com/repos/ramsey/collection/zipball/eaca1dc1054ddd10cbd83c1461907bee6fb528fa",
"reference": "eaca1dc1054ddd10cbd83c1461907bee6fb528fa",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8"
"php": "^7.3 || ^8",
"symfony/polyfill-php81": "^1.23"
},
"require-dev": {
"captainhook/captainhook": "^5.3",
@ -5781,6 +5786,7 @@
"hamcrest/hamcrest-php": "^2",
"jangregor/phpstan-prophecy": "^0.8",
"mockery/mockery": "^1.3",
"phpspec/prophecy-phpunit": "^2.0",
"phpstan/extension-installer": "^1",
"phpstan/phpstan": "^0.12.32",
"phpstan/phpstan-mockery": "^0.12.5",
@ -5808,7 +5814,7 @@
"homepage": "https://benramsey.com"
}
],
"description": "A PHP 7.2+ library for representing and manipulating collections.",
"description": "A PHP library for representing and manipulating collections.",
"keywords": [
"array",
"collection",
@ -5819,7 +5825,7 @@
],
"support": {
"issues": "https://github.com/ramsey/collection/issues",
"source": "https://github.com/ramsey/collection/tree/1.1.4"
"source": "https://github.com/ramsey/collection/tree/1.2.1"
},
"funding": [
{
@ -5831,20 +5837,20 @@
"type": "tidelift"
}
],
"time": "2021-07-30T00:58:27+00:00"
"time": "2021-08-06T03:41:06+00:00"
},
{
"name": "ramsey/uuid",
"version": "4.1.1",
"version": "4.2.1",
"source": {
"type": "git",
"url": "https://github.com/ramsey/uuid.git",
"reference": "cd4032040a750077205918c86049aa0f43d22947"
"reference": "fe665a03df4f056aa65af552a96e1976df8c8dae"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ramsey/uuid/zipball/cd4032040a750077205918c86049aa0f43d22947",
"reference": "cd4032040a750077205918c86049aa0f43d22947",
"url": "https://api.github.com/repos/ramsey/uuid/zipball/fe665a03df4f056aa65af552a96e1976df8c8dae",
"reference": "fe665a03df4f056aa65af552a96e1976df8c8dae",
"shasum": ""
},
"require": {
@ -5858,26 +5864,26 @@
"rhumsaa/uuid": "self.version"
},
"require-dev": {
"codeception/aspect-mock": "^3",
"dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7.0",
"captainhook/captainhook": "^5.10",
"captainhook/plugin-composer": "^5.3",
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
"doctrine/annotations": "^1.8",
"goaop/framework": "^2",
"ergebnis/composer-normalize": "^2.15",
"mockery/mockery": "^1.3",
"moontoast/math": "^1.1",
"paragonie/random-lib": "^2",
"php-mock/php-mock": "^2.2",
"php-mock/php-mock-mockery": "^1.3",
"php-mock/php-mock-phpunit": "^2.5",
"php-parallel-lint/php-parallel-lint": "^1.1",
"phpbench/phpbench": "^0.17.1",
"phpbench/phpbench": "^1.0",
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "^0.12",
"phpstan/phpstan-mockery": "^0.12",
"phpstan/phpstan-phpunit": "^0.12",
"phpunit/phpunit": "^8.5",
"psy/psysh": "^0.10.0",
"slevomat/coding-standard": "^6.0",
"phpunit/phpunit": "^8.5 || ^9",
"slevomat/coding-standard": "^7.0",
"squizlabs/php_codesniffer": "^3.5",
"vimeo/psalm": "3.9.4"
"vimeo/psalm": "^4.9"
},
"suggest": {
"ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.",
@ -5890,7 +5896,10 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.x-dev"
"dev-main": "4.x-dev"
},
"captainhook": {
"force-install": true
}
},
"autoload": {
@ -5906,7 +5915,6 @@
"MIT"
],
"description": "A PHP library for generating and working with universally unique identifiers (UUIDs).",
"homepage": "https://github.com/ramsey/uuid",
"keywords": [
"guid",
"identifier",
@ -5914,16 +5922,19 @@
],
"support": {
"issues": "https://github.com/ramsey/uuid/issues",
"rss": "https://github.com/ramsey/uuid/releases.atom",
"source": "https://github.com/ramsey/uuid"
"source": "https://github.com/ramsey/uuid/tree/4.2.1"
},
"funding": [
{
"url": "https://github.com/ramsey",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/ramsey/uuid",
"type": "tidelift"
}
],
"time": "2020-08-18T17:17:46+00:00"
"time": "2021-08-11T01:06:55+00:00"
},
{
"name": "spomky-labs/base64url",
@ -7733,6 +7744,85 @@
],
"time": "2021-07-28T13:41:28+00:00"
},
{
"name": "symfony/polyfill-php81",
"version": "v1.23.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php81.git",
"reference": "e66119f3de95efc359483f810c4c3e6436279436"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/e66119f3de95efc359483f810c4c3e6436279436",
"reference": "e66119f3de95efc359483f810c4c3e6436279436",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.23-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Php81\\": ""
},
"files": [
"bootstrap.php"
],
"classmap": [
"Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php81/tree/v1.23.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2021-05-21T13:25:03+00:00"
},
{
"name": "symfony/process",
"version": "v5.3.4",
@ -9455,16 +9545,16 @@
},
{
"name": "doctrine/annotations",
"version": "1.13.1",
"version": "1.13.2",
"source": {
"type": "git",
"url": "https://github.com/doctrine/annotations.git",
"reference": "e6e7b7d5b45a2f2abc5460cc6396480b2b1d321f"
"reference": "5b668aef16090008790395c02c893b1ba13f7e08"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/annotations/zipball/e6e7b7d5b45a2f2abc5460cc6396480b2b1d321f",
"reference": "e6e7b7d5b45a2f2abc5460cc6396480b2b1d321f",
"url": "https://api.github.com/repos/doctrine/annotations/zipball/5b668aef16090008790395c02c893b1ba13f7e08",
"reference": "5b668aef16090008790395c02c893b1ba13f7e08",
"shasum": ""
},
"require": {
@ -9521,9 +9611,9 @@
],
"support": {
"issues": "https://github.com/doctrine/annotations/issues",
"source": "https://github.com/doctrine/annotations/tree/1.13.1"
"source": "https://github.com/doctrine/annotations/tree/1.13.2"
},
"time": "2021-05-16T18:07:53+00:00"
"time": "2021-08-05T19:00:23+00:00"
},
{
"name": "doctrine/instantiator",
@ -9661,16 +9751,16 @@
},
{
"name": "facade/ignition",
"version": "2.11.2",
"version": "2.11.4",
"source": {
"type": "git",
"url": "https://github.com/facade/ignition.git",
"reference": "7c4e7a7da184cd00c7ce6eacc590200bb9672de7"
"reference": "1b8d83c5dac7c5ee8429daf284ce3f19b1d17ea2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/facade/ignition/zipball/7c4e7a7da184cd00c7ce6eacc590200bb9672de7",
"reference": "7c4e7a7da184cd00c7ce6eacc590200bb9672de7",
"url": "https://api.github.com/repos/facade/ignition/zipball/1b8d83c5dac7c5ee8429daf284ce3f19b1d17ea2",
"reference": "1b8d83c5dac7c5ee8429daf284ce3f19b1d17ea2",
"shasum": ""
},
"require": {
@ -9733,7 +9823,7 @@
"issues": "https://github.com/facade/ignition/issues",
"source": "https://github.com/facade/ignition"
},
"time": "2021-07-20T14:01:22+00:00"
"time": "2021-08-17T11:45:33+00:00"
},
{
"name": "facade/ignition-contracts",
@ -9926,16 +10016,16 @@
},
{
"name": "friendsofphp/php-cs-fixer",
"version": "v3.0.1",
"version": "v3.0.2",
"source": {
"type": "git",
"url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git",
"reference": "64c554bcef3c3b4702fcf34c227a316b47139b66"
"reference": "990b979379502feb7f393d6c9aa36cc9b9765f24"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/64c554bcef3c3b4702fcf34c227a316b47139b66",
"reference": "64c554bcef3c3b4702fcf34c227a316b47139b66",
"url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/990b979379502feb7f393d6c9aa36cc9b9765f24",
"reference": "990b979379502feb7f393d6c9aa36cc9b9765f24",
"shasum": ""
},
"require": {
@ -10002,7 +10092,7 @@
"description": "A tool to automatically fix PHP code style",
"support": {
"issues": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues",
"source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v3.0.1"
"source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v3.0.2"
},
"funding": [
{
@ -10010,7 +10100,7 @@
"type": "github"
}
],
"time": "2021-08-02T17:57:52+00:00"
"time": "2021-08-04T19:28:19+00:00"
},
{
"name": "hamcrest/hamcrest-php",
@ -10195,16 +10285,16 @@
},
{
"name": "nunomaduro/collision",
"version": "v5.6.0",
"version": "v5.8.0",
"source": {
"type": "git",
"url": "https://github.com/nunomaduro/collision.git",
"reference": "0122ac6b03c75279ef78d1c0ad49725dfc52a8d2"
"reference": "0c3c393462eada1233513664e2d22bb9f69ca393"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nunomaduro/collision/zipball/0122ac6b03c75279ef78d1c0ad49725dfc52a8d2",
"reference": "0122ac6b03c75279ef78d1c0ad49725dfc52a8d2",
"url": "https://api.github.com/repos/nunomaduro/collision/zipball/0c3c393462eada1233513664e2d22bb9f69ca393",
"reference": "0c3c393462eada1233513664e2d22bb9f69ca393",
"shasum": ""
},
"require": {
@ -10216,7 +10306,7 @@
"require-dev": {
"brianium/paratest": "^6.1",
"fideloper/proxy": "^4.4.1",
"friendsofphp/php-cs-fixer": "^2.17.3",
"friendsofphp/php-cs-fixer": "^3.0",
"fruitcake/laravel-cors": "^2.0.3",
"laravel/framework": "^8.0 || ^9.0",
"nunomaduro/larastan": "^0.6.2",
@ -10279,7 +10369,7 @@
"type": "patreon"
}
],
"time": "2021-07-26T20:39:06+00:00"
"time": "2021-08-13T14:23:01+00:00"
},
{
"name": "phar-io/manifest",

View file

@ -4,10 +4,10 @@ current:
label: v
major: 0
minor: 8
patch: 0
prerelease: ''
patch: 1
prerelease: 2-g55373af
buildmetadata: ''
commit: 193b32
commit: 55373a
timestamp:
year: 2020
month: 10

1064
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,25 @@
@component('mail::message')
# New Failed Delivery
@if($aliasEmail)
An attempt to deliver a message for your alias **{{ $aliasEmail }}** has failed.
@else
An attempt to deliver a message for one of your aliases has failed.
@endif
@if($originalSender)
The message was sent by **{{ $originalSender }}** {{ $originalSubject ? 'with subject: ' . $originalSubject : '' }}
@elseif($originalSubject)
The subject of the message was: **{{ $originalSubject }}**
@endif
You can head over to the failed deliveries page to see the reason why this delivery was not successful.
@component('mail::button', ['url' => config('app.url').'/failed-deliveries'])
View Failed Deliveries
@endcomponent
@endcomponent