Browse Source

Added inline encryption and protected headers

Will Browning 2 years ago
parent
commit
328036b17e

+ 2 - 2
app/CustomMailDriver/CustomMailer.php

@@ -67,7 +67,7 @@ class CustomMailer extends Mailer
             $recipient = Recipient::find($data['recipientId']);
 
             try {
-                $encrypter = new OpenPGPEncrypter(config('anonaddy.signing_key_fingerprint'), $data['fingerprint'], "~/.gnupg");
+                $encrypter = new OpenPGPEncrypter(config('anonaddy.signing_key_fingerprint'), $data['fingerprint'], "~/.gnupg", $recipient->protected_headers);
             } catch (RuntimeException $e) {
                 info($e->getMessage());
                 $encrypter = null;
@@ -78,7 +78,7 @@ class CustomMailer extends Mailer
             }
 
             if ($encrypter) {
-                $symfonyMessage = $encrypter->encrypt($symfonyMessage);
+                $symfonyMessage = $recipient->inline_encryption ? $encrypter->encryptInline($symfonyMessage) : $encrypter->encrypt($symfonyMessage);
             }
         }
 

+ 84 - 3
app/CustomMailDriver/Mime/Crypto/OpenPGPEncrypter.php

@@ -3,12 +3,14 @@
 namespace App\CustomMailDriver\Mime\Crypto;
 
 use App\CustomMailDriver\Mime\Part\EncryptedPart;
+use Illuminate\Support\Str;
 use Symfony\Component\Mailer\Exception\RuntimeException;
 use Symfony\Component\Mime\Email;
 
 class OpenPGPEncrypter
 {
     protected $gnupg = null;
+    protected $usesProtectedHeaders;
 
     /**
      * The signing hash algorithm. 'MD5', SHA1, or SHA256. SHA256 (the default) is highly recommended
@@ -52,12 +54,13 @@ class OpenPGPEncrypter
     protected $gnupgHome = null;
 
 
-    public function __construct($signingKey = null, $recipientKey = null, $gnupgHome = null)
+    public function __construct($signingKey = null, $recipientKey = null, $gnupgHome = null, $usesProtectedHeaders = false)
     {
         $this->initGNUPG();
         $this->signingKey    = $signingKey;
         $this->recipientKey = $recipientKey;
         $this->gnupgHome     = $gnupgHome;
+        $this->usesProtectedHeaders = $usesProtectedHeaders;
     }
 
     /**
@@ -132,8 +135,22 @@ class OpenPGPEncrypter
 
         $lines = preg_split('/(\r\n|\r|\n)/', rtrim($originalMessage));
 
-        for ($i=0; $i<count($lines); $i++) {
-            $lines[$i] = rtrim($lines[$i])."\r\n";
+        // Check if using protected headers or not
+        if ($this->usesProtectedHeaders) {
+            $protectedHeadersSet = false;
+            for ($i=0; $i<count($lines); $i++) {
+                if (! $protectedHeadersSet && Str::startsWith(strtolower($lines[$i]), 'content-type:')) {
+                    $lines[$i] = rtrim($lines[$i])."; protected-headers=\"v1\"\r\n";
+                    $headers->setHeaderBody('Text', 'Subject', '...');
+                    $protectedHeadersSet = true;
+                } else {
+                    $lines[$i] = rtrim($lines[$i])."\r\n";
+                }
+            }
+        } else {
+            for ($i=0; $i<count($lines); $i++) {
+                $lines[$i] = rtrim($lines[$i])."\r\n";
+            }
         }
 
         // Remove excess trailing newlines (RFC3156 section 5.4)
@@ -182,6 +199,39 @@ class OpenPGPEncrypter
         return $message->setBody(new EncryptedPart($body));
     }
 
+    /**
+     * @param Email $email
+     *
+     * @return $this
+     *
+     * @throws RuntimeException
+     */
+    public function encryptInline(Email $message): Email
+    {
+        if (!$this->signingKey) {
+            foreach ($message->getFrom() as $key => $value) {
+                $this->addSignature($this->getKey($key, 'sign'));
+            }
+        }
+
+        if (!$this->signingKey) {
+            throw new RuntimeException('Signing has been enabled, but no signature has been added. Use autoAddSignature() or addSignature()');
+        }
+
+        if (!$this->recipientKey) {
+            throw new RuntimeException('Encryption has been enabled, but no recipients have been added. Use autoAddRecipients() or addRecipient()');
+        }
+
+        $text = $this->pgpEncryptAndSignString($message->getTextBody(), $this->recipientKey, $this->signingKey);
+
+        $headers = $message->getPreparedHeaders();
+        $headers->setHeaderBody('Parameterized', 'Content-Type', 'text/plain');
+        $headers->setHeaderParameter('Content-Type', 'charset', 'utf-8');
+        $message->setHeaders($headers);
+
+        return $message->setBody(new EncryptedPart($text));
+    }
+
     /**
      * @throws RuntimeException
      */
@@ -261,6 +311,37 @@ class OpenPGPEncrypter
         throw new RuntimeException('Unable to encrypt message');
     }
 
