From df59d73d665d534b8037d5fa363dbe66786e4f81 Mon Sep 17 00:00:00 2001 From: MrMeeb Date: Fri, 25 Aug 2023 12:00:05 +0100 Subject: [PATCH] 4.34.2 --- app/app/dashboard/views/mailbox_detail.py | 13 +- app/app/errors.py | 7 + app/app/proton/proton_client.py | 20 +- app/email_handler.py | 25 +-- .../dashboard/alias_contact_manager.html | 1 + app/templates/dashboard/app.html | 2 +- app/templates/dashboard/mailbox_detail.html | 204 +++++++++--------- app/templates/dashboard/pricing.html | 28 +-- app/templates/dashboard/referral.html | 2 +- app/templates/dashboard/unsubscribe.html | 2 +- app/templates/oauth/authorize.html | 2 +- app/tests/proton/test_proton_client.py | 29 +++ 12 files changed, 175 insertions(+), 160 deletions(-) diff --git a/app/app/dashboard/views/mailbox_detail.py b/app/app/dashboard/views/mailbox_detail.py index a2e8558..06527b4 100644 --- a/app/app/dashboard/views/mailbox_detail.py +++ b/app/app/dashboard/views/mailbox_detail.py @@ -191,25 +191,16 @@ def mailbox_detail_route(mailbox_id): ) elif request.form.get("form-name") == "generic-subject": if request.form.get("action") == "save": - if not mailbox.pgp_enabled(): - flash( - "Generic subject can only be used on PGP-enabled mailbox", - "error", - ) - return redirect( - url_for("dashboard.mailbox_detail_route", mailbox_id=mailbox_id) - ) - mailbox.generic_subject = request.form.get("generic-subject") Session.commit() - flash("Generic subject for PGP-encrypted email is enabled", "success") + flash("Generic subject is enabled", "success") return redirect( url_for("dashboard.mailbox_detail_route", mailbox_id=mailbox_id) ) elif request.form.get("action") == "remove": mailbox.generic_subject = None Session.commit() - flash("Generic subject for PGP-encrypted email is disabled", "success") + flash("Generic subject is disabled", "success") return redirect( url_for("dashboard.mailbox_detail_route", mailbox_id=mailbox_id) ) diff --git a/app/app/errors.py b/app/app/errors.py index b951eb1..113b248 100644 --- a/app/app/errors.py +++ b/app/app/errors.py @@ -121,3 +121,10 @@ class AccountAlreadyLinkedToAnotherUserException(LinkException): class AccountIsUsingAliasAsEmail(LinkException): def __init__(self): super().__init__("Your account has an alias as it's email address") + + +class ProtonAccountNotVerified(LinkException): + def __init__(self): + super().__init__( + "The Proton account you are trying to use has not been verified" + ) diff --git a/app/app/proton/proton_client.py b/app/app/proton/proton_client.py index 9f4beac..f06325b 100644 --- a/app/app/proton/proton_client.py +++ b/app/app/proton/proton_client.py @@ -7,11 +7,12 @@ from typing import Optional from app.account_linking import SLPlan, SLPlanType from app.config import PROTON_EXTRA_HEADER_NAME, PROTON_EXTRA_HEADER_VALUE +from app.errors import ProtonAccountNotVerified from app.log import LOG _APP_VERSION = "OauthClient_1.0.0" -PROTON_ERROR_CODE_NOT_EXISTS = 2501 +PROTON_ERROR_CODE_HV_NEEDED = 9001 PLAN_FREE = 1 PLAN_PREMIUM = 2 @@ -57,6 +58,15 @@ def convert_access_token(access_token_response: str) -> AccessCredentials: ) +def handle_response_not_ok(status: int, body: dict, text: str) -> Exception: + if status == HTTPStatus.UNPROCESSABLE_ENTITY: + res_code = body.get("Code") + if res_code == PROTON_ERROR_CODE_HV_NEEDED: + return ProtonAccountNotVerified() + + return Exception(f"Unexpected status code. Wanted 200 and got {status}: " + text) + + class ProtonClient(ABC): @abstractmethod def get_user(self) -> Optional[UserInformation]: @@ -124,11 +134,11 @@ class HttpProtonClient(ProtonClient): @staticmethod def __validate_response(res: Response) -> dict: status = res.status_code - if status != HTTPStatus.OK: - raise Exception( - f"Unexpected status code. Wanted 200 and got {status}: " + res.text - ) as_json = res.json() + if status != HTTPStatus.OK: + raise HttpProtonClient.__handle_response_not_ok( + status=status, body=as_json, text=res.text + ) res_code = as_json.get("Code") if not res_code or res_code != 1000: raise Exception( diff --git a/app/email_handler.py b/app/email_handler.py index 7db73bc..4ccba49 100644 --- a/app/email_handler.py +++ b/app/email_handler.py @@ -878,21 +878,22 @@ def forward_email_to_mailbox( headers_to_keep.append(headers.AUTHENTICATION_RESULTS) delete_all_headers_except(msg, headers_to_keep) + if mailbox.generic_subject: + LOG.d("Use a generic subject for %s", mailbox) + orig_subject = msg[headers.SUBJECT] + orig_subject = get_header_unicode(orig_subject) + add_or_replace_header(msg, "Subject", mailbox.generic_subject) + sender = msg[headers.FROM] + sender = get_header_unicode(sender) + msg = add_header( + msg, + f"""Forwarded by SimpleLogin to {alias.email} from "{sender}" with "{orig_subject}" as subject""", + f"""Forwarded by SimpleLogin to {alias.email} from "{sender}" with {orig_subject} as subject""", + ) + # create PGP email if needed if mailbox.pgp_enabled() and user.is_premium() and not alias.disable_pgp: LOG.d("Encrypt message using mailbox %s", mailbox) - if mailbox.generic_subject: - LOG.d("Use a generic subject for %s", mailbox) - orig_subject = msg[headers.SUBJECT] - orig_subject = get_header_unicode(orig_subject) - add_or_replace_header(msg, "Subject", mailbox.generic_subject) - sender = msg[headers.FROM] - sender = get_header_unicode(sender) - msg = add_header( - msg, - f"""Forwarded by SimpleLogin to {alias.email} from "{sender}" with "{orig_subject}" as subject""", - f"""Forwarded by SimpleLogin to {alias.email} from "{sender}" with {orig_subject} as subject""", - ) try: msg = prepare_pgp_message( diff --git a/app/templates/dashboard/alias_contact_manager.html b/app/templates/dashboard/alias_contact_manager.html index a9b355d..2a2bc1d 100644 --- a/app/templates/dashboard/alias_contact_manager.html +++ b/app/templates/dashboard/alias_contact_manager.html @@ -133,6 +133,7 @@
diff --git a/app/templates/dashboard/app.html b/app/templates/dashboard/app.html index 1700276..b4d8dcf 100644 --- a/app/templates/dashboard/app.html +++ b/app/templates/dashboard/app.html @@ -48,7 +48,7 @@ {% if scope == "email" %} Email: - {{ val }} + {{ val }} {% elif scope == "name" %} Name: {{ val }} {% endif %} diff --git a/app/templates/dashboard/mailbox_detail.html b/app/templates/dashboard/mailbox_detail.html index 9c6687a..61a2c05 100644 --- a/app/templates/dashboard/mailbox_detail.html +++ b/app/templates/dashboard/mailbox_detail.html @@ -137,123 +137,115 @@
-
-
- {{ csrf_form.csrf_token }} - -
-
- Hide email subject when PGP is enabled -
- When PGP is enabled, you can choose to use a generic subject for the forwarded emails. - The original subject is then added into the email body. -
- As PGP does not encrypt the email subject and the email subject might contain sensitive information, - this option will allow a further protection of your email content. -
-
-
- As the email is encrypted, a subject like "Email for you" - will probably be rejected by your mailbox since it sounds like a spam. -
- Something like "Encrypted Email" would work much better :). -
-
- - -
- - {% if mailbox.generic_subject %} - - - {% endif %} -
-
-
- -
-

Advanced Options

- {% if spf_available %} - -
-
- {{ csrf_form.csrf_token }} - -
-
- Enforce SPF -
- To avoid email-spoofing, SimpleLogin blocks email that - seems to come from your - mailbox - but sent from unknown - IP address. -
- Only turn off this option if you know what you're doing :). -
-
- -
-
-
- {% endif %} -
+
+
+
+ {{ csrf_form.csrf_token }} +
- Authorized addresses -
- Emails sent from these addresses to a reverse-alias are considered as being sent - from {{ mailbox.email }} + Hide email subject +
+ The original subject will be added to the email body and all forwarded emails will have the generic subject. +
+ This option is often used when PGP is enabled. + As PGP does not encrypt the email subject, it allows a further protection of your email content.
- {% if mailbox.authorized_addresses | length == 0 %} +
+ + +
+ + {% if mailbox.generic_subject %} - {% else %} -
    - {% for authorized_address in mailbox.authorized_addresses %} - -
  • - {{ authorized_address.email }} - - {{ csrf_form.csrf_token }} - - - -
  • - - {% endfor %} -
+ {% endif %} -
- {{ csrf_form.csrf_token }} - - - -
+ +
+
+

Advanced Options

+ {% if spf_available %} + +
+
+ {{ csrf_form.csrf_token }} + +
+
+ Enforce SPF +
+ To avoid email-spoofing, SimpleLogin blocks email that + seems to come from your + mailbox + but sent from unknown + IP address. +
+ Only turn off this option if you know what you're doing :). +
+
+ +
+
+
+ {% endif %} +
+
+
+ Authorized addresses +
+ Emails sent from these addresses to a reverse-alias are considered as being sent + from {{ mailbox.email }} +
+
+ {% if mailbox.authorized_addresses | length == 0 %} + + {% else %} +
    + {% for authorized_address in mailbox.authorized_addresses %} + +
  • + {{ authorized_address.email }} +
    + {{ csrf_form.csrf_token }} + + + +
    +
  • + {% endfor %} +
+ {% endif %} +
+ {{ csrf_form.csrf_token }} + + + +
- {% endblock %} - {% block script %} - - + - {% endblock %} + +{% endblock %} diff --git a/app/templates/dashboard/pricing.html b/app/templates/dashboard/pricing.html index fbd1a34..462e1e7 100644 --- a/app/templates/dashboard/pricing.html +++ b/app/templates/dashboard/pricing.html @@ -207,7 +207,7 @@
Proton plan
-
Starts at $11.99 / month
+
Starts at $12.99 / month
  • , which currently supports Bitcoin, Bitcoin Cash, DAI, ApeCoin, Dogecoin, Ethereum, Litecoin, SHIBA INU, Tether and USD Coin.

    - In the future, we are going to support Monero as well. In the meantime, please send us an email at support@simplelogin.zendesk.com if you want to use this cryptocurrency. + In the future, we are going to support Monero as well. In the meantime, please send us an email at support@simplelogin.zendesk.com if you want to use this cryptocurrency.

    - Please send us an email at support@simplelogin.zendesk.com for more info. + Please send us an email at support@simplelogin.zendesk.com for more info.

    We used to offer free premium accounts for students but this program ended at June 17 2021. Please note this doesn't affect existing accounts who have already benefited from the program or requests sent before this date. @@ -708,7 +692,7 @@ data-parent="#pricing-faq">

    - No we don't have a family plan but offer 30% reduction for additional subscriptions. Please contact us at support@simplelogin.zendesk.com for more information. + No we don't have a family plan but offer 30% reduction for additional subscriptions. Please contact us at support@simplelogin.zendesk.com for more information.

    diff --git a/app/templates/dashboard/referral.html b/app/templates/dashboard/referral.html index aab7dde..66acf71 100644 --- a/app/templates/dashboard/referral.html +++ b/app/templates/dashboard/referral.html @@ -22,7 +22,7 @@ For every user who upgrades and stays with us at least 3 months, you'll get $5 :).
    The payout can be initiated any time, just send us an email at - hi@simplelogin.io + hi@simplelogin.io when you want to receive the payout.
  • {% if referrals|length == 0 %} diff --git a/app/templates/dashboard/unsubscribe.html b/app/templates/dashboard/unsubscribe.html index 4e7a4c6..f1cfa87 100644 --- a/app/templates/dashboard/unsubscribe.html +++ b/app/templates/dashboard/unsubscribe.html @@ -9,7 +9,7 @@

    Block alias

    You are about to block the alias - {{ alias }} + {{ alias }}

    After this, you will stop receiving all emails sent to this alias, please confirm.

    diff --git a/app/templates/oauth/authorize.html b/app/templates/oauth/authorize.html index 082f250..6ea55aa 100644 --- a/app/templates/oauth/authorize.html +++ b/app/templates/oauth/authorize.html @@ -61,7 +61,7 @@ {% elif scope == Scope.EMAIL %} {{ scope.value }}: - {{ user_info[scope.value] }} + {{ user_info[scope.value] }} {% elif scope == Scope.NAME %} {{ scope.value }}: {{ user_info[scope.value] }} {% endif %} diff --git a/app/tests/proton/test_proton_client.py b/app/tests/proton/test_proton_client.py index 3879e76..154cc0a 100644 --- a/app/tests/proton/test_proton_client.py +++ b/app/tests/proton/test_proton_client.py @@ -1,5 +1,7 @@ import pytest +from http import HTTPStatus +from app.errors import ProtonAccountNotVerified from app.proton import proton_client @@ -19,3 +21,30 @@ def test_convert_access_token_not_containing_invalid_length(): for case in cases: with pytest.raises(Exception): proton_client.convert_access_token(case) + + +def test_handle_response_not_ok_account_not_verified(): + res = proton_client.handle_response_not_ok( + status=HTTPStatus.UNPROCESSABLE_ENTITY, + body={"Code": proton_client.PROTON_ERROR_CODE_HV_NEEDED}, + text="", + ) + assert isinstance(res, ProtonAccountNotVerified) + + +def test_handle_response_unprocessable_entity_not_account_not_verified(): + error_text = "some error text" + res = proton_client.handle_response_not_ok( + status=HTTPStatus.UNPROCESSABLE_ENTITY, body={"Code": 4567}, text=error_text + ) + assert error_text in res.args[0] + + +def test_handle_response_not_ok_unknown_error(): + error_text = "some error text" + res = proton_client.handle_response_not_ok( + status=123, + body={"Code": proton_client.PROTON_ERROR_CODE_HV_NEEDED}, + text=error_text, + ) + assert error_text in res.args[0]