mirror of
https://github.com/Myzel394/config-lsp.git
synced 2025-06-19 07:25:27 +02:00
fix(sshd_config): Improve indexes structure
This commit is contained in:
parent
7bb34c32b4
commit
35c722995d
@ -15,7 +15,7 @@ func analyzeMatchBlocks(
|
|||||||
) []common.LSPError {
|
) []common.LSPError {
|
||||||
errs := make([]common.LSPError, 0)
|
errs := make([]common.LSPError, 0)
|
||||||
|
|
||||||
for matchBlock, options := range d.Indexes.GetAllOptionsForName("Match") {
|
for matchBlock, options := range d.Indexes.AllOptionsPerName["Match"] {
|
||||||
option := options[0]
|
option := options[0]
|
||||||
// Check if the match block has filled out all fields
|
// Check if the match block has filled out all fields
|
||||||
if matchBlock == nil || matchBlock.MatchValue == nil || len(matchBlock.MatchValue.Entries) == 0 {
|
if matchBlock == nil || matchBlock.MatchValue == nil || len(matchBlock.MatchValue.Entries) == 0 {
|
||||||
|
@ -10,13 +10,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func GetIncludeOptionLocation(
|
func GetIncludeOptionLocation(
|
||||||
include *indexes.SSHIndexIncludeLine,
|
include *indexes.SSHDIndexIncludeLine,
|
||||||
cursor uint32,
|
cursor uint32,
|
||||||
) []protocol.Location {
|
) []protocol.Location {
|
||||||
index, found := slices.BinarySearchFunc(
|
index, found := slices.BinarySearchFunc(
|
||||||
include.Values,
|
include.Values,
|
||||||
cursor,
|
cursor,
|
||||||
func(i *indexes.SSHIndexIncludeValue, cursor uint32) int {
|
func(i *indexes.SSHDIndexIncludeValue, cursor uint32) int {
|
||||||
if cursor < i.Start.Character {
|
if cursor < i.Start.Character {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
125
handlers/sshd_config/indexes/handlers.go
Normal file
125
handlers/sshd_config/indexes/handlers.go
Normal 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
|
||||||
|
}
|
@ -3,10 +3,6 @@ package indexes
|
|||||||
import (
|
import (
|
||||||
"config-lsp/common"
|
"config-lsp/common"
|
||||||
"config-lsp/handlers/sshd_config/ast"
|
"config-lsp/handlers/sshd_config/ast"
|
||||||
"config-lsp/handlers/sshd_config/fields"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"regexp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ValidPath string
|
type ValidPath string
|
||||||
@ -15,13 +11,13 @@ func (v ValidPath) AsURI() string {
|
|||||||
return "file://" + string(v)
|
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,
|
// 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
|
// Note that an entered path can represent multiple real paths, as
|
||||||
// the path can contain wildcards.
|
// the path can contain wildcards.
|
||||||
// All true paths are stored in the [Paths] field.
|
// All true paths are stored in the [Paths] field.
|
||||||
type SSHIndexIncludeValue struct {
|
type SSHDIndexIncludeValue struct {
|
||||||
common.LocationRange
|
common.LocationRange
|
||||||
Value string
|
Value string
|
||||||
|
|
||||||
@ -29,142 +25,15 @@ type SSHIndexIncludeValue struct {
|
|||||||
Paths []ValidPath
|
Paths []ValidPath
|
||||||
}
|
}
|
||||||
|
|
||||||
type SSHIndexIncludeLine struct {
|
type SSHDIndexIncludeLine struct {
|
||||||
Values []*SSHIndexIncludeValue
|
Values []*SSHDIndexIncludeValue
|
||||||
Option *ast.SSHDOption
|
Option *ast.SSHDOption
|
||||||
MatchBlock *ast.SSHDMatchBlock
|
MatchBlock *ast.SSHDMatchBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
type SSHIndexes struct {
|
type SSHDIndexes struct {
|
||||||
// This is a map of `Option name` to a list of options with that name
|
// 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
|
Includes map[uint32]*SSHDIndexIncludeLine
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ Match Address 192.168.0.1/24
|
|||||||
}
|
}
|
||||||
|
|
||||||
firstMatchBlock := config.FindMatchBlock(uint32(6))
|
firstMatchBlock := config.FindMatchBlock(uint32(6))
|
||||||
opts := indexes.GetAllOptionsForName("PermitRootLogin")
|
opts := indexes.AllOptionsPerName["PermitRootLogin"]
|
||||||
if !(len(opts) == 2 &&
|
if !(len(opts) == 2 &&
|
||||||
len(opts[nil]) == 1 &&
|
len(opts[nil]) == 1 &&
|
||||||
opts[nil][0].Value.Value == "PermitRootLogin yes" &&
|
opts[nil][0].Value.Value == "PermitRootLogin yes" &&
|
||||||
|
@ -9,7 +9,7 @@ import (
|
|||||||
|
|
||||||
type SSHDocument struct {
|
type SSHDocument struct {
|
||||||
Config *ast.SSHDConfig
|
Config *ast.SSHDConfig
|
||||||
Indexes *indexes.SSHIndexes
|
Indexes *indexes.SSHDIndexes
|
||||||
}
|
}
|
||||||
|
|
||||||
var DocumentParserMap = map[protocol.DocumentUri]*SSHDocument{}
|
var DocumentParserMap = map[protocol.DocumentUri]*SSHDocument{}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user