mirror of
https://github.com/DJSundog/wg-portal.git
synced 2024-11-23 07:03:50 -05:00
support different interface types: client and server mode
This commit is contained in:
parent
39903922dd
commit
94ca177884
@ -81,3 +81,11 @@ pre{background:#f7f7f9}iframe{overflow:hidden;border:none}@media (min-width: 768
|
||||
content:"*";
|
||||
color:red;
|
||||
}
|
||||
|
||||
a.advanced-settings:before {
|
||||
content: "Hide";
|
||||
}
|
||||
|
||||
a.advanced-settings.collapsed:before {
|
||||
content: "Show";
|
||||
}
|
@ -91,11 +91,11 @@
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-6">
|
||||
<label for="server_PersistentKeepalive">Persistent Keepalive</label>
|
||||
<label for="server_PersistentKeepalive">Persistent Keepalive (0 = off)</label>
|
||||
<input type="number" name="keepalive" class="form-control" id="server_PersistentKeepalive" placeholder="16" value="{{.Peer.PersistentKeepalive}}">
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<label for="server_MTU">Client MTU</label>
|
||||
<label for="server_MTU">Client MTU (0 = default)</label>
|
||||
<input type="number" name="mtu" class="form-control" id="server_MTU" placeholder="" value="{{.Peer.Mtu}}">
|
||||
</div>
|
||||
</div>
|
||||
@ -192,7 +192,7 @@
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-12">
|
||||
<label for="client_PersistentKeepalive">Persistent Keepalive</label>
|
||||
<label for="client_PersistentKeepalive">Persistent Keepalive (0 = off)</label>
|
||||
<input type="number" name="keepalive" class="form-control" id="client_PersistentKeepalive" placeholder="16" value="{{.Peer.PersistentKeepalive}}">
|
||||
</div>
|
||||
</div>
|
||||
@ -209,124 +209,6 @@
|
||||
</div>
|
||||
|
||||
|
||||
<button type="submit" class="btn btn-primary">Save</button>
|
||||
<a href="/admin" class="btn btn-secondary">Cancel</a>
|
||||
</form>
|
||||
{{end}}
|
||||
|
||||
<!-- custom mode -->
|
||||
{{if eq .Device.Type "custom"}}
|
||||
{{if .Peer.IsNew}}
|
||||
<h1>Create a new peer</h1>
|
||||
{{else}}
|
||||
<h1>Edit peer: <strong>{{.Peer.Identifier}}</strong></h1>
|
||||
{{end}}
|
||||
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
<input type="hidden" name="_csrf" value="{{.Csrf}}">
|
||||
<input type="hidden" name="uid" value="{{.Peer.UID}}">
|
||||
<input type="hidden" name="devicetype" value="{{.Device.Type}}">
|
||||
<input type="hidden" name="device" value="{{.Device.DeviceName}}">
|
||||
{{if .EditableKeys}}
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-12">
|
||||
<label for="custom_PrivateKey">Private Key</label>
|
||||
<input type="text" name="privkey" class="form-control" id="custom_PrivateKey" value="{{.Peer.PrivateKey}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group required col-md-12">
|
||||
<label for="custom_PublicKey">Public Key</label>
|
||||
<input type="text" name="pubkey" class="form-control" id="custom_PublicKey" value="{{.Peer.PublicKey}}" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-12">
|
||||
<label for="custom_PresharedKey">Preshared Key</label>
|
||||
<input type="text" name="presharedkey" class="form-control" id="custom_PresharedKey" value="{{.Peer.PresharedKey}}">
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<input type="hidden" name="privkey" value="{{.Peer.PrivateKey}}">
|
||||
<input type="hidden" name="presharedkey" value="{{.Peer.PresharedKey}}">
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-12">
|
||||
<label for="custom_ro_PublicKey">Public Key</label>
|
||||
<input type="text" name="pubkey" readonly class="form-control" id="custom_ro_PublicKey" value="{{.Peer.PublicKey}}">
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="form-row">
|
||||
<div class="form-group required col-md-12">
|
||||
<label for="custom_Identifier">Peer Friendly Name</label>
|
||||
<input type="text" name="identifier" class="form-control" id="custom_Identifier" value="{{.Peer.Identifier}}" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group required col-md-12">
|
||||
<label for="custom_Email">Peer Email Address</label>
|
||||
<input type="email" name="mail" class="form-control" id="custom_Email" value="{{.Peer.Email}}" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-12">
|
||||
<label for="custom_Endpoint">Endpoint Address</label>
|
||||
<input type="text" name="endpoint" class="form-control" id="custom_Endpoint" value="{{.Peer.Endpoint}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group required col-md-12">
|
||||
<label for="custom_EndpointPublicKey">Endpoint Public Key</label>
|
||||
<input type="text" name="endpointpubkey" class="form-control" id="custom_EndpointPublicKey" value="{{.Peer.EndpointPublicKey}}" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-12">
|
||||
<label for="custom_IP">Peer IP Address</label>
|
||||
<input type="text" name="ip" class="form-control" id="custom_IP" value="{{.Peer.IPsStr}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-12">
|
||||
<label for="custom_AllowedIP">Allowed IPs</label>
|
||||
<input type="text" name="allowedip" class="form-control" id="custom_AllowedIP" value="{{.Peer.AllowedIPsStr}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-12">
|
||||
<label for="custom_DNS">Peer DNS Servers</label>
|
||||
<input type="text" name="dns" class="form-control" id="custom_DNS" value="{{.Peer.DNSStr}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-6">
|
||||
<label for="custom_PersistentKeepalive">Persistent Keepalive</label>
|
||||
<input type="number" name="keepalive" class="form-control" id="custom_PersistentKeepalive" placeholder="16" value="{{.Peer.PersistentKeepalive}}">
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<label for="custom_MTU">Client MTU</label>
|
||||
<input type="number" name="mtu" class="form-control" id="custom_MTU" placeholder="" value="{{.Peer.Mtu}}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-12">
|
||||
<div class="custom-control custom-switch">
|
||||
<input class="custom-control-input" name="isdisabled" type="checkbox" value="true" id="custom_Disabled" {{if .Peer.DeactivatedAt}}checked{{end}}>
|
||||
<label class="custom-control-label" for="custom_Disabled">
|
||||
Disabled
|
||||
</label>
|
||||
</div>
|
||||
<div class="custom-control custom-switch">
|
||||
<input class="custom-control-input" name="ignoreglobalsettings" type="checkbox" value="true" id="custom_IgnoreGlobalSettings" {{if .Peer.IgnoreGlobalSettings}}checked{{end}}>
|
||||
<label class="custom-control-label" for="custom_IgnoreGlobalSettings">
|
||||
Ignore global settings
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<button type="submit" class="btn btn-primary">Save</button>
|
||||
<a href="/admin" class="btn btn-secondary">Cancel</a>
|
||||
</form>
|
||||
|
@ -23,9 +23,6 @@
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{if eq .Device.Type "client"}}active{{end}}" data-toggle="tab" href="#client">Client Mode</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{if eq .Device.Type "custom"}}active{{end}}" data-toggle="tab" href="#custom">Custom Mode (Experimental)</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div id="configContent" class="tab-content">
|
||||
@ -74,16 +71,6 @@
|
||||
<input type="text" name="ip" class="form-control" id="server_IPs" placeholder="10.6.6.1/24" value="{{.Device.IPsStr}}" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-6">
|
||||
<label for="server_FirewallMark">Firewall Mark</label>
|
||||
<input type="number" name="firewallmark" class="form-control" id="server_FirewallMark" placeholder="0" value="{{.Device.FirewallMark}}">
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<label for="server_RoutingTable">Routing Table</label>
|
||||
<input type="text" name="routingtable" class="form-control" id="server_RoutingTable" placeholder="auto" value="{{.Device.RoutingTable}}">
|
||||
</div>
|
||||
</div>
|
||||
<h3>Client's global configuration</h3>
|
||||
<div class="form-row">
|
||||
<div class="form-group required col-md-12">
|
||||
@ -103,11 +90,11 @@
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-6">
|
||||
<label for="server_MTU">Global MTU</label>
|
||||
<label for="server_MTU">MTU (also used for the server interface, 0 = default)</label>
|
||||
<input type="number" name="mtu" class="form-control" id="server_MTU" placeholder="" value="{{.Device.Mtu}}">
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<label for="server_PersistentKeepalive">Persistent Keepalive</label>
|
||||
<label for="server_PersistentKeepalive">Persistent Keepalive (0 = off)</label>
|
||||
<input type="number" name="keepalive" class="form-control" id="server_PersistentKeepalive" placeholder="16" value="{{.Device.DefaultPersistentKeepalive}}">
|
||||
</div>
|
||||
</div>
|
||||
@ -137,9 +124,39 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="d-flex align-items-center">
|
||||
<a href="#" class="advanced-settings btn btn-link collapsed" data-toggle="collapse" data-target="#collapseAdvancedServer" aria-expanded="false" aria-controls="collapseAdvancedServer">
|
||||
Advanced Settings
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="collapseAdvancedServer" class="collapse" aria-labelledby="collapseAdvancedServer">
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-6">
|
||||
<label for="server_FirewallMark">Firewall Mark (0 = default or off)</label>
|
||||
<input type="number" name="firewallmark" class="form-control" id="server_FirewallMark" placeholder="" value="{{.Device.FirewallMark}}">
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<label for="server_RoutingTable">Routing Table (empty = default or auto)</label>
|
||||
<input type="text" name="routingtable" class="form-control" id="server_RoutingTable" placeholder="auto" value="{{.Device.RoutingTable}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-12">
|
||||
<div class="custom-control custom-switch">
|
||||
<input class="custom-control-input" name="saveconfig" type="checkbox" value="true" id="server_SaveConfig" {{if .Peer.SaveConfig}}checked{{end}}>
|
||||
<label class="custom-control-label" for="server_SaveConfig">
|
||||
Save Configuration (if interface was edited via WireGuard configuration tool)
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Save</button>
|
||||
<a href="/admin" class="btn btn-secondary">Cancel</a>
|
||||
<a href="/admin/device/applyglobals" class="btn btn-dark float-right">Apply Global Settings to peers</a>
|
||||
<a href="/admin/device/applyglobals" class="btn btn-dark float-right">Apply Global Settings to clients</a>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@ -190,15 +207,15 @@
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-4">
|
||||
<label for="client_MTU">Global MTU</label>
|
||||
<label for="client_MTU">MTU (0 = default)</label>
|
||||
<input type="number" name="mtu" class="form-control" id="client_MTU" placeholder="" value="{{.Device.Mtu}}">
|
||||
</div>
|
||||
<div class="form-group col-md-4">
|
||||
<label for="client_FirewallMark">Firewall Mark</label>
|
||||
<label for="client_FirewallMark">Firewall Mark (0 = default or off)</label>
|
||||
<input type="number" name="firewallmark" class="form-control" id="client_FirewallMark" placeholder="" value="{{.Device.FirewallMark}}">
|
||||
</div>
|
||||
<div class="form-group col-md-4">
|
||||
<label for="client_RoutingTable">Routing Table</label>
|
||||
<label for="client_RoutingTable">Routing Table (empty = default or auto)</label>
|
||||
<input type="text" name="routingtable" class="form-control" id="client_RoutingTable" placeholder="auto" value="{{.Device.RoutingTable}}">
|
||||
</div>
|
||||
</div>
|
||||
@ -230,130 +247,6 @@
|
||||
|
||||
<button type="submit" class="btn btn-primary">Save</button>
|
||||
<a href="/admin" class="btn btn-secondary">Cancel</a>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- custom mode -->
|
||||
<div class="tab-pane fade {{if eq .Device.Type "custom"}}active show{{end}}" id="custom">
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
<input type="hidden" name="_csrf" value="{{.Csrf}}">
|
||||
<input type="hidden" name="device" value="{{.Device.DeviceName}}">
|
||||
<input type="hidden" name="devicetype" value="custom">
|
||||
<h3>Custom interface configuration</h3>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-12">
|
||||
<label for="custom_DisplayName">Display Name</label>
|
||||
<input type="text" name="displayname" class="form-control" id="custom_DisplayName" value="{{.Device.DisplayName}}">
|
||||
</div>
|
||||
</div>
|
||||
{{if .EditableKeys}}
|
||||
<div class="form-row">
|
||||
<div class="form-group required col-md-12">
|
||||
<label for="custom_PrivateKey">Private Key</label>
|
||||
<input type="text" name="privkey" class="form-control" id="custom_PrivateKey" value="{{.Device.PrivateKey}}" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group required col-md-12">
|
||||
<label for="custom_PublicKey">Public Key</label>
|
||||
<input type="text" name="pubkey" class="form-control" id="custom_PublicKey" value="{{.Device.PublicKey}}" required>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<input type="hidden" name="privkey" value="{{.Device.PrivateKey}}">
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-12">
|
||||
<label for="custom_ro_PublicKey">Public Key</label>
|
||||
<input type="text" name="pubkey" readonly class="form-control" id="custom_ro_PublicKey" value="{{.Device.PublicKey}}">
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-6">
|
||||
<label for="custom_ListenPort">Listen port</label>
|
||||
<input type="number" name="port" class="form-control" id="custom_ListenPort" placeholder="51820" value="{{.Device.ListenPort}}">
|
||||
</div>
|
||||
<div class="form-group required col-md-6">
|
||||
<label for="custom_IPs">Interface IP address</label>
|
||||
<input type="text" name="ip" class="form-control" id="custom_IPs" placeholder="10.6.6.1/24" value="{{.Device.IPsStr}}" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-6">
|
||||
<label for="custom_FirewallMark">Firewall Mark</label>
|
||||
<input type="number" name="firewallmark" class="form-control" id="custom_FirewallMark" placeholder="" value="{{.Device.FirewallMark}}">
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<label for="custom_RoutingTable">Routing Table</label>
|
||||
<input type="text" name="routingtable" class="form-control" id="custom_RoutingTable" placeholder="auto" value="{{.Device.RoutingTable}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-12">
|
||||
<div class="custom-control custom-switch">
|
||||
<input class="custom-control-input" name="saveconfig" type="checkbox" value="true" id="custom_SaveConfig" {{if .Peer.SaveConfig}}checked{{end}}>
|
||||
<label class="custom-control-label" for="custom_SaveConfig">
|
||||
Save Configuration (if Interface was edited via WireGuard configuration tool)
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h3>Peer's global configuration</h3>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-6">
|
||||
<label for="custom_PublicEndpoint">Public Endpoint for Clients</label>
|
||||
<input type="text" name="endpoint" class="form-control" id="custom_PublicEndpoint" placeholder="vpn.company.com:51820" value="{{.Device.DefaultEndpoint}}">
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<label for="custom_PersistentKeepalive">Persistent Keepalive</label>
|
||||
<input type="number" name="keepalive" class="form-control" id="custom_PersistentKeepalive" placeholder="16" value="{{.Device.DefaultPersistentKeepalive}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-6">
|
||||
<label for="custom_DNS">DNS Servers</label>
|
||||
<input type="text" name="dns" class="form-control" id="custom_DNS" placeholder="1.1.1.1" value="{{.Device.DNSStr}}">
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<label for="custom_AllowedIP">Default allowed IPs</label>
|
||||
<input type="text" name="allowedip" class="form-control" id="custom_AllowedIP" placeholder="10.6.6.0/24" value="{{.Device.DefaultAllowedIPsStr}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-6">
|
||||
<label for="custom_MTU">Global MTU</label>
|
||||
<input type="number" name="mtu" class="form-control" id="custom_MTU" placeholder="" value="{{.Device.Mtu}}">
|
||||
</div>
|
||||
</div>
|
||||
<h3>Interface configuration hooks</h3>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-12">
|
||||
<label for="custom_PreUp">Pre Up</label>
|
||||
<input type="text" name="preup" class="form-control" id="custom_PreUp" value="{{.Device.PreUp}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-12">
|
||||
<label for="server_PostUp">Post Up</label>
|
||||
<input type="text" name="postup" class="form-control" id="custom_PostUp" value="{{.Device.PostUp}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-12">
|
||||
<label for="custom_PreDown">Pre Down</label>
|
||||
<input type="text" name="predown" class="form-control" id="custom_PreDown" value="{{.Device.PreDown}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-12">
|
||||
<label for="server_PostDown">Post Down</label>
|
||||
<input type="text" name="postdown" class="form-control" id="custom_PostDown" value="{{.Device.PostDown}}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Save</button>
|
||||
<a href="/admin" class="btn btn-secondary">Cancel</a>
|
||||
<a href="/admin/device/applyglobals" class="btn btn-dark float-right">Apply Global Settings to clients</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -18,7 +18,9 @@
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="d-flex align-items-center">
|
||||
<span class="mr-auto">Interface status for <strong>{{.Device.DeviceName}}</strong></span>
|
||||
<span class="mr-auto">Interface status for <strong>{{.Device.DeviceName}}</strong> {{if eq $.Device.Type "server"}}(server mode){{end}}{{if eq $.Device.Type "client"}}(client mode){{end}}</span>
|
||||
<a href="/admin/device/write?dev={{.Device.DeviceName}}" title="Write interface configuration"><i class="fas fa-save"></i></a>
|
||||
|
||||
<a href="/admin/device/download?dev={{.Device.DeviceName}}" title="Download interface configuration"><i class="fas fa-download"></i></a>
|
||||
|
||||
<a href="/admin/device/edit?dev={{.Device.DeviceName}}" title="Edit interface settings"><i class="fas fa-cog"></i></a>
|
||||
@ -26,6 +28,7 @@
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
{{if eq $.Device.Type "server"}}
|
||||
<div class="col-sm-6">
|
||||
<table class="table table-sm table-borderless device-status-table">
|
||||
<tbody>
|
||||
@ -78,21 +81,60 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if eq $.Device.Type "client"}}
|
||||
<div class="col-sm-6">
|
||||
<table class="table table-sm table-borderless device-status-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Public Key:</td>
|
||||
<td>{{.Device.PublicKey}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Enabled Endpoints:</td>
|
||||
<td>{{len .Device.Interface.Peers}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Total Endpoints:</td>
|
||||
<td>{{.TotalPeers}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<table class="table table-sm table-borderless device-status-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>IP Address:</td>
|
||||
<td>{{.Device.IPsStr}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>DNS servers:</td>
|
||||
<td>{{.Device.DNSStr}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Default MTU:</td>
|
||||
<td>{{.Device.Mtu}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4 row">
|
||||
<div class="col-sm-10 col-12">
|
||||
{{with or (eq $.Device.Type "server") (eq $.Device.Type "custom")}}
|
||||
{{if eq $.Device.Type "server"}}
|
||||
<h2 class="mt-2">Current VPN Peers</h2>
|
||||
{{end}}
|
||||
{{with eq $.Device.Type "client"}}
|
||||
{{if eq $.Device.Type "client"}}
|
||||
<h2 class="mt-2">Current VPN Endpoints</h2>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="col-sm-2 col-12 text-right">
|
||||
{{with eq $.Device.Type "server"}}
|
||||
{{if eq $.Device.Type "server"}}
|
||||
<a href="/admin/peer/createldap" title="Add multiple peers" class="btn btn-primary"><i class="fa fa-fw fa-user-plus"></i></a>
|
||||
{{end}}
|
||||
<a href="/admin/peer/create" title="Add a peer" class="btn btn-primary"><i class="fa fa-fw fa-plus"></i>M</a>
|
||||
@ -140,9 +182,11 @@
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" data-toggle="tab" href="#t1{{$p.UID}}">Personal</a>
|
||||
</li>
|
||||
{{if eq $.Device.Type "server"}}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-toggle="tab" href="#t2{{$p.UID}}">Configuration</a>
|
||||
</li>
|
||||
{{end}}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-toggle="tab" href="#t3{{$p.UID}}">Danger Zone</a>
|
||||
</li>
|
||||
@ -168,22 +212,28 @@
|
||||
<p class="ml-4">{{if $p.DeactivatedAt}}-{{else}}<i class="fas fa-long-arrow-alt-down" title="Download"></i> {{formatBytes $p.Peer.ReceiveBytes}} / <i class="fas fa-long-arrow-alt-up" title="Upload"></i> {{formatBytes $p.Peer.TransmitBytes}}{{end}}</p>
|
||||
{{end}}
|
||||
</div>
|
||||
{{if eq $.Device.Type "server"}}
|
||||
<div id="t2{{$p.UID}}" class="tab-pane fade">
|
||||
<pre>{{$p.Config}}</pre>
|
||||
</div>
|
||||
{{end}}
|
||||
<div id="t3{{$p.UID}}" class="tab-pane fade">
|
||||
<a href="/admin/peer/delete?pkey={{$p.PublicKey}}" class="btn btn-danger" title="Delete peer">Delete</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
{{if eq $.Device.Type "server"}}
|
||||
<img class="list-image-large" src="/user/qrcode?pkey={{$p.PublicKey}}"/>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
{{if eq $.Device.Type "server"}}
|
||||
<div class="float-right mt-5">
|
||||
<a href="/admin/peer/download?pkey={{$p.PublicKey}}" class="btn btn-primary" title="Download configuration">Download</a>
|
||||
<a href="/admin/peer/email?pkey={{$p.PublicKey}}" class="btn btn-primary" title="Send configuration via Email">Email</a>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -160,6 +160,7 @@ func (s *Server) updateFormInSession(c *gin.Context, formData interface{}) error
|
||||
|
||||
func (s *Server) setNewPeerFormInSession(c *gin.Context) (SessionData, error) {
|
||||
currentSession := GetSessionData(c)
|
||||
|
||||
// If session does not contain a peer form ignore update
|
||||
// If url contains a formerr parameter reset the form
|
||||
if currentSession.FormData == nil || c.Query("formerr") == "" {
|
||||
|
@ -58,8 +58,6 @@ func (s *Server) PostAdminEditInterface(c *gin.Context) {
|
||||
formDevice.DefaultPersistentKeepalive = 0
|
||||
formDevice.SaveConfig = false
|
||||
case wireguard.DeviceTypeServer:
|
||||
formDevice.SaveConfig = false
|
||||
case wireguard.DeviceTypeCustom:
|
||||
}
|
||||
|
||||
// Update WireGuard device
|
||||
@ -127,6 +125,21 @@ func (s *Server) GetInterfaceConfig(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Server) GetSaveConfig(c *gin.Context) {
|
||||
currentSession := GetSessionData(c)
|
||||
|
||||
err := s.WriteWireGuardConfigFile(currentSession.DeviceName)
|
||||
if err != nil {
|
||||
SetFlashMessage(c, "Failed to save WireGuard config-file: "+err.Error(), "danger")
|
||||
c.Redirect(http.StatusSeeOther, "/admin/")
|
||||
return
|
||||
}
|
||||
|
||||
SetFlashMessage(c, "Updated WireGuard config-file", "success")
|
||||
c.Redirect(http.StatusSeeOther, "/admin/")
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Server) GetApplyGlobalConfig(c *gin.Context) {
|
||||
currentSession := GetSessionData(c)
|
||||
device := s.peers.GetDevice(currentSession.DeviceName)
|
||||
@ -149,10 +162,7 @@ func (s *Server) GetApplyGlobalConfig(c *gin.Context) {
|
||||
peer.PersistentKeepalive = device.DefaultPersistentKeepalive
|
||||
peer.DNSStr = device.DNSStr
|
||||
peer.Mtu = device.Mtu
|
||||
|
||||
if device.Type == wireguard.DeviceTypeServer {
|
||||
peer.EndpointPublicKey = device.PublicKey
|
||||
}
|
||||
|
||||
if err := s.peers.UpdatePeer(peer); err != nil {
|
||||
SetFlashMessage(c, err.Error(), "danger")
|
||||
|
@ -32,6 +32,7 @@ func SetupRoutes(s *Server) {
|
||||
admin.GET("/device/edit", s.GetAdminEditInterface)
|
||||
admin.POST("/device/edit", s.PostAdminEditInterface)
|
||||
admin.GET("/device/download", s.GetInterfaceConfig)
|
||||
admin.GET("/device/write", s.GetSaveConfig)
|
||||
admin.GET("/device/applyglobals", s.GetApplyGlobalConfig)
|
||||
admin.GET("/peer/edit", s.GetAdminEditPeer)
|
||||
admin.POST("/peer/edit", s.PostAdminEditPeer)
|
||||
|
@ -46,8 +46,6 @@ func (s *Server) PrepareNewPeer(device string) (wireguard.Peer, error) {
|
||||
peer.UID = fmt.Sprintf("u%x", md5.Sum([]byte(peer.PublicKey)))
|
||||
|
||||
switch dev.Type {
|
||||
case wireguard.DeviceTypeCustom:
|
||||
fallthrough
|
||||
case wireguard.DeviceTypeServer:
|
||||
peer.EndpointPublicKey = dev.PublicKey
|
||||
peer.Endpoint = dev.DefaultEndpoint
|
||||
@ -121,7 +119,7 @@ func (s *Server) CreatePeer(device string, peer wireguard.Peer) error {
|
||||
|
||||
// Create WireGuard interface
|
||||
if peer.DeactivatedAt == nil {
|
||||
if err := s.wg.AddPeer(device, peer.GetConfig()); err != nil {
|
||||
if err := s.wg.AddPeer(device, peer.GetConfig(&dev)); err != nil {
|
||||
return errors.WithMessage(err, "failed to add WireGuard peer")
|
||||
}
|
||||
}
|
||||
@ -137,6 +135,7 @@ func (s *Server) CreatePeer(device string, peer wireguard.Peer) error {
|
||||
// UpdatePeer updates the physical WireGuard interface and the database.
|
||||
func (s *Server) UpdatePeer(peer wireguard.Peer, updateTime time.Time) error {
|
||||
currentPeer := s.peers.GetPeerByKey(peer.PublicKey)
|
||||
dev := s.peers.GetDevice(peer.DeviceName)
|
||||
|
||||
// Update WireGuard device
|
||||
var err error
|
||||
@ -144,9 +143,9 @@ func (s *Server) UpdatePeer(peer wireguard.Peer, updateTime time.Time) error {
|
||||
case peer.DeactivatedAt == &updateTime:
|
||||
err = s.wg.RemovePeer(peer.DeviceName, peer.PublicKey)
|
||||
case peer.DeactivatedAt == nil && currentPeer.Peer != nil:
|
||||
err = s.wg.UpdatePeer(peer.DeviceName, peer.GetConfig())
|
||||
err = s.wg.UpdatePeer(peer.DeviceName, peer.GetConfig(&dev))
|
||||
case peer.DeactivatedAt == nil && currentPeer.Peer == nil:
|
||||
err = s.wg.AddPeer(peer.DeviceName, peer.GetConfig())
|
||||
err = s.wg.AddPeer(peer.DeviceName, peer.GetConfig(&dev))
|
||||
}
|
||||
if err != nil {
|
||||
return errors.WithMessage(err, "failed to update WireGuard peer")
|
||||
@ -178,10 +177,11 @@ func (s *Server) DeletePeer(peer wireguard.Peer) error {
|
||||
// RestoreWireGuardInterface restores the state of the physical WireGuard interface from the database.
|
||||
func (s *Server) RestoreWireGuardInterface(device string) error {
|
||||
activePeers := s.peers.GetActivePeers(device)
|
||||
dev := s.peers.GetDevice(device)
|
||||
|
||||
for i := range activePeers {
|
||||
if activePeers[i].Peer == nil {
|
||||
if err := s.wg.AddPeer(device, activePeers[i].GetConfig()); err != nil {
|
||||
if err := s.wg.AddPeer(device, activePeers[i].GetConfig(&dev)); err != nil {
|
||||
return errors.WithMessage(err, "failed to add WireGuard peer")
|
||||
}
|
||||
}
|
||||
|
@ -126,8 +126,15 @@ func (p Peer) GetAllowedIPs() []string {
|
||||
return common.ParseStringList(p.AllowedIPsStr)
|
||||
}
|
||||
|
||||
func (p Peer) GetConfig() wgtypes.PeerConfig {
|
||||
publicKey, _ := wgtypes.ParseKey(p.PublicKey)
|
||||
func (p Peer) GetConfig(dev *Device) wgtypes.PeerConfig {
|
||||
var publicKey wgtypes.Key
|
||||
switch dev.Type {
|
||||
case DeviceTypeServer:
|
||||
publicKey, _ = wgtypes.ParseKey(p.PublicKey)
|
||||
case DeviceTypeClient:
|
||||
publicKey, _ = wgtypes.ParseKey(p.EndpointPublicKey)
|
||||
}
|
||||
|
||||
var presharedKey *wgtypes.Key
|
||||
if p.PresharedKey != "" {
|
||||
presharedKeyTmp, _ := wgtypes.ParseKey(p.PresharedKey)
|
||||
@ -218,7 +225,6 @@ type DeviceType string
|
||||
const (
|
||||
DeviceTypeServer DeviceType = "server"
|
||||
DeviceTypeClient DeviceType = "client"
|
||||
DeviceTypeCustom DeviceType = "custom"
|
||||
)
|
||||
|
||||
type Device struct {
|
||||
@ -272,7 +278,6 @@ func (d Device) IsValid() bool {
|
||||
if len(d.GetIPAddresses()) == 0 {
|
||||
return false
|
||||
}
|
||||
case DeviceTypeCustom:
|
||||
}
|
||||
|
||||
return true
|
||||
@ -360,6 +365,17 @@ func NewPeerManager(db *gorm.DB, wg *Manager) (*PeerManager, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// validate and update existing peers if needed
|
||||
for _, deviceName := range wg.Cfg.DeviceNames {
|
||||
dev := pm.GetDevice(deviceName)
|
||||
peers = pm.GetAllPeers(deviceName)
|
||||
for i := range peers {
|
||||
if err := pm.fixPeerDefaultData(&peers[i], &dev); err != nil {
|
||||
return nil, errors.WithMessagef(err, "unable to fix peers for interface %s", deviceName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pm, nil
|
||||
}
|
||||
|
||||
@ -406,16 +422,33 @@ func (m *PeerManager) InitFromPhysicalInterface() error {
|
||||
// assumption: server mode is used
|
||||
func (m *PeerManager) validateOrCreatePeer(device string, wgPeer wgtypes.Peer) error {
|
||||
peer := Peer{}
|
||||
m.db.Where("public_key = ?", wgPeer.PublicKey.String()).FirstOrInit(&peer)
|
||||
m.db.Where("public_key = ? OR endpoint_public_key = ?", wgPeer.PublicKey.String(), wgPeer.PublicKey.String()).FirstOrInit(&peer)
|
||||
|
||||
dev := m.GetDevice(device)
|
||||
|
||||
if peer.PublicKey == "" { // peer not found, create
|
||||
peer.UID = fmt.Sprintf("u%x", md5.Sum([]byte(wgPeer.PublicKey.String())))
|
||||
if dev.Type == DeviceTypeServer {
|
||||
peer.PublicKey = wgPeer.PublicKey.String()
|
||||
peer.Identifier = "Autodetected Client (" + peer.PublicKey[0:8] + ")"
|
||||
} else if dev.Type == DeviceTypeClient {
|
||||
// create a new key pair, not really needed but otherwise our "client exists" detection does not work...
|
||||
key, err := wgtypes.GeneratePrivateKey()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to generate dummy private key")
|
||||
}
|
||||
peer.PrivateKey = key.String()
|
||||
peer.PublicKey = key.PublicKey().String()
|
||||
peer.EndpointPublicKey = wgPeer.PublicKey.String()
|
||||
if wgPeer.Endpoint != nil {
|
||||
peer.Endpoint = wgPeer.Endpoint.String()
|
||||
}
|
||||
peer.Identifier = "Autodetected Endpoint (" + peer.EndpointPublicKey[0:8] + ")"
|
||||
}
|
||||
if wgPeer.PresharedKey != (wgtypes.Key{}) {
|
||||
peer.PresharedKey = wgPeer.PresharedKey.String()
|
||||
}
|
||||
peer.Email = "autodetected@example.com"
|
||||
peer.Identifier = "Autodetected Client (" + peer.PublicKey[0:8] + ")"
|
||||
peer.UpdatedAt = time.Now()
|
||||
peer.CreatedAt = time.Now()
|
||||
IPs := make([]string, len(wgPeer.AllowedIPs)) // use allowed IP's as the peer IP's
|
||||
@ -424,9 +457,6 @@ func (m *PeerManager) validateOrCreatePeer(device string, wgPeer wgtypes.Peer) e
|
||||
}
|
||||
peer.SetIPAddresses(IPs...)
|
||||
peer.DeviceName = device
|
||||
if wgPeer.Endpoint != nil {
|
||||
peer.Endpoint = wgPeer.Endpoint.String() // TODO: do we need to import this for server mode?
|
||||
}
|
||||
|
||||
res := m.db.Create(&peer)
|
||||
if res.Error != nil {
|
||||
@ -494,6 +524,29 @@ func (m *PeerManager) populatePeerData(peer *Peer) {
|
||||
peer.IsOnline = false
|
||||
}
|
||||
|
||||
// fixPeerDefaultData tries to fill all required fields for the given peer
|
||||
func (m *PeerManager) fixPeerDefaultData(peer *Peer, device *Device) error {
|
||||
updatePeer := false
|
||||
|
||||
switch device.Type {
|
||||
case DeviceTypeServer:
|
||||
if peer.Endpoint == "" {
|
||||
peer.Endpoint = device.DefaultEndpoint
|
||||
updatePeer = true
|
||||
}
|
||||
if peer.EndpointPublicKey == "" {
|
||||
peer.EndpointPublicKey = device.PublicKey
|
||||
updatePeer = true
|
||||
}
|
||||
case DeviceTypeClient:
|
||||
}
|
||||
|
||||
if updatePeer {
|
||||
return m.UpdatePeer(*peer)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// populateDeviceData enriches the device struct with WireGuard live data like interface information
|
||||
func (m *PeerManager) populateDeviceData(device *Device) {
|
||||
// set data from WireGuard interface
|
||||
|
@ -10,13 +10,16 @@
|
||||
PrivateKey = {{ .Interface.PrivateKey }}
|
||||
Address = {{ .Interface.IPsStr }}
|
||||
|
||||
# Misc. settings
|
||||
# Misc. settings (optional)
|
||||
{{- if ne .Interface.ListenPort 0}}
|
||||
ListenPort = {{ .Interface.ListenPort }}
|
||||
{{- end}}
|
||||
{{- if ne .Interface.Mtu 0}}
|
||||
MTU = {{.Interface.Mtu}}
|
||||
{{- end}}
|
||||
{{- if and (ne .Interface.DNSStr "") (eq $.Interface.Type "client")}}
|
||||
DNS = {{ .Interface.DNSStr }}
|
||||
{{- end}}
|
||||
{{- if ne .Interface.FirewallMark 0}}
|
||||
FwMark = {{.Interface.FirewallMark}}
|
||||
{{- end}}
|
||||
@ -27,11 +30,19 @@ Table = {{.Interface.RoutingTable}}
|
||||
SaveConfig = true
|
||||
{{- end}}
|
||||
|
||||
# Interface hooks
|
||||
# Interface hooks (optional)
|
||||
{{- if .Interface.PreUp}}
|
||||
PreUp = {{ .Interface.PreUp }}
|
||||
{{- end}}
|
||||
{{- if .Interface.PostUp}}
|
||||
PostUp = {{ .Interface.PostUp }}
|
||||
{{- end}}
|
||||
{{- if .Interface.PreDown}}
|
||||
PreDown = {{ .Interface.PreDown }}
|
||||
{{- end}}
|
||||
{{- if .Interface.PostDown}}
|
||||
PostDown = {{ .Interface.PostDown }}
|
||||
{{- end}}
|
||||
|
||||
#
|
||||
# Peers
|
||||
@ -43,12 +54,24 @@ PostDown = {{ .Interface.PostDown }}
|
||||
# -WGP- Peer email: {{.Email}}
|
||||
# -WGP- PrivateKey: {{.PrivateKey}}
|
||||
[Peer]
|
||||
{{- if eq $.Interface.Type "server"}}
|
||||
PublicKey = {{ .PublicKey }}
|
||||
{{- end}}
|
||||
{{- if eq $.Interface.Type "client"}}
|
||||
PublicKey = {{ .EndpointPublicKey }}
|
||||
{{- end}}
|
||||
{{- if .PresharedKey}}
|
||||
PresharedKey = {{ .PresharedKey }}
|
||||
{{- end}}
|
||||
{{- if eq $.Interface.Type "server"}}
|
||||
AllowedIPs = {{ .IPsStr }}
|
||||
{{- end}}
|
||||
{{- if eq $.Interface.Type "client"}}
|
||||
{{- if .AllowedIPsStr}}
|
||||
AllowedIPs = {{ .AllowedIPsStr }}
|
||||
{{- if and (ne .Endpoint "") (ne $.Interface.Type "server")}}
|
||||
{{- end}}
|
||||
{{- end}}
|
||||
{{- if and (ne .Endpoint "") (eq $.Interface.Type "client")}}
|
||||
Endpoint = {{ .Endpoint }}
|
||||
{{- end}}
|
||||
{{- if ne .PersistentKeepalive 0}}
|
||||
|
@ -8,7 +8,7 @@
|
||||
PrivateKey = {{ .Peer.PrivateKey }}
|
||||
Address = {{ .Peer.IPsStr }}
|
||||
|
||||
# Misc. settings
|
||||
# Misc. settings (optional)
|
||||
{{- if .Peer.DNSStr}}
|
||||
DNS = {{ .Peer.DNSStr }}
|
||||
{{- end}}
|
||||
|
Loading…
Reference in New Issue
Block a user