Sfoglia il codice sorgente

Added uuid aliases

Will Browning 6 anni fa
parent
commit
1433805cf9

+ 1 - 0
app/Alias.php

@@ -18,6 +18,7 @@ class Alias extends Model
     ];
 
     protected $fillable = [
+        'id',
         'active',
         'description',
         'email',

+ 4 - 4
app/Console/Commands/ReceiveEmail.php

@@ -97,10 +97,10 @@ class ReceiveEmail extends Command
                         $user = $customDomain->user;
                     }
 
-                    // TODO add check here for uuid pre-generated aliases e.g. 68699f3b-a8c3-4374-9dbf-bdde64afd3e4@anonaddy.me
-
-                    // Check if this is the root domain e.g. anonaddy.me
-                    if ($recipient['domain'] === $parentDomain && !empty(config('anonaddy.admin_username'))) {
+                    // check if this is a uuid generated alias
+                    if ($alias = Alias::find($recipient['local_part'])) {
+                        $user = $alias->user;
+                    } elseif ($recipient['domain'] === $parentDomain && !empty(config('anonaddy.admin_username'))) {
                         $user = User::where('username', config('anonaddy.admin_username'))->first();
                     }
                 }

+ 19 - 0
app/Http/Controllers/AliasController.php

@@ -4,6 +4,7 @@ namespace App\Http\Controllers;
 
 use App\Http\Requests\UpdateAliasRequest;
 use App\Http\Resources\AliasResource;
+use Ramsey\Uuid\Uuid;
 
 class AliasController extends Controller
 {
@@ -21,6 +22,24 @@ class AliasController extends Controller
         ]);
     }
 
