Exemple #1
0
def test_confirmation_different_user_when_logged_in_no_auto(
        client, get_message):
    """ Default - AUTO_LOGIN == false so shouldn't log in second user. """
    e1 = "*****@*****.**"
    e2 = "*****@*****.**"

    with capture_registrations() as registrations:
        for e in e1, e2:
            data = dict(email=e, password="******", next="")
            client.post("/register", data=data)
            logout(client)

    token1 = registrations[0]["confirm_token"]
    token2 = registrations[1]["confirm_token"]

    client.get("/confirm/" + token1, follow_redirects=True)
    logout(client)
    authenticate(client, email=e1)

    response = client.get("/confirm/" + token2, follow_redirects=True)
    assert get_message("EMAIL_CONFIRMED") in response.data
    # should get a login view
    assert (
        b'<input id="password" name="password" required type="password" value="">'
        in response.data)
Exemple #2
0
def test_two_factor_json(app, client, get_message):
    with capture_registrations() as registrations:
        data = dict(email="*****@*****.**", password="******")
        response = client.post("/register",
                               content_type="application/json",
                               data=json.dumps(data))
        assert response.headers["content-type"] == "application/json"
        assert response.jdata["meta"]["code"] == 200
        assert len(response.jdata["response"]) == 2
        assert all(k in response.jdata["response"]
                   for k in ["csrf_token", "user"])

    # make sure not logged in
    response = client.get("/profile", headers={"accept": "application/json"})
    assert response.status_code == 401
    assert response.jdata["response"]["error"].encode("utf-8") == get_message(
        "UNAUTHENTICATED")

    token = registrations[0]["confirm_token"]
    response = client.get("/confirm/" + token,
                          headers={"Accept": "application/json"})

    assert response.status_code == 200
    assert response.jdata["response"]["tf_required"]
    assert response.jdata["response"]["tf_state"] == "setup_from_login"
 def test_confirm_bad_token(self):
     e = '*****@*****.**'
     with capture_registrations():
         self.register(e)
     with capture_signals() as mocks:
         self.client.get('/confirm/bogus', follow_redirects=True)
     self.assertEqual(mocks.signals_sent(), set())
Exemple #4
0
 def test_confirm_bad_token(self):
     e = '*****@*****.**'
     with capture_registrations():
         self.register(e)
     with capture_signals() as mocks:
         self.client.get('/confirm/bogus', follow_redirects=True)
     self.assertEqual(mocks.signals_sent(), set())
Exemple #5
0
def test_spa_get(app, client):
    """
    Test 'single-page-application' style redirects
    This uses json only.
    """
    with capture_flashes() as flashes:
        with capture_registrations() as registrations:
            response = client.post(
                "/register",
                data='{"email": "*****@*****.**",\
                                         "password": "******"}',
                headers={"Content-Type": "application/json"},
            )
            assert response.headers["Content-Type"] == "application/json"
        token = registrations[0]["confirm_token"]

        response = client.get("/confirm/" + token)
        assert response.status_code == 302
        split = urlsplit(response.headers["Location"])
        assert "localhost:8081" == split.netloc
        assert "/confirm-redirect" == split.path
        qparams = dict(parse_qsl(split.query))
        assert qparams["email"] == "*****@*****.**"
    # Arguably for json we shouldn't have any - this is buried in register_user
    # but really shouldn't be.
    assert len(flashes) == 1
Exemple #6
0
def test_confirm_redirect_to_post_confirm(client, get_message):
    with capture_registrations() as registrations:
        data = dict(email="*****@*****.**", password="******", next="")
        client.post("/register", data=data, follow_redirects=True)

    token = registrations[0]["confirm_token"]

    response = client.get("/confirm/" + token, follow_redirects=True)
    assert b"Post Confirm" in response.data
