• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

DigitalTolk / wireguard-ui / 24836418035

23 Apr 2026 12:55PM UTC coverage: 82.477% (+1.4%) from 81.067%
24836418035

push

github

web-flow
Fixes (#11)

* Fixes

* bump

441 of 558 branches covered (79.03%)

Branch coverage included in aggregate %.

447 of 574 new or added lines in 20 files covered. (77.87%)

9 existing lines in 2 files now uncovered.

2882 of 3471 relevant lines covered (83.03%)

13.86 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

73.91
/handler/api_v1_server.go
1
package handler
2

3
import (
4
        "net/http"
5
        "strings"
6
        "time"
7

8
        "github.com/labstack/echo/v4"
9
        "github.com/labstack/gommon/log"
10
        "golang.zx2c4.com/wireguard/wgctrl/wgtypes"
11

12
        "github.com/DigitalTolk/wireguard-ui/model"
13
        "github.com/DigitalTolk/wireguard-ui/store"
14
        "github.com/DigitalTolk/wireguard-ui/util"
15
)
16

17
// APIGetServer returns server config (interface + keypair)
18
func APIGetServer(db store.IStore) echo.HandlerFunc {
1✔
19
        return func(c echo.Context) error {
2✔
20
                server, err := db.GetServer()
1✔
21
                if err != nil {
1✔
22
                        return apiInternalError(c, "Cannot get server config")
×
23
                }
×
24
                return c.JSON(http.StatusOK, server)
1✔
25
        }
26
}
27

28
// APIUpdateServerInterface updates server interface settings
29
func APIUpdateServerInterface(db store.IStore) echo.HandlerFunc {
4✔
30
        return func(c echo.Context) error {
8✔
31
                var serverInterface model.ServerInterface
4✔
32
                if err := c.Bind(&serverInterface); err != nil {
5✔
33
                        return apiBadRequest(c, "Invalid request body")
1✔
34
                }
1✔
35

36
                if !util.ValidateServerAddresses(serverInterface.Addresses) {
4✔
37
                        return apiBadRequest(c, "Interface IP address must be in CIDR format")
1✔
38
                }
1✔
39

40
                if serverInterface.ListenPort < 1 || serverInterface.ListenPort > 65535 {
2✔
NEW
41
                        return apiBadRequest(c, "Listen port must be between 1 and 65535")
×
NEW
42
                }
×
43

44
                oldServer, beforeErr := db.GetServer()
2✔
45
                if beforeErr != nil {
2✔
NEW
46
                        log.Warnf("Cannot capture before-state for audit: %v", beforeErr)
×
NEW
47
                }
×
48

49
                serverInterface.UpdatedAt = time.Now().UTC()
2✔
50

2✔
51
                if err := db.SaveServerInterface(serverInterface); err != nil {
2✔
52
                        return apiInternalError(c, "Cannot save server interface")
×
53
                }
×
54

55
                log.Infof("Updated server interfaces: %v", serverInterface)
2✔
56
                auditLogEvent(c, "server.interface.update", "server", "interface", map[string]interface{}{
2✔
57
                        "before": oldServer.Interface,
2✔
58
                        "after":  serverInterface,
2✔
59
                })
2✔
60
                return c.JSON(http.StatusOK, serverInterface)
2✔
61
        }
62
}
63

64
// APIRegenerateServerKeypair generates a new server keypair
65
func APIRegenerateServerKeypair(db store.IStore) echo.HandlerFunc {
1✔
66
        return func(c echo.Context) error {
2✔
67
                key, err := wgtypes.GeneratePrivateKey()
1✔
68
                if err != nil {
1✔
69
                        return apiInternalError(c, "Cannot generate WireGuard key pair")
×
70
                }
×
71

72
                kp := model.ServerKeypair{
1✔
73
                        PrivateKey: key.String(),
1✔
74
                        PublicKey:  key.PublicKey().String(),
1✔
75
                        UpdatedAt:  time.Now().UTC(),
1✔
76
                }
1✔
77

1✔
78
                if err := db.SaveServerKeyPair(kp); err != nil {
1✔
79
                        return apiInternalError(c, "Cannot save server keypair")
×
80
                }
×
81

82
                log.Infof("Regenerated server keypair")
1✔
83
                auditLogEvent(c, "server.keypair.regenerate", "server", "keypair", nil)
1✔
84
                return c.JSON(http.StatusOK, kp)
1✔
85
        }
86
}
87

88
// APIGetSettings returns global settings
89
func APIGetSettings(db store.IStore) echo.HandlerFunc {
1✔
90
        return func(c echo.Context) error {
2✔
91
                settings, err := db.GetGlobalSettings()
1✔
92
                if err != nil {
1✔
93
                        return apiInternalError(c, "Cannot get global settings")
×
94
                }
×
95
                return c.JSON(http.StatusOK, settings)
1✔
96
        }
97
}
98

99
// APIUpdateSettings updates global settings
100
func APIUpdateSettings(db store.IStore) echo.HandlerFunc {
4✔
101
        return func(c echo.Context) error {
8✔
102
                var settings model.GlobalSetting
4✔
103
                if err := c.Bind(&settings); err != nil {
5✔
104
                        return apiBadRequest(c, "Invalid request body")
1✔
105
                }
1✔
106

107
                if !util.ValidateIPAddressList(settings.DNSServers) {
4✔
108
                        return apiBadRequest(c, "Invalid DNS server address")
1✔
109
                }
1✔
110

111
                if settings.MTU != 0 && (settings.MTU < 1280 || settings.MTU > 9000) {
2✔
NEW
112
                        return apiBadRequest(c, "MTU must be 0 (to omit) or between 1280 and 9000")
×
NEW
113
                }
×
114

115
                if settings.PersistentKeepalive < 0 || settings.PersistentKeepalive > 65535 {
2✔
NEW
116
                        return apiBadRequest(c, "Persistent keepalive must be between 0 and 65535")
×
NEW
117
                }
×
118

119
                if settings.ConfigFilePath != "" && !strings.HasPrefix(settings.ConfigFilePath, "/") {
2✔
NEW
120
                        return apiBadRequest(c, "Config file path must be an absolute path starting with /")
×
NEW
121
                }
×
122

123
                oldSettings, beforeErr := db.GetGlobalSettings()
2✔
124
                if beforeErr != nil {
2✔
NEW
125
                        log.Warnf("Cannot capture before-state for audit: %v", beforeErr)
×
NEW
126
                }
×
127

128
                settings.UpdatedAt = time.Now().UTC()
2✔
129

2✔
130
                if err := db.SaveGlobalSettings(settings); err != nil {
2✔
131
                        return apiInternalError(c, "Cannot save global settings")
×
132
                }
×
133

134
                log.Infof("Updated global settings")
2✔
135
                auditLogEvent(c, "settings.update", "settings", "global", map[string]interface{}{
2✔
136
                        "before": oldSettings,
2✔
137
                        "after":  settings,
2✔
138
                })
2✔
139
                return c.JSON(http.StatusOK, settings)
2✔
140
        }
141
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc