| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- // == WARNING ==
- // These functions are used to generate GitLeak's default config.
- // You are free to use these in your own project, HOWEVER, no API stability is guaranteed.
- package utils
- import (
- "fmt"
- "strings"
- regexp "github.com/wasilibs/go-re2"
- )
- const (
- // case insensitive prefix
- caseInsensitive = `(?i)`
- // identifier prefix (just an ignore group)
- identifierCaseInsensitivePrefix = `[\w.-]{0,50}?(?i:`
- identifierCaseInsensitiveSuffix = `)`
- identifierPrefix = `[\w.-]{0,50}?(?:`
- identifierSuffix = `)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}`
- // commonly used assignment operators or function call
- //language=regexp
- operator = `(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)`
- // boundaries for the secret
- // \x60 = `
- secretPrefixUnique = `\b(`
- secretPrefix = `(?:'|\"|\s|=|\x60){0,5}(`
- secretSuffix = `)(?:['|\"|\n|\r|\s|\x60|;]|$)`
- )
- func GenerateSemiGenericRegex(identifiers []string, secretRegex string, isCaseInsensitive bool) *regexp.Regexp {
- var sb strings.Builder
- // The identifiers should always be case-insensitive.
- // This is inelegant but prevents an extraneous `(?i:)` from being added to the pattern; it could be removed.
- if isCaseInsensitive {
- sb.WriteString(caseInsensitive)
- writeIdentifiers(&sb, identifiers)
- } else {
- sb.WriteString(identifierCaseInsensitivePrefix)
- writeIdentifiers(&sb, identifiers)
- sb.WriteString(identifierCaseInsensitiveSuffix)
- }
- sb.WriteString(operator)
- sb.WriteString(secretPrefix)
- sb.WriteString(secretRegex)
- sb.WriteString(secretSuffix)
- return regexp.MustCompile(sb.String())
- }
- func MergeRegexps(regexps ...*regexp.Regexp) *regexp.Regexp {
- patterns := make([]string, len(regexps))
- for i, r := range regexps {
- patterns[i] = r.String()
- }
- return regexp.MustCompile(strings.Join(patterns, "|"))
- }
- func writeIdentifiers(sb *strings.Builder, identifiers []string) {
- sb.WriteString(identifierPrefix)
- sb.WriteString(strings.Join(identifiers, "|"))
- sb.WriteString(identifierSuffix)
- }
- func GenerateUniqueTokenRegex(secretRegex string, isCaseInsensitive bool) *regexp.Regexp {
- var sb strings.Builder
- if isCaseInsensitive {
- sb.WriteString(caseInsensitive)
- }
- sb.WriteString(secretPrefixUnique)
- sb.WriteString(secretRegex)
- sb.WriteString(secretSuffix)
- return regexp.MustCompile(sb.String())
- }
- func GenerateSampleSecret(identifier string, secret string) string {
- return fmt.Sprintf("%s_api_token = \"%s\"", identifier, secret)
- }
- // See: https://github.com/gitleaks/gitleaks/issues/1222
- func GenerateSampleSecrets(identifier string, secret string) []string {
- samples := map[string]string{
- // Configuration
- // INI
- "ini - quoted1": "{i}Token=\"{s}\"",
- "ini - quoted2": "{i}Token = \"{s}\"",
- "ini - unquoted1": "{i}Token={s}",
- "ini - unquoted2": "{i}Token = {s}",
- // JSON
- "json - string": "{\n \"{i}_token\": \"{s}\"\n}",
- // TODO: "json - escaped string": "\\{\n \\\"{i}_token\\\": \\\"{s}\\\"\n\\}",
- // TODO: "json - string key/value": "{\n \"name\": \"{i}_token\",\n \"value\": \"{s}\"\n}",
- // XML
- // TODO: "xml - element": "<{i}Token>{s}</{i}Token>",
- "xml - element multiline": "<{i}Token>\n {s}\n</{i}Token>",
- // TODO: "xml - attribute": "<entry name=\"{i}Token\" value=\"{s}\" />",
- // TODO: "xml - key/value elements": "<entry>\n <name=\"{i}Token\" />\n <value=\"{s}\" />\n</entry>",
- // YAML
- "yaml - singleline - unquoted": "{i}_token: {s}",
- "yaml - singleline - single quote": "{i}_token: '{s}'",
- "yaml - singleline - double quote": "{i}_token: \"{s}\"",
- // TODO: "yaml - multiline - literal": "{i}_token: |\n {s}",
- // TODO: "yaml - multiline - folding": "{i}_token: >\n {s}",
- // "": "",
- // Programming Languages
- "C#": `string {i}Token = "{s}";`,
- "go - normal": `var {i}Token string = "{s}"`,
- "go - short": `{i}Token := "{s}"`,
- "go - backticks": "{i}Token := `{s}`",
- "java": "String {i}Token = \"{s}\";",
- // TODO: "java - escaped quotes": `config.put("sasl.jaas.config", "org.apache.kafka.common.security.plain.PlainLoginModule required username=\"JDOE35\" {i}Token=\"{s}\""`,
- // TODO:"kotlin - type": "var {i}Token: string = \"{s}\"",
- "kotlin - notype": "var {i}Token = \"{s}\"",
- "php - string concat": `${i}Token .= "{s}"`,
- // TODO: "php - null coalesce": `${i}Token ??= "{s}"`,
- "python - single quote": "{i}Token = '{s}'",
- "python - double quote": `{i}Token = "{s}"`,
- // "": "",
- // Miscellaneous
- // TODO: "url - basic auth": `https://{i}:{s}@example.com/`,
- // TODO: "url - query parameter": "https://example.com?{i}Token={s}&fooBar=baz",
- // TODO: "comment - slash": "//{s} is the password",
- // TODO: "comment - slash multiline": "/*{s} is the password",
- // TODO: "comment - hashtag": "#{s} is the password",
- // TODO: "comment - semicolon": ";{s} is the password",
- // TODO: "csv - unquoted": `{i}Token,{s},`,
- "logstash": " \"{i}Token\" => \"{s}\"",
- // TODO: "sql - tabular": "|{s}|",
- // TODO: "sql": "",
- // Makefile
- // See: https://github.com/gitleaks/gitleaks/pull/1191
- "make - recursive assignment": "{i}_TOKEN = \"{s}\"",
- "make - simple assignment": "{i}_TOKEN := \"{s}\"",
- "make - shell assignment": "{i}_TOKEN ::= \"{s}\"",
- "make - evaluated shell assignment": "{i}_TOKEN :::= \"{s}\"",
- "make - conditional assignment": "{i}_TOKEN ?= \"{s}\"",
- // TODO: "make - append": "{i}_TOKEN += \"{s}\"",
- // "": "",
- }
- replacer := strings.NewReplacer("{i}", identifier, "{s}", secret)
- cases := make([]string, 0, len(samples))
- for _, v := range samples {
- cases = append(cases, replacer.Replace(v))
- }
- return cases
- }
|