feat(wireguard): Add code actions; Add generate private key code action

This commit is contained in:
Myzel394 2024-08-18 21:40:38 +02:00
parent 72a8851a58
commit dc1ccb7e43
No known key found for this signature in database
GPG Key ID: DEC4AAB876F73185
11 changed files with 300 additions and 11 deletions

BIN
config-lsp Executable file

Binary file not shown.

View File

@ -0,0 +1,73 @@
package wireguard
import (
protocol "github.com/tliron/glsp/protocol_3_16"
)
type codeActionName string
const (
codeActionGeneratePrivateKey codeActionName = "generatePrivateKey"
)
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 (p wireguardProperty) getInsertRange(line uint32) protocol.Range {
insertPosition := p.Separator.Location.End
var length uint32 = 0
if p.Value != nil {
// Length of the value
length = p.Value.Location.End - p.Value.Location.Start
}
return protocol.Range{
Start: protocol.Position{
Line: line,
Character: insertPosition,
},
End: protocol.Position{
Line: line,
Character: insertPosition + length,
},
}
}
func (p *wireguardParser) runGeneratePrivateKey(args codeActionGeneratePrivateKeyArgs) (*protocol.ApplyWorkspaceEditParams, error) {
privateKey, err := createNewPrivateKey()
if err != nil {
return &protocol.ApplyWorkspaceEditParams{}, err
}
section, property := p.getPropertyByLine(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: property.getInsertRange(args.Line),
},
},
},
},
}, nil
}

View File

@ -0,0 +1,45 @@
package wireguard
import (
"github.com/tliron/glsp"
protocol "github.com/tliron/glsp/protocol_3_16"
)
func TextDocumentCodeAction(context *glsp.Context, params *protocol.CodeActionParams) ([]protocol.CodeAction, error) {
line := params.Range.Start.Line
parser := documentParserMap[params.TextDocument.URI]
section, property := parser.getPropertyByLine(line)
if section == nil || property == nil || property.Separator == nil {
return nil, nil
}
switch property.Key.Name {
case "PrivateKey":
if !areWireguardToolsAvailable() {
return nil, nil
}
commandID := "wireguard." + codeActionGeneratePrivateKey
command := protocol.Command{
Title: "Generate Private Key",
Command: string(commandID),
Arguments: []any{
codeActionGeneratePrivateKeyArgs{
URI: params.TextDocument.URI,
Line: line,
},
},
}
return []protocol.CodeAction{
{
Title: "Generate Private Key",
Command: &command,
},
}, nil
}
return nil, nil
}

View File

