mirror of
https://github.com/trufflesecurity/trufflehog.git
synced 2024-11-10 07:04:24 +00:00
[analyze] Separate SID from token in twilio analyzer (#3177)
* [analyze] Separate SID from token in twilio analyzer * Fix test * Set sid in detector
This commit is contained in:
parent
59fccbcf3f
commit
1df83f79ef
5 changed files with 54 additions and 47 deletions
|
@ -7,7 +7,6 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers"
|
||||
|
@ -16,7 +15,9 @@ import (
|
|||
"github.com/trufflesecurity/trufflehog/v3/pkg/context"
|
||||
)
|
||||
|
||||
type Analyzer struct{}
|
||||
type Analyzer struct {
|
||||
Cfg *config.Config
|
||||
}
|
||||
|
||||
func (a *Analyzer) Type() analyzerpb.AnalyzerType {
|
||||
return analyzerpb.AnalyzerType_Twilio
|
||||
|
@ -28,14 +29,22 @@ func (a *Analyzer) Analyze(ctx context.Context, credentialInfo map[string]string
|
|||
return nil, errors.New("key not found in credentialInfo")
|
||||
}
|
||||
|
||||
cfg := &config.Config{} // You might need to adjust this based on how you want to handle config
|
||||
info, err := AnalyzePermissions(cfg, key)
|
||||
sid, ok := credentialInfo["sid"]
|
||||
if !ok {
|
||||
return nil, errors.New("sid not found in credentialInfo")
|
||||
}
|
||||
|
||||
if a.Cfg == nil {
|
||||
a.Cfg = &config.Config{} // You might need to adjust this based on how you want to handle config
|
||||
}
|
||||
|
||||
info, err := AnalyzePermissions(a.Cfg, sid, key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// List parent and subaccounts
|
||||
accounts, err := listTwilioAccounts(cfg, key)
|
||||
accounts, err := listTwilioAccounts(a.Cfg, sid, key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -124,15 +133,6 @@ const (
|
|||
INVALID_CREDENTIALS = 20003
|
||||
)
|
||||
|
||||
// splitKey splits the key into SID and Secret
|
||||
func splitKey(key string) (string, string, error) {
|
||||
split := strings.Split(key, ":")
|
||||
if len(split) != 2 {
|
||||
return "", "", errors.New("key must be in the format SID:Secret")
|
||||
}
|
||||
return split[0], split[1], nil
|
||||
}
|
||||
|
||||
// getAccountsStatusCode returns the status code from the Accounts endpoint
|
||||
// this is used to determine whether the key is scoped as main or standard, since standard has no access here.
|
||||
func getAccountsStatusCode(cfg *config.Config, sid string, secret string) (int, error) {
|
||||
|
@ -200,12 +200,7 @@ func getVerifyServicesStatusCode(cfg *config.Config, sid string, secret string)
|
|||
return serviceRes, nil
|
||||
}
|
||||
|
||||
func listTwilioAccounts(cfg *config.Config, key string) ([]service, error) {
|
||||
sid, secret, err := splitKey(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func listTwilioAccounts(cfg *config.Config, sid, secret string) ([]service, error) {
|
||||
// create http client
|
||||
client := analyzers.NewAnalyzeClient(cfg)
|
||||
|
||||
|
@ -237,12 +232,7 @@ func listTwilioAccounts(cfg *config.Config, key string) ([]service, error) {
|
|||
return result.Accounts, nil
|
||||
}
|
||||
|
||||
func AnalyzePermissions(cfg *config.Config, key string) (*secretInfo, error) {
|
||||
sid, secret, err := splitKey(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func AnalyzePermissions(cfg *config.Config, sid, secret string) (*secretInfo, error) {
|
||||
servicesRes, err := getVerifyServicesStatusCode(cfg, sid, secret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -259,14 +249,8 @@ func AnalyzePermissions(cfg *config.Config, key string) (*secretInfo, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
func AnalyzeAndPrintPermissions(cfg *config.Config, key string) {
|
||||
// ToDo: Add in logging
|
||||
if cfg.LoggingEnabled {
|
||||
color.Red("[x] Logging is not supported for this analyzer.")
|
||||
return
|
||||
}
|
||||
|
||||
info, err := AnalyzePermissions(cfg, key)
|
||||
func AnalyzeAndPrintPermissions(cfg *config.Config, sid, secret string) {
|
||||
info, err := AnalyzePermissions(cfg, sid, secret)
|
||||
if err != nil {
|
||||
color.Red("[x] Error: %s", err.Error())
|
||||
return
|
||||
|
|
|
@ -20,13 +20,15 @@ func TestAnalyzer_Analyze(t *testing.T) {
|
|||
|
||||
tests := []struct {
|
||||
name string
|
||||
sid string
|
||||
key string
|
||||
want string // JSON string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "valid Twilio key",
|
||||
key: testSecrets.MustGetField("TWILLIO_ID") + ":" + testSecrets.MustGetField("TWILLIO_API"),
|
||||
sid: testSecrets.MustGetField("TWILLIO_ID"),
|
||||
key: testSecrets.MustGetField("TWILLIO_API"),
|
||||
want: ` {
|
||||
"AnalyzerType": 20,
|
||||
"Bindings": [
|
||||
|
@ -249,7 +251,7 @@ func TestAnalyzer_Analyze(t *testing.T) {
|
|||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
a := Analyzer{}
|
||||
got, err := a.Analyze(ctx, map[string]string{"key": tt.key})
|
||||
got, err := a.Analyze(ctx, map[string]string{"key": tt.key, "sid": tt.sid})
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Analyzer.Analyze() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
|
|
|
@ -70,7 +70,7 @@ func Run(cmd string) {
|
|||
case "slack":
|
||||
slack.AnalyzeAndPrintPermissions(secretInfo.Cfg, secretInfo.Parts["key"])
|
||||
case "twilio":
|
||||
twilio.AnalyzeAndPrintPermissions(secretInfo.Cfg, secretInfo.Parts["key"])
|
||||
twilio.AnalyzeAndPrintPermissions(secretInfo.Cfg, secretInfo.Parts["sid"], secretInfo.Parts["key"])
|
||||
case "airbrake":
|
||||
airbrake.AnalyzeAndPrintPermissions(secretInfo.Cfg, secretInfo.Parts["key"])
|
||||
case "huggingface":
|
||||
|
|
|
@ -20,19 +20,40 @@ type FormPage struct {
|
|||
}
|
||||
|
||||
func NewFormPage(c *common.Common, keyType string) FormPage {
|
||||
inputs := []textinputs.InputConfig{{
|
||||
Label: "Secret",
|
||||
Key: "key",
|
||||
Required: true,
|
||||
RedactInput: true,
|
||||
}}
|
||||
if keyType == "shopify" {
|
||||
inputs = append(inputs, textinputs.InputConfig{
|
||||
var inputs []textinputs.InputConfig
|
||||
switch keyType {
|
||||
case "twilio":
|
||||
inputs = []textinputs.InputConfig{{
|
||||
Label: "SID",
|
||||
Key: "sid",
|
||||
Required: true,
|
||||
}, {
|
||||
Label: "Token",
|
||||
Key: "key",
|
||||
Required: true,
|
||||
RedactInput: true,
|
||||
}}
|
||||
case "shopify":
|
||||
inputs = []textinputs.InputConfig{{
|
||||
Label: "Secret",
|
||||
Key: "key",
|
||||
Required: true,
|
||||
RedactInput: true,
|
||||
}, {
|
||||
Label: "Shopify URL",
|
||||
Key: "url",
|
||||
Required: true,
|
||||
})
|
||||
}}
|
||||
default:
|
||||
inputs = []textinputs.InputConfig{{
|
||||
Label: "Secret",
|
||||
Key: "key",
|
||||
Required: true,
|
||||
RedactInput: true,
|
||||
}}
|
||||
}
|
||||
|
||||
// Always append a log file option.
|
||||
inputs = append(inputs, textinputs.InputConfig{
|
||||
Label: "Log file",
|
||||
Help: "Log HTTP requests that analysis performs to this file",
|
||||
|
|
|
@ -90,7 +90,7 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
|
|||
|
||||
if res.StatusCode >= 200 && res.StatusCode < 300 {
|
||||
s1.Verified = true
|
||||
s1.AnalysisInfo = map[string]string{"key": sid + ":" + key}
|
||||
s1.AnalysisInfo = map[string]string{"key": key, "sid": sid}
|
||||
var serviceResponse serviceResponse
|
||||
if err := json.NewDecoder(res.Body).Decode(&serviceResponse); err == nil && len(serviceResponse.Services) > 0 { // no error in parsing and have at least one service
|
||||
service := serviceResponse.Services[0]
|
||||
|
|
Loading…
Reference in a new issue