diff --git a/README.md b/README.md index 4258bb6..86fee8d 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,8 @@ wireguard interface stats. See the `cap_add` and `network_mode` options on the d |-----------------------------|-----------------------------------------------------------------------------------------------------------------| | `SESSION_SECRET` | Used to encrypt the session cookies. Set this to a random value. | | `WGUI_USERNAME` | The username for the login page. (default `admin`) | -| `WGUI_PASSWORD` | The password for the user on the login page. (default `admin`) | +| `WGUI_PASSWORD` | The password for the user on the login page. Will be hashed automatically. (default `admin`) | +| `WGUI_PASSWORD_HASH` | The password hash for the user on the login page. (alternative to `WGUI_PASSWORD`) | | `WGUI_ENDPOINT_ADDRESS` | The default endpoint address used in global settings. (default is your public IP address) | | `WGUI_DNS` | The default DNS servers (comma-separated-list) used in the global settings. (default `1.1.1.1`) | | `WGUI_MTU` | The default MTU used in global settings. (default `1450`) | diff --git a/custom/js/wake_on_lan_hosts.js b/custom/js/wake_on_lan_hosts.js index 074f6b8..36ad1f3 100644 --- a/custom/js/wake_on_lan_hosts.js +++ b/custom/js/wake_on_lan_hosts.js @@ -1,3 +1,8 @@ +var base_url = jQuery(".brand-link").attr('href'); +if (base_url.substring(base_url.length - 1, base_url.length) != "/") + base_url = base_url + "/"; + + const wake_on_lan_new_template = '
\n' + '\t
\n' + '\t\t
\n' + @@ -24,9 +29,9 @@ const wake_on_lan_new_template = '
\n' + '
'; jQuery(function ($) { - $.validator.addMethod('mac', function (value, element) { - return this.optional(element) || /^([0-9A-F]{2}[:]){5}([0-9A-F]{2})$/.test(value); - }, 'Please enter a valid MAC Address.(uppercase letters and numbers, : only) ex: 00:AB:12:EF:DD:AA'); + $.validator.addMethod('mac', function (value, element) { + return this.optional(element) || /^([0-9A-F]{2}[:]){5}([0-9A-F]{2})$/.test(value); + }, 'Please enter a valid MAC Address.(uppercase letters and numbers, : only) ex: 00:AB:12:EF:DD:AA'); }); jQuery.each(["put", "delete"], function (i, method) { @@ -42,7 +47,8 @@ jQuery.each(["put", "delete"], function (i, method) { type: method, dataType: type, data: data, - success: callback + success: callback, + contentType: 'application/json' }); }; }); @@ -55,7 +61,7 @@ jQuery(function ($) { jQuery(function ($) { $('.btn-outline-success').click(function () { const $this = $(this); - $.put('/wake_on_lan_host/' + $this.data('mac-address'), function (result) { + $.put(base_url + 'wake_on_lan_host/' + $this.data('mac-address'), function (result) { $this.parents('.info-box').find('.latest-used').text(prettyDateTime(result)); }); }); @@ -76,7 +82,7 @@ jQuery(function ($) { $remove_client_confirm.click(function () { const macAddress = $remove_client_confirm.val().replaceAll(":", "-"); - $.delete('/wake_on_lan_host/' + macAddress); + $.delete(base_url + 'wake_on_lan_host/' + macAddress); $('#' + macAddress).remove(); $modal_remove_wake_on_lan_host.modal('hide'); @@ -84,10 +90,18 @@ jQuery(function ($) { }); jQuery(function ($) { - $('.latest-used').each(function () { - const $this = $(this); - $this.text(prettyDateTime($this.text().trim())); - }); + $('.latest-used').each(function () { + const $this = $(this); + const timeText = $this.text().trim(); + try { + if (timeText != "Unused") { + $this.text(prettyDateTime(timeText)); + } + } catch (ex) { + console.log(timeText); + throw ex; + } + }); }); jQuery(function ($) { @@ -109,7 +123,7 @@ jQuery(function ($) { $.ajax({ cache: false, method: 'POST', - url: '/wake_on_lan_host', + url: base_url + 'wake_on_lan_host', dataType: 'json', contentType: "application/json", data: JSON.stringify(data), diff --git a/emailer/smtp.go b/emailer/smtp.go index 38ac995..d1fdbae 100644 --- a/emailer/smtp.go +++ b/emailer/smtp.go @@ -3,9 +3,9 @@ package emailer import ( "crypto/tls" "fmt" - "time" - mail "github.com/xhit/go-simple-mail/v2" + "strings" + "time" ) type SmtpMail struct { @@ -14,13 +14,14 @@ type SmtpMail struct { username string password string authType mail.AuthType + encryption mail.Encryption noTLSCheck bool fromName string from string } func authType(authType string) mail.AuthType { - switch authType { + switch strings.ToUpper(authType) { case "PLAIN": return mail.AuthPlain case "LOGIN": @@ -30,8 +31,21 @@ func authType(authType string) mail.AuthType { } } -func NewSmtpMail(hostname string, port int, username string, password string, noTLSCheck bool, auth string, fromName, from string) *SmtpMail { - ans := SmtpMail{hostname: hostname, port: port, username: username, password: password, noTLSCheck: noTLSCheck, fromName: fromName, from: from, authType: authType(auth)} +func encryptionType(encryptionType string) mail.Encryption { + switch strings.ToUpper(encryptionType) { + case "SSL": + return mail.EncryptionSSL + case "SSLTLS": + return mail.EncryptionSSLTLS + case "TLS": + return mail.EncryptionTLS + default: + return mail.EncryptionSTARTTLS + } +} + +func NewSmtpMail(hostname string, port int, username string, password string, noTLSCheck bool, auth string, fromName, from string, encryption string) *SmtpMail { + ans := SmtpMail{hostname: hostname, port: port, username: username, password: password, noTLSCheck: noTLSCheck, fromName: fromName, from: from, authType: authType(auth), encryption: encryptionType(encryption)} return &ans } @@ -50,7 +64,7 @@ func (o *SmtpMail) Send(toName string, to string, subject string, content string server.Authentication = o.authType server.Username = o.username server.Password = o.password - server.Encryption = mail.EncryptionSTARTTLS + server.Encryption = o.encryption server.KeepAlive = false server.ConnectTimeout = 10 * time.Second server.SendTimeout = 10 * time.Second diff --git a/go.mod b/go.mod index 6cacd1e..dfe3c40 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,7 @@ require ( github.com/sendgrid/sendgrid-go v3.10.0+incompatible github.com/skip2/go-qrcode v0.0.0-20191027152451-9434209cb086 github.com/xhit/go-simple-mail/v2 v2.10.0 + golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e //golang.zx2c4.com/wireguard v0.0.20200121 // indirect golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210803171230-4253848d036c gopkg.in/go-playground/assert.v1 v1.2.1 // indirect diff --git a/go.sum b/go.sum index 607f7a1..beffdb5 100644 --- a/go.sum +++ b/go.sum @@ -1,11 +1,7 @@ -github.com/GeertJohan/go.incremental v1.0.0 h1:7AH+pY1XUgQE4Y1HcXYaMqAI0m9yrFqo/jt0CW30vsg= github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= -github.com/GeertJohan/go.rice v1.0.0 h1:KkI6O9uMaQU3VEKaj01ulavtF7o1fWT7+pk/4voiMLQ= -github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= github.com/GeertJohan/go.rice v1.0.2 h1:PtRw+Tg3oa3HYwiDBZyvOJ8LdIyf6lAovJJtr7YOAYk= github.com/GeertJohan/go.rice v1.0.2/go.mod h1:af5vUNlDNkCjOZeSGFgIJxDje9qdjsO6hshx0gTmZt4= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= -github.com/akavel/rsrc v0.8.0 h1:zjWn7ukO9Kc5Q62DOJCcxGpXC18RawVtYAGdz2aLlfw= github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -19,6 +15,7 @@ github.com/coreos/bbolt v1.3.1-coreos.6.0.20180223184059-4f5275f4ebbf/go.mod h1: github.com/daaku/go.zipexe v1.0.0 h1:VSOgZtH418pH9L16hC/JrgSNJbbAL26pj7lmD1+CGdY= github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= @@ -55,7 +52,6 @@ github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/z github.com/jcelliott/lumber v0.0.0-20160324203708-dd349441af25 h1:EFT6MH3igZK/dIVqgGbTqWVvkZ7wJ5iGN03SVtvvdd8= github.com/jcelliott/lumber v0.0.0-20160324203708-dd349441af25/go.mod h1:sWkGw/wsaHtRsT9zGQ/WyJCotGWG/Anow/9hsAcBWRw= github.com/jessevdk/go-flags v0.0.0-20150816100521-1acbbaff2f34/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 h1:uhL5Gw7BINiiPAo24A2sxkcDI0Jt/sqp1v5xQCniEFA= github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= @@ -65,6 +61,7 @@ github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqo github.com/jsimonetti/rtnetlink v0.0.0-20201216134343-bde56ed16391/go.mod h1:cR77jAZG3Y3bsb8hF6fHJbFoyFukLFOkQ98S0pQz3xw= github.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943/go.mod h1:z4c53zj6Eex712ROyh8WI0ihysb5j2ROyV42iNogmAs= github.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXpIyOK59ZnN7J0BV99cZUPmsqDRZ3eq5X+st7u/oSA= +github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b h1:c3NTyLNozICy8B4mlMXemD3z/gXgQzVXZS/HqT+i3do= github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -91,6 +88,7 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43 h1:WgyLFv10Ov49JAQI/ZLUkCZ7VJS3r74hwFIGXJsgZlY= github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo= github.com/mdlayher/genetlink v1.0.0 h1:OoHN1OdyEIkScEmRgxLEe2M9U8ClMytqA5niynLtfj0= github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc= @@ -104,18 +102,18 @@ github.com/mdlayher/netlink v1.2.2-0.20210123213345-5cc92139ae3e/go.mod h1:bacnN github.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuriDdoPSWys= github.com/mdlayher/netlink v1.4.0 h1:n3ARR+Fm0dDv37dj5wSWZXDKcy+U0zwcXS3zKMnSiT0= github.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGkAVrekmf8= +github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws= github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E= -github.com/nkovacs/streamquote v1.0.0 h1:PmVIV08Zlx2lZK5fFZlMZ04eHcDTIFJCv/5/0twVUow= github.com/nkovacs/streamquote v1.0.0/go.mod h1:BN+NaZ2CmdKqUuTUXUEm9j95B2TRbpOWpxbJYzzgUsc= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= @@ -147,6 +145,7 @@ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoH github.com/stretchr/testify v0.0.0-20150929183540-2b15294402a8/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/uber-go/atomic v1.4.0/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g= github.com/uber/jaeger-client-go v2.19.1-0.20191002155754-0be28c34dabf+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= @@ -230,16 +229,20 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190608022120-eacb66d2a7c3/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.zx2c4.com/wireguard v0.0.0-20210427022245-097af6e1351b h1:XDLXhn7ryprJVo+Lpkiib6CIuXE2031GDwtfEm7vLjI= golang.zx2c4.com/wireguard v0.0.0-20210427022245-097af6e1351b/go.mod h1:a057zjmoc00UN7gVkaJt2sXVK523kMJcogDTEvPIasg= golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210803171230-4253848d036c h1:ADNrRDI5NR23/TUCnEmlLZLt4u9DnZ2nwRkPrAcFvto= golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210803171230-4253848d036c/go.mod h1:+1XihzyZUBJcSc5WO9SwNA7v26puQwOEDwanaxfNXPQ= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v9 v9.31.0 h1:bmXmP2RSNtFES+bn4uYuHT7iJFJv7Vj+an+ZQdDaD1M= gopkg.in/go-playground/validator.v9 v9.31.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/handler/routes.go b/handler/routes.go index 6b85e5b..19512c1 100644 --- a/handler/routes.go +++ b/handler/routes.go @@ -51,7 +51,18 @@ func Login(db store.IStore) echo.HandlerFunc { } userCorrect := subtle.ConstantTimeCompare([]byte(user.Username), []byte(dbuser.Username)) == 1 - passwordCorrect := subtle.ConstantTimeCompare([]byte(user.Password), []byte(dbuser.Password)) == 1 + + var passwordCorrect bool + if dbuser.PasswordHash != "" { + match, err := util.VerifyHash(dbuser.PasswordHash, user.Password) + if err != nil { + return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot verify password"}) + } + passwordCorrect = match + } else { + passwordCorrect = subtle.ConstantTimeCompare([]byte(user.Password), []byte(dbuser.Password)) == 1 + } + if userCorrect && passwordCorrect { // TODO: refresh the token sess, _ := session.Get("session", c) diff --git a/main.go b/main.go index b28dd86..84f1b78 100644 --- a/main.go +++ b/main.go @@ -33,6 +33,7 @@ var ( flagSmtpPassword string flagSmtpAuthType string = "None" flagSmtpNoTLSCheck bool = false + flagSmtpEncryption string = "STARTTLS" flagSendgridApiKey string flagEmailFrom string flagEmailFromName string = "WireGuard UI" @@ -57,10 +58,11 @@ func init() { flag.StringVar(&flagBindAddress, "bind-address", util.LookupEnvOrString("BIND_ADDRESS", flagBindAddress), "Address:Port to which the app will be bound.") flag.StringVar(&flagSmtpHostname, "smtp-hostname", util.LookupEnvOrString("SMTP_HOSTNAME", flagSmtpHostname), "SMTP Hostname") flag.IntVar(&flagSmtpPort, "smtp-port", util.LookupEnvOrInt("SMTP_PORT", flagSmtpPort), "SMTP Port") - flag.StringVar(&flagSmtpUsername, "smtp-username", util.LookupEnvOrString("SMTP_USERNAME", flagSmtpUsername), "SMTP Password") + flag.StringVar(&flagSmtpUsername, "smtp-username", util.LookupEnvOrString("SMTP_USERNAME", flagSmtpUsername), "SMTP Username") flag.StringVar(&flagSmtpPassword, "smtp-password", util.LookupEnvOrString("SMTP_PASSWORD", flagSmtpPassword), "SMTP Password") flag.BoolVar(&flagSmtpNoTLSCheck, "smtp-no-tls-check", util.LookupEnvOrBool("SMTP_NO_TLS_CHECK", flagSmtpNoTLSCheck), "Disable TLS verification for SMTP. This is potentially dangerous.") - flag.StringVar(&flagSmtpAuthType, "smtp-auth-type", util.LookupEnvOrString("SMTP_AUTH_TYPE", flagSmtpAuthType), "SMTP Auth Type : Plain or None.") + flag.StringVar(&flagSmtpEncryption, "smtp-encryption", util.LookupEnvOrString("SMTP_ENCRYPTION", flagSmtpEncryption), "SMTP Encryption : SSL, SSLTLS, TLS or STARTTLS (by default)") + flag.StringVar(&flagSmtpAuthType, "smtp-auth-type", util.LookupEnvOrString("SMTP_AUTH_TYPE", flagSmtpAuthType), "SMTP Auth Type : Plain, Login or None.") flag.StringVar(&flagSendgridApiKey, "sendgrid-api-key", util.LookupEnvOrString("SENDGRID_API_KEY", flagSendgridApiKey), "Your sendgrid api key.") flag.StringVar(&flagEmailFrom, "email-from", util.LookupEnvOrString("EMAIL_FROM_ADDRESS", flagEmailFrom), "'From' email address.") flag.StringVar(&flagEmailFromName, "email-from-name", util.LookupEnvOrString("EMAIL_FROM_NAME", flagEmailFromName), "'From' email name.") @@ -78,6 +80,7 @@ func init() { util.SmtpPassword = flagSmtpPassword util.SmtpAuthType = flagSmtpAuthType util.SmtpNoTLSCheck = flagSmtpNoTLSCheck + util.SmtpEncryption = flagSmtpEncryption util.SendgridApiKey = flagSendgridApiKey util.EmailFrom = flagEmailFrom util.EmailFromName = flagEmailFromName @@ -138,7 +141,7 @@ func main() { if util.SendgridApiKey != "" { sendmail = emailer.NewSendgridApiMail(util.SendgridApiKey, util.EmailFromName, util.EmailFrom) } else { - sendmail = emailer.NewSmtpMail(util.SmtpHostname, util.SmtpPort, util.SmtpUsername, util.SmtpPassword, util.SmtpNoTLSCheck, util.SmtpAuthType, util.EmailFromName, util.EmailFrom) + sendmail = emailer.NewSmtpMail(util.SmtpHostname, util.SmtpPort, util.SmtpUsername, util.SmtpPassword, util.SmtpNoTLSCheck, util.SmtpAuthType, util.EmailFromName, util.EmailFrom, util.SmtpEncryption) } app.GET(util.BasePath+"/_health", handler.Health()) diff --git a/model/user.go b/model/user.go index 24a7e53..711ebd1 100644 --- a/model/user.go +++ b/model/user.go @@ -4,4 +4,6 @@ package model type User struct { Username string `json:"username"` Password string `json:"password"` + // PasswordHash takes precedence over Password. + PasswordHash string `json:"password_hash"` } diff --git a/store/jsondb/jsondb.go b/store/jsondb/jsondb.go index 755145b..285bc19 100644 --- a/store/jsondb/jsondb.go +++ b/store/jsondb/jsondb.go @@ -102,7 +102,15 @@ func (o *JsonDB) Init() error { if _, err := os.Stat(userPath); os.IsNotExist(err) { user := new(model.User) user.Username = util.LookupEnvOrString(util.UsernameEnvVar, util.DefaultUsername) - user.Password = util.LookupEnvOrString(util.PasswordEnvVar, util.DefaultPassword) + user.PasswordHash = util.LookupEnvOrString(util.PasswordHashEnvVar, "") + if user.PasswordHash == "" { + plaintext := util.LookupEnvOrString(util.PasswordEnvVar, util.DefaultPassword) + hash, err := util.HashPassword(plaintext) + if err != nil { + return err + } + user.PasswordHash = hash + } o.conn.Write("server", "users", user) } diff --git a/templates/global_settings.html b/templates/global_settings.html index 0288306..1c01438 100644 --- a/templates/global_settings.html +++ b/templates/global_settings.html @@ -91,9 +91,9 @@ Global Settings
2. DNS Servers
The DNS servers will be set to client config.
3. MTU
-
The MTU will be set to server config. By default it is 1420. You might want +
The MTU will be set to server and client config. By default it is 1420. You might want to adjust the MTU size if your connection (e.g PPPoE, 3G, satellite network, etc) has a low MTU.
-
Leave blank to omit this setting in the Server config.
+
Leave blank to omit this setting in the configs.
4. Persistent Keepalive
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 diff --git a/templates/wake_on_lan_hosts.html b/templates/wake_on_lan_hosts.html index c949f96..80ba3f6 100644 --- a/templates/wake_on_lan_hosts.html +++ b/templates/wake_on_lan_hosts.html @@ -103,7 +103,7 @@ {{ if .LatestUsed }} - {{ .LatestUsed }} + {{ .LatestUsed.Format "2006-01-02T15:04:05Z07:00"}} {{ else }} Unused {{ end }} diff --git a/util/config.go b/util/config.go index f5967eb..6a08904 100644 --- a/util/config.go +++ b/util/config.go @@ -11,6 +11,7 @@ var ( SmtpUsername string SmtpPassword string SmtpNoTLSCheck bool + SmtpEncryption string SmtpAuthType string SendgridApiKey string EmailFrom string @@ -34,6 +35,7 @@ const ( DefaultConfigFilePath = "/etc/wireguard/wg0.conf" UsernameEnvVar = "WGUI_USERNAME" PasswordEnvVar = "WGUI_PASSWORD" + PasswordHashEnvVar = "WGUI_PASSWORD_HASH" EndpointAddressEnvVar = "WGUI_ENDPOINT_ADDRESS" DNSEnvVar = "WGUI_DNS" MTUEnvVar = "WGUI_MTU" diff --git a/util/hash.go b/util/hash.go new file mode 100644 index 0000000..0ee0ec9 --- /dev/null +++ b/util/hash.go @@ -0,0 +1,30 @@ +package util + +import ( + "encoding/base64" + "fmt" + "golang.org/x/crypto/bcrypt" +) + +func HashPassword(plaintext string) (string, error) { + bytes, err := bcrypt.GenerateFromPassword([]byte(plaintext), 14) + if err != nil { + return "", fmt.Errorf("cannot hash password: %w", err) + } + return base64.StdEncoding.EncodeToString(bytes), nil +} + +func VerifyHash(base64Hash string, plaintext string) (bool, error) { + hash, err := base64.StdEncoding.DecodeString(base64Hash) + if err != nil { + return false, fmt.Errorf("cannot decode base64 hash: %w", err) + } + err = bcrypt.CompareHashAndPassword(hash, []byte(plaintext)) + if err == bcrypt.ErrMismatchedHashAndPassword { + return false, nil + } + if err != nil { + return false, fmt.Errorf("cannot verify password: %w", err) + } + return true, nil +} diff --git a/util/util.go b/util/util.go index 9e67f9e..8826ee6 100644 --- a/util/util.go +++ b/util/util.go @@ -28,6 +28,11 @@ func BuildClientConfig(client model.Client, server model.Server, setting model.G if client.UseServerDNS { clientDNS = fmt.Sprintf("DNS = %s\n", strings.Join(setting.DNSServers, ",")) } + clientMTU := "" + if setting.MTU > 0 { + clientMTU = fmt.Sprintf("MTU = %d\n", setting.MTU) + } + clientPostUp := "" if strings.TrimSpace(client.PostUp) != "" { clientPostUp = fmt.Sprintf("PostUp = %s\n", client.PostUp) @@ -74,6 +79,7 @@ func BuildClientConfig(client model.Client, server model.Server, setting model.G clientAddress + clientPrivateKey + clientDNS + + clientMTU + forwardMark + clientPostUp + clientPostDown +