mirror of
https://github.com/Myzel394/config-lsp.git
synced 2025-06-18 15:05:28 +02:00
feat(wireguard): Add code action: Create peer like this
This commit is contained in:
parent
3857bd5694
commit
15ce5958da
@ -22,7 +22,7 @@ func analyzeDNSPropertyContainsFallback(
|
|||||||
|
|
||||||
interfaceSection := sections[0]
|
interfaceSection := sections[0]
|
||||||
|
|
||||||
property := interfaceSection.FindFirstPropertyByName("DNS")
|
_, property := interfaceSection.FindFirstPropertyByName("DNS")
|
||||||
|
|
||||||
if property == nil {
|
if property == nil {
|
||||||
return
|
return
|
||||||
@ -44,7 +44,10 @@ func analyzeKeepAlivePropertyIsSet(
|
|||||||
) {
|
) {
|
||||||
for _, section := range ctx.document.Indexes.SectionsByName["Peer"] {
|
for _, section := range ctx.document.Indexes.SectionsByName["Peer"] {
|
||||||
// If an endpoint is set, then we should only check for the keepalive property
|
// If an endpoint is set, then we should only check for the keepalive property
|
||||||
if section.FindFirstPropertyByName("Endpoint") != nil && section.FindFirstPropertyByName("PersistentKeepalive") == nil {
|
_, endpoint := section.FindFirstPropertyByName("Endpoint")
|
||||||
|
_, persistentKeepAlive := section.FindFirstPropertyByName("PersistentKeepalive")
|
||||||
|
|
||||||
|
if endpoint != nil && persistentKeepAlive == nil {
|
||||||
ctx.diagnostics = append(ctx.diagnostics, protocol.Diagnostic{
|
ctx.diagnostics = append(ctx.diagnostics, protocol.Diagnostic{
|
||||||
Message: "PersistentKeepalive is not set. It is recommended to set this property, as it helps to maintain the connection when users are behind NAT",
|
Message: "PersistentKeepalive is not set. It is recommended to set this property, as it helps to maintain the connection when users are behind NAT",
|
||||||
Severity: &common.SeverityHint,
|
Severity: &common.SeverityHint,
|
||||||
@ -58,11 +61,11 @@ func analyzeSymmetricPropertiesSet(
|
|||||||
ctx *analyzerContext,
|
ctx *analyzerContext,
|
||||||
) {
|
) {
|
||||||
for _, section := range ctx.document.Indexes.SectionsByName["Interface"] {
|
for _, section := range ctx.document.Indexes.SectionsByName["Interface"] {
|
||||||
preUpProperty := section.FindFirstPropertyByName("PreUp")
|
_, preUpProperty := section.FindFirstPropertyByName("PreUp")
|
||||||
preDownProperty := section.FindFirstPropertyByName("PreDown")
|
_, preDownProperty := section.FindFirstPropertyByName("PreDown")
|
||||||
|
|
||||||
postUpProperty := section.FindFirstPropertyByName("PostUp")
|
_, postUpProperty := section.FindFirstPropertyByName("PostUp")
|
||||||
postDownProperty := section.FindFirstPropertyByName("PostDown")
|
_, postDownProperty := section.FindFirstPropertyByName("PostDown")
|
||||||
|
|
||||||
if preUpProperty != nil && preDownProperty == nil {
|
if preUpProperty != nil && preDownProperty == nil {
|
||||||
ctx.diagnostics = append(ctx.diagnostics, protocol.Diagnostic{
|
ctx.diagnostics = append(ctx.diagnostics, protocol.Diagnostic{
|
||||||
@ -94,7 +97,7 @@ func analyzeSymmetricPropertiesSet(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type key int
|
type key uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
lineKey key = iota
|
lineKey key = iota
|
||||||
@ -109,7 +112,7 @@ func analyzeDuplicateAllowedIPs(
|
|||||||
ipHostSet := utils.CreateIPv4HostSet()
|
ipHostSet := utils.CreateIPv4HostSet()
|
||||||
|
|
||||||
for _, section := range ctx.document.Indexes.SectionsByName["Peer"] {
|
for _, section := range ctx.document.Indexes.SectionsByName["Peer"] {
|
||||||
property := section.FindFirstPropertyByName("AllowedIPs")
|
_, property := section.FindFirstPropertyByName("AllowedIPs")
|
||||||
|
|
||||||
if property == nil {
|
if property == nil {
|
||||||
continue
|
continue
|
||||||
@ -123,12 +126,15 @@ func analyzeDuplicateAllowedIPs(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ipContext, _ := ipHostSet.ContainsIP(ipAddress); ipContext != nil {
|
if ipContext, _ := ipHostSet.ContainsIP(ipAddress); ipContext != nil {
|
||||||
definedLine := (*ipContext).Value(lineKey).(uint32)
|
ctxx := *ipContext
|
||||||
|
definedLineRaw := ctxx.Value(lineKey)
|
||||||
|
|
||||||
|
definedLine := definedLineRaw.(uint32)
|
||||||
|
|
||||||
ctx.diagnostics = append(ctx.diagnostics, protocol.Diagnostic{
|
ctx.diagnostics = append(ctx.diagnostics, protocol.Diagnostic{
|
||||||
Message: fmt.Sprintf("This IP range is already covered on line %d", definedLine+1),
|
Message: fmt.Sprintf("This IP range is already covered on line %d", definedLine+1),
|
||||||
Severity: &common.SeverityError,
|
Severity: &common.SeverityError,
|
||||||
Range: property.ToLSPRange(),
|
Range: property.Value.ToLSPRange(),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
ipContext := context.WithValue(
|
ipContext := context.WithValue(
|
||||||
|
@ -35,7 +35,7 @@ type WGHeader struct {
|
|||||||
type WGSection struct {
|
type WGSection struct {
|
||||||
common.LocationRange
|
common.LocationRange
|
||||||
Header WGHeader
|
Header WGHeader
|
||||||
// [uint32]WGProperty: line number -> WGProperty
|
// [uint32]*WGProperty: line number -> *WGProperty
|
||||||
Properties *treemap.Map
|
Properties *treemap.Map
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,11 +10,11 @@ func (c *WGConfig) FindSectionByLine(line uint32) *WGSection {
|
|||||||
line,
|
line,
|
||||||
func(current *WGSection, target uint32) int {
|
func(current *WGSection, target uint32) int {
|
||||||
if target < current.Start.Line {
|
if target < current.Start.Line {
|
||||||
return -1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if target > current.End.Line {
|
if target > current.End.Line {
|
||||||
return 1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
@ -42,28 +42,17 @@ func (c *WGConfig) FindPropertyByLine(line uint32) *WGProperty {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *WGSection) FindFirstPropertyByName(name string) *WGProperty {
|
func (s *WGSection) FindFirstPropertyByName(name string) (uint32, *WGProperty) {
|
||||||
it := s.Properties.Iterator()
|
it := s.Properties.Iterator()
|
||||||
for it.Next() {
|
for it.Next() {
|
||||||
|
line := it.Key().(uint32)
|
||||||
property := it.Value().(*WGProperty)
|
property := it.Value().(*WGProperty)
|
||||||
if property.Key.Name == name {
|
if property.Key.Name == name {
|
||||||
return property
|
return line, property
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return 0, nil
|
||||||
}
|
|
||||||
|
|
||||||
func (s *WGSection) FindPropertyByName(name string) *WGProperty {
|
|
||||||
it := s.Properties.Iterator()
|
|
||||||
for it.Next() {
|
|
||||||
property := it.Value().(*WGProperty)
|
|
||||||
if property.Key.Name == name {
|
|
||||||
return property
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *WGSection) GetLastProperty() *WGProperty {
|
func (s *WGSection) GetLastProperty() *WGProperty {
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"config-lsp/handlers/wireguard"
|
|
||||||
"config-lsp/handlers/wireguard/ast"
|
"config-lsp/handlers/wireguard/ast"
|
||||||
wgcommands "config-lsp/handlers/wireguard/commands"
|
|
||||||
|
|
||||||
protocol "github.com/tliron/glsp/protocol_3_16"
|
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||||
)
|
)
|
||||||
@ -13,6 +11,7 @@ type CodeActionName string
|
|||||||
const (
|
const (
|
||||||
CodeActionGeneratePrivateKey CodeActionName = "generatePrivateKey"
|
CodeActionGeneratePrivateKey CodeActionName = "generatePrivateKey"
|
||||||
CodeActionGeneratePresharedKey CodeActionName = "generatePresharedKey"
|
CodeActionGeneratePresharedKey CodeActionName = "generatePresharedKey"
|
||||||
|
CodeActionCreatePeer CodeActionName = "createPeer"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CodeAction interface {
|
type CodeAction interface {
|
||||||
@ -20,105 +19,3 @@ type CodeAction interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type CodeActionArgs interface{}
|
type CodeActionArgs interface{}
|
||||||
|
|
||||||
type CodeActionGeneratePrivateKeyArgs struct {
|
|
||||||
URI protocol.DocumentUri
|
|
||||||
Line uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func CodeActionGeneratePrivateKeyArgsFromArguments(arguments map[string]any) CodeActionGeneratePrivateKeyArgs {
|
|
||||||
return CodeActionGeneratePrivateKeyArgs{
|
|
||||||
URI: arguments["URI"].(protocol.DocumentUri),
|
|
||||||
Line: uint32(arguments["Line"].(float64)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (args CodeActionGeneratePrivateKeyArgs) RunCommand(d *wireguard.WGDocument) (*protocol.ApplyWorkspaceEditParams, error) {
|
|
||||||
privateKey, err := wgcommands.CreateNewPrivateKey()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return &protocol.ApplyWorkspaceEditParams{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
section := d.Config.FindSectionByLine(args.Line)
|
|
||||||
property := d.Config.FindPropertyByLine(args.Line)
|
|
||||||
|
|
||||||
if section == nil || property == nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
label := "Generate Private Key"
|
|
||||||
return &protocol.ApplyWorkspaceEditParams{
|
|
||||||
Label: &label,
|
|
||||||
Edit: protocol.WorkspaceEdit{
|
|
||||||
Changes: map[protocol.DocumentUri][]protocol.TextEdit{
|
|
||||||
args.URI: {
|
|
||||||
{
|
|
||||||
NewText: " " + privateKey,
|
|
||||||
Range: protocol.Range{
|
|
||||||
Start: protocol.Position{
|
|
||||||
Line: property.End.Line,
|
|
||||||
Character: property.End.Character,
|
|
||||||
},
|
|
||||||
End: protocol.Position{
|
|
||||||
Line: property.End.Line,
|
|
||||||
Character: property.End.Character,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type CodeActionGeneratePresharedKeyArgs struct {
|
|
||||||
URI protocol.DocumentUri
|
|
||||||
Line uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func CodeActionGeneratePresharedKeyArgsFromArguments(arguments map[string]any) CodeActionGeneratePresharedKeyArgs {
|
|
||||||
return CodeActionGeneratePresharedKeyArgs{
|
|
||||||
URI: arguments["URI"].(protocol.DocumentUri),
|
|
||||||
Line: uint32(arguments["Line"].(float64)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (args CodeActionGeneratePresharedKeyArgs) RunCommand(d *wireguard.WGDocument) (*protocol.ApplyWorkspaceEditParams, error) {
|
|
||||||
presharedKey, err := wgcommands.CreatePresharedKey()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return &protocol.ApplyWorkspaceEditParams{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
section := d.Config.FindSectionByLine(args.Line)
|
|
||||||
property := d.Config.FindPropertyByLine(args.Line)
|
|
||||||
|
|
||||||
if section == nil || property == nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
label := "Generate Preshared Key"
|
|
||||||
return &protocol.ApplyWorkspaceEditParams{
|
|
||||||
Label: &label,
|
|
||||||
Edit: protocol.WorkspaceEdit{
|
|
||||||
Changes: map[protocol.DocumentUri][]protocol.TextEdit{
|
|
||||||
args.URI: {
|
|
||||||
{
|
|
||||||
NewText: " " + presharedKey,
|
|
||||||
Range: protocol.Range{
|
|
||||||
Start: protocol.Position{
|
|
||||||
Line: property.End.Line,
|
|
||||||
Character: property.End.Character,
|
|
||||||
},
|
|
||||||
End: protocol.Position{
|
|
||||||
Line: property.End.Line,
|
|
||||||
Character: property.End.Character,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
191
server/handlers/wireguard/handlers/code-actions_create-peer.go
Normal file
191
server/handlers/wireguard/handlers/code-actions_create-peer.go
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"config-lsp/common"
|
||||||
|
"config-lsp/handlers/wireguard"
|
||||||
|
"config-lsp/handlers/wireguard/ast"
|
||||||
|
wgcommands "config-lsp/handlers/wireguard/commands"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CodeActionCreatePeerArgs struct {
|
||||||
|
URI protocol.DocumentUri
|
||||||
|
Line uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func CodeActionCreatePeerArgsFromArguments(arguments map[string]any) CodeActionCreatePeerArgs {
|
||||||
|
return CodeActionCreatePeerArgs{
|
||||||
|
URI: arguments["URI"].(protocol.DocumentUri),
|
||||||
|
Line: uint32(arguments["Line"].(float64)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (args CodeActionCreatePeerArgs) RunCommand(d *wireguard.WGDocument) (*protocol.ApplyWorkspaceEditParams, error) {
|
||||||
|
interfaceSection := d.Indexes.SectionsByName["Interface"][0]
|
||||||
|
section := d.Config.FindSectionByLine(args.Line)
|
||||||
|
|
||||||
|
label := fmt.Sprintf("Add Peer based on peer on line %d", args.Line)
|
||||||
|
|
||||||
|
newSection := section
|
||||||
|
|
||||||
|
// IP Address
|
||||||
|
ipAddressLine, ipAddress := newSection.FindFirstPropertyByName("AllowedIPs")
|
||||||
|
_, address := interfaceSection.FindFirstPropertyByName("Address")
|
||||||
|
if ipAddress != nil && address != nil {
|
||||||
|
_, network, err := net.ParseCIDR(address.Value.Value)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
newIPAddress := createNewIP(*network, ipAddress.Value.Value)
|
||||||
|
|
||||||
|
valueEnd := common.Location{
|
||||||
|
Line: ipAddress.End.Line,
|
||||||
|
Character: ipAddress.Value.Start.Character + uint32(len(newIPAddress)) + 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
newSection.Properties.Put(
|
||||||
|
ipAddressLine,
|
||||||
|
&ast.WGProperty{
|
||||||
|
LocationRange: common.LocationRange{
|
||||||
|
Start: ipAddress.Start,
|
||||||
|
End: valueEnd,
|
||||||
|
},
|
||||||
|
Key: ipAddress.Key,
|
||||||
|
RawValue: newIPAddress,
|
||||||
|
Separator: address.Separator,
|
||||||
|
Value: &ast.WGPropertyValue{
|
||||||
|
LocationRange: common.LocationRange{
|
||||||
|
Start: ipAddress.Value.Start,
|
||||||
|
End: valueEnd,
|
||||||
|
},
|
||||||
|
Value: newIPAddress,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preshared Key
|
||||||
|
presharedKeyLine, presharedKey := newSection.FindFirstPropertyByName("PresharedKey")
|
||||||
|
|
||||||
|
if presharedKey != nil {
|
||||||
|
var newKey string
|
||||||
|
|
||||||
|
if wgcommands.AreWireguardToolsAvailable() {
|
||||||
|
createdKey, err := wgcommands.CreatePresharedKey()
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
newKey = createdKey
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newKey = "[preshared key]"
|
||||||
|
}
|
||||||
|
|
||||||
|
valueEnd := common.Location{
|
||||||
|
Line: presharedKey.End.Line,
|
||||||
|
Character: presharedKey.Value.Start.Character + uint32(len(newKey)) + 1,
|
||||||
|
}
|
||||||
|
newSection.Properties.Put(
|
||||||
|
presharedKeyLine,
|
||||||
|
&ast.WGProperty{
|
||||||
|
LocationRange: common.LocationRange{
|
||||||
|
Start: presharedKey.Start,
|
||||||
|
End: valueEnd,
|
||||||
|
},
|
||||||
|
Key: presharedKey.Key,
|
||||||
|
RawValue: newKey,
|
||||||
|
Separator: presharedKey.Separator,
|
||||||
|
Value: &ast.WGPropertyValue{
|
||||||
|
LocationRange: common.LocationRange{
|
||||||
|
Start: presharedKey.Value.Start,
|
||||||
|
End: valueEnd,
|
||||||
|
},
|
||||||
|
Value: newKey,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
lastProperty := newSection.GetLastProperty()
|
||||||
|
println("last line")
|
||||||
|
println(lastProperty.End.Line)
|
||||||
|
println(fmt.Sprintf("~~~%s~~~", writeSection(*newSection)))
|
||||||
|
newText := writeSection(*newSection)
|
||||||
|
return &protocol.ApplyWorkspaceEditParams{
|
||||||
|
Label: &label,
|
||||||
|
Edit: protocol.WorkspaceEdit{
|
||||||
|
Changes: map[protocol.DocumentUri][]protocol.TextEdit{
|
||||||
|
args.URI: {
|
||||||
|
{
|
||||||
|
Range: protocol.Range{
|
||||||
|
Start: protocol.Position{
|
||||||
|
Line: lastProperty.End.Line,
|
||||||
|
Character: lastProperty.End.Character,
|
||||||
|
},
|
||||||
|
End: protocol.Position{
|
||||||
|
Line: lastProperty.End.Line,
|
||||||
|
Character: lastProperty.End.Character,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
NewText: newText,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeSection(section ast.WGSection) string {
|
||||||
|
text := "\n\n"
|
||||||
|
|
||||||
|
text += fmt.Sprintf("[%s]\n", section.Header.Name)
|
||||||
|
|
||||||
|
it := section.Properties.Iterator()
|
||||||
|
for it.Next() {
|
||||||
|
property := it.Value().(*ast.WGProperty)
|
||||||
|
text += fmt.Sprintf("%s = %s\n", property.Key.Name, property.Value.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try incrementing the IP address
|
||||||
|
func createNewIP(
|
||||||
|
network net.IPNet,
|
||||||
|
rawIP string,
|
||||||
|
) string {
|
||||||
|
parsedIP, _, err := net.ParseCIDR(rawIP)
|
||||||
|
parsedIP = parsedIP.To4()
|
||||||
|
|
||||||
|
if parsedIP == nil {
|
||||||
|
// IPv6 is not supported
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
lastAddress := uint32(network.IP[0])<<24 | uint32(network.IP[1])<<16 | uint32(network.IP[2])<<8 | uint32(network.IP[3])
|
||||||
|
|
||||||
|
networkMask, _ := network.Mask.Size()
|
||||||
|
for index := range 32 - networkMask {
|
||||||
|
lastAddress |= 1 << index
|
||||||
|
}
|
||||||
|
|
||||||
|
newIP := uint32(parsedIP[0])<<24 | uint32(parsedIP[1])<<16 | uint32(parsedIP[2])<<8 | uint32(parsedIP[3])
|
||||||
|
newIP += 1
|
||||||
|
|
||||||
|
if newIP >= lastAddress || newIP == 0 {
|
||||||
|
// The IP is the last one, which can't be used
|
||||||
|
// or even worse, it did a whole overflow
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Here, we successfully incremented the IP correctly
|
||||||
|
|
||||||
|
// Let's return the formatted IP now.
|
||||||
|
return fmt.Sprintf("%d.%d.%d.%d/32", newIP>>24, newIP>>16&0xFF, newIP>>8&0xFF, newIP&0xFF)
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCreateNewIPSimple24Mask(t *testing.T) {
|
||||||
|
_, network, _ := net.ParseCIDR("10.0.0.0/24")
|
||||||
|
newIP := createNewIP(*network, "10.0.0.1/32")
|
||||||
|
|
||||||
|
if newIP != "10.0.0.2/32" {
|
||||||
|
t.Errorf("Expected 10.0.0.2/32, got %s", newIP)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateNewIPDoesNotWorkWithLast24Mask(t *testing.T) {
|
||||||
|
_, network, _ := net.ParseCIDR("10.0.0.0/24")
|
||||||
|
newIP := createNewIP(*network, "10.0.0.254/32")
|
||||||
|
|
||||||
|
if newIP != "" {
|
||||||
|
t.Errorf("Expected empty string, got %s", newIP)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateNewIPDoesNotWorkWithLast24Mask2(t *testing.T) {
|
||||||
|
_, network, _ := net.ParseCIDR("10.0.0.0/24")
|
||||||
|
newIP := createNewIP(*network, "10.0.0.255/32")
|
||||||
|
|
||||||
|
if newIP != "" {
|
||||||
|
t.Errorf("Expected empty string, got %s", newIP)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateNewIPComplex20Mask(t *testing.T) {
|
||||||
|
_, network, _ := net.ParseCIDR("10.0.0.0/20")
|
||||||
|
newIP := createNewIP(*network, "10.0.0.255/32")
|
||||||
|
|
||||||
|
if newIP != "10.0.1.0/32" {
|
||||||
|
t.Errorf("Expected 10.0.1.0/32, got %s", newIP)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"config-lsp/handlers/wireguard"
|
||||||
|
wgcommands "config-lsp/handlers/wireguard/commands"
|
||||||
|
|
||||||
|
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CodeActionGeneratePrivateKeyArgs struct {
|
||||||
|
URI protocol.DocumentUri
|
||||||
|
Line uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func CodeActionGeneratePrivateKeyArgsFromArguments(arguments map[string]any) CodeActionGeneratePrivateKeyArgs {
|
||||||
|
return CodeActionGeneratePrivateKeyArgs{
|
||||||
|
URI: arguments["URI"].(protocol.DocumentUri),
|
||||||
|
Line: uint32(arguments["Line"].(float64)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (args CodeActionGeneratePrivateKeyArgs) RunCommand(d *wireguard.WGDocument) (*protocol.ApplyWorkspaceEditParams, error) {
|
||||||
|
privateKey, err := wgcommands.CreateNewPrivateKey()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return &protocol.ApplyWorkspaceEditParams{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
section := d.Config.FindSectionByLine(args.Line)
|
||||||
|
property := d.Config.FindPropertyByLine(args.Line)
|
||||||
|
|
||||||
|
if section == nil || property == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
label := "Generate Private Key"
|
||||||
|
return &protocol.ApplyWorkspaceEditParams{
|
||||||
|
Label: &label,
|
||||||
|
Edit: protocol.WorkspaceEdit{
|
||||||
|
Changes: map[protocol.DocumentUri][]protocol.TextEdit{
|
||||||
|
args.URI: {
|
||||||
|
{
|
||||||
|
NewText: " " + privateKey,
|
||||||
|
Range: protocol.Range{
|
||||||
|
Start: protocol.Position{
|
||||||
|
Line: property.End.Line,
|
||||||
|
Character: property.End.Character,
|
||||||
|
},
|
||||||
|
End: protocol.Position{
|
||||||
|
Line: property.End.Line,
|
||||||
|
Character: property.End.Character,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"config-lsp/handlers/wireguard"
|
||||||
|
wgcommands "config-lsp/handlers/wireguard/commands"
|
||||||
|
|
||||||
|
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CodeActionGeneratePresharedKeyArgs struct {
|
||||||
|
URI protocol.DocumentUri
|
||||||
|
Line uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func CodeActionGeneratePresharedKeyArgsFromArguments(arguments map[string]any) CodeActionGeneratePresharedKeyArgs {
|
||||||
|
return CodeActionGeneratePresharedKeyArgs{
|
||||||
|
URI: arguments["URI"].(protocol.DocumentUri),
|
||||||
|
Line: uint32(arguments["Line"].(float64)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (args CodeActionGeneratePresharedKeyArgs) RunCommand(d *wireguard.WGDocument) (*protocol.ApplyWorkspaceEditParams, error) {
|
||||||
|
presharedKey, err := wgcommands.CreatePresharedKey()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return &protocol.ApplyWorkspaceEditParams{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
section := d.Config.FindSectionByLine(args.Line)
|
||||||
|
property := d.Config.FindPropertyByLine(args.Line)
|
||||||
|
|
||||||
|
if section == nil || property == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
label := "Generate Preshared Key"
|
||||||
|
return &protocol.ApplyWorkspaceEditParams{
|
||||||
|
Label: &label,
|
||||||
|
Edit: protocol.WorkspaceEdit{
|
||||||
|
Changes: map[protocol.DocumentUri][]protocol.TextEdit{
|
||||||
|
args.URI: {
|
||||||
|
{
|
||||||
|
NewText: presharedKey,
|
||||||
|
Range: property.Value.ToLSPRange(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"config-lsp/handlers/wireguard"
|
||||||
|
|
||||||
|
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetAddPeerLikeThis(
|
||||||
|
d *wireguard.WGDocument,
|
||||||
|
params *protocol.CodeActionParams,
|
||||||
|
) []protocol.CodeAction {
|
||||||
|
// First, check if is on peer line
|
||||||
|
|
||||||
|
line := params.Range.Start.Line
|
||||||
|
|
||||||
|
section := d.Config.FindSectionByLine(line)
|
||||||
|
|
||||||
|
// Check if section can be copied
|
||||||
|
if section == nil || section.Start.Line != line || section.Header.Name != "Peer" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then add option
|
||||||
|
commandID := "wireguard." + CodeActionCreatePeer
|
||||||
|
command := protocol.Command{
|
||||||
|
Title: "Create new Peer based on this one",
|
||||||
|
Command: string(commandID),
|
||||||
|
Arguments: []any{
|
||||||
|
CodeActionCreatePeerArgs{
|
||||||
|
URI: params.TextDocument.URI,
|
||||||
|
Line: line,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return []protocol.CodeAction{
|
||||||
|
{
|
||||||
|
Title: "Create new Peer based on this one",
|
||||||
|
Command: &command,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"config-lsp/handlers/wireguard"
|
||||||
|
|
||||||
|
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetKeepaliveCodeActions(
|
||||||
|
d *wireguard.WGDocument,
|
||||||
|
params *protocol.CodeActionParams,
|
||||||
|
) []protocol.CodeAction {
|
||||||
|
line := params.Range.Start.Line
|
||||||
|
|
||||||
|
for _, section := range d.Indexes.SectionsByName["Peer"] {
|
||||||
|
if section.Start.Line >= line && line <= section.End.Line {
|
||||||
|
_, endpoint := section.FindFirstPropertyByName("Endpoint")
|
||||||
|
_, persistentKeepAlive := section.FindFirstPropertyByName("PersistentKeepalive")
|
||||||
|
|
||||||
|
if endpoint != nil && persistentKeepAlive == nil {
|
||||||
|
var insertionLine uint32
|
||||||
|
lastProperty := section.GetLastProperty()
|
||||||
|
|
||||||
|
if lastProperty == nil {
|
||||||
|
insertionLine = section.End.Line
|
||||||
|
} else {
|
||||||
|
insertionLine = lastProperty.End.Line + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return []protocol.CodeAction{
|
||||||
|
{
|
||||||
|
Title: "Add PersistentKeepalive",
|
||||||
|
Edit: &protocol.WorkspaceEdit{
|
||||||
|
Changes: map[protocol.DocumentUri][]protocol.TextEdit{
|
||||||
|
params.TextDocument.URI: {
|
||||||
|
{
|
||||||
|
Range: protocol.Range{
|
||||||
|
Start: protocol.Position{
|
||||||
|
Line: insertionLine,
|
||||||
|
Character: 0,
|
||||||
|
},
|
||||||
|
End: protocol.Position{
|
||||||
|
Line: insertionLine,
|
||||||
|
Character: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
NewText: "PersistentKeepalive = 25\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -7,55 +7,6 @@ import (
|
|||||||
protocol "github.com/tliron/glsp/protocol_3_16"
|
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetKeepaliveCodeActions(
|
|
||||||
d *wireguard.WGDocument,
|
|
||||||
params *protocol.CodeActionParams,
|
|
||||||
) []protocol.CodeAction {
|
|
||||||
line := params.Range.Start.Line
|
|
||||||
|
|
||||||
for _, section := range d.Indexes.SectionsByName["Peer"] {
|
|
||||||
if section.Start.Line >= line && line <= section.End.Line {
|
|
||||||
if section.FindPropertyByName("Endpoint") != nil && section.FindFirstPropertyByName("PersistentKeepalive") == nil {
|
|
||||||
var insertionLine uint32
|
|
||||||
lastProperty := section.GetLastProperty()
|
|
||||||
|
|
||||||
if lastProperty == nil {
|
|
||||||
insertionLine = section.End.Line
|
|
||||||
} else {
|
|
||||||
insertionLine = lastProperty.End.Line + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
return []protocol.CodeAction{
|
|
||||||
{
|
|
||||||
Title: "Add PersistentKeepalive",
|
|
||||||
Edit: &protocol.WorkspaceEdit{
|
|
||||||
Changes: map[protocol.DocumentUri][]protocol.TextEdit{
|
|
||||||
params.TextDocument.URI: {
|
|
||||||
{
|
|
||||||
Range: protocol.Range{
|
|
||||||
Start: protocol.Position{
|
|
||||||
Line: insertionLine,
|
|
||||||
Character: 0,
|
|
||||||
},
|
|
||||||
End: protocol.Position{
|
|
||||||
Line: insertionLine,
|
|
||||||
Character: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
NewText: "PersistentKeepalive = 25\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetKeyGenerationCodeActions(
|
func GetKeyGenerationCodeActions(
|
||||||
d *wireguard.WGDocument,
|
d *wireguard.WGDocument,
|
||||||
params *protocol.CodeActionParams,
|
params *protocol.CodeActionParams,
|
@ -15,6 +15,7 @@ func TextDocumentCodeAction(context *glsp.Context, params *protocol.CodeActionPa
|
|||||||
|
|
||||||
actions = append(actions, handlers.GetKeyGenerationCodeActions(d, params)...)
|
actions = append(actions, handlers.GetKeyGenerationCodeActions(d, params)...)
|
||||||
actions = append(actions, handlers.GetKeepaliveCodeActions(d, params)...)
|
actions = append(actions, handlers.GetKeepaliveCodeActions(d, params)...)
|
||||||
|
actions = append(actions, handlers.GetAddPeerLikeThis(d, params)...)
|
||||||
|
|
||||||
if len(actions) > 0 {
|
if len(actions) > 0 {
|
||||||
return actions, nil
|
return actions, nil
|
||||||
|
@ -24,6 +24,12 @@ func WorkspaceExecuteCommand(context *glsp.Context, params *protocol.ExecuteComm
|
|||||||
|
|
||||||
d := wireguard.DocumentParserMap[args.URI]
|
d := wireguard.DocumentParserMap[args.URI]
|
||||||
|
|
||||||
|
return args.RunCommand(d)
|
||||||
|
case string(handlers.CodeActionCreatePeer):
|
||||||
|
args := handlers.CodeActionCreatePeerArgsFromArguments(params.Arguments[0].(map[string]any))
|
||||||
|
|
||||||
|
d := wireguard.DocumentParserMap[args.URI]
|
||||||
|
|
||||||
return args.RunCommand(d)
|
return args.RunCommand(d)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user