mirror of
https://github.com/Myzel394/config-lsp.git
synced 2025-06-19 07:25:27 +02:00
fix: Improve duplicates check
This commit is contained in:
parent
d5cb9c53e9
commit
56b661db72
@ -72,10 +72,32 @@ func (v PositiveNumberValue) CheckIsValid(value string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var SimpleDuplicatesExtractor = func(value string) string {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
var ExtractKeyDuplicatesExtractor = func(separator string) func(string) string {
|
||||||
|
return func(value string) string {
|
||||||
|
splitted := strings.Split(value, separator)
|
||||||
|
|
||||||
|
if len(splitted) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return splitted[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var DuplicatesAllowedExtractor func(string) string = nil
|
||||||
|
|
||||||
type ArrayValue struct {
|
type ArrayValue struct {
|
||||||
SubValue Value
|
SubValue Value
|
||||||
Separator string
|
Separator string
|
||||||
AllowDuplicates bool
|
// If this function is nil, no duplicate check is done
|
||||||
|
// (value) => Extracted value
|
||||||
|
// This is used to extract the value from the user input,
|
||||||
|
// because you may want to preprocess the value before checking for duplicates
|
||||||
|
DuplicatesExtractor *(func(string) string)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v ArrayValue) GetTypeDescription() []string {
|
func (v ArrayValue) GetTypeDescription() []string {
|
||||||
@ -89,21 +111,19 @@ func (v ArrayValue) GetTypeDescription() []string {
|
|||||||
func (v ArrayValue) CheckIsValid(value string) error {
|
func (v ArrayValue) CheckIsValid(value string) error {
|
||||||
values := strings.Split(value, v.Separator)
|
values := strings.Split(value, v.Separator)
|
||||||
|
|
||||||
for _, subValue := range values {
|
println(fmt.Sprintf("values: %v", values))
|
||||||
err := v.SubValue.CheckIsValid(subValue)
|
|
||||||
|
|
||||||
if err != nil {
|
if v.DuplicatesExtractor != nil {
|
||||||
return err
|
valuesOccurrences := SliceToMap(
|
||||||
}
|
Map(values, *v.DuplicatesExtractor),
|
||||||
}
|
0,
|
||||||
|
)
|
||||||
if !v.AllowDuplicates {
|
|
||||||
valuesOccurrences := SliceToMap(values, 0)
|
|
||||||
|
|
||||||
// Only continue if there are actually duplicate values
|
// Only continue if there are actually duplicate values
|
||||||
if len(values) != len(valuesOccurrences) {
|
if len(values) != len(valuesOccurrences) {
|
||||||
for _, subValue := range values {
|
for _, duplicateRawValue := range values {
|
||||||
valuesOccurrences[subValue]++
|
duplicateValue := (*v.DuplicatesExtractor)(duplicateRawValue)
|
||||||
|
valuesOccurrences[duplicateValue]++
|
||||||
}
|
}
|
||||||
|
|
||||||
duplicateValues := FilterMapWhere(valuesOccurrences, func(_ string, value int) bool {
|
duplicateValues := FilterMapWhere(valuesOccurrences, func(_ string, value int) bool {
|
||||||
@ -116,6 +136,15 @@ func (v ArrayValue) CheckIsValid(value string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for _, subValue := range values {
|
||||||
|
err := v.SubValue.CheckIsValid(subValue)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,7 +127,7 @@ type ArrayContainsDuplicatesError struct {
|
|||||||
Duplicates []string
|
Duplicates []string
|
||||||
}
|
}
|
||||||
func (e ArrayContainsDuplicatesError) Error() string {
|
func (e ArrayContainsDuplicatesError) Error() string {
|
||||||
return fmt.Sprintf("Remove the following duplicate values: %s", strings.Join(e.Duplicates, ","))
|
return fmt.Sprintf("The following values are duplicated: %s", strings.Join(e.Duplicates, ","))
|
||||||
}
|
}
|
||||||
|
|
||||||
type PathDoesNotExistError struct{}
|
type PathDoesNotExistError struct{}
|
||||||
|
@ -72,7 +72,7 @@ func UserValue(separatorForMultiple string, enforceValues bool) Value {
|
|||||||
return enumValues
|
return enumValues
|
||||||
} else {
|
} else {
|
||||||
return ArrayValue{
|
return ArrayValue{
|
||||||
AllowDuplicates: false,
|
DuplicatesExtractor: &SimpleDuplicatesExtractor,
|
||||||
SubValue: enumValues,
|
SubValue: enumValues,
|
||||||
Separator: separatorForMultiple,
|
Separator: separatorForMultiple,
|
||||||
}
|
}
|
||||||
|
91
handlers/openssh/documentation-utils.go
Normal file
91
handlers/openssh/documentation-utils.go
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
package openssh
|
||||||
|
|
||||||
|
import (
|
||||||
|
"config-lsp/common"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var BooleanEnumValue = common.EnumValue{
|
||||||
|
EnforceValues: true,
|
||||||
|
Values: []string{"yes", "no"},
|
||||||
|
}
|
||||||
|
|
||||||
|
var plusMinuxCaretPrefixes = []common.Prefix{
|
||||||
|
{
|
||||||
|
Prefix: "+",
|
||||||
|
Meaning: "Append to the default set",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Prefix: "-",
|
||||||
|
Meaning: "Remove from the default set",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Prefix: "^",
|
||||||
|
Meaning: "Place at the head of the default set",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var ChannelTimeoutExtractor = common.ExtractKeyDuplicatesExtractor("=")
|
||||||
|
|
||||||
|
func PrefixPlusMinusCaret(values []string) common.PrefixWithMeaningValue {
|
||||||
|
return common.PrefixWithMeaningValue{
|
||||||
|
Prefixes: []common.Prefix{
|
||||||
|
{
|
||||||
|
Prefix: "+",
|
||||||
|
Meaning: "Append to the default set",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Prefix: "-",
|
||||||
|
Meaning: "Remove from the default set",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Prefix: "^",
|
||||||
|
Meaning: "Place at the head of the default set",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
SubValue: common.ArrayValue{
|
||||||
|
Separator: ",",
|
||||||
|
DuplicatesExtractor: &common.SimpleDuplicatesExtractor,
|
||||||
|
SubValue: common.EnumValue{
|
||||||
|
Values: values,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _cachedQueries map[string][]string = make(map[string][]string)
|
||||||
|
|
||||||
|
func queryValues(query string) ([]string, error) {
|
||||||
|
cmd := exec.Command("ssh", "-Q", query)
|
||||||
|
|
||||||
|
output, err := cmd.Output()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return []string{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Split(string(output), "\n"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func QueryOpenSSHOptions(
|
||||||
|
query string,
|
||||||
|
) ([]string, error) {
|
||||||
|
var availableQueries []string
|
||||||
|
key := query
|
||||||
|
|
||||||
|
if _cachedQueries[key] != nil && len(_cachedQueries[key]) > 0 {
|
||||||
|
return _cachedQueries[key], nil
|
||||||
|
} else {
|
||||||
|
availableQueries, err := queryValues(query)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return []string{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_cachedQueries[key] = availableQueries
|
||||||
|
}
|
||||||
|
|
||||||
|
return availableQueries, nil
|
||||||
|
}
|
||||||
|
|
@ -1,41 +0,0 @@
|
|||||||
package openssh
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os/exec"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _cachedQueries map[string][]string = make(map[string][]string)
|
|
||||||
|
|
||||||
func queryValues(query string) ([]string, error) {
|
|
||||||
cmd := exec.Command("ssh", "-Q", query)
|
|
||||||
|
|
||||||
output, err := cmd.Output()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return []string{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return strings.Split(string(output), "\n"), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func QueryOpenSSHOptions(
|
|
||||||
query string,
|
|
||||||
) ([]string, error) {
|
|
||||||
var availableQueries []string
|
|
||||||
key := query
|
|
||||||
|
|
||||||
if _cachedQueries[key] != nil && len(_cachedQueries[key]) > 0 {
|
|
||||||
return _cachedQueries[key], nil
|
|
||||||
} else {
|
|
||||||
availableQueries, err := queryValues(query)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return []string{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
_cachedQueries[key] = availableQueries
|
|
||||||
}
|
|
||||||
|
|
||||||
return availableQueries, nil
|
|
||||||
}
|
|
@ -4,52 +4,6 @@ import (
|
|||||||
"config-lsp/common"
|
"config-lsp/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
var BooleanEnumValue = common.EnumValue{
|
|
||||||
EnforceValues: true,
|
|
||||||
Values: []string{"yes", "no"},
|
|
||||||
}
|
|
||||||
|
|
||||||
var plusMinuxCaretPrefixes = []common.Prefix{
|
|
||||||
{
|
|
||||||
Prefix: "+",
|
|
||||||
Meaning: "Append to the default set",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Prefix: "-",
|
|
||||||
Meaning: "Remove from the default set",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Prefix: "^",
|
|
||||||
Meaning: "Place at the head of the default set",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func PrefixPlusMinusCaret(values []string) common.PrefixWithMeaningValue {
|
|
||||||
return common.PrefixWithMeaningValue{
|
|
||||||
Prefixes: []common.Prefix{
|
|
||||||
{
|
|
||||||
Prefix: "+",
|
|
||||||
Meaning: "Append to the default set",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Prefix: "-",
|
|
||||||
Meaning: "Remove from the default set",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Prefix: "^",
|
|
||||||
Meaning: "Place at the head of the default set",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
SubValue: common.ArrayValue{
|
|
||||||
Separator: ",",
|
|
||||||
AllowDuplicates: false,
|
|
||||||
SubValue: common.EnumValue{
|
|
||||||
Values: values,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var Options = map[string]common.Option{
|
var Options = map[string]common.Option{
|
||||||
"AcceptEnv": common.NewOption(
|
"AcceptEnv": common.NewOption(
|
||||||
`Specifies what environment variables sent by the client will be copied into the session's environ(7). See SendEnv and SetEnv in ssh_config(5) for how to configure the client. The TERM environment variable is always accepted whenever the client requests a pseudo-terminal as it is required by the protocol. Variables are specified by name, which may contain the wildcard characters ‘*’ and ‘?’. Multiple environment variables may be separated by whitespace or spread across multiple AcceptEnv directives. Be warned that some environment variables could be used to bypass restricted user environments. For this reason, care should be taken in the use of this directive. The default is not to accept any environment variables.`,
|
`Specifies what environment variables sent by the client will be copied into the session's environ(7). See SendEnv and SetEnv in ssh_config(5) for how to configure the client. The TERM environment variable is always accepted whenever the client requests a pseudo-terminal as it is required by the protocol. Variables are specified by name, which may contain the wildcard characters ‘*’ and ‘?’. Multiple environment variables may be separated by whitespace or spread across multiple AcceptEnv directives. Be warned that some environment variables could be used to bypass restricted user environments. For this reason, care should be taken in the use of this directive. The default is not to accept any environment variables.`,
|
||||||
@ -73,7 +27,7 @@ See PATTERNS in ssh_config(5) for more information on patterns. This keyword may
|
|||||||
common.CustomValue{
|
common.CustomValue{
|
||||||
FetchValue: func() common.Value {
|
FetchValue: func() common.Value {
|
||||||
return common.ArrayValue{
|
return common.ArrayValue{
|
||||||
AllowDuplicates: false,
|
DuplicatesExtractor: &common.SimpleDuplicatesExtractor,
|
||||||
SubValue: common.StringValue{},
|
SubValue: common.StringValue{},
|
||||||
Separator: " ",
|
Separator: " ",
|
||||||
}
|
}
|
||||||
@ -113,7 +67,6 @@ See PATTERNS in ssh_config(5) for more information on patterns. This keyword may
|
|||||||
Values: []string{"any"},
|
Values: []string{"any"},
|
||||||
},
|
},
|
||||||
common.ArrayValue{
|
common.ArrayValue{
|
||||||
AllowDuplicates: true,
|
|
||||||
SubValue: common.EnumValue{
|
SubValue: common.EnumValue{
|
||||||
EnforceValues: true,
|
EnforceValues: true,
|
||||||
Values: []string{
|
Values: []string{
|
||||||
@ -157,7 +110,7 @@ See PATTERNS in ssh_config(5) for more information on patterns. This keyword may
|
|||||||
common.ArrayValue{
|
common.ArrayValue{
|
||||||
SubValue: common.StringValue{},
|
SubValue: common.StringValue{},
|
||||||
Separator: " ",
|
Separator: " ",
|
||||||
AllowDuplicates: false,
|
DuplicatesExtractor: &common.DuplicatesAllowedExtractor,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
"AuthorizedPrincipalsCommand": common.NewOption(
|
"AuthorizedPrincipalsCommand": common.NewOption(
|
||||||
@ -200,7 +153,7 @@ See PATTERNS in ssh_config(5) for more information on patterns. This keyword may
|
|||||||
},
|
},
|
||||||
SubValue: common.ArrayValue{
|
SubValue: common.ArrayValue{
|
||||||
Separator: ",",
|
Separator: ",",
|
||||||
AllowDuplicates: false,
|
DuplicatesExtractor: &common.DuplicatesAllowedExtractor,
|
||||||
SubValue: common.StringValue{},
|
SubValue: common.StringValue{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -222,7 +175,7 @@ See PATTERNS in ssh_config(5) for more information on patterns. This keyword may
|
|||||||
The default is not to expire channels of any type for inactivity.`,
|
The default is not to expire channels of any type for inactivity.`,
|
||||||
common.ArrayValue{
|
common.ArrayValue{
|
||||||
Separator: " ",
|
Separator: " ",
|
||||||
AllowDuplicates: false,
|
DuplicatesExtractor: &ChannelTimeoutExtractor,
|
||||||
SubValue: common.KeyValueAssignmentValue{
|
SubValue: common.KeyValueAssignmentValue{
|
||||||
Separator: "=",
|
Separator: "=",
|
||||||
Key: common.EnumValue{
|
Key: common.EnumValue{
|
||||||
@ -407,7 +360,6 @@ See PATTERNS in ssh_config(5) for more information on patterns. This keyword may
|
|||||||
Values: []string{"none"},
|
Values: []string{"none"},
|
||||||
},
|
},
|
||||||
common.ArrayValue{
|
common.ArrayValue{
|
||||||
AllowDuplicates: true,
|
|
||||||
Separator: " ",
|
Separator: " ",
|
||||||
SubValue: common.EnumValue{
|
SubValue: common.EnumValue{
|
||||||
EnforceValues: true,
|
EnforceValues: true,
|
||||||
@ -582,7 +534,7 @@ See PATTERNS in ssh_config(5) for more information on patterns. This keyword may
|
|||||||
common.ArrayValue{
|
common.ArrayValue{
|
||||||
SubValue: common.StringValue{},
|
SubValue: common.StringValue{},
|
||||||
Separator: ",",
|
Separator: ",",
|
||||||
AllowDuplicates: false,
|
DuplicatesExtractor: &common.DuplicatesAllowedExtractor,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -631,7 +583,6 @@ See PATTERNS in ssh_config(5) for more information on patterns. This keyword may
|
|||||||
The verify-required option requires a FIDO key signature attest that the user was verified, e.g. via a PIN.
|
The verify-required option requires a FIDO key signature attest that the user was verified, e.g. via a PIN.
|
||||||
Neither the touch-required or verify-required options have any effect for other, non-FIDO, public key types.`,
|
Neither the touch-required or verify-required options have any effect for other, non-FIDO, public key types.`,
|
||||||
common.ArrayValue{
|
common.ArrayValue{
|
||||||
AllowDuplicates: true,
|
|
||||||
Separator: ",",
|
Separator: ",",
|
||||||
SubValue: common.EnumValue{
|
SubValue: common.EnumValue{
|
||||||
EnforceValues: true,
|
EnforceValues: true,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user