Merge pull request #234 from simple-login/random-alias-domain
Random alias domain
This commit is contained in:
commit
5e464a824c
|
@ -150,24 +150,19 @@
|
|||
<button class="btn btn-outline-primary">Update</button>
|
||||
</form>
|
||||
|
||||
{% if current_user.has_custom_domain() %}
|
||||
<div class="mt-3 mb-1">Select the domain for random aliases.</div>
|
||||
<form method="post" action="#random-alias" class="form-inline">
|
||||
<input type="hidden" name="form-name" value="change-random-alias-default-domain">
|
||||
<select class="form-control mr-sm-2" name="random-alias-default-domain">
|
||||
<option value="" {% if not current_user.default_random_alias_domain_id %} selected {% endif %}>
|
||||
{{ FIRST_ALIAS_DOMAIN }} (SimpleLogin domain)
|
||||
</option>
|
||||
{% for domain in current_user.custom_domains() %}
|
||||
<option value="{{ domain.id }}"
|
||||
{% if current_user.default_random_alias_domain_id == domain.id %} selected {% endif %} >
|
||||
{{ domain.domain }} (your domain)
|
||||
</option>
|
||||
<div class="mt-3 mb-1">Select the domain for random aliases.</div>
|
||||
<form method="post" action="#random-alias" class="form-inline">
|
||||
<input type="hidden" name="form-name" value="change-random-alias-default-domain">
|
||||
<select class="form-control mr-sm-2" name="random-alias-default-domain">
|
||||
{% for is_public, domain in current_user.available_domains_for_random_alias() %}
|
||||
<option value="{{ domain }}"
|
||||
{% if current_user.default_random_alias_domain() == domain %} selected {% endif %} >
|
||||
{{ domain }} ({% if is_public %} SimpleLogin domain {% else %} your domain {% endif %})
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<button class="btn btn-outline-primary">Update</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
</select>
|
||||
<button class="btn btn-outline-primary">Update</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ from app.models import (
|
|||
AliasGeneratorEnum,
|
||||
ManualSubscription,
|
||||
SenderFormatEnum,
|
||||
PublicDomain,
|
||||
)
|
||||
from app.utils import random_string
|
||||
|
||||
|
@ -162,20 +163,28 @@ def setting():
|
|||
elif request.form.get("form-name") == "change-random-alias-default-domain":
|
||||
default_domain = request.form.get("random-alias-default-domain")
|
||||
if default_domain:
|
||||
default_domain_id = int(default_domain)
|
||||
# sanity check
|
||||
domain = CustomDomain.get(default_domain_id)
|
||||
if (
|
||||
not domain
|
||||
or domain.user_id != current_user.id
|
||||
or not domain.verified
|
||||
):
|
||||
flash(
|
||||
"Something went wrong, sorry for the inconvenience. Please retry. ",
|
||||
"error",
|
||||
)
|
||||
return redirect(url_for("dashboard.setting"))
|
||||
current_user.default_random_alias_domain_id = default_domain_id
|
||||
custom_domain = CustomDomain.get_by(domain=default_domain)
|
||||
if custom_domain:
|
||||
# sanity check
|
||||
if (
|
||||
custom_domain.user_id != current_user.id
|
||||
or not custom_domain.verified
|
||||
):
|
||||
LOG.error(
|
||||
"%s cannot use domain %s", current_user, default_domain
|
||||
)
|
||||
else:
|
||||
# make sure only default_random_alias_domain_id or default_random_alias_public_domain_id is set
|
||||
current_user.default_random_alias_domain_id = custom_domain.id
|
||||
current_user.default_random_alias_public_domain_id = None
|
||||
else:
|
||||
public_domain = PublicDomain.get_by(domain=default_domain)
|
||||
if public_domain:
|
||||
# make sure only default_random_alias_domain_id or default_random_alias_public_domain_id is set
|
||||
current_user.default_random_alias_public_domain_id = (
|
||||
public_domain.id
|
||||
)
|
||||
current_user.default_random_alias_domain_id = None
|
||||
else:
|
||||
current_user.default_random_alias_domain_id = None
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import enum
|
|||
import random
|
||||
import uuid
|
||||
from email.utils import formataddr
|
||||
from typing import List
|
||||
from typing import List, Tuple
|
||||
|
||||
import arrow
|
||||
import bcrypt
|
||||
|
@ -166,8 +166,18 @@ class User(db.Model, ModelMixin, UserMixin):
|
|||
# Fields for WebAuthn
|
||||
fido_uuid = db.Column(db.String(), nullable=True, unique=True)
|
||||
|
||||
# the default domain that's used when user creates a new random alias
|
||||
# default_random_alias_domain_id XOR default_random_alias_public_domain_id
|
||||
default_random_alias_domain_id = db.Column(
|
||||
db.ForeignKey("custom_domain.id"), nullable=True, default=None
|
||||
db.ForeignKey("custom_domain.id", ondelete="SET NULL"),
|
||||
nullable=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
default_random_alias_public_domain_id = db.Column(
|
||||
db.ForeignKey("public_domain.id", ondelete="SET NULL"),
|
||||
nullable=True,
|
||||
default=None,
|
||||
)
|
||||
|
||||
# some users could have lifetime premium
|
||||
|
@ -452,6 +462,49 @@ class User(db.Model, ModelMixin, UserMixin):
|
|||
def custom_domains(self):
|
||||
return CustomDomain.filter_by(user_id=self.id, verified=True).all()
|
||||
|
||||
def available_domains_for_random_alias(self) -> List[Tuple[bool, str]]:
|
||||
"""Return available domains for user to create random aliases
|
||||
Each result record contains:
|
||||
- whether the domain is public (i.e. belongs to SimpleLogin)
|
||||
- the domain
|
||||
"""
|
||||
res = []
|
||||
for public_domain in PublicDomain.query.all():
|
||||
res.append((True, public_domain.domain))
|
||||
|
||||
for custom_domain in CustomDomain.filter_by(
|
||||
user_id=self.id, verified=True
|
||||
).all():
|
||||
res.append((False, custom_domain.domain))
|
||||
|
||||
return res
|
||||
|
||||
def default_random_alias_domain(self) -> str:
|
||||
"""return the domain used for the random alias"""
|
||||
if self.default_random_alias_domain_id:
|
||||
custom_domain = CustomDomain.get(self.default_random_alias_domain_id)
|
||||
# sanity check
|
||||
if (
|
||||
not custom_domain
|
||||
or not custom_domain.verified
|
||||
or custom_domain.user_id != self.id
|
||||
):
|
||||
LOG.error("Problem with %s default random alias domain", self)
|
||||
return FIRST_ALIAS_DOMAIN
|
||||
|
||||
return custom_domain.domain
|
||||
|
||||
if self.default_random_alias_public_domain_id:
|
||||
public_domain = PublicDomain.get(self.default_random_alias_public_domain_id)
|
||||
# sanity check
|
||||
if not public_domain:
|
||||
LOG.error("Problem with %s public random alias domain", self)
|
||||
return FIRST_ALIAS_DOMAIN
|
||||
|
||||
return public_domain.domain
|
||||
|
||||
return FIRST_ALIAS_DOMAIN
|
||||
|
||||
def fido_enabled(self) -> bool:
|
||||
if self.fido_uuid is not None:
|
||||
return True
|
||||
|
@ -824,12 +877,17 @@ class Alias(db.Model, ModelMixin):
|
|||
note: str = None,
|
||||
):
|
||||
"""create a new random alias"""
|
||||
domain = None
|
||||
custom_domain = None
|
||||
|
||||
if user.default_random_alias_domain_id:
|
||||
domain = CustomDomain.get(user.default_random_alias_domain_id)
|
||||
custom_domain = CustomDomain.get(user.default_random_alias_domain_id)
|
||||
random_email = generate_email(
|
||||
scheme=scheme, in_hex=in_hex, alias_domain=domain.domain
|
||||
scheme=scheme, in_hex=in_hex, alias_domain=custom_domain.domain
|
||||
)
|
||||
elif user.default_random_alias_public_domain_id:
|
||||
public_domain = PublicDomain.get(user.default_random_alias_public_domain_id)
|
||||
random_email = generate_email(
|
||||
scheme=scheme, in_hex=in_hex, alias_domain=public_domain.domain
|
||||
)
|
||||
else:
|
||||
random_email = generate_email(scheme=scheme, in_hex=in_hex)
|
||||
|
@ -841,8 +899,8 @@ class Alias(db.Model, ModelMixin):
|
|||
note=note,
|
||||
)
|
||||
|
||||
if domain:
|
||||
alias.custom_domain_id = domain.id
|
||||
if custom_domain:
|
||||
alias.custom_domain_id = custom_domain.id
|
||||
|
||||
return alias
|
||||
|
||||
|
@ -1610,3 +1668,9 @@ class Notification(db.Model, ModelMixin):
|
|||
|
||||
# whether user has marked the notification as read
|
||||
read = db.Column(db.Boolean, nullable=False, default=False)
|
||||
|
||||
|
||||
class PublicDomain(db.Model, ModelMixin):
|
||||
"""SimpleLogin domains that all users can use"""
|
||||
|
||||
domain = db.Column(db.String(128), unique=True, nullable=False)
|
||||
|
|
15
init_app.py
15
init_app.py
|
@ -1,5 +1,6 @@
|
|||
"""Initial loading script"""
|
||||
from app.models import Mailbox, Contact
|
||||
from app.config import ALIAS_DOMAINS
|
||||
from app.models import Mailbox, Contact, PublicDomain
|
||||
from app.log import LOG
|
||||
from app.extensions import db
|
||||
from app.pgp_utils import load_public_key
|
||||
|
@ -32,8 +33,20 @@ def load_pgp_public_keys():
|
|||
LOG.d("Finish load_pgp_public_keys")
|
||||
|
||||
|
||||
def add_public_domains():
|
||||
for alias_domain in ALIAS_DOMAINS:
|
||||
if PublicDomain.get_by(domain=alias_domain):
|
||||
LOG.d("%s is already a public domain", alias_domain)
|
||||
else:
|
||||
LOG.info("Add %s to public domain", alias_domain)
|
||||
PublicDomain.create(domain=alias_domain)
|
||||
|
||||
db.session.commit()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = create_app()
|
||||
|
||||
with app.app_context():
|
||||
load_pgp_public_keys()
|
||||
add_public_domains()
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
"""empty message
|
||||
|
||||
Revision ID: 270d598c51e3
|
||||
Revises: 7128f87af701
|
||||
Create Date: 2020-07-04 23:32:25.297082
|
||||
|
||||
"""
|
||||
import sqlalchemy_utils
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '270d598c51e3'
|
||||
down_revision = '7128f87af701'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('public_domain',
|
||||
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
||||
sa.Column('created_at', sqlalchemy_utils.types.arrow.ArrowType(), nullable=False),
|
||||
sa.Column('updated_at', sqlalchemy_utils.types.arrow.ArrowType(), nullable=True),
|
||||
sa.Column('domain', sa.String(length=128), nullable=False),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('domain')
|
||||
)
|
||||
op.add_column('users', sa.Column('default_random_alias_public_domain_id', sa.Integer(), nullable=True))
|
||||
op.drop_constraint('users_default_random_alias_domain_id_fkey', 'users', type_='foreignkey')
|
||||
op.create_foreign_key(None, 'users', 'custom_domain', ['default_random_alias_domain_id'], ['id'], ondelete='SET NULL')
|
||||
op.create_foreign_key(None, 'users', 'public_domain', ['default_random_alias_public_domain_id'], ['id'], ondelete='SET NULL')
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_constraint(None, 'users', type_='foreignkey')
|
||||
op.drop_constraint(None, 'users', type_='foreignkey')
|
||||
op.create_foreign_key('users_default_random_alias_domain_id_fkey', 'users', 'custom_domain', ['default_random_alias_domain_id'], ['id'])
|
||||
op.drop_column('users', 'default_random_alias_public_domain_id')
|
||||
op.drop_table('public_domain')
|
||||
# ### end Alembic commands ###
|
|
@ -64,6 +64,7 @@ from app.models import (
|
|||
Referral,
|
||||
AliasMailbox,
|
||||
Notification,
|
||||
PublicDomain,
|
||||
)
|
||||
from app.monitor.base import monitor_bp
|
||||
from app.oauth.base import oauth_bp
|
||||
|
@ -286,6 +287,10 @@ def fake_data():
|
|||
)
|
||||
db.session.commit()
|
||||
|
||||
for d in ["d1.localhost", "d2.localhost"]:
|
||||
PublicDomain.create(domain=d)
|
||||
db.session.commit()
|
||||
|
||||
|
||||
@login_manager.user_loader
|
||||
def load_user(user_id):
|
||||
|
|
Loading…
Reference in New Issue