generate interface and peer configuration filenames in backend only (#395)

This commit is contained in:
Christoph 2025-04-19 13:12:31 +02:00
parent a60feb7fc9
commit 6681dfa96f
14 changed files with 91 additions and 20 deletions

View File

@ -82,6 +82,14 @@ definitions:
description: EnabledPeers is the number of enabled peers for this interface. Only enabled peers are able to connect.
readOnly: true
type: integer
Filename:
description: |-
Filename is the name of the config file for this interface.
This value is read only and is not settable by the user.
example: wg0.conf
maxLength: 21
readOnly: true
type: string
FirewallMark:
description: FirewallMark is an optional firewall mark which is used to handle interface traffic.
type: integer
@ -277,6 +285,14 @@ definitions:
items:
type: string
type: array
Filename:
description: |-
Filename is the name of the config file for this peer.
This value is read only and is not settable by the user.
example: wg_peer_x.conf
maxLength: 21
readOnly: true
type: string
FirewallMark:
allOf:
- $ref: '#/definitions/models.ConfigOption-uint32'

View File

@ -89,19 +89,11 @@ watch(() => props.visible, async (newValue, oldValue) => {
function download() {
// credit: https://www.bitdegree.org/learn/javascript-download
let filename = 'WireGuard-Tunnel.conf'
if (selectedPeer.value.DisplayName) {
filename = selectedPeer.value.DisplayName
.replace(/ /g, "_")
.replace(/[^a-zA-Z0-9-_]/g, "")
.substring(0, 16)
+ ".conf"
}
let text = configString.value
let element = document.createElement('a')
element.setAttribute('href', 'data:application/octet-stream;charset=utf-8,' + encodeURIComponent(text))
element.setAttribute('download', filename)
element.setAttribute('download', selectedPeer.value.Filename)
element.style.display = 'none'
document.body.appendChild(element)

View File

@ -42,7 +42,8 @@ export function freshInterface() {
PeerDefPostDown: "",
TotalPeers: 0,
EnabledPeers: 0
EnabledPeers: 0,
Filename: ""
}
}
@ -120,6 +121,8 @@ export function freshPeer() {
Overridable: true,
},
Filename: "",
// Internal values
IgnoreGlobalSettings: false,
IsSelected: false

View File

@ -49,12 +49,11 @@ async function download() {
await interfaces.LoadInterfaceConfig(interfaces.GetSelected.Identifier)
// credit: https://www.bitdegree.org/learn/javascript-download
let filename = interfaces.GetSelected.Identifier + ".conf"
let text = interfaces.configuration
let element = document.createElement('a')
element.setAttribute('href', 'data:application/octet-stream;charset=utf-8,' + encodeURIComponent(text))
element.setAttribute('download', filename)
element.setAttribute('download', interfaces.GetSelected.Filename)
element.style.display = 'none'
document.body.appendChild(element)

View File

@ -1646,6 +1646,10 @@
"EnabledPeers": {
"type": "integer"
},
"Filename": {
"description": "the filename of the config file, for example: wg0.conf",
"type": "string"
},
"FirewallMark": {
"description": "a firewall mark",
"type": "integer"
@ -1887,6 +1891,10 @@
"type": "string"
}
},
"Filename": {
"description": "the filename of the config file, for example: wg_peer_x.conf",
"type": "string"
},
"FirewallMark": {
"description": "a firewall mark",
"allOf": [

View File

@ -88,6 +88,9 @@ definitions:
type: array
EnabledPeers:
type: integer
Filename:
description: 'the filename of the config file, for example: wg0.conf'
type: string
FirewallMark:
description: a firewall mark
type: integer
@ -256,6 +259,9 @@ definitions:
items:
type: string
type: array
Filename:
description: 'the filename of the config file, for example: wg_peer_x.conf'
type: string
FirewallMark:
allOf:
- $ref: '#/definitions/model.ConfigOption-uint32'

View File

@ -1531,6 +1531,13 @@
"type": "integer",
"readOnly": true
},
"Filename": {
"description": "Filename is the name of the config file for this interface.\nThis value is read only and is not settable by the user.",
"type": "string",
"maxLength": 21,
"readOnly": true,
"example": "wg0.conf"
},
"FirewallMark": {
"description": "FirewallMark is an optional firewall mark which is used to handle interface traffic.",
"type": "integer"
@ -1799,6 +1806,13 @@
"type": "string"
}
},
"Filename": {
"description": "Filename is the name of the config file for this peer.\nThis value is read only and is not settable by the user.",
"type": "string",
"maxLength": 21,
"readOnly": true,
"example": "wg_peer_x.conf"
},
"FirewallMark": {
"description": "FirewallMark is an optional firewall mark which is used to handle peer traffic.",
"allOf": [

View File

@ -87,6 +87,14 @@ definitions:
Only enabled peers are able to connect.
readOnly: true
type: integer
Filename:
description: |-
Filename is the name of the config file for this interface.
This value is read only and is not settable by the user.
example: wg0.conf
maxLength: 21
readOnly: true
type: string
FirewallMark:
description: FirewallMark is an optional firewall mark which is used to handle
interface traffic.
@ -310,6 +318,14 @@ definitions:
items:
type: string
type: array
Filename:
description: |-
Filename is the name of the config file for this peer.
This value is read only and is not settable by the user.
example: wg_peer_x.conf
maxLength: 21
readOnly: true
type: string
FirewallMark:
allOf:
- $ref: '#/definitions/models.ConfigOption-uint32'

View File

@ -49,6 +49,7 @@ type Interface struct {
EnabledPeers int `json:"EnabledPeers"`
TotalPeers int `json:"TotalPeers"`
Filename string `json:"Filename"` // the filename of the config file, for example: wg0.conf
}
func NewInterface(src *domain.Interface, peers []domain.Peer) *Interface {
@ -88,6 +89,7 @@ func NewInterface(src *domain.Interface, peers []domain.Peer) *Interface {
EnabledPeers: 0,
TotalPeers: 0,
Filename: src.GetConfigFileName(),
}
if len(peers) > 0 {

View File

@ -73,6 +73,10 @@ type Peer struct {
PostUp ConfigOption[string] `json:"PostUp"` // action that is executed after the device is up
PreDown ConfigOption[string] `json:"PreDown"` // action that is executed before the device is down
PostDown ConfigOption[string] `json:"PostDown"` // action that is executed after the device is down
// Calculated values
Filename string `json:"Filename"` // the filename of the config file, for example: wg_peer_x.conf
}
func NewPeer(src *domain.Peer) *Peer {
@ -105,6 +109,7 @@ func NewPeer(src *domain.Peer) *Peer {
PostUp: ConfigOptionFromDomain(src.Interface.PostUp),
PreDown: ConfigOptionFromDomain(src.Interface.PreDown),
PostDown: ConfigOptionFromDomain(src.Interface.PostDown),
Filename: src.GetConfigFileName(),
}
}

View File

@ -84,6 +84,9 @@ type Interface struct {
EnabledPeers int `json:"EnabledPeers" readonly:"true"`
// TotalPeers is the total number of peers for this interface.
TotalPeers int `json:"TotalPeers" readonly:"true"`
// Filename is the name of the config file for this interface.
// This value is read only and is not settable by the user.
Filename string `json:"Filename" example:"wg0.conf" binding:"omitempty,max=21" readonly:"true"`
}
func NewInterface(src *domain.Interface, peers []domain.Peer) *Interface {
@ -123,6 +126,7 @@ func NewInterface(src *domain.Interface, peers []domain.Peer) *Interface {
EnabledPeers: 0,
TotalPeers: 0,
Filename: src.GetConfigFileName(),
}
if len(peers) > 0 {

View File

@ -72,6 +72,10 @@ type Peer struct {
PreDown ConfigOption[string] `json:"PreDown"`
// PostDown is an optional action that is executed after the device is down.
PostDown ConfigOption[string] `json:"PostDown"`
// Filename is the name of the config file for this peer.
// This value is read only and is not settable by the user.
Filename string `json:"Filename" example:"wg_peer_x.conf" binding:"omitempty,max=21" readonly:"true"`
}
func NewPeer(src *domain.Peer) *Peer {
@ -109,6 +113,7 @@ func NewPeer(src *domain.Peer) *Peer {
PostUp: ConfigOptionFromDomain(src.Interface.PostUp),
PreDown: ConfigOptionFromDomain(src.Interface.PreDown),
PostDown: ConfigOptionFromDomain(src.Interface.PostDown),
Filename: src.GetConfigFileName(),
}
}

View File

@ -121,8 +121,8 @@ func (i *Interface) CopyCalculatedAttributes(src *Interface) {
}
func (i *Interface) GetConfigFileName() string {
filename := internal.TruncateString(string(i.Identifier), 8)
filename = allowedFileNameRegex.ReplaceAllString(filename, "")
filename := allowedFileNameRegex.ReplaceAllString(string(i.Identifier), "")
filename = internal.TruncateString(filename, 16)
filename += ".conf"
return filename

View File

@ -3,7 +3,6 @@ package domain
import (
"fmt"
"net"
"regexp"
"strings"
"time"
@ -87,17 +86,19 @@ func (p *Peer) CopyCalculatedAttributes(src *Peer) {
func (p *Peer) GetConfigFileName() string {
filename := ""
reg := regexp.MustCompile("[^a-zA-Z0-9-_]+")
if p.DisplayName != "" {
filename = p.DisplayName
filename = strings.ReplaceAll(filename, " ", "_")
filename = reg.ReplaceAllString(filename, "")
// Eliminate the automatically detected peer part,
// as it makes the filename indistinguishable among multiple auto-detected peers.
filename = strings.ReplaceAll(filename, "Autodetected_", "")
filename = allowedFileNameRegex.ReplaceAllString(filename, "")
filename = internal.TruncateString(filename, 16)
filename += ".conf"
} else {
filename = fmt.Sprintf("wg_%s", internal.TruncateString(string(p.Identifier), 8))
filename = reg.ReplaceAllString(filename, "")
filename = allowedFileNameRegex.ReplaceAllString(filename, "")
filename += ".conf"
}