File: jose.go

package info (click to toggle)
golang-github-smallstep-cli 0.15.16%2Bds-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 4,404 kB
  • sloc: sh: 512; makefile: 99
file content (110 lines) | stat: -rw-r--r-- 3,143 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package jose

import (
	"fmt"
	"io/ioutil"
	"os"
	"regexp"
	"strings"

	"github.com/pkg/errors"
	"github.com/smallstep/cli/jose"
	"github.com/urfave/cli"
)

// Command returns the cli.Command for jose related subcommands.
func Command() cli.Command {
	return cli.Command{
		Name:      "jose",
		Usage:     "collection of JOSE utilities",
		UsageText: "step crypto jose <subcommand> [arguments] [global-flags] [subcommand-flags]",
		Subcommands: cli.Commands{
			formatCommand(),
		},
	}
}

type serializer interface {
	CompactSerialize() (string, error)
	FullSerialize() string
}

func formatCommand() cli.Command {
	return cli.Command{
		Name:      "format",
		Usage:     "swap serialization format",
		UsageText: `**step crypto jose format**`,
		Action:    cli.ActionFunc(formatAction),
		Description: `**step crypto jose format** reads a JWT, a JWS, or a JWE from STDIN swaps the
serialization of the content, from compact to JSON or from JSON to compact.

## EXAMPLES

Transform a JSON encrypted message to the compact serialization format:
'''
$ echo The message | step crypto jwe encrypt --key p256.enc.pub | step crypto jose format
eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTI1NkdDTSIsImVwayI6eyJrdHkiOiJFQyIsImNydiI6IlAtMjU2IiwieCI6IlNTR1pNdjZyMGlHbmtsMnpKRERXS1JlaDU4R3RwTjVjT2tBZnlaaUI0enMiLCJ5IjoiLUJzQ2w5RjZNd28zRWZoTFJIeVdDbGlxU2d6T2tubzNuWW80azlPSVk0TSJ9LCJraWQiOiJHd0tSTUdXY1pWNFE2dGZZblpjZm90N090N2hjQ0t2cUJPVWljX0JoZ0gwIn0
.
.
iJNn8SrqE8I5Bhog
.
NO9FfC25Ow9ogzq1.6M3Jiy_osGwlioJjXPyl9w
'''

Transform a compact token to the JSON serialization format:
'''
$ step crypto jwt sign --key p256.priv.json --iss "joe" --aud "bob" \
      --sub "hello" --exp $(date -v+1M +"%s") | step crypto jose format
{
  "payload":"eyJhdWQiOiJib2IiLCJleHAiOjE1MzUyNDE4OTYsImlhdCI6MTUzMjU2MzQ5OCwiaXNzIjoiam9lIiwibmJmIjoxNTMyNTYzNDk4LCJzdWIiOiJoZWxsbyJ9",
  "protected":"eyJhbGciOiJFUzI1NiIsImtpZCI6IlpqR1g5N0xtY2ZsUG9sV3Zzb0FXekM1V1BXa05GRkgzUWRLTFVXOTc4aGsiLCJ0eXAiOiJKV1QifQ",
  "signature":"wlRDGrjQItHFu5j2H4A4T6_P5Ek00ugJXQ3iIXibsZjU96_BaqddnAqFWeKpb6xHWGRAHKtlm9bUYBfLQ8Jlsg"
}
'''`,
	}
}

func formatAction(ctx *cli.Context) error {
	input, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		return errors.Wrap(err, "error reading input")
	}

	token := stripWhitespace(string(input))

	// Attempt to parse an encrypted
	// If it fails parse a regular JWS
	var srz serializer
	if enc, err := jose.ParseEncrypted(token); err == nil {
		srz = enc
	} else {
		tok, err := jose.ParseJWS(token)
		if err != nil {
			return errors.Wrap(trimPrefix(err), "error parsing data")
		}
		srz = tok
	}

	if strings.HasPrefix(token, "{") {
		str, err := srz.CompactSerialize()
		if err != nil {
			return errors.Wrap(trimPrefix(err), "error serializing data")
		}
		fmt.Println(str)
	} else {
		fmt.Println(srz.FullSerialize())
	}

	return nil
}

func trimPrefix(err error) error {
	return errors.New(strings.TrimPrefix(err.Error(), "square/go-jose: "))
}

var stripWhitespaceRegex = regexp.MustCompile(`\s`)

// stripWhitespace strip all newlines and whitespace
func stripWhitespace(data string) string {
	return stripWhitespaceRegex.ReplaceAllString(data, "")
}