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 user_manager.models import UserAcl, AuthenticationToken
from vpn_invite.models import InviteSettings, PeerInvite 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 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) data['invite_data'] = get_peer_invite_data(peer_invite, invite_settings)
if request.GET.get('action') == 'email': if request.GET.get('action') == 'email':
data['status'] = 'success' data['status'], data['message'] = send_email(request.GET.get('address'), data['invite_data']['email_subject'], data['invite_data']['email_body'])
data['message'] = 'Email sent' if data['status'] == 'success':
return JsonResponse(data) return JsonResponse(data)
else:
return JsonResponse(data, status=400)
else: else:
if request.GET.get('action') == 'email': if request.GET.get('action') == 'email':
data['status'] = 'error' 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)"); $("#invitePassword").html("Access Password: <strong>" + inviteData.password + "</strong> (Share this password via a separate secure channel)");
$("#inviteExpiration").text(new Date(inviteData.expiration).toLocaleString()); $("#inviteExpiration").text(new Date(inviteData.expiration).toLocaleString());
} else { } 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) { 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 // Handler for sending invite via Email
$("#sendInviteEmailButton").on("click", function(e) { $("#sendInviteEmailButton").on("click", function(e, textStatus, xhr) {
e.preventDefault(); e.preventDefault();
var contact = $("#inviteContactInput").val().trim(); var contact = $("#inviteContactInput").val().trim();
if(!isValidEmail(contact)) { if(!isValidEmail(contact)) {
@ -732,15 +739,30 @@
data: { invite: inviteData.uuid, action: 'email', address: contact }, data: { invite: inviteData.uuid, action: 'email', address: contact },
type: 'GET', type: 'GET',
dataType: 'json', dataType: 'json',
success: function(response) { success: function(response, textStatus, xhr) {
var message = response.message;
if (!message) {
message = xhr.statusText;
}
if(response.status === "success") { 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 { } 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) { 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 { } else {
@ -764,13 +786,24 @@
$("#inviteText").text(inviteData.text_body); $("#inviteText").text(inviteData.text_body);
$("#invitePassword").html("Access Password: <strong>" + inviteData.password + "</strong> (Share this password via a separate secure channel)"); $("#invitePassword").html("Access Password: <strong>" + inviteData.password + "</strong> (Share this password via a separate secure channel)");
$("#inviteExpiration").text(new Date(inviteData.expiration).toLocaleString()); $("#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 { } 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) { 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 { } else {

View File

@ -1,15 +1,20 @@
import ipaddress import ipaddress
import random import random
import re import re
import smtplib
import subprocess import subprocess
from datetime import timedelta 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.db.models import Max
from django.utils import timezone from django.utils import timezone
from user_manager.models import UserAcl from user_manager.models import UserAcl
from vpn_invite.models import PeerInvite, InviteSettings from vpn_invite.models import PeerInvite, InviteSettings
from wireguard.models import Peer, WireGuardInstance from wireguard.models import Peer, WireGuardInstance
from wireguard_tools.models import EmailSettings
def user_has_access_to_instance(user_acl: UserAcl, instance: WireGuardInstance): 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) peer=peer, invite_password=password[:32], invite_expiration=timezone.now() + timedelta(minutes=invite_settings.invite_expiration)
) )
return peer_invite 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