Преглед изворни кода

Merge pull request #162 from simple-login/fido-beta

Add Fido as a beta feature
Son Nguyen Kim пре 5 година
родитељ
комит
f5efab940c

+ 1 - 12
README.md

@@ -1160,18 +1160,7 @@ Whenever the model changes, a new migration has to be created.
 If you have Docker installed, you can create the migration by the following script: 
 
 ```bash
-# create a postgres database for SimpleLogin
-docker rm -f sl-db
-docker run -p 5432:5432 --name sl-db -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=sl -d postgres
-
-# run run `flask db upgrade` to upgrade the DB to the latest stage and
-env DB_URI=postgresql://postgres:postgres@127.0.0.1:5432/sl flask db upgrade
-
-# finally `flask db migrate` to generate the migration script.
-env DB_URI=postgresql://postgres:postgres@127.0.0.1:5432/sl flask db migrate
-
-# remove the db
-docker rm -f sl-db
+sh new_migration.sh 
 ```
 
 Make sure to review the migration script before committing it. 

+ 1 - 1
app/auth/views/fido.py

@@ -31,7 +31,7 @@ def fido():
 
     user = User.get(user_id)
 
-    if not (user and (user.fido_enabled())):
+    if not (user and user.fido_enabled()):
         flash("Only user with security key linked should go to this page", "warning")
         return redirect(url_for("auth.login"))
 

+ 16 - 13
app/dashboard/templates/dashboard/setting.html

@@ -85,22 +85,25 @@
     </div>
     <!-- END change name & profile picture -->
 
-    <div class="card">
-      <div class="card-body">
-        <div class="card-title">Security Key (WebAuthn)</div>
-        <div class="mb-3">
-          You can secure your account by linking either your FIDO-supported physical key such as Yubikey, Google Titan,
-          or a device with appropriate hardware to your account.
+    {% if current_user.can_use_fido %}
+      <div class="card">
+        <div class="card-body">
+          <div class="card-title">Security Key (WebAuthn)</div>
+          <div class="mb-3">
+            You can secure your account by linking either your FIDO-supported physical key such as Yubikey, Google
+            Titan,
+            or a device with appropriate hardware to your account.
+          </div>
+          {% if current_user.fido_uuid is none %}
+            <a href="{{ url_for('dashboard.fido_setup') }}" class="btn btn-outline-primary">Setup WebAuthn</a>
+          {% else %}
+            <a href="{{ url_for('dashboard.fido_cancel') }}" class="btn btn-outline-danger">Disable WebAuthn</a>
+          {% endif %}
         </div>
-        {% if current_user.fido_uuid is none %}
-          <a href="{{ url_for('dashboard.fido_setup') }}" class="btn btn-outline-primary">Setup WebAuthn</a>
-        {% else %}
-          <a href="{{ url_for('dashboard.fido_cancel') }}" class="btn btn-outline-danger">Disable WebAuthn</a>
-        {% endif %}
       </div>
-    </div>
+    {% endif %}
 
-    <div class="card">
+    <div class="card" id="totp">
       <div class="card-body">
         <div class="card-title">One-Time Password (TOTP)</div>
         <div class="mb-3">

+ 7 - 0
app/dashboard/views/fido_setup.py

@@ -25,6 +25,13 @@ def fido_setup():
         flash("You have already registered your security key", "warning")
         return redirect(url_for("dashboard.index"))
 
+    if not current_user.can_use_fido:
+        flash(
+            "This feature is currently in invitation-only beta. Please send us an email if you want to try",
+            "warning",
+        )
+        return redirect(url_for("dashboard.index"))
+
     fido_token_form = FidoTokenForm()
 
     # Handling POST requests

+ 6 - 1
app/models.py

@@ -140,8 +140,13 @@ class User(db.Model, ModelMixin, UserMixin):
     fido_pk = db.Column(db.String(), nullable=True, unique=True)
     fido_sign_count = db.Column(db.Integer(), nullable=True)
 
+    # whether user can use Fido
+    can_use_fido = db.Column(
+        db.Boolean, default=False, nullable=False, server_default="0"
+    )
+
     def fido_enabled(self) -> bool:
