made it all

This commit is contained in:
iTakinn
2025-10-12 17:49:27 -03:00
commit cbf771ab23
3 changed files with 1145 additions and 0 deletions
+369
View File
@@ -0,0 +1,369 @@
{if $error}
<div class="alert alert-danger">
<strong>Erro:</strong> {$error}
</div>
{else}
<div class="row">
<div class="col-md-6">
{if $formatted_config}
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">
<i class="fa fa-qrcode"></i> Código QR
</h3>
</div>
<div class="panel-body text-center">
<div id="qrcode" style="display: inline-block; margin-bottom: 10px;"></div>
<p class="text-muted">Escaneie este código QR com seu cliente WireGuard</p>
<div class="text-center" style="margin-top: 15px;">
<button class="btn btn-info btn-sm" onclick="showInstructions()">
<i class="fa fa-info-circle"></i> Instruções de Instalação
</button>
</div>
</div>
</div>
{else}
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">
<i class="fa fa-qrcode"></i> Código QR
</h3>
</div>
<div class="panel-body text-center">
<p class="text-muted">Configuração não disponível</p>
</div>
</div>
{/if}
</div>
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">
<i class="fa fa-cog"></i> Configuração WireGuard
</h3>
</div>
<div class="panel-body">
{if $formatted_config}
<div class="form-group">
<label>Arquivo de Configuração:</label>
<pre class="wireguard-config" style="background: #f8f9fa; border: 1px solid #dee2e6; border-radius: 4px; padding: 15px; font-family: 'Courier New', monospace; font-size: 13px; line-height: 1.4; color: #333; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word; max-height: 350px; overflow-y: auto;">{$formatted_config|escape}</pre>
</div>
<div class="text-center">
<button class="btn btn-primary" onclick="downloadFormattedConfig()">
<i class="fa fa-download"></i> Baixar Configuração
</button>
<button class="btn btn-default" onclick="copyFormattedConfig()">
<i class="fa fa-copy"></i> Copiar para Área de Transferência
</button>
</div>
{else}
<p class="text-muted">Configuração não disponível</p>
{/if}
</div>
</div>
</div>
</div>
{/if}
{* Modal de Instruções *}
<div class="modal fade" id="instructionsModal" tabindex="-1" role="dialog">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Instruções de Configuração WireGuard</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Fechar"><span aria-hidden="true">&times;</span></button>
</div>
<div class="modal-body">
<h5>Dispositivos Móveis (Android/iOS):</h5>
<ol>
<li>Instale o aplicativo WireGuard da Google Play Store ou App Store</li>
<li>Abra o aplicativo e toque no botão "+"</li>
<li>Selecione "Escanear código QR"</li>
<li>Escaneie o código QR exibido acima</li>
<li>Dê um nome ao seu túnel e salve</li>
</ol>
<h5>Desktop (Windows/macOS/Linux):</h5>
<ol>
<li>Baixe e instale o WireGuard de <a href="https://www.wireguard.com/install/" target="_blank">wireguard.com</a></li>
<li>Clique em "Adicionar Túnel" → "Adicionar túnel vazio..."</li>
<li>Copie a configuração acima e cole</li>
<li>Salve e ative o túnel</li>
</ol>
<h5>Linha de Comando (Linux):</h5>
<ol>
<li>Salve a configuração em um arquivo (ex: <code>wg0.conf</code>)</li>
<li>Execute: <code>sudo wg-quick up wg0</code></li>
<li>Para parar: <code>sudo wg-quick down wg0</code></li>
</ol>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Fechar</button>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/qrcode@1.5.3/build/qrcode.min.js" onload="initQRCode()" onerror="loadQRCodeFallback()"></script>
<script>
var qrCodeLibraryLoaded = false;
var configForQR = null;
function initQRCode() {
qrCodeLibraryLoaded = true;
console.log('QRCode library loaded successfully');
if (configForQR) {
generateQRCode(configForQR);
}
}
function loadQRCodeFallback() {
console.log('Primary QRCode library failed, trying fallback...');
var script = document.createElement('script');
script.src = 'https://cdn.jsdelivr.net/npm/qrcode-generator@1.4.4/qrcode.min.js';
script.onload = function() {
console.log('Fallback QRCode library loaded');
qrCodeLibraryLoaded = true;
if (configForQR) {
generateQRCodeFallback(configForQR);
}
};
script.onerror = function() {
console.error('Both QRCode libraries failed to load');
var qrCodeElement = document.getElementById('qrcode');
if (qrCodeElement) {
qrCodeElement.innerHTML = '<p class="text-danger">Unable to load QR Code library</p>';
}
};
document.head.appendChild(script);
}
function generateQRCode(configText) {
var qrCodeElement = document.getElementById('qrcode');
console.log('Generating QR Code with qrcode.js...');
console.log('Config text length:', configText.length);
if (qrCodeElement && configText && configText.trim() !== '') {
// Check if QRCode library is loaded
if (typeof QRCode === 'undefined') {
console.error('Biblioteca QRCode não disponível, tentando fallback');
generateQRCodeFallback(configText);
return;
}
try {
QRCode.toCanvas(qrCodeElement, configText, {
width: 250,
margin: 3,
color: {
dark: '#000000',
light: '#FFFFFF'
}
}, function(error) {
if (error) {
console.error('Falha na geração do QR Code:', error);
qrCodeElement.innerHTML = '<p class="text-danger">Falha na geração do QR Code: ' + error.message + '</p>';
} else {
console.log('QR Code gerado com sucesso');
}
});
} catch (e) {
console.error('Exceção durante a geração do QR code:', e);
qrCodeElement.innerHTML = '<p class="text-danger">Erro na geração do QR Code: ' + e.message + '</p>';
}
} else {
console.error('Falha na geração do QR Code: elemento ou configuração ausente');
if (qrCodeElement) {
qrCodeElement.innerHTML = '<p class="text-warning">Configuração não disponível para QR code</p>';
}
}
}
function generateQRCodeFallback(configText) {
var qrCodeElement = document.getElementById('qrcode');
console.log('Trying fallback QR code generation...');
if (qrCodeElement && configText) {
try {
// Create QR code using online service as fallback
var qrUrl = 'https://api.qrserver.com/v1/create-qr-code/?size=250x250&data=' + encodeURIComponent(configText);
var img = document.createElement('img');
img.src = qrUrl;
img.alt = 'WireGuard QR Code';
img.style.border = '3px solid #ddd';
img.style.borderRadius = '4px';
img.onload = function() {
console.log('Fallback QR code loaded successfully');
};
img.onerror = function() {
qrCodeElement.innerHTML = '<p class="text-danger">Falha ao gerar código QR</p>';
};
qrCodeElement.innerHTML = '';
qrCodeElement.appendChild(img);
} catch (e) {
console.error('Falha na geração do QR code de fallback:', e);
qrCodeElement.innerHTML = '<p class="text-danger">Falha na geração do código QR</p>';
}
}
}
// Generate QR Code if formatted config is available
{if $formatted_config}
document.addEventListener('DOMContentLoaded', function() {
configForQR = {$formatted_config|json_encode};
if (qrCodeLibraryLoaded) {
generateQRCode(configForQR);
} else {
console.log('Waiting for QRCode library to load...');
// Timeout fallback
setTimeout(function() {
if (!qrCodeLibraryLoaded && configForQR) {
console.log('Timeout reached, using fallback QR generation');
generateQRCodeFallback(configForQR);
}
}, 3000);
}
});
{else}
console.log('No formatted config available for QR code');
{/if}
function downloadFormattedConfig() {
{if $formatted_config}
var config = {$formatted_config|json_encode};
var element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(config));
element.setAttribute('download', '{$peer_name|default:"wireguard"}.conf');
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
{/if}
}
function copyFormattedConfig() {
{if $formatted_config}
var config = {$formatted_config|json_encode};
if (navigator.clipboard && window.isSecureContext) {
navigator.clipboard.writeText(config).then(function() {
alert('Configuração copiada para a área de transferência!');
}).catch(function(err) {
fallbackCopyTextToClipboard(config);
});
} else {
fallbackCopyTextToClipboard(config);
}
{/if}
}
function fallbackCopyTextToClipboard(text) {
var textArea = document.createElement("textarea");
textArea.value = text;
textArea.style.top = "0";
textArea.style.left = "0";
textArea.style.position = "fixed";
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
try {
var successful = document.execCommand('copy');
if (successful) {
alert('Configuração copiada para a área de transferência!');
} else {
alert('Falha ao copiar configuração. Por favor, copie manualmente.');
}
} catch (err) {
alert('Falha ao copiar configuração. Por favor, copie manualmente.');
}
document.body.removeChild(textArea);
}
// Legacy functions for backward compatibility
function downloadConfig() {
var textarea = document.querySelector('textarea');
if (textarea) {
var config = textarea.value;
var element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(config));
element.setAttribute('download', '{$peer_name|default:"wireguard"}.conf');
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
}
function copyConfig() {
var textarea = document.querySelector('textarea');
if (textarea) {
textarea.select();
try {
document.execCommand('copy');
alert('Configuração copiada para a área de transferência!');
} catch (err) {
alert('Falha ao copiar configuração. Por favor, selecione e copie manualmente.');
}
}
}
function showInstructions() {
$('#instructionsModal').modal('show');
}
</script>
<style>
.panel-heading .fa {
margin-right: 5px;
}
.center-block {
display: block;
margin-left: auto;
margin-right: auto;
}
code {
word-break: break-all;
}
.table-condensed td {
padding: 5px;
}
.modal-body h5 {
color: #337ab7;
margin-top: 20px;
margin-bottom: 10px;
}
.modal-body h5:first-child {
margin-top: 0;
}
/***** Modal close button alignment *****/
.modal-header {
position: relative;
}
.modal-header .close {
position: absolute;
right: 15px;
top: 50%;
transform: translateY(-50%);
font-size: 28px;
line-height: 1;
}
.wireguard-config {
max-height: 350px;
overflow-y: auto;
}
#qrcode canvas {
border: 1px solid #ddd;
border-radius: 4px;
}
</style>
+584
View File
@@ -0,0 +1,584 @@
<?php
if (!defined("WHMCS")) {
die("This file cannot be accessed directly");
}
use Illuminate\Database\Capsule\Manager as Capsule;
function wgdashboard_MetaData(){
return array(
'DisplayName' => 'WGDashboard',
'DefaultNonSSLPort' => '10086',
'DefaultSSLPort' => '443',
'APIVersion' => '1.0',
'RequiresServer' => true,
);
}
function wgdashboard_GetHostname(array $params) {
$hostname = $params['serverhostname'] ?? '';
if ($hostname === '') {
throw new Exception('Could not find the WGDashboard\'s hostname - did you configure server group for the product?');
}
// WHMCS sometimes stores placeholders like DOT/DASH
foreach ([ 'DOT' => '.', 'DASH' => '-' ] as $from => $to) {
$hostname = str_replace($from, $to, $hostname);
}
$hostname = preg_replace('#^https?://#i', '', trim($hostname));
$hostname = rtrim($hostname, '/');
// Strip port from hostname; always use $params['serverport']
if (strpos($hostname, ':') !== false) {
$hostname = explode(':', $hostname)[0];
}
$protocol = (!empty($params['serversecure'])) ? 'https://' : 'http://';
$port = isset($params['serverport']) && is_numeric($params['serverport']) && (int)$params['serverport'] > 0
? (int)$params['serverport']
: null;
return $protocol . $hostname . ($port ? (':' . $port) : '');
}
function wgdashboard_API(array $params, $endpoint, array $data = [], $method = "GET", $dontLog = false) {
$hostname = wgdashboard_GetHostname($params);
$url = $hostname . '/api/' . $endpoint;
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
curl_setopt($curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
curl_setopt($curl, CURLOPT_USERAGENT, "WGDashboard-WHMCS");
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($curl, CURLOPT_POSTREDIR, CURL_REDIR_POST_301);
curl_setopt($curl, CURLOPT_TIMEOUT, 30);
$headers = [
"wg-dashboard-apikey: " . $params['serverpassword'],
"Accept: application/json",
"Content-Type: application/json",
];
if($method === 'POST' || $method === 'PATCH' || $method === 'PUT') {
if(!empty($data)) {
$jsonData = json_encode($data);
curl_setopt($curl, CURLOPT_POSTFIELDS, $jsonData);
$headers[] = "Content-Length: " . strlen($jsonData);
}
}
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
$response = curl_exec($curl);
$responseData = json_decode($response, true);
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
$curlErr = curl_error($curl);
if($response === false && !$dontLog) logModuleCall("WGDashboard-WHMCS", "CURL ERROR", $curlErr, "");
curl_close($curl);
$result = [
'status_code' => $httpCode,
'data' => $responseData
];
if(!$dontLog) logModuleCall("WGDashboard-WHMCS", $method . " - " . $url,
isset($data) ? json_encode($data) : "",
print_r($result, true));
return $result;
}
function wgdashboard_Error($func, $params, Exception $err) {
logModuleCall("WGDashboard-WHMCS", $func, $params, $err->getMessage(), $err->getTraceAsString());
}
function wgdashboard_ConfigOptions()
{
return [
'Allowed IPs' => [
'Type' => 'text',
'Size' => '40',
'Description' => 'Default allowed IPs for created peers (e.g. 10.10.0.0/24 or 0.0.0.0/0)',
'Default' => '0.0.0.0/0',
],
'Config Name' => [
'Type' => 'text',
'Size' => '30',
'Description' => 'WireGuard config name on WGDashboard (if you manage multiple configs)',
'Default' => 'wg0',
],
'Peer Template' => [
'Type' => 'textarea',
'Description' => "Optional JSON template to merge into peer creation payload. Use {{client_email}} or {{domain}} placeholders.",
],
];
}
function wgdashboard_TestConnection(array $params) {
$solutions = [
0 => "Check module debug log for more detailed error.",
401 => "Authorization header either missing or not provided.",
403 => "Double check the API key (which should be in the server password field).",
404 => "Result not found.",
422 => "Validation error.",
500 => "WGDashboard errored, check panel logs.",
];
$err = "";
try {
$response = wgdashboard_API($params, 'getWireguardConfigurations');
if($response['status_code'] !== 200) {
$status_code = $response['status_code'];
$err = "Invalid status_code received: " . $status_code . ". Possible solutions: "
. (isset($solutions[$status_code]) ? $solutions[$status_code] : "None.");
}
} catch(Exception $e) {
wgdashboard_Error(__FUNCTION__, $params, $e);
$err = $e->getMessage();
}
return [
"success" => $err === "",
"error" => $err,
];
}
function wgdashboard_GetPeerID(array $params, $raw = false) {
// Try to get from database directly first
if (!empty($params['serviceid'])) {
try {
$service = Capsule::table('tblhosting')->where('id', $params['serviceid'])->first();
if ($service && !empty($service->username)) {
if ($raw) {
// Get peer info by searching in the configuration
$configName = $params['configoptions']['Config Name'] ?? $params['configoption2'] ?? 'wg0';
$configResult = wgdashboard_API($params, 'getWireguardConfigurationInfo?configurationName=' . urlencode($configName), [], 'GET', false); // Force logging
// Debug: Force logging for this call even with dontLog=true
if(function_exists('logModuleCall')) {
logModuleCall("WGDashboard-WHMCS", "GetPeerID RAW Debug", "Config: " . $configName . ", Looking for: " . $service->username, "Status: " . $configResult['status_code'] . "\nResponse: " . print_r($configResult, true));
}
if($configResult['status_code'] === 200 && isset($configResult['data']['data']['configurationPeers'])) {
foreach($configResult['data']['data']['configurationPeers'] as $peer) {
// Check both 'id' and 'public_key' fields
if(($peer['id'] ?? '') === $service->username || ($peer['public_key'] ?? '') === $service->username) {
return ['status_code' => 200, 'data' => $peer];
}
}
// Debug: If not found, log what peers exist
if(function_exists('logModuleCall')) {
$peerIds = array_map(function($p) { return $p['id'] ?? $p['public_key'] ?? 'no-id'; }, $configResult['data']['data']['configurationPeers']);
logModuleCall("WGDashboard-WHMCS", "GetPeerID NOT FOUND", "Looking for: " . $service->username, "Available peers: " . implode(', ', $peerIds));
}
}
} else {
return $service->username; // This is the public key/id
}
}
} catch (Exception $e) {
// Continue to other methods
}
}
// Try to get peer public key from service username first
if (!empty($params['serviceusername'])) {
if ($raw) {
// Get peer info by searching in the configuration
$configName = $params['configoptions']['Config Name'] ?? $params['configoption2'] ?? 'wg0';
$configResult = wgdashboard_API($params, 'getWireguardConfigurationInfo?configurationName=' . urlencode($configName), [], 'GET', true);
if($configResult['status_code'] === 200 && isset($configResult['data']['data']['configurationPeers'])) {
foreach($configResult['data']['data']['configurationPeers'] as $peer) {
// Check both 'id' and 'public_key' fields
if(($peer['id'] ?? '') === $params['serviceusername'] || ($peer['public_key'] ?? '') === $params['serviceusername']) {
return ['status_code' => 200, 'data' => $peer];
}
}
}
} else {
return $params['serviceusername']; // This is the public key/id
}
}
// Try to get from custom fields
if (!empty($params['customfields']['peer_public_key'])) {
if ($raw) {
$configName = $params['configoptions']['Config Name'] ?? $params['configoption2'] ?? 'wg0';
$configResult = wgdashboard_API($params, 'getWireguardConfigurationInfo?configurationName=' . urlencode($configName), [], 'GET', true);
if($configResult['status_code'] === 200 && isset($configResult['data']['data']['configurationPeers'])) {
foreach($configResult['data']['data']['configurationPeers'] as $peer) {
// Check both 'id' and 'public_key' fields
if(($peer['id'] ?? '') === $params['customfields']['peer_public_key'] || ($peer['public_key'] ?? '') === $params['customfields']['peer_public_key']) {
return ['status_code' => 200, 'data' => $peer];
}
}
}
} else {
return $params['customfields']['peer_public_key'];
}
}
return null;
}
function wgdashboard_GenerateKeyPair() {
if (function_exists('exec') && !in_array('exec', explode(',', ini_get('disable_functions')))) {
$privateKey = '';
$publicKey = '';
exec('wg genkey 2>/dev/null', $output, $return_code);
if ($return_code === 0 && !empty($output[0])) {
$privateKey = trim($output[0]);
// Generate public key from private key
$publicOutput = [];
exec("echo '$privateKey' | wg pubkey 2>/dev/null", $publicOutput, $pub_return_code);
if ($pub_return_code === 0 && !empty($publicOutput[0])) {
$publicKey = trim($publicOutput[0]);
return [
'private_key' => $privateKey,
'public_key' => $publicKey
];
}
}
}
return [
'private_key' => '',
'public_key' => ''
];
}
function wgdashboard_CreateAccount(array $params)
{
try {
$peerId = wgdashboard_GetPeerID($params);
if(isset($peerId)) throw new Exception('Failed to create peer because it is already created.');
$clientEmail = $params['clientsdetails']['email'] ?? '';
$domain = $params['domain'] ?? '';
$serviceId = $params['serviceid'] ?? null;
$allowedIpsDefault = $params['configoptions']['Allowed IPs'] ?? $params['configoption1'] ?? '0.0.0.0/0';
$configName = $params['configoptions']['Config Name'] ?? $params['configoption2'] ?? 'wg0';
$peerName = preg_replace('/[^a-zA-Z0-9_\-\.]/', '_', ($params['clientsdetails']['email'] ?? 'peer') . '_' . ($serviceId ?: uniqid()));
$keys = wgdashboard_GenerateKeyPair();
$payload = [
"name" => $peerName,
"DNS" => "1.1.1.1",
"endpoint_allowed_ip" => "0.0.0.0/0",
"keepalive" => 21,
"mtu" => 1420,
"preshared_key" => "",
"preshared_key_bulkAdd" => false,
"advanced_security" => "off",
];
// Only add keys if they were successfully generated
if (!empty($keys['private_key']) && !empty($keys['public_key'])) {
$payload["private_key"] = $keys['private_key'];
$payload["public_key"] = $keys['public_key'];
}
if (!empty($params['configoptions']['Peer Template'])) {
$template = $params['configoptions']['Peer Template'];
$template = str_replace(['{{client_email}}', '{{domain}}', '{{serviceid}}'], [$clientEmail, $domain, $serviceId], $template);
$jsonTemplate = @json_decode($template, true);
if (is_array($jsonTemplate)) {
$payload = array_merge($payload, $jsonTemplate);
}
}
$result = wgdashboard_API($params, 'addPeers/' . urlencode($configName), $payload, 'POST');
if($result['status_code'] !== 200) {
throw new Exception('WGDashboard create failed: HTTP ' . $result['status_code'] . ' - ' . print_r($result['data'], true));
}
$publicKeyToStore = '';
if (!empty($keys['public_key'])) {
$publicKeyToStore = $keys['public_key'];
} else {
if (isset($result['data']['data']) && is_array($result['data']['data']) && !empty($result['data']['data'][0])) {
$createdPeer = $result['data']['data'][0];
$publicKeyToStore = $createdPeer['id'] ?? '';
}
if (empty($publicKeyToStore)) {
sleep(1);
$configResult = wgdashboard_API($params, 'getWireguardConfigurationInfo?configurationName=' . urlencode($configName), [], 'GET', true);
if($configResult['status_code'] === 200 && isset($configResult['data']['data']['configurationPeers'])) {
foreach($configResult['data']['data']['configurationPeers'] as $peer) {
if($peer['name'] === $peerName) {
$publicKeyToStore = $peer['id'] ?? $peer['public_key'] ?? '';
break;
}
}
}
}
}
if (empty($publicKeyToStore)) {
throw new Exception('Failed to obtain public key for created peer');
}
try {
Capsule::table('tblhosting')->where('id', $params['serviceid'])->update([
'username' => $publicKeyToStore,
'password' => '',
]);
} catch (Exception $e) {
return $e->getMessage() . "<br />" . $e->getTraceAsString();
}
} catch(Exception $err) {
return $err->getMessage();
}
return 'success';
}
function wgdashboard_TerminateAccount($params)
{
try {
$publicKey = wgdashboard_GetPeerID($params);
if(!isset($publicKey)) throw new Exception('Failed to terminate peer because it doesn\'t exist.');
$configName = $params['configoptions']['Config Name'] ?? $params['configoption2'] ?? 'wg0';
$publicKeyEncoded = urlencode($publicKey);
$deleteResult = wgdashboard_API($params, 'deletePeers/' . urlencode($configName) . '?id=' . $publicKeyEncoded, [], 'DELETE');
if($deleteResult['status_code'] !== 200) throw new Exception('Failed to delete the peer, received error code: ' . $deleteResult['status_code'] . '. Enable module debug log for more info.');
} catch(Exception $err) {
return $err->getMessage();
}
return 'success';
}
function wgdashboard_SuspendAccount($params)
{
try {
$publicKey = wgdashboard_GetPeerID($params);
if(!isset($publicKey)) throw new Exception('Failed to suspend peer because it doesn\'t exist.');
$configName = $params['configoptions']['Config Name'] ?? $params['configoption2'] ?? 'wg0';
$publicKeyEncoded = urlencode($publicKey);
$suspendResult = wgdashboard_API($params, 'restrictPeers/' . urlencode($configName) . '?id=' . $publicKeyEncoded, [], 'POST');
if($suspendResult['status_code'] !== 200) throw new Exception('Failed to suspend the peer, received error code: ' . $suspendResult['status_code'] . '. Enable module debug log for more info.');
} catch(Exception $err) {
return $err->getMessage();
}
return 'success';
}
function wgdashboard_UnsuspendAccount($params)
{
try {
$publicKey = wgdashboard_GetPeerID($params);
if(!isset($publicKey)) throw new Exception('Failed to unsuspend peer because it doesn\'t exist.');
$configName = $params['configoptions']['Config Name'] ?? $params['configoption2'] ?? 'wg0';
$publicKeyEncoded = urlencode($publicKey);
$unsuspendResult = wgdashboard_API($params, 'allowAccessPeers/' . urlencode($configName) . '?id=' . $publicKeyEncoded, [], 'POST');
if($unsuspendResult['status_code'] !== 200) throw new Exception('Failed to unsuspend the peer, received error code: ' . $unsuspendResult['status_code'] . '. Enable module debug log for more info.');
} catch(Exception $err) {
return $err->getMessage();
}
return 'success';
}
function wgdashboard_ChangePackage($params)
{
try {
$peerId = wgdashboard_GetPeerID($params);
if(!isset($peerId)) throw new Exception('Failed to change package because peer doesn\'t exist.');
$configName = $params['configoptions']['Config Name'] ?? $params['configoption2'] ?? 'wg0';
$allowedIps = $params['configoptions']['Allowed IPs'] ?? $params['configoption1'] ?? '0.0.0.0/0';
$updateData = [
'allowed_ip' => $allowedIps,
];
$updateResult = wgdashboard_API($params, 'updatePeer/' . urlencode($configName) . '/' . urlencode($peerId), $updateData, 'POST');
if($updateResult['status_code'] !== 200) throw new Exception('Failed to update the peer, received error code: ' . $updateResult['status_code'] . '. Enable module debug log for more info.');
} catch(Exception $err) {
return $err->getMessage();
}
return 'success';
}
function wgdashboard_AdminServicesTabFields($params)
{
$fields = [];
try {
$publicKey = wgdashboard_GetPeerID($params);
$fields['Public Key'] = $publicKey ?: 'Not found';
if($publicKey) {
$peerData = wgdashboard_GetPeerID($params, true);
if($peerData && $peerData['status_code'] === 200 && isset($peerData['data'])) {
$peer = $peerData['data'];
$fields['Peer Name'] = $peer['name'] ?? 'N/A';
$fields['Allowed IPs'] = $peer['allowed_ip'] ?? 'N/A';
$fields['Status'] = ucfirst($peer['status'] ?? 'N/A');
$latestHandshake = $peer['latest_handshake'] ?? null;
if ($latestHandshake && is_numeric($latestHandshake) && $latestHandshake > 0) {
$fields['Latest Handshake'] = date('Y-m-d H:i:s', $latestHandshake);
} elseif ($latestHandshake && preg_match('/^\d+:\d+:\d+$/', $latestHandshake)) {
$fields['Latest Handshake'] = $latestHandshake . ' ago';
} else {
$fields['Latest Handshake'] = 'Never';
}
$cumuReceive = floatval($peer['cumu_receive'] ?? 0);
$totalReceive = floatval($peer['total_receive'] ?? 0);
$totalReceivedMB = $cumuReceive + $totalReceive;
if ($totalReceivedMB >= 1) {
$fields['Data Received P->S'] = number_format($totalReceivedMB, 2) . ' GB';
} else {
$fields['Data Received P->S'] = number_format($totalReceivedMB*1024, 2) . ' MB';
}
$cumuSent = floatval($peer['cumu_sent'] ?? 0);
$totalSent = floatval($peer['total_sent'] ?? 0);
$totalSentMB = $cumuSent + $totalSent;
if ($totalSentMB >= 1) {
$fields['Data Sent S->P'] = number_format($totalSentMB, 2) . ' GB';
} else {
$fields['Data Sent S->P'] = number_format($totalSentMB*1024, 2) . ' MB';
}
$totalDataMB = $totalReceivedMB + $totalSentMB;
if ($totalDataMB >= 1) {
$fields['Total Data'] = number_format($totalDataMB, 2) . ' GB';
} else {
$fields['Total Data'] = number_format($totalDataMB*1024, 2) . ' MB';
}
}
}
} catch (Exception $e) {
$fields['Error'] = $e->getMessage();
}
return $fields;
}
function wgdashboard_ClientArea(array $params) {
if($params['moduletype'] !== 'wgdashboard') return;
try {
$hostname = wgdashboard_GetHostname($params);
$publicKey = wgdashboard_GetPeerID($params);
if(!$publicKey) {
return [
'templatefile' => 'clientarea',
'vars' => [
'error' => 'Peer não encontrado ou ainda não criado.',
],
];
}
$configName = $params['configoptions']['Config Name'] ?? $params['configoption2'] ?? 'wg0';
$peerData = wgdashboard_GetPeerID($params, true);
if(!$peerData || $peerData['status_code'] !== 200) {
return [
'templatefile' => 'clientarea',
'vars' => [
'error' => 'Falha ao recuperar dados do peer.',
],
];
}
$peer = $peerData['data'];
$formattedConfig = '';
if (!empty($peer['private_key'])) {
$formattedConfig = "[Interface]\n";
$formattedConfig .= "PrivateKey = " . ($peer['private_key'] ?? '') . "\n";
$formattedConfig .= "Address = " . ($peer['allowed_ip'] ?? '10.0.0.1/32') . "\n";
$formattedConfig .= "MTU = " . ($peer['mtu'] ?? '1420') . "\n";
$formattedConfig .= "DNS = " . ($peer['DNS'] ?? '1.1.1.1') . "\n";
$formattedConfig .= "\n";
$formattedConfig .= "[Peer]\n";
$serverPublicKey = '';
if (isset($peer['configuration']['PublicKey'])) {
$serverPublicKey = $peer['configuration']['PublicKey'];
} else {
$configInfoResult = wgdashboard_API($params, 'getWireguardConfigurationInfo?configurationName=' . urlencode($configName), [], 'GET', true);
if($configInfoResult['status_code'] === 200 && isset($configInfoResult['data']['data']['configurationInfo']['PublicKey'])) {
$serverPublicKey = $configInfoResult['data']['data']['configurationInfo']['PublicKey'];
}
}
$formattedConfig .= "PublicKey = " . ($serverPublicKey ?: 'N/A') . "\n";
$formattedConfig .= "AllowedIPs = " . ($peer['endpoint_allowed_ip'] ?? '0.0.0.0/0') . "\n";
$endpoint = 'N/A';
if (!empty($peer['remote_endpoint'])) {
$port = '';
if (isset($peer['configuration']['ListenPort'])) {
$port = $peer['configuration']['ListenPort'];
} else {
if (isset($configInfoResult) && $configInfoResult['status_code'] === 200 && isset($configInfoResult['data']['data']['configurationInfo']['ListenPort'])) {
$port = $configInfoResult['data']['data']['configurationInfo']['ListenPort'];
} else {
$port = '51820';
}
}
$endpoint = $peer['remote_endpoint'] . ':' . $port;
}
$formattedConfig .= "Endpoint = " . $endpoint . "\n";
$formattedConfig .= "PersistentKeepalive = " . ($peer['keepalive'] ?? '21') . "\n";
}
return [
'templatefile' => 'clientarea',
'vars' => [
'formatted_config' => $formattedConfig,
'peer_name' => $peer['name'] ?? 'wireguard',
],
];
} catch (Exception $err) {
return [
'templatefile' => 'clientarea',
'vars' => [
'error' => $err->getMessage(),
],
];
}
}