| 
									
										
										
										
											2017-09-17 14:37:10 +02:00
										 |  |  | from mailu import app, db, dkim, login_manager | 
					
						
							| 
									
										
										
										
											2016-02-20 13:57:26 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-19 20:37:48 +01:00
										 |  |  | from sqlalchemy.ext import declarative | 
					
						
							| 
									
										
										
										
											2017-10-29 14:48:34 +01:00
										 |  |  | from passlib import context, hash | 
					
						
							| 
									
										
										
										
											2017-11-10 15:25:30 +01:00
										 |  |  | from datetime import datetime, date | 
					
						
							| 
									
										
										
										
											2017-11-10 11:55:58 +01:00
										 |  |  | from email.mime import text | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-19 20:37:48 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-20 15:36:56 +01:00
										 |  |  | import re | 
					
						
							| 
									
										
										
										
											2016-06-25 15:50:05 +02:00
										 |  |  | import time | 
					
						
							|  |  |  | import os | 
					
						
							|  |  |  | import glob | 
					
						
							| 
									
										
										
										
											2017-11-10 11:55:58 +01:00
										 |  |  | import smtplib | 
					
						
							| 
									
										
										
										
											2018-04-12 21:35:38 +02:00
										 |  |  | import idna | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Idna(db.TypeDecorator): | 
					
						
							|  |  |  |     """ Stores a Unicode string in it's IDNA representation (ASCII only)
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     impl = db.String | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def process_bind_param(self, value, dialect): | 
					
						
							|  |  |  |         return idna.encode(value) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def process_result_value(self, value, dialect): | 
					
						
							|  |  |  |         return idna.decode(value) | 
					
						
							| 
									
										
										
										
											2016-03-20 15:36:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-19 20:37:48 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-24 19:17:40 +02:00
										 |  |  | # Many-to-many association table for domain managers | 
					
						
							|  |  |  | managers = db.Table('manager', | 
					
						
							| 
									
										
										
										
											2018-04-12 20:30:19 +02:00
										 |  |  |     db.Column('domain_name', Idna, db.ForeignKey('domain.name')), | 
					
						
							| 
									
										
										
										
											2016-05-01 20:04:40 +02:00
										 |  |  |     db.Column('user_email', db.String(255), db.ForeignKey('user.email')) | 
					
						
							| 
									
										
										
										
											2016-03-19 20:37:48 +01:00
										 |  |  | ) | 
					
						
							| 
									
										
										
										
											2016-02-20 13:57:26 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-20 20:11:59 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-11 13:33:04 +02:00
										 |  |  | class CommaSeparatedList(db.TypeDecorator): | 
					
						
							|  |  |  |     """ Stores a list as a comma-separated string, compatible with Postfix.
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     impl = db.String | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def process_bind_param(self, value, dialect): | 
					
						
							|  |  |  |         if type(value) is not list: | 
					
						
							|  |  |  |             raise TypeError("Shoud be a list") | 
					
						
							|  |  |  |         for item in value: | 
					
						
							|  |  |  |             if "," in item: | 
					
						
							|  |  |  |                 raise ValueError("No item should contain a comma") | 
					
						
							|  |  |  |         return ",".join(value) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def process_result_value(self, value, dialect): | 
					
						
							| 
									
										
										
										
											2016-08-11 15:41:12 +02:00
										 |  |  |         return filter(bool, value.split(",")) | 
					
						
							| 
									
										
										
										
											2016-08-11 13:33:04 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-20 11:31:14 +01:00
										 |  |  | class Base(db.Model): | 
					
						
							|  |  |  |     """ Base class for all models
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     __abstract__ = True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     created_at = db.Column(db.Date, nullable=False, default=datetime.now) | 
					
						
							|  |  |  |     updated_at = db.Column(db.Date, nullable=True, onupdate=datetime.now) | 
					
						
							| 
									
										
										
										
											2016-03-20 11:38:37 +01:00
										 |  |  |     comment = db.Column(db.String(255), nullable=True) | 
					
						
							| 
									
										
										
										
											2016-03-20 11:31:14 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Domain(Base): | 
					
						
							| 
									
										
										
										
											2016-03-19 20:37:48 +01:00
										 |  |  |     """ A DNS domain that has mail addresses associated to it.
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2016-10-16 17:18:00 +02:00
										 |  |  |     __tablename__ = "domain" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-12 19:07:48 +02:00
										 |  |  |     name = db.Column(Idna, primary_key=True, nullable=False) | 
					
						
							| 
									
										
										
										
											2016-04-24 19:17:40 +02:00
										 |  |  |     managers = db.relationship('User', secondary=managers, | 
					
						
							|  |  |  |         backref=db.backref('manager_of'), lazy='dynamic') | 
					
						
							| 
									
										
										
										
											2016-03-22 21:22:49 +01:00
										 |  |  |     max_users = db.Column(db.Integer, nullable=False, default=0) | 
					
						
							|  |  |  |     max_aliases = db.Column(db.Integer, nullable=False, default=0) | 
					
						
							| 
									
										
										
										
											2017-02-02 22:29:33 +01:00
										 |  |  |     max_quota_bytes = db.Column(db.Integer(), nullable=False, default=0) | 
					
						
							| 
									
										
										
										
											2017-12-03 12:01:25 +01:00
										 |  |  |     signup_enabled = db.Column(db.Boolean(), nullable=False, default=False) | 
					
						
							| 
									
										
										
										
											2016-02-20 13:57:26 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-25 15:50:05 +02:00
										 |  |  |     @property | 
					
						
							|  |  |  |     def dkim_key(self): | 
					
						
							|  |  |  |         file_path = app.config["DKIM_PATH"].format( | 
					
						
							|  |  |  |             domain=self.name, selector=app.config["DKIM_SELECTOR"]) | 
					
						
							|  |  |  |         if os.path.exists(file_path): | 
					
						
							|  |  |  |             with open(file_path, "rb") as handle: | 
					
						
							|  |  |  |                 return handle.read() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @dkim_key.setter | 
					
						
							|  |  |  |     def dkim_key(self, value): | 
					
						
							|  |  |  |         file_path = app.config["DKIM_PATH"].format( | 
					
						
							|  |  |  |             domain=self.name, selector=app.config["DKIM_SELECTOR"]) | 
					
						
							|  |  |  |         with open(file_path, "wb") as handle: | 
					
						
							|  |  |  |             handle.write(value) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def dkim_publickey(self): | 
					
						
							| 
									
										
										
										
											2016-06-25 16:06:52 +02:00
										 |  |  |         dkim_key = self.dkim_key | 
					
						
							|  |  |  |         if dkim_key: | 
					
						
							|  |  |  |             return dkim.strip_key(self.dkim_key).decode("utf8") | 
					
						
							| 
									
										
										
										
											2016-06-25 15:50:05 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def generate_dkim_key(self): | 
					
						
							|  |  |  |         self.dkim_key = dkim.gen_key() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-01 20:04:40 +02:00
										 |  |  |     def has_email(self, localpart): | 
					
						
							|  |  |  |         for email in self.users + self.aliases: | 
					
						
							|  |  |  |             if email.localpart == localpart: | 
					
						
							| 
									
										
										
										
											2016-03-22 19:47:15 +01:00
										 |  |  |                 return True | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-20 13:57:26 +01:00
										 |  |  |     def __str__(self): | 
					
						
							|  |  |  |         return self.name | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 12:10:58 +02:00
										 |  |  |     def __eq__(self, other): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             return self.name == other.name | 
					
						
							|  |  |  |         except AttributeError: | 
					
						
							|  |  |  |             return False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-20 13:57:26 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-03 18:30:00 +02:00
										 |  |  | class Alternative(Base): | 
					
						
							|  |  |  |     """ Alternative name for a served domain.
 | 
					
						
							|  |  |  |     The name "domain alias" was avoided to prevent some confusion. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     __tablename__ = "alternative" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-12 20:30:19 +02:00
										 |  |  |     name = db.Column(Idna, primary_key=True, nullable=False) | 
					
						
							|  |  |  |     domain_name = db.Column(Idna, db.ForeignKey(Domain.name)) | 
					
						
							| 
									
										
										
										
											2017-09-03 18:30:00 +02:00
										 |  |  |     domain = db.relationship(Domain, | 
					
						
							|  |  |  |         backref=db.backref('alternatives', cascade='all, delete-orphan')) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __str__(self): | 
					
						
							|  |  |  |         return self.name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-10 20:30:03 +02:00
										 |  |  | class Relay(Base): | 
					
						
							|  |  |  |     """ Relayed mail domain.
 | 
					
						
							|  |  |  |     The domain is either relayed publicly or through a specified SMTP host. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     __tablename__ = "relay" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-12 22:21:28 +02:00
										 |  |  |     name = db.Column(db.String(80), primary_key=True, nullable=False) | 
					
						
							|  |  |  |     smtp = db.Column(db.String(80), nullable=True) | 
					
						
							| 
									
										
										
										
											2017-09-10 20:30:03 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __str__(self): | 
					
						
							|  |  |  |         return self.name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-16 17:18:00 +02:00
										 |  |  | class Email(object): | 
					
						
							| 
									
										
										
										
											2016-05-01 20:04:40 +02:00
										 |  |  |     """ Abstraction for an email address (localpart and domain).
 | 
					
						
							| 
									
										
										
										
											2016-03-19 20:37:48 +01:00
										 |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-20 21:14:04 +02:00
										 |  |  |     localpart = db.Column(db.String(80), nullable=False) | 
					
						
							| 
									
										
										
										
											2016-03-19 20:37:48 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @declarative.declared_attr | 
					
						
							|  |  |  |     def domain_name(cls): | 
					
						
							| 
									
										
										
										
											2018-04-12 20:30:19 +02:00
										 |  |  |         return db.Column(Idna, db.ForeignKey(Domain.name), | 
					
						
							| 
									
										
										
										
											2016-04-20 21:14:04 +02:00
										 |  |  |             nullable=False) | 
					
						
							| 
									
										
										
										
											2016-02-20 13:57:26 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-20 21:14:04 +02:00
										 |  |  |     # This field is redundant with both localpart and domain name. | 
					
						
							|  |  |  |     # It is however very useful for quick lookups without joining tables, | 
					
						
							|  |  |  |     # especially when the mail server il reading the database. | 
					
						
							|  |  |  |     @declarative.declared_attr | 
					
						
							| 
									
										
										
										
											2016-05-01 20:04:40 +02:00
										 |  |  |     def email(cls): | 
					
						
							| 
									
										
										
										
											2016-04-20 21:14:04 +02:00
										 |  |  |         updater = lambda context: "{0}@{1}".format( | 
					
						
							|  |  |  |             context.current_parameters["localpart"], | 
					
						
							| 
									
										
										
										
											2018-04-13 08:13:26 +02:00
										 |  |  |             idna.encode(context.current_parameters["domain_name"]).decode('ascii'), | 
					
						
							| 
									
										
										
										
											2016-04-20 21:14:04 +02:00
										 |  |  |         ) | 
					
						
							| 
									
										
										
										
											2017-10-29 13:44:37 +01:00
										 |  |  |         return db.Column(db.String(255, collation="NOCASE"), | 
					
						
							| 
									
										
										
										
											2016-04-20 21:14:04 +02:00
										 |  |  |             primary_key=True, nullable=False, | 
					
						
							|  |  |  |             default=updater) | 
					
						
							| 
									
										
										
										
											2016-02-20 13:57:26 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-10 11:55:58 +01:00
										 |  |  |     def sendmail(self, subject, body): | 
					
						
							|  |  |  |         """ Send an email to the address.
 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         from_address = '{}@{}'.format( | 
					
						
							|  |  |  |             app.config['POSTMASTER'], app.config['DOMAIN']) | 
					
						
							|  |  |  |         with smtplib.SMTP('smtp', port=10025) as smtp: | 
					
						
							|  |  |  |             msg = text.MIMEText(body) | 
					
						
							|  |  |  |             msg['Subject'] = subject | 
					
						
							|  |  |  |             msg['From'] = from_address | 
					
						
							|  |  |  |             msg['To'] = self.email | 
					
						
							|  |  |  |             smtp.sendmail(from_address, [self.email], msg.as_string()) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-20 21:14:04 +02:00
										 |  |  |     def __str__(self): | 
					
						
							| 
									
										
										
										
											2016-05-01 20:04:40 +02:00
										 |  |  |         return self.email | 
					
						
							| 
									
										
										
										
											2016-02-20 13:57:26 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-19 20:37:48 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-16 17:18:00 +02:00
										 |  |  | class User(Base, Email): | 
					
						
							| 
									
										
										
										
											2016-05-01 20:04:40 +02:00
										 |  |  |     """ A user is an email address that has a password to access a mailbox.
 | 
					
						
							| 
									
										
										
										
											2016-03-19 20:37:48 +01:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2016-10-16 17:18:00 +02:00
										 |  |  |     __tablename__ = "user" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-11 14:13:56 +02:00
										 |  |  |     domain = db.relationship(Domain, | 
					
						
							|  |  |  |         backref=db.backref('users', cascade='all, delete-orphan')) | 
					
						
							| 
									
										
										
										
											2016-03-19 20:37:48 +01:00
										 |  |  |     password = db.Column(db.String(255), nullable=False) | 
					
						
							|  |  |  |     quota_bytes = db.Column(db.Integer(), nullable=False, default=10**9) | 
					
						
							|  |  |  |     global_admin = db.Column(db.Boolean(), nullable=False, default=False) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-22 21:05:08 +01:00
										 |  |  |     # Features | 
					
						
							|  |  |  |     enable_imap = db.Column(db.Boolean(), nullable=False, default=True) | 
					
						
							|  |  |  |     enable_pop = db.Column(db.Boolean(), nullable=False, default=True) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-20 11:00:01 +01:00
										 |  |  |     # Filters | 
					
						
							| 
									
										
										
										
											2016-05-04 16:12:56 +02:00
										 |  |  |     forward_enabled = db.Column(db.Boolean(), nullable=False, default=False) | 
					
						
							| 
									
										
										
										
											2016-08-13 20:01:40 +02:00
										 |  |  |     forward_destination = db.Column(db.String(255), nullable=True, default=None) | 
					
						
							| 
									
										
										
										
											2017-09-03 15:43:30 +02:00
										 |  |  |     forward_keep = db.Column(db.Boolean(), nullable=False, default=True) | 
					
						
							| 
									
										
										
										
											2016-05-04 16:12:56 +02:00
										 |  |  |     reply_enabled = db.Column(db.Boolean(), nullable=False, default=False) | 
					
						
							| 
									
										
										
										
											2016-03-20 11:14:27 +01:00
										 |  |  |     reply_subject = db.Column(db.String(255), nullable=True, default=None) | 
					
						
							| 
									
										
										
										
											2016-03-20 11:00:01 +01:00
										 |  |  |     reply_body = db.Column(db.Text(), nullable=True, default=None) | 
					
						
							| 
									
										
										
										
											2017-11-10 15:25:30 +01:00
										 |  |  |     reply_enddate = db.Column(db.Date, nullable=False, | 
					
						
							|  |  |  |         default=date(2999, 12, 31)) | 
					
						
							| 
									
										
										
										
											2016-03-20 11:00:01 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-20 11:09:06 +01:00
										 |  |  |     # Settings | 
					
						
							|  |  |  |     displayed_name = db.Column(db.String(160), nullable=False, default="") | 
					
						
							|  |  |  |     spam_enabled = db.Column(db.Boolean(), nullable=False, default=True) | 
					
						
							| 
									
										
										
										
											2016-11-08 20:33:01 +01:00
										 |  |  |     spam_threshold = db.Column(db.Integer(), nullable=False, default=80.0) | 
					
						
							| 
									
										
										
										
											2016-03-20 11:09:06 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Flask-login attributes | 
					
						
							| 
									
										
										
										
											2016-03-19 20:37:48 +01:00
										 |  |  |     is_authenticated = True | 
					
						
							|  |  |  |     is_active = True | 
					
						
							|  |  |  |     is_anonymous = False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-20 21:14:04 +02:00
										 |  |  |     def get_id(self): | 
					
						
							| 
									
										
										
										
											2016-05-01 20:04:40 +02:00
										 |  |  |         return self.email | 
					
						
							| 
									
										
										
										
											2016-04-20 21:14:04 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-29 13:44:37 +01:00
										 |  |  |     scheme_dict = {'SHA512-CRYPT': "sha512_crypt", | 
					
						
							|  |  |  |                    'SHA256-CRYPT': "sha256_crypt", | 
					
						
							|  |  |  |                    'MD5-CRYPT': "md5_crypt", | 
					
						
							| 
									
										
										
										
											2017-08-24 07:23:54 -07:00
										 |  |  |                    'CRYPT': "des_crypt"} | 
					
						
							| 
									
										
										
										
											2016-03-20 15:36:56 +01:00
										 |  |  |     pw_context = context.CryptContext( | 
					
						
							| 
									
										
										
										
											2017-08-24 07:23:54 -07:00
										 |  |  |         schemes = scheme_dict.values(), | 
					
						
							| 
									
										
										
										
											2017-09-02 17:36:22 +02:00
										 |  |  |         default=scheme_dict[app.config['PASSWORD_SCHEME']], | 
					
						
							| 
									
										
										
										
											2016-03-20 15:36:56 +01:00
										 |  |  |     ) | 
					
						
							| 
									
										
										
										
											2016-03-19 20:37:48 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def check_password(self, password): | 
					
						
							| 
									
										
										
										
											2016-03-20 15:36:56 +01:00
										 |  |  |         reference = re.match('({[^}]+})?(.*)', self.password).group(2) | 
					
						
							|  |  |  |         return User.pw_context.verify(password, reference) | 
					
						
							| 
									
										
										
										
											2016-03-19 20:37:48 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-02 17:36:22 +02:00
										 |  |  |     def set_password(self, password, hash_scheme=app.config['PASSWORD_SCHEME'], raw=False): | 
					
						
							| 
									
										
										
										
											2017-08-24 07:23:54 -07:00
										 |  |  |         """Set password for user with specified encryption scheme
 | 
					
						
							|  |  |  |            @password: plain text password to encrypt (if raw == True the hash itself) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         # for the list of hash schemes see https://wiki2.dovecot.org/Authentication/PasswordSchemes | 
					
						
							|  |  |  |         if raw: | 
					
						
							|  |  |  |             self.password = '{'+hash_scheme+'}' + password | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             self.password = '{'+hash_scheme+'}' + User.pw_context.encrypt(password, self.scheme_dict[hash_scheme]) | 
					
						
							| 
									
										
										
										
											2016-03-19 20:37:48 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def get_managed_domains(self): | 
					
						
							|  |  |  |         if self.global_admin: | 
					
						
							|  |  |  |             return Domain.query.all() | 
					
						
							|  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2016-04-24 19:42:02 +02:00
										 |  |  |             return self.manager_of | 
					
						
							| 
									
										
										
										
											2016-03-19 20:37:48 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-19 15:34:14 +02:00
										 |  |  |     def get_managed_emails(self, include_aliases=True): | 
					
						
							| 
									
										
										
										
											2016-05-01 20:04:40 +02:00
										 |  |  |         emails = [] | 
					
						
							| 
									
										
										
										
											2016-03-22 20:34:21 +01:00
										 |  |  |         for domain in self.get_managed_domains(): | 
					
						
							| 
									
										
										
										
											2016-05-01 20:04:40 +02:00
										 |  |  |             emails.extend(domain.users) | 
					
						
							| 
									
										
										
										
											2016-06-19 15:34:14 +02:00
										 |  |  |             if include_aliases: | 
					
						
							|  |  |  |                 emails.extend(domain.aliases) | 
					
						
							| 
									
										
										
										
											2016-05-01 20:04:40 +02:00
										 |  |  |         return emails | 
					
						
							| 
									
										
										
										
											2016-03-22 20:34:21 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-10 11:55:58 +01:00
										 |  |  |     def send_welcome(self): | 
					
						
							|  |  |  |         if app.config["WELCOME"].lower() == "true": | 
					
						
							|  |  |  |             self.sendmail(app.config["WELCOME_SUBJECT"], | 
					
						
							|  |  |  |                 app.config["WELCOME_BODY"]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-19 20:37:48 +01:00
										 |  |  |     @classmethod | 
					
						
							|  |  |  |     def login(cls, email, password): | 
					
						
							| 
									
										
										
										
											2016-05-01 20:09:47 +02:00
										 |  |  |         user = cls.query.get(email) | 
					
						
							| 
									
										
										
										
											2016-03-19 20:37:48 +01:00
										 |  |  |         return user if (user and user.check_password(password)) else None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-17 14:37:10 +02:00
										 |  |  | login_manager.user_loader(User.query.get) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-19 20:37:48 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-16 17:18:00 +02:00
										 |  |  | class Alias(Base, Email): | 
					
						
							| 
									
										
										
										
											2016-05-01 20:04:40 +02:00
										 |  |  |     """ An alias is an email address that redirects to some destination.
 | 
					
						
							| 
									
										
										
										
											2016-03-19 20:37:48 +01:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2016-10-16 17:18:00 +02:00
										 |  |  |     __tablename__ = "alias" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-11 14:13:56 +02:00
										 |  |  |     domain = db.relationship(Domain, | 
					
						
							|  |  |  |         backref=db.backref('aliases', cascade='all, delete-orphan')) | 
					
						
							| 
									
										
										
										
											2016-08-20 12:23:55 +02:00
										 |  |  |     wildcard = db.Column(db.Boolean(), nullable=False, default=False) | 
					
						
							| 
									
										
										
										
											2016-08-11 16:32:50 +02:00
										 |  |  |     destination = db.Column(CommaSeparatedList, nullable=False, default=[]) | 
					
						
							| 
									
										
										
										
											2016-04-28 20:07:38 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-29 14:48:34 +01:00
										 |  |  | class Token(Base): | 
					
						
							|  |  |  |     """ A token is an application password for a given user.
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     __tablename__ = "token" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     id = db.Column(db.Integer(), primary_key=True) | 
					
						
							|  |  |  |     user_email = db.Column(db.String(255), db.ForeignKey(User.email), | 
					
						
							|  |  |  |         nullable=False) | 
					
						
							|  |  |  |     user = db.relationship(User, | 
					
						
							|  |  |  |         backref=db.backref('tokens', cascade='all, delete-orphan')) | 
					
						
							|  |  |  |     password = db.Column(db.String(255), nullable=False) | 
					
						
							|  |  |  |     ip = db.Column(db.String(255)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def check_password(self, password): | 
					
						
							|  |  |  |         return hash.sha256_crypt.verify(password, self.password) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def set_password(self, password): | 
					
						
							| 
									
										
										
										
											2017-10-29 15:39:14 +01:00
										 |  |  |         self.password = hash.sha256_crypt.using(rounds=1000).hash(password) | 
					
						
							| 
									
										
										
										
											2017-10-29 14:48:34 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __str__(self): | 
					
						
							|  |  |  |         return self.comment | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-28 20:07:38 +02:00
										 |  |  | class Fetch(Base): | 
					
						
							|  |  |  |     """ A fetched account is a repote POP/IMAP account fetched into a local
 | 
					
						
							|  |  |  |     account. | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2016-10-16 17:18:00 +02:00
										 |  |  |     __tablename__ = "fetch" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-28 20:07:38 +02:00
										 |  |  |     id = db.Column(db.Integer(), primary_key=True) | 
					
						
							| 
									
										
										
										
											2016-05-01 20:04:40 +02:00
										 |  |  |     user_email = db.Column(db.String(255), db.ForeignKey(User.email), | 
					
						
							| 
									
										
										
										
											2016-04-28 20:07:38 +02:00
										 |  |  |         nullable=False) | 
					
						
							| 
									
										
										
										
											2016-08-11 14:13:56 +02:00
										 |  |  |     user = db.relationship(User, | 
					
						
							|  |  |  |         backref=db.backref('fetches', cascade='all, delete-orphan')) | 
					
						
							| 
									
										
										
										
											2016-04-28 20:07:38 +02:00
										 |  |  |     protocol = db.Column(db.Enum('imap', 'pop3'), nullable=False) | 
					
						
							|  |  |  |     host = db.Column(db.String(255), nullable=False) | 
					
						
							|  |  |  |     port = db.Column(db.Integer(), nullable=False) | 
					
						
							|  |  |  |     tls = db.Column(db.Boolean(), nullable=False) | 
					
						
							|  |  |  |     username = db.Column(db.String(255), nullable=False) | 
					
						
							|  |  |  |     password = db.Column(db.String(255), nullable=False) | 
					
						
							| 
									
										
										
										
											2017-02-02 22:45:43 +01:00
										 |  |  |     keep = db.Column(db.Boolean(), nullable=False) | 
					
						
							| 
									
										
										
										
											2016-09-10 13:05:55 +02:00
										 |  |  |     last_check = db.Column(db.DateTime, nullable=True) | 
					
						
							|  |  |  |     error = db.Column(db.String(1023), nullable=True) |