github.com/thiagoyeds/go-cloud@v0.26.0/secrets/secrets.go (about) 1 // Copyright 2019 The Go Cloud Development Kit Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package secrets provides an easy and portable way to encrypt and decrypt 16 // messages. Subpackages contain driver implementations of 17 // secrets for supported services. 18 // 19 // See https://gocloud.dev/howto/secrets/ for a detailed how-to guide. 20 // 21 // 22 // OpenCensus Integration 23 // 24 // OpenCensus supports tracing and metric collection for multiple languages and 25 // backend providers. See https://opencensus.io. 26 // 27 // This API collects OpenCensus traces and metrics for the following methods: 28 // - Encrypt 29 // - Decrypt 30 // All trace and metric names begin with the package import path. 31 // The traces add the method name. 32 // For example, "gocloud.dev/secrets/Encrypt". 33 // The metrics are "completed_calls", a count of completed method calls by driver, 34 // method and status (error code); and "latency", a distribution of method latency 35 // by driver and method. 36 // For example, "gocloud.dev/secrets/latency". 37 // 38 // To enable trace collection in your application, see "Configure Exporter" at 39 // https://opencensus.io/quickstart/go/tracing. 40 // To enable metric collection in your application, see "Exporting stats" at 41 // https://opencensus.io/quickstart/go/metrics. 42 package secrets // import "gocloud.dev/secrets" 43 44 import ( 45 "context" 46 "net/url" 47 "sync" 48 49 "gocloud.dev/internal/gcerr" 50 "gocloud.dev/internal/oc" 51 "gocloud.dev/internal/openurl" 52 "gocloud.dev/secrets/driver" 53 ) 54 55 // Keeper does encryption and decryption. To create a Keeper, use constructors 56 // found in driver subpackages. 57 type Keeper struct { 58 k driver.Keeper 59 tracer *oc.Tracer 60 61 // mu protects the closed variable. 62 // Read locks are kept to allow holding a read lock for long-running calls, 63 // and thereby prevent closing until a call finishes. 64 mu sync.RWMutex 65 closed bool 66 } 67 68 // NewKeeper is intended for use by drivers only. Do not use in application code. 69 var NewKeeper = newKeeper 70 71 // newKeeper creates a Keeper. 72 func newKeeper(k driver.Keeper) *Keeper { 73 return &Keeper{ 74 k: k, 75 tracer: &oc.Tracer{ 76 Package: pkgName, 77 Provider: oc.ProviderName(k), 78 LatencyMeasure: latencyMeasure, 79 }, 80 } 81 } 82 83 const pkgName = "gocloud.dev/secrets" 84 85 var ( 86 latencyMeasure = oc.LatencyMeasure(pkgName) 87 88 // OpenCensusViews are predefined views for OpenCensus metrics. 89 // The views include counts and latency distributions for API method calls. 90 // See the example at https://godoc.org/go.opencensus.io/stats/view for usage. 91 OpenCensusViews = oc.Views(pkgName, latencyMeasure) 92 ) 93 94 // Encrypt encrypts the plaintext and returns the cipher message. 95 func (k *Keeper) Encrypt(ctx context.Context, plaintext []byte) (ciphertext []byte, err error) { 96 ctx = k.tracer.Start(ctx, "Encrypt") 97 defer func() { k.tracer.End(ctx, err) }() 98 99 k.mu.RLock() 100 defer k.mu.RUnlock() 101 if k.closed { 102 return nil, errClosed 103 } 104 105 b, err := k.k.Encrypt(ctx, plaintext) 106 if err != nil { 107 return nil, wrapError(k, err) 108 } 109 return b, nil 110 } 111 112 // Decrypt decrypts the ciphertext and returns the plaintext. 113 func (k *Keeper) Decrypt(ctx context.Context, ciphertext []byte) (plaintext []byte, err error) { 114 ctx = k.tracer.Start(ctx, "Decrypt") 115 defer func() { k.tracer.End(ctx, err) }() 116 117 k.mu.RLock() 118 defer k.mu.RUnlock() 119 if k.closed { 120 return nil, errClosed 121 } 122 123 b, err := k.k.Decrypt(ctx, ciphertext) 124 if err != nil { 125 return nil, wrapError(k, err) 126 } 127 return b, nil 128 } 129 130 var errClosed = gcerr.Newf(gcerr.FailedPrecondition, nil, "secrets: Keeper has been closed") 131 132 // Close releases any resources used for the Keeper. 133 func (k *Keeper) Close() error { 134 k.mu.Lock() 135 prev := k.closed 136 k.closed = true 137 k.mu.Unlock() 138 if prev { 139 return errClosed 140 } 141 return wrapError(k, k.k.Close()) 142 } 143 144 // ErrorAs converts i to driver-specific types. See 145 // https://gocloud.dev/concepts/as/ for background information and the 146 // driver package documentation for the specific types supported for 147 // that driver. 148 // 149 // ErrorAs panics if i is nil or not a pointer. 150 // ErrorAs returns false if err == nil. 151 func (k *Keeper) ErrorAs(err error, i interface{}) bool { 152 return gcerr.ErrorAs(err, i, k.k.ErrorAs) 153 } 154 155 func wrapError(k *Keeper, err error) error { 156 if err == nil { 157 return nil 158 } 159 if gcerr.DoNotWrap(err) { 160 return err 161 } 162 return gcerr.New(k.k.ErrorCode(err), err, 2, "secrets") 163 } 164 165 // KeeperURLOpener represents types that can open Keepers based on a URL. 166 // The opener must not modify the URL argument. OpenKeeperURL must be safe to 167 // call from multiple goroutines. 168 // 169 // This interface is generally implemented by types in driver packages. 170 type KeeperURLOpener interface { 171 OpenKeeperURL(ctx context.Context, u *url.URL) (*Keeper, error) 172 } 173 174 // URLMux is a URL opener multiplexer. It matches the scheme of the URLs 175 // against a set of registered schemes and calls the opener that matches the 176 // URL's scheme. 177 // See https://gocloud.dev/concepts/urls/ for more information. 178 // 179 // The zero value is a multiplexer with no registered schemes. 180 type URLMux struct { 181 schemes openurl.SchemeMap 182 } 183 184 // KeeperSchemes returns a sorted slice of the registered Keeper schemes. 185 func (mux *URLMux) KeeperSchemes() []string { return mux.schemes.Schemes() } 186 187 // ValidKeeperScheme returns true iff scheme has been registered for Keepers. 188 func (mux *URLMux) ValidKeeperScheme(scheme string) bool { return mux.schemes.ValidScheme(scheme) } 189 190 // RegisterKeeper registers the opener with the given scheme. If an opener 191 // already exists for the scheme, RegisterKeeper panics. 192 func (mux *URLMux) RegisterKeeper(scheme string, opener KeeperURLOpener) { 193 mux.schemes.Register("secrets", "Keeper", scheme, opener) 194 } 195 196 // OpenKeeper calls OpenKeeperURL with the URL parsed from urlstr. 197 // OpenKeeper is safe to call from multiple goroutines. 198 func (mux *URLMux) OpenKeeper(ctx context.Context, urlstr string) (*Keeper, error) { 199 opener, u, err := mux.schemes.FromString("Keeper", urlstr) 200 if err != nil { 201 return nil, err 202 } 203 return opener.(KeeperURLOpener).OpenKeeperURL(ctx, u) 204 } 205 206 // OpenKeeperURL dispatches the URL to the opener that is registered with the 207 // URL's scheme. OpenKeeperURL is safe to call from multiple goroutines. 208 func (mux *URLMux) OpenKeeperURL(ctx context.Context, u *url.URL) (*Keeper, error) { 209 opener, err := mux.schemes.FromURL("Keeper", u) 210 if err != nil { 211 return nil, err 212 } 213 return opener.(KeeperURLOpener).OpenKeeperURL(ctx, u) 214 } 215 216 var defaultURLMux = new(URLMux) 217 218 // DefaultURLMux returns the URLMux used by OpenKeeper. 219 // 220 // Driver packages can use this to register their KeeperURLOpener on the mux. 221 func DefaultURLMux() *URLMux { 222 return defaultURLMux 223 } 224 225 // OpenKeeper opens the Keeper identified by the URL given. 226 // See the URLOpener documentation in driver subpackages for 227 // details on supported URL formats, and https://gocloud.dev/concepts/urls 228 // for more information. 229 func OpenKeeper(ctx context.Context, urlstr string) (*Keeper, error) { 230 return defaultURLMux.OpenKeeper(ctx, urlstr) 231 }