def test_unsupported_carrier(self):
        # Arrange
        mailbox = Mailbox('+15555555555', carrier='Foo Wireless')

        # Act
        result = mailbox.is_carrier_supported()

        # Assert
        self.assertFalse(result)
    def test_supported_carrier(self):
        # Arrange
        mailbox = Mailbox('+15555555555', carrier='Verizon Wireless')

        # Act
        result = mailbox.is_carrier_supported()

        # Assert
        self.assertTrue(result)
    def test_get_disable_code(self):
        # Arrange
        mailbox = Mailbox('+15555555555', carrier='Verizon Wireless')

        # Act
        disable_code = mailbox.get_disable_code()

        # Assert
        self.assertEqual(disable_code, '*73')
    def test_get_call_forwarding_code(self):
        # Arrange
        mailbox = Mailbox('+15555555555', carrier='Verizon Wireless')

        # Act
        forwarding_code = mailbox.get_call_forwarding_code()

        # Assert
        self.assertEqual(forwarding_code, '*719999999999')
    def test_get_region_code(self):
        # Arrange
        mailbox = Mailbox('+15555555555', carrier='Verizon Wireless')

        # Act
        region_code = mailbox.get_region_code()

        # Assert
        self.assertEqual(region_code, 'US')
    def test_send_contact_info(self):
        # Arrange
        mailbox = Mailbox('+15555555555', name='Jane Foo', email='*****@*****.**', carrier='Foo Wireless')
        mock_client = MagicMock()

        # Act
        with patch('app.models.get_twilio_rest_client', return_value=mock_client):
            mailbox.send_contact_info('+17777777777')

        # Assert
        assert mock_client.messages.create.called
        self.assertFalse(mailbox.call_forwarding_set)
    def test_generate_config_image(self):
        # Arrange
        mailbox = Mailbox('+15555555555', carrier='Foo Wireless')

        # Act
        with patch('app.models.qrcode') as mock_qrcode:
            mailbox.generate_config_image()

        # Assert
        assert mock_qrcode.make.called

        qrcode_json = mock_qrcode.make.call_args[0][0]
        self.assertIn('+1555555555', qrcode_json)
        self.assertIn('"call_forwarding_set": false', qrcode_json)
        self.assertNotIn('_sa_instance_state', qrcode_json)
    def test_send_config_image(self):
        # Arrange
        mailbox = Mailbox('+15555555555', carrier='Foo Wireless')
        mock_thread = MagicMock()

        # Act
        with patch('app.models.Thread', return_value=mock_thread) as MockThread:
            mailbox.send_config_image()

        # Assert
        body = MockThread.call_args[1]['args'][1]
        self.assertIn('Now get on with your life!', body)

        media_url = MockThread.call_args[1]['args'][3]
        self.assertEqual(media_url, 'http://localhost/config-image')

        assert mock_thread.start.called
    def test_qr_codes_yes(self):
        # Arrange
        mailbox = Mailbox(
            phone_number='+15555555555',
            carrier='Verizon Wireless',
            name='Jane Foo',
            email='*****@*****.**',
            call_forwarding_set=True)
        mailbox.send_config_image = MagicMock()

        # Act
        reply = _process_answer('YEAH', mailbox)

        # Assert
        self.assertEqual(mailbox.feelings_on_qr_codes, 'love')
        self.assertIn('ME TOO', reply)

        mailbox.send_config_image.assert_called_once_with()
    def test_qr_codes_no(self):
        # Arrange
        mailbox = Mailbox(
            phone_number='+15555555555',
            carrier='Verizon Wireless',
            name='Jane Foo',
            email='*****@*****.**',
            call_forwarding_set=True)
        mailbox.send_config_image = MagicMock()

        # Act
        reply = _process_answer('not so much', mailbox)

        # Assert
        self.assertEqual(mailbox.feelings_on_qr_codes, 'hate')
        self.assertIn('for nerds', reply)

        self.assertFalse(mailbox.send_config_image.called)
    def test_qr_codes_unsure(self):
        # Arrange
        mailbox = Mailbox(
            phone_number='+15555555555',
            carrier='Verizon Wireless',
            name='Jane Foo',
            email='*****@*****.**',
            call_forwarding_set=True)
        mailbox.send_config_image = MagicMock()

        # Act
        reply = _process_answer("I can take them or leave them", mailbox)

        # Assert
        self.assertIsNone(mailbox.feelings_on_qr_codes)
        self.assertIn('kidder', reply)

        self.assertFalse(mailbox.send_config_image.called)
