Skip to content

Commit 90f8101

Browse files
committed
feat(cli): implement auth jwt command
fixes akash-network/support#323 Signed-off-by: Artur Troian <[email protected]>
1 parent dd37426 commit 90f8101

File tree

4 files changed

+179
-3
lines changed

4 files changed

+179
-3
lines changed

cmd/akash/cmd/auth.go

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"strconv"
6+
"time"
7+
8+
"github.com/golang-jwt/jwt/v5"
9+
"github.com/spf13/cobra"
10+
11+
sdkclient "github.com/cosmos/cosmos-sdk/client"
12+
13+
ajwt "github.com/akash-network/akash-api/go/util/jwt"
14+
)
15+
16+
const (
17+
FlagJWTExp = "exp"
18+
FlagJWTNbf = "nbf"
19+
FlagJWTAccess = "access"
20+
FlagJWTScope = "scope"
21+
)
22+
23+
func AuthCmd() *cobra.Command {
24+
cmd := &cobra.Command{
25+
Use: "auth",
26+
}
27+
28+
cmd.AddCommand(authJWTCmd())
29+
30+
return cmd
31+
}
32+
33+
func authJWTCmd() *cobra.Command {
34+
cmd := &cobra.Command{
35+
Use: "jwt",
36+
Args: cobra.NoArgs,
37+
RunE: func(cmd *cobra.Command, args []string) error {
38+
cctx, err := sdkclient.GetClientTxContext(cmd)
39+
if err != nil {
40+
return err
41+
}
42+
43+
signer := ajwt.NewSigner(cctx.Keyring, cctx.FromAddress)
44+
45+
now := time.Now()
46+
nbf := now
47+
48+
expString, err := cmd.Flags().GetString(FlagJWTExp)
49+
if err != nil {
50+
return err
51+
}
52+
53+
var exp time.Time
54+
// first, attempt to parse expiration value as duration.
55+
// fallback to unix timestamp if fails
56+
dur, err := time.ParseDuration(expString)
57+
if err != nil {
58+
expInt, err := strconv.ParseInt(expString, 10, 64)
59+
if err != nil {
60+
return err
61+
}
62+
63+
exp = time.Unix(expInt, 0)
64+
} else {
65+
exp = now.Add(dur)
66+
}
67+
68+
if cmd.Flags().Changed(FlagJWTNbf) {
69+
nbfString, err := cmd.Flags().GetString(FlagJWTNbf)
70+
if err != nil {
71+
return err
72+
}
73+
74+
// first, attempt to parse expiration value as duration.
75+
// fallback to unix timestamp if fails
76+
dur, err := time.ParseDuration(nbfString)
77+
if err != nil {
78+
nbfInt, err := strconv.ParseInt(nbfString, 10, 64)
79+
if err != nil {
80+
return err
81+
}
82+
83+
exp = time.Unix(nbfInt, 0)
84+
} else {
85+
exp = now.Add(dur)
86+
}
87+
}
88+
89+
accessString, err := cmd.Flags().GetString(FlagJWTAccess)
90+
if err != nil {
91+
return err
92+
}
93+
94+
access, valid := parseAccess(accessString)
95+
if !valid {
96+
return fmt.Errorf("invalid `access` flags")
97+
}
98+
99+
var scope ajwt.PermissionScopes
100+
101+
if cmd.Flags().Changed(FlagJWTScope) {
102+
scopeString, err := cmd.Flags().GetString(FlagJWTAccess)
103+
if err != nil {
104+
return err
105+
}
106+
107+
if err = scope.UnmarshalCSV(scopeString); err != nil {
108+
return err
109+
}
110+
}
111+
112+
if !exp.After(now) {
113+
return fmt.Errorf("`exp` value is invalid or in the past. expected %d (exp) > %d (curr)", exp.Unix(), now.Unix())
114+
}
115+
116+
if !nbf.After(exp) {
117+
return fmt.Errorf("`nbf` value is invalid. expected %d (nbf) < %d (exp)", nbf.Unix(), exp.Unix())
118+
}
119+
120+
claims := ajwt.Claims{
121+
RegisteredClaims: jwt.RegisteredClaims{
122+
Issuer: cctx.FromAddress.String(),
123+
IssuedAt: jwt.NewNumericDate(now),
124+
NotBefore: jwt.NewNumericDate(nbf),
125+
ExpiresAt: jwt.NewNumericDate(exp),
126+
},
127+
Version: "v1",
128+
Leases: ajwt.Leases{
129+
Access: access,
130+
Scope: scope,
131+
},
132+
}
133+
134+
tok := jwt.NewWithClaims(ajwt.SigningMethodES256K, &claims)
135+
136+
tokString, err := tok.SignedString(signer)
137+
if err != nil {
138+
return err
139+
}
140+
141+
return cctx.PrintString(tokString)
142+
},
143+
}
144+
145+
cmd.Flags().String(FlagJWTExp, "15m", "Set token's `exp` field. Format is either 15m|h or unix timestamp")
146+
cmd.Flags().String(FlagJWTNbf, "", "Set token's `nbf` field. Format is either 15m|h or unix timestamp. Empty equals to current timestamp")
147+
cmd.Flags().String(FlagJWTAccess, "full", "Set token's `leases.access` field. Permitted values are full|scoped|granular. Default is full")
148+
cmd.Flags().StringSlice(FlagJWTScope, nil, "Set token's `leases.scope` field. Comma separated list of scopes. Can only be set if `leases.access=scoped`. Allowed scopes are")
149+
150+
return cmd
151+
}
152+
153+
func parseAccess(val string) (ajwt.AccessType, bool) {
154+
res := ajwt.AccessType(val)
155+
156+
switch res {
157+
case ajwt.AccessTypeFull:
158+
case ajwt.AccessTypeScoped:
159+
case ajwt.AccessTypeGranular:
160+
default:
161+
return ajwt.AccessTypeNone, false
162+
}
163+
164+
return res, true
165+
}

