Repository: nats-io/nsc (go)

Issue:
nsc import user does not expect a decorated jwt
When importing a system account using the procedure described [here](https://docs.nats.io/running-a-nats-service/nats_admin/security/jwt#import-operator-self-service) the final step fails.

```
root@clientk1:~# nsc import user --file system_user.jwt
[ERR ] failed to decode `system_user.jwt`: illegal base64 data at input byte 10
```

I was able to import the user by editing the jwt to remove the decoration line at the top and the corresponding line at the bottom of the file.  That is, remove the "-----BEGIN NATS ACCOUNT JWT-----".

```
root@clientk1:~# nsc import user --file system_user.jwt
[ OK ] user sys-non-op was successfully imported
```

Note that `nsc add operator` and `nsc import account` expect decorated JWTs.

Similar issues reported in #381 #499.  Apologies if this is fixed already.

nsc was installed using:

```
go install github.com/nats-io/nsc@latest
```

Pull request:
[FIX] importing of user jwt files regardless of whether they are decorated or not
[TEST] added test for importing accounts regardless of whether they are decorated or not

FIX #571 

Patch:
diff --git a/cmd/importuser.go b/cmd/importuser.go
index 78a6e4b..2755455 100644
--- a/cmd/importuser.go
+++ b/cmd/importuser.go
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020-2020 The NATS Authors
+ * Copyright 2018-2023 The NATS Authors
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -55,7 +55,7 @@ type ImportUser struct {
 	fileImport
 }
 
-func (p *ImportUser) SetDefaults(ctx ActionCtx) error {
+func (p *ImportUser) SetDefaults(_ctx ActionCtx) error {
 	return nil
 }
 
@@ -88,16 +88,16 @@ func (p *ImportUser) Run(ctx ActionCtx) (store.Status, error) {
 		r.AddError("failed to import %#q: %v", p.file, err)
 		return r, err
 	}
-	theJWT := ""
+	theJWT := strings.TrimSpace(string(content))
 	var kp nkeys.KeyPair
-	if strings.HasSuffix(p.file, ".jwt") {
-		theJWT = string(content)
-	} else {
-		if theJWT, err = jwt.ParseDecoratedJWT(content); err == nil {
-			if kp, err = jwt.ParseDecoratedUserNKey(content); err != nil {
-				r.AddError("failed to parse decorated key in %#q: %v", p.file, err)
-				return r, err
-			}
+	if !strings.HasPrefix(theJWT, "ey") {
+		theJWT, err = jwt.ParseDecoratedJWT(content)
+		if err != nil {
+			r.AddError("failed to parse decorated JWT in %q: %v", p.file, err)
+			return r, err
+		}
+		if kp, err = jwt.ParseDecoratedUserNKey(content); err != nil {
+			r.AddWarning("failed to parse decorated key in %#q: %v", p.file, err)
 		}
 	}
 	claim, err := jwt.DecodeUserClaims(theJWT)


Test patch:
diff --git a/cmd/importaccount_test.go b/cmd/importaccount_test.go
index 9de1e39..16f49f3 100644
--- a/cmd/importaccount_test.go
+++ b/cmd/importaccount_test.go
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 The NATS Authors
+ * Copyright 2018-2023 The NATS Authors
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -121,3 +121,33 @@ func Test_ImportDecoratedAccount(t *testing.T) {
 	_, _, err = ExecuteCmd(rootCmd, "import", "account", "--file", decorated)
 	require.NoError(t, err)
 }
+
+func Test_ImportAccountFromDescribe(t *testing.T) {
+	ts := NewTestStore(t, "O")
+	defer ts.Done(t)
+
+	ts.AddAccount(t, "A")
+	cmd := createDescribeAccountCmd()
+	cmd.Flags().BoolVarP(&Raw, "raw", "R", false, "output the raw JWT (exclusive of long-ids)")
+	fp := filepath.Join(ts.Dir, "A.jwt")
+
+	// generate a jwt with describe, and import it
+	_, _, err := ExecuteCmd(cmd, "--raw", "--output-file", fp)
+	require.NoError(t, err)
+	_, _, err = ExecuteCmd(createDeleteAccountCmd(), "A")
+	require.NoError(t, err)
+	_, _, err = ExecuteCmd(createImportAccountCmd(), "--file", fp)
+	require.NoError(t, err)
+	require.NoError(t, os.Remove(fp))
+
+	// generate a jwt with describe that is not armored, and import it
+	cmd = createDescribeAccountCmd()
+	cmd.Flags().BoolVarP(&Raw, "raw", "R", false, "output the raw JWT (exclusive of long-ids)")
+	stdout, _, err := ExecuteCmd(cmd, "--raw")
+	require.NoError(t, err)
+	require.NoError(t, Write(fp, []byte(stdout)))
+	_, _, err = ExecuteCmd(createDeleteAccountCmd(), "A")
+	require.NoError(t, err)
+	_, _, err = ExecuteCmd(createImportAccountCmd(), "--file", fp)
+	require.NoError(t, err)
+}
diff --git a/cmd/importuser_test.go b/cmd/importuser_test.go
index db967db..f2f6064 100644
--- a/cmd/importuser_test.go
+++ b/cmd/importuser_test.go
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020-2020 The NATS Authors
+ * Copyright 2018-2023 The NATS Authors
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -120,3 +120,43 @@ func Test_ImportUserOtherAccount(t *testing.T) {
 	_, _, err = ExecuteCmd(createImportUserCmd(), "--file", file)
 	require.Error(t, err)
 }
+
+func Test_ImportUserFromDescribe(t *testing.T) {
+	ts := NewTestStore(t, "O")
+	defer ts.Done(t)
+
+	ts.AddAccount(t, "A")
+	ts.AddUser(t, "A", "U")
+	creds := filepath.Join(ts.Dir, "u.creds")
+	_, _, err := ExecuteCmd(createGenerateCredsCmd(), "--output-file", creds)
+	require.NoError(t, err)
+	_, _, err = ExecuteCmd(createDeleteUserCmd(), "U")
+	require.NoError(t, err)
+
+	// import a creds
+	_, _, err = ExecuteCmd(createImportUserCmd(), "--file", creds)
+	require.NoError(t, err)
+
+	// generate a jwt with describe, and import it
+	cmd := createDescribeUserCmd()
+	cmd.Flags().BoolVarP(&Raw, "raw", "R", false, "output the raw JWT (exclusive of long-ids)")
+	fp := filepath.Join(ts.Dir, "u.jwt")
+	_, _, err = ExecuteCmd(cmd, "--raw", "--output-file", fp)
+	require.NoError(t, err)
+	_, _, err = ExecuteCmd(createDeleteUserCmd(), "U")
+	require.NoError(t, err)
+	_, _, err = ExecuteCmd(createImportUserCmd(), "--file", fp)
+	require.NoError(t, err)
+	require.NoError(t, os.Remove(fp))
+
+	// generate a jwt with describe that is not armored, and import it
+	cmd = createDescribeUserCmd()
+	cmd.Flags().BoolVarP(&Raw, "raw", "R", false, "output the raw JWT (exclusive of long-ids)")
+	stdout, _, err := ExecuteCmd(cmd, "--raw")
+	require.NoError(t, err)
+	require.NoError(t, Write(fp, []byte(stdout)))
+	_, _, err = ExecuteCmd(createDeleteUserCmd(), "U")
+	require.NoError(t, err)
+	_, _, err = ExecuteCmd(createImportUserCmd(), "--file", fp)
+	require.NoError(t, err)
+}