wg-portal/internal/server/handlers.go

391 lines
10 KiB
Go
Raw Normal View History

2020-11-05 13:37:51 -05:00
package server
import (
"net/http"
2020-11-07 04:31:48 -05:00
"net/url"
2020-11-05 13:37:51 -05:00
"strconv"
2020-11-07 04:31:48 -05:00
"strings"
"time"
2020-11-05 13:37:51 -05:00
2020-11-07 05:47:52 -05:00
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
2020-11-05 13:37:51 -05:00
"github.com/gin-gonic/gin"
)
func (s *Server) GetIndex(c *gin.Context) {
c.HTML(http.StatusOK, "index.html", gin.H{
"route": c.Request.URL.Path,
"session": s.getSessionData(c),
"static": s.getStaticData(),
})
}
func (s *Server) HandleError(c *gin.Context, code int, message, details string) {
// TODO: if json
//c.JSON(code, gin.H{"error": message, "details": details})
c.HTML(code, "error.html", gin.H{
"data": gin.H{
"Code": strconv.Itoa(code),
"Message": message,
"Details": details,
},
"route": c.Request.URL.Path,
"session": s.getSessionData(c),
"static": s.getStaticData(),
})
}
func (s *Server) GetAdminIndex(c *gin.Context) {
2020-11-07 04:31:48 -05:00
device := s.users.GetDevice()
users := s.users.GetAllUsers()
c.HTML(http.StatusOK, "admin_index.html", struct {
Route string
Session SessionData
Static StaticData
Peers []User
Device Device
}{
Route: c.Request.URL.Path,
Session: s.getSessionData(c),
Static: s.getStaticData(),
Peers: users,
Device: device,
})
}
func (s *Server) GetAdminEditInterface(c *gin.Context) {
device := s.users.GetDevice()
users := s.users.GetAllUsers()
c.HTML(http.StatusOK, "admin_edit_interface.html", struct {
Route string
Alerts AlertData
Session SessionData
Static StaticData
Peers []User
Device Device
}{
Route: c.Request.URL.Path,
Alerts: s.getAlertData(c),
Session: s.getSessionData(c),
Static: s.getStaticData(),
Peers: users,
Device: device,
})
}
func (s *Server) PostAdminEditInterface(c *gin.Context) {
device := s.users.GetDevice()
var err error
device.ListenPort, err = strconv.Atoi(c.PostForm("port"))
2020-11-05 13:37:51 -05:00
if err != nil {
2020-11-07 04:31:48 -05:00
s.setAlert(c, "invalid port: "+err.Error(), "danger")
c.Redirect(http.StatusSeeOther, "/admin/device/edit")
2020-11-05 13:37:51 -05:00
return
}
2020-11-07 04:31:48 -05:00
ipField := c.PostForm("ip")
ips := strings.Split(ipField, ",")
validatedIPs := make([]string, 0, len(ips))
for i := range ips {
ips[i] = strings.TrimSpace(ips[i])
if ips[i] != "" {
validatedIPs = append(validatedIPs, ips[i])
}
}
if len(validatedIPs) == 0 {
s.setAlert(c, "invalid ip address", "danger")
c.Redirect(http.StatusSeeOther, "/admin/device/edit")
return
}
device.IPs = validatedIPs
device.Endpoint = c.PostForm("endpoint")
dnsField := c.PostForm("dns")
dns := strings.Split(dnsField, ",")
validatedDNS := make([]string, 0, len(dns))
for i := range dns {
dns[i] = strings.TrimSpace(dns[i])
if dns[i] != "" {
validatedDNS = append(validatedDNS, dns[i])
}
}
device.DNS = validatedDNS
allowedIPField := c.PostForm("allowedip")
allowedIP := strings.Split(allowedIPField, ",")
validatedAllowedIP := make([]string, 0, len(allowedIP))
for i := range allowedIP {
allowedIP[i] = strings.TrimSpace(allowedIP[i])
if allowedIP[i] != "" {
validatedAllowedIP = append(validatedAllowedIP, allowedIP[i])
}
}
device.AllowedIPs = validatedAllowedIP
device.Mtu, err = strconv.Atoi(c.PostForm("mtu"))
if err != nil {
s.setAlert(c, "invalid MTU: "+err.Error(), "danger")
c.Redirect(http.StatusSeeOther, "/admin/device/edit")
return
}
device.PersistentKeepalive, err = strconv.Atoi(c.PostForm("keepalive"))
2020-11-05 13:37:51 -05:00
if err != nil {
2020-11-07 04:31:48 -05:00
s.setAlert(c, "invalid PersistentKeepalive: "+err.Error(), "danger")
c.Redirect(http.StatusSeeOther, "/admin/device/edit")
2020-11-05 13:37:51 -05:00
return
}
2020-11-07 04:31:48 -05:00
// Update WireGuard device
err = s.wg.UpdateDevice(device.DeviceName, device.GetDeviceConfig())
if err != nil {
s.setAlert(c, "failed to update device in WireGuard: "+err.Error(), "danger")
c.Redirect(http.StatusSeeOther, "/admin/device/edit")
return
}
// Update in database
err = s.users.UpdateDevice(device)
if err != nil {
s.setAlert(c, "failed to update device in database: "+err.Error(), "danger")
c.Redirect(http.StatusSeeOther, "/admin/device/edit")
return
}
s.setAlert(c, "changes applied successfully", "success")
c.Redirect(http.StatusSeeOther, "/admin/device/edit")
}
func (s *Server) GetAdminEditPeer(c *gin.Context) {
2020-11-06 06:21:47 -05:00
device := s.users.GetDevice()
2020-11-07 04:31:48 -05:00
user := s.users.GetUserByKey(c.Query("pkey"))
2020-11-06 06:21:47 -05:00
2020-11-07 04:31:48 -05:00
c.HTML(http.StatusOK, "admin_edit_client.html", struct {
Route string
Alerts AlertData
Session SessionData
Static StaticData
Peer User
Device Device
}{
Route: c.Request.URL.Path,
Alerts: s.getAlertData(c),
Session: s.getSessionData(c),
Static: s.getStaticData(),
Peer: user,
Device: device,
})
}
func (s *Server) PostAdminEditPeer(c *gin.Context) {
user := s.users.GetUserByKey(c.Query("pkey"))
urlEncodedKey := url.QueryEscape(c.Query("pkey"))
var err error
user.Identifier = c.PostForm("identifier")
if user.Identifier == "" {
s.setAlert(c, "invalid identifier, must not be empty", "danger")
c.Redirect(http.StatusSeeOther, "/admin/peer/edit?pkey="+urlEncodedKey)
return
2020-11-05 13:37:51 -05:00
}
2020-11-07 04:31:48 -05:00
user.Email = c.PostForm("mail")
if user.Email == "" {
s.setAlert(c, "invalid email, must not be empty", "danger")
c.Redirect(http.StatusSeeOther, "/admin/peer/edit?pkey="+urlEncodedKey)
return
}
ipField := c.PostForm("ip")
ips := strings.Split(ipField, ",")
validatedIPs := make([]string, 0, len(ips))
for i := range ips {
ips[i] = strings.TrimSpace(ips[i])
if ips[i] != "" {
validatedIPs = append(validatedIPs, ips[i])
}
}
if len(validatedIPs) == 0 {
s.setAlert(c, "invalid ip address", "danger")
c.Redirect(http.StatusSeeOther, "/admin/peer/edit?pkey="+urlEncodedKey)
return
}
user.IPs = validatedIPs
allowedIPField := c.PostForm("allowedip")
allowedIP := strings.Split(allowedIPField, ",")
validatedAllowedIP := make([]string, 0, len(allowedIP))
for i := range allowedIP {
allowedIP[i] = strings.TrimSpace(allowedIP[i])
if allowedIP[i] != "" {
validatedAllowedIP = append(validatedAllowedIP, allowedIP[i])
}
}
user.AllowedIPs = validatedAllowedIP
user.IgnorePersistentKeepalive = c.PostForm("ignorekeepalive") != ""
disabled := c.PostForm("isdisabled") != ""
now := time.Now()
if disabled && user.DeactivatedAt == nil {
user.DeactivatedAt = &now
} else if !disabled {
user.DeactivatedAt = nil
}
// Update WireGuard device
if user.DeactivatedAt == &now {
err = s.wg.RemovePeer(user.PublicKey)
if err != nil {
s.setAlert(c, "failed to remove peer in WireGuard: "+err.Error(), "danger")
c.Redirect(http.StatusSeeOther, "/admin/peer/edit?pkey="+urlEncodedKey)
return
}
} else if user.DeactivatedAt == nil && user.Peer != nil {
err = s.wg.UpdatePeer(user.GetPeerConfig())
if err != nil {
s.setAlert(c, "failed to update peer in WireGuard: "+err.Error(), "danger")
c.Redirect(http.StatusSeeOther, "/admin/peer/edit?pkey="+urlEncodedKey)
return
}
} else if user.DeactivatedAt == nil && user.Peer == nil {
err = s.wg.AddPeer(user.GetPeerConfig())
if err != nil {
s.setAlert(c, "failed to add peer in WireGuard: "+err.Error(), "danger")
c.Redirect(http.StatusSeeOther, "/admin/peer/edit?pkey="+urlEncodedKey)
return
}
}
// Update in database
err = s.users.UpdateUser(user)
if err != nil {
s.setAlert(c, "failed to update user in database: "+err.Error(), "danger")
c.Redirect(http.StatusSeeOther, "/admin/peer/edit?pkey="+urlEncodedKey)
return
}
s.setAlert(c, "changes applied successfully", "success")
c.Redirect(http.StatusSeeOther, "/admin/peer/edit?pkey="+urlEncodedKey)
}
func (s *Server) GetAdminCreatePeer(c *gin.Context) {
device := s.users.GetDevice()
2020-11-07 05:47:52 -05:00
user := User{}
user.AllowedIPsStr = device.AllowedIPsStr
user.IPsStr = "" // TODO: add a valid ip here
2020-11-07 04:31:48 -05:00
c.HTML(http.StatusOK, "admin_edit_client.html", struct {
2020-11-06 06:21:47 -05:00
Route string
2020-11-07 04:31:48 -05:00
Alerts AlertData
2020-11-06 06:21:47 -05:00
Session SessionData
Static StaticData
2020-11-07 04:31:48 -05:00
Peer User
2020-11-06 06:21:47 -05:00
Device Device
}{
Route: c.Request.URL.Path,
2020-11-07 04:31:48 -05:00
Alerts: s.getAlertData(c),
2020-11-06 06:21:47 -05:00
Session: s.getSessionData(c),
Static: s.getStaticData(),
2020-11-07 04:31:48 -05:00
Peer: user,
2020-11-06 06:21:47 -05:00
Device: device,
2020-11-05 13:37:51 -05:00
})
}
2020-11-06 06:21:47 -05:00
2020-11-07 04:31:48 -05:00
func (s *Server) PostAdminCreatePeer(c *gin.Context) {
2020-11-07 05:47:52 -05:00
user := User{}
key, err := wgtypes.GeneratePrivateKey()
2020-11-07 04:31:48 -05:00
if err != nil {
2020-11-07 05:47:52 -05:00
s.HandleError(c, http.StatusInternalServerError, "Private key generation error", err.Error())
return
}
user.PrivateKey = key.String()
user.PublicKey = key.PublicKey().String()
user.Identifier = c.PostForm("identifier")
if user.Identifier == "" {
s.setAlert(c, "invalid identifier, must not be empty", "danger")
c.Redirect(http.StatusSeeOther, "/admin/peer/create")
return
}
user.Email = c.PostForm("mail")
if user.Email == "" {
s.setAlert(c, "invalid email, must not be empty", "danger")
c.Redirect(http.StatusSeeOther, "/admin/peer/create")
2020-11-07 04:31:48 -05:00
return
}
ipField := c.PostForm("ip")
ips := strings.Split(ipField, ",")
validatedIPs := make([]string, 0, len(ips))
for i := range ips {
ips[i] = strings.TrimSpace(ips[i])
if ips[i] != "" {
validatedIPs = append(validatedIPs, ips[i])
}
}
if len(validatedIPs) == 0 {
s.setAlert(c, "invalid ip address", "danger")
2020-11-07 05:47:52 -05:00
c.Redirect(http.StatusSeeOther, "/admin/peer/create")
2020-11-07 04:31:48 -05:00
return
}
2020-11-07 05:47:52 -05:00
user.IPs = validatedIPs
2020-11-07 04:31:48 -05:00
allowedIPField := c.PostForm("allowedip")
allowedIP := strings.Split(allowedIPField, ",")
validatedAllowedIP := make([]string, 0, len(allowedIP))
for i := range allowedIP {
allowedIP[i] = strings.TrimSpace(allowedIP[i])
if allowedIP[i] != "" {
validatedAllowedIP = append(validatedAllowedIP, allowedIP[i])
}
}
2020-11-07 05:47:52 -05:00
user.AllowedIPs = validatedAllowedIP
2020-11-07 04:31:48 -05:00
2020-11-07 05:47:52 -05:00
user.IgnorePersistentKeepalive = c.PostForm("ignorekeepalive") != ""
disabled := c.PostForm("isdisabled") != ""
now := time.Now()
if disabled && user.DeactivatedAt == nil {
user.DeactivatedAt = &now
} else if !disabled {
user.DeactivatedAt = nil
2020-11-07 04:31:48 -05:00
}
// Update WireGuard device
2020-11-07 05:47:52 -05:00
if user.DeactivatedAt == nil {
err = s.wg.AddPeer(user.GetPeerConfig())
if err != nil {
s.setAlert(c, "failed to add peer in WireGuard: "+err.Error(), "danger")
c.Redirect(http.StatusSeeOther, "/admin/peer/create")
return
}
2020-11-07 04:31:48 -05:00
}
// Update in database
2020-11-07 05:47:52 -05:00
err = s.users.CreateUser(user)
2020-11-07 04:31:48 -05:00
if err != nil {
2020-11-07 05:47:52 -05:00
s.setAlert(c, "failed to add user in database: "+err.Error(), "danger")
c.Redirect(http.StatusSeeOther, "/admin/peer/create")
2020-11-07 04:31:48 -05:00
return
}
2020-11-07 05:47:52 -05:00
s.setAlert(c, "client created successfully", "success")
c.Redirect(http.StatusSeeOther, "/admin")
2020-11-07 04:31:48 -05:00
}
2020-11-06 06:21:47 -05:00
func (s *Server) GetUserQRCode(c *gin.Context) {
2020-11-07 04:31:48 -05:00
user := s.users.GetUserByKey(c.Query("pkey"))
2020-11-06 06:21:47 -05:00
png, err := user.GetQRCode()
if err != nil {
s.HandleError(c, http.StatusInternalServerError, "QRCode error", err.Error())
return
}
c.Data(http.StatusOK, "image/png", png)
return
}