wg-portal/internal/server/server_helper.go

298 lines
9.5 KiB
Go
Raw Normal View History

2020-11-09 05:06:02 -05:00
package server
import (
"crypto/md5"
"fmt"
2020-11-09 17:43:57 -05:00
"io/ioutil"
"path"
2020-11-09 17:43:57 -05:00
"syscall"
2020-11-09 05:06:02 -05:00
"time"
"github.com/h44z/wg-portal/internal/wireguard"
2020-11-09 05:06:02 -05:00
"github.com/h44z/wg-portal/internal/common"
2021-02-26 16:17:04 -05:00
"github.com/h44z/wg-portal/internal/users"
"github.com/pkg/errors"
2021-02-26 16:17:04 -05:00
"github.com/sirupsen/logrus"
2020-11-09 05:06:02 -05:00
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
2021-02-26 16:17:04 -05:00
"gorm.io/gorm"
2020-11-09 05:06:02 -05:00
)
// PrepareNewPeer initiates a new peer for the given WireGuard device.
func (s *Server) PrepareNewPeer(device string) (wireguard.Peer, error) {
dev := s.peers.GetDevice(device)
2020-11-09 05:06:02 -05:00
peer := wireguard.Peer{}
2021-02-21 17:23:58 -05:00
peer.IsNew = true
peer.AllowedIPsStr = dev.AllowedIPsStr
peer.IPs = make([]string, len(dev.IPs))
for i := range dev.IPs {
freeIP, err := s.peers.GetAvailableIp(device, dev.IPs[i])
2020-11-09 05:06:02 -05:00
if err != nil {
return wireguard.Peer{}, errors.WithMessage(err, "failed to get available IP addresses")
2020-11-09 05:06:02 -05:00
}
2021-02-21 17:23:58 -05:00
peer.IPs[i] = freeIP
2020-11-09 05:06:02 -05:00
}
2021-02-21 17:23:58 -05:00
peer.IPsStr = common.ListToString(peer.IPs)
2020-11-09 05:06:02 -05:00
psk, err := wgtypes.GenerateKey()
if err != nil {
return wireguard.Peer{}, errors.Wrap(err, "failed to generate key")
2020-11-09 05:06:02 -05:00
}
key, err := wgtypes.GeneratePrivateKey()
if err != nil {
return wireguard.Peer{}, errors.Wrap(err, "failed to generate private key")
2020-11-09 05:06:02 -05:00
}
2021-02-21 17:23:58 -05:00
peer.PresharedKey = psk.String()
peer.PrivateKey = key.String()
peer.PublicKey = key.PublicKey().String()
peer.UID = fmt.Sprintf("u%x", md5.Sum([]byte(peer.PublicKey)))
2020-11-09 05:06:02 -05:00
2021-02-21 17:23:58 -05:00
return peer, nil
2020-11-09 05:06:02 -05:00
}
// CreatePeerByEmail creates a new peer for the given email. If no user with the specified email was found, a new one
// will be created.
func (s *Server) CreatePeerByEmail(device, email, identifierSuffix string, disabled bool) error {
user, err := s.users.GetOrCreateUser(email)
if err != nil {
return errors.WithMessagef(err, "failed to load/create related user %s", email)
2020-11-09 05:06:02 -05:00
}
peer, err := s.PrepareNewPeer(device)
2020-11-09 05:06:02 -05:00
if err != nil {
return errors.WithMessage(err, "failed to prepare new peer")
2020-11-09 05:06:02 -05:00
}
2021-02-21 17:23:58 -05:00
peer.Email = email
peer.Identifier = fmt.Sprintf("%s %s (%s)", user.Firstname, user.Lastname, identifierSuffix)
2020-11-09 05:06:02 -05:00
now := time.Now()
if disabled {
2021-02-21 17:23:58 -05:00
peer.DeactivatedAt = &now
2020-11-09 05:06:02 -05:00
}
return s.CreatePeer(device, peer)
2020-11-09 05:06:02 -05:00
}
// CreatePeer creates the new peer in the database. If the peer has no assigned ip addresses, a new one will be assigned
// automatically. Also, if the private key is empty, a new key-pair will be generated.
// This function also configures the new peer on the physical WireGuard interface if the peer is not deactivated.
func (s *Server) CreatePeer(device string, peer wireguard.Peer) error {
dev := s.peers.GetDevice(device)
peer.AllowedIPsStr = dev.AllowedIPsStr
if peer.IPs == nil || len(peer.IPs) == 0 {
peer.IPs = make([]string, len(dev.IPs))
for i := range dev.IPs {
freeIP, err := s.peers.GetAvailableIp(device, dev.IPs[i])
if err != nil {
2021-02-26 16:17:04 -05:00
return errors.WithMessage(err, "failed to get available IP addresses")
}
peer.IPs[i] = freeIP
}
peer.IPsStr = common.ListToString(peer.IPs)
}
if peer.PrivateKey == "" { // if private key is empty create a new one
2020-11-09 05:06:02 -05:00
psk, err := wgtypes.GenerateKey()
if err != nil {
2021-02-26 16:17:04 -05:00
return errors.Wrap(err, "failed to generate key")
2020-11-09 05:06:02 -05:00
}
key, err := wgtypes.GeneratePrivateKey()
if err != nil {
2021-02-26 16:17:04 -05:00
return errors.Wrap(err, "failed to generate private key")
2020-11-09 05:06:02 -05:00
}
peer.PresharedKey = psk.String()
peer.PrivateKey = key.String()
peer.PublicKey = key.PublicKey().String()
2020-11-09 05:06:02 -05:00
}
peer.DeviceName = dev.DeviceName
peer.UID = fmt.Sprintf("u%x", md5.Sum([]byte(peer.PublicKey)))
2020-11-09 05:06:02 -05:00
// Create WireGuard interface
if peer.DeactivatedAt == nil {
if err := s.wg.AddPeer(device, peer.GetConfig()); err != nil {
2021-02-26 16:17:04 -05:00
return errors.WithMessage(err, "failed to add WireGuard peer")
2020-11-09 05:06:02 -05:00
}
}
// Create in database
if err := s.peers.CreatePeer(peer); err != nil {
2021-02-26 16:17:04 -05:00
return errors.WithMessage(err, "failed to create peer")
2020-11-09 05:06:02 -05:00
}
return s.WriteWireGuardConfigFile(device)
2020-11-09 05:06:02 -05:00
}
// UpdatePeer updates the physical WireGuard interface and the database.
func (s *Server) UpdatePeer(peer wireguard.Peer, updateTime time.Time) error {
currentPeer := s.peers.GetPeerByKey(peer.PublicKey)
2020-11-09 05:06:02 -05:00
// Update WireGuard device
var err error
switch {
case peer.DeactivatedAt == &updateTime:
err = s.wg.RemovePeer(peer.DeviceName, peer.PublicKey)
case peer.DeactivatedAt == nil && currentPeer.Peer != nil:
err = s.wg.UpdatePeer(peer.DeviceName, peer.GetConfig())
case peer.DeactivatedAt == nil && currentPeer.Peer == nil:
err = s.wg.AddPeer(peer.DeviceName, peer.GetConfig())
2020-11-09 05:06:02 -05:00
}
if err != nil {
2021-02-26 16:17:04 -05:00
return errors.WithMessage(err, "failed to update WireGuard peer")
2020-11-09 05:06:02 -05:00
}
// Update in database
if err := s.peers.UpdatePeer(peer); err != nil {
2021-02-26 16:17:04 -05:00
return errors.WithMessage(err, "failed to update peer")
2020-11-09 05:06:02 -05:00
}
return s.WriteWireGuardConfigFile(peer.DeviceName)
2020-11-09 05:06:02 -05:00
}
// DeletePeer removes the peer from the physical WireGuard interface and the database.
func (s *Server) DeletePeer(peer wireguard.Peer) error {
2020-11-09 05:06:02 -05:00
// Delete WireGuard peer
if err := s.wg.RemovePeer(peer.DeviceName, peer.PublicKey); err != nil {
2021-02-26 16:17:04 -05:00
return errors.WithMessage(err, "failed to remove WireGuard peer")
2020-11-09 05:06:02 -05:00
}
// Delete in database
if err := s.peers.DeletePeer(peer); err != nil {
2021-02-26 16:17:04 -05:00
return errors.WithMessage(err, "failed to remove peer")
2020-11-09 05:06:02 -05:00
}
return s.WriteWireGuardConfigFile(peer.DeviceName)
2020-11-09 05:06:02 -05:00
}
// RestoreWireGuardInterface restores the state of the physical WireGuard interface from the database.
func (s *Server) RestoreWireGuardInterface(device string) error {
activePeers := s.peers.GetActivePeers(device)
for i := range activePeers {
if activePeers[i].Peer == nil {
if err := s.wg.AddPeer(device, activePeers[i].GetConfig()); err != nil {
2021-02-26 16:17:04 -05:00
return errors.WithMessage(err, "failed to add WireGuard peer")
}
}
}
return nil
}
2020-11-09 17:43:57 -05:00
// WriteWireGuardConfigFile writes the configuration file for the physical WireGuard interface.
func (s *Server) WriteWireGuardConfigFile(device string) error {
if s.config.WG.ConfigDirectoryPath == "" {
2020-11-09 17:43:57 -05:00
return nil // writing disabled
}
if err := syscall.Access(s.config.WG.ConfigDirectoryPath, syscall.O_RDWR); err != nil {
2021-02-26 16:17:04 -05:00
return errors.Wrap(err, "failed to check WireGuard config access rights")
2020-11-09 17:43:57 -05:00
}
dev := s.peers.GetDevice(device)
cfg, err := dev.GetConfigFile(s.peers.GetActivePeers(device))
2020-11-09 17:43:57 -05:00
if err != nil {
2021-02-26 16:17:04 -05:00
return errors.WithMessage(err, "failed to get config file")
2020-11-09 17:43:57 -05:00
}
filePath := path.Join(s.config.WG.ConfigDirectoryPath, dev.DeviceName+".conf")
if err := ioutil.WriteFile(filePath, cfg, 0644); err != nil {
2021-02-26 16:17:04 -05:00
return errors.Wrap(err, "failed to write WireGuard config file")
2020-11-09 17:43:57 -05:00
}
return nil
}
2021-02-26 16:17:04 -05:00
// CreateUser creates the user in the database and optionally adds a default WireGuard peer for the user.
func (s *Server) CreateUser(user users.User, device string) error {
2021-02-26 16:17:04 -05:00
if user.Email == "" {
return errors.New("cannot create user with empty email address")
}
// Check if user already exists, if so re-enable
if existingUser := s.users.GetUserUnscoped(user.Email); existingUser != nil {
user.DeletedAt = gorm.DeletedAt{} // reset deleted flag to enable that user again
return s.UpdateUser(user)
}
// Create user in database
if err := s.users.CreateUser(&user); err != nil {
return errors.WithMessage(err, "failed to create user in manager")
}
// Check if user already has a peer setup, if not, create one
return s.CreateUserDefaultPeer(user.Email, device)
2021-02-26 16:17:04 -05:00
}
// UpdateUser updates the user in the database. If the user is marked as deleted, it will get remove from the database.
// Also, if the user is re-enabled, all it's linked WireGuard peers will be activated again.
2021-02-26 16:17:04 -05:00
func (s *Server) UpdateUser(user users.User) error {
if user.DeletedAt.Valid {
return s.DeleteUser(user)
}
currentUser := s.users.GetUserUnscoped(user.Email)
// Update in database
if err := s.users.UpdateUser(&user); err != nil {
return errors.WithMessage(err, "failed to update user in manager")
}
// If user was deleted (disabled), reactivate it's peers
if currentUser.DeletedAt.Valid {
for _, peer := range s.peers.GetPeersByMail(user.Email) {
now := time.Now()
peer.DeactivatedAt = nil
if err := s.UpdatePeer(peer, now); err != nil {
logrus.Errorf("failed to update (re)activated peer %s for %s: %v", peer.PublicKey, user.Email, err)
}
}
}
return nil
}
// DeleteUser removes the user from the database.
// Also, if the user has linked WireGuard peers, they will be deactivated.
2021-02-26 16:17:04 -05:00
func (s *Server) DeleteUser(user users.User) error {
currentUser := s.users.GetUserUnscoped(user.Email)
// Update in database
if err := s.users.DeleteUser(&user); err != nil {
return errors.WithMessage(err, "failed to delete user in manager")
}
// If user was active, disable it's peers
if !currentUser.DeletedAt.Valid {
for _, peer := range s.peers.GetPeersByMail(user.Email) {
now := time.Now()
peer.DeactivatedAt = &now
if err := s.UpdatePeer(peer, now); err != nil {
logrus.Errorf("failed to update deactivated peer %s for %s: %v", peer.PublicKey, user.Email, err)
}
}
}
return nil
}
func (s *Server) CreateUserDefaultPeer(email, device string) error {
2021-02-26 16:17:04 -05:00
// Check if user is active, if not, quit
var existingUser *users.User
if existingUser = s.users.GetUser(email); existingUser == nil {
return nil
}
// Check if user already has a peer setup, if not, create one
if s.config.Core.CreateDefaultPeer {
peers := s.peers.GetPeersByMail(email)
if len(peers) == 0 { // Create default vpn peer
if err := s.CreatePeer(device, wireguard.Peer{
2021-02-26 16:17:04 -05:00
Identifier: existingUser.Firstname + " " + existingUser.Lastname + " (Default)",
Email: existingUser.Email,
CreatedBy: existingUser.Email,
UpdatedBy: existingUser.Email,
}); err != nil {
return errors.WithMessagef(err, "failed to automatically create vpn peer for %s", email)
}
}
}
return nil
}