feat: implement email sending functionality for peer invites

This commit is contained in:
Eduardo Silva 2025-03-01 10:52:20 -03:00
parent b4321218a2
commit d8b51bf812
3 changed files with 94 additions and 14 deletions

View File

@ -18,7 +18,8 @@ from django.views.decorators.http import require_http_methods
from user_manager.models import UserAcl, AuthenticationToken
from vpn_invite.models import InviteSettings, PeerInvite
from wgwadmlibrary.tools import user_allowed_peers, user_has_access_to_peer, get_peer_invite_data, create_peer_invite
from wgwadmlibrary.tools import user_allowed_peers, user_has_access_to_peer, get_peer_invite_data, create_peer_invite, \
send_email
from wireguard.models import WebadminSettings, Peer, PeerStatus, WireGuardInstance
@ -334,9 +335,11 @@ def api_peer_invite(request):
data['invite_data'] = get_peer_invite_data(peer_invite, invite_settings)
if request.GET.get('action') == 'email':
data['status'] = 'success'
data['message'] = 'Email sent'
data['status'], data['message'] = send_email(request.GET.get('address'), data['invite_data']['email_subject'], data['invite_data']['email_body'])
if data['status'] == 'success':
return JsonResponse(data)
else:
return JsonResponse(data, status=400)
else:
if request.GET.get('action') == 'email':
data['status'] = 'error'

View File

@ -653,11 +653,18 @@
$("#invitePassword").html("Access Password: <strong>" + inviteData.password + "</strong> (Share this password via a separate secure channel)");
$("#inviteExpiration").text(new Date(inviteData.expiration).toLocaleString());
} else {
$("#inviteMessage").html("<div class='alert alert-danger'>" + response.message + "</div>");
$("#inviteMessage").html("<div class='alert alert-danger'>" + (response.message || "Unknown error") + "</div>");
}
},
error: function(xhr, status, error) {
$("#inviteMessage").html("<div class='alert alert-danger'>Error creating invite: " + error + "</div>");
var message = "Error creating invite.";
try {
var resp = xhr.responseJSON;
message = resp && resp.message ? resp.message : xhr.statusText;
} catch(err) {
message = xhr.statusText;
}
$("#inviteMessage").html("<div class='alert alert-danger'>" + message + "</div>");
}
});
});
@ -718,7 +725,7 @@
});
// Handler for sending invite via Email
$("#sendInviteEmailButton").on("click", function(e) {
$("#sendInviteEmailButton").on("click", function(e, textStatus, xhr) {
e.preventDefault();
var contact = $("#inviteContactInput").val().trim();
if(!isValidEmail(contact)) {
@ -732,15 +739,30 @@
data: { invite: inviteData.uuid, action: 'email', address: contact },
type: 'GET',
dataType: 'json',
success: function(response) {
success: function(response, textStatus, xhr) {
var message = response.message;
if (!message) {
message = xhr.statusText;
}
if(response.status === "success") {
$("#inviteMessage").html("<div class='alert alert-success'>Email sent successfully.</div>");
$("#inviteMessage").html("<div class='alert alert-success'>" + message + "</div>");
} else {
$("#inviteMessage").html("<div class='alert alert-danger'>" + response.message + "</div>");
$("#inviteMessage").html("<div class='alert alert-danger'>" + message + "</div>");
}
},
error: function(xhr, status, error) {
$("#inviteMessage").html("<div class='alert alert-danger'>Error sending email: " + error + "</div>");
var message = "Error sending email.";
try {
var resp = xhr.responseJSON;
if (resp && resp.message) {
message = resp.message;
} else {
message = xhr.statusText;
}
} catch(err) {
message = xhr.statusText;
}
$("#inviteMessage").html("<div class='alert alert-danger'>" + message + "</div>");
}
});
} else {
@ -764,13 +786,24 @@
$("#inviteText").text(inviteData.text_body);
$("#invitePassword").html("Access Password: <strong>" + inviteData.password + "</strong> (Share this password via a separate secure channel)");
$("#inviteExpiration").text(new Date(inviteData.expiration).toLocaleString());
$("#inviteMessage").html("<div class='alert alert-success'>Invite refreshed successfully.</div>");
$("#inviteMessage").html("<div class='alert alert-success'>" + (response.message || xhr.statusText) + "</div>");
} else {
$("#inviteMessage").html("<div class='alert alert-danger'>" + response.message + "</div>");
$("#inviteMessage").html("<div class='alert alert-danger'>" + (response.message || "Error refreshing invite.") + "</div>");
}
},
error: function(xhr, status, error) {
$("#inviteMessage").html("<div class='alert alert-danger'>Error refreshing invite: " + error + "</div>");
var message = "Error refreshing invite.";
try {
var resp = xhr.responseJSON;
if (resp && resp.message) {
message = resp.message;
} else {
message = xhr.statusText;
}
} catch(err) {
message = xhr.statusText;
}
$("#inviteMessage").html("<div class='alert alert-danger'>" + message + "</div>");
}
});
} else {

View File

@ -1,15 +1,20 @@
import ipaddress
import random
import re
import smtplib
import subprocess
from datetime import timedelta
from email.mime.text import MIMEText
from django.core.exceptions import ValidationError
from django.core.validators import validate_email
from django.db.models import Max
from django.utils import timezone
from user_manager.models import UserAcl
from vpn_invite.models import PeerInvite, InviteSettings
from wireguard.models import Peer, WireGuardInstance
from wireguard_tools.models import EmailSettings
def user_has_access_to_instance(user_acl: UserAcl, instance: WireGuardInstance):
@ -169,3 +174,42 @@ def create_peer_invite(peer: Peer, invite_settings: InviteSettings):
peer=peer, invite_password=password[:32], invite_expiration=timezone.now() + timedelta(minutes=invite_settings.invite_expiration)
)
return peer_invite
def send_email(destination, subject, body):
success = 'error'
message = ''
try:
validate_email(destination)
except ValidationError:
return 'error', 'Invalid email address.'
email_settings = EmailSettings.objects.filter(name='email_settings', enabled=True).first()
if not email_settings:
message = 'Email settings not configured.'
return success, message
try:
msg = MIMEText(body, 'plain')
msg['Subject'] = subject
msg['From'] = email_settings.smtp_from_address
msg['To'] = destination
if email_settings.smtp_encryption.lower() == 'ssl':
server = smtplib.SMTP_SSL(email_settings.smtp_host, email_settings.smtp_port)
else:
server = smtplib.SMTP(email_settings.smtp_host, email_settings.smtp_port)
server.starttls()
if email_settings.smtp_username and email_settings.smtp_password:
server.login(email_settings.smtp_username, email_settings.smtp_password)
server.sendmail(email_settings.smtp_from_address, destination, msg.as_string())
server.quit()
success = 'success'
message = 'Email sent successfully.'
except Exception as e:
success = 'error'
message = f'Error sending email: {str(e)}'
return success, message