Skip to content

Commit

Permalink
feat(sshd_config): Add first iteration of new sshd_config handler; Ad…
Browse files Browse the repository at this point in the history
…d ast; Add parser
  • Loading branch information
Myzel394 committed Sep 9, 2024
1 parent 492c33a commit af580fa
Show file tree
Hide file tree
Showing 13 changed files with 1,548 additions and 0 deletions.
42 changes: 42 additions & 0 deletions handlers/sshd_config/Config.g4
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
grammar Config;

lineStatement
: (entry | (WHITESPACE? leadingComment) | WHITESPACE?) EOF
;

entry
: WHITESPACE? key? WHITESPACE value? WHITESPACE? leadingComment?
;

key
: STRING
;

value
: STRING
;

leadingComment
: HASH WHITESPACE? (STRING WHITESPACE?)+
;


HASH
: '#'
;

MATCH
: ('M' | 'm') ('A' | 'a') ('T' | 't') ('C' | 'c') ('H' | 'h')
;

WHITESPACE
: [ \t]+
;

STRING
: ~(' ' | '\t' | '\r' | '\n' | '#')+
;

NEWLINE
: '\r'? '\n'
;
45 changes: 45 additions & 0 deletions handlers/sshd_config/ast/error-listener.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package ast

import (
"config-lsp/common"

"github.com/antlr4-go/antlr/v4"
)

type errorListenerContext struct {
line uint32
}

type errorListener struct {
*antlr.DefaultErrorListener
Errors []common.LSPError
context errorListenerContext
}

func (d *errorListener) SyntaxError(
recognizer antlr.Recognizer,
offendingSymbol interface{},
_ int,
character int,
message string,
error antlr.RecognitionException,
) {
line := d.context.line
d.Errors = append(d.Errors, common.LSPError{
Range: common.CreateSingleCharRange(uint32(line), uint32(character)),
Err: common.SyntaxError{
Message: message,
},
})
}

func createErrorListener(
line uint32,
) errorListener {
return errorListener{
Errors: make([]common.LSPError, 0),
context: errorListenerContext{
line: line,
},
}
}
117 changes: 117 additions & 0 deletions handlers/sshd_config/ast/listener.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package ast

import (
"config-lsp/common"
"config-lsp/handlers/sshd_config/ast/parser"
"strings"
)

func createListener(
config *SSHConfig,
context *sshListenerContext,
) sshParserListener {
return sshParserListener{
Config: config,
Errors: make([]common.LSPError, 0),
sshContext: context,
}
}

type sshListenerContext struct {
line uint32
currentOption *SSHOption
currentMatchBlock *SSHMatchBlock
isKeyAMatchBlock bool
}

func createSSHListenerContext() *sshListenerContext {
context := new(sshListenerContext)
context.isKeyAMatchBlock = false

return context
}

type sshParserListener struct {
*parser.BaseConfigListener
Config *SSHConfig
Errors []common.LSPError
sshContext *sshListenerContext
}

func (s *sshParserListener) EnterEntry(ctx *parser.EntryContext) {
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
location.ChangeBothLines(s.sshContext.line)

option := &SSHOption{
LocationRange: location,
Value: ctx.GetText(),
}

if s.sshContext.currentMatchBlock == nil {
s.Config.Options.Put(
location.Start.Line,
option,
)

s.sshContext.currentOption = option
} else {
s.sshContext.currentMatchBlock.Options.Put(
location.Start.Line,
option,
)

s.sshContext.currentOption = option
}
}

func (s *sshParserListener) EnterKey(ctx *parser.KeyContext) {
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
location.ChangeBothLines(s.sshContext.line)

text := ctx.GetText()

if strings.ToLower(text) == "match" {
s.sshContext.isKeyAMatchBlock = true
}

s.sshContext.currentOption.Key = &SSHKey{
LocationRange: location,
Value: ctx.GetText(),
}
}

func (s *sshParserListener) EnterValue(ctx *parser.ValueContext) {
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
location.ChangeBothLines(s.sshContext.line)

s.sshContext.currentOption.OptionValue = &SSHValue{
LocationRange: location,
Value: ctx.GetText(),
}
}

func (s *sshParserListener) ExitValue(ctx *parser.ValueContext) {
if s.sshContext.isKeyAMatchBlock {
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
location.ChangeBothLines(s.sshContext.line)

rawEntry, _ := s.Config.Options.Get(location.Start.Line)
entry := rawEntry.(*SSHOption)

// Overwrite the current match block
matchBlock := &SSHMatchBlock{
LocationRange: location,
MatchEntry: entry,
}
s.Config.Options.Put(
location.Start.Line,
matchBlock,
)

s.sshContext.currentMatchBlock = matchBlock
s.sshContext.isKeyAMatchBlock = false
}

s.sshContext.currentOption = nil
}

