Update check

This commit is contained in:
Eduardo Silva 2024-02-23 14:23:22 -03:00
parent 578f7a63f9
commit 03a9c12696
24 changed files with 349 additions and 16 deletions

View File

@ -1,8 +1,13 @@
from django.http import JsonResponse
from django.views.decorators.http import require_http_methods
from django.contrib.auth.decorators import login_required
from django.conf import settings
from django.utils import timezone
from wireguard.models import WebadminSettings
import requests
import subprocess
@login_required
@require_http_methods(["GET"])
def wireguard_status(request):
@ -53,3 +58,38 @@ def wireguard_status(request):
output[interface][peer][key] = value
return JsonResponse(output)
def cron_check_updates(request):
webadmin_settings, webadmin_settings_created = WebadminSettings.objects.get_or_create(name='webadmin_settings')
if webadmin_settings.last_checked is None or timezone.now() - webadmin_settings.last_checked > timezone.timedelta(hours=6):
try:
version = settings.WIREGUARD_WEBADMIN_VERSION / 10000
url = f'https://updates.eth0.com.br/api/check_updates/?app=wireguard_webadmin&version={version}'
response = requests.get(url)
response.raise_for_status()
data = response.json()
if 'update_available' in data:
webadmin_settings.update_available = data['update_available']
if data['update_available']:
webadmin_settings.latest_version = float(data['current_version']) * 10000
webadmin_settings.last_checked = timezone.now()
webadmin_settings.save()
response_data = {
'update_available': webadmin_settings.update_available,
'latest_version': webadmin_settings.latest_version,
'current_version': settings.WIREGUARD_WEBADMIN_VERSION,
}
return JsonResponse(response_data)
except Exception as e:
webadmin_settings.update_available = False
webadmin_settings.save()
return JsonResponse({'update_available': False})
return JsonResponse({'update_available': webadmin_settings.update_available})

16
cron/Dockerfile-cron Normal file
View File

@ -0,0 +1,16 @@
FROM ubuntu:latest
# Instalar cron
RUN apt-get update && apt-get install -y cron curl
# Adicionar seus scripts de cron
COPY cron_tasks /etc/cron.d/cron_tasks
# Dar permissões apropriadas
RUN chmod 0644 /etc/cron.d/cron_tasks
# Criar um arquivo de log para armazenar os resultados do cron
RUN touch /var/log/cron.log
# Executar o cron em primeiro plano
CMD cron -f

1
cron/cron_tasks Normal file
View File

@ -0,0 +1 @@
* * * * * root /usr/bin/curl -s http://wireguard-webadmin:8000/api/cron_check_updates/ >> /var/log/cron.log 2>&1

View File

@ -27,6 +27,13 @@ services:
- net.ipv4.ip_forward=1
command: /bin/bash /app/init.sh
wireguard-webadmin-cron:
build:
context: ./cron
dockerfile: Dockerfile-cron
depends_on:
- wireguard-webadmin
volumes:
static_volume:
wireguard:

View File

@ -26,6 +26,13 @@ services:
- net.ipv4.ip_forward=1
command: /bin/bash /app/init.sh
wireguard-webadmin-cron:
build:
context: ./cron
dockerfile: Dockerfile-cron
depends_on:
- wireguard-webadmin
volumes:
static_volume:
wireguard:

View File

@ -26,6 +26,13 @@ services:
- net.ipv4.ip_forward=1
command: /bin/bash /app/init.sh
wireguard-webadmin-cron:
build:
context: ./cron
dockerfile: Dockerfile-cron
depends_on:
- wireguard-webadmin
nginx:
container_name: wireguard-webadmin-nginx
restart: unless-stopped

View File

@ -14,8 +14,8 @@ fi
cat > /app/wireguard_webadmin/production_settings.py <<EOL
DEBUG = $DEBUG_VALUE
ALLOWED_HOSTS = ['$SERVER_ADDRESS']
CSRF_TRUSTED_ORIGINS = ['https://$SERVER_ADDRESS']
ALLOWED_HOSTS = ['wireguard-webadmin', '$SERVER_ADDRESS']
CSRF_TRUSTED_ORIGINS = ['http://wireguard-webadmin', 'https://$SERVER_ADDRESS']
SECRET_KEY = '$(openssl rand -base64 32)'
EOL

