// Copyright 2018, the Blazer authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package b2 import ( "context" "errors" "io" "time" ) // Key is a B2 application key. A Key grants limited access on a global or // per-bucket basis. type Key struct { c *Client k beKeyInterface } // Capabilities returns the list of capabilites granted by this application // key. func (k *Key) Capabilities() []string { return k.k.caps() } // Name returns the user-supplied name of this application key. Key names are // useless. func (k *Key) Name() string { return k.k.name() } // Expires returns the expiration date of this application key. func (k *Key) Expires() time.Time { return k.k.expires() } // Delete removes the key from B2. func (k *Key) Delete(ctx context.Context) error { return k.k.del(ctx) } // Secret returns the value that should be passed into NewClient(). It is only // available on newly created keys; it is not available from ListKey // operations. func (k *Key) Secret() string { return k.k.secret() } // ID returns the application key ID. This, plus the secret, is necessary to // authenticate to B2. func (k *Key) ID() string { return k.k.id() } type keyOptions struct { caps []string prefix string lifetime time.Duration } // KeyOption specifies desired properties for application keys. type KeyOption func(*keyOptions) // Lifetime requests a key with the given lifetime. func Lifetime(d time.Duration) KeyOption { return func(k *keyOptions) { k.lifetime = d } } // Deadline requests a key that expires after the given date. func Deadline(t time.Time) KeyOption { d := t.Sub(time.Now()) return Lifetime(d) } // Capabilities requests a key with the given capability. func Capabilities(caps ...string) KeyOption { return func(k *keyOptions) { k.caps = append(k.caps, caps...) } } // Prefix limits the requested application key to be valid only for objects // that begin with prefix. This can only be used when requesting an // application key within a specific bucket. func Prefix(prefix string) KeyOption { return func(k *keyOptions) { k.prefix = prefix } } // CreateKey creates a global application key that is valid for all buckets in // this project. The key's secret will only be accessible on the object // returned from this call. func (c *Client) CreateKey(ctx context.Context, name string, opts ...KeyOption) (*Key, error) { var ko keyOptions for _, o := range opts { o(&ko) } if ko.prefix != "" { return nil, errors.New("Prefix is not a valid option for global application keys") } ki, err := c.backend.createKey(ctx, name, ko.caps, ko.lifetime, "", "") if err != nil { return nil, err } return &Key{ c: c, k: ki, }, nil } // ListKeys lists all the keys associated with this project. It takes the // maximum number of keys it should return in a call, as well as a cursor // (which should be empty for the initial call). It will return up to count // keys, as well as the cursor for the next invocation. // // ListKeys returns io.EOF when there are no more keys, although it may do so // concurrently with the final set of keys. func (c *Client) ListKeys(ctx context.Context, count int, cursor string) ([]*Key, string, error) { ks, next, err := c.backend.listKeys(ctx, count, cursor) if err != nil { return nil, "", err } if len(ks) == 0 { return nil, "", io.EOF } var keys []*Key for _, k := range ks { keys = append(keys, &Key{ c: c, k: k, }) } var rerr error if next == "" { rerr = io.EOF } return keys, next, rerr } // CreateKey creates a scoped application key that is valid only for this bucket. func (b *Bucket) CreateKey(ctx context.Context, name string, opts ...KeyOption) (*Key, error) { var ko keyOptions for _, o := range opts { o(&ko) } ki, err := b.r.createKey(ctx, name, ko.caps, ko.lifetime, b.b.id(), ko.prefix) if err != nil { return nil, err } return &Key{ c: b.c, k: ki, }, nil }