mirror of
https://github.com/Myzel394/config-lsp.git
synced 2025-06-19 07:25:27 +02:00
feat(sshd_config): Add indexes
This commit is contained in:
parent
47c511996b
commit
998c0740d1
@ -3,6 +3,7 @@ package analyzer
|
|||||||
import (
|
import (
|
||||||
"config-lsp/common"
|
"config-lsp/common"
|
||||||
"config-lsp/handlers/sshd_config"
|
"config-lsp/handlers/sshd_config"
|
||||||
|
"config-lsp/handlers/sshd_config/indexes"
|
||||||
"config-lsp/utils"
|
"config-lsp/utils"
|
||||||
|
|
||||||
protocol "github.com/tliron/glsp/protocol_3_16"
|
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||||
@ -22,5 +23,19 @@ func Analyze(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
indexes, indexErrors := indexes.CreateIndexes(*d.Config)
|
||||||
|
_ = indexes
|
||||||
|
|
||||||
|
errors = append(errors, indexErrors...)
|
||||||
|
|
||||||
|
if len(errors) > 0 {
|
||||||
|
return utils.Map(
|
||||||
|
errors,
|
||||||
|
func(err common.LSPError) protocol.Diagnostic {
|
||||||
|
return err.ToDiagnostic()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -158,7 +158,7 @@ Match 192.168.0.2
|
|||||||
t.Errorf("Expected sixth entry to be 'MaxAuthTries 3', but got: %v", sixthEntry.Value)
|
t.Errorf("Expected sixth entry to be 'MaxAuthTries 3', but got: %v", sixthEntry.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
firstOption, firstMatchBlock := p.FindOption(uint32(4))
|
firstOption, firstMatchBlock := p.FindOption(uint32(3))
|
||||||
|
|
||||||
if !(firstOption.Key.Value == "PasswordAuthentication" && firstOption.OptionValue.Value == "yes" && firstMatchBlock.MatchEntry.Value == "Match 192.168.0.1") {
|
if !(firstOption.Key.Value == "PasswordAuthentication" && firstOption.OptionValue.Value == "yes" && firstMatchBlock.MatchEntry.Value == "Match 192.168.0.1") {
|
||||||
t.Errorf("Expected first option to be 'PasswordAuthentication yes' and first match block to be 'Match 192.168.0.1', but got: %v, %v", firstOption, firstMatchBlock)
|
t.Errorf("Expected first option to be 'PasswordAuthentication yes' and first match block to be 'Match 192.168.0.1', but got: %v, %v", firstOption, firstMatchBlock)
|
||||||
|
@ -103,7 +103,12 @@ func (c SSHConfig) FindOption(line uint32) (*SSHOption, *SSHMatchBlock) {
|
|||||||
rawEntry, found := c.Options.Get(line)
|
rawEntry, found := c.Options.Get(line)
|
||||||
|
|
||||||
if found {
|
if found {
|
||||||
return rawEntry.(*SSHOption), nil
|
switch rawEntry.(type) {
|
||||||
|
case *SSHMatchBlock:
|
||||||
|
return rawEntry.(*SSHMatchBlock).MatchEntry, rawEntry.(*SSHMatchBlock)
|
||||||
|
case *SSHOption:
|
||||||
|
return rawEntry.(*SSHOption), nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
88
handlers/sshd_config/indexes/indexes.go
Normal file
88
handlers/sshd_config/indexes/indexes.go
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
package indexes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"config-lsp/common"
|
||||||
|
"config-lsp/handlers/sshd_config/ast"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var allowedDoubleOptions = map[string]struct{}{
|
||||||
|
"AllowGroups": {},
|
||||||
|
"AllowUsers": {},
|
||||||
|
"DenyGroups": {},
|
||||||
|
"DenyUsers": {},
|
||||||
|
"ListenAddress": {},
|
||||||
|
"Match": {},
|
||||||
|
"Port": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
type SSHIndexEntry struct {
|
||||||
|
Option string
|
||||||
|
MatchBlock *ast.SSHMatchBlock
|
||||||
|
}
|
||||||
|
|
||||||
|
type SSHIndexes struct {
|
||||||
|
EntriesPerKey map[SSHIndexEntry][]*ast.SSHOption
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateIndexes(config ast.SSHConfig) (*SSHIndexes, []common.LSPError) {
|
||||||
|
errs := make([]common.LSPError, 0)
|
||||||
|
indexes := &SSHIndexes{
|
||||||
|
EntriesPerKey: make(map[SSHIndexEntry][]*ast.SSHOption),
|
||||||
|
}
|
||||||
|
|
||||||
|
it := config.Options.Iterator()
|
||||||
|
|
||||||
|
for it.Next() {
|
||||||
|
entry := it.Value().(ast.SSHEntry)
|
||||||
|
|
||||||
|
switch entry.(type) {
|
||||||
|
case *ast.SSHOption:
|
||||||
|
option := entry.(*ast.SSHOption)
|
||||||
|
|
||||||
|
errs = append(errs, addOption(indexes, option, nil)...)
|
||||||
|
case *ast.SSHMatchBlock:
|
||||||
|
matchBlock := entry.(*ast.SSHMatchBlock)
|
||||||
|
|
||||||
|
it := matchBlock.Options.Iterator()
|
||||||
|
|
||||||
|
for it.Next() {
|
||||||
|
option := it.Value().(*ast.SSHOption)
|
||||||
|
|
||||||
|
errs = append(errs, addOption(indexes, option, matchBlock)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return indexes, errs
|
||||||
|
}
|
||||||
|
|
||||||
|
func addOption(
|
||||||
|
i *SSHIndexes,
|
||||||
|
option *ast.SSHOption,
|
||||||
|
matchBlock *ast.SSHMatchBlock,
|
||||||
|
) []common.LSPError {
|
||||||
|
var errs []common.LSPError
|
||||||
|
|
||||||
|
indexEntry := SSHIndexEntry{
|
||||||
|
Option: option.Key.Value,
|
||||||
|
MatchBlock: matchBlock,
|
||||||
|
}
|
||||||
|
|
||||||
|
if existingEntry, found := i.EntriesPerKey[indexEntry]; found {
|
||||||
|
if _, found := allowedDoubleOptions[option.Key.Value]; found {
|
||||||
|
// Double value, but doubles are allowed
|
||||||
|
i.EntriesPerKey[indexEntry] = append(existingEntry, option)
|
||||||
|
} else {
|
||||||
|
errs = append(errs, common.LSPError{
|
||||||
|
Range: option.Key.LocationRange,
|
||||||
|
Err: errors.New(fmt.Sprintf("Option %s is already defined on line %d", option.Key.Value, existingEntry[0].Start.Line+1)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
i.EntriesPerKey[indexEntry] = []*ast.SSHOption{option}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errs
|
||||||
|
}
|
105
handlers/sshd_config/indexes/indexes_test.go
Normal file
105
handlers/sshd_config/indexes/indexes_test.go
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
package indexes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"config-lsp/handlers/sshd_config/ast"
|
||||||
|
"config-lsp/utils"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSimpleExample(
|
||||||
|
t *testing.T,
|
||||||
|
) {
|
||||||
|
input := utils.Dedent(`
|
||||||
|
PermitRootLogin yes
|
||||||
|
RootLogin yes
|
||||||
|
PermitRootLogin no
|
||||||
|
`)
|
||||||
|
config := ast.NewSSHConfig()
|
||||||
|
errors := config.Parse(input)
|
||||||
|
|
||||||
|
if len(errors) > 0 {
|
||||||
|
t.Fatalf("Unexpected errors: %v", errors)
|
||||||
|
}
|
||||||
|
|
||||||
|
indexes, errors := CreateIndexes(*config)
|
||||||
|
|
||||||
|
if !(len(errors) == 1) {
|
||||||
|
t.Fatalf("Expected 1 error, but got %v", len(errors))
|
||||||
|
}
|
||||||
|
|
||||||
|
indexEntry := SSHIndexEntry{
|
||||||
|
Option: "PermitRootLogin",
|
||||||
|
MatchBlock: nil,
|
||||||
|
}
|
||||||
|
if !(indexes.EntriesPerKey[indexEntry][0].Value == "PermitRootLogin yes" && indexes.EntriesPerKey[indexEntry][0].Start.Line == 0) {
|
||||||
|
t.Errorf("Expected 'PermitRootLogin yes', but got %v", indexes.EntriesPerKey[indexEntry][0].Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
indexEntry = SSHIndexEntry{
|
||||||
|
Option: "RootLogin",
|
||||||
|
MatchBlock: nil,
|
||||||
|
}
|
||||||
|
if !(indexes.EntriesPerKey[indexEntry][0].Value == "RootLogin yes" && indexes.EntriesPerKey[indexEntry][0].Start.Line == 1) {
|
||||||
|
t.Errorf("Expected 'RootLogin yes', but got %v", indexes.EntriesPerKey[indexEntry][0].Value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestComplexExample(
|
||||||
|
t *testing.T,
|
||||||
|
) {
|
||||||
|
input := utils.Dedent(`
|
||||||
|
PermitRootLogin yes
|
||||||
|
Port 22
|
||||||
|
Port 2022
|
||||||
|
Port 2024
|
||||||
|
|
||||||
|
Match Address 192.168.0.1/24
|
||||||
|
PermitRootLogin no
|
||||||
|
RoomLogin yes
|
||||||
|
PermitRootLogin yes
|
||||||
|
`)
|
||||||
|
config := ast.NewSSHConfig()
|
||||||
|
errors := config.Parse(input)
|
||||||
|
|
||||||
|
if len(errors) > 0 {
|
||||||
|
t.Fatalf("Expected no errors, but got %v", len(errors))
|
||||||
|
}
|
||||||
|
|
||||||
|
indexes, errors := CreateIndexes(*config)
|
||||||
|
|
||||||
|
if !(len(errors) == 1) {
|
||||||
|
t.Fatalf("Expected no errors, but got %v", len(errors))
|
||||||
|
}
|
||||||
|
|
||||||
|
indexEntry := SSHIndexEntry{
|
||||||
|
Option: "PermitRootLogin",
|
||||||
|
MatchBlock: nil,
|
||||||
|
}
|
||||||
|
if !(indexes.EntriesPerKey[indexEntry][0].Value == "PermitRootLogin yes" && indexes.EntriesPerKey[indexEntry][0].Start.Line == 0) {
|
||||||
|
t.Errorf("Expected 'PermitRootLogin yes' on line 0, but got %v on line %v", indexes.EntriesPerKey[indexEntry][0].Value, indexes.EntriesPerKey[indexEntry][0].Start.Line)
|
||||||
|
}
|
||||||
|
|
||||||
|
firstMatchBlock := config.FindMatchBlock(uint32(6))
|
||||||
|
indexEntry = SSHIndexEntry{
|
||||||
|
Option: "PermitRootLogin",
|
||||||
|
MatchBlock: firstMatchBlock,
|
||||||
|
}
|
||||||
|
if !(indexes.EntriesPerKey[indexEntry][0].Value == "\tPermitRootLogin no" && indexes.EntriesPerKey[indexEntry][0].Start.Line == 6) {
|
||||||
|
t.Errorf("Expected 'PermitRootLogin no' on line 6, but got %v on line %v", indexes.EntriesPerKey[indexEntry][0].Value, indexes.EntriesPerKey[indexEntry][0].Start.Line)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Double check
|
||||||
|
indexEntry = SSHIndexEntry{
|
||||||
|
Option: "Port",
|
||||||
|
MatchBlock: nil,
|
||||||
|
}
|
||||||
|
if !(indexes.EntriesPerKey[indexEntry][0].Value == "Port 22" &&
|
||||||
|
indexes.EntriesPerKey[indexEntry][0].Start.Line == 1 &&
|
||||||
|
len(indexes.EntriesPerKey[indexEntry]) == 3 &&
|
||||||
|
indexes.EntriesPerKey[indexEntry][1].Value == "Port 2022" &&
|
||||||
|
indexes.EntriesPerKey[indexEntry][1].Start.Line == 2 &&
|
||||||
|
indexes.EntriesPerKey[indexEntry][2].Value == "Port 2024" &&
|
||||||
|
indexes.EntriesPerKey[indexEntry][2].Start.Line == 3) {
|
||||||
|
t.Errorf("Expected 'Port 22' on line 1, but got %v on line %v", indexes.EntriesPerKey[indexEntry][0].Value, indexes.EntriesPerKey[indexEntry][0].Start.Line)
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user