Exemple #12
0
def mailbox_already_used(email: str, user) -> bool:
    if Mailbox.get_by(email=email, user_id=user.id):
        return True

    # support the case user wants to re-add their real email as mailbox
    # can happen when user changes their root email and wants to add this new email as mailbox
    if email == user.email:
        return False

    return False
Exemple #13
0
def alias_transfer_receive_route():
    """
    URL has ?alias_id=signed_alias_id
    """
    token = request.args.get("token")
    alias = Alias.get_by(transfer_token=token)

    if not alias:
        flash("Invalid link", "error")
        return redirect(url_for("dashboard.index"))

    # alias already belongs to this user
    if alias.user_id == current_user.id:
        flash("You already own this alias", "warning")
        return redirect(url_for("dashboard.index"))

    # check if user has not exceeded the alias quota
    if not current_user.can_create_new_alias():
        LOG.d("%s can't receive new alias", current_user)
        flash(
            "You have reached free plan limit, please upgrade to create new aliases",
            "warning",
        )
        return redirect(url_for("dashboard.index"))

    mailboxes = current_user.mailboxes()

    if request.method == "POST":
        mailbox_ids = request.form.getlist("mailbox_ids")
        # check if mailbox is not tempered with
        mailboxes = []
        for mailbox_id in mailbox_ids:
            mailbox = Mailbox.get(mailbox_id)
            if (not mailbox or mailbox.user_id != current_user.id
                    or not mailbox.verified):
                flash("Something went wrong, please retry", "warning")
                return redirect(request.url)
            mailboxes.append(mailbox)

        if not mailboxes:
            flash("You must select at least 1 mailbox", "warning")
            return redirect(request.url)

        LOG.d("transfer alias from %s to %s with %s", alias.user, current_user,
              mailboxes)
        transfer(alias, current_user, mailboxes)
        flash(f"You are now owner of {alias.email}", "success")
        return redirect(url_for("dashboard.index",
                                highlight_alias_id=alias.id))

    return render_template(
        "dashboard/alias_transfer_receive.html",
        alias=alias,
        mailboxes=mailboxes,
    )
Exemple #14
0
def handle_unsubscribe(envelope: Envelope):
    msg = email.message_from_bytes(envelope.original_content)

    # format: alias_id:
    subject = msg["Subject"]
    try:
        # subject has the format {alias.id}=
        if subject.endswith("="):
            alias_id = int(subject[:-1])
        # some email providers might strip off the = suffix
        else:
            alias_id = int(subject)

        alias = Alias.get(alias_id)
    except Exception:
        LOG.warning("Cannot parse alias from subject %s", msg["Subject"])
        return "550 SL E8"

    if not alias:
        LOG.warning("No such alias %s", alias_id)
        return "550 SL E9"

    # This sender cannot unsubscribe
    mail_from = envelope.mail_from.lower().strip()
    mailbox = Mailbox.get_by(user_id=alias.user_id, email=mail_from)
    if not mailbox or mailbox not in alias.mailboxes:
        LOG.d("%s cannot disable alias %s", envelope.mail_from, alias)
        return "550 SL E10"

    # Sender is owner of this alias
    alias.enabled = False
    db.session.commit()
    user = alias.user

    enable_alias_url = URL + f"/dashboard/?highlight_alias_id={alias.id}"
    for mailbox in alias.mailboxes:
        send_email(
            mailbox.email,
            f"Alias {alias.email} has been disabled successfully",
            render(
                "transactional/unsubscribe-disable-alias.txt",
                user=user,
                alias=alias.email,
                enable_alias_url=enable_alias_url,
            ),
            render(
                "transactional/unsubscribe-disable-alias.html",
                user=user,
                alias=alias.email,
                enable_alias_url=enable_alias_url,
            ),
        )

    return "250 Unsubscribe request accepted"
