github.com/grailbio/base@v0.0.11/security/keycrypt/lookup.go (about) 1 // Copyright 2018 GRAIL, Inc. All rights reserved. 2 // Use of this source code is governed by the Apache-2.0 3 // license that can be found in the LICENSE file. 4 5 package keycrypt 6 7 import ( 8 "fmt" 9 "net/url" 10 "strings" 11 "sync" 12 ) 13 14 var ( 15 mu sync.Mutex 16 resolvers = map[string]Resolver{} 17 localSchemes = []string{"keychain", "localfile"} 18 ) 19 20 // Register associates a Resolver with a scheme. 21 func Register(scheme string, resolver Resolver) { 22 mu.Lock() 23 resolvers[scheme] = resolver 24 mu.Unlock() 25 } 26 27 // For testing. 28 func unregister(scheme string) { 29 mu.Lock() 30 resolvers[scheme] = nil 31 mu.Unlock() 32 } 33 34 // RegisterFunc associates a Resolver (given by a func) 35 // with a scheme. 36 func RegisterFunc(scheme string, f func(string) Keycrypt) { 37 Register(scheme, ResolverFunc(f)) 38 } 39 40 // Lookup retrieves a secret based on a URL, in the standard form: 41 // scheme://host/path. The URL is interpreted according to the 42 // Resolver registered with the given scheme. The scheme "local" 43 // is a special scheme that attempts known local storage schemes: 44 // first "keychain", and then "file". 45 func Lookup(rawurl string) (Secret, error) { 46 u, err := url.Parse(rawurl) 47 if err != nil { 48 return nil, err 49 } 50 mu.Lock() 51 defer mu.Unlock() 52 var r Resolver 53 if u.Scheme == "local" { 54 for _, s := range localSchemes { 55 r = resolvers[s] 56 if r != nil { 57 break 58 } 59 } 60 if r == nil { 61 return nil, fmt.Errorf("no local resolvers found, tried: %s", strings.Join(localSchemes, ", ")) 62 } 63 } else { 64 r = resolvers[u.Scheme] 65 } 66 if r == nil { 67 return nil, fmt.Errorf("unknown scheme \"%s\"", u.Scheme) 68 } 69 name := u.Path 70 if name != "" && name[0] == '/' { 71 name = name[1:] 72 } 73 return r.Resolve(u.Host).Lookup(name), nil 74 } 75 76 // Get data from a keycrypt URL. 77 func Get(rawurl string) ([]byte, error) { 78 s, err := Lookup(rawurl) 79 if err != nil { 80 return nil, err 81 } 82 return s.Get() 83 } 84 85 // Put writes data to a keycrypt URL. 86 func Put(rawurl string, data []byte) error { 87 s, err := Lookup(rawurl) 88 if err != nil { 89 return err 90 } 91 return s.Put(data) 92 }