forked from TrueCloudLab/restic
3a3cf608f5
Conceptually the backend configuration should be validated when creating or opening the backend, but not when filling in information from environment variables into the configuration.
95 lines
2.2 KiB
Go
95 lines
2.2 KiB
Go
package b2
|
|
|
|
import (
|
|
"os"
|
|
"path"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/restic/restic/internal/errors"
|
|
"github.com/restic/restic/internal/options"
|
|
"github.com/restic/restic/internal/restic"
|
|
)
|
|
|
|
// Config contains all configuration necessary to connect to an b2 compatible
|
|
// server.
|
|
type Config struct {
|
|
AccountID string
|
|
Key options.SecretString
|
|
Bucket string
|
|
Prefix string
|
|
|
|
Connections uint `option:"connections" help:"set a limit for the number of concurrent connections (default: 5)"`
|
|
}
|
|
|
|
// NewConfig returns a new config with default options applied.
|
|
func NewConfig() Config {
|
|
return Config{
|
|
Connections: 5,
|
|
}
|
|
}
|
|
|
|
func init() {
|
|
options.Register("b2", Config{})
|
|
}
|
|
|
|
var bucketName = regexp.MustCompile("^[a-zA-Z0-9-]+$")
|
|
|
|
// checkBucketName tests the bucket name against the rules at
|
|
// https://help.backblaze.com/hc/en-us/articles/217666908-What-you-need-to-know-about-B2-Bucket-names
|
|
func checkBucketName(name string) error {
|
|
if name == "" {
|
|
return errors.New("bucket name not found")
|
|
}
|
|
|
|
if len(name) < 6 {
|
|
return errors.New("bucket name is too short")
|
|
}
|
|
|
|
if len(name) > 50 {
|
|
return errors.New("bucket name is too long")
|
|
}
|
|
|
|
if !bucketName.MatchString(name) {
|
|
return errors.New("bucket name contains invalid characters, allowed are: a-z, 0-9, dash (-)")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ParseConfig parses the string s and extracts the b2 config. The supported
|
|
// configuration format is b2:bucketname/prefix. If no prefix is given the
|
|
// prefix "restic" will be used.
|
|
func ParseConfig(s string) (*Config, error) {
|
|
if !strings.HasPrefix(s, "b2:") {
|
|
return nil, errors.New("invalid format, want: b2:bucket-name[:path]")
|
|
}
|
|
|
|
s = s[3:]
|
|
bucket, prefix, _ := strings.Cut(s, ":")
|
|
if err := checkBucketName(bucket); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(prefix) > 0 {
|
|
prefix = strings.TrimPrefix(path.Clean(prefix), "/")
|
|
}
|
|
|
|
cfg := NewConfig()
|
|
cfg.Bucket = bucket
|
|
cfg.Prefix = prefix
|
|
|
|
return &cfg, nil
|
|
}
|
|
|
|
var _ restic.ApplyEnvironmenter = &Config{}
|
|
|
|
// ApplyEnvironment saves values from the environment to the config.
|
|
func (cfg *Config) ApplyEnvironment(prefix string) {
|
|
if cfg.AccountID == "" {
|
|
cfg.AccountID = os.Getenv(prefix + "B2_ACCOUNT_ID")
|
|
}
|
|
if cfg.Key.String() == "" {
|
|
cfg.Key = options.NewSecretString(os.Getenv(prefix + "B2_ACCOUNT_KEY"))
|
|
}
|
|
}
|