View File

@ -1,6 +1,11 @@
asgiref==3.7.2
certifi==2024.2.2
charset-normalizer==3.3.2
Django==5.0.1
idna==3.6
pypng==0.20220715.0
qrcode==7.4.2
requests==2.31.0
sqlparse==0.4.4
typing_extensions==4.9.0
urllib3==2.2.1

View File

@ -26,6 +26,9 @@
<!-- summernote -->
<link rel="stylesheet" href="/static/AdminLTE-3.2.0/plugins/summernote/summernote-bs4.min.css">
</head>
{% load custom_tags %}
{% tag_webadmin_version as webadmin_version %}
<body class="hold-transition sidebar-mini layout-fixed">
<div class="wrapper">
@ -165,7 +168,34 @@
</div>
<!-- /.content-header -->
<!-- Generic Modal Structure -->
<div class="modal fade" id="genericModal" tabindex="-1" aria-labelledby="genericModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="genericModalLabel">Modal Title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body" id="genericModalBody">
<!-- Content will be loaded here -->
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal" id="genericModalCloseButton">Close</button>
<a href="#" class="btn btn-primary" id="genericModalActionButton">Action</a>
</div>
</div>
</div>
</div>
<!-- End modal -->
<!-- Main content -->
<section class="content">
<div class="container-fluid">
{% if pending_changes_warning %}
@ -190,9 +220,9 @@
</div>
<!-- /.content-wrapper -->
<footer class="main-footer">
wireguard-webadmin
{% if webadmin_version.update_available %}<a class='btn btn-sm btn-danger' id="btn_update_changelog">Update Available</a>{% else %}wireguard-webadmin {% endif %}
<div class="float-right d-none d-sm-inline-block">
<b>Version</b> 0.9.0
<b>Version</b> {{ webadmin_version.current_version }}
</div>
</footer>
@ -259,8 +289,53 @@
{% endif %}
{% endcomment %}
{% include "template_messages.html" %}
<script>
$(document).ready(function() {
const webadminVersion = '{{ webadmin_version.current_version }}';
$('#btn_update_changelog').on('click', function() {
$.ajax({
url: `https://updates.eth0.com.br/api/application_changelog/?app=wireguard_webadmin&version=${webadminVersion}`,
type: 'GET',
success: function(response) {
const updates = response.updates.sort((a, b) => new Date(b.release_date) - new Date(a.release_date));
let updatesHtml = '';
updates.forEach(update => {
updatesHtml += `<div class="update">
<h5>Version ${update.version}</h5>
<p>${update.release_notes.replace(/\r\n/g, "<br>")}</p>
</div>`;
});
// Update modal content
$('#genericModalLabel').text('Wireguard Webadmin Updates');
$('#genericModalBody').html(updatesHtml);
$('#genericModalCloseButton').text('Close');
$('#genericModalActionButton').text('Update Instructions').attr('href', 'https://github.com/eduardogsilva/wireguard_webadmin').attr('target', '_blank');
// Show modal
$('#genericModal').modal('show');
},
error: function(xhr, status, error) {
// Update modal for error display
$('#genericModalLabel').text('Error');
$('#genericModalBody').html('<p>An error occurred while fetching the update information. Please try again later.</p>');
$('#genericModalCloseButton').text('Close');
$('#genericModalActionButton').hide(); // Hide the action button in case of error
// Show modal
$('#genericModal').modal('show');
console.error("An error occurred while fetching updates: ", error);
}
});
});
});
</script>
{% include "template_messages.html" %}
{% block custom_page_scripts %}

View File

@ -9,7 +9,7 @@
<ul>
<li>AllowedIPs on client configuration side.</li>
<li>Make Peer's last handshake permanent</li>
<li>wireguard_webadmin Update notification</li>
<li>Allow peer portforwarding</li>
</ul>

View File

