1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-08-29 12:04:02 +00:00
This commit is contained in:
r350178982 2025-04-21 17:58:43 +08:00
parent 1ea9f19d78
commit 0fa64a1192
2 changed files with 73 additions and 49 deletions

View File

@ -1002,7 +1002,7 @@ def send_html_email(subject, con_template, con_context, from_email, to_email,
""" """
# get logo path # get logo path
from seahub.utils.mail import add_smime_sign from seahub.utils.mail import SmimeEmailMessage
logo_path = LOGO_PATH logo_path = LOGO_PATH
custom_logo_file = os.path.join(MEDIA_ROOT, CUSTOM_LOGO_PATH) custom_logo_file = os.path.join(MEDIA_ROOT, CUSTOM_LOGO_PATH)
if os.path.exists(custom_logo_file): if os.path.exists(custom_logo_file):
@ -1022,13 +1022,9 @@ def send_html_email(subject, con_template, con_context, from_email, to_email,
if reply_to is not None: if reply_to is not None:
headers['Reply-to'] = reply_to headers['Reply-to'] = reply_to
msg = EmailMessage(subject, t.render(con_context), from_email, msg = SmimeEmailMessage(subject, t.render(con_context), from_email,
to_email, headers=headers) to_email, headers=headers)
msg.content_subtype = "html" msg.content_subtype = "html"
sig_part = add_smime_sign(msg)
if sig_part:
msg.attach(sig_part)
msg.send() msg.send()
def gen_dir_share_link(token): def gen_dir_share_link(token):

View File

@ -2,10 +2,14 @@
import os import os
import logging import logging
from email.mime.application import MIMEApplication from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from cryptography.hazmat.primitives import serialization, hashes from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.serialization import pkcs7 from cryptography.hazmat.primitives.serialization import pkcs7
from cryptography import x509 from cryptography import x509
import base64 import base64
from django.core.mail.message import SafeMIMEMultipart
from django.template import loader from django.template import loader
from django.core.mail import EmailMessage from django.core.mail import EmailMessage
@ -17,53 +21,80 @@ from seahub import settings
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class SmimeEmailMessage(EmailMessage):
def add_smime_sign(msg): def __init__(self, *args, **kwargs):
if not ENABLE_SMIME: super(SmimeEmailMessage, self).__init__(*args, **kwargs)
return None
CERTS_DIR = getattr(settings, 'SMIME_CERTS_DIR', '/opt/seafile/seahub-data/certs')
cert_file = os.path.join(CERTS_DIR, 'cert.pem')
key_file = os.path.join(CERTS_DIR, 'private_key.pem')
if not os.path.exists(cert_file):
logger.warning('smime cert file %s does not exists.' % cert_file)
return None
if not os.path.exists(key_file): def _signed(self, msg):
logger.warning('smime key file %s does not exists.' % key_file) if not ENABLE_SMIME:
return None return msg
# Load the private key CERTS_DIR = getattr(settings, 'SMIME_CERTS_DIR', '/opt/seafile/seahub-data/certs')
with open(key_file, "rb") as f: cert_file = os.path.join(CERTS_DIR, 'cert.pem')
private_key = serialization.load_pem_private_key(f.read(), password=None) key_file = os.path.join(CERTS_DIR, 'private_key.pem')
# Load the certificate if not os.path.exists(cert_file):
with open(cert_file, "rb") as f: logger.warning(f'smime cert file {cert_file} does not exist.')
certificate = x509.load_pem_x509_certificate(f.read()) return msg
if not os.path.exists(key_file):
logger.warning(f'smime key file {key_file} does not exist.')
return msg
msg.mixed_subtype = "signed" try:
# Load the private key
with open(key_file, "rb") as f:
private_key = serialization.load_pem_private_key(f.read(), password=None)
msg_payload = msg.message().as_string().encode() # Load the certificate
with open(cert_file, "rb") as f:
certificate = x509.load_pem_x509_certificate(f.read())
except Exception as e:
logger.error(e)
return msg
builder = pkcs7.PKCS7SignatureBuilder() \ original_msg = msg
.set_data(msg_payload) \ msg_payload = msg.as_string().encode()
.add_signer(certificate, private_key, hashes.SHA256())
pkcs7_signature = builder.sign(serialization.Encoding.SMIME, [pkcs7.PKCS7Options.DetachedSignature])
# Base64 encode the signature for S/MIME builder = pkcs7.PKCS7SignatureBuilder() \
signature_b64 = base64.b64encode(pkcs7_signature).decode() .set_data(msg_payload) \
.add_signer(certificate, private_key, hashes.SHA256())
pkcs7_signature = builder.sign(serialization.Encoding.SMIME, [pkcs7.PKCS7Options.DetachedSignature])
# Create the S/MIME signature part signature = base64.b64encode(pkcs7_signature).decode()
sig_part = MIMEApplication(
signature_b64,
"pkcs7-signature",
)
sig_part.set_param("name", "smime.p7s")
sig_part.add_header("Content-Disposition", "attachment", filename="smime.p7s")
return sig_part signed_msg = SafeMIMEMultipart(
_subtype='signed',
protocol='application/pkcs7-signature',
micalg='sha-256'
)
for header in ['Subject', 'From', 'To', 'Date']:
if header in original_msg.keys():
signed_msg[header] = original_msg[header]
signed_msg.attach(original_msg)
sig_part = MIMEApplication(
signature,
'pkcs7-signature',
name='smime.p7s',
)
sig_part.add_header(
'Content-Disposition',
'attachment; filename="smime.p7s"'
)
signed_msg.attach(sig_part)
return signed_msg
def message(self):
original_msg = super().message()
return self._signed(original_msg)
def send_html_email_with_dj_template(recipients, subject, dj_template, context={}): def send_html_email_with_dj_template(recipients, subject, dj_template, context={}):
""" """
@ -92,15 +123,12 @@ def send_html_email_with_dj_template(recipients, subject, dj_template, context={
t = loader.get_template(dj_template) t = loader.get_template(dj_template)
html_message = t.render(context) html_message = t.render(context)
mail = EmailMessage(subject=subject, body=html_message, to=[recipients]) mail = SmimeEmailMessage(subject=subject, body=html_message, to=[recipients])
mail.content_subtype = "html" mail.content_subtype = "html"
try: try:
sig_part = add_smime_sign(mail)
if sig_part:
mail.attach(sig_part)
mail.send() mail.send()
return True return True
except Exception as e: except Exception as e:
logger.error(e) logger.exception(e)
return False return False