github.com/nats-io/nsc@v0.0.0-20221206222106-35db9400b257/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/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  }