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