def test_update_custom_domains(flask_client):
    user = login(flask_client)

    d1 = CustomDomain.create(
        user_id=user.id, domain="test1.org", verified=True, commit=True
    )

    # test update catch all
    assert d1.catch_all is False
    r = flask_client.patch(f"/api/custom_domains/{d1.id}", json={"catch_all": True})
    assert r.status_code == 200
    assert d1.catch_all is True

    # make sure the full domain json is returned
    cd_json = r.json["custom_domain"]
    assert cd_json["domain_name"]
    assert cd_json["id"] == d1.id
    assert cd_json["nb_alias"] == 0
    assert "is_verified" in cd_json
    assert "catch_all" in cd_json
    assert "name" in cd_json
    assert "random_prefix_generation" in cd_json
    assert cd_json["creation_date"]
    assert cd_json["creation_timestamp"]

    assert cd_json["mailboxes"]
    for mailbox in cd_json["mailboxes"]:
        assert "id" in mailbox
        assert "email" in mailbox

    # test update random_prefix_generation
    assert d1.random_prefix_generation is False
    r = flask_client.patch(
        f"/api/custom_domains/{d1.id}", json={"random_prefix_generation": True}
    )
    assert r.status_code == 200
    assert d1.random_prefix_generation is True

    # test update name
    assert d1.name is None
    r = flask_client.patch(f"/api/custom_domains/{d1.id}", json={"name": "test name"})
    assert r.status_code == 200
    assert d1.name == "test name"

    # test update mailboxes
    assert d1.mailboxes == [user.default_mailbox]
    mb = Mailbox.create(
        user_id=user.id, email="*****@*****.**", verified=True, commit=True
    )
    r = flask_client.patch(
        f"/api/custom_domains/{d1.id}", json={"mailbox_ids": [mb.id]}
    )
    assert r.status_code == 200
    assert d1.mailboxes == [mb]
Exemple #16
0
    def test_send_info_to_user_restore(self):
        # Arrange
        mailbox = Mailbox('+15555555555', carrier='Foo Wireless', feelings_on_qr_codes='love')
        mock_client = MagicMock()

        mock_thread = MagicMock()

        # Act
        with patch('app.models.get_twilio_rest_client', return_value=mock_client):
            with patch('app.models.Thread', return_value=mock_thread) as MockThread:
                mailbox.send_contact_info('+15555555555')

        # Assert
        assert mock_client.messages.create.called
        self.assertTrue(mailbox.call_forwarding_set)

        body = MockThread.call_args[1]['args'][1]
        self.assertIn('Now get on with your life!', body)

        assert mock_thread.start.called
def test_delete_mailbox(flask_client):
    user = login(flask_client)

    # create a mailbox
    mb = Mailbox.create(user_id=user.id, email="*****@*****.**")
    db.session.commit()

    r = flask_client.delete(
        f"/api/mailboxes/{mb.id}",
    )

    assert r.status_code == 200
Exemple #18
0
def email_already_used(email: str) -> bool:
    """test if an email can be used when:
    - user signs up
    - add a new mailbox
    """
    if User.get_by(email=email):
        return True

    if Mailbox.get_by(email=email):
        return True

    return False
Exemple #19
0
def test_success_v3(flask_client):
    user = User.create(
        email="[email protected]",
        password="******",
        name="Test User",
        activated=True,
    )
    db.session.commit()

    # create api_key
    api_key = ApiKey.create(user.id, "for test")
    db.session.commit()

    # create another mailbox
    mb = Mailbox.create(user_id=user.id, email="*****@*****.**", verified=True)
    db.session.commit()

    # create new alias with note
    word = random_word()
    suffix = f".{word}@{EMAIL_DOMAIN}"
    suffix = signer.sign(suffix).decode()

    r = flask_client.post(
        url_for("api.new_custom_alias_v3", hostname="www.test.com"),
        headers={"Authentication": api_key.code},
        json={
            "alias_prefix": "prefix",
            "signed_suffix": suffix,
            "note": "test note",
            "mailbox_ids": [user.default_mailbox_id, mb.id],
            "name": "your name",
        },
    )

    assert r.status_code == 201
    assert r.json["alias"] == f"prefix.{word}@{EMAIL_DOMAIN}"

    # assert returned field
    res = r.json
    assert "id" in res
    assert "email" in res
    assert "creation_date" in res
    assert "creation_timestamp" in res
    assert "nb_forward" in res
    assert "nb_block" in res
    assert "nb_reply" in res
    assert "enabled" in res
    assert "note" in res
    assert res["name"] == "your name"

    new_alias: Alias = Alias.get_by(email=r.json["alias"])
    assert new_alias.note == "test note"
    assert len(new_alias.mailboxes) == 2
Exemple #20
0
    def test_import_config_image_failure(self):
        # Arrange
        mock_response = MagicMock()

        mock_response.json.side_effect = ValueError
        
        # Act
        with patch('app.models.requests.get', return_value=mock_response):
            result = Mailbox.import_config_image('http://example.com')

        # Assert
        self.assertIn('Ooops!', result)
