From e47e5a52552f553bdab9fdadcbad3b3f22f7f378 Mon Sep 17 00:00:00 2001 From: MrMeeb Date: Mon, 27 Jan 2025 12:00:07 +0000 Subject: [PATCH] 4.64.3 --- app/app/api/views/setting.py | 3 ++- app/app/dashboard/views/account_setting.py | 6 +++-- app/app/dashboard/views/setting.py | 3 ++- app/app/fake_data.py | 27 ++++++++++++++++++++++ app/app/proton/utils.py | 14 ++++++++--- app/email_handler.py | 15 ++++++------ app/init_app.py | 5 ++-- app/server.py | 3 +-- app/templates/dashboard/setting.html | 2 +- 9 files changed, 59 insertions(+), 19 deletions(-) diff --git a/app/app/api/views/setting.py b/app/app/api/views/setting.py index 7f04a7b..f58c7fb 100644 --- a/app/app/api/views/setting.py +++ b/app/app/api/views/setting.py @@ -144,5 +144,6 @@ def get_available_domains_for_random_alias_v2(): @require_api_auth def unlink_proton_account(): user = g.user - perform_proton_account_unlink(user) + if not perform_proton_account_unlink(user): + return jsonify(error="The account cannot be unlinked"), 400 return jsonify({"ok": True}) diff --git a/app/app/dashboard/views/account_setting.py b/app/app/dashboard/views/account_setting.py index d1fb4cf..efd1649 100644 --- a/app/app/dashboard/views/account_setting.py +++ b/app/app/dashboard/views/account_setting.py @@ -239,6 +239,8 @@ def unlink_proton_account(): flash("Invalid request", "warning") return redirect(url_for("dashboard.setting")) - perform_proton_account_unlink(current_user) - flash("Your Proton account has been unlinked", "success") + if not perform_proton_account_unlink(current_user): + flash("Account cannot be unlinked", "warning") + else: + flash("Your Proton account has been unlinked", "success") return redirect(url_for("dashboard.setting")) diff --git a/app/app/dashboard/views/setting.py b/app/app/dashboard/views/setting.py index f0de91a..c912dc4 100644 --- a/app/app/dashboard/views/setting.py +++ b/app/app/dashboard/views/setting.py @@ -41,7 +41,7 @@ from app.models import ( PartnerSubscription, UnsubscribeBehaviourEnum, ) -from app.proton.utils import get_proton_partner +from app.proton.utils import get_proton_partner, can_unlink_proton_account from app.utils import ( random_string, CSRFValidationForm, @@ -323,4 +323,5 @@ def setting(): ALIAS_RAND_SUFFIX_LENGTH=ALIAS_RANDOM_SUFFIX_LENGTH, connect_with_proton=CONNECT_WITH_PROTON, proton_linked_account=proton_linked_account, + can_unlink_proton_account=can_unlink_proton_account(current_user), ) diff --git a/app/app/fake_data.py b/app/app/fake_data.py index b5b0d0b..78c5050 100644 --- a/app/app/fake_data.py +++ b/app/app/fake_data.py @@ -33,8 +33,11 @@ from app.models import ( SLDomain, Hibp, AliasHibp, + PartnerUser, + PartnerSubscription, ) from app.pgp_utils import load_public_key +from app.proton.utils import get_proton_partner def fake_data(): @@ -269,3 +272,27 @@ def fake_data(): CustomDomain.create( user_id=user.id, domain="old.com", verified=True, ownership_verified=True ) + + # Create a user + proton_partner = get_proton_partner() + user = User.create( + email="test@proton.me", + name="Proton test", + password="password", + activated=True, + is_admin=False, + intro_shown=True, + from_partner=True, + flush=True, + ) + pu = PartnerUser.create( + user_id=user.id, + partner_id=proton_partner.id, + partner_email="test@proton.me", + external_user_id="DUMMY", + flush=True, + ) + PartnerSubscription.create( + partner_user_id=pu.id, end_at=arrow.now().shift(years=1, days=1) + ) + Session.commit() diff --git a/app/app/proton/utils.py b/app/app/proton/utils.py index abbd3a9..0bd4ff3 100644 --- a/app/app/proton/utils.py +++ b/app/app/proton/utils.py @@ -1,9 +1,10 @@ -from newrelic import agent from typing import Optional +from newrelic import agent + from app.db import Session -from app.log import LOG from app.errors import ProtonPartnerNotSetUp +from app.log import LOG from app.models import Partner, PartnerUser, User from app.user_audit_log_utils import emit_user_audit_log, UserAuditLogAction @@ -26,7 +27,13 @@ def is_proton_partner(partner: Partner) -> bool: return partner.name == PROTON_PARTNER_NAME -def perform_proton_account_unlink(current_user: User): +def can_unlink_proton_account(user: User) -> bool: + return (user.flags & User.FLAG_CREATED_FROM_PARTNER) == 0 + + +def perform_proton_account_unlink(current_user: User) -> bool: + if not can_unlink_proton_account(current_user): + return False proton_partner = get_proton_partner() partner_user = PartnerUser.get_by( user_id=current_user.id, partner_id=proton_partner.id @@ -41,3 +48,4 @@ def perform_proton_account_unlink(current_user: User): PartnerUser.delete(partner_user.id) Session.commit() agent.record_custom_event("AccountUnlinked", {"partner": proton_partner.name}) + return True diff --git a/app/email_handler.py b/app/email_handler.py index d5e03b3..eef1e79 100644 --- a/app/email_handler.py +++ b/app/email_handler.py @@ -47,11 +47,6 @@ from typing import List, Tuple, Optional import newrelic.agent from aiosmtpd.controller import Controller from aiosmtpd.smtp import Envelope -from email_validator import validate_email, EmailNotValidError -from flanker.addresslib import address -from flanker.addresslib.address import EmailAddress -from sqlalchemy.exc import IntegrityError - from app import pgp_utils, s3, config, contact_utils from app.alias_utils import ( try_auto_create, @@ -174,8 +169,12 @@ from app.pgp_utils import ( load_public_key_and_check, ) from app.utils import sanitize_email +from email_validator import validate_email, EmailNotValidError +from flanker.addresslib import address +from flanker.addresslib.address import EmailAddress from init_app import load_pgp_public_keys from server import create_light_app +from sqlalchemy.exc import IntegrityError def get_or_create_contact( @@ -606,9 +605,11 @@ def handle_forward(envelope, msg: Message, rcpt_to: str) -> List[Tuple[bool, str if reply_to_email == alias.email: LOG.i("Reply-to same as alias %s", alias) else: - reply_to_contact.append( - get_or_create_reply_to_contact(reply_to_email, alias, msg) + reply_contact = get_or_create_reply_to_contact( + reply_to_email, alias, msg ) + if reply_contact: + reply_to_contact.append(reply_contact) if alias.user.delete_on is not None: LOG.d(f"user {user} is pending to be deleted. Do not forward") diff --git a/app/init_app.py b/app/init_app.py index e911669..ced9087 100644 --- a/app/init_app.py +++ b/app/init_app.py @@ -56,14 +56,15 @@ def add_sl_domains(): Session.commit() -def add_proton_partner(): +def add_proton_partner() -> Partner: proton_partner = Partner.get_by(name=PROTON_PARTNER_NAME) if not proton_partner: - Partner.create( + proton_partner = Partner.create( name=PROTON_PARTNER_NAME, contact_email="simplelogin@protonmail.com", ) Session.commit() + return proton_partner if __name__ == "__main__": diff --git a/app/server.py b/app/server.py index e707b03..507b885 100644 --- a/app/server.py +++ b/app/server.py @@ -8,7 +8,6 @@ import flask_limiter import flask_profiler import newrelic.agent import sentry_sdk - from flask import ( Flask, redirect, @@ -498,9 +497,9 @@ def register_custom_commands(app): from init_app import add_sl_domains, add_proton_partner LOG.w("reset db, add fake data") + add_proton_partner() fake_data() add_sl_domains() - add_proton_partner() @app.cli.command("send-newsletter") @click.option("-n", "--newsletter_id", type=int, help="Newsletter ID to be sent") diff --git a/app/templates/dashboard/setting.html b/app/templates/dashboard/setting.html index e595f11..bef06dc 100644 --- a/app/templates/dashboard/setting.html +++ b/app/templates/dashboard/setting.html @@ -144,7 +144,7 @@ - {% if connect_with_proton %} + {% if connect_with_proton and can_unlink_proton_account %}