github.com/kbehouse/nsc@v0.0.6/cmd/util_test.go (about)

     1  /*
     2   * Copyright 2018-2021 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  	"encoding/json"
    20  	"fmt"
    21  	"io/ioutil"
    22  	"net/http"
    23  	"net/http/httptest"
    24  	"net/url"
    25  	"os"
    26  	"path/filepath"
    27  	"regexp"
    28  	"strings"
    29  	"testing"
    30  	"time"
    31  
    32  	"github.com/kbehouse/nsc/cmd/store"
    33  	cli "github.com/nats-io/cliprompts/v2"
    34  	jwt1 "github.com/nats-io/jwt"
    35  	"github.com/nats-io/jwt/v2"
    36  	"github.com/nats-io/nats-server/v2/server"
    37  	nats "github.com/nats-io/nats.go"
    38  	"github.com/nats-io/nkeys"
    39  	"github.com/stretchr/testify/require"
    40  )
    41  
    42  type TestStore struct {
    43  	Dir string
    44  
    45  	Store    *store.Store
    46  	KeyStore store.KeyStore
    47  
    48  	OperatorKey     nkeys.KeyPair
    49  	OperatorKeyPath string
    50  
    51  	Server  *server.Server
    52  	ports   *server.Ports
    53  	Clients []*nats.Conn
    54  }
    55  
    56  // Some globals must be reset
    57  func ResetForTests() {
    58  	config = ToolConfig{}
    59  	ResetSharedFlags()
    60  	wellKnownOperators = nil
    61  }
    62  
    63  func ResetSharedFlags() {
    64  	KeyPathFlag = ""
    65  	Json = false
    66  	Raw = false
    67  	JsonPath = ""
    68  }
    69  
    70  func NewEmptyStore(t *testing.T) *TestStore {
    71  	ResetForTests()
    72  	// init runs early
    73  	SetEnvOptions()
    74  	var ts TestStore
    75  
    76  	homeEnv = t.Name()
    77  
    78  	ts.Dir = MakeTempDir(t)
    79  	require.NoError(t, os.Setenv(t.Name(), filepath.Join(ts.Dir, "toolprefs")))
    80  	_, err := initToolHome(t.Name())
    81  	require.NoError(t, err)
    82  
    83  	// debug the test that created the store
    84  	_ = ioutil.WriteFile(filepath.Join(ts.Dir, "test.txt"), []byte(t.Name()), 0700)
    85  
    86  	err = ForceStoreRoot(t, ts.GetStoresRoot())
    87  	require.NoError(t, err)
    88  
    89  	nkeysDir := filepath.Join(ts.Dir, "keys")
    90  	err = os.Mkdir(nkeysDir, 0700)
    91  	require.NoError(t, err, "error creating %#q", nkeysDir)
    92  	require.NoError(t, err)
    93  	err = os.Setenv(store.NKeysPathEnv, nkeysDir)
    94  	require.NoError(t, err)
    95  
    96  	return &ts
    97  }
    98  
    99  func NewTestStoreWithOperator(t *testing.T, operatorName string, operator nkeys.KeyPair) *TestStore {
   100  	ResetForTests()
   101  	// init runs early
   102  	SetEnvOptions()
   103  	var ts TestStore
   104  
   105  	// ngsStore is a global - so first test to get it initializes it
   106  	homeEnv = t.Name()
   107  
   108  	ts.OperatorKey = operator
   109  	ts.Dir = MakeTempDir(t)
   110  	require.NoError(t, os.Setenv(t.Name(), filepath.Join(ts.Dir, "toolprefs")))
   111  	_, err := initToolHome(t.Name())
   112  	require.NoError(t, err)
   113  	// debug the test that created the store
   114  	_ = ioutil.WriteFile(filepath.Join(ts.Dir, "test.txt"), []byte(t.Name()), 0700)
   115  
   116  	err = ForceStoreRoot(t, ts.GetStoresRoot())
   117  	require.NoError(t, err)
   118  
   119  	ForceOperator(t, operatorName)
   120  	ts.AddOperatorWithKey(t, operatorName, operator)
   121  
   122  	return &ts
   123  }
   124  
   125  func NewTestStoreWithOperatorJWT(t *testing.T, operator string) *TestStore {
   126  	oc, err := jwt.DecodeOperatorClaims(operator)
   127  	require.NoError(t, err)
   128  	ts := NewTestStoreWithOperator(t, oc.Name, nil)
   129  	ts.Store.StoreClaim([]byte(operator))
   130  	return ts
   131  }
   132  
   133  func (ts *TestStore) Reload(t *testing.T) {
   134  	s, err := store.LoadStore(ts.Store.Dir)
   135  	require.NoError(t, err)
   136  	if ts.Store == nil {
   137  		ts.Store = s
   138  	}
   139  	ctx, err := ts.Store.GetContext()
   140  	require.NoError(t, err, "getting context")
   141  
   142  	ts.KeyStore = ctx.KeyStore
   143  
   144  	GetConfig().SetDefaults()
   145  }
   146  
   147  func (ts *TestStore) AddOperator(t *testing.T, operatorName string) *store.Store {
   148  	_, _, kp := CreateOperatorKey(t)
   149  	return ts.AddOperatorWithKey(t, operatorName, kp)
   150  }
   151  
   152  func (ts *TestStore) AddOperatorWithKey(t *testing.T, operatorName string, operator nkeys.KeyPair) *store.Store {
   153  	storeRoot := ts.GetStoresRoot()
   154  	operatorRoot := filepath.Join(storeRoot, operatorName)
   155  	err := os.MkdirAll(operatorRoot, 0700)
   156  	require.NoError(t, err, "error creating %#q", operatorRoot)
   157  
   158  	nkeysDir := filepath.Join(ts.Dir, "keys")
   159  	_, err = os.Stat(nkeysDir)
   160  	if err != nil && os.IsNotExist(err) {
   161  		err = os.Mkdir(nkeysDir, 0700)
   162  		require.NoError(t, err, "error creating %#q", nkeysDir)
   163  	}
   164  	require.NoError(t, err)
   165  
   166  	err = os.Setenv(store.NKeysPathEnv, nkeysDir)
   167  	require.NoError(t, err, "nkeys env")
   168  
   169  	var nk = &store.NamedKey{}
   170  	nk.Name = operatorName
   171  	nk.KP = operator
   172  
   173  	s, err := store.CreateStore(operatorName, storeRoot, nk)
   174  	require.NoError(t, err)
   175  	ts.Store = s
   176  
   177  	ctx, err := ts.Store.GetContext()
   178  	require.NoError(t, err, "getting context")
   179  
   180  	ts.KeyStore = ctx.KeyStore
   181  	ts.OperatorKey = operator
   182  	ts.OperatorKeyPath = ""
   183  	if operator != nil {
   184  		ts.OperatorKeyPath, err = ts.KeyStore.Store(operator)
   185  		require.NoError(t, err, "store operator key")
   186  	}
   187  
   188  	ForceOperator(t, operatorName)
   189  
   190  	return s
   191  }
   192  
   193  func (ts *TestStore) SwitchOperator(t *testing.T, operator string) {
   194  	storeRoot := ts.GetStoresRoot()
   195  	s, err := store.LoadStore(filepath.Join(storeRoot, operator))
   196  	require.NoError(t, err)
   197  	ts.Store = s
   198  
   199  	ctx, err := ts.Store.GetContext()
   200  	require.NoError(t, err, "getting context")
   201  	ts.KeyStore = ctx.KeyStore
   202  
   203  	oc, err := s.LoadRootClaim()
   204  	require.NoError(t, err)
   205  
   206  	kp, err := ts.KeyStore.GetKeyPair(oc.Subject)
   207  	require.NoError(t, err)
   208  
   209  	ts.OperatorKey = kp
   210  	ts.OperatorKeyPath = ""
   211  	if kp != nil {
   212  		ts.OperatorKeyPath = ts.KeyStore.GetKeyPath(oc.Subject)
   213  	}
   214  
   215  	ForceOperator(t, operator)
   216  }
   217  
   218  func NewTestStore(t *testing.T, operatorName string) *TestStore {
   219  	_, _, kp := CreateOperatorKey(t)
   220  	return NewTestStoreWithOperator(t, operatorName, kp)
   221  }
   222  
   223  func TestStoreTree(t *testing.T) {
   224  	ts := NewTestStore(t, "foo")
   225  	ts.AddAccount(t, "bar")
   226  	ts.AddAccount(t, "foo")
   227  
   228  	v, err := store.LoadStore(filepath.Join(config.StoreRoot, config.Operator))
   229  	require.NoError(t, err)
   230  	require.NotNil(t, v)
   231  }
   232  
   233  func (ts *TestStore) Done(t *testing.T) {
   234  	for _, nc := range ts.Clients {
   235  		nc.Close()
   236  	}
   237  	if ts.Server != nil {
   238  		ts.Server.Shutdown()
   239  		ts.ports = nil
   240  	}
   241  	cli.ResetPromptLib()
   242  	if t.Failed() {
   243  		t.Log("test artifacts:", ts.Dir)
   244  	}
   245  }
   246  
   247  func (ts *TestStore) GetStoresRoot() string {
   248  	return filepath.Join(ts.Dir, "store")
   249  }
   250  
   251  func (ts *TestStore) AddAccount(t *testing.T, accountName string) {
   252  	if !ts.Store.Has(store.Accounts, accountName, store.JwtName(accountName)) {
   253  		_, _, err := ExecuteCmd(CreateAddAccountCmd(), "--name", accountName)
   254  		require.NoError(t, err)
   255  	}
   256  }
   257  
   258  func (ts *TestStore) AddAccountWithSigner(t *testing.T, accountName string, sk nkeys.KeyPair) {
   259  	if !ts.Store.Has(store.Accounts, accountName, store.JwtName(accountName)) {
   260  		seed, err := sk.Seed()
   261  		require.NoError(t, err)
   262  		_, _, err = ExecuteCmd(HoistRootFlags(CreateAddAccountCmd()), "--name", accountName, "-K", string(seed))
   263  		require.NoError(t, err)
   264  	}
   265  }
   266  
   267  func (ts *TestStore) AddUser(t *testing.T, accountName string, userName string) {
   268  	ts.AddAccount(t, accountName)
   269  	_, _, err := ExecuteCmd(CreateAddUserCmd(), "--account", accountName, "--name", userName)
   270  	require.NoError(t, err)
   271  }
   272  
   273  func (ts *TestStore) AddUserWithSigner(t *testing.T, accountName string, userName string, sk nkeys.KeyPair) {
   274  	ts.AddAccount(t, accountName)
   275  	seed, err := sk.Seed()
   276  	require.NoError(t, err)
   277  	_, _, err = ExecuteCmd(HoistRootFlags(CreateAddUserCmd()), "--account", accountName, "--name", userName, "-K", string(seed))
   278  	require.NoError(t, err)
   279  }
   280  
   281  func (ts *TestStore) AddExport(t *testing.T, accountName string, kind jwt.ExportType, subject string, public bool) {
   282  	flags := []string{"--account", accountName, "--subject", subject}
   283  	if !public {
   284  		flags = append(flags, "--private")
   285  	}
   286  	if kind == jwt.Service {
   287  		flags = append(flags, "--service")
   288  	}
   289  
   290  	ts.AddAccount(t, accountName)
   291  	_, _, err := ExecuteCmd(createAddExportCmd(), flags...)
   292  	require.NoError(t, err)
   293  }
   294  
   295  func (ts *TestStore) ImportRequiresToken(t *testing.T, srcAccount string, subject string) bool {
   296  	ac, err := ts.Store.ReadAccountClaim(srcAccount)
   297  	require.NoError(t, err)
   298  	for _, ex := range ac.Exports {
   299  		if string(ex.Subject) == subject {
   300  			return ex.TokenReq
   301  		}
   302  	}
   303  	return false
   304  }
   305  
   306  func (ts *TestStore) AddImport(t *testing.T, srcAccount string, subject string, targetAccountName string) {
   307  	flags := []string{"--account", targetAccountName}
   308  
   309  	if ts.ImportRequiresToken(t, srcAccount, subject) {
   310  		token := ts.GenerateActivation(t, srcAccount, subject, targetAccountName)
   311  		f, err := ioutil.TempFile(ts.Dir, "token")
   312  		require.NoError(t, err)
   313  		_, err = f.WriteString(token)
   314  		require.NoError(t, err)
   315  		require.NoError(t, f.Close())
   316  		flags = append(flags, "--token", f.Name())
   317  	} else {
   318  		flags = append(flags, "--src-account", srcAccount, "--remote-subject", subject)
   319  	}
   320  	_, _, err := ExecuteCmd(createAddImportCmd(), flags...)
   321  	require.NoError(t, err)
   322  }
   323  
   324  func (ts *TestStore) GenerateActivation(t *testing.T, srcAccount string, subject string, targetAccount string) string {
   325  	tpub := ts.GetAccountPublicKey(t, targetAccount)
   326  	ac, err := ts.Store.ReadAccountClaim(srcAccount)
   327  	require.NoError(t, err)
   328  	for _, i := range ac.Exports {
   329  		if subject == string(i.Subject) {
   330  			break
   331  		}
   332  	}
   333  
   334  	flags := []string{"--account", srcAccount, "--target-account", tpub, "--subject", subject}
   335  	stdout, _, err := ExecuteCmd(createGenerateActivationCmd(), flags...)
   336  	require.NoError(t, err)
   337  	token, err := jwt.ParseDecoratedJWT([]byte(stdout))
   338  	require.NoError(t, err)
   339  	return token
   340  }
   341  
   342  func (ts *TestStore) GenerateActivationWithSigner(t *testing.T, srcAccount string, subject string, targetAccount string, sk nkeys.KeyPair) string {
   343  	tpub := ts.GetAccountPublicKey(t, targetAccount)
   344  	seed, err := sk.Seed()
   345  	require.NoError(t, err)
   346  
   347  	flags := []string{"--account", srcAccount, "--target-account", tpub, "--subject", subject, "-K", string(seed)}
   348  	stdout, _, err := ExecuteCmd(HoistRootFlags(createGenerateActivationCmd()), flags...)
   349  	require.NoError(t, err)
   350  	token, err := jwt.ParseDecoratedJWT([]byte(stdout))
   351  	require.NoError(t, err)
   352  	return token
   353  }
   354  
   355  func MakeTempDir(t *testing.T) string {
   356  	p, err := ioutil.TempDir("", "store_test")
   357  	require.NoError(t, err)
   358  	return p
   359  }
   360  
   361  func StoreKey(t *testing.T, kp nkeys.KeyPair, dir string) string {
   362  	p, err := kp.PublicKey()
   363  	require.NoError(t, err)
   364  
   365  	s, err := kp.Seed()
   366  	require.NoError(t, err)
   367  
   368  	fp := filepath.Join(dir, string(p)+".nk")
   369  	err = ioutil.WriteFile(fp, s, 0600)
   370  	require.NoError(t, err)
   371  	return fp
   372  }
   373  
   374  func CreateAccountKey(t *testing.T) (seed []byte, pub string, kp nkeys.KeyPair) {
   375  	return CreateNkey(t, nkeys.PrefixByteAccount)
   376  }
   377  
   378  func CreateUserKey(t *testing.T) (seed []byte, pub string, kp nkeys.KeyPair) {
   379  	return CreateNkey(t, nkeys.PrefixByteUser)
   380  }
   381  
   382  func CreateOperatorKey(t *testing.T) (seed []byte, pub string, kp nkeys.KeyPair) {
   383  	return CreateNkey(t, nkeys.PrefixByteOperator)
   384  }
   385  
   386  func CreateNkey(t *testing.T, kind nkeys.PrefixByte) ([]byte, string, nkeys.KeyPair) {
   387  	kp, err := nkeys.CreatePair(kind)
   388  	require.NoError(t, err)
   389  
   390  	seed, err := kp.Seed()
   391  	require.NoError(t, err)
   392  
   393  	pub, err := kp.PublicKey()
   394  	require.NoError(t, err)
   395  	return seed, pub, kp
   396  }
   397  
   398  func ForceStoreRoot(t *testing.T, fp string) error {
   399  	config.StoreRoot = fp
   400  	return nil
   401  }
   402  
   403  func ForceOperator(t *testing.T, operator string) {
   404  	config.Operator = operator
   405  }
   406  
   407  func StripTableDecorations(s string) string {
   408  	decorations := []string{"╭", "─", "┬", "╮", "├", "│", "┤", "┼", "╰", "┴", "╯", "-", "+", "|"}
   409  	for _, c := range decorations {
   410  		s = strings.Replace(s, c, "", -1)
   411  	}
   412  	// replace multiple spaces with just one
   413  	re := regexp.MustCompile(`\s+`)
   414  	return re.ReplaceAllString(s, " ")
   415  }
   416  
   417  func (ts *TestStore) GetAccountKey(t *testing.T, name string) nkeys.KeyPair {
   418  	ac, err := ts.Store.ReadAccountClaim(name)
   419  	require.NoError(t, err)
   420  	kp, err := ts.KeyStore.GetKeyPair(ac.Subject)
   421  	require.NoError(t, err)
   422  	return kp
   423  }
   424  
   425  func (ts *TestStore) GetUserKey(t *testing.T, account string, name string) nkeys.KeyPair {
   426  	uc, err := ts.Store.ReadUserClaim(account, name)
   427  	require.NoError(t, err)
   428  	kp, err := ts.KeyStore.GetKeyPair(uc.Subject)
   429  	require.NoError(t, err)
   430  	return kp
   431  }
   432  
   433  func (ts *TestStore) GetAccountKeyPath(t *testing.T, name string) string {
   434  	sc, err := ts.Store.ReadAccountClaim(name)
   435  	require.NoError(t, err)
   436  	return ts.KeyStore.GetKeyPath(sc.Subject)
   437  }
   438  
   439  func (ts *TestStore) GetOperatorPublicKey(t *testing.T) string {
   440  	oc, err := ts.Store.ReadOperatorClaim()
   441  	require.NoError(t, err)
   442  	pk, err := ts.KeyStore.GetPublicKey(oc.Subject)
   443  	require.NoError(t, err)
   444  	return pk
   445  }
   446  
   447  func (ts *TestStore) GetAccountPublicKey(t *testing.T, name string) string {
   448  	sc, err := ts.Store.ReadAccountClaim(name)
   449  	require.NoError(t, err)
   450  	pk, err := ts.KeyStore.GetPublicKey(sc.Subject)
   451  	require.NoError(t, err)
   452  	return pk
   453  }
   454  
   455  func (ts *TestStore) GetUserPublicKey(t *testing.T, account string, name string) string {
   456  	sc, err := ts.Store.ReadUserClaim(account, name)
   457  	require.NoError(t, err)
   458  	pk, err := ts.KeyStore.GetPublicKey(sc.Subject)
   459  	require.NoError(t, err)
   460  	return pk
   461  }
   462  
   463  func (ts *TestStore) GetUserSeedKey(t *testing.T, account string, name string) string {
   464  	sc, err := ts.Store.ReadUserClaim(account, name)
   465  	require.NoError(t, err)
   466  	pk, err := ts.KeyStore.GetSeed(sc.Subject)
   467  	require.NoError(t, err)
   468  	return pk
   469  }
   470  
   471  // Runs a server from a config file, if `Port` is not set it runs at a random port
   472  func (ts *TestStore) RunServerWithConfig(t *testing.T, config string) *server.Ports {
   473  	var opts server.Options
   474  	require.NoError(t, opts.ProcessConfigFile(config))
   475  	return ts.RunServer(t, &opts)
   476  }
   477  
   478  // Runs a NATS server at a random port
   479  func (ts *TestStore) RunServer(t *testing.T, opts *server.Options) *server.Ports {
   480  	if opts == nil {
   481  		opts = &server.Options{
   482  			Host:           "127.0.0.1",
   483  			Port:           -1,
   484  			HTTPPort:       -1,
   485  			NoLog:          true,
   486  			NoSigs:         true,
   487  			MaxControlLine: 2048,
   488  		}
   489  	}
   490  	if opts.Port == 0 {
   491  		opts.Port = -1
   492  	}
   493  	if opts.HTTPPort == 0 {
   494  		opts.HTTPPort = -1
   495  	}
   496  	opts.NoLog = true
   497  
   498  	var err error
   499  	ts.Server, err = server.NewServer(opts)
   500  	require.NoError(t, err)
   501  	require.NotNil(t, ts.Server)
   502  
   503  	if !opts.NoLog {
   504  		ts.Server.ConfigureLogger()
   505  	}
   506  
   507  	// Run server in Go routine.
   508  	go ts.Server.Start()
   509  
   510  	ts.ports = ts.Server.PortsInfo(10 * time.Second)
   511  	require.NotNil(t, ts.ports)
   512  
   513  	return ts.ports
   514  }
   515  
   516  func (ts *TestStore) GetConnz(t *testing.T) *server.Connz {
   517  	if ts.ports == nil {
   518  		t.Fatal("not connected")
   519  	}
   520  	r, err := http.Get(fmt.Sprintf("%s/connz", ts.ports.Monitoring[0]))
   521  	require.NoError(t, err)
   522  
   523  	defer r.Body.Close()
   524  	body, err := ioutil.ReadAll(r.Body)
   525  	require.NoError(t, err)
   526  
   527  	var connz server.Connz
   528  	require.NoError(t, json.Unmarshal(body, &connz))
   529  
   530  	return &connz
   531  }
   532  
   533  func (ts *TestStore) CreateClient(t *testing.T, option ...nats.Option) *nats.Conn {
   534  	if ts.ports == nil {
   535  		t.Fatal("attempt to create a nats connection without a server running")
   536  	}
   537  	nc, err := nats.Connect(strings.Join(ts.ports.Nats, ","), option...)
   538  	require.NoError(t, err)
   539  	ts.Clients = append(ts.Clients, nc)
   540  	return nc
   541  }
   542  
   543  func (ts *TestStore) WaitForClient(t *testing.T, name string, subs uint32, maxWait time.Duration) {
   544  	max := time.Now().Add(maxWait)
   545  	end := max.Unix()
   546  	for {
   547  		connz := ts.GetConnz(t)
   548  		if connz.NumConns > 0 {
   549  			for _, v := range connz.Conns {
   550  				if v.Name == name && v.NumSubs >= subs {
   551  					return
   552  				}
   553  			}
   554  		}
   555  		time.Sleep(500 * time.Millisecond)
   556  		if time.Now().Unix() >= end {
   557  			t.Fatalf("timed out looking for client %q with %d subs", name, subs)
   558  		}
   559  	}
   560  }
   561  
   562  func (ts *TestStore) VerifyOperator(t *testing.T, name string, managed bool) {
   563  	s, err := store.LoadStore(filepath.Join(ts.GetStoresRoot(), name))
   564  	require.NoError(t, err)
   565  	require.NotNil(t, s)
   566  
   567  	oc, err := s.ReadOperatorClaim()
   568  	require.NoError(t, err)
   569  	require.NotNil(t, oc)
   570  	require.Equal(t, name, oc.Name)
   571  	require.Equal(t, managed, s.IsManaged())
   572  
   573  	kp, err := ts.KeyStore.GetKeyPair(oc.Subject)
   574  	require.NoError(t, err)
   575  	if managed {
   576  		require.Nil(t, kp)
   577  	} else {
   578  		require.NotNil(t, kp)
   579  	}
   580  }
   581  
   582  func (ts *TestStore) VerifyAccount(t *testing.T, operator string, account string, verifyKeys bool) {
   583  	s, err := store.LoadStore(filepath.Join(ts.GetStoresRoot(), operator))
   584  	require.NoError(t, err)
   585  	require.NotNil(t, s)
   586  
   587  	ac, err := s.ReadAccountClaim(account)
   588  	require.NoError(t, err)
   589  	require.NotNil(t, ac)
   590  	require.Equal(t, account, ac.Name)
   591  
   592  	if verifyKeys {
   593  		old := ts.KeyStore.Env
   594  		defer func() {
   595  			ts.KeyStore.Env = old
   596  		}()
   597  		ts.KeyStore.Env = operator
   598  
   599  		kp, err := ts.KeyStore.GetKeyPair(ac.Subject)
   600  		require.NoError(t, err)
   601  		require.NotNil(t, kp)
   602  	}
   603  }
   604  
   605  func (ts *TestStore) VerifyUser(t *testing.T, operator string, account string, user string, verifyKeys bool) {
   606  	s, err := store.LoadStore(filepath.Join(ts.GetStoresRoot(), operator))
   607  	require.NoError(t, err)
   608  	require.NotNil(t, s)
   609  
   610  	uc, err := s.ReadUserClaim(account, user)
   611  	require.NoError(t, err)
   612  	require.NotNil(t, uc)
   613  	require.Equal(t, user, uc.Name)
   614  
   615  	if verifyKeys {
   616  		old := ts.KeyStore.Env
   617  		defer func() {
   618  			ts.KeyStore.Env = old
   619  		}()
   620  		ts.KeyStore.Env = operator
   621  
   622  		kp, err := ts.KeyStore.GetKeyPair(uc.Subject)
   623  		require.NoError(t, err)
   624  		require.NotNil(t, kp)
   625  		sk, err := kp.Seed()
   626  		require.NoError(t, err)
   627  
   628  		fp := ts.KeyStore.CalcUserCredsPath(account, user)
   629  		_, err = os.Stat(fp)
   630  		require.NoError(t, err)
   631  
   632  		creds, err := Read(fp)
   633  		require.NoError(t, err)
   634  		require.Contains(t, string(creds), string(sk))
   635  	}
   636  }
   637  
   638  func (ts *TestStore) DoesNotExist(t *testing.T, fp string) {
   639  	_, err := os.Stat(fp)
   640  	require.True(t, os.IsNotExist(err), fmt.Sprintf("should not exist %s", fp))
   641  }
   642  
   643  func Test_Util(t *testing.T) {
   644  	ts := NewTestStore(t, "O")
   645  	defer ts.Done(t)
   646  
   647  	oc, err := ts.Store.ReadOperatorClaim()
   648  	require.NoError(t, err)
   649  	pk, _ := ts.OperatorKey.PublicKey()
   650  	require.Equal(t, pk, oc.Subject)
   651  
   652  	ts.AddAccount(t, "A")
   653  	ac, err := ts.Store.ReadAccountClaim("A")
   654  	require.NoError(t, err)
   655  	require.Equal(t, oc.Subject, ac.Issuer)
   656  
   657  	_, pk, kp := CreateOperatorKey(t)
   658  	ts.AddOperatorWithKey(t, "OO", kp)
   659  	oc2, err := ts.Store.ReadOperatorClaim()
   660  	require.NoError(t, err)
   661  	require.Equal(t, pk, oc2.Subject)
   662  
   663  	ts.AddAccount(t, "AA")
   664  	ac2, err := ts.Store.ReadAccountClaim("AA")
   665  	require.NoError(t, err)
   666  	require.Equal(t, pk, ac2.Issuer)
   667  }
   668  
   669  type TasOpts struct {
   670  	Vers             int
   671  	OperatorOnlyIfV2 bool
   672  }
   673  
   674  func RunTestAccountServerWithOperatorKP(t *testing.T, okp nkeys.KeyPair, opts TasOpts) (*httptest.Server, map[string][]byte) {
   675  	storage := make(map[string][]byte)
   676  	opk, err := okp.PublicKey()
   677  	require.NoError(t, err)
   678  
   679  	tas := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   680  		errHandler := func(w http.ResponseWriter, err error) {
   681  			w.WriteHeader(http.StatusInternalServerError)
   682  			w.Write([]byte(err.Error()))
   683  		}
   684  		getHandler := func(w http.ResponseWriter, r *http.Request) {
   685  			var data []byte
   686  			id := filepath.Base(r.RequestURI)
   687  			data = storage[id]
   688  
   689  			// if we don't have v2, and they ask for v2, ignore it
   690  			if r.RequestURI == "/jwt/v2/operator" && !opts.OperatorOnlyIfV2 {
   691  				data = nil
   692  			}
   693  			if r.RequestURI == "/jwt/v1/operator" && opts.OperatorOnlyIfV2 {
   694  				// option to only answer to v2 - they asked v1
   695  				data = nil
   696  			}
   697  
   698  			if data == nil {
   699  				w.WriteHeader(http.StatusNotFound)
   700  			}
   701  			w.Header().Add("Content-Type", "application/jwt")
   702  			w.Write(data)
   703  			if data == nil {
   704  				t.Log(r.RequestURI, "not found")
   705  			} else {
   706  				t.Log(r.RequestURI, "OK")
   707  			}
   708  		}
   709  
   710  		updateAccountHandler := func(w http.ResponseWriter, r *http.Request) {
   711  			defer r.Body.Close()
   712  			body, err := ioutil.ReadAll(r.Body)
   713  			if err != nil {
   714  				errHandler(w, err)
   715  				return
   716  			}
   717  
   718  			ac, err := jwt.DecodeAccountClaims(string(body))
   719  			if err != nil {
   720  				errHandler(w, err)
   721  				return
   722  			}
   723  
   724  			ok := false
   725  			if ac.Claims().IsSelfSigned() || ac.Issuer == opk {
   726  				ok = true
   727  			} else {
   728  				ok = ac.SigningKeys.Contains(ac.Issuer)
   729  			}
   730  
   731  			// store a copy of the source jwt that we can inspect
   732  			orig := fmt.Sprintf("SRC_%s", ac.Subject)
   733  			storage[orig] = body
   734  
   735  			if ok {
   736  				ac.Limits.Conn = -1
   737  				ac.Limits.Data = -1
   738  				ac.Limits.Exports = -1
   739  				ac.Limits.Imports = -1
   740  				ac.Limits.LeafNodeConn = -1
   741  				ac.Limits.Payload = -1
   742  				ac.Limits.Subs = -1
   743  				ac.Limits.WildcardExports = true
   744  
   745  				token, err := ac.Encode(okp)
   746  				if err != nil {
   747  					errHandler(w, err)
   748  					return
   749  				}
   750  				storage[ac.Subject] = []byte(token)
   751  
   752  				w.WriteHeader(http.StatusOK)
   753  			} else {
   754  				errHandler(w, fmt.Errorf("account %q not self-signed nor by a signer - issuer %q", ac.Subject, ac.Issuer))
   755  			}
   756  		}
   757  
   758  		updateActivationHandler := func(w http.ResponseWriter, r *http.Request) {
   759  			defer r.Body.Close()
   760  			body, err := ioutil.ReadAll(r.Body)
   761  			if err != nil {
   762  				errHandler(w, err)
   763  				return
   764  			}
   765  
   766  			ac, err := jwt.DecodeActivationClaims(string(body))
   767  			if err != nil {
   768  				errHandler(w, err)
   769  				return
   770  			}
   771  			hid, err := ac.HashID()
   772  			if err != nil {
   773  				errHandler(w, err)
   774  				return
   775  			}
   776  			storage[hid] = body
   777  			w.WriteHeader(http.StatusOK)
   778  		}
   779  
   780  		switch r.Method {
   781  		case http.MethodGet:
   782  			getHandler(w, r)
   783  		case http.MethodPost:
   784  			p := r.URL.Path
   785  			if strings.Contains(p, "/accounts/") {
   786  				updateAccountHandler(w, r)
   787  			} else if strings.HasSuffix(p, "/activations") {
   788  				updateActivationHandler(w, r)
   789  			}
   790  		default:
   791  			w.WriteHeader(http.StatusBadRequest)
   792  		}
   793  	}))
   794  
   795  	if opts.Vers == 1 {
   796  		oc := jwt1.NewOperatorClaims(opk)
   797  		oc.Name = "T"
   798  		oc.Subject = opk
   799  		u, err := url.Parse(tas.URL)
   800  		require.NoError(t, err)
   801  		u.Path = "jwt/v1"
   802  		oc.AccountServerURL = u.String()
   803  		token, err := oc.Encode(okp)
   804  		require.NoError(t, err)
   805  		storage["operator"] = []byte(token)
   806  	} else {
   807  		oc := jwt.NewOperatorClaims(opk)
   808  		oc.Name = "T"
   809  		oc.Subject = opk
   810  		u, err := url.Parse(tas.URL)
   811  		require.NoError(t, err)
   812  		u.Path = "jwt/v1"
   813  		oc.AccountServerURL = u.String()
   814  		token, err := oc.Encode(okp)
   815  		require.NoError(t, err)
   816  		storage["operator"] = []byte(token)
   817  	}
   818  
   819  	return tas, storage
   820  }
   821  
   822  // Runs a TestAccountServer returning the server and the underlying storage
   823  func RunTestAccountServer(t *testing.T) (*httptest.Server, map[string][]byte) {
   824  	_, _, okp := CreateOperatorKey(t)
   825  	return RunTestAccountServerWithOperatorKP(t, okp, TasOpts{Vers: 2})
   826  }