mirror of
https://github.com/trufflesecurity/trufflehog.git
synced 2024-11-14 00:47:21 +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"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers"
|
"github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers"
|
||||||
|
@ -16,7 +15,9 @@ import (
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/context"
|
"github.com/trufflesecurity/trufflehog/v3/pkg/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Analyzer struct{}
|
type Analyzer struct {
|
||||||
|
Cfg *config.Config
|
||||||
|
}
|
||||||
|
|
||||||
func (a *Analyzer) Type() analyzerpb.AnalyzerType {
|
func (a *Analyzer) Type() analyzerpb.AnalyzerType {
|
||||||
return analyzerpb.AnalyzerType_Twilio
|
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")
|
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
|
sid, ok := credentialInfo["sid"]
|
||||||
info, err := AnalyzePermissions(cfg, key)
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// List parent and subaccounts
|
// List parent and subaccounts
|
||||||
accounts, err := listTwilioAccounts(cfg, key)
|
accounts, err := listTwilioAccounts(a.Cfg, sid, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -124,15 +133,6 @@ const (
|
||||||
INVALID_CREDENTIALS = 20003
|
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
|
// 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.
|
// 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) {
|
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
|
return serviceRes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func listTwilioAccounts(cfg *config.Config, key string) ([]service, error) {
|
func listTwilioAccounts(cfg *config.Config, sid, secret string) ([]service, error) {
|
||||||
sid, secret, err := splitKey(key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// create http client
|
// create http client
|
||||||
client := analyzers.NewAnalyzeClient(cfg)
|
client := analyzers.NewAnalyzeClient(cfg)
|
||||||
|
|
||||||
|
@ -237,12 +232,7 @@ func listTwilioAccounts(cfg *config.Config, key string) ([]service, error) {
|
||||||
return result.Accounts, nil
|
return result.Accounts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func AnalyzePermissions(cfg *config.Config, key string) (*secretInfo, error) {
|
func AnalyzePermissions(cfg *config.Config, sid, secret string) (*secretInfo, error) {
|
||||||
sid, secret, err := splitKey(key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
servicesRes, err := getVerifyServicesStatusCode(cfg, sid, secret)
|
servicesRes, err := getVerifyServicesStatusCode(cfg, sid, secret)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -259,14 +249,8 @@ func AnalyzePermissions(cfg *config.Config, key string) (*secretInfo, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func AnalyzeAndPrintPermissions(cfg *config.Config, key string) {
|
func AnalyzeAndPrintPermissions(cfg *config.Config, sid, secret string) {
|
||||||
// ToDo: Add in logging
|
info, err := AnalyzePermissions(cfg, sid, secret)
|
||||||
if cfg.LoggingEnabled {
|
|
||||||
color.Red("[x] Logging is not supported for this analyzer.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
info, err := AnalyzePermissions(cfg, key)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
color.Red("[x] Error: %s", err.Error())
|
color.Red("[x] Error: %s", err.Error())
|
||||||
return
|
return
|
||||||
|
|
|
@ -20,13 +20,15 @@ func TestAnalyzer_Analyze(t *testing.T) {
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
sid string
|
||||||
key string
|
key string
|
||||||
want string // JSON string
|
want string // JSON string
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "valid Twilio key",
|
name: "valid Twilio key",
|
||||||
key: testSecrets.MustGetField("TWILLIO_ID") + ":" + testSecrets.MustGetField("TWILLIO_API"),
|
sid: testSecrets.MustGetField("TWILLIO_ID"),
|
||||||
|
key: testSecrets.MustGetField("TWILLIO_API"),
|
||||||
want: ` {
|
want: ` {
|
||||||
"AnalyzerType": 20,
|
"AnalyzerType": 20,
|
||||||
"Bindings": [
|
"Bindings": [
|
||||||
|
@ -249,7 +251,7 @@ func TestAnalyzer_Analyze(t *testing.T) {
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
a := Analyzer{}
|
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 {
|
if (err != nil) != tt.wantErr {
|
||||||
t.Errorf("Analyzer.Analyze() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("Analyzer.Analyze() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
return
|
return
|
||||||
|
|
|
@ -70,7 +70,7 @@ func Run(cmd string) {
|
||||||
case "slack":
|
case "slack":
|
||||||
slack.AnalyzeAndPrintPermissions(secretInfo.Cfg, secretInfo.Parts["key"])
|
slack.AnalyzeAndPrintPermissions(secretInfo.Cfg, secretInfo.Parts["key"])
|
||||||
case "twilio":
|
case "twilio":
|
||||||
twilio.AnalyzeAndPrintPermissions(secretInfo.Cfg, secretInfo.Parts["key"])
|
twilio.AnalyzeAndPrintPermissions(secretInfo.Cfg, secretInfo.Parts["sid"], secretInfo.Parts["key"])
|
||||||
case "airbrake":
|
case "airbrake":
|
||||||
airbrake.AnalyzeAndPrintPermissions(secretInfo.Cfg, secretInfo.Parts["key"])
|
airbrake.AnalyzeAndPrintPermissions(secretInfo.Cfg, secretInfo.Parts["key"])
|
||||||
case "huggingface":
|
case "huggingface":
|
||||||
|
|
|
@ -20,19 +20,40 @@ type FormPage struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFormPage(c *common.Common, keyType string) FormPage {
|
func NewFormPage(c *common.Common, keyType string) FormPage {
|
||||||
inputs := []textinputs.InputConfig{{
|
var inputs []textinputs.InputConfig
|
||||||
Label: "Secret",
|
switch keyType {
|
||||||
Key: "key",
|
case "twilio":
|
||||||
Required: true,
|
inputs = []textinputs.InputConfig{{
|
||||||
RedactInput: true,
|
Label: "SID",
|
||||||
}}
|
Key: "sid",
|
||||||
if keyType == "shopify" {
|
Required: true,
|
||||||
inputs = append(inputs, textinputs.InputConfig{
|
}, {
|
||||||
|
Label: "Token",
|
||||||
|
Key: "key",
|
||||||
|
Required: true,
|
||||||
|
RedactInput: true,
|
||||||
|
}}
|
||||||
|
case "shopify":
|
||||||
|
inputs = []textinputs.InputConfig{{
|
||||||
|
Label: "Secret",
|
||||||
|
Key: "key",
|
||||||
|
Required: true,
|
||||||
|
RedactInput: true,
|
||||||
|
}, {
|
||||||
Label: "Shopify URL",
|
Label: "Shopify URL",
|
||||||
Key: "url",
|
Key: "url",
|
||||||
Required: true,
|
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{
|
inputs = append(inputs, textinputs.InputConfig{
|
||||||
Label: "Log file",
|
Label: "Log file",
|
||||||
Help: "Log HTTP requests that analysis performs to this 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 {
|
if res.StatusCode >= 200 && res.StatusCode < 300 {
|
||||||
s1.Verified = true
|
s1.Verified = true
|
||||||
s1.AnalysisInfo = map[string]string{"key": sid + ":" + key}
|
s1.AnalysisInfo = map[string]string{"key": key, "sid": sid}
|
||||||
var serviceResponse serviceResponse
|
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
|
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]
|
service := serviceResponse.Services[0]
|
||||||
|
|
Loading…
Reference in a new issue