def test_confirm_redirect_to_post_confirm(client, get_message):
    with capture_registrations() as registrations:
        data = dict(email='*****@*****.**', password='******', next='')
        client.post('/register', data=data, follow_redirects=True)

    token = registrations[0]['confirm_token']

    response = client.get('/confirm/' + token, follow_redirects=True)
    assert b'Post Confirm' in response.data
 def test_confirm_twice(self):
     e = '*****@*****.**'
     with capture_registrations() as registrations:
         self.register(e)
         token = registrations[0]['confirm_token']
     self.client.get('/confirm/' + token, follow_redirects=True)
     self.logout()
     with capture_signals() as mocks:
         self.client.get('/confirm/' + token, follow_redirects=True)
     self.assertEqual(mocks.signals_sent(), set([user_confirmed]))
Exemple #9
0
 def test_confirm_twice(self):
     e = '*****@*****.**'
     with capture_registrations() as registrations:
         self.register(e)
         token = registrations[0]['confirm_token']
     self.client.get('/confirm/' + token, follow_redirects=True)
     self.logout()
     with capture_signals() as mocks:
         self.client.get('/confirm/' + token, follow_redirects=True)
     self.assertEqual(mocks.signals_sent(), set([user_confirmed]))
Exemple #10
0
    def test_send_confirmation_of_already_confirmed_account(self):
        e = '*****@*****.**'

        with capture_registrations() as registrations:
            r = self.register(e)
            token = registrations[0]['confirm_token']

        self.client.get('/confirm/' + token, follow_redirects=True)
        self.logout()
        r = self._post('/confirm', data=dict(email=e))
        m = self.get_message('ALREADY_CONFIRMED')
        self.assertIn(m.encode('utf-8'), r.data)
Exemple #11
0
def test_confirm_redirect(client, get_message):
    with capture_registrations() as registrations:
        data = dict(email="*****@*****.**", password="******", next="")
        client.post("/register", data=data, follow_redirects=True)

    token = registrations[0]["confirm_token"]

    response = client.get("/confirm/" + token)
    assert "location" in response.headers
    assert "/login" in response.location

    response = client.get(response.location)
    assert get_message("EMAIL_CONFIRMED") in response.data
def test_expired_confirmation_token(client, get_message):
    with capture_registrations() as registrations:
        data = dict(email='*****@*****.**', password='******', next='')
        client.post('/register', data=data, follow_redirects=True)

    user = registrations[0]['user']
    token = registrations[0]['confirm_token']

    time.sleep(1)

    response = client.get('/confirm/' + token, follow_redirects=True)
    msg = get_message('CONFIRMATION_EXPIRED', within='1 milliseconds', email=user.email)
    assert msg in response.data
def test_confirm_redirect(client, get_message):
    with capture_registrations() as registrations:
        data = dict(email='*****@*****.**', password='******', next='')
        client.post('/register', data=data, follow_redirects=True)

    token = registrations[0]['confirm_token']

    response = client.get('/confirm/' + token)
    assert 'location' in response.headers
    assert '/login' in response.location

    response = client.get(response.location)
    assert get_message('EMAIL_CONFIRMED') in response.data
 def test_confirm(self):
     e = '*****@*****.**'
     with capture_registrations() as registrations:
         self.register(e)
         token = registrations[0]['confirm_token']
     with capture_signals() as mocks:
         self.client.get('/confirm/' + token, follow_redirects=True)
     user = self.app.security.datastore.find_user(email='*****@*****.**')
     self.assertTrue(mocks.signals_sent(), set([user_confirmed]))
     calls = mocks[user_confirmed]
     self.assertEqual(len(calls), 1)
     args, kwargs = calls[0]
     self.assertEqual(args[0].id, user.id)
     self.assertEqual(kwargs['app'], self.app)