Exemple #21
0
def test_get_mailboxes_v2(flask_client):
    user = login(flask_client)

    Mailbox.create(user_id=user.id, email="*****@*****.**", verified=True)
    Mailbox.create(user_id=user.id, email="*****@*****.**", verified=False)
    db.session.commit()

    r = flask_client.get(
        "/api/v2/mailboxes",
    )
    assert r.status_code == 200
    # 3 mailboxes: the default, m1 and m2
    assert len(r.json["mailboxes"]) == 3

    for mb in r.json["mailboxes"]:
        assert "email" in mb
        assert "id" in mb
        assert "default" in mb
        assert "creation_timestamp" in mb
        assert "nb_alias" in mb
        assert "verified" in mb
Exemple #22
0
def sanity_check():
    """
    #TODO: investigate why DNS sometimes not working
    Different sanity checks
    - detect if there's mailbox that's using a invalid domain
    """
    for mailbox in Mailbox.filter_by(verified=True).all():
        # hack to not query DNS too often
        sleep(1)
        if not email_domain_can_be_used_as_mailbox(mailbox.email):
            mailbox.nb_failed_checks += 1
            nb_email_log = nb_email_log_for_mailbox(mailbox)

            # alert if too much fail and nb_email_log > 100
            if mailbox.nb_failed_checks > 10 and nb_email_log > 100:
                log_func = LOG.exception
            else:
                log_func = LOG.warning

            log_func(
                "issue with mailbox %s domain. #alias %s, nb email log %s",
                mailbox,
                mailbox.nb_alias(),
                nb_email_log,
            )
        else:  # reset nb check
            mailbox.nb_failed_checks = 0

    db.session.commit()

    for user in User.filter_by(activated=True).all():
        if user.email.lower() != user.email:
            LOG.exception("%s does not have lowercase email", user)

    for mailbox in Mailbox.filter_by(verified=True).all():
        if mailbox.email.lower() != mailbox.email:
            LOG.exception("%s does not have lowercase email", mailbox)

    LOG.d("Finish sanity check")
Exemple #23
0
def delete_mailbox(mailbox_id):
    """
    Delete mailbox
    Input:
        mailbox_id: in url
    Output:
        200 if deleted successfully

    """
    user = g.user
    mailbox = Mailbox.get(mailbox_id)

    if not mailbox or mailbox.user_id != user.id:
        return jsonify(error="Forbidden"), 403

    if mailbox.id == user.default_mailbox_id:
        return jsonify(error="You cannot delete the default mailbox"), 400

    Mailbox.delete(mailbox_id)
    db.session.commit()

    return jsonify(deleted=True), 200
Exemple #24
0
def test_add_domain_used_in_mailbox(flask_client):
    """cannot add domain if it has been used in a verified mailbox"""
    user = login(flask_client)
    user.lifetime = True
    Session.commit()

    Mailbox.create(user_id=user.id,
                   email="*****@*****.**",
                   verified=True,
                   commit=True)

    r = flask_client.post(
        url_for("dashboard.custom_domain"),
        data={
            "form-name": "create",
            "domain": "new-domain.com"
        },
        follow_redirects=True,
    )

    assert r.status_code == 200
    assert b"new-domain.com already used in a SimpleLogin mailbox" in r.data
Exemple #25
0
def alias_transfer_receive_route():
    """
    URL has ?alias_id=signed_alias_id
    """
    s = Signer(ALIAS_TRANSFER_SECRET)
    signed_alias_id = request.args.get("alias_id")

    try:
        alias_id = int(s.unsign(signed_alias_id))
    except Exception:
        flash("Invalid link", "error")
        return redirect(url_for("dashboard.index"))
    else:
        alias = Alias.get(alias_id)

    # alias already belongs to this user
    if alias.user_id == current_user.id:
        flash("You already own this alias", "warning")
        return redirect(url_for("dashboard.index"))

    mailboxes = current_user.mailboxes()

    if request.method == "POST":
        mailbox_ids = request.form.getlist("mailbox_ids")
        # check if mailbox is not tempered with
        mailboxes = []
        for mailbox_id in mailbox_ids:
            mailbox = Mailbox.get(mailbox_id)
            if (not mailbox or mailbox.user_id != current_user.id
                    or not mailbox.verified):
                flash("Something went wrong, please retry", "warning")
                return redirect(request.url)
            mailboxes.append(mailbox)

        if not mailboxes:
            flash("You must select at least 1 mailbox", "warning")
            return redirect(request.url)

        LOG.d("transfer alias from %s to %s with %s", alias.user, current_user,
              mailboxes)
        transfer(alias, current_user, mailboxes)
        flash(f"You are now owner of {alias.email}", "success")
        return redirect(url_for("dashboard.index",
                                highlight_alias_id=alias.id))

    return render_template(
        "dashboard/alias_transfer_receive.html",
        alias=alias,
        mailboxes=mailboxes,
    )
