diff --git a/cmd/account.go b/cmd/account.go index f79f3e5..f003cdd 100644 --- a/cmd/account.go +++ b/cmd/account.go @@ -1,6 +1,10 @@ package cmd import ( + "fmt" + "time" + + "github.com/paastech-cloud/cli/internal/config" "github.com/spf13/cobra" ) @@ -8,8 +12,26 @@ var accountCmd = &cobra.Command{ GroupID: "account", Use: "account", Short: "Get infos about user account", - Long: "Get infos about user account", RunE: func(cmd *cobra.Command, args []string) error { + jwt, err := config.ExtractJWTInfos() + if err != nil { + return err + } + + fmt.Println("👤 You are logged in as: " + jwt.Username) + timeDiff := jwt.ExpirationTime.Sub(time.Now()) + if timeDiff > 0 { + fmt.Println( + "⌛ Current session expires in: " + fmt.Sprintf( + "%02dh%02dm%02ds", + int(timeDiff.Hours()), + int(timeDiff.Minutes())%60, + int(timeDiff.Seconds())%60, + ), + ) + } else { + fmt.Println("❌ Current session is expired. Please log back in.") + } return nil }, } diff --git a/cmd/login.go b/cmd/login.go index 2d3b19b..0cfaa85 100644 --- a/cmd/login.go +++ b/cmd/login.go @@ -18,8 +18,7 @@ var ( var loginCmd = &cobra.Command{ GroupID: "account", Use: "login", - Short: "Log in to PaaSTech.cloud", - Long: "Log in to PaaSTech.cloud", + Short: "Log in to PaaSTech", RunE: func(cmd *cobra.Command, args []string) error { email, _ := cmd.Flags().GetString("email") password, _ := cmd.Flags().GetString("password") diff --git a/go.mod b/go.mod index 542249a..62583d1 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/paastech-cloud/cli go 1.20 require ( - github.com/mitchellh/go-homedir v1.1.0 + github.com/golang-jwt/jwt/v5 v5.0.0 github.com/spf13/cobra v1.7.0 github.com/spf13/viper v1.16.0 golang.org/x/crypto v0.10.0 diff --git a/go.sum b/go.sum index 228aee0..e1ef55f 100644 --- a/go.sum +++ b/go.sum @@ -86,6 +86,8 @@ github.com/go-git/go-git/v5 v5.7.0/go.mod h1:coJHKEOk5kUClpsNlXrUvPrDxY3w3gjHvhc github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= +github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -172,8 +174,6 @@ github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0V github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= -github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= diff --git a/internal/config/config.go b/internal/config/config.go index 067352b..0847afd 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -2,17 +2,33 @@ package config import ( "errors" + "fmt" "os" "path/filepath" + "time" + "github.com/golang-jwt/jwt/v5" "github.com/spf13/viper" ) -// Load the auth config (jwt) from $HOME/.config/paastech/auth.yaml -func LoadAuthConfig() error { +type JWTInfos struct { + Username string + ExpirationTime time.Time +} + +// Set and return auth config as config file +func authConfigFile() string { // Define config path authConfigFile := filepath.Join(os.Getenv("HOME"), ".config", "paastech", "auth.yaml") viper.SetConfigFile(authConfigFile) + viper.ReadInConfig() + return authConfigFile +} + +// Load the auth config (jwt) from $HOME/.config/paastech/auth.yaml +func LoadAuthConfig() error { + // Set auth config file as config + authConfigFile := authConfigFile() // Check if the auth.yaml file exists, if not, create it if _, err := os.Stat(authConfigFile); os.IsNotExist(err) { @@ -33,15 +49,39 @@ func LoadAuthConfig() error { // Set the jwt in config file func SetJWT(jwt string) { - // Define config path - authConfigFile := filepath.Join(os.Getenv("HOME"), ".config", "paastech", "auth.yaml") - viper.SetConfigFile(authConfigFile) + // Set auth config file as config + authConfigFile() // Change jwt value in config file viper.Set("jwt", jwt) viper.WriteConfig() } +// Extract payload from jwt and return it as UserInfos struct +func ExtractJWTInfos() (JWTInfos, error) { + // Set auth config file as config + authConfigFile() + + // Get jwt from config + tokenString := viper.GetString("jwt") + if tokenString == "" { + return JWTInfos{}, errors.New("Not logged in") + } + + // Parse payload + token, _, err := new(jwt.Parser).ParseUnverified(tokenString, jwt.MapClaims{}) + if err != nil { + fmt.Println(tokenString) + return JWTInfos{}, errors.New("Impossible to parse user jwt") + } + claims := token.Claims.(jwt.MapClaims) + + return JWTInfos{ + Username: claims["username"].(string), + ExpirationTime: time.Unix(int64(claims["exp"].(float64)), 0), + }, nil +} + // Create the auth config file in the home config directory func createAuthConfig(path string) error { // Create the $HOME/.config/paastech directory if it doesn't exist