1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-08-29 20:14:19 +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):
if not ENABLE_SMIME:
return None
CERTS_DIR = getattr(settings, 'SMIME_CERTS_DIR', '/opt/seafile/seahub-data/certs') def __init__(self, *args, **kwargs):
cert_file = os.path.join(CERTS_DIR, 'cert.pem') super(SmimeEmailMessage, self).__init__(*args, **kwargs)
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):
logger.warning('smime key file %s does not exists.' % key_file)
return None
# Load the private key def _signed(self, msg):
with open(key_file, "rb") as f: if not ENABLE_SMIME:
private_key = serialization.load_pem_private_key(f.read(), password=None) return msg
# Load the certificate CERTS_DIR = getattr(settings, 'SMIME_CERTS_DIR', '/opt/seafile/seahub-data/certs')
with open(cert_file, "rb") as f: cert_file = os.path.join(CERTS_DIR, 'cert.pem')
certificate = x509.load_pem_x509_certificate(f.read()) key_file = os.path.join(CERTS_DIR, 'private_key.pem')
msg.mixed_subtype = "signed"
msg_payload = msg.message().as_string().encode() if not os.path.exists(cert_file):
logger.warning(f'smime cert file {cert_file} does not exist.')
return msg
if not os.path.exists(key_file):
logger.warning(f'smime key file {key_file} does not exist.')
return msg
try:
# Load the private key
with open(key_file, "rb") as f:
private_key = serialization.load_pem_private_key(f.read(), password=None)
# 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