+    public function store()
+    {
+        if (user()->hasExceededNewAliasLimit()) {
+            return response('', 429);
+        }
+
+        $uuid = Uuid::uuid4();
+
+        $alias = user()->aliases()->create([
+            'id' => $uuid,
+            'email' => $uuid . '@anonaddy.me',
+            'local_part' => $uuid,
+            'domain' => 'anonaddy.me'
+        ]);
+
+        return new AliasResource($alias->fresh());
+    }
+
     public function update(UpdateAliasRequest $request, $id)
     {
         $alias = user()->aliases()->findOrFail($id);

+ 3 - 0
app/Http/Resources/AliasResource.php

@@ -12,6 +12,9 @@ class AliasResource extends JsonResource
             'id' => $this->id,
             'user_id' => $this->user_id,
             'domain_id' => $this->domain_id,
+            'local_part' => $this->local_part,
+            'extension' => $this->extension,
+            'domain' => $this->domain,
             'email' => $this->email,
             'active' => $this->active,
             'description' => $this->description,

+ 72 - 2
resources/js/pages/Aliases.vue

@@ -118,6 +118,14 @@
           class="absolute right-0 inset-y-0 w-5 h-full text-grey-300 fill-current pointer-events-none mr-2 flex items-center"
         />
       </div>
+      <div class="mt-4 md:mt-0">
+        <button
+          @click="generateAliasModalOpen = true"
+          class="bg-cyan-400 hover:bg-cyan-300 text-cyan-900 font-bold py-3 px-4 rounded focus:outline-none ml-auto"
+        >
+          Generate New Alias
+        </button>
+      </div>
     </div>
     <div class="bg-white rounded shadow overflow-x-auto">
       <table v-if="initialAliases.length" class="w-full whitespace-no-wrap">
@@ -299,10 +307,10 @@
                 v-clipboard:error="clipboardError"
               >
                 <span class="font-semibold text-indigo-800">{{
-                  alias.local_part | truncate(20)
+                  alias.local_part | truncate(25)
                 }}</span>
                 <span class="block text-grey-400 text-sm">{{
-                  getAliasEmail(alias) | truncate(35)
+                  getAliasEmail(alias) | truncate(40)
                 }}</span>
               </span>
             </div>
@@ -469,6 +477,40 @@
       </div>
     </div>
 
+    <Modal :open="generateAliasModalOpen" @close="generateAliasModalOpen = false">
+      <div class="max-w-lg w-full bg-white rounded-lg shadow-2xl p-6">
+        <h2
+          class="font-semibold text-grey-900 text-2xl leading-tight border-b-2 border-grey-100 pb-4"
+        >
+          Generate new UUID alias
+        </h2>
+        <p class="mt-4 text-grey-700">
+          This will generate a new unique alias in the form of<br /><br />
+          86064c92-da41-443e-a2bf-5a7b0247842f@anonaddy.me<br /><br />
+          Useful if you do not wish to include your username in the email as a potential link
+          between aliases.<br /><br />
+          Other aliases e.g. alias@{{ domain }} or .me are created automatically when they receive
+          their first email.
+        </p>
+        <div class="mt-6">
+          <button
+            @click="generateNewAlias"
+            class="bg-cyan-400 hover:bg-cyan-300 text-cyan-900 font-bold py-3 px-4 rounded focus:outline-none"
+            :class="generateAliasLoading ? 'cursor-not-allowed' : ''"
+            :disabled="generateAliasLoading"
+          >
+            Generate Alias
+          </button>
+          <button
+            @click="generateAliasModalOpen = false"
+            class="ml-4 px-4 py-3 text-grey-800 font-semibold bg-white hover:bg-grey-50 border border-grey-100 rounded focus:outline-none"
+          >
+            Cancel
+          </button>
+        </div>
+      </div>
+    </Modal>
+
     <Modal :open="editAliasRecipientsModalOpen" @close="closeAliasRecipientsModal">
       <div class="max-w-lg w-full bg-white rounded-lg shadow-2xl px-6 py-6">
         <h2
@@ -615,6 +657,8 @@ export default {
       currentSortDir: 'desc',
       editAliasRecipientsLoading: false,
       editAliasRecipientsModalOpen: false,
+      generateAliasModalOpen: false,
+      generateAliasLoading: false,
       recipientsAliasToEdit: {},
       aliasRecipientsToEdit: [],
     }
@@ -689,6 +733,9 @@ export default {
 
       this.aliases = _.orderBy(this.aliases, [this.currentSort], [this.currentSortDir])
     },
+    reSort() {
+      this.aliases = _.orderBy(this.aliases, [this.currentSort], [this.currentSortDir])
+    },
     openAliasRecipientsModal(alias) {
       this.editAliasRecipientsModalOpen = true
       this.recipientsAliasToEdit = alias
@@ -731,6 +778,29 @@ export default {
           this.error()
         })
     },
