Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ArvanCloud Provider #565

Open
wants to merge 3 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions PROVIDERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,24 @@ Scaleway can be integrated by using the following configuration block.
References -
1. https://www.scaleway.com/en/docs/generate-api-keys/

### ArvanCloud

ArvanCloud can be integrated by using the following configuration block.

```yaml
- # provider is the name of the provider
provider: arvancloud # or r1c
# api_key is the api_key for arvancloud
api_key: $R1C_API_KEY
```

The `api_key` can be generated from ArvanCloud Machine User manager.

References -
1. https://www.arvancloud.ir/en/dev/api
2. https://docs.arvancloud.ir/en/developer-tools/api/api-usage
3. https://panel.arvancloud.ir/profile/machine-user

### Cloudflare

Cloudflare can be integrated by using the following configuration block.
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.22.2
toolchain go1.22.3

require (
git.arvancloud.ir/arvancloud/cdn-go-sdk v0.12.1
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible
github.com/Azure/go-autorest/autorest v0.11.28
github.com/Azure/go-autorest/autorest/azure/auth v0.5.12
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdi
cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
git.arvancloud.ir/arvancloud/cdn-go-sdk v0.12.1 h1:yYxJ5KSIcL8YJrQrKlcPZqvQQc4nK8VVrVkEK8J0NwY=
git.arvancloud.ir/arvancloud/cdn-go-sdk v0.12.1/go.mod h1:ujHWzPDF3SdsJNwN2tBYZQyQJE9h0obkR7TYJRe8KO4=
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU=
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
Expand Down
5 changes: 5 additions & 0 deletions pkg/inventory/inventory.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"

"github.com/projectdiscovery/cloudlist/pkg/providers/alibaba"
"github.com/projectdiscovery/cloudlist/pkg/providers/arvancloud"
"github.com/projectdiscovery/cloudlist/pkg/providers/aws"
"github.com/projectdiscovery/cloudlist/pkg/providers/azure"
"github.com/projectdiscovery/cloudlist/pkg/providers/cloudflare"
Expand Down Expand Up @@ -48,6 +49,8 @@ func New(optionBlocks schema.Options) (*Inventory, error) {
}

var Providers = map[string][]string{
"r1c": arvancloud.Services,
"arvancloud": arvancloud.Services,
"aws": aws.Services,
"do": digitalocean.Services,
"digitalocean": digitalocean.Services,
Expand Down Expand Up @@ -85,6 +88,8 @@ func GetServices() []string {
// nameToProvider returns the provider for a name
func nameToProvider(value string, block schema.OptionBlock) (schema.Provider, error) {
switch value {
case "r1c", "arvancloud":
return arvancloud.New(block)
case "aws":
return aws.New(block)
case "do", "digitalocean":
Expand Down
86 changes: 86 additions & 0 deletions pkg/providers/arvancloud/arvancloud.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package arvancloud

import (
"context"
"strings"

r1c "git.arvancloud.ir/arvancloud/cdn-go-sdk"
"github.com/projectdiscovery/cloudlist/pkg/schema"
)

var Services = []string{"dns"}

// apiToken is a ArvanCloud user machine token
const apiToken = "api_key"
const providerName = "arvancloud"

// Provider is a data provider for ArvanCloud API
type Provider struct {
id string
client *r1c.APIClient
services schema.ServiceMap
}

// New creates a new provider client for ArvanCloud API
func New(options schema.OptionBlock) (*Provider, error) {
id, _ := options.GetMetadata("id")
apiToken, ok := options.GetMetadata(apiToken)
if !ok {
return nil, &schema.ErrNoSuchKey{Name: apiToken}
}

configuration := r1c.NewConfiguration()
configuration.AddDefaultHeader("authorization", apiToken)

// Construct a new API object
api := r1c.NewAPIClient(configuration)

supportedServicesMap := make(map[string]struct{})
for _, s := range Services {
supportedServicesMap[s] = struct{}{}
}

services := make(schema.ServiceMap)
if ss, ok := options.GetMetadata("services"); ok {
for _, s := range strings.Split(ss, ",") {
if _, ok := supportedServicesMap[s]; ok {
services[s] = struct{}{}
}
}
}
if len(services) == 0 {
for _, s := range Services {
services[s] = struct{}{}
}
}

return &Provider{id: id, client: api, services: services}, nil
}

// Name returns the name of the provider
func (p *Provider) Name() string {
return providerName
}

// ID returns the name of the provider id
func (p *Provider) ID() string {
return p.id
}

// Services returns the provider services
func (p *Provider) Services() []string {
return p.services.Keys()
}

// Resources returns the provider for an resource deployment source.
func (p *Provider) Resources(ctx context.Context) (*schema.Resources, error) {
finalResources := schema.NewResources()

if p.services.Has("dns") {
dnsProvider := &dnsProvider{id: p.id, client: p.client}
if resources, err := dnsProvider.GetResource(ctx); err == nil {
finalResources.Merge(resources)
}
}
return finalResources, nil
}
76 changes: 76 additions & 0 deletions pkg/providers/arvancloud/dns.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package arvancloud

import (
"context"
"fmt"

r1c "git.arvancloud.ir/arvancloud/cdn-go-sdk"
"github.com/pkg/errors"
"github.com/projectdiscovery/cloudlist/pkg/schema"
)

// dnsProvider is a provider for ArvanCloud DNS resources
type dnsProvider struct {
id string
client *r1c.APIClient
}

func (d *dnsProvider) name() string {
return "dns"
}

// GetResource returns all the resources in the store for a provider.
func (d *dnsProvider) GetResource(ctx context.Context) (*schema.Resources, error) {
list := schema.NewResources()

domains, _, err := d.client.DomainApi.DomainsIndex(ctx).Execute()
if err != nil {
return nil, errors.Wrap(err, "could not get domains")
}

for _, domain := range domains.GetData() {
dnsRecords, _, err := d.client.DNSManagementApi.DnsRecordsIndex(ctx, domain.GetId()).Execute()
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("could not get dns records for domain `%s`", domain.GetName()))
}

for _, r := range dnsRecords.GetData() {
// It's for A/AAAA records that can have multiple values
arrayRecord := r.DnsRecordGenericArrayValue
if arrayRecord.GetType() != "a" && arrayRecord.GetType() != "aaaa" {
continue
}

for _, record := range arrayRecord.GetValue() {
if v, ok := record.(map[string]interface{}); ok {
list.Append(&schema.Resource{
Public: true,
Provider: providerName,
DNSName: fmt.Sprintf("%s.%s", arrayRecord.GetName(), domain.GetName()),
PublicIPv4: v["ip"].(string),
ID: d.id,
Service: d.name(),
})
} else {
return nil, errors.Wrap(err, fmt.Sprintf("could not get ip for `%s` record", arrayRecord.GetName()))
}
}

// It's for normal records with one value
objectRecord := r.DnsRecordGenericObjectValue
if objectRecord.GetType() != "cname" {
continue
}

list.Append(&schema.Resource{
Public: true,
Provider: providerName,
DNSName: objectRecord.GetName(),
ID: d.id,
Service: d.name(),
})
}
}

return list, nil
}
Loading