Added client default settings page

Added client default settings page, where you can set Allowed IPs, Extra Allowed IPs, use server dns, enable after creation.
This commit is contained in:
Arminas 2023-02-10 07:22:24 +02:00 committed by GitHub
parent fdb36e4711
commit 5fff577c60
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 293 additions and 7 deletions

View file

@ -596,6 +596,22 @@ func GlobalSettings(db store.IStore) echo.HandlerFunc {
}
}
// ClientDefaultSettings handler
func ClientDefaultSettings(db store.IStore) echo.HandlerFunc {
return func(c echo.Context) error {
clientDefaultSettings, err := db.GetClientDefaultSettings()
if err != nil {
log.Error("Cannot get client default settings: ", err)
}
return c.Render(http.StatusOK, "client_default_settings.html", map[string]interface{}{
"baseData": model.BaseData{Active: "client-default-settings", CurrentUser: currentUser(c)},
"clientDefaultSettings": clientDefaultSettings,
})
}
}
// Status handler
func Status(db store.IStore) echo.HandlerFunc {
type PeerVM struct {
@ -709,6 +725,50 @@ func GlobalSettingSubmit(db store.IStore) echo.HandlerFunc {
}
}
// ClientDefaultSettingsSubmit handler to update the client default settings
func ClientDefaultSettingsSubmit(db store.IStore) echo.HandlerFunc {
return func(c echo.Context) error {
//data := make(map[string]interface{})
//err := json.NewDecoder(c.Request().Body).Decode(&data)
//if err != nil {
// return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, "Bad post data"})
//}
//
//var clientDefaultSettings model.ClientDefaults
//fmt.Println(data["allowed_ips"])
//
//clientDefaultSettings.AllowedIps = strings.Split(data["allowed_ips"].(string), ",")
//clientDefaultSettings.ExtraAllowedIps = strings.Split(data["extra_allowed_ips"].(string), ",")
//clientDefaultSettings.EnableAfterCreation = data["enable_after_creation"].(bool)
//clientDefaultSettings.UseServerDNS = data["use_server_dns"].(bool)
var clientDefaultSettings model.ClientDefaults
c.Bind(&clientDefaultSettings)
// validate the input allowed ips list
if util.ValidateCIDRList(clientDefaultSettings.AllowedIps, true) == false {
log.Warnf("Invalid Allowed IPs list input from user: %v", clientDefaultSettings.AllowedIps)
return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, "Allowed IPs must be in CIDR format"})
}
// validate the input extra allowed ips list
if util.ValidateCIDRList(clientDefaultSettings.ExtraAllowedIps, true) == false {
log.Warnf("Invalid Extra Allowed IPs list input from user: %v", clientDefaultSettings.ExtraAllowedIps)
return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, "Extra Allowed IPs must be in CIDR format"})
}
// write config to the database
if err := db.SaveClientDefaultSettings(clientDefaultSettings); err != nil {
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Error saving client default settings"})
}
log.Infof("Updated client default settings: %v", clientDefaultSettings)
return c.JSON(http.StatusOK, jsonHTTPResponse{true, "Updated client default settings successfully"})
}
}
// MachineIPAddresses handler to get local interface ip addresses
func MachineIPAddresses() echo.HandlerFunc {
return func(c echo.Context) error {

View file

@ -158,7 +158,9 @@ func main() {
app.POST(util.BasePath+"/wg-server/interfaces", handler.WireGuardServerInterfaces(db), handler.ValidSession, handler.ContentTypeJson)
app.POST(util.BasePath+"/wg-server/keypair", handler.WireGuardServerKeyPair(db), handler.ValidSession, handler.ContentTypeJson)
app.GET(util.BasePath+"/global-settings", handler.GlobalSettings(db), handler.ValidSession)
app.GET(util.BasePath+"/client-default-settings", handler.ClientDefaultSettings(db), handler.ValidSession)
app.POST(util.BasePath+"/global-settings", handler.GlobalSettingSubmit(db), handler.ValidSession, handler.ContentTypeJson)
app.POST(util.BasePath+"/client-default-settings", handler.ClientDefaultSettingsSubmit(db), handler.ValidSession, handler.ContentTypeJson)
app.GET(util.BasePath+"/status", handler.Status(db), handler.ValidSession)
app.GET(util.BasePath+"/api/clients", handler.GetClients(db), handler.ValidSession)
app.GET(util.BasePath+"/api/client/:id", handler.GetClient(db), handler.ValidSession)

View file

@ -2,8 +2,8 @@ package model
// ClientDefaults Defaults for creation of new clients used in the templates
type ClientDefaults struct {
AllowedIps []string
ExtraAllowedIps []string
UseServerDNS bool
EnableAfterCreation bool
AllowedIps []string `json:"allowed_ips"`
ExtraAllowedIps []string `json:"extra_allowed_ips"`
UseServerDNS bool `json:"use_server_dns"`
EnableAfterCreation bool `json:"enable_after_creation"`
}

View file

@ -36,7 +36,7 @@ func (t *TemplateRegistry) Render(w io.Writer, name string, data interface{}, c
data.(map[string]interface{})[k] = v
}
data.(map[string]interface{})["client_defaults"] = util.ClientDefaultsFromEnv()
data.(map[string]interface{})["client_defaults"] = util.ClientDefaultsFromDatabase()
}
// login page does not need the base layout
@ -83,6 +83,11 @@ func New(tmplBox *rice.Box, extraData map[string]string, secret []byte) *echo.Ec
log.Fatal(err)
}
tmplClientDefaultSettingsString, err := tmplBox.String("client_default_settings.html")
if err != nil {
log.Fatal(err)
}
tmplStatusString, err := tmplBox.String("status.html")
if err != nil {
log.Fatal(err)
@ -103,6 +108,7 @@ func New(tmplBox *rice.Box, extraData map[string]string, secret []byte) *echo.Ec
templates["clients.html"] = template.Must(template.New("clients").Funcs(funcs).Parse(tmplBaseString + tmplClientsString))
templates["server.html"] = template.Must(template.New("server").Funcs(funcs).Parse(tmplBaseString + tmplServerString))
templates["global_settings.html"] = template.Must(template.New("global_settings").Funcs(funcs).Parse(tmplBaseString + tmplGlobalSettingsString))
templates["client_default_settings.html"] = template.Must(template.New("client_default_settings").Funcs(funcs).Parse(tmplBaseString + tmplClientDefaultSettingsString))
templates["status.html"] = template.Must(template.New("status").Funcs(funcs).Parse(tmplBaseString + tmplStatusString))
templates["wake_on_lan_hosts.html"] = template.Must(template.New("wake_on_lan_hosts").Funcs(funcs).Parse(tmplBaseString + tmplWakeOnLanHostsString))

View file

@ -42,6 +42,7 @@ func (o *JsonDB) Init() error {
var serverInterfacePath string = path.Join(serverPath, "interfaces.json")
var serverKeyPairPath string = path.Join(serverPath, "keypair.json")
var globalSettingPath string = path.Join(serverPath, "global_settings.json")
var clientDefaultSettingsPath string = path.Join(serverPath, "client_default_settings.json")
var userPath string = path.Join(serverPath, "users.json")
// create directories if they do not exist
if _, err := os.Stat(clientPath); os.IsNotExist(err) {
@ -102,6 +103,12 @@ func (o *JsonDB) Init() error {
o.conn.Write("server", "global_settings", globalSetting)
}
// client default settings
if _, err := os.Stat(clientDefaultSettingsPath); os.IsNotExist(err) {
clientDefaultSetting := util.ClientDefaultsFromEnv()
o.conn.Write("server", "client_default_settings", clientDefaultSetting)
}
// user info
if _, err := os.Stat(userPath); os.IsNotExist(err) {
user := new(model.User)
@ -138,6 +145,12 @@ func (o *JsonDB) GetGlobalSettings() (model.GlobalSetting, error) {
return settings, o.conn.Read("server", "global_settings", &settings)
}
// GetClientDefaultSettings func to query client default settings from the database
func (o *JsonDB) GetClientDefaultSettings() (model.ClientDefaults, error) {
settings := model.ClientDefaults{}
return settings, o.conn.Read("server", "client_default_settings", &settings)
}
// GetServer func to query Server settings from the database
func (o *JsonDB) GetServer() (model.Server, error) {
server := model.Server{}
@ -213,7 +226,7 @@ func (o *JsonDB) GetClientByID(clientID string, qrCodeSettings model.QRCodeSetti
server, _ := o.GetServer()
globalSettings, _ := o.GetGlobalSettings()
client := client
if !qrCodeSettings.IncludeDNS{
if !qrCodeSettings.IncludeDNS {
globalSettings.DNSServers = []string{}
}
if !qrCodeSettings.IncludeMTU {
@ -255,3 +268,7 @@ func (o *JsonDB) SaveServerKeyPair(serverKeyPair model.ServerKeypair) error {
func (o *JsonDB) SaveGlobalSettings(globalSettings model.GlobalSetting) error {
return o.conn.Write("server", "global_settings", globalSettings)
}
func (o *JsonDB) SaveClientDefaultSettings(clientDefaults model.ClientDefaults) error {
return o.conn.Write("server", "client_default_settings", clientDefaults)
}

View file

@ -9,6 +9,7 @@ type IStore interface {
GetUser() (model.User, error)
SaveUser(user model.User) error
GetGlobalSettings() (model.GlobalSetting, error)
GetClientDefaultSettings() (model.ClientDefaults, error)
GetServer() (model.Server, error)
GetClients(hasQRCode bool) ([]model.ClientData, error)
GetClientByID(clientID string, qrCode model.QRCodeSettings) (model.ClientData, error)
@ -17,6 +18,7 @@ type IStore interface {
SaveServerInterface(serverInterface model.ServerInterface) error
SaveServerKeyPair(serverKeyPair model.ServerKeypair) error
SaveGlobalSettings(globalSettings model.GlobalSetting) error
SaveClientDefaultSettings(clientDefaults model.ClientDefaults) error
GetWakeOnLanHosts() ([]model.WakeOnLanHost, error)
GetWakeOnLanHost(macAddress string) (*model.WakeOnLanHost, error)
DeleteWakeOnHostLanHost(macAddress string) error

View file

@ -124,6 +124,14 @@
</p>
</a>
</li>
<li class="nav-item">
<a href="{{.basePath}}/client-default-settings" class="nav-link {{if eq .baseData.Active "client-default-settings" }}active{{end}}">
<i class="nav-icon fas fa-cog"></i>
<p>
Client Default Settings
</p>
</a>
</li>
<li class="nav-header">UTILITIES</li>
<li class="nav-item">
<a href="{{.basePath}}/status" class="nav-link {{if eq .baseData.Active "status" }}active{{end}}">
@ -488,7 +496,7 @@
$("#client_public_key").val("");
$("#client_preshared_key").val("");
$("#client_allocated_ips").importTags('');
$("#client_extra_allowed_ips").importTags('');
//$("#client_extra_allowed_ips").importTags('');
updateIPAllocationSuggestion();
});
});

View file

@ -0,0 +1,173 @@
{{define "title"}}
Client Defaults Settings
{{end}}
{{define "top_css"}}
{{end}}
{{define "username"}}
{{ .username }}
{{end}}
{{define "page_title"}}
Client Defaults Settings
{{end}}
{{define "page_content"}}
<section class="content">
<div class="container-fluid">
<!-- <h5 class="mt-4 mb-2">Global Settings</h5> -->
<div class="row">
<!-- left column -->
<div class="col-md-6">
<div class="card card-success">
<div class="card-header">
<h3 class="card-title">Client Defaults Settings</h3>
</div>
<!-- /.card-header -->
<!-- form start -->
<form role="form" id="frm_client_default_settings" name="frm_client_default_settings">
<div class="card-body">
<div class="form-group">
<label for="allowed_ips" class="control-label">Allowed IPs</label>
<input type="text" data-role="tagsinput" class="form-control" id="allowed_ips" value="">
</div>
<div class="form-group">
<label for="extra_allowed_ips" class="control-label">Extra Allowed IPs</label>
<input type="text" data-role="tagsinput" class="form-control" id="extra_allowed_ips" value="">
</div>
<div class="form-group">
<div class="icheck-primary d-inline">
<input type="checkbox" id="use_server_dns_chkbox" {{ if .clientDefaultSettings.UseServerDNS }}checked{{ end }}>
<label for="use_server_dns_chkbox">
Use server DNS
</label>
</div>
</div>
<div class="form-group">
<div class="icheck-primary d-inline">
<input type="checkbox" id="enable_after_creation_chkbox" {{ if .clientDefaultSettings.EnableAfterCreation }}checked{{ end }}>
<label for="enable_after_creation_chkbox">
Enable after creation
</label>
</div>
</div>
</div>
<!-- /.card-body -->
<div class="card-footer">
<button type="submit" class="btn btn-success" >Save</button>
</div>
</form>
</div>
<!-- /.card -->
</div>
<div class="col-md-6">
<div class="card card-success">
<div class="card-header">
<h3 class="card-title">Help</h3>
</div>
<!-- /.card-header -->
<div class="card-body">
<dl>
<dt>1. Endpoint Address</dt>
<dd>The public IP address of your Wireguard server that the client will connect to. Click on
<strong>Suggest</strong> button to auto detect the public IP address of your server.</dd>
<dt>2. DNS Servers</dt>
<dd>The DNS servers will be set to client config.</dd>
<dt>3. MTU</dt>
<dd>The MTU will be set to server and client config. By default it is <code>1420</code>. You might want
to adjust the MTU size if your connection (e.g PPPoE, 3G, satellite network, etc) has a low MTU.</dd>
<dd>Leave blank to omit this setting in the configs.</dd>
<dt>4. Persistent Keepalive</dt>
<dd>By default, WireGuard peers remain silent while they do not need to communicate,
so peers located behind a NAT and/or firewall may be unreachable from other peers
until they reach out to other peers themselves. Adding <code>PersistentKeepalive</code>
can ensure that the connection remains open.</dd>
<dd>Leave blank to omit this setting in the Client config.</dd>
<dt>5. Forward Mark</dt>
<dd>Set an <code>fwmark</code> on all packets going out of WireGuard's UDP socket. Default value: <code>0xca6c</code></dd>
<dt>6. Wireguard Config File Path</dt>
<dd>The path of your Wireguard server config file. Please make sure the parent directory
exists and is writable.</dd>
</dl>
</div>
</div>
<!-- /.card -->
</div>
</div>
<!-- /.row -->
</div>
</section>
{{end}}
{{define "bottom_js"}}
<script>
function submitClientDefaultSettings() {
const allowed_ips = $("#allowed_ips").val().split(",");
const extra_allowed_ips = $("#extra_allowed_ips").val().split(",");
const use_server_dns = $("#use_server_dns_chkbox").is(':checked');
const enable_after_creation = $("#enable_after_creation_chkbox").is(':checked');
const data = {"allowed_ips": allowed_ips, "extra_allowed_ips": extra_allowed_ips, "use_server_dns": use_server_dns, "enable_after_creation": enable_after_creation};
$.ajax({
cache: false,
method: 'POST',
url: '{{.basePath}}/client-default-settings',
dataType: 'json',
contentType: "application/json",
data: JSON.stringify(data),
success: function(data) {
toastr.success('Update client default settings successfully');
},
error: function(jqXHR, exception) {
const responseJson = jQuery.parseJSON(jqXHR.responseText);
toastr.error(responseJson['message']);
}
});
}
</script>
<script>
$("#allowed_ips").tagsInput({
'width': '100%',
'height': '75%',
'interactive': true,
'defaultText': 'Add More',
'removeWithBackspace': true,
'minChars': 0,
'placeholderColor': '#666666'
});
$("#extra_allowed_ips").tagsInput({
'width': '100%',
'height': '75%',
'interactive': true,
'defaultText': 'Add More',
'removeWithBackspace': true,
'minChars': 0,
'placeholderColor': '#666666'
});
{{range .clientDefaultSettings.AllowedIps}}
$("#allowed_ips").removeTag('{{.}}');
$("#allowed_ips").addTag('{{.}}');
{{end}}
{{range .clientDefaultSettings.ExtraAllowedIps}}
$("#extra_allowed_ips").removeTag('{{.}}');
$("#extra_allowed_ips").addTag('{{.}}');
{{end}}
// Global setting form validation
$(document).ready(function () {
$.validator.setDefaults({
submitHandler: function () {
submitClientDefaultSettings();
}
});
$("#frm_client_default_settings").validate({
});
});
</script>
{{end}}

View file

@ -93,6 +93,24 @@ func ClientDefaultsFromEnv() model.ClientDefaults {
return clientDefaults
}
// ClientDefaultsFromDatabase to read the default values for creating a new client from the database
func ClientDefaultsFromDatabase() model.ClientDefaults {
// initialize database directory
dir := "./db"
db, err := scribble.New(dir, nil)
if err != nil {
panic(err)
}
// read client default settings
clientDefaults := model.ClientDefaults{}
if err := db.Read("server", "client_default_settings", &clientDefaults); err != nil {
panic(err)
}
return clientDefaults
}
// ValidateCIDR to validate a network CIDR
func ValidateCIDR(cidr string) bool {
_, _, err := net.ParseCIDR(cidr)