mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-02-06 03:13:42 -05:00
@@ -9,6 +9,7 @@ from flask_wtf import CsrfProtect
|
||||
from webassets.filter import get_filter
|
||||
from werkzeug.exceptions import abort
|
||||
|
||||
from app.notify_client.api_client import AdminAPIClient
|
||||
from app.its_dangerous_session import ItsdangerousSessionInterface
|
||||
import app.proxy_fix
|
||||
from config import configs
|
||||
@@ -18,6 +19,8 @@ db = SQLAlchemy()
|
||||
login_manager = LoginManager()
|
||||
csrf = CsrfProtect()
|
||||
|
||||
admin_api_client = AdminAPIClient()
|
||||
|
||||
|
||||
def create_app(config_name):
|
||||
application = Flask(__name__)
|
||||
@@ -37,6 +40,7 @@ def create_app(config_name):
|
||||
proxy_fix.init_app(application)
|
||||
|
||||
application.session_interface = ItsdangerousSessionInterface()
|
||||
admin_api_client.init_app(application)
|
||||
|
||||
return application
|
||||
|
||||
|
||||
5
app/main/exceptions.py
Normal file
5
app/main/exceptions.py
Normal file
@@ -0,0 +1,5 @@
|
||||
|
||||
|
||||
class AdminApiClientException(Exception):
|
||||
def __init__(self, message):
|
||||
self.value = message
|
||||
@@ -15,19 +15,16 @@ def govuk():
|
||||
|
||||
|
||||
@main.route("/register-from-invite")
|
||||
@login_required
|
||||
def registerfrominvite():
|
||||
return render_template('register-from-invite.html')
|
||||
|
||||
|
||||
@main.route("/verify")
|
||||
@login_required
|
||||
def verify():
|
||||
return render_template('verify.html')
|
||||
|
||||
|
||||
@main.route("/verify-mobile")
|
||||
@login_required
|
||||
def verifymobile():
|
||||
return render_template('verify-mobile.html')
|
||||
|
||||
@@ -50,7 +47,6 @@ def addservice():
|
||||
|
||||
|
||||
@main.route("/two-factor")
|
||||
@login_required
|
||||
def twofactor():
|
||||
return render_template('two-factor.html')
|
||||
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta
|
||||
from random import randint
|
||||
|
||||
from flask import render_template, redirect, jsonify
|
||||
from flask_login import login_user
|
||||
from flask import render_template, redirect, jsonify, session
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
|
||||
from app import admin_api_client
|
||||
from app.main import main
|
||||
from app.main.dao import users_dao
|
||||
from app.main.encryption import hashpw
|
||||
from app.main.exceptions import AdminApiClientException
|
||||
from app.main.forms import RegisterUserForm
|
||||
from app.models import User
|
||||
|
||||
@@ -26,10 +30,43 @@ def process_register():
|
||||
created_at=datetime.now(),
|
||||
role_id=1)
|
||||
try:
|
||||
sms_code = send_sms_code(form.mobile_number.data)
|
||||
email_code = send_email_code(form.email_address.data)
|
||||
session['sms_code'] = hashpw(sms_code)
|
||||
session['email_code'] = hashpw(email_code)
|
||||
session['expiry_date'] = str(datetime.now() + timedelta(hours=1))
|
||||
users_dao.insert_user(user)
|
||||
login_user(user)
|
||||
return redirect('/two-factor')
|
||||
except Exception as e:
|
||||
return jsonify(database_error=e.message), 400
|
||||
except AdminApiClientException as e:
|
||||
return jsonify(admin_api_client_error=e.value)
|
||||
except SQLAlchemyError:
|
||||
return jsonify(database_error='encountered database error'), 400
|
||||
else:
|
||||
return jsonify(form.errors), 400
|
||||
return redirect('/verify')
|
||||
|
||||
|
||||
def send_sms_code(mobile_number):
|
||||
sms_code = _create_code()
|
||||
try:
|
||||
admin_api_client.send_sms(mobile_number, message=sms_code, token=admin_api_client.auth_token)
|
||||
except:
|
||||
raise AdminApiClientException('Exception when sending sms.')
|
||||
return sms_code
|
||||
|
||||
|
||||
def send_email_code(email):
|
||||
email_code = _create_code()
|
||||
try:
|
||||
admin_api_client.send_email(email_address=email,
|
||||
from_str='notify@digital.cabinet-office.gov.uk',
|
||||
message=email_code,
|
||||
subject='Verification code',
|
||||
token=admin_api_client.auth_token)
|
||||
except:
|
||||
raise AdminApiClientException('Exception when sending email.')
|
||||
|
||||
return email_code
|
||||
|
||||
|
||||
def _create_code():
|
||||
return ''.join(["%s" % randint(0, 9) for _ in range(0, 5)])
|
||||
|
||||
0
app/notify_client/__init__.py
Normal file
0
app/notify_client/__init__.py
Normal file
8
app/notify_client/api_client.py
Normal file
8
app/notify_client/api_client.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from __future__ import unicode_literals
|
||||
from notify_client import NotifyAPIClient
|
||||
|
||||
|
||||
class AdminAPIClient(NotifyAPIClient):
|
||||
def init_app(self, app):
|
||||
self.base_url = app.config['NOTIFY_DATA_API_URL']
|
||||
self.auth_token = app.config['NOTIFY_DATA_API_AUTH_TOKEN']
|
||||
10
config.py
10
config.py
@@ -1,3 +1,5 @@
|
||||
import os
|
||||
|
||||
|
||||
class Config(object):
|
||||
DEBUG = False
|
||||
@@ -11,6 +13,14 @@ class Config(object):
|
||||
MAX_FAILED_LOGIN_COUNT = 10
|
||||
PASS_SECRET_KEY = 'secret-key-unique-changeme'
|
||||
|
||||
SESSION_COOKIE_NAME = 'notify_admin_session'
|
||||
SESSION_COOKIE_PATH = '/admin'
|
||||
SESSION_COOKIE_HTTPONLY = True
|
||||
SESSION_COOKIE_SECURE = True
|
||||
|
||||
NOTIFY_DATA_API_URL = os.getenv('NOTIFY_API_URL', "http://localhost:6001")
|
||||
NOTIFY_DATA_API_AUTH_TOKEN = os.getenv('NOTIFY_API_TOKEN', "dev-token")
|
||||
|
||||
WTF_CSRF_ENABLED = True
|
||||
SECRET_KEY = 'secret-key'
|
||||
HTTP_PROTOCOL = 'http'
|
||||
|
||||
@@ -8,4 +8,6 @@ SQLAlchemy==1.0.5
|
||||
SQLAlchemy-Utils==0.30.5
|
||||
Flask-WTF==0.11
|
||||
Flask-Login==0.2.11
|
||||
Flask-Bcrypt==0.6.2
|
||||
Flask-Bcrypt==0.6.2
|
||||
|
||||
git+https://github.com/alphagov/notify-api-client.git@0.1.4#egg=notify-api-client==0.1.4
|
||||
@@ -1,3 +1,4 @@
|
||||
-r requirements.txt
|
||||
pep8==1.5.7
|
||||
pytest==2.8.1
|
||||
pytest==2.8.1
|
||||
pytest-mock==0.8.1
|
||||
|
||||
@@ -7,17 +7,22 @@ def test_render_register_returns_template_with_form(notifications_admin, notific
|
||||
assert 'Create an account' in response.get_data(as_text=True)
|
||||
|
||||
|
||||
def test_process_register_creates_new_user(notifications_admin, notifications_admin_db):
|
||||
def test_process_register_creates_new_user(notifications_admin, notifications_admin_db, mocker):
|
||||
_set_up_mocker(mocker)
|
||||
|
||||
response = notifications_admin.test_client().post('/register',
|
||||
data={'name': 'Some One Valid',
|
||||
'email_address': 'someone@example.gov.uk',
|
||||
'mobile_number': '+441231231231',
|
||||
'password': 'validPassword!'})
|
||||
assert response.status_code == 302
|
||||
assert response.location == 'http://localhost/two-factor'
|
||||
assert response.location == 'http://localhost/verify'
|
||||
|
||||
|
||||
def test_process_register_returns_400_when_mobile_number_is_invalid(notifications_admin, notifications_admin_db):
|
||||
def test_process_register_returns_400_when_mobile_number_is_invalid(notifications_admin,
|
||||
notifications_admin_db,
|
||||
mocker):
|
||||
_set_up_mocker(mocker)
|
||||
response = notifications_admin.test_client().post('/register',
|
||||
data={'name': 'Bad Mobile',
|
||||
'email_address': 'bad_mobile@example.gov.uk',
|
||||
@@ -28,7 +33,8 @@ def test_process_register_returns_400_when_mobile_number_is_invalid(notification
|
||||
assert 'Please enter a +44 mobile number' in response.get_data(as_text=True)
|
||||
|
||||
|
||||
def test_should_return_400_when_email_is_not_gov_uk(notifications_admin, notifications_admin_db):
|
||||
def test_should_return_400_when_email_is_not_gov_uk(notifications_admin, notifications_admin_db, mocker):
|
||||
_set_up_mocker(mocker)
|
||||
response = notifications_admin.test_client().post('/register',
|
||||
data={'name': 'Bad Mobile',
|
||||
'email_address': 'bad_mobile@example.not.right',
|
||||
@@ -39,6 +45,23 @@ def test_should_return_400_when_email_is_not_gov_uk(notifications_admin, notific
|
||||
assert 'Please enter a gov.uk email address' in response.get_data(as_text=True)
|
||||
|
||||
|
||||
def test_should_add_verify_codes_on_session(notifications_admin, notifications_admin_db, mocker):
|
||||
_set_up_mocker(mocker)
|
||||
with notifications_admin.test_client() as client:
|
||||
response = client.post('/register',
|
||||
data={'name': 'Test Codes',
|
||||
'email_address': 'test_codes@example.gov.uk',
|
||||
'mobile_number': '+441234567890',
|
||||
'password': 'validPassword!'})
|
||||
assert response.status_code == 302
|
||||
assert 'notify_admin_session' in response.headers.get('Set-Cookie')
|
||||
|
||||
|
||||
def _set_up_mocker(mocker):
|
||||
mocker.patch("app.admin_api_client.send_sms")
|
||||
mocker.patch("app.admin_api_client.send_email")
|
||||
|
||||
|
||||
def test_should_return_400_if_password_is_blacklisted(notifications_admin, notifications_admin_db):
|
||||
response = notifications_admin.test_client().post('/register',
|
||||
data={'name': 'Bad Mobile',
|
||||
|
||||
Reference in New Issue
Block a user