Exemple #15
0
 def test_confirm(self):
     e = '*****@*****.**'
     with capture_registrations() as registrations:
         self.register(e)
         token = registrations[0]['confirm_token']
     with capture_signals() as mocks:
         self.client.get('/confirm/' + token, follow_redirects=True)
     user = self.app.security.datastore.find_user(email='*****@*****.**')
     self.assertTrue(mocks.signals_sent(), set([user_confirmed]))
     calls = mocks[user_confirmed]
     self.assertEqual(len(calls), 1)
     args, kwargs = calls[0]
     self.assertEqual(args[0], self.app)
     self.assertTrue(compare_user(kwargs['user'], user))
 def test_confirm(self):
     e = "*****@*****.**"
     with capture_registrations() as registrations:
         self.register(e)
         token = registrations[0]["confirm_token"]
     with capture_signals() as mocks:
         self.client.get("/confirm/" + token, follow_redirects=True)
     user = self.app.security.datastore.find_user(email="*****@*****.**")
     self.assertTrue(mocks.signals_sent(), set([user_confirmed]))
     calls = mocks[user_confirmed]
     self.assertEqual(len(calls), 1)
     args, kwargs = calls[0]
     self.assertEqual(args[0], self.app)
     self.assertTrue(compare_user(kwargs["user"], user))
def test_expired_confirmation_token(client, get_message):
    with capture_registrations() as registrations:
        data = dict(email='*****@*****.**', password='******', next='')
        client.post('/register', data=data, follow_redirects=True)

    user = registrations[0]['user']
    token = registrations[0]['confirm_token']

    time.sleep(1)

    response = client.get('/confirm/' + token, follow_redirects=True)
    msg = get_message('CONFIRMATION_EXPIRED',
                      within='1 milliseconds',
                      email=user.email)
    assert msg in response.data
Exemple #18
0
def test_expired_confirmation_token(client, get_message):
    with capture_registrations() as registrations:
        data = dict(email="*****@*****.**", password="******", next="")
        client.post("/register", data=data, follow_redirects=True)

    user = registrations[0]["user"]
    token = registrations[0]["confirm_token"]

    time.sleep(1)

    response = client.get("/confirm/" + token, follow_redirects=True)
    msg = get_message("CONFIRMATION_EXPIRED",
                      within="1 milliseconds",
                      email=user.email)
    assert msg in response.data
Exemple #19
0
    def test_user_deleted_before_confirmation(self):
        e = '*****@*****.**'

        with capture_registrations() as registrations:
            self.register(e)
            user = registrations[0]['user']
            token = registrations[0]['confirm_token']

        with self.app.app_context():
            from flask_security.core import _security
            _security.datastore.delete(user)
            _security.datastore.commit()

        r = self.client.get('/confirm/' + token, follow_redirects=True)
        msg = self.app.config['SECURITY_MSG_INVALID_CONFIRMATION_TOKEN'][0]
        self.assertIn(msg.encode('utf-8'), r.data)
Exemple #20
0
def test_two_factor(app, client):
    """ If two-factor is enabled, the confirm shouldn't login, but start the
    2-factor setup.
    """
    with capture_registrations() as registrations:
        data = dict(email="*****@*****.**", password="******", next="")
        client.post("/register", data=data, follow_redirects=True)

    # make sure not logged in
    response = client.get("/profile")
    assert response.status_code == 302
    assert "/login?next=%2Fprofile" in response.location

    token = registrations[0]["confirm_token"]
    response = client.get("/confirm/" + token, follow_redirects=False)
    assert "tf-setup" in response.location
    def test_confirm_email_of_user_different_than_current_user(self):
        e1 = '*****@*****.**'
        e2 = '*****@*****.**'

        with capture_registrations() as registrations:
            self.register(e1)
            self.register(e2)
            token1 = registrations[0]['confirm_token']
            token2 = registrations[1]['confirm_token']

        self.client.get('/confirm/' + token1, follow_redirects=True)
        self.client.get('/logout')
        self.authenticate(email=e1)
        r = self.client.get('/confirm/' + token2, follow_redirects=True)
        m = self.app.config['SECURITY_MSG_EMAIL_CONFIRMED'][0]
        self.assertIn(m.encode('utf-8'), r.data)
        self.assertIn(b'Hello [email protected]', r.data)