@ -11,8 +11,6 @@ func TextDocumentHover(
context *glsp.Context,
params *protocol.HoverParams,
) (*protocol.Hover, error) {
// cursor := params.Position.Character
parser := documentParserMap[params.TextDocument.URI]
switch parser.getTypeByLine(params.Position.Line) {

View File

@ -0,0 +1,37 @@
package wireguard
import (
"os/exec"
"strings"
)
func areWireguardToolsAvailable() bool {
_, err := exec.LookPath("wg")
return err == nil
}
func createNewPrivateKey() (string, error) {
cmd := exec.Command("wg", "genkey")
bytes, err := cmd.Output()
if err != nil {
return "", err
}
return string(bytes), nil
}
func createPublicKey(privateKey string) (string, error) {
cmd := exec.Command("wg", "pubkey")
cmd.Stdin = strings.NewReader(privateKey)
bytes, err := cmd.Output()
if err != nil {
return "", err
}
return strings.ReplaceAll(string(bytes), "\n", ""), nil
}

View File

@ -327,3 +327,19 @@ func (p *wireguardParser) getBelongingSectionByLine(line uint32) *wireguardSecti
return nil
}
func (p *wireguardParser) getPropertyByLine(line uint32) (*wireguardSection, *wireguardProperty) {
section := p.getSectionByLine(line)
if section.Name == nil {
return nil, nil
}
property, _ := section.findProperty(line)
if property == nil {
return nil, nil
}
return section, property
}

View File

@ -0,0 +1,40 @@
package wireguard
import "testing"
func TestWireguardAvailable(
t *testing.T,
) {
if !areWireguardToolsAvailable() {
t.Skip("Wireguard tools not available")
}
}
func TestWireguardPrivateKey(
t *testing.T,
) {
privateKey, err := createNewPrivateKey()
if err != nil {
t.Fatal(err)
}
t.Log(privateKey)
}
func TestWireguardPublicKey(
t *testing.T,
) {
privateKey := "UPBKR0kLF2C/+Ei5fwN5KHsAcon9xfBX+RWhebYFGWg="
publicKey, err := createPublicKey(privateKey)
if err != nil {
t.Fatal(err)
}
if publicKey != "3IPUqUKXUkkU7tNp/G/KgcBqUh3N0WWJpfQf79lGdl0=" {
t.Fatalf("Public key does not match, it's: %v", publicKey)
}
t.Log(publicKey)
}

View File

@ -0,0 +1,23 @@
package wireguard
import (
"strings"
"github.com/tliron/glsp"
protocol "github.com/tliron/glsp/protocol_3_16"
)
func WorkspaceExecuteCommand(context *glsp.Context, params *protocol.ExecuteCommandParams) (*protocol.ApplyWorkspaceEditParams, error) {
_, command, _ := strings.Cut(params.Command, ".")
switch command {
case string(codeActionGeneratePrivateKey):
args := codeActionGeneratePrivateKeyArgsFromArguments(params.Arguments[0].(map[string]any))
parser := documentParserMap[args.URI]
return parser.runGeneratePrivateKey(args)
}
return nil, nil
}

View File

@ -17,15 +17,17 @@ var lspHandler protocol.Handler
func SetUpRootHandler() {
rootHandler = NewRootHandler()
lspHandler = protocol.Handler{
Initialize: initialize,
Initialized: initialized,
Shutdown: shutdown,
SetTrace: setTrace,
TextDocumentDidOpen: TextDocumentDidOpen,
TextDocumentDidChange: TextDocumentDidChange,
TextDocumentCompletion: TextDocumentCompletion,
TextDocumentHover: TextDocumentHover,
TextDocumentDidClose: TextDocumentDidClose,
Initialize: initialize,
Initialized: initialized,
Shutdown: shutdown,
SetTrace: setTrace,
TextDocumentDidOpen: TextDocumentDidOpen,
TextDocumentDidChange: TextDocumentDidChange,
TextDocumentCompletion: TextDocumentCompletion,
TextDocumentHover: TextDocumentHover,
TextDocumentDidClose: TextDocumentDidClose,
TextDocumentCodeAction: TextDocumentCodeAction,
WorkspaceExecuteCommand: WorkspaceExecuteCommand,
}
server := server.NewServer(&lspHandler, lsName, false)

View File

@ -0,0 +1,23 @@
package roothandler
import (
"config-lsp/handlers/wireguard"
"github.com/tliron/glsp"
protocol "github.com/tliron/glsp/protocol_3_16"
)
func TextDocumentCodeAction(context *glsp.Context, params *protocol.CodeActionParams) (any, error) {
language := rootHandler.GetLanguageForDocument(params.TextDocument.URI)
switch language {
case LanguageFstab:
return nil, nil
case LanguageSSHDConfig:
return nil, nil
case LanguageWireguard:
return wireguard.TextDocumentCodeAction(context, params)
}
panic("root-handler/TextDocumentCompletion: unexpected language" + language)
}

View File

@ -0,0 +1,32 @@
package roothandler
import (
"config-lsp/handlers/wireguard"
"strings"
"github.com/tliron/glsp"
protocol "github.com/tliron/glsp/protocol_3_16"
)
func WorkspaceExecuteCommand(context *glsp.Context, params *protocol.ExecuteCommandParams) (any, error) {
commandSection, _, _ := strings.Cut(params.Command, ".")
var edit *protocol.ApplyWorkspaceEditParams
var err error
switch commandSection {
case "wireguard":
edit, err = wireguard.WorkspaceExecuteCommand(context, params)
}
if err != nil {
return nil, err
}
context.Notify(
"workspace/applyEdit",
edit,
)
return nil, nil
}