Exemple #26
0
def test_update_mailbox_email(flask_client):
    user = User.create(
        email="[email protected]", password="******", name="Test User", activated=True
    )
    db.session.commit()

    # create api_key
    api_key = ApiKey.create(user.id, "for test")
    db.session.commit()

    # create a mailbox
    mb = Mailbox.create(user_id=user.id, email="*****@*****.**")
    db.session.commit()

    r = flask_client.put(
        f"/api/mailboxes/{mb.id}",
        headers={"Authentication": api_key.code},
        json={"email": "*****@*****.**"},
    )

    assert r.status_code == 200

    mb = Mailbox.get(mb.id)
    assert mb.new_email == "*****@*****.**"
Exemple #27
0
def delete_mailbox(mailbox_id: int):
    from server import create_light_app

    with create_light_app().app_context():
        mailbox = Mailbox.get(mailbox_id)
        if not mailbox:
            return

        mailbox_email = mailbox.email
        user = mailbox.user

        Mailbox.delete(mailbox_id)
        db.session.commit()
        LOG.d("Mailbox %s %s deleted", mailbox_id, mailbox_email)

        send_email(
            user.email,
            f"Your mailbox {mailbox_email} has been deleted",
            f"""Mailbox {mailbox_email} along with its aliases are deleted successfully.

Regards,
SimpleLogin team.
        """,
        )
Exemple #28
0
def mailbox_confirm_change_route():
    s = Signer(MAILBOX_SECRET)
    signed_mailbox_id = request.args.get("mailbox_id")

    try:
        mailbox_id = int(s.unsign(signed_mailbox_id))
    except Exception:
        flash("Invalid link", "error")
        return redirect(url_for("dashboard.index"))
    else:
        mailbox = Mailbox.get(mailbox_id)

        # new_email can be None if user cancels change in the meantime
        if mailbox and mailbox.new_email:
            user = mailbox.user
            if Mailbox.get_by(email=mailbox.new_email, user_id=user.id):
                flash(f"{mailbox.new_email} is already used", "error")
                return redirect(
                    url_for("dashboard.mailbox_detail_route",
                            mailbox_id=mailbox.id))

            mailbox.email = mailbox.new_email
            mailbox.new_email = None

            # mark mailbox as verified if the change request is sent from an unverified mailbox
            mailbox.verified = True
            Session.commit()

            LOG.d("Mailbox change %s is verified", mailbox)
            flash(f"The {mailbox.email} is updated", "success")
            return redirect(
                url_for("dashboard.mailbox_detail_route",
                        mailbox_id=mailbox.id))
        else:
            flash("Invalid link", "error")
            return redirect(url_for("dashboard.index"))
Exemple #29
0
def test_get_mailboxes(flask_client):
    user = User.create(email="[email protected]",
                       password="******",
                       name="Test User",
                       activated=True)
    db.session.commit()

    # create api_key
    api_key = ApiKey.create(user.id, "for test")
    db.session.commit()

    Mailbox.create(user_id=user.id, email="*****@*****.**", verified=True)
    Mailbox.create(user_id=user.id, email="*****@*****.**", verified=False)
    db.session.commit()

    r = flask_client.get(
        url_for("api.get_mailboxes"),
        headers={"Authentication": api_key.code},
    )
    assert r.status_code == 200
    # [email protected] is not returned as it's not verified
    assert r.json == {
        "mailboxes": [
            {
                "email": "[email protected]",
                "id": 1,
                "default": True
            },
            {
                "email": "*****@*****.**",
                "id": 2,
                "default": False
            },
        ]
    }
    print(json.dumps(r.json, indent=2))
Exemple #30
0
def test_update_alias_mailboxes(flask_client):
    user = User.create(email="[email protected]",
                       password="******",
                       name="Test User",
                       activated=True)
    db.session.commit()

    mb1 = Mailbox.create(user_id=user.id, email="*****@*****.**", verified=True)
    mb2 = Mailbox.create(user_id=user.id, email="*****@*****.**", verified=True)

    # create api_key
    api_key = ApiKey.create(user.id, "for test")
    db.session.commit()

    alias = Alias.create_new_random(user)
    db.session.commit()

    r = flask_client.put(
        url_for("api.update_alias", alias_id=alias.id),
        headers={"Authentication": api_key.code},
        json={"mailbox_ids": [mb1.id, mb2.id]},
    )

    assert r.status_code == 200
    alias = Alias.get(alias.id)

    assert alias.mailbox
    assert len(alias._mailboxes) == 1

    # fail when update with empty mailboxes
    r = flask_client.put(
        url_for("api.update_alias", alias_id=alias.id),
        headers={"Authentication": api_key.code},
        json={"mailbox_ids": []},
    )
    assert r.status_code == 400
