Skip to content

Commit

Permalink
Updates config and library with the proper functions from utils. Remo…
Browse files Browse the repository at this point in the history
…ves utils completely.
  • Loading branch information
kyallanum committed Dec 31, 2023
1 parent 65bea3d commit 366bc7f
Show file tree
Hide file tree
Showing 9 changed files with 467 additions and 32 deletions.
17 changes: 8 additions & 9 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
config "github.com/kyallanum/athena/v1.0.0/models/config"
library "github.com/kyallanum/athena/v1.0.0/models/library"
logs "github.com/kyallanum/athena/v1.0.0/models/logs"
"github.com/kyallanum/athena/v1.0.0/utils"
)

func errCheck(err error) {
Expand Down Expand Up @@ -46,31 +45,31 @@ func parseFlags(configFile *string, logFile *string) error {
return nil
}

func resolveLogFile(contents *logs.LogFile, config *config.Configuration) (*library.Library, error) {
func resolveLogFile(contents *logs.LogFile, configuration *config.Configuration) (*library.Library, error) {
wrapError := func(err error) error {
return fmt.Errorf("unable to resolve log file: \n\t%w", err)
}

if contents == nil || contents.Len() == 0 {
return nil, fmt.Errorf("log file contains no contents")
} else if config == nil || (config.Name == "" && config.Rules == nil) {
} else if configuration == nil || (configuration.Name == "" && configuration.Rules == nil) {
return nil, fmt.Errorf("configuration file has no contents")
} else if config.Name == "" {
} else if configuration.Name == "" {
return nil, fmt.Errorf("configuration file contains no log name")
} else if config.Rules == nil || len(config.Rules) == 0 {
} else if configuration.Rules == nil || len(configuration.Rules) == 0 {
return nil, fmt.Errorf("configuration does not have any rules")
}

ret_library := library.Library.New(library.Library{}, config.Name)
ret_library := library.Library.New(library.Library{}, configuration.Name)

fmt.Println("Resolving Log File")
for i := 0; i < len(config.Rules); i++ {
currentRuleData, err := utils.ResolveRule(contents, &config.Rules[i])
for i := 0; i < len(configuration.Rules); i++ {
currentRuleData, err := config.ResolveRule(contents, &configuration.Rules[i])
if err != nil {
return nil, wrapError(err)
}

ret_library.AddRuleData(config.Rules[i].Name, currentRuleData)
ret_library.AddRuleData(configuration.Rules[i].Name, currentRuleData)
}

fmt.Println("Log File Resolved")
Expand Down
22 changes: 1 addition & 21 deletions models/config/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package models
import (
"encoding/json"
"fmt"
"regexp"
)

// A Configuration struct represents the top level of a JSON configuration file.
Expand Down Expand Up @@ -39,7 +38,7 @@ type Rule struct {
func (config *Configuration) TranslateConfiguration() error {
for ruleIndex, currentRule := range config.Rules {
for searchTermIndex, currentSearchTerm := range currentRule.SearchTerms {
err := translateRegex(&currentSearchTerm)
err := translateConfigurationNamedGroups(&currentSearchTerm)
if err != nil {
return err
}
Expand All @@ -49,25 +48,6 @@ func (config *Configuration) TranslateConfiguration() error {
return nil
}

func translateRegex(regex *string) error {
if *regex == "" {
return fmt.Errorf("empty search terms are not allowed")
}

defer func() {
if err := recover(); err != nil {
panic(fmt.Errorf("unable to translate regex: \"%s\" for Go standards, this is most likely an internal error: \n\t%s", *regex, err.(string)))
}
}()

regexAddGolangGroupName := `(\(\?)(\<[\w\W]+?\>)`
compiledRegex := regexp.MustCompile(regexAddGolangGroupName)

*regex = compiledRegex.ReplaceAllString(*regex, "${1}P${2}")

return nil
}

func CreateConfiguration(source string) (config *Configuration, err error) {
wrapError := func(err error) error {
return fmt.Errorf("unable to create configuration object: \n\t%w", err)
Expand Down
44 changes: 42 additions & 2 deletions models/config/configuration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ import (
"reflect"
"strings"
"testing"

logs "github.com/kyallanum/athena/v1.0.0/models/logs"
)

func TestTranslateRegex(t *testing.T) {
regexToTranslate := "(?<test_name>)"
err := translateRegex(&regexToTranslate)
err := translateConfigurationNamedGroups(&regexToTranslate)

if err != nil {
t.Errorf("An error occurred while attempting to translate regex: \n\t%v", err)
Expand All @@ -26,7 +28,7 @@ func TestTranslateRegex(t *testing.T) {

func TestTranslateRegexEmptyString(t *testing.T) {
regexToTranslate := ""
err := translateRegex(&regexToTranslate)
err := translateConfigurationNamedGroups(&regexToTranslate)

if err.Error() != "empty search terms are not allowed" {
t.Errorf("Error was not properly returned when checking for empty string.")
Expand Down Expand Up @@ -135,3 +137,41 @@ func TestCreateConfigurationFromWeb(t *testing.T) {
})
}
}

func TestResolveRule(t *testing.T) {
os.Stdout, _ = os.Open(os.DevNull)
defer os.Stdout.Close()

logFile, _ := logs.LoadLogFile("../../examples/apt-term.log")

currentConfig, _ := CreateConfiguration("../../examples/apt-term-config.json")

currentRule := currentConfig.Rules[0]

ruleData, err := ResolveRule(logFile, &currentRule)
if err != nil {
t.Errorf("An error was returned when one should not have been: \n\t%s", err.Error())
}

if reflect.TypeOf(ruleData).String() != "*models.RuleData" {
t.Errorf("The incorrect datatype was not returned: \n\t%s", reflect.TypeOf(ruleData).String())
}
}

func TestResolveRuleBadRule(t *testing.T) {
defer func() {
if err := recover(); err == nil {
t.Errorf("An error was not returned when one should have been.")
} else if (err.(error)).Error() != "unable to resolve search terms for rule : \n\truntime error: index out of range [0] with length 0" {
t.Errorf("%s", err.(error).Error())
}
}()
os.Stdout, _ = os.Open(os.DevNull)
defer os.Stdout.Close()

logFile, _ := logs.LoadLogFile("../examples/apt-term.log")

currentRule := &Rule{}

ResolveRule(logFile, currentRule)
}
102 changes: 102 additions & 0 deletions models/config/regex_utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package models

import (
"fmt"
"regexp"
"strings"

library "github.com/kyallanum/athena/v1.0.0/models/library"
)

// func resolveLine determines whether the current log line matches a
// matches a given log line
func resolveLine(line string, regex string) *map[string]string {
defer func() {
if err := recover(); err != nil {
panic(fmt.Errorf("the provided regular expression cannot be compiled: \n\t%s", err.(string)))
}
}()

currentRegexp := regexp.MustCompile(regex)
match := currentRegexp.FindStringSubmatch(line)
result := make(map[string]string)

if len(match) > 0 {
for index, name := range currentRegexp.SubexpNames() {
if index != 0 && name != "" {
result[name] = match[index]
}
}
return &result
}
return nil
}

func translateSearchTermReference(regex string, currentSearchTermData *library.SearchTermData) (string, error) {
defer func() {
if err := recover(); err != nil {
panic(fmt.Errorf("the search term could not be translated. this is most likely an internal error: \n\t%s", err.(string)))
}
}()

// Matches the pattern: {{name_to_replace}}
nameExtractRegex := `(\{\{(?P<name_to_replace>[\w]+?)\}\})`
re := regexp.MustCompile(nameExtractRegex)
matches := re.FindAllStringSubmatch(regex, -1)
numMatches := len(matches)

keysToLookup := []string{}

// The first three groups are useless for this case. So get the last one.
for _, match := range matches {
keysToLookup = append(keysToLookup, match[2])
}

// Validate all strings to replace and then replace them one by one.
for i := 0; i < numMatches; i++ {
stringToReplace, err := currentSearchTermData.Value(strings.TrimSpace(strings.ToLower(keysToLookup[i])))
if err != nil {
return "", fmt.Errorf("an error occurred when translating a search term reference. \n\tthe following key was not registered in a previous search term: %s", keysToLookup[i])
}
stringToReplace = escapeSpecialCharacters(stringToReplace)
foundString := re.FindString(regex)
if foundString != "" {
regex = strings.Replace(regex, foundString, stringToReplace, 1)
}
}

return regex, nil
}

func escapeSpecialCharacters(regex string) string {
defer func() {
if err := recover(); err != nil {
panic(fmt.Errorf("a string could not be escaped. this is most likely an internal error: \n\t%s", err.(string)))
}
}()
charactersToEscape := `([\*\+\?\\\.\^\[\]\$\&\|]{1})`
re := regexp.MustCompile(charactersToEscape)

regex = re.ReplaceAllString(regex, `\${1}`)
return regex
}

func translateConfigurationNamedGroups(regex *string) error {
if *regex == "" {
return fmt.Errorf("empty search terms are not allowed")
}

defer func() {
if err := recover(); err != nil {
panic(fmt.Errorf("unable to translate regex: \"%s\" for Go standards, this is most likely an internal error: \n\t%s", *regex, err.(string)))
}
}()

// Matches the pattern (?<group_name>)
regexAddGolangGroupName := `(\(\?)(\<[\w\W]+?\>)`
compiledRegex := regexp.MustCompile(regexAddGolangGroupName)

*regex = compiledRegex.ReplaceAllString(*regex, "${1}P${2}")

return nil
}
102 changes: 102 additions & 0 deletions models/config/regex_utils_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package models

import (
"reflect"
"testing"

library "github.com/kyallanum/athena/v1.0.0/models/library"
)

func TestResolveLine(t *testing.T) {
defer func() {
if err := recover(); err != nil {
t.Errorf("An error was returned improperly when calling resolveLine: \n\t%s", (err.(error)).Error())
}
}()
line := "test line 1"
regex := "stuff"

result := resolveLine(line, regex)
if result != nil {
t.Errorf("An incorrect object was returned when calling resolveLine")
}

regex = `(?P<test_name>line \d+)`
result = resolveLine(line, regex)

if reflect.TypeOf(result).String() != "*map[string]string" {
t.Errorf("resolveLine did not return the proper data type: \n\t%s", reflect.TypeOf(result).String())
}
}

func TestResolveLineBadRegex(t *testing.T) {
defer func() {
if err := recover(); err == nil {
t.Errorf("An error was not returned properly when it should have")
} else if (err.(error)).Error() != "the provided regular expression cannot be compiled: \n\tregexp: Compile(`(stuff`): error parsing regexp: missing closing ): `(stuff`" {
t.Errorf("The improper error was returned when calling with a bad regex: \n\t%s", (err.(error)).Error())
}
}()

line := "test line 1"
regex := "(stuff"

_ = resolveLine(line, regex)
}

func TestTranslateSearchTermReference(t *testing.T) {
defer func() {
if err := recover(); err != nil {
t.Errorf("An error was returned when it shouldn't have: \n\t%s", (err.(error).Error()))
}
}()

regex := `Testing {{test}}`
st_data := library.SearchTermData.New(library.SearchTermData{})
st_data.AddValue("test", "Test1")

newRegex, err := translateSearchTermReference(regex, st_data)
if err != nil {
t.Errorf("An error was returned when it shouldn't have: \n\t%s", err.Error())
}

if newRegex != "Testing Test1" {
t.Errorf("TranslateSearchTermReference returned the wrong value: \n\t%s", newRegex)
}
}

func TestTranslateSearchTermReferenceBadReference(t *testing.T) {
defer func() {
if err := recover(); err != nil {
t.Errorf("An error was returned when it shouldn't have: \n\t%s", (err.(error).Error()))
}
}()

regex := `Testing {{test}}`
st_data := library.SearchTermData.New(library.SearchTermData{})
st_data.AddValue("bad_test", "testing")

_, err := translateSearchTermReference(regex, st_data)
if err == nil {
t.Errorf("An error was not returned when it should have.")
}

if err.Error() != "an error occurred when translating a search term reference. \n\tthe following key was not registered in a previous search term: test" {
t.Errorf("An improper error was returned when attempting to translate search term reference: \n\t%s", err.Error())
}
}

func TestValidateString(t *testing.T) {
defer func() {
if err := recover(); err != nil {
t.Errorf("An error occurred when it shouldn't have: \n\t%s", (err.(error).Error()))
}
}()

stringToValidate := `*+?\\.^[]$&|`
validatedString := escapeSpecialCharacters(stringToValidate)

if validatedString != "\\*\\+\\?\\\\\\\\\\.\\^\\[\\]\\$\\&\\|" {
t.Errorf("String was not validated properly: %s", validatedString)
}
}
Loading

0 comments on commit 366bc7f

Please sign in to comment.