Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Client default settings page #315

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Open
46 changes: 46 additions & 0 deletions handler/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,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), Admin: isAdmin(c)},
"clientDefaultSettings": clientDefaultSettings,
})
}
}

// Status handler
func Status(db store.IStore) echo.HandlerFunc {
type PeerVM struct {
Expand Down Expand Up @@ -882,6 +898,36 @@ 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 {

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 {
Expand Down
3 changes: 3 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,9 @@ func main() {
app.POST(util.BasePath+"/wg-server/keypair", handler.WireGuardServerKeyPair(db), handler.ValidSession, handler.ContentTypeJson, handler.NeedsAdmin)
app.GET(util.BasePath+"/global-settings", handler.GlobalSettings(db), handler.ValidSession, handler.NeedsAdmin)
app.POST(util.BasePath+"/global-settings", handler.GlobalSettingSubmit(db), handler.ValidSession, handler.ContentTypeJson, handler.NeedsAdmin)
app.POST(util.BasePath+"/client-default-settings", handler.ClientDefaultSettingsSubmit(db), handler.ValidSession, handler.ContentTypeJson, handler.NeedsAdmin)
app.GET(util.BasePath+"/client-default-settings", handler.ClientDefaultSettings(db), handler.ValidSession, handler.NeedsAdmin)

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)
Expand Down
8 changes: 4 additions & 4 deletions model/client_defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
}
8 changes: 7 additions & 1 deletion router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -83,6 +83,11 @@ func New(tmplDir fs.FS, extraData map[string]string, secret []byte) *echo.Echo {
log.Fatal(err)
}

tmplClientDefaultSettingsString, err := util.StringFromEmbedFile("client_default_settings.html")
if err != nil {
log.Fatal(err)
}

tmplUsersSettingsString, err := util.StringFromEmbedFile(tmplDir, "users_settings.html")
if err != nil {
log.Fatal(err)
Expand Down Expand Up @@ -113,6 +118,7 @@ func New(tmplDir fs.FS, extraData map[string]string, secret []byte) *echo.Echo {
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["users_settings.html"] = template.Must(template.New("users_settings").Funcs(funcs).Parse(tmplBaseString + tmplUsersSettingsString))
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))
Expand Down
18 changes: 18 additions & 0 deletions store/jsondb/jsondb.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 hashesPath string = path.Join(serverPath, "hashes.json")
var userPath string = path.Join(serverPath, "users.json")

Expand Down Expand Up @@ -115,6 +116,12 @@ func (o *JsonDB) Init() error {
o.conn.Write("server", "hashes", clientServerHashes)
}

// client default settings
if _, err := os.Stat(clientDefaultSettingsPath); os.IsNotExist(err) {
clientDefaultSetting := util.ClientDefaultsFromEnv()
o.conn.Write("server", "client_default_settings", clientDefaultSetting)
}

// user info
results, err := o.conn.ReadAll("users")
if err != nil || len(results) < 1 {
Expand Down Expand Up @@ -188,6 +195,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{}
Expand Down Expand Up @@ -303,6 +316,11 @@ 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)
}

func (o *JsonDB) GetPath() string {
return o.dbPath
}
Expand Down
2 changes: 2 additions & 0 deletions store/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type IStore interface {
SaveUser(user model.User) error
DeleteUser(username string) 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)
Expand All @@ -19,6 +20,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
Expand Down
10 changes: 9 additions & 1 deletion templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,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-item">
<a href="{{.basePath}}/users-settings" class="nav-link {{if eq .baseData.Active "users-settings" }}active{{end}}">
<i class="nav-icon fas fa-cog"></i>
Expand Down Expand Up @@ -554,7 +562,7 @@ <h1>{{template "page_title" .}}</h1>
$("#client_public_key").val("");
$("#client_preshared_key").val("");
$("#client_allocated_ips").importTags('');
$("#client_extra_allowed_ips").importTags('');
//$("#client_extra_allowed_ips").importTags('');
updateIPAllocationSuggestion();
});
});
Expand Down
161 changes: 161 additions & 0 deletions templates/client_default_settings.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
{{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. Allowed IPs</dt>
<dd>Specify a list of addresses that will get routed to the <code>server</code>. These addresses will be included in 'AllowedIPs' of client config.</dd>
<dt>2. Extra Allowed IPs</dt>
<dd>Specify a list of addresses that will get routed to the <code>client</code>. These addresses will be included in 'AllowedIPs' of WG server config</dd>
<dt>3. Use server DNS</dt>
<dd>Specify if clients use server DNS by default.</dd>
<dt>4. Enable after creation</dt>
<dd>Specify if clients become enabled after creation.</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}}
18 changes: 18 additions & 0 deletions util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,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)
Expand Down