86 changes: 86 additions & 0 deletions handlers/sshd_config/ast/parser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package ast

import (
"config-lsp/common"
"config-lsp/handlers/sshd_config/ast/parser"
"config-lsp/utils"
"regexp"

"github.com/antlr4-go/antlr/v4"
"github.com/emirpasic/gods/maps/treemap"

gods "github.com/emirpasic/gods/utils"
)

func NewSSHConfig() *SSHConfig {
config := &SSHConfig{}
config.Clear()

return config
}

func (c *SSHConfig) Clear() {
c.Options = treemap.NewWith(gods.UInt32Comparator)
c.CommentLines = make(map[uint32]struct{})
}

var commentPattern = regexp.MustCompile(`^\s*#.*$`)
var emptyPattern = regexp.MustCompile(`^\s*$`)

func (c *SSHConfig) Parse(input string) []common.LSPError {
errors := make([]common.LSPError, 0)
lines := utils.SplitIntoLines(input)
context := createSSHListenerContext()

for rawLineNumber, line := range lines {
context.line = uint32(rawLineNumber)

if commentPattern.MatchString(line) {
c.CommentLines[context.line] = struct{}{}
continue
}

if emptyPattern.MatchString(line) {
continue
}

errors = append(
errors,
c.parseStatement(context, line)...,
)
}

return errors
}

func (c *SSHConfig) parseStatement(
context *sshListenerContext,
input string,
) []common.LSPError {
stream := antlr.NewInputStream(input)

lexerErrorListener := createErrorListener(context.line)
lexer := parser.NewConfigLexer(&stream)
lexer.RemoveErrorListeners()
lexer.AddErrorListener(&lexerErrorListener)

tokenStream := antlr.NewCommonTokenStream(lexer, antlr.TokenDefaultChannel)

parserErrorListener := createErrorListener(context.line)
antlrParser := parser.NewConfigParser(tokenStream)
antlrParser.RemoveErrorListeners()
antlrParser.AddErrorListener(&parserErrorListener)

listener := createListener(c, context)
antlr.ParseTreeWalkerDefault.Walk(
&listener,
antlrParser.LineStatement(),
)

errors := lexerErrorListener.Errors
errors = append(errors, parserErrorListener.Errors...)
errors = append(errors, listener.Errors...)

return errors
}

26 changes: 26 additions & 0 deletions handlers/sshd_config/ast/parser/Config.interp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
token literal names:
null
'#'
null
null
null
null

token symbolic names:
null
HASH
MATCH
WHITESPACE
STRING
NEWLINE

rule names:
lineStatement
entry
key
value
leadingComment


atn:
[4, 1, 5, 55, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 1, 0, 1, 0, 3, 0, 13, 8, 0, 1, 0, 1, 0, 3, 0, 17, 8, 0, 3, 0, 19, 8, 0, 1, 0, 1, 0, 1, 1, 3, 1, 24, 8, 1, 1, 1, 3, 1, 27, 8, 1, 1, 1, 1, 1, 3, 1, 31, 8, 1, 1, 1, 3, 1, 34, 8, 1, 1, 1, 3, 1, 37, 8, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1, 4, 3, 4, 45, 8, 4, 1, 4, 1, 4, 3, 4, 49, 8, 4, 4, 4, 51, 8, 4, 11, 4, 12, 4, 52, 1, 4, 0, 0, 5, 0, 2, 4, 6, 8, 0, 0, 61, 0, 18, 1, 0, 0, 0, 2, 23, 1, 0, 0, 0, 4, 38, 1, 0, 0, 0, 6, 40, 1, 0, 0, 0, 8, 42, 1, 0, 0, 0, 10, 19, 3, 2, 1, 0, 11, 13, 5, 3, 0, 0, 12, 11, 1, 0, 0, 0, 12, 13, 1, 0, 0, 0, 13, 14, 1, 0, 0, 0, 14, 19, 3, 8, 4, 0, 15, 17, 5, 3, 0, 0, 16, 15, 1, 0, 0, 0, 16, 17, 1, 0, 0, 0, 17, 19, 1, 0, 0, 0, 18, 10, 1, 0, 0, 0, 18, 12, 1, 0, 0, 0, 18, 16, 1, 0, 0, 0, 19, 20, 1, 0, 0, 0, 20, 21, 5, 0, 0, 1, 21, 1, 1, 0, 0, 0, 22, 24, 5, 3, 0, 0, 23, 22, 1, 0, 0, 0, 23, 24, 1, 0, 0, 0, 24, 26, 1, 0, 0, 0, 25, 27, 3, 4, 2, 0, 26, 25, 1, 0, 0, 0, 26, 27, 1, 0, 0, 0, 27, 28, 1, 0, 0, 0, 28, 30, 5, 3, 0, 0, 29, 31, 3, 6, 3, 0, 30, 29, 1, 0, 0, 0, 30, 31, 1, 0, 0, 0, 31, 33, 1, 0, 0, 0, 32, 34, 5, 3, 0, 0, 33, 32, 1, 0, 0, 0, 33, 34, 1, 0, 0, 0, 34, 36, 1, 0, 0, 0, 35, 37, 3, 8, 4, 0, 36, 35, 1, 0, 0, 0, 36, 37, 1, 0, 0, 0, 37, 3, 1, 0, 0, 0, 38, 39, 5, 4, 0, 0, 39, 5, 1, 0, 0, 0, 40, 41, 5, 4, 0, 0, 41, 7, 1, 0, 0, 0, 42, 44, 5, 1, 0, 0, 43, 45, 5, 3, 0, 0, 44, 43, 1, 0, 0, 0, 44, 45, 1, 0, 0, 0, 45, 50, 1, 0, 0, 0, 46, 48, 5, 4, 0, 0, 47, 49, 5, 3, 0, 0, 48, 47, 1, 0, 0, 0, 48, 49, 1, 0, 0, 0, 49, 51, 1, 0, 0, 0, 50, 46, 1, 0, 0, 0, 51, 52, 1, 0, 0, 0, 52, 50, 1, 0, 0, 0, 52, 53, 1, 0, 0, 0, 53, 9, 1, 0, 0, 0, 11, 12, 16, 18, 23, 26, 30, 33, 36, 44, 48, 52]
6 changes: 6 additions & 0 deletions handlers/sshd_config/ast/parser/Config.tokens
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
HASH=1
MATCH=2
WHITESPACE=3
STRING=4
NEWLINE=5
'#'=1
32 changes: 32 additions & 0 deletions handlers/sshd_config/ast/parser/ConfigLexer.interp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
token literal names:
null
'#'
null
null
null
null