Exemple #31
0
def test_mailbox_delete(flask_client):
    user = User.create(
        email="[email protected]",
        password="******",
        name="Test User",
        activated=True,
        commit=True,
    )

    m1 = Mailbox.create(user_id=user.id,
                        email="*****@*****.**",
                        verified=True,
                        commit=True)
    m2 = Mailbox.create(user_id=user.id,
                        email="*****@*****.**",
                        verified=True,
                        commit=True)
    m3 = Mailbox.create(user_id=user.id,
                        email="*****@*****.**",
                        verified=True,
                        commit=True)

    # alias has 2 mailboxes
    alias = Alias.create_new(user, "prefix", mailbox_id=m1.id)
    Session.commit()

    alias._mailboxes.append(m2)
    alias._mailboxes.append(m3)
    Session.commit()

    assert len(alias.mailboxes) == 3

    # delete m1, should not delete alias
    Mailbox.delete(m1.id)
    alias = Alias.get(alias.id)
    assert len(alias.mailboxes) == 2
Exemple #32
0
def test_cancel_mailbox_email_change(flask_client):
    user = User.create(email="[email protected]",
                       password="******",
                       name="Test User",
                       activated=True)
    db.session.commit()

    # create api_key
    api_key = ApiKey.create(user.id, "for test")
    db.session.commit()

    # create a mailbox
    mb = Mailbox.create(user_id=user.id, email="*****@*****.**")
    db.session.commit()

    # update mailbox email
    r = flask_client.put(
        url_for("api.delete_mailbox", mailbox_id=mb.id),
        headers={"Authentication": api_key.code},
        json={"email": "*****@*****.**"},
    )
    assert r.status_code == 200

    mb = Mailbox.get(mb.id)
    assert mb.new_email == "*****@*****.**"

    # cancel mailbox email change
    r = flask_client.put(
        url_for("api.delete_mailbox", mailbox_id=mb.id),
        headers={"Authentication": api_key.code},
        json={"cancel_email_change": True},
    )
    assert r.status_code == 200

    mb = Mailbox.get(mb.id)
    assert mb.new_email is None
Exemple #33
0
def sanity_check():
    """
    #TODO: investigate why DNS sometimes not working
    Different sanity checks
    - detect if there's mailbox that's using a invalid domain
    """
    for mailbox in Mailbox.filter_by(verified=True).all():
        # hack to not query DNS too often
        sleep(1)
        if not email_domain_can_be_used_as_mailbox(mailbox.email):
            mailbox.nb_failed_checks += 1
            nb_email_log = nb_email_log_for_mailbox(mailbox)

            # alert if too much fail and nb_email_log > 100
            if mailbox.nb_failed_checks > 10 and nb_email_log > 100:
                log_func = LOG.exception
                mailbox.verified = False
            else:
                log_func = LOG.warning

            log_func(
                "issue with mailbox %s domain. #alias %s, nb email log %s",
                mailbox,
                mailbox.nb_alias(),
                nb_email_log,
            )
        else:  # reset nb check
            mailbox.nb_failed_checks = 0

        db.session.commit()

    for user in User.filter_by(activated=True).all():
        if user.email.lower().strip().replace(" ", "") != user.email:
            LOG.exception("%s does not have sanitized email", user)

    for alias in Alias.query.all():
        if alias.email.lower().strip().replace(" ", "") != alias.email:
            LOG.exception("Alias %s email not sanitized", alias)

    for contact in Contact.query.all():
        if contact.reply_email.lower().strip().replace(" ", "") != contact.reply_email:
            LOG.exception("Contact %s reply-email not sanitized", contact)

    for mailbox in Mailbox.query.all():
        if mailbox.email.lower().strip().replace(" ", "") != mailbox.email:
            LOG.exception("Mailbox %s address not sanitized", mailbox)

    LOG.d("Finish sanity check")
Exemple #34
0
def cancel_mailbox_change_route(mailbox_id):
    mailbox = Mailbox.get(mailbox_id)
    if not mailbox or mailbox.user_id != current_user.id:
        flash("You cannot see this page", "warning")
        return redirect(url_for("dashboard.index"))

    if mailbox.new_email:
        mailbox.new_email = None
        db.session.commit()
        flash("Your mailbox change is cancelled", "success")
        return redirect(
            url_for("dashboard.mailbox_detail_route", mailbox_id=mailbox_id))
    else:
        flash("You have no pending mailbox change", "warning")
        return redirect(
            url_for("dashboard.mailbox_detail_route", mailbox_id=mailbox_id))