-        if self.fido_uuid is not None:
+        if self.can_use_fido and self.fido_uuid is not None:
             return True
         return False
 

+ 2 - 0
app/paddle_utils.py

@@ -10,11 +10,13 @@ import collections
 import phpserialize
 import requests
 from Crypto.Hash import SHA1
+
 # Crypto can be found at https://pypi.org/project/pycryptodome/
 from Crypto.PublicKey import RSA
 from Crypto.Signature import PKCS1_v1_5
 
 from app.config import PADDLE_PUBLIC_KEY_PATH, PADDLE_VENDOR_ID, PADDLE_AUTH_CODE
+
 # Your Paddle public key.
 from app.log import LOG
 

+ 43 - 0
migrations/versions/2020_050717_026e7a782ed6_.py

@@ -0,0 +1,43 @@
+"""empty message
+
+Revision ID: 026e7a782ed6
+Revises: ae94fe5c4e9f
+Create Date: 2020-05-07 17:51:48.440962
+
+"""
+import sqlalchemy_utils
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision = '026e7a782ed6'
+down_revision = 'ae94fe5c4e9f'
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+    # ### commands auto generated by Alembic - please adjust! ###
+    op.add_column('users', sa.Column('can_use_fido', sa.Boolean(), server_default='0', nullable=False))
+    op.add_column('users', sa.Column('fido_credential_id', sa.String(), nullable=True))
+    op.add_column('users', sa.Column('fido_pk', sa.String(), nullable=True))
+    op.add_column('users', sa.Column('fido_sign_count', sa.Integer(), nullable=True))
+    op.add_column('users', sa.Column('fido_uuid', sa.String(), nullable=True))
+    op.create_unique_constraint(None, 'users', ['fido_credential_id'])
+    op.create_unique_constraint(None, 'users', ['fido_pk'])
+    op.create_unique_constraint(None, 'users', ['fido_uuid'])
+    # ### end Alembic commands ###
+
+
+def downgrade():
+    # ### commands auto generated by Alembic - please adjust! ###
+    op.drop_constraint(None, 'users', type_='unique')
+    op.drop_constraint(None, 'users', type_='unique')
+    op.drop_constraint(None, 'users', type_='unique')
+    op.drop_column('users', 'fido_uuid')
+    op.drop_column('users', 'fido_sign_count')
+    op.drop_column('users', 'fido_pk')
+    op.drop_column('users', 'fido_credential_id')
+    op.drop_column('users', 'can_use_fido')
+    # ### end Alembic commands ###

+ 16 - 0
new_migration.sh

@@ -0,0 +1,16 @@
+# Generate a new migration script using Docker
+# To run it:
+# sh new_migration.sh
+
+# create a postgres database for SimpleLogin
+docker rm -f sl-db
+docker run -p 5432:5432 --name sl-db -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=sl -d postgres
+
+# run run `flask db upgrade` to upgrade the DB to the latest stage and
+env DB_URI=postgresql://postgres:postgres@127.0.0.1:5432/sl flask db upgrade
+
+# finally `flask db migrate` to generate the migration script.
+env DB_URI=postgresql://postgres:postgres@127.0.0.1:5432/sl flask db migrate
+
+# remove the db
+docker rm -f sl-db

+ 1 - 1
templates/emails/com/welcome.html

@@ -13,7 +13,7 @@
 {% block content %}
   {{ render_text("My name is Son. I’m the founder of SimpleLogin and I wanted to be the first to welcome you on board.") }}
 
-  {{ render_text('To better secure your account, I recommend enabling Multi-Factor Authentication (MFA) on your <a href="https://app.simplelogin.io/dashboard/setting">Setting page</a>.') }}
+  {{ render_text('To better secure your account, I recommend enabling Multi-Factor Authentication (MFA) on your <a href="https://app.simplelogin.io/dashboard/setting/#totp">Setting page</a>.') }}
 
   {{ render_text('If you have any feedback or improvement ideas please let me know by simply replying to this email. Yes, this email is not sent from a no-reply address.
 ') }}