@ -1,5 +1,5 @@
from django.contrib import admin
from .models import WireGuardInstance, Peer, PeerAllowedIP
from .models import WireGuardInstance, Peer, PeerAllowedIP, WebadminSettings
class WireGuardInstanceAdmin(admin.ModelAdmin):
@ -21,3 +21,10 @@ class PeerAllowedIPAdmin(admin.ModelAdmin):
search_fields = ('peer', 'priority', 'allowed_ip', 'netmask', 'created', 'updated', 'uuid')
admin.site.register(PeerAllowedIP, PeerAllowedIPAdmin)
class WebadminSettingsAdmin(admin.ModelAdmin):
list_display = ('current_version', 'latest_version', 'update_available', 'created', 'updated', 'uuid')
search_fields = ('current_version', 'latest_version', 'update_available', 'created', 'updated', 'uuid')
#admin.site.register(WebadminSettings, WebadminSettingsAdmin)

View File

@ -13,12 +13,12 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='wireguardinstance',
name='dns_primary',
field=models.GenericIPAddressField(default='1.1.1.1', protocol='IPv4', unique=True),
field=models.GenericIPAddressField(default='1.1.1.1', protocol='IPv4', unique=False),
),
migrations.AddField(
model_name='wireguardinstance',
name='dns_secondary',
field=models.GenericIPAddressField(blank=True, default='1.0.0.1', null=True, protocol='IPv4', unique=True),
field=models.GenericIPAddressField(blank=True, default='1.0.0.1', null=True, protocol='IPv4', unique=False),
),
migrations.AddField(
model_name='wireguardinstance',

View File

@ -0,0 +1,28 @@
# Generated by Django 5.0.1 on 2024-02-22 17:54
import uuid
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('wireguard', '0008_wireguardinstance_dns_primary_and_more'),
]
operations = [
migrations.CreateModel(
name='WebadminSettings',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('webadmin_settings', models.CharField(max_length=20, unique=True)),
('update_available', models.BooleanField(default=False)),
('current_version', models.DecimalField(decimal_places=4, default=0, max_digits=8)),
('latest_version', models.DecimalField(decimal_places=4, default=0, max_digits=8)),
('last_checked', models.DateTimeField(blank=True, null=True)),
('updated', models.DateTimeField(auto_now=True)),
('created', models.DateTimeField(auto_now_add=True)),
('uuid', models.UUIDField(default=uuid.uuid4, editable=False, unique=True)),
],
),
]

View File

