mirror of
https://github.com/h44z/wg-portal.git
synced 2025-08-10 23:42:24 +00:00
refactor template handling
This commit is contained in:
parent
4c7f2b24bc
commit
7a0a3b1e9e
@ -5,6 +5,7 @@ import (
|
|||||||
"github.com/h44z/wg-portal/internal/app/api/core"
|
"github.com/h44z/wg-portal/internal/app/api/core"
|
||||||
handlersV0 "github.com/h44z/wg-portal/internal/app/api/v0/handlers"
|
handlersV0 "github.com/h44z/wg-portal/internal/app/api/v0/handlers"
|
||||||
"github.com/h44z/wg-portal/internal/app/auth"
|
"github.com/h44z/wg-portal/internal/app/auth"
|
||||||
|
"github.com/h44z/wg-portal/internal/app/filetemplate"
|
||||||
"github.com/h44z/wg-portal/internal/app/users"
|
"github.com/h44z/wg-portal/internal/app/users"
|
||||||
"github.com/h44z/wg-portal/internal/app/wireguard"
|
"github.com/h44z/wg-portal/internal/app/wireguard"
|
||||||
"os"
|
"os"
|
||||||
@ -63,7 +64,12 @@ func main() {
|
|||||||
statisticsCollector, err := wireguard.NewStatisticsCollector(cfg, database, wireGuard)
|
statisticsCollector, err := wireguard.NewStatisticsCollector(cfg, database, wireGuard)
|
||||||
internal.AssertNoError(err)
|
internal.AssertNoError(err)
|
||||||
|
|
||||||
backend, err := app.New(cfg, eventBus, authenticator, userManager, wireGuardManager, statisticsCollector)
|
templateManager, err := filetemplate.NewTemplateManager(cfg, database, database)
|
||||||
|
internal.AssertNoError(err)
|
||||||
|
|
||||||
|
backend, err := app.New(cfg, eventBus, authenticator, userManager, wireGuardManager,
|
||||||
|
statisticsCollector, templateManager)
|
||||||
|
|
||||||
internal.AssertNoError(err)
|
internal.AssertNoError(err)
|
||||||
err = backend.Startup(ctx)
|
err = backend.Startup(ctx)
|
||||||
internal.AssertNoError(err)
|
internal.AssertNoError(err)
|
||||||
|
@ -201,7 +201,7 @@ func (r *SqlRepo) migrate() error {
|
|||||||
func (r *SqlRepo) GetInterface(ctx context.Context, id domain.InterfaceIdentifier) (*domain.Interface, error) {
|
func (r *SqlRepo) GetInterface(ctx context.Context, id domain.InterfaceIdentifier) (*domain.Interface, error) {
|
||||||
var in domain.Interface
|
var in domain.Interface
|
||||||
|
|
||||||
err := r.db.WithContext(ctx).First(&in, id).Error
|
err := r.db.WithContext(ctx).Preload("Addresses").First(&in, id).Error
|
||||||
|
|
||||||
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
|
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
return nil, domain.ErrNotFound
|
return nil, domain.ErrNotFound
|
||||||
@ -356,6 +356,17 @@ func (r *SqlRepo) GetInterfaceIps(ctx context.Context) (map[domain.InterfaceIden
|
|||||||
|
|
||||||
// region peers
|
// region peers
|
||||||
|
|
||||||
|
func (r *SqlRepo) GetPeer(ctx context.Context, id domain.PeerIdentifier) (*domain.Peer, error) {
|
||||||
|
var peer domain.Peer
|
||||||
|
|
||||||
|
err := r.db.WithContext(ctx).Where("identifier = ?", id).Find(&peer).Error
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &peer, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *SqlRepo) GetInterfacePeers(ctx context.Context, id domain.InterfaceIdentifier) ([]domain.Peer, error) {
|
func (r *SqlRepo) GetInterfacePeers(ctx context.Context, id domain.InterfaceIdentifier) ([]domain.Peer, error) {
|
||||||
var peers []domain.Peer
|
var peers []domain.Peer
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"github.com/h44z/wg-portal/internal/app"
|
"github.com/h44z/wg-portal/internal/app"
|
||||||
"github.com/h44z/wg-portal/internal/app/api/v0/model"
|
"github.com/h44z/wg-portal/internal/app/api/v0/model"
|
||||||
"github.com/h44z/wg-portal/internal/domain"
|
"github.com/h44z/wg-portal/internal/domain"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -129,17 +130,23 @@ func (e interfaceEndpoint) handleConfigGet() gin.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, `[Interface]
|
config, err := e.app.GetInterfaceConfig(c.Request.Context(), domain.InterfaceIdentifier(id))
|
||||||
Address = 10.0.0.1/32, fd12:3456:789a::1/128
|
if err != nil {
|
||||||
ListenPort = 51820
|
c.JSON(http.StatusInternalServerError, model.Error{
|
||||||
PrivateKey = <Private Key>
|
Code: http.StatusInternalServerError, Message: err.Error(),
|
||||||
SaveConfig = true
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
[Peer]
|
configString, err := io.ReadAll(config)
|
||||||
PublicKey = <Client public key>
|
if err != nil {
|
||||||
PresharedKey = <Pre-Shared Key>
|
c.JSON(http.StatusInternalServerError, model.Error{
|
||||||
AllowedIPs = 10.0.0.2/32,fd12:3456:789a::2/128
|
Code: http.StatusInternalServerError, Message: err.Error(),
|
||||||
PersistentKeepalive = 25`)
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, string(configString))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,9 +19,10 @@ type App struct {
|
|||||||
UserManager
|
UserManager
|
||||||
WireGuardManager
|
WireGuardManager
|
||||||
StatisticsCollector
|
StatisticsCollector
|
||||||
|
TemplateManager
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(cfg *config.Config, bus evbus.MessageBus, authenticator Authenticator, users UserManager, wireGuard WireGuardManager, stats StatisticsCollector) (*App, error) {
|
func New(cfg *config.Config, bus evbus.MessageBus, authenticator Authenticator, users UserManager, wireGuard WireGuardManager, stats StatisticsCollector, templates TemplateManager) (*App, error) {
|
||||||
|
|
||||||
a := &App{
|
a := &App{
|
||||||
Config: cfg,
|
Config: cfg,
|
||||||
@ -31,6 +32,7 @@ func New(cfg *config.Config, bus evbus.MessageBus, authenticator Authenticator,
|
|||||||
UserManager: users,
|
UserManager: users,
|
||||||
WireGuardManager: wireGuard,
|
WireGuardManager: wireGuard,
|
||||||
StatisticsCollector: stats,
|
StatisticsCollector: stats,
|
||||||
|
TemplateManager: templates,
|
||||||
}
|
}
|
||||||
|
|
||||||
startupContext, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
startupContext, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
|
52
internal/app/filetemplate/manager.go
Normal file
52
internal/app/filetemplate/manager.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package filetemplate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/h44z/wg-portal/internal/config"
|
||||||
|
"github.com/h44z/wg-portal/internal/domain"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Manager struct {
|
||||||
|
cfg *config.Config
|
||||||
|
tplHandler *TemplateHandler
|
||||||
|
|
||||||
|
users UserDatabaseRepo
|
||||||
|
wg WireguardDatabaseRepo
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTemplateManager(cfg *config.Config, users UserDatabaseRepo, wg WireguardDatabaseRepo) (*Manager, error) {
|
||||||
|
tplHandler, err := newTemplateHandler()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to initialize template handler: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
m := &Manager{
|
||||||
|
cfg: cfg,
|
||||||
|
tplHandler: tplHandler,
|
||||||
|
|
||||||
|
users: users,
|
||||||
|
wg: wg,
|
||||||
|
}
|
||||||
|
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Manager) GetInterfaceConfig(ctx context.Context, id domain.InterfaceIdentifier) (io.Reader, error) {
|
||||||
|
iface, peers, err := m.wg.GetInterfaceAndPeers(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to fetch interface %s: %w", id, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.tplHandler.GetInterfaceConfig(iface, peers)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Manager) GetPeerConfig(ctx context.Context, id domain.PeerIdentifier) (io.Reader, error) {
|
||||||
|
peer, err := m.wg.GetPeer(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to fetch peer %s: %w", id, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.tplHandler.GetPeerConfig(peer)
|
||||||
|
}
|
16
internal/app/filetemplate/repos.go
Normal file
16
internal/app/filetemplate/repos.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package filetemplate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/h44z/wg-portal/internal/domain"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserDatabaseRepo interface {
|
||||||
|
GetUser(ctx context.Context, id domain.UserIdentifier) (*domain.User, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type WireguardDatabaseRepo interface {
|
||||||
|
GetInterfaceAndPeers(ctx context.Context, id domain.InterfaceIdentifier) (*domain.Interface, []domain.Peer, error)
|
||||||
|
GetPeer(ctx context.Context, id domain.PeerIdentifier) (*domain.Peer, error)
|
||||||
|
GetInterface(ctx context.Context, id domain.InterfaceIdentifier) (*domain.Interface, error)
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package app
|
package filetemplate
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -14,30 +14,34 @@ import (
|
|||||||
//go:embed tpl_files/*
|
//go:embed tpl_files/*
|
||||||
var TemplateFiles embed.FS
|
var TemplateFiles embed.FS
|
||||||
|
|
||||||
type templateHandler struct {
|
type TemplateHandler struct {
|
||||||
wireGuardTemplates *template.Template
|
wireGuardTemplates *template.Template
|
||||||
|
|
||||||
mailHtmlTemplates *htmlTemplate.Template
|
mailHtmlTemplates *htmlTemplate.Template
|
||||||
mailTextTemplates *template.Template
|
mailTextTemplates *template.Template
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTemplateHandler() (*templateHandler, error) {
|
func newTemplateHandler() (*TemplateHandler, error) {
|
||||||
templateCache, err := template.New("WireGuard").ParseFS(TemplateFiles, "tpl_files/*.tpl")
|
tplFuncs := template.FuncMap{
|
||||||
|
"CidrsToString": domain.CidrsToString,
|
||||||
|
}
|
||||||
|
|
||||||
|
templateCache, err := template.New("WireGuard").Funcs(tplFuncs).ParseFS(TemplateFiles, "tpl_files/*.tpl")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
mailHtmlTemplateCache, err := htmlTemplate.New("WireGuard").ParseFS(TemplateFiles, "tpl_files/*.gohtml")
|
mailHtmlTemplateCache, err := htmlTemplate.New("WireGuard").Funcs(tplFuncs).ParseFS(TemplateFiles, "tpl_files/*.gohtml")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse html template files: %w", err)
|
return nil, fmt.Errorf("failed to parse html template files: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
mailTxtTemplateCache, err := template.New("WireGuard").ParseFS(TemplateFiles, "tpl_files/*.gotpl")
|
mailTxtTemplateCache, err := template.New("WireGuard").Funcs(tplFuncs).ParseFS(TemplateFiles, "tpl_files/*.gotpl")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse text template files: %w", err)
|
return nil, fmt.Errorf("failed to parse text template files: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := &templateHandler{
|
handler := &TemplateHandler{
|
||||||
wireGuardTemplates: templateCache,
|
wireGuardTemplates: templateCache,
|
||||||
mailHtmlTemplates: mailHtmlTemplateCache,
|
mailHtmlTemplates: mailHtmlTemplateCache,
|
||||||
mailTextTemplates: mailTxtTemplateCache,
|
mailTextTemplates: mailTxtTemplateCache,
|
||||||
@ -46,7 +50,7 @@ func newTemplateHandler() (*templateHandler, error) {
|
|||||||
return handler, nil
|
return handler, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c templateHandler) GetInterfaceConfig(cfg *domain.Interface, peers []*domain.Peer) (io.Reader, error) {
|
func (c TemplateHandler) GetInterfaceConfig(cfg *domain.Interface, peers []domain.Peer) (io.Reader, error) {
|
||||||
var tplBuff bytes.Buffer
|
var tplBuff bytes.Buffer
|
||||||
|
|
||||||
err := c.wireGuardTemplates.ExecuteTemplate(&tplBuff, "wg_interface.tpl", map[string]interface{}{
|
err := c.wireGuardTemplates.ExecuteTemplate(&tplBuff, "wg_interface.tpl", map[string]interface{}{
|
||||||
@ -63,7 +67,7 @@ func (c templateHandler) GetInterfaceConfig(cfg *domain.Interface, peers []*doma
|
|||||||
return &tplBuff, nil
|
return &tplBuff, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c templateHandler) GetPeerConfig(peer *domain.Peer) (io.Reader, error) {
|
func (c TemplateHandler) GetPeerConfig(peer *domain.Peer) (io.Reader, error) {
|
||||||
var tplBuff bytes.Buffer
|
var tplBuff bytes.Buffer
|
||||||
|
|
||||||
err := c.wireGuardTemplates.ExecuteTemplate(&tplBuff, "wg_peer.tpl", map[string]interface{}{
|
err := c.wireGuardTemplates.ExecuteTemplate(&tplBuff, "wg_peer.tpl", map[string]interface{}{
|
||||||
@ -79,7 +83,7 @@ func (c templateHandler) GetPeerConfig(peer *domain.Peer) (io.Reader, error) {
|
|||||||
return &tplBuff, nil
|
return &tplBuff, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c templateHandler) GetConfigMail(user *domain.User, peer *domain.Peer, link string) (io.Reader, io.Reader, error) {
|
func (c TemplateHandler) GetConfigMail(user *domain.User, peer *domain.Peer, link string) (io.Reader, io.Reader, error) {
|
||||||
var tplBuff bytes.Buffer
|
var tplBuff bytes.Buffer
|
||||||
var htmlTplBuff bytes.Buffer
|
var htmlTplBuff bytes.Buffer
|
||||||
|
|
||||||
@ -104,7 +108,7 @@ func (c templateHandler) GetConfigMail(user *domain.User, peer *domain.Peer, lin
|
|||||||
return &tplBuff, &htmlTplBuff, nil
|
return &tplBuff, &htmlTplBuff, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c templateHandler) GetConfigMailWithAttachment(user *domain.User, peer *domain.Peer) (io.Reader, io.Reader, error) {
|
func (c TemplateHandler) GetConfigMailWithAttachment(user *domain.User, peer *domain.Peer) (io.Reader, io.Reader, error) {
|
||||||
var tplBuff bytes.Buffer
|
var tplBuff bytes.Buffer
|
||||||
var htmlTplBuff bytes.Buffer
|
var htmlTplBuff bytes.Buffer
|
||||||
|
|
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
# Core settings
|
# Core settings
|
||||||
PrivateKey = {{ .Interface.KeyPair.PrivateKey }}
|
PrivateKey = {{ .Interface.KeyPair.PrivateKey }}
|
||||||
Address = {{ .Interface.AddressStr }}
|
Address = {{ CidrsToString .Interface.Addresses }}
|
||||||
|
|
||||||
# Misc. settings (optional)
|
# Misc. settings (optional)
|
||||||
{{- if ne .Interface.ListenPort 0}}
|
{{- if ne .Interface.ListenPort 0}}
|
@ -3,6 +3,7 @@ package app
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/h44z/wg-portal/internal/domain"
|
"github.com/h44z/wg-portal/internal/domain"
|
||||||
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Authenticator interface {
|
type Authenticator interface {
|
||||||
@ -41,3 +42,8 @@ type WireGuardManager interface {
|
|||||||
type StatisticsCollector interface {
|
type StatisticsCollector interface {
|
||||||
StartBackgroundJobs(ctx context.Context)
|
StartBackgroundJobs(ctx context.Context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TemplateManager interface {
|
||||||
|
GetInterfaceConfig(ctx context.Context, id domain.InterfaceIdentifier) (io.Reader, error)
|
||||||
|
GetPeerConfig(ctx context.Context, id domain.PeerIdentifier) (io.Reader, error)
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user