+    generateNewAlias() {
+      this.generateAliasLoading = true
+
+      axios
+        .post('/aliases', JSON.stringify({}), {
+          headers: { 'Content-Type': 'application/json' },
+        })
+        .then(({ data }) => {
+          this.generateAliasLoading = false
+          this.aliases.push(data.data)
+          this.reSort()
+          this.generateAliasModalOpen = false
+          this.success('New alias generated successfully')
+        })
+        .catch(error => {
+          this.generateAliasLoading = false
+          if (error.response.status === 429) {
+            this.error('You have reached your hourly limit for creating new aliases')
+          } else {
+            this.error()
+          }
+        })
+    },
     editAlias(alias) {
       if (this.aliasDescriptionToEdit.length > 100) {
         return this.error('Description cannot be more than 100 characters')

+ 1 - 1
resources/js/pages/Recipients.vue

@@ -79,7 +79,7 @@
                 :data-tippy-content="
                   `Use this to attach recipients to new aliases as they are created e.g. alias+key@${
                     user.username
-                  }.anonaddy.com. You can attach multiple recipients by doing alias+2.3@${
+                  }.anonaddy.com. You can attach multiple recipients by doing alias+2.3.4@${
                     user.username
                   }.anonaddy.com`
                 "

+ 1 - 0
routes/web.php

@@ -17,6 +17,7 @@ Route::post('/login/2fa', 'TwoFactorAuthController@authenticateTwoFactor')->name
 
 Route::middleware(['auth', 'verified', '2fa'])->group(function () {
     Route::get('/', 'AliasController@index')->name('aliases.index');
+    Route::post('/aliases', 'AliasController@store')->name('aliases.store');
     Route::patch('/aliases/{id}', 'AliasController@update')->name('aliases.update');
     Route::delete('/aliases/{id}', 'AliasController@destroy')->name('aliases.destroy');
 

+ 10 - 0
tests/Feature/AliasesTest.php

@@ -143,6 +143,16 @@ class AliasesTest extends TestCase
         $this->assertEquals($aliasRecipient->recipient->email, $response->data('recipients')[0]['email']);
     }
 
+    /** @test */
+    public function user_can_generate_new_alias()
+    {
+        $response = $this->json('POST', '/aliases', []);
+
+        $response->assertStatus(200);
+        $this->assertCount(1, $this->user->aliases);
+        $this->assertEquals($this->user->aliases[0]->email, $response->getData()->data->email);
+    }
+
     /** @test */
     public function user_can_activate_alias()
     {

+ 55 - 0
tests/Feature/ReceiveEmailTest.php

@@ -247,6 +247,61 @@ class ReceiveEmailTest extends TestCase
         });
     }
 
+    /** @test */
+    public function it_can_forward_email_with_uuid_generated_alias()
+    {
+        Mail::fake();
+
+        Mail::assertNothingSent();
+
+        $uuid = '86064c92-da41-443e-a2bf-5a7b0247842f';
+
+        config([
+            'anonaddy.admin_username' => 'random'
+        ]);
+
+        factory(Alias::class)->create([
+            'id' => $uuid,
+            'user_id' => $this->user->id,
+            'email' => $uuid.'@anonaddy.me',
+            'local_part' => $uuid,
+            'domain' => 'anonaddy.me',
+        ]);
+
+        $defaultRecipient = $this->user->defaultRecipient;
+
+        $this->artisan(
+            'anonaddy:receive-email',
+            [
+                'file' => base_path('tests/emails/email_with_uuid.eml'),
+                '--sender' => 'will@anonaddy.com',
+                '--recipient' => [$uuid.'@anonaddy.me'],
+                '--local_part' => [$uuid],
+                '--extension' => [''],
+                '--domain' => ['anonaddy.me'],
+                '--size' => '892'
+            ]
+        )->assertExitCode(0);
+
+        $this->assertDatabaseHas('aliases', [
+            'local_part' => $uuid,
+            'domain' => 'anonaddy.me',
+            'email' => $uuid.'@anonaddy.me',
+            'emails_forwarded' => 1,
+            'emails_blocked' => 0
+        ]);
+        $this->assertDatabaseHas('users', [
+            'id' => $this->user->id,
+            'username' => 'johndoe',
+            'bandwidth' => '892'
+        ]);
+        $this->assertCount(1, $this->user->aliases);
+
+        Mail::assertQueued(ForwardEmail::class, function ($mail) use ($defaultRecipient) {
+            return $mail->hasTo($defaultRecipient->email);
+        });
+    }
+
     /** @test */
     public function it_can_forward_email_with_existing_alias_and_receipients()
     {

+ 28 - 0
tests/emails/email_with_uuid.eml

@@ -0,0 +1,28 @@
+Date: Wed, 20 Feb 2019 15:00:00 +0100 (CET)
+From: Will <will@anonaddy.com>
+To: <86064c92-da41-443e-a2bf-5a7b0247842f@anonaddy.me>
+Subject: Test Email
+Content-Type: multipart/mixed; boundary="----=_Part_10031_1199410393.1550677940425"
+
+------=_Part_10031_1199410393.1550677940425
+Content-Type: text/html; charset=UTF-8
+Content-Transfer-Encoding: quoted-printable
+
+Hi,<br>
+<br>
+This is a test email.<br>
+<br>
+Will
+
+
+------=_Part_10031_1199410393.1550677940425
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: quoted-printable
+
+Hi,
+
+This is a test email.
+
+Will
+
+------=_Part_10031_1199410393.1550677940425--