Exemple #35
0
def get_mailboxes_v2():
    """
    Get all mailboxes - including unverified mailboxes
    Output:
        - mailboxes: list of mailbox dict
    """
    user = g.user
    mailboxes = []

    for mailbox in Mailbox.filter_by(user_id=user.id):
        mailboxes.append(mailbox)

    return (
        jsonify(mailboxes=[mailbox_to_dict(mb) for mb in mailboxes]),
        200,
    )
def test_full_payload(flask_client):
    """Create alias with:
    - additional mailbox
    - note
    - name
    - hostname (in URL)
    """

    user = login(flask_client)

    # create another mailbox
    mb = Mailbox.create(user_id=user.id, email="*****@*****.**", verified=True)
    Session.commit()

    word = random_word()
    suffix = f".{word}@{EMAIL_DOMAIN}"
    signed_suffix = signer.sign(suffix).decode()

    assert AliasUsedOn.count() == 0

    r = flask_client.post(
        "/api/v3/alias/custom/new?hostname=example.com",
        json={
            "alias_prefix": "prefix",
            "signed_suffix": signed_suffix,
            "note": "test note",
            "mailbox_ids": [user.default_mailbox_id, mb.id],
            "name": "your name",
        },
    )

    assert r.status_code == 201
    assert r.json["alias"] == f"prefix.{word}@{EMAIL_DOMAIN}"

    # assert returned field
    res = r.json
    assert res["note"] == "test note"
    assert res["name"] == "your name"

    new_alias: Alias = Alias.get_by(email=r.json["alias"])
    assert new_alias.note == "test note"
    assert len(new_alias.mailboxes) == 2

    alias_used_on = AliasUsedOn.first()
    assert alias_used_on.alias_id == new_alias.id
    assert alias_used_on.hostname == "example.com"
Exemple #37
0
def mailbox_verify():
    s = Signer(MAILBOX_SECRET)
    mailbox_id = request.args.get("mailbox_id")

    try:
        r_id = int(s.unsign(mailbox_id))
    except Exception:
        flash("Invalid link. Please delete and re-add your mailbox", "error")
        return redirect(url_for("dashboard.mailbox_route"))
    else:
        mailbox = Mailbox.get(r_id)
        mailbox.verified = True
        db.session.commit()

        LOG.d("Mailbox %s is verified", mailbox)

        return render_template("dashboard/mailbox_validation.html",
                               mailbox=mailbox)
Exemple #38
0
def test_get_alias_infos_with_pagination_v3_no_duplicate(flask_client):
    """When an alias belongs to multiple mailboxes, make sure get_alias_infos_with_pagination_v3
    returns no duplicates
    """
    user = User.create(
        email="[email protected]",
        password="******",
        name="Test User",
        activated=True,
        commit=True,
    )

    alias = Alias.first()
    mb = Mailbox.create(user_id=user.id, email="*****@*****.**")
    alias._mailboxes.append(mb)
    Session.commit()

    alias_infos = get_alias_infos_with_pagination_v3(user)
    assert len(alias_infos) == 1
Exemple #39
0
def test_get_alias_infos_with_pagination_v3_query_alias_mailboxes(flask_client):
    """test the query on the alias additional mailboxes"""
    user = User.create(
        email="[email protected]",
        password="******",
        name="Test User",
        activated=True,
        commit=True,
    )
    alias = Alias.first()
    mb = Mailbox.create(user_id=user.id, email="*****@*****.**")
    alias._mailboxes.append(mb)
    Session.commit()

    alias_infos = get_alias_infos_with_pagination_v3(user, mailbox_id=mb.id)
    assert len(alias_infos) == 1

    alias_infos = get_alias_infos_with_pagination_v3(user, query=alias.email)
    assert len(alias_infos) == 1
Exemple #40
0
def test_delete_mailbox(flask_client):
    user = User.create(
        email="[email protected]", password="******", name="Test User", activated=True
    )
    db.session.commit()

    # create api_key
    api_key = ApiKey.create(user.id, "for test")
    db.session.commit()

    # create a mailbox
    mb = Mailbox.create(user_id=user.id, email="*****@*****.**")
    db.session.commit()

    r = flask_client.delete(
        f"/api/mailboxes/{mb.id}",
        headers={"Authentication": api_key.code},
    )

    assert r.status_code == 200