Exemple #22
0
def test_spa_get_bad_token(app, client, get_message):
    """ Test expired and invalid token"""
    with capture_flashes() as flashes:
        with capture_registrations() as registrations:
            response = client.post(
                "/register",
                data='{"email": "*****@*****.**",\
                                         "password": "******"}',
                headers={"Content-Type": "application/json"},
            )
            assert response.headers["Content-Type"] == "application/json"
        token = registrations[0]["confirm_token"]
        time.sleep(1)

        response = client.get("/confirm/" + token)
        assert response.status_code == 302
        split = urlsplit(response.headers["Location"])
        assert "localhost:8081" == split.netloc
        assert "/confirm-error" == split.path
        qparams = dict(parse_qsl(split.query))
        assert len(qparams) == 2
        assert all(k in qparams for k in ["email", "error"])

        msg = get_message("CONFIRMATION_EXPIRED",
                          within="1 milliseconds",
                          email="*****@*****.**")
        assert msg == qparams["error"].encode("utf-8")

        # Test mangled token
        token = (
            "WyIxNjQ2MzYiLCIxMzQ1YzBlZmVhM2VhZjYwODgwMDhhZGU2YzU0MzZjMiJd."
            "BZEw_Q.lQyo3npdPZtcJ_sNHVHP103syjM"
            "&url_id=fbb89a8328e58c181ea7d064c2987874bc54a23d")
        response = client.get("/confirm/" + token)
        assert response.status_code == 302
        split = urlsplit(response.headers["Location"])
        assert "localhost:8081" == split.netloc
        assert "/confirm-error" == split.path
        qparams = dict(parse_qsl(split.query))
        assert len(qparams) == 1
        assert all(k in qparams for k in ["error"])

        msg = get_message("INVALID_CONFIRMATION_TOKEN")
        assert msg == qparams["error"].encode("utf-8")
    assert len(flashes) == 1
Exemple #23
0
    def test_confirm_email_of_user_different_than_current_user(self):
        e1 = '*****@*****.**'
        e2 = '*****@*****.**'

        with capture_registrations() as registrations:
            self.register(e1)
            self.logout()
            self.register(e2)
            token1 = registrations[0]['confirm_token']
            token2 = registrations[1]['confirm_token']

        self.client.get('/confirm/' + token1, follow_redirects=True)
        self.client.get('/logout')
        self.authenticate(email=e1)
        r = self.client.get('/confirm/' + token2, follow_redirects=True)
        m = self.app.config['SECURITY_MSG_EMAIL_CONFIRMED'][0]
        self.assertIn(m.encode('utf-8'), r.data)
        self.assertIn(b'Hello [email protected]', r.data)
Exemple #24
0
def test_email_conflict_for_confirmation_token(app, client, get_message,
                                               sqlalchemy_datastore):
    with capture_registrations() as registrations:
        data = dict(email="*****@*****.**", password="******", next="")
        client.post("/register", data=data, follow_redirects=True)

    user = registrations[0]["user"]
    token = registrations[0]["confirm_token"]

    # Change the user's email
    user.email = "*****@*****.**"
    with app.app_context():
        sqlalchemy_datastore.put(user)
        sqlalchemy_datastore.commit()

    response = client.get("/confirm/" + token, follow_redirects=True)
    msg = get_message("INVALID_CONFIRMATION_TOKEN")
    assert msg in response.data
def test_email_conflict_for_confirmation_token(app, client, get_message,
                                               sqlalchemy_datastore):
    with capture_registrations() as registrations:
        data = dict(email='*****@*****.**', password='******', next='')
        client.post('/register', data=data, follow_redirects=True)

    user = registrations[0]['user']
    token = registrations[0]['confirm_token']

    # Change the user's email
    user.email = '*****@*****.**'
    with app.app_context():
        sqlalchemy_datastore.put(user)
        sqlalchemy_datastore.commit()

    response = client.get('/confirm/' + token, follow_redirects=True)
    msg = get_message('INVALID_CONFIRMATION_TOKEN')
    assert msg in response.data