@ -0,0 +1,17 @@
# Generated by Django 5.0.1 on 2024-02-22 18:03
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('wireguard', '0009_webadminsettings'),
]
operations = [
migrations.RemoveField(
model_name='webadminsettings',
name='webadmin_settings',
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 5.0.1 on 2024-02-22 18:04
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('wireguard', '0010_remove_webadminsettings_webadmin_settings'),
]
operations = [
migrations.AddField(
model_name='webadminsettings',
name='name',
field=models.CharField(default='webadmin_settings', max_length=20, unique=True),
),
]

View File

@ -0,0 +1,21 @@
# Generated by Django 5.0.1 on 2024-02-22 19:02
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('wireguard', '0011_webadminsettings_name'),
]
operations = [
migrations.RemoveField(
model_name='webadminsettings',
name='current_version',
),
migrations.RemoveField(
model_name='webadminsettings',
name='latest_version',
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 5.0.1 on 2024-02-22 19:05
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('wireguard', '0012_remove_webadminsettings_current_version_and_more'),
]
operations = [
migrations.AddField(
model_name='webadminsettings',
name='current_version',
field=models.PositiveIntegerField(default=0),
),
migrations.AddField(
model_name='webadminsettings',
name='latest_version',
field=models.PositiveIntegerField(default=0),
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 5.0.1 on 2024-02-23 15:37
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('wireguard', '0013_webadminsettings_current_version_and_more'),
]
operations = [
migrations.AlterField(
model_name='wireguardinstance',
name='dns_primary',
field=models.GenericIPAddressField(default='1.1.1.1', protocol='IPv4'),
),
migrations.AlterField(
model_name='wireguardinstance',
name='dns_secondary',
field=models.GenericIPAddressField(blank=True, default='1.0.0.1', null=True, protocol='IPv4'),
),
]

View File

@ -29,6 +29,21 @@ NETMASK_CHOICES = (
)
class WebadminSettings(models.Model):
name = models.CharField(default='webadmin_settings', max_length=20, unique=True)
update_available = models.BooleanField(default=False)
current_version = models.PositiveIntegerField(default=0)
latest_version = models.PositiveIntegerField(default=0)
last_checked = models.DateTimeField(blank=True, null=True)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
def __str__(self):
return self.name
class WireGuardInstance(models.Model):
name = models.CharField(max_length=100, blank=True, null=True)
instance_id = models.PositiveIntegerField(unique=True, default=0)
@ -41,8 +56,8 @@ class WireGuardInstance(models.Model):
post_up = models.TextField(blank=True, null=True)
post_down = models.TextField(blank=True, null=True)
peer_list_refresh_interval = models.IntegerField(default=20)
dns_primary = models.GenericIPAddressField(unique=True, protocol='IPv4', default='1.1.1.1')
dns_secondary = models.GenericIPAddressField(unique=True, protocol='IPv4', default='1.0.0.1', blank=True, null=True)
dns_primary = models.GenericIPAddressField(unique=False, protocol='IPv4', default='1.1.1.1')
dns_secondary = models.GenericIPAddressField(unique=False, protocol='IPv4', default='1.0.0.1', blank=True, null=True)
pending_changes = models.BooleanField(default=True)
created = models.DateTimeField(auto_now_add=True)

View File

@ -1,11 +1,13 @@
from decimal import Decimal, ROUND_DOWN
from django.shortcuts import render, get_object_or_404, redirect
from user_manager.models import UserAcl
from wireguard.forms import WireGuardInstanceForm
from .models import WireGuardInstance
from .models import WireGuardInstance, WebadminSettings
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.db import models
from django.conf import settings
import os
import subprocess
@ -67,8 +69,7 @@ def generate_instance_defaults():
@login_required
def view_welcome(request):
page_title = 'Welcome'
breadcrumb = {'level2': {'title': 'Place holder', 'href': '/blabla'}}
context = {'page_title': page_title, 'breadcrumb': breadcrumb}
context = {'page_title': page_title}
return render(request, 'wireguard/welcome.html', context)

View File

View File

@ -0,0 +1,18 @@
from django import template
from django.conf import settings
from wireguard.models import WebadminSettings
register = template.Library()
@register.simple_tag
def tag_webadmin_version():
webadmin_settings, settings_created = WebadminSettings.objects.get_or_create(name='webadmin_settings')
if webadmin_settings.current_version != settings.WIREGUARD_WEBADMIN_VERSION:
webadmin_settings.current_version = settings.WIREGUARD_WEBADMIN_VERSION
webadmin_settings.save()
return {
'current_version': settings.WIREGUARD_WEBADMIN_VERSION / 10000,
'latest_version': webadmin_settings.latest_version / 10000,
'update_available': webadmin_settings.update_available,
}

View File

@ -38,6 +38,7 @@ INSTALLED_APPS = [
'django.contrib.staticfiles',
'wireguard',
'user_manager',
'wireguard_tools',
]
MIDDLEWARE = [
@ -127,4 +128,6 @@ STATICFILES_DIRS = [
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
WIREGUARD_WEBADMIN_VERSION = 9000
from wireguard_webadmin.production_settings import *

View File

@ -22,7 +22,7 @@ from console.views import view_console
from user_manager.views import view_user_list, view_manage_user
from accounts.views import view_create_first_user, view_login, view_logout
from wireguard_tools.views import export_wireguard_configs, download_config_or_qrcode, restart_wireguard_interfaces
from api.views import wireguard_status
from api.views import wireguard_status, cron_check_updates
urlpatterns = [
@ -43,5 +43,6 @@ urlpatterns = [
path('accounts/login/', view_login, name='login'),
path('accounts/logout/', view_logout, name='logout'),
path('api/wireguard_status/', wireguard_status, name='api_wireguard_status'),
path('api/cron_check_updates/', cron_check_updates, name='cron_check_updates'),
]