Merge pull request #342 from herrboyer/linting

Linting
This commit is contained in:
Son Nguyen Kim 2020-12-07 17:45:50 +01:00 committed by GitHub
commit bf139f83b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 179 additions and 113 deletions

20
.flake8 Normal file
View File

@ -0,0 +1,20 @@
[flake8]
ignore =
# line length is handled by black
E501,
# W503 & E203 are not PEP 8 compliant and conflicts with black
W503,
E203
exclude =
.git,
__pycache__,
.pytest_cache,
static,
templates,
# migrations are generated by alembic
migrations,
docs
per-file-ignores =
# ignore unused imports in __init__
__init__.py:F401

View File

@ -32,9 +32,10 @@ jobs:
poetry config virtualenvs.create false
poetry install
- name: Test formatting
- name: Check formatting & linting
run: |
black --check .
flake8
- name: Test with pytest
run: |

View File

@ -3,4 +3,8 @@ repos:
rev: stable
hooks:
- id: black
language_version: python3.7
language_version: python3.7
- repo: https://gitlab.com/pycqa/flake8
rev: master
hooks:
- id: flake8

View File

@ -159,7 +159,7 @@ def get_alias_infos_with_pagination_v2(
if alias_filter == "enabled":
q = q.filter(Alias.enabled)
elif alias_filter == "disabled":
q = q.filter(Alias.enabled == False)
q = q.filter(Alias.enabled.is_(False))
if sort == "old2new":
q = q.order_by(Alias.created_at)
@ -198,7 +198,7 @@ def get_alias_infos_with_pagination_v3(
func.sum(case([(EmailLog.is_reply, 1)], else_=0)).label("nb_reply"),
func.sum(
case(
[(and_(EmailLog.is_reply == False, EmailLog.blocked), 1)],
[(and_(EmailLog.is_reply.is_(False), EmailLog.blocked), 1)],
else_=0,
)
).label("nb_blocked"),
@ -207,8 +207,8 @@ def get_alias_infos_with_pagination_v3(
[
(
and_(
EmailLog.is_reply == False,
EmailLog.blocked == False,
EmailLog.is_reply.is_(False),
EmailLog.blocked.is_(False),
),
1,
)
@ -273,7 +273,7 @@ def get_alias_infos_with_pagination_v3(
.filter(
or_(
EmailLog.created_at == sub.c.max_created_at,
sub.c.max_created_at == None, # no email log yet for this alias
sub.c.max_created_at.is_(None), # no email log yet for this alias
)
)
)
@ -292,7 +292,7 @@ def get_alias_infos_with_pagination_v3(
if alias_filter == "enabled":
q = q.filter(Alias.enabled)
elif alias_filter == "disabled":
q = q.filter(Alias.enabled == False)
q = q.filter(Alias.enabled.is_(False))
q = q.order_by(Alias.pinned.desc())

View File

@ -14,13 +14,11 @@ from app.api.serializer import (
get_alias_info_v2,
get_alias_infos_with_pagination_v3,
)
from app.config import EMAIL_DOMAIN
from app.dashboard.views.alias_log import get_alias_log
from app.email_utils import parseaddr_unicode, is_valid_email, generate_reply_email
from app.extensions import db
from app.log import LOG
from app.models import Alias, Contact, Mailbox, AliasMailbox
from app.utils import random_string
@api_bp.route("/aliases", methods=["GET", "POST"])

View File

@ -106,7 +106,7 @@ def auth_register():
send_email(
email,
f"Just one more step to join SimpleLogin",
"Just one more step to join SimpleLogin",
render("transactional/code-activation.txt", code=code),
render("transactional/code-activation.html", code=code),
)
@ -206,7 +206,7 @@ def auth_reactivate():
send_email(
email,
f"Just one more step to join SimpleLogin",
"Just one more step to join SimpleLogin",
render("transactional/code-activation.txt", code=code),
render("transactional/code-activation.html", code=code),
)

View File

@ -70,7 +70,7 @@ def fido():
if fido_token_form.validate_on_submit():
try:
sk_assertion = json.loads(fido_token_form.sk_assertion.data)
except Exception as e:
except Exception:
flash("Key verification failed. Error: Invalid Payload", "warning")
return redirect(url_for("auth.login"))

View File

@ -85,7 +85,7 @@ def register():
try:
send_activation_email(user, next_url)
except:
except Exception:
flash("Invalid email, are you sure the email is correct?", "error")
return redirect(url_for("auth.register"))

View File

@ -173,7 +173,7 @@ try:
PADDLE_VENDOR_ID = int(os.environ["PADDLE_VENDOR_ID"])
PADDLE_MONTHLY_PRODUCT_ID = int(os.environ["PADDLE_MONTHLY_PRODUCT_ID"])
PADDLE_YEARLY_PRODUCT_ID = int(os.environ["PADDLE_YEARLY_PRODUCT_ID"])
except:
except (KeyError, ValueError):
print("Paddle param not set")
PADDLE_VENDOR_ID = -1
PADDLE_MONTHLY_PRODUCT_ID = -1

View File

@ -1,4 +1,3 @@
import re
from dataclasses import dataclass
from operator import or_
@ -9,13 +8,12 @@ from flask_wtf import FlaskForm
from sqlalchemy import and_, func, case
from wtforms import StringField, validators, ValidationError
from app.config import EMAIL_DOMAIN, PAGE_LIMIT
from app.config import PAGE_LIMIT
from app.dashboard.base import dashboard_bp
from app.email_utils import parseaddr_unicode, is_valid_email, generate_reply_email
from app.extensions import db
from app.log import LOG
from app.models import Alias, Contact, EmailLog
from app.utils import random_string
def email_validator():
@ -68,8 +66,8 @@ def get_contact_infos(alias: Alias, page=0, contact_id=None) -> [ContactInfo]:
[
(
and_(
EmailLog.is_reply == False,
EmailLog.blocked == False,
EmailLog.is_reply.is_(False),
EmailLog.blocked.is_(False),
),
1,
)
@ -107,7 +105,7 @@ def get_contact_infos(alias: Alias, page=0, contact_id=None) -> [ContactInfo]:
or_(
EmailLog.created_at == sub.c.max_email_log_created_at,
# no email log yet for this contact
sub.c.max_email_log_created_at == None,
sub.c.max_email_log_created_at.is_(None),
)
)
)

View File

@ -49,12 +49,12 @@ def alias_log(alias_id, page_id):
)
total = base.count()
email_forwarded = (
base.filter(EmailLog.is_reply == False)
.filter(EmailLog.blocked == False)
base.filter(EmailLog.is_reply.is_(False))
.filter(EmailLog.blocked.is_(False))
.count()
)
email_replied = base.filter(EmailLog.is_reply == True).count()
email_blocked = base.filter(EmailLog.blocked == True).count()
email_replied = base.filter(EmailLog.is_reply.is_(True)).count()
email_blocked = base.filter(EmailLog.blocked.is_(True)).count()
last_page = (
len(logs) < PAGE_LIMIT
) # lightweight pagination without counting all objects

View File

@ -4,7 +4,7 @@ from flask_login import login_required, current_user
from app.dashboard.base import dashboard_bp
from app.extensions import db
from app.models import Contact
from app.pgp_utils import PGPException, load_public_key, load_public_key_and_check
from app.pgp_utils import PGPException, load_public_key_and_check
@dashboard_bp.route("/contact/<int:contact_id>/", methods=["GET", "POST"])

View File

@ -114,7 +114,7 @@ def domain_detail_dns(custom_domain_id):
custom_domain.dmarc_verified = False
db.session.commit()
flash(
f"DMARC: The TXT record is not correctly set",
"DMARC: The TXT record is not correctly set",
"warning",
)
dmarc_ok = False
@ -228,7 +228,7 @@ def delete_domain(custom_domain_id: CustomDomain):
user.email,
f"Your domain {domain_name} has been deleted",
f"""Domain {domain_name} along with its aliases are deleted successfully.
Regards,
SimpleLogin team.
""",

View File

@ -36,7 +36,7 @@ def fido_setup():
if fido_token_form.validate_on_submit():
try:
sk_assertion = json.loads(fido_token_form.sk_assertion.data)
except Exception as e:
except Exception:
flash("Key registration failed. Error: Invalid Payload", "warning")
return redirect(url_for("dashboard.index"))

View File

@ -76,7 +76,7 @@ def index():
if current_user.can_create_new_alias():
return redirect(url_for("dashboard.custom_alias"))
else:
flash(f"You need to upgrade your plan to create new alias.", "warning")
flash("You need to upgrade your plan to create new alias.", "warning")
elif request.form.get("form-name") == "create-random-email":
if current_user.can_create_new_alias():
@ -104,7 +104,7 @@ def index():
)
)
else:
flash(f"You need to upgrade your plan to create new alias.", "warning")
flash("You need to upgrade your plan to create new alias.", "warning")
elif request.form.get("form-name") == "delete-email":
alias_id = request.form.get("alias-id")

View File

@ -16,7 +16,7 @@ from app.extensions import db
from app.log import LOG
from app.models import Alias, AuthorizedAddress
from app.models import Mailbox
from app.pgp_utils import PGPException, load_public_key, load_public_key_and_check
from app.pgp_utils import PGPException, load_public_key_and_check
class ChangeEmailForm(FlaskForm):
@ -200,12 +200,12 @@ def verify_mailbox_change(user, mailbox, new_email):
s = Signer(MAILBOX_SECRET)
mailbox_id_signed = s.sign(str(mailbox.id)).decode()
verification_url = (
URL + "/dashboard/mailbox/confirm_change" + f"?mailbox_id={mailbox_id_signed}"
f"{URL}/dashboard/mailbox/confirm_change?mailbox_id={mailbox_id_signed}"
)
send_email(
new_email,
f"Confirm mailbox change on SimpleLogin",
"Confirm mailbox change on SimpleLogin",
render(
"transactional/verify-mailbox-change.txt",
user=user,

View File

@ -5,9 +5,7 @@ from flask_login import login_required, current_user
from app.dashboard.base import dashboard_bp
from app.extensions import db
from app.log import LOG
from app.models import Referral
from app.utils import random_string
_REFERRAL_PATTERN = r"[0-9a-z-_]{3,}"

View File

@ -20,7 +20,7 @@ def refused_email_route():
email_logs: [EmailLog] = (
EmailLog.query.filter(
EmailLog.user_id == current_user.id, EmailLog.refused_email_id != None
EmailLog.user_id == current_user.id, EmailLog.refused_email_id.isnot(None)
)
.order_by(EmailLog.id.desc())
.all()

View File

@ -159,7 +159,7 @@ def setting():
profile_updated = True
if profile_updated:
flash(f"Your profile has been updated", "success")
flash("Your profile has been updated", "success")
return redirect(url_for("dashboard.setting"))
elif request.form.get("form-name") == "change-password":

View File

@ -15,7 +15,7 @@ def _get_dns_resolver():
def get_ns(hostname) -> [str]:
try:
answers = _get_dns_resolver().resolve(hostname, "NS")
except:
except Exception:
return []
return [a.to_text() for a in answers]

View File

@ -11,7 +11,6 @@ from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import make_msgid, formatdate, parseaddr
from smtplib import SMTP
from uuid import uuid4
import arrow
import dkim
@ -109,7 +108,7 @@ def send_activation_email(email, name, activation_link):
def send_reset_password_email(email, name, reset_password_link):
send_email(
email,
f"Reset your password on SimpleLogin",
"Reset your password on SimpleLogin",
render(
"transactional/reset-password.txt",
name=name,
@ -126,7 +125,7 @@ def send_reset_password_email(email, name, reset_password_link):
def send_change_email(new_email, current_email, name, link):
send_email(
new_email,
f"Confirm email update on SimpleLogin",
"Confirm email update on SimpleLogin",
render(
"transactional/change-email.txt",
name=name,

View File

@ -73,7 +73,7 @@ def _get_logger(name):
return logger
print(f">>> init logging <<<")
print(">>> init logging <<<")
# Disable flask logs such as 127.0.0.1 - - [15/Feb/2013 10:52:22] "GET /index.html HTTP/1.1" 200
log = logging.getLogger("werkzeug")

View File

@ -54,7 +54,7 @@ def token():
return jsonify(error=f"{code} already expired"), 400
if auth_code.client_id != client.id:
return jsonify(error=f"are you sure this code belongs to you?"), 400
return jsonify(error="are you sure this code belongs to you?"), 400
LOG.debug(
"Create Oauth token for user %s, client %s", auth_code.user, auth_code.client

View File

@ -95,7 +95,7 @@ def change_plan(subscription_id: str, plan_id) -> (bool, str):
# "unable to complete the resubscription because we could not charge the customer for the resubscription"
if res["error"]["code"] == 147:
return False, "Your card cannot be charged"
except:
except KeyError:
LOG.exception(
f"cannot change subscription {subscription_id} to {plan_id}, paddle response: {res}"
)

View File

@ -41,7 +41,7 @@ def load_public_key_and_check(public_key: str) -> str:
else:
dummy_data = BytesIO(b"test")
try:
r = encrypt_file(dummy_data, fingerprint)
encrypt_file(dummy_data, fingerprint)
except Exception as e:
LOG.exception("Cannot encrypt using the imported key")
# remove the fingerprint

View File

@ -108,7 +108,7 @@ class SpamAssassin(object):
# create final json
self.report_json = dict()
for tablelist in tablelists:
wordlist = re.split("\s+", tablelist)
wordlist = re.split(r"\s+", tablelist)
try:
self.report_json[wordlist[1]] = {
"partscore": float(wordlist[0]),

20
cron.py
View File

@ -48,7 +48,7 @@ from server import create_app
def notify_trial_end():
for user in User.query.filter(
User.activated == True, User.trial_end.isnot(None), User.lifetime == False
User.activated.is_(True), User.trial_end.isnot(None), User.lifetime.is_(False)
).all():
if user.in_trial() and arrow.now().shift(
days=3
@ -58,7 +58,7 @@ def notify_trial_end():
def delete_refused_emails():
for refused_email in RefusedEmail.query.filter(RefusedEmail.deleted == False).all():
for refused_email in RefusedEmail.query.filter_by(deleted=False).all():
if arrow.now().shift(days=1) > refused_email.delete_at >= arrow.now():
LOG.d("Delete refused email %s", refused_email)
if refused_email.path:
@ -76,7 +76,7 @@ def delete_refused_emails():
def notify_premium_end():
"""sent to user who has canceled their subscription and who has their subscription ending soon"""
for sub in Subscription.query.filter(Subscription.cancelled == True).all():
for sub in Subscription.query.filter_by(cancelled=True).all():
if (
arrow.now().shift(days=3).date()
> sub.next_bill_date
@ -174,9 +174,9 @@ def stats_before(moment: Arrow) -> Stats:
nb_user = q.count()
LOG.d("total number user %s", nb_user)
nb_referred_user = q.filter(User.referral_id != None).count()
nb_referred_user = q.filter(User.referral_id.isnot(None)).count()
nb_referred_user_upgrade = 0
for user in q.filter(User.referral_id != None):
for user in q.filter(User.referral_id.isnot(None)):
if user.is_premium():
nb_referred_user_upgrade += 1
@ -231,13 +231,13 @@ def stats_before(moment: Arrow) -> Stats:
)
nb_premium = Subscription.query.filter(
Subscription.created_at < moment, Subscription.cancelled == False
Subscription.created_at < moment, Subscription.cancelled.is_(False)
).count()
nb_apple_premium = AppleSubscription.query.filter(
AppleSubscription.created_at < moment
).count()
nb_cancelled_premium = Subscription.query.filter(
Subscription.created_at < moment, Subscription.cancelled == True
Subscription.created_at < moment, Subscription.cancelled.is_(True)
).count()
nb_custom_domain = CustomDomain.query.filter(
@ -316,7 +316,7 @@ def sanity_check():
"""
mailbox_ids = (
db.session.query(Mailbox.id)
.filter(Mailbox.verified == True, Mailbox.disabled == False)
.filter(Mailbox.verified.is_(True), Mailbox.disabled.is_(False))
.all()
)
mailbox_ids = [e[0] for e in mailbox_ids]
@ -418,8 +418,8 @@ def sanity_check():
def check_custom_domain():
LOG.d("Check verified domain for DNS issues")
for custom_domain in CustomDomain.query.filter(
CustomDomain.verified == True
for custom_domain in CustomDomain.query.filter_by(
verified=True
): # type: CustomDomain
mx_domains = get_mx_domains(custom_domain.domain)

View File

@ -1081,8 +1081,8 @@ def handle_unknown_mailbox(
envelope, msg, reply_email: str, user: User, alias: Alias, contact: Contact
):
LOG.warning(
f"Reply email can only be used by mailbox. "
f"Actual mail_from: %s. msg from header: %s, reverse-alias %s, %s %s %s",
"Reply email can only be used by mailbox. "
"Actual mail_from: %s. msg from header: %s, reverse-alias %s, %s %s %s",
envelope.mail_from,
msg["From"],
reply_email,
@ -1205,9 +1205,7 @@ def handle_bounce(contact: Contact, alias: Alias, msg: Message, user: User):
email_log.bounced_mailbox_id = mailbox.id
db.session.commit()
refused_email_url = (
URL + f"/dashboard/refused_email?highlight_id=" + str(email_log.id)
)
refused_email_url = f"{URL}/dashboard/refused_email?highlight_id={email_log.id}"
nb_bounced = EmailLog.filter_by(contact_id=contact.id, bounced=True).count()
if nb_bounced >= 2 and alias.cannot_be_disabled:
@ -1331,9 +1329,7 @@ def handle_bounce_reply_phase(alias: Alias, msg: Message, user: User):
db.session.commit()
refused_email_url = (
URL + f"/dashboard/refused_email?highlight_id=" + str(email_log.id)
)
refused_email_url = f"{URL}/dashboard/refused_email?highlight_id={email_log.id}"
LOG.d(
"Inform user %s about bounced email sent by %s to %s",
@ -1395,9 +1391,7 @@ def handle_spam(
LOG.d("Create spam email %s", refused_email)
refused_email_url = (
URL + f"/dashboard/refused_email?highlight_id=" + str(email_log.id)
)
refused_email_url = f"{URL}/dashboard/refused_email?highlight_id={email_log.id}"
disable_alias_link = f"{URL}/dashboard/unsubscribe/{alias.id}"
if is_reply:
@ -1542,7 +1536,7 @@ def handle_unsubscribe_user(user_id: int, mail_from: str) -> str:
send_email(
user.email,
f"You have been unsubscribed from SimpleLogin newsletter",
"You have been unsubscribed from SimpleLogin newsletter",
render(
"transactional/unsubscribe-newsletter.txt",
user=user,

View File

@ -9,7 +9,7 @@ from server import create_app
def load_pgp_public_keys():
"""Load PGP public key to keyring"""
for mailbox in Mailbox.query.filter(Mailbox.pgp_public_key != None).all():
for mailbox in Mailbox.query.filter(Mailbox.pgp_public_key.isnot(None)).all():
LOG.d("Load PGP key for mailbox %s", mailbox)
fingerprint = load_public_key(mailbox.pgp_public_key)
@ -21,7 +21,7 @@ def load_pgp_public_keys():
mailbox.pgp_finger_print = fingerprint
db.session.commit()
for contact in Contact.query.filter(Contact.pgp_public_key != None).all():
for contact in Contact.query.filter(Contact.pgp_public_key.insnot(None)).all():
LOG.d("Load PGP key for %s", contact)
fingerprint = load_public_key(contact.pgp_public_key)

View File

@ -57,7 +57,7 @@ def onboarding_send_from_alias(user):
send_email(
to_email,
f"SimpleLogin Tip: Send emails from your alias",
"SimpleLogin Tip: Send emails from your alias",
render("com/onboarding/send-from-alias.txt", user=user, to_email=to_email),
render("com/onboarding/send-from-alias.html", user=user, to_email=to_email),
unsubscribe_link,
@ -72,7 +72,7 @@ def onboarding_pgp(user):
send_email(
to_email,
f"SimpleLogin Tip: Secure your emails with PGP",
"SimpleLogin Tip: Secure your emails with PGP",
render("com/onboarding/pgp.txt", user=user, to_email=to_email),
render("com/onboarding/pgp.html", user=user, to_email=to_email),
unsubscribe_link,
@ -87,7 +87,7 @@ def onboarding_browser_extension(user):
send_email(
to_email,
f"SimpleLogin Tip: Chrome/Firefox/Safari extensions and Android/iOS apps",
"SimpleLogin Tip: Chrome/Firefox/Safari extensions and Android/iOS apps",
render("com/onboarding/browser-extension.txt", user=user, to_email=to_email),
render("com/onboarding/browser-extension.html", user=user, to_email=to_email),
unsubscribe_link,
@ -102,7 +102,7 @@ def onboarding_mailbox(user):
send_email(
to_email,
f"SimpleLogin Tip: Multiple mailboxes",
"SimpleLogin Tip: Multiple mailboxes",
render("com/onboarding/mailbox.txt", user=user, to_email=to_email),
render("com/onboarding/mailbox.html", user=user, to_email=to_email),
unsubscribe_link,
@ -121,7 +121,7 @@ def handle_batch_import(batch_import: BatchImport):
LOG.d("Download file %s from %s", batch_import.file, file_url)
r = requests.get(file_url)
lines = [l.decode() for l in r.iter_lines()]
lines = [line.decode() for line in r.iter_lines()]
reader = csv.DictReader(lines)
for row in reader:
@ -173,7 +173,7 @@ if __name__ == "__main__":
with app.app_context():
for job in Job.query.filter(
Job.taken == False, Job.run_at > min_dt, Job.run_at <= max_dt
Job.taken.is_(False), Job.run_at > min_dt, Job.run_at <= max_dt
).all():
LOG.d("Take job %s", job)

56
poetry.lock generated
View File

@ -413,6 +413,20 @@ category = "main"
optional = false
python-versions = "*"
[[package]]
name = "flake8"
version = "3.8.4"
description = "the modular source code checker: pep8 pyflakes and co"
category = "dev"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
[package.dependencies]
importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
mccabe = ">=0.6.0,<0.7.0"
pycodestyle = ">=2.6.0a1,<2.7.0"
pyflakes = ">=2.2.0,<2.3.0"
[[package]]
name = "flask"
version = "1.1.2"
@ -880,6 +894,14 @@ category = "main"
optional = false
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*"
[[package]]
name = "mccabe"
version = "0.6.1"
description = "McCabe checker, plugin for flake8"
category = "dev"
optional = false
python-versions = "*"
[[package]]
name = "memory-profiler"
version = "0.57.0"
@ -1119,6 +1141,14 @@ python-versions = "*"
[package.dependencies]
pyasn1 = ">=0.4.6,<0.5.0"
[[package]]
name = "pycodestyle"
version = "2.6.0"
description = "Python style guide checker"
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[[package]]
name = "pycparser"
version = "2.20"
@ -1135,6 +1165,14 @@ category = "main"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[[package]]
name = "pyflakes"
version = "2.2.0"
description = "passive checker of Python programs"
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[[package]]
name = "pygments"
version = "2.7.1"
@ -1690,7 +1728,7 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"]
[metadata]
lock-version = "1.1"
python-versions = "^3.7"
content-hash = "f1d1febeb8977d9365d17ea9bbbf88de19e5c24784f6769c13f44df0411347bc"
content-hash = "9ead7e73c3472edd0f5ebcfbcd480f2b7d6c601b3c25d58bb29c989bf682945b"
[metadata.files]
aiohttp = [
@ -1935,6 +1973,10 @@ filelock = [
{file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"},
{file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"},
]
flake8 = [
{file = "flake8-3.8.4-py2.py3-none-any.whl", hash = "sha256:749dbbd6bfd0cf1318af27bf97a14e28e5ff548ef8e5b1566ccfb25a11e7c839"},
{file = "flake8-3.8.4.tar.gz", hash = "sha256:aadae8761ec651813c24be05c6f7b4680857ef6afaae4651a4eccaef97ce6c3b"},
]
flask = [
{file = "Flask-1.1.2-py2.py3-none-any.whl", hash = "sha256:8a4fdd8936eba2512e9c85df320a37e694c93945b33ef33c89946a340a238557"},
{file = "Flask-1.1.2.tar.gz", hash = "sha256:4efa1ae2d7c9865af48986de8aeb8504bf32c7f3d6fdc9353d34b21f4b127060"},
@ -2147,6 +2189,10 @@ markupsafe = [
{file = "MarkupSafe-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"},
{file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"},
]
mccabe = [
{file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
{file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
]
memory-profiler = [
{file = "memory_profiler-0.57.0.tar.gz", hash = "sha256:23b196f91ea9ac9996e30bfab1e82fecc30a4a1d24870e81d1e81625f786a2c3"},
]
@ -2331,6 +2377,10 @@ pyasn1-modules = [
{file = "pyasn1_modules-0.2.8-py3.6.egg", hash = "sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0"},
{file = "pyasn1_modules-0.2.8-py3.7.egg", hash = "sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd"},
]
pycodestyle = [
{file = "pycodestyle-2.6.0-py2.py3-none-any.whl", hash = "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367"},
{file = "pycodestyle-2.6.0.tar.gz", hash = "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"},
]
pycparser = [
{file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"},
{file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"},
@ -2372,6 +2422,10 @@ pycryptodome = [
{file = "pycryptodome-3.9.8-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:9f62d21bc693f3d7d444f17ed2ad7a913b4c37c15cd807895d013c39c0517dfd"},
{file = "pycryptodome-3.9.8.tar.gz", hash = "sha256:0e24171cf01021bc5dc17d6a9d4f33a048f09d62cc3f62541e95ef104588bda4"},
]
pyflakes = [
{file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"},
{file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"},
]
pygments = [
{file = "Pygments-2.7.1-py3-none-any.whl", hash = "sha256:307543fe65c0947b126e83dd5a61bd8acbd84abec11f43caebaf5534cbc17998"},
{file = "Pygments-2.7.1.tar.gz", hash = "sha256:926c3f319eda178d1bd90851e4317e6d8cdb5e292a3386aac9bd75eca29cf9c7"},

View File

@ -81,6 +81,7 @@ pytest = "^6.1.0"
black = "^20.8b1"
pre-commit = "^2.7.1"
pytest-cov = "^2.10.1"
flake8 = "^3.8.4"
[build-system]
requires = ["poetry>=0.12"]

View File

@ -77,7 +77,6 @@ from app.models import (
Referral,
AliasMailbox,
Notification,
SLDomain,
)
from app.monitor.base import monitor_bp
from app.oauth.base import oauth_bp
@ -94,7 +93,7 @@ if SENTRY_DSN:
],
)
# the app is served behin nginx which uses http and not https
# the app is served behind nginx which uses http and not https
os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"
@ -419,7 +418,7 @@ def setup_error_page(app):
return render_template("error/403.html"), 403
@app.errorhandler(429)
def forbidden(e):
def rate_limited(e):
LOG.warning("Client hit rate limit on path %s", request.path)
if request.path.startswith("/api/"):
return jsonify(error="Rate limit exceeded"), 429
@ -588,7 +587,7 @@ def setup_paddle_callback(app: Flask):
send_email(
user.email,
f"SimpleLogin - what can we do to improve the product?",
"SimpleLogin - what can we do to improve the product?",
render(
"transactional/subscription-cancel.txt",
name=user.name or "",

View File

@ -4,14 +4,18 @@ import flask_migrate
from IPython import embed
from sqlalchemy_utils import create_database, database_exists, drop_database
from app.config import (
DB_URI,
ALIAS_DOMAINS,
PREMIUM_ALIAS_DOMAINS,
)
from app.dns_utils import get_ns
from app.config import DB_URI
from app.email_utils import send_email, render, get_email_domain_part
from app.models import *
from app.log import LOG
from app.extensions import db
from app.models import (
User,
DeletedAlias,
SLDomain,
CustomDomain,
DomainDeletedAlias,
Mailbox,
)
from job_runner import (
onboarding_pgp,
onboarding_browser_extension,
@ -129,7 +133,7 @@ def disable_mailbox(mailbox_id):
email_msg = f"""Hi,
Your mailbox {mailbox.email} cannot receive emails.
Your mailbox {mailbox.email} cannot receive emails.
To avoid forwarding emails to an invalid mailbox, we have disabled this mailbox along with all of its aliases.
If this is a mistake, please reply to this email.

View File

@ -22,7 +22,7 @@ def test_auth_login_success_mfa_disabled(flask_client):
assert r.status_code == 200
assert r.json["api_key"]
assert r.json["email"]
assert r.json["mfa_enabled"] == False
assert not r.json["mfa_enabled"]
assert r.json["mfa_key"] is None
assert r.json["name"] == "Test User"
@ -48,7 +48,7 @@ def test_auth_login_success_mfa_enabled(flask_client):
assert r.status_code == 200
assert r.json["api_key"] is None
assert r.json["mfa_enabled"] == True
assert r.json["mfa_enabled"]
assert r.json["mfa_key"]
assert r.json["name"] == "Test User"
@ -70,7 +70,7 @@ def test_auth_login_device_exist(flask_client):
assert r.status_code == 200
api_key = r.json["api_key"]
assert r.json["mfa_enabled"] == False
assert not r.json["mfa_enabled"]
assert r.json["mfa_key"] is None
assert r.json["name"] == "Test User"

View File

@ -1,7 +1,5 @@
import json
from app.alias_utils import delete_alias
from app.models import CustomDomain, DomainDeletedAlias, Alias
from app.models import CustomDomain, Alias
from tests.utils import login

View File

@ -1,12 +1,12 @@
from flask import url_for
from app.extensions import db
from app.models import User, ApiKey, Mailbox
from app.models import Mailbox
from tests.utils import login
def test_create_mailbox(flask_client):
user = login(flask_client)
login(flask_client)
r = flask_client.post(
"/api/mailboxes",

View File

@ -161,7 +161,7 @@ def test_cannot_create_alias_in_trash(flask_client):
db.session.commit()
# create new alias with note
suffix = f"@ab.cd"
suffix = "@ab.cd"
suffix = signer.sign(suffix).decode()
r = flask_client.post(
@ -176,7 +176,7 @@ def test_cannot_create_alias_in_trash(flask_client):
# assert alias creation is successful
assert r.status_code == 201
assert r.json["alias"] == f"prefix@ab.cd"
assert r.json["alias"] == "prefix@ab.cd"
# delete alias: it's going to be moved to ab.cd trash
alias = Alias.get_by(email="prefix@ab.cd")

View File

@ -1,11 +1,9 @@
import json
from app.models import CustomDomain, AliasGeneratorEnum, SenderFormatEnum
from tests.utils import login, pretty
from tests.utils import login
def test_get_setting(flask_client):
user = login(flask_client)
login(flask_client)
r = flask_client.get("/api/setting")
assert r.status_code == 200

View File

@ -1,5 +1,6 @@
import os
# flake8: noqa: E402
os.environ["CONFIG"] = os.path.abspath(
os.path.join(os.path.dirname(os.path.dirname(__file__)), "tests/test.env")

View File

@ -1,6 +1,5 @@
from flask import url_for
from app.config import EMAIL_DOMAIN
from app.models import (
Alias,
Contact,

View File

@ -208,7 +208,7 @@ def test_add_alias_in_custom_domain_trash(flask_client):
# delete a custom-domain alias: alias should go the DomainDeletedAlias
alias = Alias.create(
user_id=user.id,
email=f"prefix@ab.cd",
email="prefix@ab.cd",
custom_domain_id=custom_domain.id,
mailbox_id=user.default_mailbox_id,
commit=True,
@ -219,7 +219,7 @@ def test_add_alias_in_custom_domain_trash(flask_client):
assert DomainDeletedAlias.query.count() == 1
# create the same alias, should return error
suffix = f"@ab.cd"
suffix = "@ab.cd"
signed_suffix = signer.sign(suffix).decode()
r = flask_client.post(
url_for("dashboard.custom_alias"),

View File

@ -622,7 +622,7 @@ def test_authorize_code_id_token_flow(flask_client):
def test_authorize_page_invalid_client_id(flask_client):
"""make sure to redirect user to redirect_url?error=invalid_client_id"""
user = login(flask_client)
client = Client.create_new("test client", user.id)
Client.create_new("test client", user.id)
db.session.commit()

View File

@ -1,4 +1,4 @@
from app.dns_utils import *
from app.dns_utils import get_mx_domains, get_spf_domain, get_txt_record
# use our own domain for test
_DOMAIN = "simplelogin.io"
@ -20,6 +20,5 @@ def test_get_spf_domain():
def test_get_txt_record():
r = get_txt_record(_DOMAIN)
assert len(r) > 0

View File

@ -27,6 +27,8 @@ from app.extensions import db
from app.models import User, CustomDomain
from tests.utils import login
# flake8: noqa: E101, W191
def test_get_email_domain_part():
assert get_email_domain_part("ab@cd.com") == "cd.com"
@ -141,8 +143,8 @@ def test_copy():
From: abcd@gmail.com
To: hey@example.org
Subject: subject
Body
Body
"""
msg = email.message_from_string(email_str)
msg2 = copy(msg)

View File

@ -10,7 +10,6 @@ from app.models import (
Alias,
Contact,
Mailbox,
AliasMailbox,
SenderFormatEnum,
EnumE,
)