github.com/mckael/restic@v0.8.3/internal/backend/b2/config.go (about)

     1  package b2
     2  
     3  import (
     4  	"path"
     5  	"regexp"
     6  	"strings"
     7  
     8  	"github.com/restic/restic/internal/errors"
     9  	"github.com/restic/restic/internal/options"
    10  )
    11  
    12  // Config contains all configuration necessary to connect to an b2 compatible
    13  // server.
    14  type Config struct {
    15  	AccountID string
    16  	Key       string
    17  	Bucket    string
    18  	Prefix    string
    19  
    20  	Connections uint `option:"connections" help:"set a limit for the number of concurrent connections (default: 5)"`
    21  }
    22  
    23  // NewConfig returns a new config with default options applied.
    24  func NewConfig() Config {
    25  	return Config{
    26  		Connections: 5,
    27  	}
    28  }
    29  
    30  func init() {
    31  	options.Register("b2", Config{})
    32  }
    33  
    34  var bucketName = regexp.MustCompile("^[a-zA-Z0-9-]+$")
    35  
    36  // checkBucketName tests the bucket name against the rules at
    37  // https://help.backblaze.com/hc/en-us/articles/217666908-What-you-need-to-know-about-B2-Bucket-names
    38  func checkBucketName(name string) error {
    39  	if name == "" {
    40  		return errors.New("bucket name is empty")
    41  	}
    42  
    43  	if len(name) < 6 {
    44  		return errors.New("bucket name is too short")
    45  	}
    46  
    47  	if len(name) > 50 {
    48  		return errors.New("bucket name is too long")
    49  	}
    50  
    51  	if !bucketName.MatchString(name) {
    52  		return errors.New("bucket name contains invalid characters, allowed are: a-z, 0-9, dash (-)")
    53  	}
    54  
    55  	return nil
    56  }
    57  
    58  // ParseConfig parses the string s and extracts the b2 config. The supported
    59  // configuration format is b2:bucketname/prefix. If no prefix is given the
    60  // prefix "restic" will be used.
    61  func ParseConfig(s string) (interface{}, error) {
    62  	if !strings.HasPrefix(s, "b2:") {
    63  		return nil, errors.New("invalid format, want: b2:bucket-name[:path]")
    64  	}
    65  
    66  	s = s[3:]
    67  	data := strings.SplitN(s, ":", 2)
    68  	if len(data) == 0 || len(data[0]) == 0 {
    69  		return nil, errors.New("bucket name not found")
    70  	}
    71  
    72  	cfg := NewConfig()
    73  	cfg.Bucket = data[0]
    74  
    75  	if err := checkBucketName(cfg.Bucket); err != nil {
    76  		return nil, err
    77  	}
    78  
    79  	if len(data) == 2 {
    80  		p := data[1]
    81  		if len(p) > 0 {
    82  			p = path.Clean(p)
    83  		}
    84  
    85  		if len(p) > 0 && path.IsAbs(p) {
    86  			p = p[1:]
    87  		}
    88  
    89  		cfg.Prefix = p
    90  	}
    91  
    92  	return cfg, nil
    93  }