def test_email_conflict_for_confirmation_token(app, client, get_message,
                                               sqlalchemy_datastore):
    with capture_registrations() as registrations:
        data = dict(email='*****@*****.**', password='******', next='')
        client.post('/register', data=data, follow_redirects=True)

    user = registrations[0]['user']
    token = registrations[0]['confirm_token']

    # Change the user's email
    user.email = '*****@*****.**'
    with app.app_context():
        sqlalchemy_datastore.put(user)
        sqlalchemy_datastore.commit()

    response = client.get('/confirm/' + token, follow_redirects=True)
    msg = get_message('INVALID_CONFIRMATION_TOKEN')
    assert msg in response.data
def test_confirmation_different_user_when_logged_in(client, get_message):
    e1 = '*****@*****.**'
    e2 = '*****@*****.**'

    with capture_registrations() as registrations:
        for e in e1, e2:
            client.post('/register', data=dict(email=e, password='******'))
            logout(client)

    token1 = registrations[0]['confirm_token']
    token2 = registrations[1]['confirm_token']

    client.get('/confirm/' + token1, follow_redirects=True)
    logout(client)
    authenticate(client, email=e1)

    response = client.get('/confirm/' + token2, follow_redirects=True)
    assert get_message('EMAIL_CONFIRMED') in response.data
    assert b'Hello [email protected]' in response.data
def test_confirmation_different_user_when_logged_in(client, get_message):
    e1 = '*****@*****.**'
    e2 = '*****@*****.**'

    with capture_registrations() as registrations:
        for e in e1, e2:
            client.post('/register', data=dict(email=e, password='******'))
            logout(client)

    token1 = registrations[0]['confirm_token']
    token2 = registrations[1]['confirm_token']

    client.get('/confirm/' + token1, follow_redirects=True)
    logout(client)
    authenticate(client, email=e1)

    response = client.get('/confirm/' + token2, follow_redirects=True)
    assert get_message('EMAIL_CONFIRMED') in response.data
    assert b'Hello [email protected]' in response.data
Exemple #29
0
    def test_expired_confirmation_token_sends_email(self):
        e = '*****@*****.**'

        with capture_registrations() as registrations:
            self.register(e)
            token = registrations[0]['confirm_token']

        time.sleep(1.25)

        with self.app.extensions['mail'].record_messages() as outbox:
            r = self.client.get('/confirm/' + token, follow_redirects=True)

            self.assertEqual(len(outbox), 1)
            self.assertNotIn(token, outbox[0].html)

            expire_text = self.AUTH_CONFIG['SECURITY_CONFIRM_EMAIL_WITHIN']
            msg = self.app.config['SECURITY_MSG_CONFIRMATION_EXPIRED'][0]
            msg = msg % dict(within=expire_text, email=e)
            self.assertIn(msg.encode('utf-8'), r.data)
Exemple #30
0
def test_confirmation_different_user_when_logged_in(client, get_message):
    e1 = "*****@*****.**"
    e2 = "*****@*****.**"

    with capture_registrations() as registrations:
        for e in e1, e2:
            data = dict(email=e, password="******", next="")
            client.post("/register", data=data)
            logout(client)

    token1 = registrations[0]["confirm_token"]
    token2 = registrations[1]["confirm_token"]

    client.get("/confirm/" + token1, follow_redirects=True)
    logout(client)
    authenticate(client, email=e1)

    response = client.get("/confirm/" + token2, follow_redirects=True)
    assert get_message("EMAIL_CONFIRMED") in response.data
    assert b"Welcome [email protected]" in response.data
