mirror of
https://github.com/Pacerino/CaddyProxyManager.git
synced 2026-07-08 06:42:07 -04:00
Introduce per-host plugin support: Caddy module discovery, module config endpoints, plugin schemas (basicauth, cloudflare) and the host plugins API. On the frontend, add the Plugins page, plugin/host plugin dialogs and schema-driven form fields.
106 lines
3.0 KiB
Go
106 lines
3.0 KiB
Go
package database
|
|
|
|
import (
|
|
"database/sql/driver"
|
|
"encoding/json"
|
|
"errors"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type Host struct {
|
|
gorm.Model
|
|
Domains string `json:"domains" validate:"required,domains"`
|
|
Matcher string `json:"matcher"`
|
|
Upstreams []Upstream
|
|
Plugins []HostPlugin
|
|
}
|
|
|
|
// HostPlugin is a per-host plugin configuration. Handler holds the rendered
|
|
// Caddy route handler JSON (secrets already hashed), which is injected into
|
|
// the host's route. ModuleID is the dotted Caddy module name.
|
|
type HostPlugin struct {
|
|
gorm.Model
|
|
HostID uint `json:"hostId" gorm:"index"`
|
|
ModuleID string `json:"moduleId" validate:"required"`
|
|
// Handler is the rendered route handler object applied to the route.
|
|
Handler JSON `json:"handler"`
|
|
Enabled bool `json:"enabled" gorm:"default:true"`
|
|
}
|
|
|
|
type Upstream struct {
|
|
gorm.Model
|
|
HostID uint `json:"hostId"`
|
|
Backend string `json:"backend" validate:"required,hostname_port"`
|
|
}
|
|
|
|
// JSON is a json.RawMessage that persists as TEXT in SQLite via the
|
|
// Valuer/Scanner interfaces.
|
|
type JSON json.RawMessage
|
|
|
|
// Value implements driver.Valuer.
|
|
func (j JSON) Value() (driver.Value, error) {
|
|
if len(j) == 0 {
|
|
return "null", nil
|
|
}
|
|
return string(j), nil
|
|
}
|
|
|
|
// Scan implements sql.Scanner.
|
|
func (j *JSON) Scan(value any) error {
|
|
if value == nil {
|
|
*j = JSON("null")
|
|
return nil
|
|
}
|
|
switch v := value.(type) {
|
|
case []byte:
|
|
*j = append((*j)[0:0], v...)
|
|
case string:
|
|
*j = append((*j)[0:0], v...)
|
|
default:
|
|
return errors.New("unsupported type for JSON column")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// MarshalJSON makes JSON serialise as raw JSON rather than a byte array.
|
|
func (j JSON) MarshalJSON() ([]byte, error) {
|
|
if len(j) == 0 {
|
|
return []byte("null"), nil
|
|
}
|
|
return j, nil
|
|
}
|
|
|
|
// UnmarshalJSON captures raw JSON as-is.
|
|
func (j *JSON) UnmarshalJSON(data []byte) error {
|
|
*j = append((*j)[0:0], data...)
|
|
return nil
|
|
}
|
|
|
|
// ModuleConfig stores a configuration fragment for a single Caddy module
|
|
// (plugin). Config is applied to the live Caddy config at Path via the admin
|
|
// API. ModuleID is the dotted Caddy module name, e.g. "dns.providers.cloudflare".
|
|
type ModuleConfig struct {
|
|
gorm.Model
|
|
// ModuleID is the dotted Caddy module name this fragment configures.
|
|
ModuleID string `json:"moduleId" gorm:"uniqueIndex" validate:"required"`
|
|
// Path is the admin API config path the fragment is patched into,
|
|
// e.g. "apps/tls/automation/policies". Relative to /config/.
|
|
Path string `json:"path" validate:"required"`
|
|
// Config is the JSON fragment patched into Path.
|
|
Config JSON `json:"config" validate:"required"`
|
|
// Enabled controls whether the fragment is applied on reconcile.
|
|
Enabled bool `json:"enabled" gorm:"default:true"`
|
|
}
|
|
|
|
type User struct {
|
|
gorm.Model
|
|
Name string `validate:"required"`
|
|
Email string `gorm:"unique" validate:"required,email"`
|
|
Secret string `json:"secret,omitempty"`
|
|
// Provider is the auth source for this user: "local" or "oidc".
|
|
Provider string `json:"provider" gorm:"default:local"`
|
|
// Subject is the OIDC subject identifier (sub claim), empty for local users.
|
|
Subject string `json:"subject,omitempty" gorm:"index"`
|
|
}
|