fix(sshd_config): Improve indexes structure

This commit is contained in:
Myzel394 2024-09-17 23:33:32 +02:00
parent 7bb34c32b4
commit 35c722995d
No known key found for this signature in database
GPG Key ID: DEC4AAB876F73185
6 changed files with 138 additions and 144 deletions

View File

@ -15,7 +15,7 @@ func analyzeMatchBlocks(
) []common.LSPError {
errs := make([]common.LSPError, 0)
for matchBlock, options := range d.Indexes.GetAllOptionsForName("Match") {
for matchBlock, options := range d.Indexes.AllOptionsPerName["Match"] {
option := options[0]
// Check if the match block has filled out all fields
if matchBlock == nil || matchBlock.MatchValue == nil || len(matchBlock.MatchValue.Entries) == 0 {

View File

@ -10,13 +10,13 @@ import (
)
func GetIncludeOptionLocation(
include *indexes.SSHIndexIncludeLine,
include *indexes.SSHDIndexIncludeLine,
cursor uint32,
) []protocol.Location {
index, found := slices.BinarySearchFunc(
include.Values,
cursor,
func(i *indexes.SSHIndexIncludeValue, cursor uint32) int {
func(i *indexes.SSHDIndexIncludeValue, cursor uint32) int {
if cursor < i.Start.Character {
return -1
}

View File

@ -0,0 +1,125 @@
package indexes
import (
"config-lsp/common"
"config-lsp/handlers/sshd_config/ast"
"config-lsp/handlers/sshd_config/fields"
"errors"
"fmt"
"regexp"
)
var whitespacePattern = regexp.MustCompile(`\S+`)
func CreateIndexes(config ast.SSHDConfig) (*SSHDIndexes, []common.LSPError) {
errs := make([]common.LSPError, 0)
indexes := &SSHDIndexes{
AllOptionsPerName: make(map[string](map[*ast.SSHDMatchBlock]([]*ast.SSHDOption))),
Includes: make(map[uint32]*SSHDIndexIncludeLine),
}
it := config.Options.Iterator()
for it.Next() {
entry := it.Value().(ast.SSHDEntry)
switch entry.(type) {
case *ast.SSHDOption:
option := entry.(*ast.SSHDOption)
errs = append(errs, addOption(indexes, option, nil)...)
case *ast.SSHDMatchBlock:
matchBlock := entry.(*ast.SSHDMatchBlock)
errs = append(errs, addOption(indexes, matchBlock.MatchEntry, matchBlock)...)
it := matchBlock.Options.Iterator()
for it.Next() {
option := it.Value().(*ast.SSHDOption)
errs = append(errs, addOption(indexes, option, matchBlock)...)
}
}
}
// Add Includes
for matchBlock, options := range indexes.AllOptionsPerName["Include"] {
includeOption := options[0]
rawValue := includeOption.OptionValue.Value.Value
pathIndexes := whitespacePattern.FindAllStringIndex(rawValue, -1)
paths := make([]*SSHDIndexIncludeValue, 0)
for _, pathIndex := range pathIndexes {
startIndex := pathIndex[0]
endIndex := pathIndex[1]
rawPath := rawValue[startIndex:endIndex]
offset := includeOption.OptionValue.Start.Character
path := SSHDIndexIncludeValue{
LocationRange: common.LocationRange{
Start: common.Location{
Line: includeOption.Start.Line,
Character: uint32(startIndex) + offset,
},
End: common.Location{
Line: includeOption.Start.Line,
Character: uint32(endIndex) + offset - 1,
},
},
Value: rawPath,
Paths: make([]ValidPath, 0),
}
paths = append(paths, &path)
}
indexes.Includes[includeOption.Start.Line] = &SSHDIndexIncludeLine{
Values: paths,
Option: includeOption,
MatchBlock: matchBlock,
}
}
return indexes, errs
}
func addOption(
i *SSHDIndexes,
option *ast.SSHDOption,
matchBlock *ast.SSHDMatchBlock,
) []common.LSPError {
var errs []common.LSPError
if optionsMap, found := i.AllOptionsPerName[option.Key.Key]; found {
if options, found := optionsMap[matchBlock]; found {
if _, duplicatesAllowed := fields.AllowedDuplicateOptions[option.Key.Key]; !duplicatesAllowed {
firstDefinedOption := options[0]
errs = append(errs, common.LSPError{
Range: option.Key.LocationRange,
Err: errors.New(fmt.Sprintf(
"Option '%s' has already been defined on line %d",
option.Key.Key,
firstDefinedOption.Start.Line+1,
)),
})
} else {
i.AllOptionsPerName[option.Key.Key][matchBlock] = append(
i.AllOptionsPerName[option.Key.Key][matchBlock],
option,
)
}
} else {
i.AllOptionsPerName[option.Key.Key][matchBlock] = []*ast.SSHDOption{
option,
}
}
} else {
i.AllOptionsPerName[option.Key.Key] = map[*ast.SSHDMatchBlock]([]*ast.SSHDOption){
matchBlock: {
option,
},
}
}
return errs
}

View File

@ -3,10 +3,6 @@ package indexes
import (
"config-lsp/common"
"config-lsp/handlers/sshd_config/ast"
"config-lsp/handlers/sshd_config/fields"
"errors"
"fmt"
"regexp"
)
type ValidPath string
@ -15,13 +11,13 @@ func (v ValidPath) AsURI() string {
return "file://" + string(v)
}
// SSHIndexIncludeValue Used to store the individual includes
// SSHDIndexIncludeValue Used to store the individual includes
// An `Include` statement can have multiple paths,
// each [SSHIndexIncludeValue] represents a single entered path.
// each [SSHDIndexIncludeValue] represents a single entered path.
// Note that an entered path can represent multiple real paths, as
// the path can contain wildcards.
// All true paths are stored in the [Paths] field.
type SSHIndexIncludeValue struct {
type SSHDIndexIncludeValue struct {
common.LocationRange
Value string
@ -29,142 +25,15 @@ type SSHIndexIncludeValue struct {
Paths []ValidPath
}
type SSHIndexIncludeLine struct {
Values []*SSHIndexIncludeValue
type SSHDIndexIncludeLine struct {
Values []*SSHDIndexIncludeValue
Option *ast.SSHDOption
MatchBlock *ast.SSHDMatchBlock
}
type SSHIndexes struct {
type SSHDIndexes struct {
// This is a map of `Option name` to a list of options with that name
AllOptionsPerName map[*ast.SSHDMatchBlock](map[string]([]*ast.SSHDOption))
AllOptionsPerName map[string](map[*ast.SSHDMatchBlock]([]*ast.SSHDOption))
Includes map[uint32]*SSHIndexIncludeLine
}
func (i SSHIndexes) GetAllOptionsForName(name string) map[*ast.SSHDMatchBlock][]*ast.SSHDOption {
allOptions := make(map[*ast.SSHDMatchBlock][]*ast.SSHDOption)
for matchBlock, options := range i.AllOptionsPerName {
if opts, found := options[name]; found {
allOptions[matchBlock] = opts
}
}
return allOptions
}
var whitespacePattern = regexp.MustCompile(`\S+`)
func CreateIndexes(config ast.SSHDConfig) (*SSHIndexes, []common.LSPError) {
errs := make([]common.LSPError, 0)
indexes := &SSHIndexes{
AllOptionsPerName: make(map[*ast.SSHDMatchBlock](map[string]([]*ast.SSHDOption))),
Includes: make(map[uint32]*SSHIndexIncludeLine),
}
it := config.Options.Iterator()
for it.Next() {
entry := it.Value().(ast.SSHDEntry)
switch entry.(type) {
case *ast.SSHDOption:
option := entry.(*ast.SSHDOption)
errs = append(errs, addOption(indexes, option, nil)...)
case *ast.SSHDMatchBlock:
matchBlock := entry.(*ast.SSHDMatchBlock)
errs = append(errs, addOption(indexes, matchBlock.MatchEntry, matchBlock)...)
it := matchBlock.Options.Iterator()
for it.Next() {
option := it.Value().(*ast.SSHDOption)
errs = append(errs, addOption(indexes, option, matchBlock)...)
}
}
}
// Add Includes
for matchBlock, options := range indexes.GetAllOptionsForName("Include") {
includeOption := options[0]
rawValue := includeOption.OptionValue.Value.Value
pathIndexes := whitespacePattern.FindAllStringIndex(rawValue, -1)
paths := make([]*SSHIndexIncludeValue, 0)
for _, pathIndex := range pathIndexes {
startIndex := pathIndex[0]
endIndex := pathIndex[1]
rawPath := rawValue[startIndex:endIndex]
offset := includeOption.OptionValue.Start.Character
path := SSHIndexIncludeValue{
LocationRange: common.LocationRange{
Start: common.Location{
Line: includeOption.Start.Line,
Character: uint32(startIndex) + offset,
},
End: common.Location{
Line: includeOption.Start.Line,
Character: uint32(endIndex) + offset - 1,
},
},
Value: rawPath,
Paths: make([]ValidPath, 0),
}
paths = append(paths, &path)
}
indexes.Includes[includeOption.Start.Line] = &SSHIndexIncludeLine{
Values: paths,
Option: includeOption,
MatchBlock: matchBlock,
}
}
return indexes, errs
}
func addOption(
i *SSHIndexes,
option *ast.SSHDOption,
matchBlock *ast.SSHDMatchBlock,
) []common.LSPError {
var errs []common.LSPError
if optionsMap, found := i.AllOptionsPerName[matchBlock]; found {
if options, found := optionsMap[option.Key.Key]; found {
if _, duplicatesAllowed := fields.AllowedDuplicateOptions[option.Key.Key]; !duplicatesAllowed {
firstDefinedOption := options[0]
errs = append(errs, common.LSPError{
Range: option.Key.LocationRange,
Err: errors.New(fmt.Sprintf(
"Option '%s' has already been defined on line %d",
option.Key.Key,
firstDefinedOption.Start.Line+1,
)),
})
} else {
i.AllOptionsPerName[matchBlock][option.Key.Key] = append(
i.AllOptionsPerName[matchBlock][option.Key.Key],
option,
)
}
} else {
i.AllOptionsPerName[matchBlock][option.Key.Key] = []*ast.SSHDOption{
option,
}
}
} else {
i.AllOptionsPerName[matchBlock] = map[string]([]*ast.SSHDOption){
option.Key.Key: {
option,
},
}
}
return errs
Includes map[uint32]*SSHDIndexIncludeLine
}

View File

@ -34,7 +34,7 @@ Match Address 192.168.0.1/24
}
firstMatchBlock := config.FindMatchBlock(uint32(6))
opts := indexes.GetAllOptionsForName("PermitRootLogin")
opts := indexes.AllOptionsPerName["PermitRootLogin"]
if !(len(opts) == 2 &&
len(opts[nil]) == 1 &&
opts[nil][0].Value.Value == "PermitRootLogin yes" &&

View File

@ -9,7 +9,7 @@ import (
type SSHDocument struct {
Config *ast.SSHDConfig
Indexes *indexes.SSHIndexes
Indexes *indexes.SSHDIndexes
}
var DocumentParserMap = map[protocol.DocumentUri]*SSHDocument{}