Exemple #31
0
def test_confirmable_flag(app, client, sqlalchemy_datastore, get_message):
    recorded_confirms = []
    recorded_instructions_sent = []

    @user_confirmed.connect_via(app)
    def on_confirmed(app, user):
        assert isinstance(app, Flask)
        assert isinstance(user, UserMixin)
        recorded_confirms.append(user)

    @confirm_instructions_sent.connect_via(app)
    def on_instructions_sent(app, user, token):
        assert isinstance(app, Flask)
        assert isinstance(user, UserMixin)
        assert isinstance(token, string_types)
        recorded_instructions_sent.append(user)

    # Test login before confirmation
    email = "*****@*****.**"

    with capture_registrations() as registrations:
        data = dict(email=email, password="******", next="")
        response = client.post("/register", data=data)

    assert response.status_code == 302

    response = authenticate(client, email=email)
    assert get_message("CONFIRMATION_REQUIRED") in response.data

    # Test invalid token
    response = client.get("/confirm/bogus", follow_redirects=True)
    assert get_message("INVALID_CONFIRMATION_TOKEN") in response.data

    # Test JSON
    response = client.post(
        "/confirm",
        data='{"email": "*****@*****.**"}',
        headers={"Content-Type": "application/json"},
    )
    assert response.status_code == 200
    assert response.headers["Content-Type"] == "application/json"
    assert "user" in response.jdata["response"]
    assert len(recorded_instructions_sent) == 1

    # Test ask for instructions with invalid email
    response = client.post("/confirm", data=dict(email="*****@*****.**"))
    assert get_message("USER_DOES_NOT_EXIST") in response.data

    # Test resend instructions
    response = client.post("/confirm", data=dict(email=email))
    assert get_message("CONFIRMATION_REQUEST", email=email) in response.data
    assert len(recorded_instructions_sent) == 2

    # Test confirm
    token = registrations[0]["confirm_token"]
    response = client.get("/confirm/" + token, follow_redirects=True)
    assert get_message("EMAIL_CONFIRMED") in response.data
    assert len(recorded_confirms) == 1

    # Test already confirmed
    response = client.get("/confirm/" + token, follow_redirects=True)
    assert get_message("ALREADY_CONFIRMED") in response.data
    assert len(recorded_instructions_sent) == 2

    # Test already confirmed and expired token
    app.config["SECURITY_CONFIRM_EMAIL_WITHIN"] = "-1 days"
    with app.app_context():
        user = registrations[0]["user"]
        expired_token = generate_confirmation_token(user)
    response = client.get("/confirm/" + expired_token, follow_redirects=True)
    assert get_message("ALREADY_CONFIRMED") in response.data
    assert len(recorded_instructions_sent) == 2

    # Test already confirmed when asking for confirmation instructions
    logout(client)

    response = client.get("/confirm")
    assert response.status_code == 200

    response = client.post("/confirm", data=dict(email=email))
    assert get_message("ALREADY_CONFIRMED") in response.data

    # Test user was deleted before confirmation
    with capture_registrations() as registrations:
        data = dict(email="*****@*****.**", password="******", next="")
        client.post("/register", data=data)

    user = registrations[0]["user"]
    token = registrations[0]["confirm_token"]

    with app.app_context():
        sqlalchemy_datastore.delete(user)
        sqlalchemy_datastore.commit()

    response = client.get("/confirm/" + token, follow_redirects=True)
    assert get_message("INVALID_CONFIRMATION_TOKEN") in response.data
