github.com/nats-io/nsc/v2@v2.8.7-0.20240307184528-efd7023c6896/cmd/memresolverconfigbuilder.go (about) 1 /* 2 * Copyright 2018-2019 The NATS Authors 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 * http://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 16 package cmd 17 18 import ( 19 "bytes" 20 "errors" 21 "fmt" 22 "os" 23 "path/filepath" 24 "sort" 25 26 "github.com/nats-io/jwt/v2" 27 28 "github.com/nats-io/nsc/v2/cmd/store" 29 ) 30 31 type MemResolverConfigBuilder struct { 32 operator string 33 claims map[string]string 34 pubToName map[string]string 35 dir string 36 sysAccount string 37 } 38 39 func NewMemResolverConfigBuilder() *MemResolverConfigBuilder { 40 cb := MemResolverConfigBuilder{} 41 cb.claims = make(map[string]string) 42 cb.pubToName = make(map[string]string) 43 return &cb 44 } 45 46 func (cb *MemResolverConfigBuilder) SetOutputDir(fp string) error { 47 cb.dir = fp 48 return nil 49 } 50 51 func (cb *MemResolverConfigBuilder) SetSystemAccount(id string) error { 52 cb.sysAccount = id 53 return nil 54 } 55 56 func (cb *MemResolverConfigBuilder) Add(rawClaim []byte) error { 57 token := string(rawClaim) 58 gc, err := jwt.DecodeGeneric(token) 59 if err != nil { 60 return err 61 } 62 switch gc.ClaimType() { 63 case jwt.OperatorClaim: 64 oc, err := jwt.DecodeOperatorClaims(token) 65 if err != nil { 66 return err 67 } 68 cb.operator = token 69 cb.pubToName[oc.Subject] = oc.Name 70 cb.pubToName["__OPERATOR__"] = oc.Subject 71 case jwt.AccountClaim: 72 ac, err := jwt.DecodeAccountClaims(token) 73 if err != nil { 74 return err 75 } 76 cb.claims[ac.Subject] = token 77 cb.pubToName[ac.Subject] = ac.Name 78 } 79 return nil 80 } 81 82 func (cb *MemResolverConfigBuilder) GenerateConfig() ([]byte, error) { 83 var buf bytes.Buffer 84 85 opk := cb.pubToName["__OPERATOR__"] 86 if opk == "" { 87 return nil, errors.New("operator is not set") 88 } 89 buf.WriteString(fmt.Sprintf("// Operator %q\n", cb.pubToName[opk])) 90 buf.WriteString(fmt.Sprintf("operator: %s\n\n", cb.operator)) 91 92 if cb.sysAccount != "" { 93 buf.WriteString(fmt.Sprintf("system_account: %s\n\n", cb.sysAccount)) 94 } 95 96 var keys []string 97 for k := range cb.claims { 98 keys = append(keys, k) 99 } 100 sort.Strings(keys) 101 buf.WriteString("resolver: MEMORY\n\n") 102 buf.WriteString("resolver_preload: {\n") 103 for _, k := range keys { 104 v := cb.claims[k] 105 buf.WriteString(fmt.Sprintf(" // Account %q\n", cb.pubToName[k])) 106 buf.WriteString(fmt.Sprintf(" %s: %s\n\n", k, v)) 107 } 108 buf.WriteString("}\n") 109 return buf.Bytes(), nil 110 } 111 112 func (cb *MemResolverConfigBuilder) writeFile(dir string, name string, token string) (string, error) { 113 fp := filepath.Join(dir, store.JwtName(name)) 114 err := os.WriteFile(fp, []byte(token), 0666) 115 return fp, err 116 } 117 118 func (cb *MemResolverConfigBuilder) GenerateDir() ([]byte, error) { 119 var buf bytes.Buffer 120 121 if err := MaybeMakeDir(cb.dir); err != nil { 122 return nil, err 123 } 124 125 opk := cb.pubToName["__OPERATOR__"] 126 if opk == "" { 127 return nil, errors.New("operator is not set") 128 } 129 130 fn, err := cb.writeFile(cb.dir, cb.pubToName[opk], cb.operator) 131 if err != nil { 132 return nil, err 133 } 134 buf.WriteString(fmt.Sprintf("// Operator %q\n", cb.pubToName[opk])) 135 buf.WriteString(fmt.Sprintf("operator: %q\n\n", filepath.Join(".", filepath.Base(fn)))) 136 137 if cb.sysAccount != "" { 138 buf.WriteString(fmt.Sprintf("system_account: %s\n\n", cb.sysAccount)) 139 } 140 141 var keys []string 142 for k := range cb.claims { 143 keys = append(keys, k) 144 } 145 sort.Strings(keys) 146 buf.WriteString("resolver: MEMORY\n\n") 147 buf.WriteString("resolver_preload: {\n") 148 for _, k := range keys { 149 v := cb.claims[k] 150 n := cb.pubToName[k] 151 buf.WriteString(fmt.Sprintf(" // Account %q\n", n)) 152 fn, err := cb.writeFile(cb.dir, n, v) 153 if err != nil { 154 return nil, err 155 } 156 rel, err := filepath.Rel(cb.dir, fn) 157 if err != nil { 158 return nil, err 159 } 160 buf.WriteString(fmt.Sprintf(" %s: %q\n\n", k, rel)) 161 } 162 buf.WriteString("}\n") 163 164 err = os.WriteFile(filepath.Join(cb.dir, "resolver.conf"), buf.Bytes(), 0666) 165 if err != nil { 166 return nil, err 167 } 168 169 return nil, nil 170 } 171 172 func (cb *MemResolverConfigBuilder) Generate() ([]byte, error) { 173 if cb.dir != "" { 174 return cb.GenerateDir() 175 } 176 return cb.GenerateConfig() 177 }