+    /**
+     * @param $plaintext
+     * @param $keyFingerprints
+     *
+     * @return string
+     *
+     * @throws RuntimeException
+     */
+    protected function pgpEncryptAndSignString($plaintext, $keyFingerprint, $signingKeyFingerprint)
+    {
+        if (isset($this->keyPassphrases[$signingKeyFingerprint]) && !$this->keyPassphrases[$signingKeyFingerprint]) {
+            $passPhrase = $this->keyPassphrases[$signingKeyFingerprint];
+        } else {
+            $passPhrase = null;
+        }
+
+        $this->gnupg->clearsignkeys();
+        $this->gnupg->addsignkey($signingKeyFingerprint, $passPhrase);
+        $this->gnupg->clearencryptkeys();
+        $this->gnupg->addencryptkey($keyFingerprint);
+        $this->gnupg->setarmor(1);
+
+        $encrypted = $this->gnupg->encryptsign($plaintext);
+
+        if ($encrypted) {
+            return $encrypted;
+        }
+
+        throw new RuntimeException('Unable to encrypt and sign message');
+    }
+
     /**
      * @param $identifier
      * @param $purpose

+ 38 - 0
app/Http/Controllers/Api/InlineEncryptedRecipientController.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace App\Http\Controllers\Api;
+
+use App\Http\Controllers\Controller;
+use App\Http\Resources\RecipientResource;
+use Illuminate\Http\Request;
+
+class InlineEncryptedRecipientController extends Controller
+{
+    public function store(Request $request)
+    {
+        $request->validate(['id' => 'required|string']);
+
+        $recipient = user()->recipients()->findOrFail($request->id);
+
+        if (! $recipient->fingerprint) {
+            return response('You need to add a public key to this recipient before you can enable inline encryption', 422);
+        }
+
+        if ($recipient->protected_headers) {
+            return response('You need to disable protected headers (hide subject) before you can enable inline encryption', 422);
+        }
+
+        $recipient->update(['inline_encryption' => true]);
+
+        return new RecipientResource($recipient->load('aliases'));
+    }
+
+    public function destroy($id)
+    {
+        $recipient = user()->recipients()->findOrFail($id);
+
+        $recipient->update(['inline_encryption' => false]);
+
+        return response('', 204);
+    }
+}

+ 38 - 0
app/Http/Controllers/Api/ProtectedHeadersRecipientController.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace App\Http\Controllers\Api;
+
+use App\Http\Controllers\Controller;
+use App\Http\Resources\RecipientResource;
+use Illuminate\Http\Request;
+
+class ProtectedHeadersRecipientController extends Controller
+{
+    public function store(Request $request)
+    {
+        $request->validate(['id' => 'required|string']);
+
+        $recipient = user()->recipients()->findOrFail($request->id);
+
+        if (! $recipient->fingerprint) {
+            return response('You need to add a public key to this recipient before you can enable protected headers (hide subject)', 422);
+        }
+
+        if ($recipient->inline_encryption) {
+            return response('You need to disable inline encryption before you can enable protected headers (hide subject)', 422);
+        }
+
+        $recipient->update(['protected_headers' => true]);
+
+        return new RecipientResource($recipient->load('aliases'));
+    }
+
+    public function destroy($id)
+    {
+        $recipient = user()->recipients()->findOrFail($id);
+
+        $recipient->update(['protected_headers' => false]);
+
+        return response('', 204);
+    }
+}

+ 2 - 0
app/Http/Resources/RecipientResource.php

@@ -14,6 +14,8 @@ class RecipientResource extends JsonResource
             'email' => $this->email,
             'can_reply_send' => $this->can_reply_send,
             'should_encrypt' => $this->should_encrypt,
+            'inline_encryption' => $this->inline_encryption,
+            'protected_headers' => $this->protected_headers,
             'fingerprint' => $this->fingerprint,
             'email_verified_at' => $this->email_verified_at?->toDateTimeString(),
             'aliases' => AliasResource::collection($this->whenLoaded('aliases')),

+ 5 - 1
app/Models/Recipient.php

@@ -32,6 +32,8 @@ class Recipient extends Model
         'user_id',
         'can_reply_send',
         'should_encrypt',
+        'inline_encryption',
+        'protected_headers',
         'fingerprint',
         'email_verified_at'
     ];
@@ -46,7 +48,9 @@ class Recipient extends Model
         'id' => 'string',
         'user_id' => 'string',
         'can_reply_send' => 'boolean',
-        'should_encrypt' => 'boolean'
+        'should_encrypt' => 'boolean',
+        'inline_encryption' => 'boolean',
+        'protected_headers' => 'boolean'
     ];
 
     public static function boot()

+ 85 - 86
composer.lock

@@ -217,26 +217,26 @@
         },
         {
             "name": "brick/math",
-            "version": "0.9.3",
+            "version": "0.10.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/brick/math.git",
-                "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae"
+                "reference": "de846578401f4e58f911b3afeb62ced56365ed87"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/brick/math/zipball/ca57d18f028f84f777b2168cd1911b0dee2343ae",
-                "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae",
+                "url": "https://api.github.com/repos/brick/math/zipball/de846578401f4e58f911b3afeb62ced56365ed87",
+                "reference": "de846578401f4e58f911b3afeb62ced56365ed87",
                 "shasum": ""
             },
             "require": {
                 "ext-json": "*",
-                "php": "^7.1 || ^8.0"
+                "php": "^7.4 || ^8.0"
             },
             "require-dev": {
                 "php-coveralls/php-coveralls": "^2.2",
-                "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0",
-                "vimeo/psalm": "4.9.2"
+                "phpunit/phpunit": "^9.0",
+                "vimeo/psalm": "4.25.0"
             },
             "type": "library",
             "autoload": {
@@ -261,19 +261,15 @@
             ],
             "support": {
                 "issues": "https://github.com/brick/math/issues",
-                "source": "https://github.com/brick/math/tree/0.9.3"
+                "source": "https://github.com/brick/math/tree/0.10.1"
             },
             "funding": [
                 {
                     "url": "https://github.com/BenMorel",
                     "type": "github"
-                },
-                {
-                    "url": "https://tidelift.com/funding/github/packagist/brick/math",
-                    "type": "tidelift"
                 }
             ],
-            "time": "2021-08-15T20:50:18+00:00"
+            "time": "2022-08-01T22:54:31+00:00"
         },
         {
             "name": "dasprid/enum",
@@ -492,16 +488,16 @@
         },
         {
             "name": "doctrine/dbal",
-            "version": "3.3.7",
+            "version": "3.4.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/doctrine/dbal.git",
-                "reference": "9f79d4650430b582f4598fe0954ef4d52fbc0a8a"
+                "reference": "118a360e9437e88d49024f36283c8bcbd76105f5"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/doctrine/dbal/zipball/9f79d4650430b582f4598fe0954ef4d52fbc0a8a",
-                "reference": "9f79d4650430b582f4598fe0954ef4d52fbc0a8a",
+                "url": "https://api.github.com/repos/doctrine/dbal/zipball/118a360e9437e88d49024f36283c8bcbd76105f5",
+                "reference": "118a360e9437e88d49024f36283c8bcbd76105f5",
                 "shasum": ""
             },
             "require": {
@@ -509,21 +505,21 @@
                 "doctrine/cache": "^1.11|^2.0",
                 "doctrine/deprecations": "^0.5.3|^1",
                 "doctrine/event-manager": "^1.0",
-                "php": "^7.3 || ^8.0",
+                "php": "^7.4 || ^8.0",
                 "psr/cache": "^1|^2|^3",
                 "psr/log": "^1|^2|^3"
             },
             "require-dev": {
                 "doctrine/coding-standard": "9.0.0",
                 "jetbrains/phpstorm-stubs": "2022.1",
-                "phpstan/phpstan": "1.7.13",
-                "phpstan/phpstan-strict-rules": "^1.2",
-                "phpunit/phpunit": "9.5.20",
-                "psalm/plugin-phpunit": "0.16.1",
-                "squizlabs/php_codesniffer": "3.7.0",
-                "symfony/cache": "^5.2|^6.0",
-                "symfony/console": "^2.7|^3.0|^4.0|^5.0|^6.0",
-                "vimeo/psalm": "4.23.0"
+                "phpstan/phpstan": "1.8.2",
+                "phpstan/phpstan-strict-rules": "^1.3",
+                "phpunit/phpunit": "9.5.21",
+                "psalm/plugin-phpunit": "0.17.0",
+                "squizlabs/php_codesniffer": "3.7.1",
+                "symfony/cache": "^5.4|^6.0",
+                "symfony/console": "^4.4|^5.4|^6.0",
+                "vimeo/psalm": "4.24.0"
             },
             "suggest": {
                 "symfony/console": "For helpful console commands such as SQL execution and import of files."
@@ -583,7 +579,7 @@
             ],
             "support": {
                 "issues": "https://github.com/doctrine/dbal/issues",
-                "source": "https://github.com/doctrine/dbal/tree/3.3.7"
+                "source": "https://github.com/doctrine/dbal/tree/3.4.0"
             },
             "funding": [
                 {
@@ -599,7 +595,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2022-06-13T21:43:03+00:00"
+            "time": "2022-08-06T20:35:57+00:00"
         },
         {
             "name": "doctrine/deprecations",
@@ -1699,16 +1695,16 @@
         },
         {
             "name": "laravel/framework",
-            "version": "v9.22.1",
+            "version": "v9.23.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/laravel/framework.git",
-                "reference": "b3b3dd43b9899f23df6d1d3e5390bd4662947a46"
+                "reference": "c4eea9060d847b5c93957b203caa8f57544a76ab"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/laravel/framework/zipball/b3b3dd43b9899f23df6d1d3e5390bd4662947a46",
-                "reference": "b3b3dd43b9899f23df6d1d3e5390bd4662947a46",
+                "url": "https://api.github.com/repos/laravel/framework/zipball/c4eea9060d847b5c93957b203caa8f57544a76ab",
+                "reference": "c4eea9060d847b5c93957b203caa8f57544a76ab",
                 "shasum": ""
             },
             "require": {
@@ -1729,7 +1725,7 @@
                 "psr/log": "^1.0|^2.0|^3.0",
                 "psr/simple-cache": "^1.0|^2.0|^3.0",
                 "ramsey/uuid": "^4.2.2",
-                "symfony/console": "^6.0",
+                "symfony/console": "^6.0.3",
                 "symfony/error-handler": "^6.0",
                 "symfony/finder": "^6.0",
                 "symfony/http-foundation": "^6.0",
@@ -1875,20 +1871,20 @@
                 "issues": "https://github.com/laravel/framework/issues",
                 "source": "https://github.com/laravel/framework"
             },
-            "time": "2022-07-26T16:16:33+00:00"
+            "time": "2022-08-02T14:24:44+00:00"
         },
         {
             "name": "laravel/sanctum",
-            "version": "v3.0.0",
+            "version": "v3.0.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/laravel/sanctum.git",
-                "reference": "fae52063ea7fb1d916baba787918c40fd3d8ab62"
+                "reference": "b71e80a3a8e8029e2ec8c1aa814b999609ce16dc"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/laravel/sanctum/zipball/fae52063ea7fb1d916baba787918c40fd3d8ab62",
-                "reference": "fae52063ea7fb1d916baba787918c40fd3d8ab62",
+                "url": "https://api.github.com/repos/laravel/sanctum/zipball/b71e80a3a8e8029e2ec8c1aa814b999609ce16dc",
+                "reference": "b71e80a3a8e8029e2ec8c1aa814b999609ce16dc",
                 "shasum": ""
             },
             "require": {
@@ -1940,7 +1936,7 @@
                 "issues": "https://github.com/laravel/sanctum/issues",
                 "source": "https://github.com/laravel/sanctum"
             },
-            "time": "2022-07-25T13:44:55+00:00"
+            "time": "2022-07-29T21:33:30+00:00"
         },
         {
             "name": "laravel/serializable-closure",
@@ -2899,16 +2895,16 @@
         },
         {
             "name": "myclabs/php-enum",
-            "version": "1.8.3",
+            "version": "1.8.4",
             "source": {
                 "type": "git",
                 "url": "https://github.com/myclabs/php-enum.git",
-                "reference": "b942d263c641ddb5190929ff840c68f78713e937"
+                "reference": "a867478eae49c9f59ece437ae7f9506bfaa27483"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/myclabs/php-enum/zipball/b942d263c641ddb5190929ff840c68f78713e937",
-                "reference": "b942d263c641ddb5190929ff840c68f78713e937",
+                "url": "https://api.github.com/repos/myclabs/php-enum/zipball/a867478eae49c9f59ece437ae7f9506bfaa27483",
+                "reference": "a867478eae49c9f59ece437ae7f9506bfaa27483",
                 "shasum": ""
             },
             "require": {
@@ -2924,7 +2920,10 @@
             "autoload": {
                 "psr-4": {
                     "MyCLabs\\Enum\\": "src/"
-                }
+                },
+                "classmap": [
+                    "stubs/Stringable.php"
+                ]
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
@@ -2943,7 +2942,7 @@
             ],
             "support": {
                 "issues": "https://github.com/myclabs/php-enum/issues",
-                "source": "https://github.com/myclabs/php-enum/tree/1.8.3"
+                "source": "https://github.com/myclabs/php-enum/tree/1.8.4"
             },
             "funding": [
                 {
@@ -2955,20 +2954,20 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-07-05T08:18:36+00:00"
+            "time": "2022-08-04T09:53:51+00:00"
         },
         {
             "name": "nesbot/carbon",
-            "version": "2.60.0",
+            "version": "2.61.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/briannesbitt/Carbon.git",
-                "reference": "00a259ae02b003c563158b54fb6743252b638ea6"
+                "reference": "bdf4f4fe3a3eac4de84dbec0738082a862c68ba6"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/00a259ae02b003c563158b54fb6743252b638ea6",
-                "reference": "00a259ae02b003c563158b54fb6743252b638ea6",
+                "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/bdf4f4fe3a3eac4de84dbec0738082a862c68ba6",
+                "reference": "bdf4f4fe3a3eac4de84dbec0738082a862c68ba6",
                 "shasum": ""
             },
             "require": {
@@ -3057,7 +3056,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2022-07-27T15:57:48+00:00"
+            "time": "2022-08-06T12:41:24+00:00"
         },
         {
             "name": "nette/schema",
@@ -4494,20 +4493,20 @@
         },
         {
             "name": "ramsey/uuid",
-            "version": "4.3.1",
+            "version": "4.4.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/ramsey/uuid.git",
-                "reference": "8505afd4fea63b81a85d3b7b53ac3cb8dc347c28"
+                "reference": "373f7bacfcf3de038778ff27dcce5672ddbf4c8a"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/ramsey/uuid/zipball/8505afd4fea63b81a85d3b7b53ac3cb8dc347c28",
-                "reference": "8505afd4fea63b81a85d3b7b53ac3cb8dc347c28",
+                "url": "https://api.github.com/repos/ramsey/uuid/zipball/373f7bacfcf3de038778ff27dcce5672ddbf4c8a",
+                "reference": "373f7bacfcf3de038778ff27dcce5672ddbf4c8a",
                 "shasum": ""
             },
             "require": {
-                "brick/math": "^0.8 || ^0.9",
+                "brick/math": "^0.8 || ^0.9 || ^0.10",
                 "ext-ctype": "*",
                 "ext-json": "*",
                 "php": "^8.0",
@@ -4523,7 +4522,6 @@
                 "doctrine/annotations": "^1.8",
                 "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",
@@ -4572,7 +4570,7 @@
             ],
             "support": {
                 "issues": "https://github.com/ramsey/uuid/issues",
-                "source": "https://github.com/ramsey/uuid/tree/4.3.1"
+                "source": "https://github.com/ramsey/uuid/tree/4.4.0"
             },
             "funding": [
                 {
@@ -4584,7 +4582,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2022-03-27T21:42:02+00:00"
+            "time": "2022-08-05T17:58:37+00:00"
         },
         {
             "name": "spomky-labs/cbor-php",
@@ -6926,16 +6924,16 @@
         },
         {
             "name": "thecodingmachine/safe",
-            "version": "v2.2.2",
+            "version": "v2.2.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/thecodingmachine/safe.git",
-                "reference": "440284f9592c9df402832452a6871a8b3c48d97e"
+                "reference": "e454a3142d2197694d1fda291a4462ccd3f66e12"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/440284f9592c9df402832452a6871a8b3c48d97e",
-                "reference": "440284f9592c9df402832452a6871a8b3c48d97e",
+                "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/e454a3142d2197694d1fda291a4462ccd3f66e12",
+                "reference": "e454a3142d2197694d1fda291a4462ccd3f66e12",
                 "shasum": ""
             },
             "require": {
@@ -7058,9 +7056,9 @@
             "description": "PHP core functions that throw exceptions instead of returning FALSE on error",
             "support": {
                 "issues": "https://github.com/thecodingmachine/safe/issues",
-                "source": "https://github.com/thecodingmachine/safe/tree/v2.2.2"
+                "source": "https://github.com/thecodingmachine/safe/tree/v2.2.3"
             },
-            "time": "2022-07-20T17:46:34+00:00"
+            "time": "2022-08-04T14:05:49+00:00"
         },
         {
             "name": "tijsverkoyen/css-to-inline-styles",
@@ -7271,16 +7269,16 @@
         },
         {
             "name": "web-auth/cose-lib",
-            "version": "v4.0.4",
+            "version": "v4.0.5",
             "source": {
                 "type": "git",
                 "url": "https://github.com/web-auth/cose-lib.git",
-                "reference": "72dfdef87ff01896f415cf2f17422dcb6f0d94dd"
+                "reference": "2fe6c0d35136d75bc538372a317ca5df5a75ce73"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/web-auth/cose-lib/zipball/72dfdef87ff01896f415cf2f17422dcb6f0d94dd",
-                "reference": "72dfdef87ff01896f415cf2f17422dcb6f0d94dd",
+                "url": "https://api.github.com/repos/web-auth/cose-lib/zipball/2fe6c0d35136d75bc538372a317ca5df5a75ce73",
+                "reference": "2fe6c0d35136d75bc538372a317ca5df5a75ce73",
                 "shasum": ""
             },
             "require": {
@@ -7296,6 +7294,7 @@
             "require-dev": {
                 "ekino/phpstan-banned-code": "^1.0",
                 "infection/infection": "^0.26.12",
+                "php-parallel-lint/php-parallel-lint": "^1.3",
                 "phpstan/phpstan": "^1.7",
                 "phpstan/phpstan-beberlei-assert": "^1.0",
                 "phpstan/phpstan-deprecation-rules": "^1.0",
@@ -7339,7 +7338,7 @@
             ],
             "support": {
                 "issues": "https://github.com/web-auth/cose-lib/issues",
-                "source": "https://github.com/web-auth/cose-lib/tree/v4.0.4"
+                "source": "https://github.com/web-auth/cose-lib/tree/v4.0.5"
             },
             "funding": [
                 {
@@ -7351,7 +7350,7 @@
                     "type": "patreon"
                 }
             ],
-            "time": "2022-07-16T13:53:10+00:00"
+            "time": "2022-08-04T16:48:04+00:00"
         },
         {
             "name": "web-auth/metadata-service",
@@ -7506,20 +7505,20 @@
         },
         {
             "name": "web-token/jwt-core",
-            "version": "v3.0.6",
+            "version": "v3.1.x-dev",
             "source": {
                 "type": "git",
                 "url": "https://github.com/web-token/jwt-core.git",
-                "reference": "99205a4eb4c383fea2afa526b79eeb0967ad1491"
+                "reference": "4d956e786a4e35d54c74787ebff840a0311c5e83"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/web-token/jwt-core/zipball/99205a4eb4c383fea2afa526b79eeb0967ad1491",
-                "reference": "99205a4eb4c383fea2afa526b79eeb0967ad1491",
+                "url": "https://api.github.com/repos/web-token/jwt-core/zipball/4d956e786a4e35d54c74787ebff840a0311c5e83",
+                "reference": "4d956e786a4e35d54c74787ebff840a0311c5e83",
                 "shasum": ""
             },
             "require": {
-                "brick/math": "^0.9",
+                "brick/math": "^0.9|^0.10",
                 "ext-json": "*",
                 "ext-mbstring": "*",
                 "fgrosse/phpasn1": "^2.0",
@@ -7570,7 +7569,7 @@
                 "symfony"
             ],
             "support": {
-                "source": "https://github.com/web-token/jwt-core/tree/v3.0.6"
+                "source": "https://github.com/web-token/jwt-core/tree/v3.1"
             },
             "funding": [
                 {
@@ -7578,11 +7577,11 @@
                     "type": "patreon"
                 }
             ],
-            "time": "2022-05-30T12:05:48+00:00"
+            "time": "2022-08-04T21:04:09+00:00"
         },
         {
             "name": "web-token/jwt-signature",
-            "version": "v3.0.6",
+            "version": "v3.0.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/web-token/jwt-signature.git",
@@ -7647,7 +7646,7 @@
                 "symfony"
             ],
             "support": {
-                "source": "https://github.com/web-token/jwt-signature/tree/v3.0.6"
+                "source": "https://github.com/web-token/jwt-signature/tree/v3.0.7"
             },
             "funding": [
                 {
@@ -10519,16 +10518,16 @@
         },
         {
             "name": "spatie/flare-client-php",
-            "version": "1.2.0",
+            "version": "1.3.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/spatie/flare-client-php.git",
-                "reference": "86a380f5b1ce839af04a08f1c8f2697184cdf23f"
+                "reference": "b1b974348750925b717fa8c8b97a0db0d1aa40ca"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/spatie/flare-client-php/zipball/86a380f5b1ce839af04a08f1c8f2697184cdf23f",
-                "reference": "86a380f5b1ce839af04a08f1c8f2697184cdf23f",
+                "url": "https://api.github.com/repos/spatie/flare-client-php/zipball/b1b974348750925b717fa8c8b97a0db0d1aa40ca",
+                "reference": "b1b974348750925b717fa8c8b97a0db0d1aa40ca",
                 "shasum": ""
             },
             "require": {
@@ -10576,7 +10575,7 @@
             ],
             "support": {
                 "issues": "https://github.com/spatie/flare-client-php/issues",
-                "source": "https://github.com/spatie/flare-client-php/tree/1.2.0"
+                "source": "https://github.com/spatie/flare-client-php/tree/1.3.0"
             },
             "funding": [
                 {
@@ -10584,7 +10583,7 @@
                     "type": "github"
                 }
             ],
-            "time": "2022-05-16T12:13:39+00:00"
+            "time": "2022-08-08T10:10:20+00:00"
         },
         {
             "name": "spatie/ignition",

+ 33 - 0
database/migrations/2022_08_05_085825_add_protected_headers_and_inline_encryption_to_recipients_table.php

@@ -0,0 +1,33 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class () extends Migration {
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('recipients', function (Blueprint $table) {
+            $table->boolean('protected_headers')->after('should_encrypt')->default(false);
+            $table->boolean('inline_encryption')->after('should_encrypt')->default(false);
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('recipients', function (Blueprint $table) {
+            $table->dropColumn('protected_headers');
+            $table->dropColumn('inline_encryption');
+        });
+    }
+};

+ 100 - 100
package-lock.json

@@ -102,9 +102,9 @@
             }
         },
         "node_modules/@babel/generator": {
-            "version": "7.18.10",
-            "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.10.tgz",
-            "integrity": "sha512-0+sW7e3HjQbiHbj1NeU/vN8ornohYlacAfZIaXhdoGweQqgcNy69COVciYYqEXJ/v+9OBA7Frxm4CVAuNqKeNA==",
+            "version": "7.18.12",
+            "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.12.tgz",
+            "integrity": "sha512-dfQ8ebCN98SvyL7IxNMCUtZQSq5R7kxgN+r8qYTGDmmSion1hX2C0zq2yo1bsCDhXixokv1SAWTZUMYbO/V5zg==",
             "dependencies": {
                 "@babel/types": "^7.18.10",
                 "@jridgewell/gen-mapping": "^0.3.2",
@@ -425,13 +425,13 @@
             }
         },
         "node_modules/@babel/helper-wrap-function": {
-            "version": "7.18.10",
-            "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.18.10.tgz",
-            "integrity": "sha512-95NLBP59VWdfK2lyLKe6eTMq9xg+yWKzxzxbJ1wcYNi1Auz200+83fMDADjRxBvc2QQor5zja2yTQzXGhk2GtQ==",
+            "version": "7.18.11",
+            "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.18.11.tgz",
+            "integrity": "sha512-oBUlbv+rjZLh2Ks9SKi4aL7eKaAXBWleHzU89mP0G6BMUlRxSckk9tSIkgDGydhgFxHuGSlBQZfnaD47oBEB7w==",
             "dependencies": {
                 "@babel/helper-function-name": "^7.18.9",
                 "@babel/template": "^7.18.10",
-                "@babel/traverse": "^7.18.10",
+                "@babel/traverse": "^7.18.11",
                 "@babel/types": "^7.18.10"
             },
             "engines": {
@@ -521,9 +521,9 @@
             }
         },
         "node_modules/@babel/parser": {
-            "version": "7.18.10",
-            "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.10.tgz",
-            "integrity": "sha512-TYk3OA0HKL6qNryUayb5UUEhM/rkOQozIBEA5ITXh5DWrSp0TlUQXMyZmnWxG/DizSWBeeQ0Zbc5z8UGaaqoeg==",
+            "version": "7.18.11",
+            "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.11.tgz",
+            "integrity": "sha512-9JKn5vN+hDt0Hdqn1PiJ2guflwP+B6Ga8qbDuoF0PzzVhrzsKIJo8yGqVk6CmMHiMei9w1C1Bp9IMJSIK+HPIQ==",
             "bin": {
                 "parser": "bin/babel-parser.js"
             },
@@ -1611,9 +1611,9 @@
             }
         },
         "node_modules/@babel/traverse": {
-            "version": "7.18.10",
-            "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.10.tgz",
-            "integrity": "sha512-J7ycxg0/K9XCtLyHf0cz2DqDihonJeIo+z+HEdRe9YuT8TY4A66i+Ab2/xZCEW7Ro60bPCBBfqqboHSamoV3+g==",
+            "version": "7.18.11",
+            "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.11.tgz",
+            "integrity": "sha512-TG9PiM2R/cWCAy6BPJKeHzNbu4lPzOSZpeMfeNErskGpTJx6trEvFaVCbDvpcxwy49BKWmEPwiW8mrysNiDvIQ==",
             "dependencies": {
                 "@babel/code-frame": "^7.18.6",
                 "@babel/generator": "^7.18.10",
@@ -1621,7 +1621,7 @@
                 "@babel/helper-function-name": "^7.18.9",
                 "@babel/helper-hoist-variables": "^7.18.6",
                 "@babel/helper-split-export-declaration": "^7.18.6",
-                "@babel/parser": "^7.18.10",
+                "@babel/parser": "^7.18.11",
                 "@babel/types": "^7.18.10",
                 "debug": "^4.1.0",
                 "globals": "^11.1.0"
@@ -1808,9 +1808,9 @@
             }
         },
         "node_modules/@types/babel__traverse": {
-            "version": "7.17.1",
-            "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.17.1.tgz",
-            "integrity": "sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA==",
+            "version": "7.18.0",
+            "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.0.tgz",
+            "integrity": "sha512-v4Vwdko+pgymgS+A2UIaJru93zQd85vIGWObM5ekZNdXCKtDYqATlEYnWgfo86Q6I1Lh0oXnksDnMU1cwmlPDw==",
             "dependencies": {
                 "@babel/types": "^7.3.0"
             }
@@ -1966,9 +1966,9 @@
             "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ=="
         },
         "node_modules/@types/mime": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.0.tgz",
-            "integrity": "sha512-fccbsHKqFDXClBZTDLA43zl0+TbxyIwyzIzwwhvoJvhNjOErCdeX2xJbURimv2EbSVUGav001PaCJg4mZxMl4w=="
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz",
+            "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA=="
         },
         "node_modules/@types/minimatch": {
             "version": "3.0.5",
@@ -1976,9 +1976,9 @@
             "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ=="
         },
         "node_modules/@types/node": {
-            "version": "18.6.3",
-            "resolved": "https://registry.npmjs.org/@types/node/-/node-18.6.3.tgz",
-            "integrity": "sha512-6qKpDtoaYLM+5+AFChLhHermMQxc3TOEFIDzrZLPRGHPrLEwqFkkT5Kx3ju05g6X7uDPazz3jHbKPX0KzCjntg=="
+            "version": "18.6.4",
+            "resolved": "https://registry.npmjs.org/@types/node/-/node-18.6.4.tgz",
+            "integrity": "sha512-I4BD3L+6AWiUobfxZ49DlU43gtI+FTHSv9pE2Zekg6KjMpre4ByusaljW3vYSLJrvQ1ck1hUaeVu8HVlY3vzHg=="
         },
         "node_modules/@types/parse-json": {
             "version": "4.0.0",
@@ -2983,9 +2983,9 @@
             }
         },
         "node_modules/caniuse-lite": {
-            "version": "1.0.30001373",
-            "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001373.tgz",
-            "integrity": "sha512-pJYArGHrPp3TUqQzFYRmP/lwJlj8RCbVe3Gd3eJQkAV8SAC6b19XS9BjMvRdvaS8RMkaTN8ZhoHP6S1y8zzwEQ==",
+            "version": "1.0.30001374",
+            "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001374.tgz",
+            "integrity": "sha512-mWvzatRx3w+j5wx/mpFN5v5twlPrabG8NqX2c6e45LCpymdoGqNvRkRutFUqpRTXKFQFNQJasvK0YT7suW6/Hw==",
             "funding": [
                 {
                     "type": "opencollective",
@@ -4025,9 +4025,9 @@
             "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
         },
         "node_modules/electron-to-chromium": {
-            "version": "1.4.208",
-            "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.208.tgz",
-            "integrity": "sha512-diMr4t69FigAGUk2KovP0bygEtN/9AkqEVkzjEp0cu+zFFbZMVvwACpTTfuj1mAmFR5kNoSW8wGKDFWIvmThiQ=="
+            "version": "1.4.211",
+            "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.211.tgz",
+            "integrity": "sha512-BZSbMpyFQU0KBJ1JG26XGeFI3i4op+qOYGxftmZXFZoHkhLgsSv4DHDJfl8ogII3hIuzGt51PaZ195OVu0yJ9A=="
         },
         "node_modules/elliptic": {
             "version": "6.5.4",
@@ -4337,9 +4337,9 @@
             "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
         },
         "node_modules/fastest-levenshtein": {
-            "version": "1.0.14",
-            "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.14.tgz",
-            "integrity": "sha512-tFfWHjnuUfKE186Tfgr+jtaFc0mZTApEgKDOeyN+FwOqRkO/zK/3h1AiRd8u8CY53owL3CUmGr/oI9p/RdyLTA==",
+            "version": "1.0.16",
+            "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz",
+            "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==",
             "engines": {
                 "node": ">= 4.9.1"
             }
@@ -5210,9 +5210,9 @@
             "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
         },
         "node_modules/is-core-module": {
-            "version": "2.9.0",
-            "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz",
-            "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==",
+            "version": "2.10.0",
+            "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz",
+            "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==",
             "dependencies": {
                 "has": "^1.0.3"
             },
@@ -6244,13 +6244,13 @@
             }
         },
         "node_modules/object.assign": {
-            "version": "4.1.2",
-            "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz",
-            "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==",
+            "version": "4.1.3",
+            "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.3.tgz",
+            "integrity": "sha512-ZFJnX3zltyjcYJL0RoCJuzb+11zWGyaDbjgxZbdV7rFEcHQuYxrZqhow67aA7xpes6LhojyFDaBKAFfogQrikA==",
             "dependencies": {
-                "call-bind": "^1.0.0",
-                "define-properties": "^1.1.3",
-                "has-symbols": "^1.0.1",
+                "call-bind": "^1.0.2",
+                "define-properties": "^1.1.4",
+                "has-symbols": "^1.0.3",
                 "object-keys": "^1.1.1"
             },
             "engines": {
@@ -6587,9 +6587,9 @@
             }
         },
         "node_modules/postcss": {
-            "version": "8.4.14",
-            "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz",
-            "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==",
+            "version": "8.4.16",
+            "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz",
+            "integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==",
             "funding": [
                 {
                     "type": "opencollective",
@@ -8260,9 +8260,9 @@
             }
         },
         "node_modules/tailwindcss": {
-            "version": "3.1.7",
-            "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.1.7.tgz",
-            "integrity": "sha512-r7mgumZ3k0InfVPpGWcX8X/Ut4xBfv+1O/+C73ar/m01LxGVzWvPxF/w6xIUPEztrCoz7axfx0SMdh8FH8ZvRQ==",
+            "version": "3.1.8",
+            "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.1.8.tgz",
+            "integrity": "sha512-YSneUCZSFDYMwk+TGq8qYFdCA3yfBRdBlS7txSq0LUmzyeqRe3a8fBQzbz9M3WS/iFT4BNf/nmw9mEzrnSaC0g==",
             "dependencies": {
                 "arg": "^5.0.2",
                 "chokidar": "^3.5.3",
@@ -9311,9 +9311,9 @@
             }
         },
         "node_modules/yargs-parser": {
-            "version": "21.0.1",
-            "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz",
-            "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==",
+            "version": "21.1.1",
+            "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+            "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
             "engines": {
                 "node": ">=12"
             }
@@ -9372,9 +9372,9 @@
             }
         },
         "@babel/generator": {
-            "version": "7.18.10",
-            "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.10.tgz",
-            "integrity": "sha512-0+sW7e3HjQbiHbj1NeU/vN8ornohYlacAfZIaXhdoGweQqgcNy69COVciYYqEXJ/v+9OBA7Frxm4CVAuNqKeNA==",
+            "version": "7.18.12",
+            "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.12.tgz",
+            "integrity": "sha512-dfQ8ebCN98SvyL7IxNMCUtZQSq5R7kxgN+r8qYTGDmmSion1hX2C0zq2yo1bsCDhXixokv1SAWTZUMYbO/V5zg==",
             "requires": {
                 "@babel/types": "^7.18.10",
                 "@jridgewell/gen-mapping": "^0.3.2",
@@ -9608,13 +9608,13 @@
             "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw=="
         },
         "@babel/helper-wrap-function": {
-            "version": "7.18.10",
-            "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.18.10.tgz",
-            "integrity": "sha512-95NLBP59VWdfK2lyLKe6eTMq9xg+yWKzxzxbJ1wcYNi1Auz200+83fMDADjRxBvc2QQor5zja2yTQzXGhk2GtQ==",
+            "version": "7.18.11",
+            "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.18.11.tgz",
+            "integrity": "sha512-oBUlbv+rjZLh2Ks9SKi4aL7eKaAXBWleHzU89mP0G6BMUlRxSckk9tSIkgDGydhgFxHuGSlBQZfnaD47oBEB7w==",
             "requires": {
                 "@babel/helper-function-name": "^7.18.9",
                 "@babel/template": "^7.18.10",
-                "@babel/traverse": "^7.18.10",
+                "@babel/traverse": "^7.18.11",
                 "@babel/types": "^7.18.10"
             }
         },
@@ -9685,9 +9685,9 @@
             }
         },
         "@babel/parser": {
-            "version": "7.18.10",
-            "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.10.tgz",
-            "integrity": "sha512-TYk3OA0HKL6qNryUayb5UUEhM/rkOQozIBEA5ITXh5DWrSp0TlUQXMyZmnWxG/DizSWBeeQ0Zbc5z8UGaaqoeg=="
+            "version": "7.18.11",
+            "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.11.tgz",
+            "integrity": "sha512-9JKn5vN+hDt0Hdqn1PiJ2guflwP+B6Ga8qbDuoF0PzzVhrzsKIJo8yGqVk6CmMHiMei9w1C1Bp9IMJSIK+HPIQ=="
         },
         "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
             "version": "7.18.6",
@@ -10395,9 +10395,9 @@
             }
         },
         "@babel/traverse": {
-            "version": "7.18.10",
-            "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.10.tgz",
-            "integrity": "sha512-J7ycxg0/K9XCtLyHf0cz2DqDihonJeIo+z+HEdRe9YuT8TY4A66i+Ab2/xZCEW7Ro60bPCBBfqqboHSamoV3+g==",
+            "version": "7.18.11",
+            "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.11.tgz",
+            "integrity": "sha512-TG9PiM2R/cWCAy6BPJKeHzNbu4lPzOSZpeMfeNErskGpTJx6trEvFaVCbDvpcxwy49BKWmEPwiW8mrysNiDvIQ==",
             "requires": {
                 "@babel/code-frame": "^7.18.6",
                 "@babel/generator": "^7.18.10",
@@ -10405,7 +10405,7 @@
                 "@babel/helper-function-name": "^7.18.9",
                 "@babel/helper-hoist-variables": "^7.18.6",
                 "@babel/helper-split-export-declaration": "^7.18.6",
-                "@babel/parser": "^7.18.10",
+                "@babel/parser": "^7.18.11",
                 "@babel/types": "^7.18.10",
                 "debug": "^4.1.0",
                 "globals": "^11.1.0"
@@ -10554,9 +10554,9 @@
             }
         },
         "@types/babel__traverse": {
-            "version": "7.17.1",
-            "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.17.1.tgz",
-            "integrity": "sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA==",
+            "version": "7.18.0",
+            "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.0.tgz",
+            "integrity": "sha512-v4Vwdko+pgymgS+A2UIaJru93zQd85vIGWObM5ekZNdXCKtDYqATlEYnWgfo86Q6I1Lh0oXnksDnMU1cwmlPDw==",
             "requires": {
                 "@babel/types": "^7.3.0"
             }
@@ -10712,9 +10712,9 @@
             "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ=="
         },
         "@types/mime": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.0.tgz",
-            "integrity": "sha512-fccbsHKqFDXClBZTDLA43zl0+TbxyIwyzIzwwhvoJvhNjOErCdeX2xJbURimv2EbSVUGav001PaCJg4mZxMl4w=="
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz",
+            "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA=="
         },
         "@types/minimatch": {
             "version": "3.0.5",
@@ -10722,9 +10722,9 @@
             "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ=="
         },
         "@types/node": {
-            "version": "18.6.3",
-            "resolved": "https://registry.npmjs.org/@types/node/-/node-18.6.3.tgz",
-            "integrity": "sha512-6qKpDtoaYLM+5+AFChLhHermMQxc3TOEFIDzrZLPRGHPrLEwqFkkT5Kx3ju05g6X7uDPazz3jHbKPX0KzCjntg=="
+            "version": "18.6.4",
+            "resolved": "https://registry.npmjs.org/@types/node/-/node-18.6.4.tgz",
+            "integrity": "sha512-I4BD3L+6AWiUobfxZ49DlU43gtI+FTHSv9pE2Zekg6KjMpre4ByusaljW3vYSLJrvQ1ck1hUaeVu8HVlY3vzHg=="
         },
         "@types/parse-json": {
             "version": "4.0.0",
@@ -11542,9 +11542,9 @@
             }
         },
         "caniuse-lite": {
-            "version": "1.0.30001373",
-            "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001373.tgz",
-            "integrity": "sha512-pJYArGHrPp3TUqQzFYRmP/lwJlj8RCbVe3Gd3eJQkAV8SAC6b19XS9BjMvRdvaS8RMkaTN8ZhoHP6S1y8zzwEQ=="
+            "version": "1.0.30001374",
+            "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001374.tgz",
+            "integrity": "sha512-mWvzatRx3w+j5wx/mpFN5v5twlPrabG8NqX2c6e45LCpymdoGqNvRkRutFUqpRTXKFQFNQJasvK0YT7suW6/Hw=="
         },
         "chalk": {
             "version": "4.1.2",
@@ -12309,9 +12309,9 @@
             "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
         },
         "electron-to-chromium": {
-            "version": "1.4.208",
-            "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.208.tgz",
-            "integrity": "sha512-diMr4t69FigAGUk2KovP0bygEtN/9AkqEVkzjEp0cu+zFFbZMVvwACpTTfuj1mAmFR5kNoSW8wGKDFWIvmThiQ=="
+            "version": "1.4.211",
+            "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.211.tgz",
+            "integrity": "sha512-BZSbMpyFQU0KBJ1JG26XGeFI3i4op+qOYGxftmZXFZoHkhLgsSv4DHDJfl8ogII3hIuzGt51PaZ195OVu0yJ9A=="
         },
         "elliptic": {
             "version": "6.5.4",
@@ -12556,9 +12556,9 @@
             "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
         },
         "fastest-levenshtein": {
-            "version": "1.0.14",
-            "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.14.tgz",
-            "integrity": "sha512-tFfWHjnuUfKE186Tfgr+jtaFc0mZTApEgKDOeyN+FwOqRkO/zK/3h1AiRd8u8CY53owL3CUmGr/oI9p/RdyLTA=="
+            "version": "1.0.16",
+            "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz",
+            "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg=="
         },
         "fastq": {
             "version": "1.13.0",
@@ -13166,9 +13166,9 @@
             "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
         },
         "is-core-module": {
-            "version": "2.9.0",
-            "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz",
-            "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==",
+            "version": "2.10.0",
+            "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz",
+            "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==",
             "requires": {
                 "has": "^1.0.3"
             }
@@ -13918,13 +13918,13 @@
             "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="
         },
         "object.assign": {
-            "version": "4.1.2",
-            "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz",
-            "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==",
+            "version": "4.1.3",
+            "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.3.tgz",
+            "integrity": "sha512-ZFJnX3zltyjcYJL0RoCJuzb+11zWGyaDbjgxZbdV7rFEcHQuYxrZqhow67aA7xpes6LhojyFDaBKAFfogQrikA==",
             "requires": {
-                "call-bind": "^1.0.0",
-                "define-properties": "^1.1.3",
-                "has-symbols": "^1.0.1",
+                "call-bind": "^1.0.2",
+                "define-properties": "^1.1.4",
+                "has-symbols": "^1.0.3",
                 "object-keys": "^1.1.1"
             }
         },
@@ -14163,9 +14163,9 @@
             "requires": {}
         },
         "postcss": {
-            "version": "8.4.14",
-            "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz",
-            "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==",
+            "version": "8.4.16",
+            "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz",
+            "integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==",
             "requires": {
                 "nanoid": "^3.3.4",
                 "picocolors": "^1.0.0",
@@ -15327,9 +15327,9 @@
             }
         },
         "tailwindcss": {
-            "version": "3.1.7",
-            "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.1.7.tgz",
-            "integrity": "sha512-r7mgumZ3k0InfVPpGWcX8X/Ut4xBfv+1O/+C73ar/m01LxGVzWvPxF/w6xIUPEztrCoz7axfx0SMdh8FH8ZvRQ==",
+            "version": "3.1.8",
+            "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.1.8.tgz",
+            "integrity": "sha512-YSneUCZSFDYMwk+TGq8qYFdCA3yfBRdBlS7txSq0LUmzyeqRe3a8fBQzbz9M3WS/iFT4BNf/nmw9mEzrnSaC0g==",
             "requires": {
                 "arg": "^5.0.2",
                 "chokidar": "^3.5.3",
@@ -16067,9 +16067,9 @@
             }
         },
         "yargs-parser": {
-            "version": "21.0.1",
-            "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz",
-            "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg=="
+            "version": "21.1.1",
+            "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+            "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="
         }
     }
 }

+ 118 - 0
resources/js/pages/Recipients.vue

@@ -60,6 +60,24 @@
             <icon name="info" class="inline-block w-4 h-4 text-grey-300 fill-current" />
           </span>
         </span>
+        <span v-else-if="props.column.label == 'Inline Encryption'">
+          PGP/Inline
+          <span
+            class="tooltip outline-none"
+            :data-tippy-content="`Use inline (PGP/Inline) instead of PGP/MIME encyption for forwarded messages. Please Note: This will ONLY encrypt and forward the plain text content!`"
+          >
+            <icon name="info" class="inline-block w-4 h-4 text-grey-300 fill-current" />
+          </span>
+        </span>
+        <span v-else-if="props.column.label == 'Hide Subject'">
+          Hide Subject
+          <span
+            class="tooltip outline-none"
+            :data-tippy-content="`Enabling this setting will hide and encrypt the email subject using protected headers. Many mail clients are able to automatically decrypt and display the subject once the email arrives.`"
+          >
+            <icon name="info" class="inline-block w-4 h-4 text-grey-300 fill-current" />
+          </span>
+        </span>
         <span v-else>
           {{ props.column.label }}
         </span>
@@ -150,6 +168,28 @@
             Add public key
           </button>
         </span>
+        <span
+          v-else-if="props.column.field === 'inline_encryption'"
+          class="flex justify-center items-center"
+        >
+          <Toggle
+            v-if="props.row.fingerprint"
+            v-model="rows[props.row.originalIndex].inline_encryption"
+            @on="turnOnInlineEncryption(props.row.id)"
+            @off="turnOffInlineEncryption(props.row.id)"
+          />
+        </span>
+        <span
+          v-else-if="props.column.field === 'protected_headers'"
+          class="flex justify-center items-center"
+        >
+          <Toggle
+            v-if="props.row.fingerprint"
+            v-model="rows[props.row.originalIndex].protected_headers"
+            @on="turnOnProtectedHeaders(props.row.id)"
+            @off="turnOffProtectedHeaders(props.row.id)"
+          />
+        </span>
         <span v-else-if="props.column.field === 'email_verified_at'">
           <span
             name="check"
@@ -422,6 +462,20 @@ export default {
           type: 'boolean',
           globalSearchDisabled: true,
         },
+        {
+          label: 'Inline Encryption',
+          field: 'inline_encryption',
+          type: 'boolean',
+          globalSearchDisabled: true,
+          sortable: false,
+        },
+        {
+          label: 'Hide Subject',
+          field: 'protected_headers',
+          type: 'boolean',
+          globalSearchDisabled: true,
+          sortable: false,
+        },
         {
           label: 'Verified',
           field: 'email_verified_at',
@@ -704,6 +758,70 @@ export default {
           this.error()
         })
     },
+    turnOnInlineEncryption(id) {
+      axios
+        .post(
+          `/api/v1/inline-encrypted-recipients`,
+          JSON.stringify({
+            id: id,
+          }),
+          {
+            headers: { 'Content-Type': 'application/json' },
+          }
+        )
+        .then(response => {
+          //
+        })
+        .catch(error => {
+          if (error.response.status === 422) {
+            this.error(error.response.data)
+          } else {
+            this.error()
+          }
+        })
+    },
+    turnOffInlineEncryption(id) {
+      axios
+        .delete(`/api/v1/inline-encrypted-recipients/${id}`)
+        .then(response => {
+          //
+        })
+        .catch(error => {
+          this.error()
+        })
+    },
+    turnOnProtectedHeaders(id) {
+      axios
+        .post(
+          `/api/v1/protected-headers-recipients`,
+          JSON.stringify({
+            id: id,
+          }),
+          {
+            headers: { 'Content-Type': 'application/json' },
+          }
+        )
+        .then(response => {
+          //
+        })
+        .catch(error => {
+          if (error.response.status === 422) {
+            this.error(error.response.data)
+          } else {
+            this.error()
+          }
+        })
+    },
+    turnOffProtectedHeaders(id) {
+      axios
+        .delete(`/api/v1/protected-headers-recipients/${id}`)
+        .then(response => {
+          //
+        })
+        .catch(error => {
+          this.error()
+        })
+    },
     openRecipientKeyModal(recipient) {
       this.addRecipientKeyModalOpen = true
       this.recipientToAddKey = recipient

+ 12 - 0
routes/api.php

@@ -16,6 +16,8 @@ use App\Http\Controllers\Api\DomainDefaultRecipientController;
 use App\Http\Controllers\Api\DomainOptionController;
 use App\Http\Controllers\Api\EncryptedRecipientController;
 use App\Http\Controllers\Api\FailedDeliveryController;
+use App\Http\Controllers\Api\InlineEncryptedRecipientController;
+use App\Http\Controllers\Api\ProtectedHeadersRecipientController;
 use App\Http\Controllers\Api\RecipientController;
 use App\Http\Controllers\Api\RecipientKeyController;
 use App\Http\Controllers\Api\ReorderRuleController;
@@ -73,6 +75,16 @@ Route::group([
         Route::delete('/encrypted-recipients/{id}', 'destroy');
     });
 
+    Route::controller(InlineEncryptedRecipientController::class)->group(function () {
+        Route::post('/inline-encrypted-recipients', 'store');
+        Route::delete('/inline-encrypted-recipients/{id}', 'destroy');
+    });
+
+    Route::controller(ProtectedHeadersRecipientController::class)->group(function () {
+        Route::post('/protected-headers-recipients', 'store');
+        Route::delete('/protected-headers-recipients/{id}', 'destroy');
+    });
+
     Route::controller(AllowedRecipientController::class)->group(function () {
         Route::post('/allowed-recipients', 'store');
         Route::delete('/allowed-recipients/{id}', 'destroy');

+ 64 - 0
tests/Feature/Api/RecipientsTest.php

@@ -307,4 +307,68 @@ class RecipientsTest extends TestCase
         $response->assertStatus(204);
         $this->assertFalse($this->user->recipients[0]->can_reply_send);
     }
+
+    /** @test */
+    public function user_can_turn_on_inline_encryption()
+    {
+        $recipient = Recipient::factory()->create([
+            'user_id' => $this->user->id,
+            'inline_encryption' => false,
+            'fingerprint' => '26A987650243B28802524E2F809FD0D502E2F695'
+        ]);
+
+        $response = $this->json('POST', '/api/v1/inline-encrypted-recipients/', [
+            'id' => $recipient->id
+        ]);
+
+        $response->assertStatus(200);
+        $this->assertEquals(true, $response->getData()->data->inline_encryption);
+    }
+
+    /** @test */
+    public function user_can_turn_off_inline_encryption()
+    {
+        $recipient = Recipient::factory()->create([
+            'user_id' => $this->user->id,
+            'inline_encryption' => true,
+            'fingerprint' => '26A987650243B28802524E2F809FD0D502E2F695'
+        ]);
+
+        $response = $this->json('DELETE', '/api/v1/inline-encrypted-recipients/'.$recipient->id);
+
+        $response->assertStatus(204);
+        $this->assertFalse($this->user->recipients[0]->inline_encryption);
+    }
+
+    /** @test */
+    public function user_can_turn_on_protected_headers()
+    {
+        $recipient = Recipient::factory()->create([
+            'user_id' => $this->user->id,
+            'protected_headers' => false,
+            'fingerprint' => '26A987650243B28802524E2F809FD0D502E2F695'
+        ]);
+
+        $response = $this->json('POST', '/api/v1/protected-headers-recipients/', [
+            'id' => $recipient->id
+        ]);
+
+        $response->assertStatus(200);
+        $this->assertEquals(true, $response->getData()->data->protected_headers);
+    }
+
+    /** @test */
+    public function user_can_turn_off_protected_headers()
+    {
+        $recipient = Recipient::factory()->create([
+            'user_id' => $this->user->id,
+            'protected_headers' => true,
+            'fingerprint' => '26A987650243B28802524E2F809FD0D502E2F695'
+        ]);
+
+        $response = $this->json('DELETE', '/api/v1/protected-headers-recipients/'.$recipient->id);
+
+        $response->assertStatus(204);
+        $this->assertFalse($this->user->recipients[0]->protected_headers);
+    }
 }