def test_confirmable_flag(app, client, sqlalchemy_datastore, get_message):
    recorded_confirms = []
    recorded_instructions_sent = []

    @user_confirmed.connect_via(app)
    def on_confirmed(app, user):
        recorded_confirms.append(user)

    @confirm_instructions_sent.connect_via(app)
    def on_instructions_sent(app, user):
        recorded_instructions_sent.append(user)

    # Test login before confirmation
    email = '*****@*****.**'

    with capture_registrations() as registrations:
        data = dict(email=email, password='******', next='')
        response = client.post('/register', data=data)

    assert response.status_code == 302

    response = authenticate(client, email=email)
    assert get_message('CONFIRMATION_REQUIRED') in response.data

    # Test invalid token
    response = client.get('/confirm/bogus', follow_redirects=True)
    assert get_message('INVALID_CONFIRMATION_TOKEN') in response.data

    # Test JSON
    response = client.post('/confirm', data='{"email": "*****@*****.**"}', headers={
        'Content-Type': 'application/json'
    })
    assert response.status_code == 200
    assert response.headers['Content-Type'] == 'application/json'
    assert 'user' in response.jdata['response']
    assert len(recorded_instructions_sent) == 1

    # Test ask for instructions with invalid email
    response = client.post('/confirm', data=dict(email='*****@*****.**'))
    assert get_message('USER_DOES_NOT_EXIST') in response.data

    # Test resend instructions
    response = client.post('/confirm', data=dict(email=email))
    assert get_message('CONFIRMATION_REQUEST', email=email) in response.data
    assert len(recorded_instructions_sent) == 2

    # Test confirm
    token = registrations[0]['confirm_token']
    response = client.get('/confirm/' + token, follow_redirects=True)
    assert get_message('EMAIL_CONFIRMED') in response.data
    assert len(recorded_confirms) == 1

    # Test already confirmed
    response = client.get('/confirm/' + token, follow_redirects=True)
    assert get_message('ALREADY_CONFIRMED') in response.data

    # Test already confirmed when asking for confirmation instructions
    logout(client)

    response = client.get('/confirm')
    assert response.status_code == 200

    response = client.post('/confirm', data=dict(email=email))
    assert get_message('ALREADY_CONFIRMED') in response.data

    # Test user was deleted before confirmation
    with capture_registrations() as registrations:
        data = dict(email='*****@*****.**', password='******', next='')
        client.post('/register', data=data)

    user = registrations[0]['user']
    token = registrations[0]['confirm_token']

    with app.app_context():
        sqlalchemy_datastore.delete(user)
        sqlalchemy_datastore.commit()

    response = client.get('/confirm/' + token, follow_redirects=True)
    assert get_message('INVALID_CONFIRMATION_TOKEN') in response.data
def test_confirmable_flag(app, client, sqlalchemy_datastore, get_message):
    recorded_confirms = []
    recorded_instructions_sent = []

    @user_confirmed.connect_via(app)
    def on_confirmed(app, user):
        recorded_confirms.append(user)

    @confirm_instructions_sent.connect_via(app)
    def on_instructions_sent(app, user):
        recorded_instructions_sent.append(user)

    # Test login before confirmation
    email = '*****@*****.**'

    with capture_registrations() as registrations:
        response = client.post('/register',
                               data=dict(email=email, password='******'))

    assert response.status_code == 302

    response = authenticate(client, email=email)
    assert get_message('CONFIRMATION_REQUIRED') in response.data

    # Test invalid token
    response = client.get('/confirm/bogus', follow_redirects=True)
    assert get_message('INVALID_CONFIRMATION_TOKEN') in response.data

    # Test JSON
    response = client.post('/confirm',
                           data='{"email": "*****@*****.**"}',
                           headers={'Content-Type': 'application/json'})
    assert response.status_code == 200
    assert response.headers['Content-Type'] == 'application/json'
    assert 'user' in response.jdata['response']
    assert len(recorded_instructions_sent) == 1

    # Test ask for instructions with invalid email
    response = client.post('/confirm', data=dict(email='*****@*****.**'))
    assert get_message('USER_DOES_NOT_EXIST') in response.data

    # Test resend instructions
    response = client.post('/confirm', data=dict(email=email))
    assert get_message('CONFIRMATION_REQUEST', email=email) in response.data
    assert len(recorded_instructions_sent) == 2

    # Test confirm
    token = registrations[0]['confirm_token']
    response = client.get('/confirm/' + token, follow_redirects=True)
    assert get_message('EMAIL_CONFIRMED') in response.data
    assert len(recorded_confirms) == 1

    # Test already confirmed
    response = client.get('/confirm/' + token, follow_redirects=True)
    assert get_message('ALREADY_CONFIRMED') in response.data

    # Test already confirmed when asking for confirmation instructions
    logout(client)

    response = client.get('/confirm')
    assert response.status_code == 200

    response = client.post('/confirm', data=dict(email=email))
    assert get_message('ALREADY_CONFIRMED') in response.data

    # Test user was deleted before confirmation
    with capture_registrations() as registrations:
        client.post('/register',
                    data=dict(email='*****@*****.**', password='******'))

    user = registrations[0]['user']
    token = registrations[0]['confirm_token']

    with app.app_context():
        sqlalchemy_datastore.delete(user)
        sqlalchemy_datastore.commit()

    response = client.get('/confirm/' + token, follow_redirects=True)
    assert get_message('INVALID_CONFIRMATION_TOKEN') in response.data