token symbolic names:
null
HASH
MATCH
WHITESPACE
STRING
NEWLINE

rule names:
HASH
MATCH
WHITESPACE
STRING
NEWLINE

channel names:
DEFAULT_TOKEN_CHANNEL
HIDDEN

mode names:
DEFAULT_MODE

atn:
[4, 0, 5, 34, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 2, 21, 8, 2, 11, 2, 12, 2, 22, 1, 3, 4, 3, 26, 8, 3, 11, 3, 12, 3, 27, 1, 4, 3, 4, 31, 8, 4, 1, 4, 1, 4, 0, 0, 5, 1, 1, 3, 2, 5, 3, 7, 4, 9, 5, 1, 0, 7, 2, 0, 77, 77, 109, 109, 2, 0, 65, 65, 97, 97, 2, 0, 84, 84, 116, 116, 2, 0, 67, 67, 99, 99, 2, 0, 72, 72, 104, 104, 2, 0, 9, 9, 32, 32, 4, 0, 9, 10, 13, 13, 32, 32, 35, 35, 36, 0, 1, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 9, 1, 0, 0, 0, 1, 11, 1, 0, 0, 0, 3, 13, 1, 0, 0, 0, 5, 20, 1, 0, 0, 0, 7, 25, 1, 0, 0, 0, 9, 30, 1, 0, 0, 0, 11, 12, 5, 35, 0, 0, 12, 2, 1, 0, 0, 0, 13, 14, 7, 0, 0, 0, 14, 15, 7, 1, 0, 0, 15, 16, 7, 2, 0, 0, 16, 17, 7, 3, 0, 0, 17, 18, 7, 4, 0, 0, 18, 4, 1, 0, 0, 0, 19, 21, 7, 5, 0, 0, 20, 19, 1, 0, 0, 0, 21, 22, 1, 0, 0, 0, 22, 20, 1, 0, 0, 0, 22, 23, 1, 0, 0, 0, 23, 6, 1, 0, 0, 0, 24, 26, 8, 6, 0, 0, 25, 24, 1, 0, 0, 0, 26, 27, 1, 0, 0, 0, 27, 25, 1, 0, 0, 0, 27, 28, 1, 0, 0, 0, 28, 8, 1, 0, 0, 0, 29, 31, 5, 13, 0, 0, 30, 29, 1, 0, 0, 0, 30, 31, 1, 0, 0, 0, 31, 32, 1, 0, 0, 0, 32, 33, 5, 10, 0, 0, 33, 10, 1, 0, 0, 0, 4, 0, 22, 27, 30, 0]
6 changes: 6 additions & 0 deletions handlers/sshd_config/ast/parser/ConfigLexer.tokens
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
HASH=1
MATCH=2
WHITESPACE=3
STRING=4
NEWLINE=5
'#'=1
Loading

0 comments on commit af580fa

Please sign in to comment.