Przeglądaj źródła

Add option to logout of other browser sessions

Will Browning 4 lat temu
rodzic
commit
55870adb1a

+ 112 - 50
README.md

@@ -4,13 +4,56 @@ This is the source code for self-hosting AnonAddy.
 
 ## FAQ
 
-#### **Why is it called AnonAddy?**
+- [Why is it called AnonAddy?](#why-is-it-called-anonaddy)
+- [Why did you make this site?](#why-did-you-make-this-site)
+- [Why should I use AnonAddy?](#why-should-i-use-anonaddy)
+- [Do you store emails?](#do-you-store-emails)
+- [What is a shared domain alias?](#what-is-a-shared-domain-alias)
+- [What is a standard alias?](#what-is-a-standard-alias)
+- [Can I use my own domain?](#can-i-use-my-own-domain)
+- [Why should I use this instead of a similar service?](#why-should-i-use-this-instead-of-a-similar-service)
+- [Is there a browser extension?](#is-there-a-browser-extension)
+- [Is there an Android app?](#is-there-an-android-app)
+- [Is there an iOS app?](#is-there-an-ios-app)
+- [How do I add my own GPG/OpenPGP key for encryption?](#how-do-i-add-my-own-gpgopenpgp-key-for-encryption)
+- [Are attachments encrypted too?](#are-attachments-encrypted-too)
+- [Are forwarded emails signed when encryption is enabled?](#are-forwarded-emails-signed-when-encryption-is-enabled)
+- [What if I don't want anyone to link ownership of my aliases together?](#what-if-i-dont-want-anyone-to-link-ownership-of-my-aliases-together)
+- [Where is the server located?](#where-is-the-server-located)
+- [What if I don't trust you?](#what-if-i-dont-trust-you)
+- [What is the maximum number of recipients I can add to an alias?](#what-is-the-maximum-number-of-recipients-i-can-add-to-an-alias)
+- [What happens when I delete my account?](#what-happens-when-i-delete-my-account)
+- [Does this work with any email provider?](#does-this-work-with-any-email-provider)
+- [How do I reply to a forwarded email?](#how-do-i-reply-to-a-forwarded-email)
+- [Does AnonAddy strip out the banner information when I reply to an email?](#does-anonaddy-strip-out-the-banner-information-when-i-reply-to-an-email)
+- [How do I send email from an alias?](#how-do-i-send-email-from-an-alias)
+- [Will people see my real email if I reply to a forwarded one?](#will-people-see-my-real-email-if-i-reply-to-a-forwarded-one)
+- [Can emails have attachments?](#can-emails-have-attachments)
+- [What is the max email size limit?](#what-is-the-max-email-size-limit)
+- [What happens if I have a subscription but then cancel it?](#what-happens-if-i-have-a-subscription-but-then-cancel-it)
+- [If I subscribe will Stripe see my real email address?](#if-i-subscribe-will-stripe-see-my-real-email-address)
+- [How do you prevent spammers?](#how-do-you-prevent-spammers)
+- [What do you use to do DNS lookups on domain names?](#what-do-you-use-to-do-dns-lookups-on-domain-names)
+- [Is there a limit to how many emails I can forward?](#is-there-a-limit-to-how-many-emails-i-can-forward)
+- [Is there a limit to how many aliases I can create per hour?](#is-there-a-limit-to-how-many-aliases-i-can-create-per-hour)
+- [How is my bandwidth calculated?](#how-is-my-bandwidth-calculated)
+- [How many emails can I receive before I go over my bandwidth limit?](#how-many-emails-can-i-receive-before-i-go-over-my-bandwidth-limit)
+- [What happens if I go over my bandwidth limit in a given month?](#what-happens-if-i-go-over-my-bandwidth-limit-in-a-given-month)
+- [Can I login using an additional username?](#can-i-login-using-an-additional-username)
+- [I'm not receiving any emails, what's wrong?](#im-not-receiving-any-emails-whats-wrong)
+- [How do I know this site won't disappear next month?](#how-do-i-know-this-site-wont-disappear-next-month)
+- [Is the application tested?](#is-the-appliction-tested)
+- [How do I host this myself?](#how-do-i-host-this-myself)
+- [Who's behind AnonAddy?](#whos-behind-anonaddy)
+- [I couldn't find an answer to my question, how can I contact you?](#i-couldnt-find-an-answer-to-my-question-how-can-i-contact-you)
+
+## Why is it called AnonAddy?
 
 AnonAddy is short for "Anonymous Email Address". The word "Addy" is internet slang for email address, e.g.
 
 > "My addy is being spammed. I should've kept it private."
 
-#### **Why did you make this site?**
+## Why did you make this site?
 
 I made this service after trying a few other options that do a similar thing. I was really interested in how they worked and loved the thought of protecting my real email addresses from spam.
 
@@ -25,7 +68,7 @@ I made the code open-source to show everyone what was going on behind the scenes
 
 I use this service myself for the vast majority of sites I'm signed up to.
 
-#### **Why should I use AnonAddy?**
+## Why should I use AnonAddy?
 
 There are a number of reasons you should consider using this service:
 
@@ -36,23 +79,23 @@ There are a number of reasons you should consider using this service:
 * Update where emails are forwarded without having to go through and change your email address for each site individually
 * Reply to forwarded emails anonymously without revealing your true email address
 
-#### **Do you store emails?**
+## Do you store emails?
 
 No I definitely do not store/save any emails that pass through the server.
 
-#### **What is a shared domain alias?**
+## What is a shared domain alias?
 
 A shared domain alias is any alias that has a domain name that is also shared with other users. For example anyone can generate an alias with the @anonaddy.me domain. Aliases with shared domain names must be pre-generated and cannot be created on-the-fly like standard aliases.
 
-#### **What is a standard alias?**
+## What is a standard alias?
 
 A standard alias is any alias that can be created on-the-fly. Automatic on-the-fly alias creation is only available for domains that are unique to you. For example, your unique username subdomain, any additional usernames or any custom domains. So if you signed up with the username "johndoe", any alias you create using @johndoe.anonaddy.com would be a standard alias (even if you've generated a UUID/Random Word one).
 
-#### **Can I use my own domain?**
+## Can I use my own domain?
 
 Yes you can use your own domain name so you can also have *@example.com as your aliases. To do so you simply need to add a TXT record to verify your ownership of the domain. Then you will need to add an MX record to your domain so that our server can handle incoming emails. You can then add a few other records to enable sending from your domain too.
 
-#### **Why should I use this instead of a similar service?**
+## Why should I use this instead of a similar service?
 
 Here are a few reasons I can think of:
 
@@ -68,19 +111,32 @@ Here are a few reasons I can think of:
 * Ability to add additional usernames to compartmentalise aliases
 * New features added regularly
 
-#### **Is there a browser extension?**
+## Is there a browser extension?
 
 Yes there is an [open-source](https://github.com/anonaddy/browser-extension) browser extension available to download for [Firefox](https://addons.mozilla.org/en-GB/firefox/addon/anonaddy/) and [Chrome](https://chrome.google.com/webstore/detail/anonaddy/iadbdpnoknmbdeolbapdackdcogdmjpe) (also available on other chromium based browsers such as Brave and Vivaldi). You can use the extension to generate new aliases remotely.
 
-#### **How do I add my own GPG/OpenPGP key for encryption?**
+## Is there an Android app?
+
+There is not an official Android app that I have made myself as I am not familiar with mobile development.
+
+There is however an excellent [open-source](https://gitlab.com/Stjin/anonaddy-android) Android app created by [Stjin](https://twitter.com/Stjinchan) that is available to download from the [Play Store](https://play.google.com/store/apps/details?id=host.stjin.anonaddy) (paid) and [F-Droid](https://f-droid.org/packages/host.stjin.anonaddy) (free). The developer of this app has put in a lot of time and effort so if you would like to support him please purchase the Play Store version.
+
+There is also another unofficial [open-source](https://github.com/KhalidWar/anonaddy) Android app created by [KhalidWar](https://twitter.com/RealKhalidWar) available from the [Play Store](https://play.google.com/store/apps/details?id=com.khalidwar.anonaddy).
+
+## Is there an iOS app?
+
+At the moment there is not an app available for iOS. I believe the developers above may be looking into creating one but there is no time scale on this. In the meantime please use the web application in your mobile's browser.
+
+
+## How do I add my own GPG/OpenPGP key for encryption?
 
 On the recipients page you simply need to click "Add public key" and paste in your **public** key data. Now all emails forwarded to you will be encrypted with your key. You should also replace the subject line of forwarded messages in your account settings as this cannot be encrypted.
 
-#### **Are attachments encrypted too?**
+## Are attachments encrypted too?
 
 Yes attachments are part of the email body and are also encrypted if you have it enabled.
 
-#### **Are forwarded emails signed when encryption is enabled?**
+## Are forwarded emails signed when encryption is enabled?
 
 Yes when you have encryption enabled all forwarded emails are signed using our mailer@anonaddy.me private key.
 
@@ -88,26 +144,26 @@ You can add this key to your own keyring so that you can verify emails have come
 
 The fingerprint of the mailer@anonaddy.me key is "26A987650243B28802524E2F809FD0D502E2F695" you can find the key on [https://keys.openpgp.org](https://keys.openpgp.org/search?q=26A987650243B28802524E2F809FD0D502E2F695).
 
-#### **What if I don't want anyone to link ownership of my aliases together?**
+## What if I don't want anyone to link ownership of my aliases together?
 
 If you're concerned that your aliases are all linked by your username e.g. @johndoe.anonaddy.com, then you have a couple of options:
 
 1. You can generate UUID or random word aliases instead, these are all under a shared domain and cannot be linked to a user.
 2. You can add additional usernames and separate your aliases under your these. e.g. you could have one username for personal stuff, another for work, another for hobbies etc.
 
-#### **Where is the server located?**
+## Where is the server located?
 
 The server is located in Amsterdam, Netherlands with [Greenhost.net](https://greenhost.net/). Greenhost focuses greatly on privacy and security and their servers run entirely on Dutch wind energy.
 
-#### **What if I don't trust you?**
+## What if I don't trust you?
 
 It's good to keep your guard up when online so you should never trust anyone 100%. I'll try my best to be as honest and transparent as I can but if you still aren't convinced you can always just fire up your own server and self-host this application. You'll need to know about server administration and PHP. You can find more information here [https://github.com/anonaddy/anonaddy#self-hosting](https://github.com/anonaddy/anonaddy#self-hosting).
 
-#### **What is the maximum number of recipients I can add to an alias?**
+## What is the maximum number of recipients I can add to an alias?
 
 The limit is currently set to 10 which should suffice in the vast majority of situations.
 
-#### **What happens when I delete my account?**
+## What happens when I delete my account?
 
 When you delete your account the following happens:
 
@@ -119,29 +175,29 @@ When you delete your account the following happens:
 * Your username and any additional usernames that you created are encrypted and added to a table in the database. This is to prevent anybody signing up with the same username in the future.
 * Any subscription information is deleted from the database
 
-#### **Does this work with any email provider?**
+## Does this work with any email provider?
 
 Yes this will work with any provider, although I can't guarantee it won't land in spam initially.
 
-#### **How do I reply to a forwarded email?**
+## How do I reply to a forwarded email?
 
-Each forwarded email has a Reply-To: header set. This header will look something like this:
+Each forwarded email has a From: header set. This header will look something like this:
 
-Reply-To: <<span class="break-words"><alias+hello=example.com@johndoe.anonaddy.com></span>>
+From: <<span class="break-words"><alias+hello=example.com@johndoe.anonaddy.com></span>>
 
 Where hello@example.com is the address of the person who sent you the email and alias@johndoe.anonaddy.com is the alias that forwarded you the email.
 
-Almost all mail clients respect the Reply-To: header, so all you need to do is click reply and it should automatically fill the To: field with the correct address.
-
-Some users have reported that Gmail's web mail has not been using the Reply-To header. If this is the case then you will have to manually copy the value of the Reply-To header and use this instead.
+All you need to do is click reply in your email client or web interface and it will automatically fill the To: field with the correct address.
 
 To check if a reply has worked properly check in your dashboard if the reply count has been incremented for that alias.
 
-#### **Does AnonAddy strip out the banner information when I reply to an email?**
+For further details please see this help article - [Replying to email using an alias](https://anonaddy.com/help/replying-to-email-using-an-alias/).
+
+## Does AnonAddy strip out the banner information when I reply to an email?
 
 At the moment the site does not automatically strip out the "This email was sent to..." text from forwarded emails when you reply to them. You need to either remove this from the quoted text manually or set the banner information to "off" in your account settings.
 
-#### **How do I send email from an alias?**
+## How do I send email from an alias?
 
 This works in the same way as replying to an email.
 
@@ -155,7 +211,9 @@ All you need to do is enter the following in the To: field.
 
 Then send the email exactly as you would any other. To check that the email has sent successfully, look in your dashboard at the sent count column and see if it has been incremented for that alias.
 
-This works exactly the same for UUID/Random Word aliases, additional usernames and custom domains.
+If you want an easy way to construct the correct email address that you should send to you can click "Send from" next to any alias in the web application and after entering the destination address it will display the right email address to use.
+
+This works exactly the same for shared domain aliases, additional usernames and custom domains.
 
 You can even use the send from feature to create an alias on the fly that does not yet exist. This only works for standard aliases or those at custom domains that behave as a catch-all.
 
@@ -167,19 +225,21 @@ If you need to send an email to an address with an extension e.g. **hello+whatev
 
 Just enter the extension too!
 
-#### **Will people see my real email if I reply to a forwarded one?**
+For further details please see this help article - [Sending email from an alias](https://anonaddy.com/help/sending-email-from-an-alias/).
+
+## Will people see my real email if I reply to a forwarded one?
 
 No, your real email will not be shown, the email will look as if it has come from us instead. Just make sure not to include anything that might identify you when composing the reply, i.e. your full name.
 
-#### **Can emails have attachments?**
+## Can emails have attachments?
 
 Yes you can add attachments to emails forwarded and replies. Attachments count towards your bandwidth.
 
-#### **What is the max email size limit?**
+## What is the max email size limit?
 
 The max email size is currently set to 10MB (including attachments).
 
-#### **What happens if I have a subscription but then cancel it?**
+## What happens if I have a subscription but then cancel it?
 
 If you cancel your subscription it will remain active until the end of your current billing cycle, you will still be able to use your paid plan features until the billing cycle ends.
 
@@ -195,34 +255,34 @@ A few days before your billing cycle ends you will receive an email letting you
 
 You will not be able to activate any of the above again until you resubscribe.
 
-#### **If I subscribe will Stripe see my real email address?**
+## If I subscribe will Stripe see my real email address?
 
 No, Stripe will instead be given an alias. This alias will only be created if Stripe sends an email to it, for example if your card payment fails or if your card has expired.
 
-#### **How do you prevent spammers?**
+## How do you prevent spammers?
 
 The following is in place to help prevent spam:
 
-* SpamAssassin - score threshold of 5.0
+* Rspamd - Fast, free and open-source spam filtering system
 * DNS blacklist checks - spamhaus.org
 * SPF, DKIM - to check the SPF record on the sender's domain
 * DMARC - to check for email spoofing and reject emails that fail
 * FQDN - the sender must be using a valid fully qualified domain name
 * PTR record check - if the sender has no valid PTR record it is rejected
 
-#### **What do you use to do DNS lookups on domain names?**
+## What do you use to do DNS lookups on domain names?
 
 The server is running a local DNS caching server to improve the speed of queries.
 
-#### **Is there a limit to how many emails I can forward?**
+## Is there a limit to how many emails I can forward?
 
 Not unless you are really going to town. Each user is throttled to 200 emails per hour through the server.
 
-#### **Is there a limit to how many aliases I can create per hour?**
+## Is there a limit to how many aliases I can create per hour?
 
 Currently you are limited to creating 10 new aliases per hour on the free plan, 20 per hour on the Lite plan and 50 per hour on the Pro plan. If you try to create more than this the emails will be deferred until you are back below the limit.
 
-#### **How is my bandwidth calculated?**
+## How is my bandwidth calculated?
 
 Each time a new email is received Postfix calculates its size in bytes. A column in the database is then simply incremented by that size when the email is forwarded or a reply is sent. At the start of each month your bandwidth is reset to 0.
 
@@ -230,19 +290,19 @@ I don't use rolling 30 day total as the only way to do this would be to log the
 
 Blocked emails do not count towards your bandwidth (e.g. an alias is inactive or deleted).
 
-#### **How many emails can I receive before I go over my bandwidth limit?**
+## How many emails can I receive before I go over my bandwidth limit?
 
 The average email is about 76800 bytes (75KB), this is roughly equivalent to 7,000 words in plain text. So the 10MB monthly allowance would be around 140 emails and the Lite plan's 50MB would be almost 700 emails.
 
-#### **What happens if I go over my bandwidth limit in a given month?**
+## What happens if I go over my bandwidth limit in a given month?
 
-If you get close to your limit you'll be sent an email letting you know. If you continue and go over your limit the server will start discarding emails until your bandwidth resets the next month or you upgrade your plan.
+If you get close to your limit (over 80%) you'll be sent an email letting you know. If you continue and go over your limit the server will start discarding emails until your bandwidth resets the next month or you upgrade your plan.
 
-#### **Can I login using an additional username?**
+## Can I login using an additional username?
 
 You can add 1 additional username as a Lite user and up to 3 additional usernames as a Pro user for totals of 2 and 4 respectively (including the one you signed up with). You can currently only login with the one that you originally signed up with.
 
-#### **I'm not receiving any emails, what's wrong?**
+## I'm not receiving any emails, what's wrong?
 
 Please make sure to add mailer@anonaddy.me, mailer@anonaddy.com and any other aliases you use to your address book and also to check your spam folder. Make sure to mark emails from us as safe if they turn up in spam.
 
@@ -264,29 +324,31 @@ If you are having issues with emails being rejected as "possibly spammy" by Goog
 
 If you still aren't receiving emails please contact me.
 
-#### **How do I know this site won't disappear next month?**
+## How do I know this site won't disappear next month?
 
-I am very passionite about this project. I use it myself everyday and will be keeping it running indefinitely.
+I am very passionate about this project. I use it myself every day and will be keeping it running indefinitely. The service also provides me with an income.
 
-#### **Is the application tested?**
+## Is the application tested?
 
 Yes it has over 180 automated PHPUnit tests written.
 
-#### **How do I host this myself?**
+## How do I host this myself?
 
 You will need to set up your own server with Postfix so that you can pipe the received mail to the application. You can find more information here [https://github.com/anonaddy/anonaddy#self-hosting](https://github.com/anonaddy/anonaddy#self-hosting).
 
-#### **Who's behind AnonAddy?**
+For those who prefer using Docker there is an image you can use here - [github.com/anonaddy/docker](https://github.com/anonaddy/docker).
+
+## Who's behind AnonAddy?
 
 My name is Will Browning, I'm a web developer from the UK and an advocate for online privacy and open-source software. You can find me on [Twitter](https://twitter.com/willbrowningme) although I don't tweet that much!
 
-#### **I couldn't find an answer to my question, how can I contact you?**
+## I couldn't find an answer to my question, how can I contact you?
 
 For any other questions just send an email to - [contact@anonaddy.com](mailto:contact@anonaddy.com) ([GPG Key](https://anonaddy.com/anonaddy-contact-public-key.asc))
 
 ## Self Hosting
 
-#### Software Requirements
+## Software Requirements
 
 * Postfix (3.0.0+) (plus postfix-mysql for database queries and postfix-pcre)
 * PHP (7.3+) and the [php-mailparse](https://pecl.php.net/package/mailparse) extension, the [php-gnupg](https://pecl.php.net/package/gnupg) extension if you plan to encrypt forwarded emails, the [php-imagick](https://pecl.php.net/package/imagick) extension for generating 2FA QR codes

+ 20 - 0
app/Http/Controllers/BrowserSessionController.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Auth;
+
+class BrowserSessionController extends Controller
+{
+    public function destroy(Request $request)
+    {
+        $request->validate([
+            'current_password_sesssions' => 'password',
+        ]);
+
+        Auth::logoutOtherDevices($request->current_password_sesssions);
+
+        return back()->with(['status' => 'Successfully logged out of other browser sessions!']);
+    }
+}

+ 4 - 0
app/Http/Controllers/PasswordController.php

@@ -3,6 +3,7 @@
 namespace App\Http\Controllers;
 
 use App\Http\Requests\UpdatePasswordRequest;
+use Illuminate\Support\Facades\Auth;
 use Illuminate\Support\Facades\Hash;
 
 class PasswordController extends Controller
@@ -13,6 +14,9 @@ class PasswordController extends Controller
             return redirect(url()->previous().'#update-password')->withErrors(['current' => 'Current password incorrect']);
         }
 
+        // Log out of other sessions
+        Auth::logoutOtherDevices($request->current);
+
         user()->password = Hash::make($request->password);
         user()->save();
 

+ 1 - 1
app/Http/Kernel.php

@@ -33,7 +33,7 @@ class Kernel extends HttpKernel
             \App\Http\Middleware\EncryptCookies::class,
             \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
             \Illuminate\Session\Middleware\StartSession::class,
-            // \Illuminate\Session\Middleware\AuthenticateSession::class,
+            \Illuminate\Session\Middleware\AuthenticateSession::class,
             \Illuminate\View\Middleware\ShareErrorsFromSession::class,
             \App\Http\Middleware\VerifyCsrfToken::class,
             \Illuminate\Routing\Middleware\SubstituteBindings::class,

+ 1 - 0
app/Jobs/DeleteAccount.php

@@ -46,6 +46,7 @@ class DeleteAccount implements ShouldQueue
         $this->user->additionalUsernames()->get()->each->delete(); // In order to fire deleting model event.
         $this->user->tokens()->delete();
         $this->user->rules()->delete();
+        $this->user->webauthnKeys()->delete();
         $this->user->delete();
     }
 }

+ 35 - 175
composer.lock

@@ -2837,89 +2837,6 @@
             ],
             "time": "2020-11-22T14:29:11+00:00"
         },
-        {
-            "name": "league/uri-components",
-            "version": "2.2.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/thephpleague/uri-components.git",
-                "reference": "14bab20b05bc20d16dec17401a9027c679412589"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/thephpleague/uri-components/zipball/14bab20b05bc20d16dec17401a9027c679412589",
-                "reference": "14bab20b05bc20d16dec17401a9027c679412589",
-                "shasum": ""
-            },
-            "require": {
-                "ext-json": "*",
-                "league/uri-interfaces": "^2.1",
-                "php": "^7.2",
-                "psr/http-message": "^1.0"
-            },
-            "require-dev": {
-                "friendsofphp/php-cs-fixer": "^2.3",
-                "guzzlehttp/psr7": "^1.4",
-                "laminas/laminas-diactoros": "^2.0",
-                "league/uri": "^6.0",
-                "phpstan/phpstan": "^0.12",
-                "phpstan/phpstan-phpunit": "^0.12",
-                "phpstan/phpstan-strict-rules": "^0.12",
-                "phpunit/phpunit": "^7.0 | ^8.0"
-            },
-            "suggest": {
-                "ext-fileinfo": "Needed to create Data URI from a filepath",
-                "ext-gmp": "to improve handle IPV4 parsing",
-                "ext-intl": "to handle IDN host",
-                "jeremykendall/php-domain-parser": "Public Suffix and Top Level Domain parsing implemented in PHP",
-                "league/uri": "to allow manipulating URI objects",
-                "php-64bit": "to improve handle IPV4 parsing",
-                "psr/http-message-implementation": "to allow manipulating PSR-7 Uri objects"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "League\\Uri\\": "src"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Ignace Nyamagana Butera",
-                    "email": "nyamsprod@gmail.com",
-                    "homepage": "https://nyamsprod.com"
-                }
-            ],
-            "description": "URI components manipulation library",
-            "homepage": "http://uri.thephpleague.com",
-            "keywords": [
-                "authority",
-                "components",
-                "fragment",
-                "host",
-                "path",
-                "port",
-                "query",
-                "rfc3986",
-                "scheme",
-                "uri",
-                "url",
-                "userinfo"
-            ],
-            "support": {
-                "issues": "https://github.com/thephpleague/uri-components/issues",
-                "source": "https://github.com/thephpleague/uri-components/tree/2.2.1"
-            },
-            "time": "2020-02-09T19:44:04+00:00"
-        },
         {
             "name": "league/uri-interfaces",
             "version": "2.2.0",
@@ -8556,16 +8473,16 @@
         },
         {
             "name": "web-auth/cose-lib",
-            "version": "v3.2.12",
+            "version": "v3.3.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/web-auth/cose-lib.git",
-                "reference": "27ab1f059d6ffb776ec01bd421ccb4338335e5a2"
+                "reference": "eea6fae63ff5c81bf98c115b1be5f38a69682c16"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/web-auth/cose-lib/zipball/27ab1f059d6ffb776ec01bd421ccb4338335e5a2",
-                "reference": "27ab1f059d6ffb776ec01bd421ccb4338335e5a2",
+                "url": "https://api.github.com/repos/web-auth/cose-lib/zipball/eea6fae63ff5c81bf98c115b1be5f38a69682c16",
+                "reference": "eea6fae63ff5c81bf98c115b1be5f38a69682c16",
                 "shasum": ""
             },
             "require": {
@@ -8574,21 +8491,9 @@
                 "ext-mbstring": "*",
                 "ext-openssl": "*",
                 "fgrosse/phpasn1": "^2.1",
-                "php": "^7.2"
+                "php": ">=7.2"
             },
             "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "v1.0": "1.0.x-dev",
-                    "v1.1": "1.1.x-dev",
-                    "v1.2": "1.2.x-dev",
-                    "v2.0": "2.0.x-dev",
-                    "v2.1": "2.1.x-dev",
-                    "v3.0": "3.0.x-dev",
-                    "v3.1": "3.1.x-dev",
-                    "v3.2": "3.2.x-dev"
-                }
-            },
             "autoload": {
                 "psr-4": {
                     "Cose\\": "src/"
@@ -8615,7 +8520,7 @@
                 "RFC8152"
             ],
             "support": {
-                "source": "https://github.com/web-auth/cose-lib/tree/v3.2.12"
+                "source": "https://github.com/web-auth/cose-lib/tree/v3.3.1"
             },
             "funding": [
                 {
@@ -8627,28 +8532,27 @@
                     "type": "patreon"
                 }
             ],
-            "time": "2020-10-29T08:24:25+00:00"
+            "time": "2021-01-09T13:31:01+00:00"
         },
         {
             "name": "web-auth/metadata-service",
-            "version": "v3.2.12",
+            "version": "v3.3.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/web-auth/webauthn-metadata-service.git",
-                "reference": "1a27a204280acf0e49e496b5bc8fcc2225e830f6"
+                "reference": "8488d3a832a38cc81c670fce05de1e515c6e64b1"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/web-auth/webauthn-metadata-service/zipball/1a27a204280acf0e49e496b5bc8fcc2225e830f6",
-                "reference": "1a27a204280acf0e49e496b5bc8fcc2225e830f6",
+                "url": "https://api.github.com/repos/web-auth/webauthn-metadata-service/zipball/8488d3a832a38cc81c670fce05de1e515c6e64b1",
+                "reference": "8488d3a832a38cc81c670fce05de1e515c6e64b1",
                 "shasum": ""
             },
             "require": {
                 "beberlei/assert": "^3.2",
                 "ext-json": "*",
                 "league/uri": "^6.0",
-                "league/uri-components": "^2.1",
-                "php": "^7.1",
+                "php": ">=7.2",
                 "psr/http-client": "^1.0",
                 "psr/http-factory": "^1.0",
                 "psr/log": "^1.1"
@@ -8658,14 +8562,6 @@
                 "web-token/jwt-signature-algorithm-ecdsa": "Mandatory for fetching Metadata Statement from distant sources"
             },
             "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "v2.1": "2.1.x-dev",
-                    "v3.0": "3.0.x-dev",
-                    "v3.1": "3.1.x-dev",
-                    "v3.2": "3.2.x-dev"
-                }
-            },
             "autoload": {
                 "psr-4": {
                     "Webauthn\\MetadataService\\": "src/"
@@ -8693,22 +8589,22 @@
                 "webauthn"
             ],
             "support": {
-                "source": "https://github.com/web-auth/webauthn-metadata-service/tree/v3.2.12"
+                "source": "https://github.com/web-auth/webauthn-metadata-service/tree/v3.3.1"
             },
-            "time": "2020-07-21T21:19:41+00:00"
+            "time": "2021-01-09T13:31:01+00:00"
         },
         {
             "name": "web-auth/webauthn-lib",
-            "version": "v3.2.12",
+            "version": "v3.3.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/web-auth/webauthn-lib.git",
-                "reference": "b3df2a171ff224d4a3c2b1e8dfae3212abe722fc"
+                "reference": "e411527a41c1013512fccdfce61681eb36484c77"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/web-auth/webauthn-lib/zipball/b3df2a171ff224d4a3c2b1e8dfae3212abe722fc",
-                "reference": "b3df2a171ff224d4a3c2b1e8dfae3212abe722fc",
+                "url": "https://api.github.com/repos/web-auth/webauthn-lib/zipball/e411527a41c1013512fccdfce61681eb36484c77",
+                "reference": "e411527a41c1013512fccdfce61681eb36484c77",
                 "shasum": ""
             },
             "require": {
@@ -8716,7 +8612,8 @@
                 "ext-json": "*",
                 "ext-mbstring": "*",
                 "ext-openssl": "*",
-                "php": "^7.2",
+                "fgrosse/phpasn1": "^2.1",
+                "php": ">=7.2",
                 "psr/http-client": "^1.0",
                 "psr/http-factory": "^1.0",
                 "psr/http-message": "^1.0",
@@ -8725,6 +8622,7 @@
                 "spomky-labs/base64url": "^2.0",
                 "spomky-labs/cbor-php": "^1.1|^2.0",
                 "symfony/process": "^3.0|^4.0|^5.0",
+                "thecodingmachine/safe": "^1.1",
                 "web-auth/cose-lib": "self.version",
                 "web-auth/metadata-service": "self.version"
             },
@@ -8736,18 +8634,6 @@
                 "web-token/jwt-signature-algorithm-rsa": "Mandatory for the AndroidSafetyNet Attestation Statement support"
             },
             "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "v1.0": "1.0.x-dev",
-                    "v1.1": "1.1.x-dev",
-                    "v1.2": "1.2.x-dev",
-                    "v2.0": "2.0.x-dev",
-                    "v2.1": "2.1.x-dev",
-                    "v3.0": "3.0.x-dev",
-                    "v3.1": "3.1.x-dev",
-                    "v3.2": "3.2.x-dev"
-                }
-            },
             "autoload": {
                 "psr-4": {
                     "Webauthn\\": "src/"
@@ -8775,7 +8661,7 @@
                 "webauthn"
             ],
             "support": {
-                "source": "https://github.com/web-auth/webauthn-lib/tree/v3.2.12"
+                "source": "https://github.com/web-auth/webauthn-lib/tree/v3.3.1"
             },
             "funding": [
                 {
@@ -8787,20 +8673,20 @@
                     "type": "patreon"
                 }
             ],
-            "time": "2020-08-31T19:42:44+00:00"
+            "time": "2021-01-09T13:31:01+00:00"
         },
         {
             "name": "web-token/jwt-core",
-            "version": "v2.2.6",
+            "version": "v2.2.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/web-token/jwt-core.git",
-                "reference": "8115d846f3a9ee817dca03024eb4c17a3c0ff81a"
+                "reference": "e68c4940da62682426e78eafb1e3a3ba4c7cbabe"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/web-token/jwt-core/zipball/8115d846f3a9ee817dca03024eb4c17a3c0ff81a",
-                "reference": "8115d846f3a9ee817dca03024eb4c17a3c0ff81a",
+                "url": "https://api.github.com/repos/web-token/jwt-core/zipball/e68c4940da62682426e78eafb1e3a3ba4c7cbabe",
+                "reference": "e68c4940da62682426e78eafb1e3a3ba4c7cbabe",
                 "shasum": ""
             },
             "require": {
@@ -8814,20 +8700,7 @@
             "conflict": {
                 "spomky-labs/jose": "*"
             },
-            "require-dev": {
-                "phpunit/phpunit": "^8.0"
-            },
             "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "v1.0": "1.0.x-dev",
-                    "v1.1": "1.1.x-dev",
-                    "v1.2": "1.2.x-dev",
-                    "v1.3": "1.3.x-dev",
-                    "v2.0": "2.0.x-dev",
-                    "v2.1": "2.1.x-dev"
-                }
-            },
             "autoload": {
                 "psr-4": {
                     "Jose\\Component\\Core\\": ""
@@ -8868,7 +8741,7 @@
                 "symfony"
             ],
             "support": {
-                "source": "https://github.com/web-token/jwt-core/tree/v2.2.6"
+                "source": "https://github.com/web-token/jwt-core/tree/v2.2.7"
             },
             "funding": [
                 {
@@ -8876,28 +8749,25 @@
                     "type": "patreon"
                 }
             ],
-            "time": "2020-09-29T21:35:58+00:00"
+            "time": "2020-12-13T16:35:27+00:00"
         },
         {
             "name": "web-token/jwt-signature",
-            "version": "v2.2.6",
+            "version": "v2.2.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/web-token/jwt-signature.git",
-                "reference": "f4d83f77031c9d27edebbea053931074030d3b09"
+                "reference": "cad4f3c51d9e3537c5f45f26ae2c61d08fd5ffd2"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/web-token/jwt-signature/zipball/f4d83f77031c9d27edebbea053931074030d3b09",
-                "reference": "f4d83f77031c9d27edebbea053931074030d3b09",
+                "url": "https://api.github.com/repos/web-token/jwt-signature/zipball/cad4f3c51d9e3537c5f45f26ae2c61d08fd5ffd2",
+                "reference": "cad4f3c51d9e3537c5f45f26ae2c61d08fd5ffd2",
                 "shasum": ""
             },
             "require": {
                 "web-token/jwt-core": "^2.1"
             },
-            "require-dev": {
-                "phpunit/phpunit": "^8.0"
-            },
             "suggest": {
                 "web-token/jwt-signature-algorithm-ecdsa": "ECDSA Based Signature Algorithms",
                 "web-token/jwt-signature-algorithm-eddsa": "EdDSA Based Signature Algorithms",
@@ -8907,16 +8777,6 @@
                 "web-token/jwt-signature-algorithm-rsa": "RSA Based Signature Algorithms"
             },
             "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "v1.0": "1.0.x-dev",
-                    "v1.1": "1.1.x-dev",
-                    "v1.2": "1.2.x-dev",
-                    "v1.3": "1.3.x-dev",
-                    "v2.0": "2.0.x-dev",
-                    "v2.1": "2.1.x-dev"
-                }
-            },
             "autoload": {
                 "psr-4": {
                     "Jose\\Component\\Signature\\": ""
@@ -8957,7 +8817,7 @@
                 "symfony"
             ],
             "support": {
-                "source": "https://github.com/web-token/jwt-signature/tree/v2.2.0"
+                "source": "https://github.com/web-token/jwt-signature/tree/v2.2.7"
             },
             "funding": [
                 {
@@ -8965,7 +8825,7 @@
                     "type": "patreon"
                 }
             ],
-            "time": "2020-08-01T11:48:26+00:00"
+            "time": "2020-12-13T16:35:27+00:00"
         },
         {
             "name": "webmozart/assert",

+ 3 - 3
config/version.yml

@@ -3,11 +3,11 @@ blade-directive: version
 current:
   label: v
   major: 0
-  minor: 6
-  patch: 2
+  minor: 7
+  patch: 0
   prerelease: ''
   buildmetadata: ''
-  commit: 660bf1
+  commit: e19ac3
   timestamp:
     year: 2020
     month: 10

Plik diff jest za duży
+ 542 - 203
package-lock.json


+ 11 - 9
package.json

@@ -2,29 +2,31 @@
     "private": true,
     "scripts": {
         "dev": "npm run development",
-        "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
-        "watch": "npm run development -- --watch",
-        "watch-poll": "npm run watch -- --watch-poll",
-        "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
+        "development": "mix",
+        "watch": "mix watch",
+        "watch-poll": "mix watch -- --watch-options-poll=1000",
+        "hot": "mix watch --hot",
         "prod": "npm run production",
-        "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
+        "production": "mix --production",
         "format": "prettier --write 'resources/**/*.{css,js,vue}'"
     },
     "dependencies": {
-        "autoprefixer": "^9.8.6",
+        "autoprefixer": "^10.0.2",
         "axios": "^0.21.1",
         "cross-env": "^7.0.3",
         "dayjs": "^1.10.2",
-        "laravel-mix": "^5.0.9",
+        "laravel-mix": "^6.0.6",
         "lodash": "^4.17.20",
         "portal-vue": "^2.1.7",
-        "postcss": "^7.0.35",
+        "postcss": "^8.1.14",
+        "postcss-import": "^12.0.1",
         "resolve-url-loader": "^3.1.2",
-        "tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.0.2",
+        "tailwindcss": "^2.0.1",
         "tippy.js": "^6.2.7",
         "v-clipboard": "^2.2.3",
         "vue": "^2.6.12",
         "vue-good-table": "^2.21.2",
+        "vue-loader": "^15.9.6",
         "vue-multiselect": "^2.1.6",
         "vue-notification": "^1.3.20",
         "vue-template-compiler": "^2.6.12",

+ 1 - 1
resources/js/app.js

@@ -9,7 +9,7 @@ dayjs.extend(advancedFormat)
 dayjs.extend(relativeTime)
 dayjs.extend(utc)
 
-window.Vue = require('vue')
+import Vue from 'vue'
 
 import PortalVue from 'portal-vue'
 import Clipboard from 'v-clipboard'

+ 38 - 0
resources/views/settings/show.blade.php

@@ -246,6 +246,8 @@
 
                     <div class="mt-4 w-24 border-b-2 border-grey-200"></div>
 
+                    <p class="mt-6">Ensure your account is using a long, random, unique password to stay secure. It is recommended to use a password manager such as BitWarden. Updating your password will also logout your active sessions on other browsers and devices.</p>
+
                     <div class="mt-6 flex flex-wrap mb-4">
                         <label for="current" class="block text-grey-700 text-sm mb-2">
                             {{ __('Current Password') }}:
@@ -290,6 +292,42 @@
 
             </form>
 
+            <form id="logout-browser-sessions" method="POST" action="{{ route('browser-sessions.destroy') }}" class="pt-16">
+                @method('DELETE')
+                @csrf
+
+                <div class="mb-6">
+
+                    <h3 class="font-bold text-xl">
+                        Browser Sessions
+                    </h3>
+
+                    <div class="mt-4 w-24 border-b-2 border-grey-200"></div>
+
+                    <p class="mt-6">If necessary, you may logout of all of your other browser sessions across all of your devices. If you feel your account has been compromised, you should also update your password.</p>
+
+                    <div class="mt-6 flex flex-wrap mb-4">
+                        <label for="current" class="block text-grey-700 text-sm mb-2">
+                            {{ __('Current Password') }}:
+                        </label>
+
+                        <input id="current" type="password" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:ring{{ $errors->has('current_password_sesssions') ? ' border-red-500' : '' }}" name="current_password_sesssions" placeholder="********" required>
+
+                        @if ($errors->has('current_password_sesssions'))
+                            <p class="text-red-500 text-xs italic mt-4">
+                                {{ $errors->first('current_password_sesssions') }}
+                            </p>
+                        @endif
+                    </div>
+
+                </div>
+
+                <button type="submit" class="bg-cyan-400 w-full hover:bg-cyan-300 text-cyan-900 font-bold py-3 px-4 rounded focus:outline-none">
+                    {{ __('Logout Other Browser Sessions') }}
+                </button>
+
+            </form>
+
         </div>
 
         <div class="mb-4">

+ 2 - 0
routes/web.php

@@ -74,6 +74,8 @@ Route::group([
 
     Route::post('/password', 'PasswordController@update')->name('settings.password');
 
+    Route::delete('/browser-sessions', 'BrowserSessionController@destroy')->name('browser-sessions.destroy');
+
     Route::post('/2fa/enable', 'Auth\TwoFactorAuthController@store')->name('settings.2fa_enable');
     Route::post('/2fa/regenerate', 'Auth\TwoFactorAuthController@update')->name('settings.2fa_regenerate');
     Route::post('/2fa/disable', 'Auth\TwoFactorAuthController@destroy')->name('settings.2fa_disable');

+ 1 - 1
tests/Feature/Api/ApiTokensTest.php

@@ -20,7 +20,7 @@ class ApiTokensTest extends TestCase
         parent::setUp();
 
         $this->user = User::factory()->create();
-        Passport::actingAs($this->user, []);
+        Passport::actingAs($this->user, [], 'web');
         $this->user->recipients()->save($this->user->defaultRecipient);
 
         $clientRepository = new ClientRepository();

+ 7 - 2
webpack.mix.js

@@ -1,9 +1,14 @@
-let mix = require('laravel-mix')
+const mix = require('laravel-mix')
 
 mix
   .js('resources/js/app.js', 'public/js')
+  .vue()
   .js('resources/js/webauthn.js', 'public/js')
-  .postCss('resources/css/app.css', 'public/css', [require('tailwindcss')])
+  .postCss('resources/css/app.css', 'public/css', [
+    require('postcss-import'),
+    require('tailwindcss'),
+    require('autoprefixer'),
+  ])
 
 if (mix.inProduction()) {
   mix.version()

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików