Skip to content

Commit

Permalink
Merge branch 'main' into feat/oss-95-launchdarkly-analyzer
Browse files Browse the repository at this point in the history
  • Loading branch information
kashifkhan0771 committed Mar 4, 2025
2 parents 9806026 + 59c6f2d commit cc2ac00
Showing 31 changed files with 2,239 additions and 244 deletions.
93 changes: 2 additions & 91 deletions README.md
Original file line number Diff line number Diff line change
@@ -662,97 +662,8 @@ your custom detector has multiple `regex` set (in this example `hogID`, and `hog

**NB:** This feature is alpha and subject to change.

## Regex Detector Example

```yaml
# config.yaml
detectors:
- name: HogTokenDetector
keywords:
- hog
regex:
hogID: '\b(HOG[0-9A-Z]{17})\b'
hogToken: '[^A-Za-z0-9+\/]{0,1}([A-Za-z0-9+\/]{40})[^A-Za-z0-9+\/]{0,1}'
verify:
- endpoint: http://localhost:8000/
# unsafe must be set if the endpoint is HTTP
unsafe: true
headers:
- "Authorization: super secret authorization header"
```

```
$ trufflehog filesystem /tmp --config config.yaml --results=verified,unknown
🐷🔑🐷 TruffleHog. Unearth your secrets. 🐷🔑🐷

Found verified result 🐷🔑
Detector Type: CustomRegex
Decoder Type: PLAIN
Raw result: HOGAAIUNNWHAHJJWUQYR
File: /tmp/hog-facts.txt
```
Data structure sent to the custom verification server:
```
{
"HogTokenDetector": {
"HogID": ["HOGAAIUNNWHAHJJWUQYR"],
"HogSecret": ["sD9vzqdSsAOxntjAJ/qZ9sw+8PvEYg0r7D1Hhh0C"],
}
}
```
## Verification Server Example (Python)
Unless you run a verification server, secrets found by the custom regex
detector will be unverified. Here is an example Python implementation of a
verification server for the above `config.yaml` file.
```python
import json
from http.server import BaseHTTPRequestHandler, HTTPServer
AUTH_HEADER = 'super secret authorization header'
class Verifier(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(405)
self.end_headers()
def do_POST(self):
try:
if self.headers['Authorization'] != AUTH_HEADER:
self.send_response(401)
self.end_headers()
return
# read the body
length = int(self.headers['Content-Length'])
request = json.loads(self.rfile.read(length))
self.log_message("%s", request)
# check the match, you'll need to implement validateToken, which takes an array of ID's and Secrets
if not validateTokens(request['HogTokenDetector']['hogID'], request['HogTokenDetector']['hogSecret']):
self.send_response(200)
self.end_headers()
else:
# any other response besides 200
self.send_response(406)
self.end_headers()
except Exception:
self.send_response(400)
self.end_headers()
with HTTPServer(('', 8000), Verifier) as server:
try:
server.serve_forever()
except KeyboardInterrupt:
pass
```

### Regex Detector Example
[Here](/pkg/custom_detectors/CUSTOM_DETECTORS.md) is how to setup a custom regex detector with verification server.


## :mag: Analyze
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ module github.com/trufflesecurity/trufflehog/v3

go 1.23.1

toolchain go1.23.6
toolchain go1.24.0

replace github.com/jpillora/overseer => github.com/trufflesecurity/overseer v1.2.8

79 changes: 79 additions & 0 deletions pkg/analyzer/analyzers/airtable/airtableoauth/airtable.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package airtableoauth

import (
"errors"

"github.com/fatih/color"

"github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers"
"github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers/airtable/common"
"github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/config"
"github.com/trufflesecurity/trufflehog/v3/pkg/context"
)

var _ analyzers.Analyzer = (*Analyzer)(nil)

type Analyzer struct {
Cfg *config.Config
}

func (Analyzer) Type() analyzers.AnalyzerType { return analyzers.AnalyzerTypeAirtableOAuth }

func (a Analyzer) Analyze(_ context.Context, credInfo map[string]string) (*analyzers.AnalyzerResult, error) {
token, ok := credInfo["token"]
if !ok {
return nil, errors.New("token not found in credInfo")
}

userInfo, err := common.FetchAirtableUserInfo(token)
if err != nil {
return nil, err
}

var basesInfo *common.AirtableBases
baseScope := common.PermissionStrings[common.SchemaBasesRead]
if hasScope(userInfo.Scopes, baseScope) {
basesInfo, _ = common.FetchAirtableBases(token)
}

return common.MapToAnalyzerResult(userInfo, basesInfo), nil
}

func AnalyzeAndPrintPermissions(cfg *config.Config, token string) {
userInfo, err := common.FetchAirtableUserInfo(token)
if err != nil {
color.Red("[x] Error : %s", err.Error())
return
}

color.Green("[!] Valid Airtable OAuth2 Access Token\n\n")
printUserAndPermissions(userInfo)

baseScope := common.PermissionStrings[common.SchemaBasesRead]
if hasScope(userInfo.Scopes, baseScope) {
var basesInfo *common.AirtableBases
basesInfo, _ = common.FetchAirtableBases(token)
common.PrintBases(basesInfo)
}
}

func hasScope(scopes []string, target string) bool {
for _, scope := range scopes {
if scope == target {
return true
}
}
return false
}

func printUserAndPermissions(info *common.AirtableUserInfo) {
scopeStatusMap := make(map[string]bool)
for _, scope := range common.PermissionStrings {
scopeStatusMap[scope] = false
}
for _, scope := range info.Scopes {
scopeStatusMap[scope] = true
}

common.PrintUserAndPermissions(info, scopeStatusMap)
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package airtable
package airtableoauth

import (
_ "embed"
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"AnalyzerType": 22,
"AnalyzerType": 28,
"Bindings": [
{
"Resource": {
Loading
Oops, something went wrong.

0 comments on commit cc2ac00

Please sign in to comment.