cmd/akash/cmd/root.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig) {
145145
ecmd.EventCmd(),
146146
QueryCmd(),
147147
TxCmd(),
148+
AuthCmd(),
148149
keys.Commands(app.DefaultHome),
149150
genutilcli.InitCmd(app.ModuleBasics(), app.DefaultHome),
150151
genutilcli.CollectGenTxsCmd(banktypes.GenesisBalancesIterator{}, app.DefaultHome),

go.mod

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ go 1.23.0
55
toolchain go1.23.6
66

77
require (
8-
github.com/akash-network/akash-api v0.0.78
8+
github.com/akash-network/akash-api v0.0.79
99
github.com/blang/semver/v4 v4.0.0
1010
github.com/boz/go-lifecycle v0.1.1
1111
github.com/cosmos/cosmos-sdk v0.45.16
@@ -77,6 +77,8 @@ replace (
7777
google.golang.org/grpc => google.golang.org/grpc v1.33.2
7878
)
7979

80+
require github.com/golang-jwt/jwt/v5 v5.2.2
81+
8082
require (
8183
cosmossdk.io/api v0.2.6 // indirect
8284
cosmossdk.io/core v0.5.1 // indirect
@@ -189,6 +191,9 @@ require (
189191
github.com/tendermint/go-amino v0.16.0 // indirect
190192
github.com/tidwall/btree v1.5.0 // indirect
191193
github.com/x448/float16 v0.8.4 // indirect
194+
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
195+
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
196+
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
192197
github.com/zondax/hid v0.9.1 // indirect
193198
github.com/zondax/ledger-go v0.14.1 // indirect
194199
go.etcd.io/bbolt v1.3.6 // indirect

go.sum

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBA
7676
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
7777
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
7878
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
79-
github.com/akash-network/akash-api v0.0.78 h1:X75JgjjjL3B+nZjWWEjSq8SXRUPM2r59x/Wc0wjOx1g=
80-
github.com/akash-network/akash-api v0.0.78/go.mod h1:SpY0xGhmCu6Nz/M5MsKIyJUwzw2FBKR3yAeawUcBlG4=
79+
github.com/akash-network/akash-api v0.0.79 h1:F/Qkjc6zmkqfiLdw4QlGqFW7EwwViXXUy5wkXMPNnDU=
80+
github.com/akash-network/akash-api v0.0.79/go.mod h1:SpY0xGhmCu6Nz/M5MsKIyJUwzw2FBKR3yAeawUcBlG4=
8181
github.com/akash-network/cometbft v0.34.27-akash.3 h1:ObmkKrMybIuRLPcwPwUMJ8Pllsr+Gsve443mkJsonMA=
8282
github.com/akash-network/cometbft v0.34.27-akash.3/go.mod h1:BcCbhKv7ieM0KEddnYXvQZR+pZykTKReJJYf7YC7qhw=
8383
github.com/akash-network/cosmos-sdk v0.45.16-akash.3 h1:QiHOQ1ACzCvAEXRlzGNQhp9quWLOowE104D0uESGrEk=
@@ -411,6 +411,8 @@ github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY
411411
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
412412
github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
413413
github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
414+
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
415+
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
414416
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
415417
github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
416418
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@@ -1030,8 +1032,11 @@ github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV
10301032
github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
10311033
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
10321034
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
1035+
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
10331036
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
1037+
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
10341038
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
1039+
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
10351040
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
10361041
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
10371042
github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=

0 commit comments

Comments
 (0)