diff --git a/handler/routes.go b/handler/routes.go index 75a6eea..4dc95c6 100644 --- a/handler/routes.go +++ b/handler/routes.go @@ -75,7 +75,8 @@ func Login(db store.IStore) echo.HandlerFunc { dbuser, err := db.GetUserByName(username) if err != nil { - return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot query user from DB"}) + log.Infof("Cannot query user %s from DB", username) + return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Invalid credentials"}) } userCorrect := subtle.ConstantTimeCompare([]byte(username), []byte(dbuser.Username)) == 1 @@ -173,7 +174,7 @@ func Logout() echo.HandlerFunc { } // LoadProfile to load user information -func LoadProfile(db store.IStore) echo.HandlerFunc { +func LoadProfile() echo.HandlerFunc { return func(c echo.Context) error { return c.Render(http.StatusOK, "profile.html", map[string]interface{}{ "baseData": model.BaseData{Active: "profile", CurrentUser: currentUser(c), Admin: isAdmin(c)}, @@ -182,7 +183,7 @@ func LoadProfile(db store.IStore) echo.HandlerFunc { } // UsersSettings handler -func UsersSettings(db store.IStore) echo.HandlerFunc { +func UsersSettings() echo.HandlerFunc { return func(c echo.Context) error { return c.Render(http.StatusOK, "users_settings.html", map[string]interface{}{ "baseData": model.BaseData{Active: "users-settings", CurrentUser: currentUser(c), Admin: isAdmin(c)}, diff --git a/main.go b/main.go index a93357c..e11cf29 100644 --- a/main.go +++ b/main.go @@ -31,23 +31,23 @@ var ( gitRef = "N/A" buildTime = fmt.Sprintf(time.Now().UTC().Format("01-02-2006 15:04:05")) // configuration variables - flagDisableLogin bool = false - flagBindAddress string = "0.0.0.0:5000" - flagSmtpHostname string = "127.0.0.1" - flagSmtpPort int = 25 + flagDisableLogin = false + flagBindAddress = "0.0.0.0:5000" + flagSmtpHostname = "127.0.0.1" + flagSmtpPort = 25 flagSmtpUsername string flagSmtpPassword string - flagSmtpAuthType string = "NONE" - flagSmtpNoTLSCheck bool = false - flagSmtpEncryption string = "STARTTLS" - flagSmtpHelo string = "localhost" + flagSmtpAuthType = "NONE" + flagSmtpNoTLSCheck = false + flagSmtpEncryption = "STARTTLS" + flagSmtpHelo = "localhost" flagSendgridApiKey string flagEmailFrom string - flagEmailFromName string = "WireGuard UI" + flagEmailFromName = "WireGuard UI" flagTelegramToken string - flagTelegramAllowConfRequest bool = false - flagTelegramFloodWait int = 60 - flagSessionSecret string = util.RandomString(32) + flagTelegramAllowConfRequest = false + flagTelegramFloodWait = 60 + flagSessionSecret = util.RandomString(32) flagWgConfTemplate string flagBasePath string flagSubnetRanges string @@ -94,9 +94,9 @@ func init() { flag.StringVar(&flagSubnetRanges, "subnet-ranges", util.LookupEnvOrString("SUBNET_RANGES", flagSubnetRanges), "IP ranges to choose from when assigning an IP for a client.") var ( - smtpPasswordLookup = util.LookupEnvOrString("SMTP_PASSWORD", flagSmtpPassword) - sengridApiKeyLookup = util.LookupEnvOrString("SENDGRID_API_KEY", flagSendgridApiKey) - sessionSecretLookup = util.LookupEnvOrString("SESSION_SECRET", flagSessionSecret) + smtpPasswordLookup = util.LookupEnvOrString("SMTP_PASSWORD", flagSmtpPassword) + sendgridApiKeyLookup = util.LookupEnvOrString("SENDGRID_API_KEY", flagSendgridApiKey) + sessionSecretLookup = util.LookupEnvOrString("SESSION_SECRET", flagSessionSecret) ) // check empty smtpPassword env var @@ -106,9 +106,9 @@ func init() { flag.StringVar(&flagSmtpPassword, "smtp-password", util.LookupEnvOrFile("SMTP_PASSWORD_FILE", flagSmtpPassword), "SMTP Password File") } - // check empty sengridApiKey env var - if sengridApiKeyLookup != "" { - flag.StringVar(&flagSendgridApiKey, "sendgrid-api-key", sengridApiKeyLookup, "Your sendgrid api key.") + // check empty sendgridApiKey env var + if sendgridApiKeyLookup != "" { + flag.StringVar(&flagSendgridApiKey, "sendgrid-api-key", sendgridApiKeyLookup, "Your sendgrid api key.") } else { flag.StringVar(&flagSendgridApiKey, "sendgrid-api-key", util.LookupEnvOrFile("SENDGRID_API_KEY_FILE", flagSendgridApiKey), "File containing your sendgrid api key.") } @@ -215,12 +215,12 @@ func main() { app.GET(util.BasePath+"/login", handler.LoginPage()) app.POST(util.BasePath+"/login", handler.Login(db), handler.ContentTypeJson) app.GET(util.BasePath+"/logout", handler.Logout(), handler.ValidSession) - app.GET(util.BasePath+"/profile", handler.LoadProfile(db), handler.ValidSession) - app.GET(util.BasePath+"/users-settings", handler.UsersSettings(db), handler.ValidSession, handler.NeedsAdmin) + app.GET(util.BasePath+"/profile", handler.LoadProfile(), handler.ValidSession) + app.GET(util.BasePath+"/users-settings", handler.UsersSettings(), handler.ValidSession, handler.NeedsAdmin) app.POST(util.BasePath+"/update-user", handler.UpdateUser(db), handler.ValidSession, handler.ContentTypeJson) app.POST(util.BasePath+"/create-user", handler.CreateUser(db), handler.ValidSession, handler.ContentTypeJson, handler.NeedsAdmin) app.POST(util.BasePath+"/remove-user", handler.RemoveUser(db), handler.ValidSession, handler.ContentTypeJson, handler.NeedsAdmin) - app.GET(util.BasePath+"/getusers", handler.GetUsers(db), handler.ValidSession, handler.NeedsAdmin) + app.GET(util.BasePath+"/get-users", handler.GetUsers(db), handler.ValidSession, handler.NeedsAdmin) app.GET(util.BasePath+"/api/user/:username", handler.GetUser(db), handler.ValidSession) } @@ -276,10 +276,13 @@ func main() { if strings.HasPrefix(util.BindAddress, "unix://") { // Listen on unix domain socket. // https://github.com/labstack/echo/issues/830 - syscall.Unlink(util.BindAddress[6:]) + err := syscall.Unlink(util.BindAddress[6:]) + if err != nil { + app.Logger.Fatalf("Cannot unlink unix socket: Error: %v", err) + } l, err := net.Listen("unix", util.BindAddress[6:]) if err != nil { - app.Logger.Fatal(err) + app.Logger.Fatalf("Cannot create unix socket. Error: %v", err) } app.Listener = l app.Logger.Fatal(app.Start("")) @@ -292,7 +295,7 @@ func main() { func initServerConfig(db store.IStore, tmplDir fs.FS) { settings, err := db.GetGlobalSettings() if err != nil { - log.Fatalf("Cannot get global settings: ", err) + log.Fatalf("Cannot get global settings: %v", err) } if _, err := os.Stat(settings.ConfigFilePath); err == nil { @@ -302,23 +305,23 @@ func initServerConfig(db store.IStore, tmplDir fs.FS) { server, err := db.GetServer() if err != nil { - log.Fatalf("Cannot get server config: ", err) + log.Fatalf("Cannot get server config: %v", err) } clients, err := db.GetClients(false) if err != nil { - log.Fatalf("Cannot get client config: ", err) + log.Fatalf("Cannot get client config: %v", err) } users, err := db.GetUsers() if err != nil { - log.Fatalf("Cannot get user config: ", err) + log.Fatalf("Cannot get user config: %v", err) } // write config file err = util.WriteWireGuardServerConfig(tmplDir, server, clients, users, settings) if err != nil { - log.Fatalf("Cannot create server config: ", err) + log.Fatalf("Cannot create server config: %v", err) } } diff --git a/store/jsondb/jsondb.go b/store/jsondb/jsondb.go index 03b5b62..8b5f84e 100644 --- a/store/jsondb/jsondb.go +++ b/store/jsondb/jsondb.go @@ -37,14 +37,14 @@ func New(dbPath string) (*JsonDB, error) { } func (o *JsonDB) Init() error { - var clientPath string = path.Join(o.dbPath, "clients") - var serverPath string = path.Join(o.dbPath, "server") - var userPath string = path.Join(o.dbPath, "users") - var wakeOnLanHostsPath string = path.Join(o.dbPath, "wake_on_lan_hosts") - 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 hashesPath string = path.Join(serverPath, "hashes.json") + var clientPath = path.Join(o.dbPath, "clients") + var serverPath = path.Join(o.dbPath, "server") + var userPath = path.Join(o.dbPath, "users") + var wakeOnLanHostsPath = path.Join(o.dbPath, "wake_on_lan_hosts") + var serverInterfacePath = path.Join(serverPath, "interfaces.json") + var serverKeyPairPath = path.Join(serverPath, "keypair.json") + var globalSettingPath = path.Join(serverPath, "global_settings.json") + var hashesPath = path.Join(serverPath, "hashes.json") // create directories if they do not exist if _, err := os.Stat(clientPath); os.IsNotExist(err) { @@ -189,7 +189,7 @@ func (o *JsonDB) GetUsers() ([]model.User, error) { for _, i := range results { user := model.User{} - if err := json.Unmarshal([]byte(i), &user); err != nil { + if err := json.Unmarshal(i, &user); err != nil { return users, fmt.Errorf("cannot decode user json structure: %v", err) } users = append(users, user) @@ -267,7 +267,7 @@ func (o *JsonDB) GetClients(hasQRCode bool) ([]model.ClientData, error) { clientData := model.ClientData{} // get client info - if err := json.Unmarshal([]byte(f), &client); err != nil { + if err := json.Unmarshal(f, &client); err != nil { return clients, fmt.Errorf("cannot decode client json structure: %v", err) } @@ -278,7 +278,7 @@ func (o *JsonDB) GetClients(hasQRCode bool) ([]model.ClientData, error) { png, err := qrcode.Encode(util.BuildClientConfig(client, server, globalSettings), qrcode.Medium, 256) if err == nil { - clientData.QRCode = "data:image/png;base64," + base64.StdEncoding.EncodeToString([]byte(png)) + clientData.QRCode = "data:image/png;base64," + base64.StdEncoding.EncodeToString(png) } else { fmt.Print("Cannot generate QR code: ", err) } @@ -315,7 +315,7 @@ func (o *JsonDB) GetClientByID(clientID string, qrCodeSettings model.QRCodeSetti png, err := qrcode.Encode(util.BuildClientConfig(client, server, globalSettings), qrcode.Medium, 256) if err == nil { - clientData.QRCode = "data:image/png;base64," + base64.StdEncoding.EncodeToString([]byte(png)) + clientData.QRCode = "data:image/png;base64," + base64.StdEncoding.EncodeToString(png) } else { fmt.Print("Cannot generate QR code: ", err) } diff --git a/store/jsondb/jsondb_wake_on_lan.go b/store/jsondb/jsondb_wake_on_lan.go index 661ba05..bf43fcf 100644 --- a/store/jsondb/jsondb_wake_on_lan.go +++ b/store/jsondb/jsondb_wake_on_lan.go @@ -23,7 +23,7 @@ func (o *JsonDB) GetWakeOnLanHosts() ([]model.WakeOnLanHost, error) { host := model.WakeOnLanHost{} // get client info - if err := json.Unmarshal([]byte(f), &host); err != nil { + if err := json.Unmarshal(f, &host); err != nil { return hosts, fmt.Errorf("cannot decode client json structure: %v", err) } diff --git a/telegram/bot.go b/telegram/bot.go index 7e33de7..7842f63 100644 --- a/telegram/bot.go +++ b/telegram/bot.go @@ -26,8 +26,8 @@ var ( Bot *echotron.API BotMutex sync.RWMutex - floodWait = make(map[int64]int64, 0) - floodMessageSent = make(map[int64]struct{}, 0) + floodWait = make(map[int64]int64) + floodMessageSent = make(map[int64]struct{}) ) func Start(initDeps TgBotInitDependencies) (err error) { @@ -84,12 +84,15 @@ func Start(initDeps TgBotInitDependencies) (err error) { continue } floodMessageSent[userid] = struct{}{} - bot.SendMessage( + _, err := bot.SendMessage( fmt.Sprintf("You can only request your configs once per %d minutes", FloodWait), userid, &echotron.MessageOptions{ ReplyToMessageID: update.Message.ID, }) + if err != nil { + log.Errorf("Failed to send telegram message. Error %v", err) + } continue } floodWait[userid] = time.Now().Unix() @@ -100,12 +103,15 @@ func Start(initDeps TgBotInitDependencies) (err error) { for _, f := range failed { messageText += f + "\n" } - bot.SendMessage( + _, err := bot.SendMessage( messageText, userid, &echotron.MessageOptions{ ReplyToMessageID: update.Message.ID, }) + if err != nil { + log.Errorf("Failed to send telegram message. Error %v", err) + } } } } diff --git a/templates/users_settings.html b/templates/users_settings.html index 6fb8d69..11a8ef8 100644 --- a/templates/users_settings.html +++ b/templates/users_settings.html @@ -96,7 +96,7 @@ Users Settings $.ajax({ cache: false, method: 'GET', - url: '{{.basePath}}/getusers', + url: '{{.basePath}}/get-users', dataType: 'json', contentType: "application/json", success: function (data) { diff --git a/util/cache.go b/util/cache.go index 8037c30..b9694b9 100644 --- a/util/cache.go +++ b/util/cache.go @@ -3,5 +3,5 @@ package util import "sync" var IPToSubnetRange = map[string]uint16{} -var TgUseridToClientID = map[int64]([]string){} +var TgUseridToClientID = map[int64][]string{} var TgUseridToClientIDMutex sync.RWMutex diff --git a/util/hash.go b/util/hash.go index 0ee0ec9..2dc6b28 100644 --- a/util/hash.go +++ b/util/hash.go @@ -2,6 +2,7 @@ package util import ( "encoding/base64" + "errors" "fmt" "golang.org/x/crypto/bcrypt" ) @@ -20,7 +21,7 @@ func VerifyHash(base64Hash string, plaintext string) (bool, error) { return false, fmt.Errorf("cannot decode base64 hash: %w", err) } err = bcrypt.CompareHashAndPassword(hash, []byte(plaintext)) - if err == bcrypt.ErrMismatchedHashAndPassword { + if errors.Is(err, bcrypt.ErrMismatchedHashAndPassword) { return false, nil } if err != nil { diff --git a/util/util.go b/util/util.go index 337745a..88b7089 100644 --- a/util/util.go +++ b/util/util.go @@ -7,7 +7,6 @@ import ( "fmt" "io" "io/fs" - "io/ioutil" "math/rand" "net" "os" @@ -189,7 +188,7 @@ func GetInterfaceIPs() ([]model.Interface, error) { return nil, err } - var interfaceList = []model.Interface{} + var interfaceList []model.Interface // get interface's ip addresses for _, i := range ifaces { @@ -230,9 +229,9 @@ func GetPublicIP() (model.Interface, error) { consensus := externalip.NewConsensus(&cfg, nil) // add trusted voters - consensus.AddVoter(externalip.NewHTTPSource("http://checkip.amazonaws.com/"), 1) + consensus.AddVoter(externalip.NewHTTPSource("https://checkip.amazonaws.com/"), 1) consensus.AddVoter(externalip.NewHTTPSource("http://whatismyip.akamai.com"), 1) - consensus.AddVoter(externalip.NewHTTPSource("http://ifconfig.top"), 1) + consensus.AddVoter(externalip.NewHTTPSource("https://ifconfig.top"), 1) publicInterface := model.Interface{} publicInterface.Name = "Public Address" @@ -244,7 +243,7 @@ func GetPublicIP() (model.Interface, error) { publicInterface.IPAddress = ip.String() } - // error handling happend above, no need to pass it through + // error handling happened above, no need to pass it through return publicInterface, nil } @@ -292,7 +291,7 @@ func GetAllocatedIPs(ignoreClientID string) ([]string, error) { // append client's addresses to the result for _, f := range records { client := model.Client{} - if err := json.Unmarshal([]byte(f), &client); err != nil { + if err := json.Unmarshal(f, &client); err != nil { return nil, err } @@ -336,15 +335,15 @@ func GetBroadcastIP(n *net.IPNet) net.IP { // GetBroadcastAndNetworkAddrsLookup get the ip address that can't be used with current server interfaces func GetBroadcastAndNetworkAddrsLookup(interfaceAddresses []string) map[string]bool { - list := make(map[string]bool, 0) + list := make(map[string]bool) for _, ifa := range interfaceAddresses { - _, net, err := net.ParseCIDR(ifa) + _, netAddr, err := net.ParseCIDR(ifa) if err != nil { continue } - broadcastAddr := GetBroadcastIP(net).String() - networkAddr := net.IP.String() + broadcastAddr := GetBroadcastIP(netAddr).String() + networkAddr := netAddr.IP.String() list[broadcastAddr] = true list[networkAddr] = true } @@ -354,14 +353,14 @@ func GetBroadcastAndNetworkAddrsLookup(interfaceAddresses []string) map[string]b // GetAvailableIP get the ip address that can be allocated from an CIDR // We need interfaceAddresses to find real broadcast and network addresses func GetAvailableIP(cidr string, allocatedList, interfaceAddresses []string) (string, error) { - ip, net, err := net.ParseCIDR(cidr) + ip, netAddr, err := net.ParseCIDR(cidr) if err != nil { return "", err } unavailableIPs := GetBroadcastAndNetworkAddrsLookup(interfaceAddresses) - for ip := ip.Mask(net.Mask); net.Contains(ip); inc(ip) { + for ip := ip.Mask(netAddr.Mask); netAddr.Contains(ip); inc(ip) { available := true suggestedAddr := ip.String() for _, allocatedAddr := range allocatedList { @@ -386,7 +385,7 @@ func ValidateIPAllocation(serverAddresses []string, ipAllocatedList []string, ip // clientCIDR must be in CIDR format if ip == nil { - return false, fmt.Errorf("Invalid ip allocation input %s. Must be in CIDR format", clientCIDR) + return false, fmt.Errorf("invalid ip allocation input %s. Must be in CIDR format", clientCIDR) } // return false immediately if the ip is already in use (in ipAllocatedList) @@ -398,7 +397,7 @@ func ValidateIPAllocation(serverAddresses []string, ipAllocatedList []string, ip // even if it is not in use, we still need to check if it // belongs to a network of the server. - var isValid bool = false + var isValid = false for _, serverCIDR := range serverAddresses { _, serverNet, _ := net.ParseCIDR(serverCIDR) if serverNet.Contains(ip) { @@ -437,7 +436,7 @@ func findSubnetRangeForIP(cidr string) (uint16, error) { } } } - return 0, fmt.Errorf("Subnet range not found for this IP") + return 0, fmt.Errorf("subnet range not found for this IP") } // FillClientSubnetRange to fill subnet ranges client belongs to, does nothing if SRs are not found @@ -470,11 +469,11 @@ func ValidateAndFixSubnetRanges(db store.IStore) error { var serverSubnets []*net.IPNet for _, addr := range server.Interface.Addresses { addr = strings.TrimSpace(addr) - _, net, err := net.ParseCIDR(addr) + _, netAddr, err := net.ParseCIDR(addr) if err != nil { return err } - serverSubnets = append(serverSubnets, net) + serverSubnets = append(serverSubnets, netAddr) } for _, rng := range SubnetRangesOrder { @@ -544,7 +543,7 @@ func WriteWireGuardServerConfig(tmplDir fs.FS, serverConfig model.Server, client // if set, read wg.conf template from WgConfTemplate if len(WgConfTemplate) > 0 { - fileContentBytes, err := ioutil.ReadFile(WgConfTemplate) + fileContentBytes, err := os.ReadFile(WgConfTemplate) if err != nil { return err }