diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1eeebf1..1e5d93a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -7,7 +7,7 @@ on: jobs: releases-matrix: name: Release Go Binary - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 strategy: matrix: # build and publish in parallel: linux/386, linux/amd64, darwin/386, darwin/amd64 diff --git a/README.md b/README.md index 86fee8d..3f87609 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,7 @@ SMTP_PORT: the SMTP port SMTP_USERNAME: the SMTP username to authenticate SMTP_PASSWORD: the SMTP user password SMTP_AUTH_TYPE: the authentication type. Possible values: PLAIN, LOGIN, NONE +SMTP_ENCRYPTION: the encryption method. Possible values: SSL, SSLTLS, TLS or STARTTLS (default) EMAIL_FROM_ADDRESS: the sender's email address EMAIL_FROM_NAME: the sender's name ``` diff --git a/handler/routes.go b/handler/routes.go index 19512c1..dd6a94a 100644 --- a/handler/routes.go +++ b/handler/routes.go @@ -138,7 +138,15 @@ func GetClient(db store.IStore) echo.HandlerFunc { return func(c echo.Context) error { clientID := c.Param("id") - clientData, err := db.GetClientByID(clientID, true) + qrCodeIncludeFwMark := c.QueryParam("qrCodeIncludeFwMark") + qrCodeSettings := model.QRCodeSettings{ + Enabled: true, + IncludeDNS: true, + IncludeFwMark: qrCodeIncludeFwMark == "true", + IncludeMTU: true, + } + + clientData, err := db.GetClientByID(clientID, qrCodeSettings) if err != nil { return c.JSON(http.StatusNotFound, jsonHTTPResponse{false, "Client not found"}) } @@ -257,7 +265,13 @@ func EmailClient(db store.IStore, mailer emailer.Emailer, emailSubject, emailCon c.Bind(&payload) // TODO validate email - clientData, err := db.GetClientByID(payload.ID, true) + qrCodeSettings := model.QRCodeSettings{ + Enabled: true, + IncludeDNS: true, + IncludeFwMark: true, + IncludeMTU: true, + } + clientData, err := db.GetClientByID(payload.ID, qrCodeSettings) if err != nil { log.Errorf("Cannot generate client id %s config file for downloading: %v", payload.ID, err) return c.JSON(http.StatusNotFound, jsonHTTPResponse{false, "Client not found"}) @@ -304,7 +318,7 @@ func UpdateClient(db store.IStore) echo.HandlerFunc { c.Bind(&_client) // validate client existence - clientData, err := db.GetClientByID(_client.ID, false) + clientData, err := db.GetClientByID(_client.ID, model.QRCodeSettings{Enabled: false}) if err != nil { return c.JSON(http.StatusNotFound, jsonHTTPResponse{false, "Client not found"}) } @@ -370,7 +384,7 @@ func SetClientStatus(db store.IStore) echo.HandlerFunc { clientID := data["id"].(string) status := data["status"].(bool) - clientdata, err := db.GetClientByID(clientID, false) + clientdata, err := db.GetClientByID(clientID, model.QRCodeSettings{Enabled: false}) if err != nil { return c.JSON(http.StatusNotFound, jsonHTTPResponse{false, err.Error()}) } @@ -395,7 +409,7 @@ func DownloadClient(db store.IStore) echo.HandlerFunc { return c.JSON(http.StatusNotFound, jsonHTTPResponse{false, "Missing clientid parameter"}) } - clientData, err := db.GetClientByID(clientID, false) + clientData, err := db.GetClientByID(clientID, model.QRCodeSettings{Enabled: false}) if err != nil { log.Errorf("Cannot generate client id %s config file for downloading: %v", clientID, err) return c.JSON(http.StatusNotFound, jsonHTTPResponse{false, "Client not found"}) diff --git a/model/client.go b/model/client.go index 9609265..b9e8141 100644 --- a/model/client.go +++ b/model/client.go @@ -28,3 +28,10 @@ type ClientData struct { Client *Client QRCode string } + +type QRCodeSettings struct { + Enabled bool + IncludeDNS bool + IncludeFwMark bool + IncludeMTU bool +} diff --git a/store/jsondb/jsondb.go b/store/jsondb/jsondb.go index 285bc19..b0d39f5 100644 --- a/store/jsondb/jsondb.go +++ b/store/jsondb/jsondb.go @@ -81,14 +81,18 @@ func (o *JsonDB) Init() error { // global settings if _, err := os.Stat(globalSettingPath); os.IsNotExist(err) { - - publicInterface, err := util.GetPublicIP() - if err != nil { - return err + endpointAddress := util.LookupEnvOrString(util.EndpointAddressEnvVar, "") + if endpointAddress == "" { + // automatically find an external IP address + publicInterface, err := util.GetPublicIP() + if err != nil { + return err + } + endpointAddress = publicInterface.IPAddress } globalSetting := new(model.GlobalSetting) - globalSetting.EndpointAddress = util.LookupEnvOrString(util.EndpointAddressEnvVar, publicInterface.IPAddress) + globalSetting.EndpointAddress = endpointAddress globalSetting.DNSServers = util.LookupEnvOrStrings(util.DNSEnvVar, []string{util.DefaultDNS}) globalSetting.MTU = util.LookupEnvOrInt(util.MTUEnvVar, util.DefaultMTU) globalSetting.PersistentKeepalive = util.LookupEnvOrInt(util.PersistentKeepaliveEnvVar, util.DefaultPersistentKeepalive) @@ -190,7 +194,7 @@ func (o *JsonDB) GetClients(hasQRCode bool) ([]model.ClientData, error) { return clients, nil } -func (o *JsonDB) GetClientByID(clientID string, hasQRCode bool) (model.ClientData, error) { +func (o *JsonDB) GetClientByID(clientID string, qrCodeSettings model.QRCodeSettings) (model.ClientData, error) { client := model.Client{} clientData := model.ClientData{} @@ -200,9 +204,17 @@ func (o *JsonDB) GetClientByID(clientID string, hasQRCode bool) (model.ClientDat } // generate client qrcode image in base64 - if hasQRCode && client.PrivateKey != "" { + if qrCodeSettings.Enabled && client.PrivateKey != "" { server, _ := o.GetServer() globalSettings, _ := o.GetGlobalSettings() + client := client + client.UseServerDNS = qrCodeSettings.IncludeDNS + if !qrCodeSettings.IncludeMTU { + globalSettings.MTU = 0 + } + if !qrCodeSettings.IncludeFwMark { + globalSettings.ForwardMark = "" + } png, err := qrcode.Encode(util.BuildClientConfig(client, server, globalSettings), qrcode.Medium, 256) if err == nil { diff --git a/store/store.go b/store/store.go index 98795b2..2dca8a7 100644 --- a/store/store.go +++ b/store/store.go @@ -10,7 +10,7 @@ type IStore interface { GetGlobalSettings() (model.GlobalSetting, error) GetServer() (model.Server, error) GetClients(hasQRCode bool) ([]model.ClientData, error) - GetClientByID(clientID string, hasQRCode bool) (model.ClientData, error) + GetClientByID(clientID string, qrCode model.QRCodeSettings) (model.ClientData, error) SaveClient(client model.Client) error DeleteClient(clientID string) error SaveServerInterface(serverInterface model.ServerInterface) error diff --git a/templates/base.html b/templates/base.html index 28f5e84..ff77df5 100644 --- a/templates/base.html +++ b/templates/base.html @@ -386,7 +386,7 @@ $("#modal_new_client").modal('hide'); toastr.success('Created new client successfully'); // Update the home page (clients page) after adding successfully - if (window.location.pathname === "/") { + if (window.location.pathname === "{{.basePath}}/") { populateClient(resp.id); } }, diff --git a/templates/clients.html b/templates/clients.html index 538782b..cdce8c0 100644 --- a/templates/clients.html +++ b/templates/clients.html @@ -68,7 +68,18 @@ Wireguard Clients - QR code + @@ -387,6 +398,37 @@ Wireguard Clients }); }); + // regenerateQRCode function for regenerating QR Code adding/removing some parts of configuration because of compatibility issues with some clients + function regenerateQRCode() { + const client_id = $("#qr_client_id").val(); + const QRCodeImg = $("#qr_code"); + let include_fwmark = false; + if ($("#qr_include_fwmark").is(':checked')){ + include_fwmark = true; + } + QRCodeImg.hide(); + $.ajax({ + cache: false, + method: 'GET', + url: '{{.basePath}}/api/client/' + client_id, + data: { + qrCodeIncludeFwMark: include_fwmark + }, + dataType: 'json', + contentType: "application/json", + success: function (resp) { + const client = resp.Client; + + $(".modal-title").text("Scan QR Code for " + client.name + " profile"); + QRCodeImg.attr('src', resp.QRCode).show(); + }, + error: function (jqXHR, exception) { + const responseJson = jQuery.parseJSON(jqXHR.responseText); + toastr.error(responseJson['message']); + } + }); + } + // submitEmailClient function for sending an email to the client with the configuration function submitEmailClient() { const client_id = $("#e_client_id").val(); @@ -467,7 +509,7 @@ Wireguard Clients const formId = $(form).attr('id'); if (formId === "frm_edit_client") { submitEditClient(); - }else if (formId === "frm_email_client") { + } else if (formId === "frm_email_client") { submitEmailClient(); } } @@ -500,31 +542,14 @@ Wireguard Clients let modal = $(this); const button = $(event.relatedTarget); const client_id = button.data('clientid'); - const QRCodeImg = modal.find("#qr_code"); - QRCodeImg.hide(); - $.ajax({ - cache: false, - method: 'GET', - url: '{{.basePath}}/api/client/' + client_id, - dataType: 'json', - contentType: "application/json", - success: function (resp) { - const client = resp.Client; - modal.find(".modal-title").text("Scan QR Code for " + client.name + " profile"); - QRCodeImg.attr('src', resp.QRCode).show(); - }, - error: function (jqXHR, exception) { - const responseJson = jQuery.parseJSON(jqXHR.responseText); - toastr.error(responseJson['message']); - } - }); + modal.find("#qr_client_id").val(client_id); + regenerateQRCode(); }); $(document).ready(function () { $.validator.setDefaults({ submitHandler: function (form) { - //submitEditClient(); submitHandler(form); } }); @@ -577,6 +602,7 @@ Wireguard Clients $(element).removeClass('is-invalid'); } }); + // }); {{end}} diff --git a/templates/global_settings.html b/templates/global_settings.html index 1c01438..3b0724e 100644 --- a/templates/global_settings.html +++ b/templates/global_settings.html @@ -172,7 +172,7 @@ Global Settings } function updateEndpointSuggestionIP() { - $.getJSON("/api/machine-ips", null, function(data) { + $.getJSON("{{.basePath}}/api/machine-ips", null, function(data) { $("#ip_suggestion option").remove(); $.each(data, function(index, item) { $("#ip_suggestion").append( diff --git a/util/util.go b/util/util.go index 8826ee6..5a3a5f1 100644 --- a/util/util.go +++ b/util/util.go @@ -70,7 +70,7 @@ func BuildClientConfig(client model.Client, server model.Server, setting model.G } forwardMark := "" - if setting.ForwardMark != "" && setting.ForwardMark != DefaultForwardMark { + if setting.ForwardMark != "" { forwardMark = fmt.Sprintf("FwMark = %s\n", setting.ForwardMark) }