Skip to content

Commit

Permalink
add twilio analyze relationships
Browse files Browse the repository at this point in the history
  • Loading branch information
dustin-decker committed Aug 1, 2024
1 parent b193feb commit 5dc1ce5
Show file tree
Hide file tree
Showing 4 changed files with 403 additions and 40 deletions.
138 changes: 99 additions & 39 deletions pkg/analyzer/analyzers/twilio/twilio.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ func (a *Analyzer) Analyze(ctx context.Context, credentialInfo map[string]string
return nil, err
}

// List parent and subaccounts
accounts, err := listTwilioAccounts(cfg, key)
if err != nil {
return nil, err
}

var permissions []Permission
if info.AccountStatusCode == 200 {
permissions = []Permission{
Expand Down Expand Up @@ -69,21 +75,37 @@ func (a *Analyzer) Analyze(ctx context.Context, credentialInfo map[string]string
}
}

// Can we get org information?
resource := analyzers.Resource{
Name: "Twilio API",
Type: "API",
}

var bindings []analyzers.Binding
for _, perm := range permissions {
permStr, _ := perm.ToString()
bindings = append(bindings, analyzers.Binding{
Resource: resource,
Permission: analyzers.Permission{
Value: permStr,
},
})
parentAccountSID := info.ServicesRes.Services[0].AccountSID
parentAccountFriendlyName := info.ServicesRes.Services[0].FriendlyName

for _, account := range accounts {
accountType := "Account"
if account.SID != parentAccountSID {
accountType = "SubAccount"
}
resource := analyzers.Resource{
Name: account.FriendlyName,
FullyQualifiedName: "twilio.com/account/" + account.SID,
Type: accountType,
}
if account.SID != parentAccountSID {
resource.Parent = &analyzers.Resource{
Name: parentAccountFriendlyName,
FullyQualifiedName: "twilio.com/account/" + parentAccountSID,
Type: "Account",
}
}

for _, perm := range permissions {
permStr, _ := perm.ToString()
bindings = append(bindings, analyzers.Binding{
Resource: resource,
Permission: analyzers.Permission{
Value: permStr,
},
})
}
}

return &analyzers.AnalyzerResult{
Expand All @@ -92,12 +114,12 @@ func (a *Analyzer) Analyze(ctx context.Context, credentialInfo map[string]string
}, nil
}

type VerifyJSON struct {
type verifyJSON struct {

Check failure on line 117 in pkg/analyzer/analyzers/twilio/twilio.go

View workflow job for this annotation

GitHub Actions / golangci-lint

type `verifyJSON` is unused (unused)
Code int `json:"code"`
}

type SecretInfo struct {
VerifyJson VerifyJSON
type secretInfo struct {
ServicesRes serviceResponse
AccountStatusCode int
}

Expand Down Expand Up @@ -127,11 +149,6 @@ func getAccountsStatusCode(cfg *config.Config, sid string, secret string) (int,
return 0, err
}

// add query params
q := req.URL.Query()
q.Add("FriendlyName", "zpoOnD08HdLLZGFnGUMTxbX3qQ1kS")
req.URL.RawQuery = q.Encode()

// add basicAuth
req.SetBasicAuth(sid, secret)

Expand All @@ -144,50 +161,93 @@ func getAccountsStatusCode(cfg *config.Config, sid string, secret string) (int,
return resp.StatusCode, nil
}

type serviceResponse struct {
Code int `json:"code"`
Services []service `json:"services"`
}

type service struct {
FriendlyName string `json:"friendly_name"` // friendly name of a service
SID string `json:"sid"` // object id of service
AccountSID string `json:"account_sid"` // account sid
}

// getVerifyServicesStatusCode returns the status code and the JSON response from the Verify Services endpoint
// only the code value is captured in the JSON response and this is only shown when the key is invalid or has no permissions
func getVerifyServicesStatusCode(cfg *config.Config, sid string, secret string) (VerifyJSON, error) {
var verifyJSON VerifyJSON
func getVerifyServicesStatusCode(cfg *config.Config, sid string, secret string) (serviceResponse, error) {
var serviceRes serviceResponse

// create http client
client := analyzers.NewAnalyzeClient(cfg)

// create request
req, err := http.NewRequest("GET", "https://verify.twilio.com/v2/Services", nil)
if err != nil {
return verifyJSON, err
return serviceRes, err
}

// add query params
q := req.URL.Query()
q.Add("FriendlyName", "zpoOnD08HdLLZGFnGUMTxbX3qQ1kS")
req.URL.RawQuery = q.Encode()
// add basicAuth
req.SetBasicAuth(sid, secret)

// send request
resp, err := client.Do(req)
if err != nil {
return serviceRes, err
}
defer resp.Body.Close()

// read response
if err := json.NewDecoder(resp.Body).Decode(&serviceRes); err != nil {
return serviceRes, err
}

return serviceRes, nil
}

func listTwilioAccounts(cfg *config.Config, key string) ([]service, error) {
sid, secret, err := splitKey(key)
if err != nil {
return nil, err
}

// create http client
client := analyzers.NewAnalyzeClient(cfg)

// create request
req, err := http.NewRequest("GET", "https://api.twilio.com/2010-04-01/Accounts.json", nil)
if err != nil {
return nil, err
}

// add basicAuth
req.SetBasicAuth(sid, secret)

// send request
resp, err := client.Do(req)
if err != nil {
return verifyJSON, err
return nil, err
}
defer resp.Body.Close()

var result struct {
Accounts []service `json:"accounts"`
}

// read response
if err := json.NewDecoder(resp.Body).Decode(&verifyJSON); err != nil {
return verifyJSON, err
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, err
}

return verifyJSON, nil
return result.Accounts, nil
}

func AnalyzePermissions(cfg *config.Config, key string) (*SecretInfo, error) {
func AnalyzePermissions(cfg *config.Config, key string) (*secretInfo, error) {
sid, secret, err := splitKey(key)
if err != nil {
return nil, err
}

verifyJSON, err := getVerifyServicesStatusCode(cfg, sid, secret)
servicesRes, err := getVerifyServicesStatusCode(cfg, sid, secret)
if err != nil {
return nil, err
}
Expand All @@ -197,8 +257,8 @@ func AnalyzePermissions(cfg *config.Config, key string) (*SecretInfo, error) {
return nil, err
}

return &SecretInfo{
VerifyJson: verifyJSON,
return &secretInfo{
ServicesRes: servicesRes,
AccountStatusCode: statusCode,
}, nil
}
Expand All @@ -216,12 +276,12 @@ func AnalyzeAndPrintPermissions(cfg *config.Config, key string) {
return
}

if info.VerifyJson.Code == INVALID_CREDENTIALS {
if info.ServicesRes.Code == INVALID_CREDENTIALS {
color.Red("[x] Invalid Twilio API Key")
return
}

if info.VerifyJson.Code == AUTHENTICATED_NO_PERMISSION {
if info.ServicesRes.Code == AUTHENTICATED_NO_PERMISSION {
printRestrictedKeyMsg()
return
}
Expand Down
Loading

0 comments on commit 5dc1ce5

Please sign in to comment.