Exemple #41
0
def create_mailbox():
    """
    Create a new mailbox. User needs to verify the mailbox via an activation email.
    Input:
        email: in body
    Output:
        the new mailbox
        - id
        - email
        - verified

    """
    user = g.user
    mailbox_email = request.get_json().get("email").lower().strip().replace(
        " ", "")

    if mailbox_already_used(mailbox_email, user):
        return jsonify(error=f"{mailbox_email} already used"), 400
    elif not email_domain_can_be_used_as_mailbox(mailbox_email):
        return (
            jsonify(
                error=
                f"{mailbox_email} cannot be used. Please note a mailbox cannot "
                f"be a disposable email address"),
            400,
        )
    else:
        new_mailbox = Mailbox.create(email=mailbox_email, user_id=user.id)
        db.session.commit()

        send_verification_email(user, new_mailbox)

        return (
            jsonify(
                id=new_mailbox.id,
                email=new_mailbox.email,
                verified=new_mailbox.verified,
                default=user.default_mailbox_id == new_mailbox.id,
            ),
            201,
        )
Exemple #42
0
    def test_import_config_image(self):
        # Arrange
        # Start off with an existing Mailbox
        mailbox = Mailbox('+15555555555', carrier='Foo Wireless', call_forwarding_set=True)
        db.session.add(mailbox)
        db.session.commit()

        mock_response = MagicMock()
        mock_response.json.return_value = [{'type': 'qrcode', 'symbol': [{'data': '{"id": 1, "feelings_on_qr_codes": "love", "phone_number": "+15555555555", "name": "Jane Foo", "email": "*****@*****.**", "call_forwarding_set": false, "carrier": "Foo Wireless"}', 'error': None, 'seq': 0}]}]

        # Act
        with patch('app.models.requests.get', return_value=mock_response):
            result = Mailbox.import_config_image('http://example.com')

        # Assert
        self.assertEqual(Mailbox.query.count(), 1)

        imported_mailbox = Mailbox.query.one()
        self.assertEqual(mailbox.phone_number, '+15555555555')
        self.assertFalse(mailbox.call_forwarding_set)

        self.assertIn('Now I remember *everything* about you', result)
Exemple #43
0
def test_update_custom_domains(flask_client):
    user = login(flask_client)

    d1 = CustomDomain.create(
        user_id=user.id, domain="test1.org", verified=True, commit=True
    )

    # test update catch all
    assert d1.catch_all is False
    r = flask_client.patch(f"/api/custom_domains/{d1.id}", json={"catch_all": True})
    assert r.status_code == 200
    assert d1.catch_all is True

    # test update random_prefix_generation
    assert d1.random_prefix_generation is False
    r = flask_client.patch(
        f"/api/custom_domains/{d1.id}", json={"random_prefix_generation": True}
    )
    assert r.status_code == 200
    assert d1.random_prefix_generation is True

    # test update name
    assert d1.name is None
    r = flask_client.patch(f"/api/custom_domains/{d1.id}", json={"name": "test name"})
    assert r.status_code == 200
    assert d1.name == "test name"

    # test update mailboxes
    assert d1.mailboxes == [user.default_mailbox]
    mb = Mailbox.create(
        user_id=user.id, email="*****@*****.**", verified=True, commit=True
    )
    r = flask_client.patch(
        f"/api/custom_domains/{d1.id}", json={"mailbox_ids": [mb.id]}
    )
    assert r.status_code == 200
    assert d1.mailboxes == [mb]
Exemple #44
0
def create_mailbox():
    """
    Create a new mailbox. User needs to verify the mailbox via an activation email.
    Input:
        email: in body
    Output:
        the new mailbox dict
    """
    user = g.user
    mailbox_email = sanitize_email(request.get_json().get("email"))

    if not user.is_premium():
        return jsonify(
            error=f"Only premium plan can add additional mailbox"), 400

    if not is_valid_email(mailbox_email):
        return jsonify(error=f"{mailbox_email} invalid"), 400
    elif mailbox_already_used(mailbox_email, user):
        return jsonify(error=f"{mailbox_email} already used"), 400
    elif not email_can_be_used_as_mailbox(mailbox_email):
        return (
            jsonify(
                error=
                f"{mailbox_email} cannot be used. Please note a mailbox cannot "
                f"be a disposable email address"),
            400,
        )
    else:
        new_mailbox = Mailbox.create(email=mailbox_email, user_id=user.id)
        Session.commit()

        send_verification_email(user, new_mailbox)

        return (
            jsonify(mailbox_to_dict(new_mailbox)),
            201,
        )