def test_confirmable_flag(app, client, sqlalchemy_datastore, get_message):
    recorded_confirms = []
    recorded_instructions_sent = []

    @user_confirmed.connect_via(app)
    def on_confirmed(app, user):
        assert isinstance(app, Flask)
        assert isinstance(user, UserMixin)
        recorded_confirms.append(user)

    @confirm_instructions_sent.connect_via(app)
    def on_instructions_sent(app, user, token):
        assert isinstance(app, Flask)
        assert isinstance(user, UserMixin)
        assert isinstance(token, str)
        recorded_instructions_sent.append(user)

    # Test login before confirmation
    email = '*****@*****.**'

    with capture_registrations() as registrations:
        data = dict(email=email, password='******', next='')
        response = client.post('/register', data=data)

    assert response.status_code == 302

    response = authenticate(client, email=email)
    assert get_message('CONFIRMATION_REQUIRED') in response.data

    # Test invalid token
    response = client.get('/confirm/bogus', follow_redirects=True)
    assert get_message('INVALID_CONFIRMATION_TOKEN') in response.data

    # Test ask for instructions with invalid email
    response = client.post('/confirm', data=dict(email='*****@*****.**'))
    assert get_message('USER_DOES_NOT_EXIST') in response.data

    # Test resend instructions
    response = client.post('/confirm', data=dict(email=email))
    assert get_message('CONFIRMATION_REQUEST', email=email) in response.data
    assert len(recorded_instructions_sent) == 1

    # Test confirm
    token = registrations[0]['confirm_token']
    response = client.get('/confirm/' + token, follow_redirects=True)
    assert get_message('EMAIL_CONFIRMED') in response.data
    assert len(recorded_confirms) == 1

    # Test already confirmed
    response = client.get('/confirm/' + token, follow_redirects=True)
    assert get_message('ALREADY_CONFIRMED') in response.data
    assert len(recorded_instructions_sent) == 1

    # Test already confirmed and expired token
    app.config['SECURITY_CONFIRM_EMAIL_WITHIN'] = '-1 days'
    with app.app_context():
        user = registrations[0]['user']
        expired_token = generate_confirmation_token(user)
    response = client.get('/confirm/' + expired_token, follow_redirects=True)
    assert get_message('ALREADY_CONFIRMED') in response.data
    assert len(recorded_instructions_sent) == 1

    # Test already confirmed when asking for confirmation instructions
    logout(client)

    response = client.get('/confirm')
    assert response.status_code == 200

    response = client.post('/confirm', data=dict(email=email))
    assert get_message('ALREADY_CONFIRMED') in response.data

    # Test user was deleted before confirmation
    with capture_registrations() as registrations:
        data = dict(email='*****@*****.**', password='******', next='')
        client.post('/register', data=data)

    user = registrations[0]['user']
    token = registrations[0]['confirm_token']

    with app.app_context():
        sqlalchemy_datastore.delete(user)
        sqlalchemy_datastore.commit()

    response = client.get('/confirm/' + token, follow_redirects=True)
    assert get_message('INVALID_CONFIRMATION_TOKEN') in response.data