Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/authz/pkce.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func UserPkceCmd(imsConfig *ims.Config) *cobra.Command {
cmd.Flags().StringVarP(&imsConfig.Organization, "organization", "o", "", "IMS Organization.")
cmd.Flags().StringSliceVarP(&imsConfig.Scopes, "scopes", "s", []string{""}, "Scopes to request.")
cmd.Flags().BoolVarP(&imsConfig.PublicClient, "public", "b", false, "Public client, ignore secret.")
//TODO: cmd.Flags().IntVarP(&imsConfig.Port, "port", "C", 8888, "Local port to be used by the OAuth Client.")
cmd.Flags().IntVarP(&imsConfig.Port, "port", "l", 8888, "Local port to be used by the OAuth Client.")

return cmd
}
2 changes: 1 addition & 1 deletion cmd/authz/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func UserCmd(imsConfig *ims.Config) *cobra.Command {
cmd.Flags().StringVarP(&imsConfig.ClientSecret, "clientSecret", "p", "", "IMS client secret.")
cmd.Flags().StringVarP(&imsConfig.Organization, "organization", "o", "", "IMS Organization.")
cmd.Flags().StringSliceVarP(&imsConfig.Scopes, "scopes", "s", []string{""}, "Scopes to request.")
//TODO: cmd.Flags().IntVarP(&imsConfig.Port, "port", "C", 8888, "Local port to be used by the OAuth Client.")
cmd.Flags().IntVarP(&imsConfig.Port, "port", "l", 8888, "Local port to be used by the OAuth Client.")

return cmd
}
12 changes: 7 additions & 5 deletions cmd/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,20 @@ func decodeCmd(imsConfig *ims.Config) *cobra.Command {
Use: "decode",
Aliases: []string{"dec"},
Short: "Decode a JWT token.",
Long: "Decode a JWT token.",
Long: "Decode a JWT token and display the header and payload as prettified JSON.",
RunE: func(cmd *cobra.Command, args []string) error {
cmd.SilenceUsage = true
cmd.SilenceErrors = true

resp, err := imsConfig.DecodeToken()
decoded, err := imsConfig.DecodeToken()
if err != nil {
return fmt.Errorf("error decoding the token: %v", err)
}
for _, part := range resp {
fmt.Println(part)
}

fmt.Println(decoded.Header)
fmt.Println()
fmt.Println(decoded.Payload)

return nil
},
}
Expand Down
3 changes: 2 additions & 1 deletion cmd/organizations.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"fmt"

"github.com/adobe/imscli/ims"
"github.com/adobe/imscli/output"
"github.com/spf13/cobra"
)

Expand All @@ -32,7 +33,7 @@ func organizationsCmd(imsConfig *ims.Config) *cobra.Command {
if err != nil {
return fmt.Errorf("error in get organizations cmd: %v", err)
}
fmt.Println(resp)
output.PrintPrettyJSON(resp)
return nil
},
}
Expand Down
3 changes: 2 additions & 1 deletion cmd/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"fmt"

"github.com/adobe/imscli/ims"
"github.com/adobe/imscli/output"
"github.com/spf13/cobra"
)

Expand All @@ -31,7 +32,7 @@ func profileCmd(imsConfig *ims.Config) *cobra.Command {
if err != nil {
return fmt.Errorf("error in get profile cmd: %v", err)
}
fmt.Println(resp)
output.PrintPrettyJSON(resp)
return nil
},
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
package cmd

import (
"io/ioutil"
"io"
"log"

"github.com/adobe/imscli/ims"
Expand All @@ -30,7 +30,7 @@ func RootCmd(version string) *cobra.Command {
Version: version,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
if !verbose {
log.SetOutput(ioutil.Discard)
log.SetOutput(io.Discard)
}
// This call of the initParams will load all env vars, config file and flags.
return initParams(cmd, imsConfig, configFile)
Expand Down
3 changes: 2 additions & 1 deletion cmd/validate/access_token.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"fmt"

"github.com/adobe/imscli/ims"
"github.com/adobe/imscli/output"
"github.com/spf13/cobra"
)

Expand All @@ -34,7 +35,7 @@ func AccessTokenCmd(imsConfig *ims.Config) *cobra.Command {
if !resp.Valid {
return fmt.Errorf("invalid token: %v", resp.Info)
}
fmt.Println(resp.Info)
output.PrintPrettyJSON(resp.Info)
return nil
},
}
Expand Down
3 changes: 2 additions & 1 deletion cmd/validate/authorization_code.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"fmt"

"github.com/adobe/imscli/ims"
"github.com/adobe/imscli/output"
"github.com/spf13/cobra"
)

Expand All @@ -34,7 +35,7 @@ func AuthzCodeCmd(imsConfig *ims.Config) *cobra.Command {
if !resp.Valid {
return fmt.Errorf("invalid token: %v", resp.Info)
}
fmt.Println(resp.Info)
output.PrintPrettyJSON(resp.Info)
return nil
},
}
Expand Down
3 changes: 2 additions & 1 deletion cmd/validate/device_token.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"fmt"

"github.com/adobe/imscli/ims"
"github.com/adobe/imscli/output"
"github.com/spf13/cobra"
)

Expand All @@ -34,7 +35,7 @@ func DeviceTokenCmd(imsConfig *ims.Config) *cobra.Command {
if !resp.Valid {
return fmt.Errorf("invalid token: %v", resp.Info)
}
fmt.Println(resp.Info)
output.PrintPrettyJSON(resp.Info)
return nil
},
}
Expand Down
3 changes: 2 additions & 1 deletion cmd/validate/refresh_token.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"fmt"

"github.com/adobe/imscli/ims"
"github.com/adobe/imscli/output"
"github.com/spf13/cobra"
)

Expand All @@ -34,7 +35,7 @@ func RefreshTokenCmd(imsConfig *ims.Config) *cobra.Command {
if !resp.Valid {
return fmt.Errorf("invalid token: %v", resp.Info)
}
fmt.Println(resp.Info)
output.PrintPrettyJSON(resp.Info)
return nil
},
}
Expand Down
10 changes: 8 additions & 2 deletions ims/authz_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (
"github.com/pkg/browser"
)

const port = 8888
const defaultPort = 8888

/*
* Validate that:
Expand Down Expand Up @@ -66,6 +66,12 @@ func (i Config) AuthorizeUser() (string, error) {
return "", fmt.Errorf("invalid parameters for login user: %v", err)
}

// Use default port if not specified
port := i.Port
if port == 0 {
port = defaultPort
}

httpClient, err := i.httpClient()
if err != nil {
return "", fmt.Errorf("error creating the HTTP Client: %v", err)
Expand All @@ -85,7 +91,7 @@ func (i Config) AuthorizeUser() (string, error) {
ClientSecret: i.ClientSecret,
Scope: i.Scopes,
UsePKCE: i.PKCE,
RedirectURI: "http://localhost:8888",
RedirectURI: fmt.Sprintf("http://localhost:%d", port),
OnError: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, `
<h1>An error occurred</h1>
Expand Down
56 changes: 46 additions & 10 deletions ims/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,20 @@
package ims

import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"strings"
)

// DecodedToken represents the decoded parts of a JWT token.
type DecodedToken struct {
Header string
Payload string
Signature string
}

func (i Config) validateDecodeTokenConfig() error {

if i.Token == "" {
Expand All @@ -24,7 +33,7 @@ func (i Config) validateDecodeTokenConfig() error {
return nil
}

func (i Config) DecodeToken() ([]string, error) {
func (i Config) DecodeToken() (*DecodedToken, error) {
err := i.validateDecodeTokenConfig()
if err != nil {
return nil, fmt.Errorf("incomplete parameters for token decodification: %v", err)
Expand All @@ -35,13 +44,40 @@ func (i Config) DecodeToken() ([]string, error) {
return nil, fmt.Errorf("the JWT is not composed by 3 parts")
}

// i<2 to not decode the signature since it is not encoded
for i:=0; i<2; i++ {
decodedPart, err := base64.RawURLEncoding.DecodeString(parts[i])
if err != nil {
return nil, fmt.Errorf("error decoding token, part %d: %v", i, err)
}
parts[i] = string(decodedPart)
// Decode header and payload (not signature since it's binary)
decoded := &DecodedToken{
Signature: parts[2],
}

// Decode and prettify header
headerBytes, err := base64.RawURLEncoding.DecodeString(parts[0])
if err != nil {
return nil, fmt.Errorf("error decoding token header: %v", err)
}
decoded.Header, err = prettyJSON(headerBytes)
if err != nil {
return nil, fmt.Errorf("error formatting token header: %v", err)
}

// Decode and prettify payload
payloadBytes, err := base64.RawURLEncoding.DecodeString(parts[1])
if err != nil {
return nil, fmt.Errorf("error decoding token payload: %v", err)
}
decoded.Payload, err = prettyJSON(payloadBytes)
if err != nil {
return nil, fmt.Errorf("error formatting token payload: %v", err)
}
return parts, nil
}

return decoded, nil
}

// prettyJSON formats JSON bytes with indentation.
func prettyJSON(data []byte) (string, error) {
var prettyBuf bytes.Buffer
err := json.Indent(&prettyBuf, data, "", " ")
if err != nil {
return "", err
}
return prettyBuf.String(), nil
}
4 changes: 2 additions & 2 deletions ims/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,11 +145,11 @@ func modifyFulfillableData(data string) (string, error) {
}
defer func() {
if _, gzErr := io.Copy(io.Discard, gzipReader); gzErr != nil {
fmt.Errorf("error while consuming the gzip reader: %v", gzErr)
log.Printf("error while consuming the gzip reader: %v", gzErr)
}

if gzErr := gzipReader.Close(); gzErr != nil {
fmt.Errorf("unable to close gzip reader: %v", gzErr)
log.Printf("unable to close gzip reader: %v", gzErr)
}
}()

Expand Down
30 changes: 30 additions & 0 deletions output/output.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright 2025 Adobe. All rights reserved.
// This file is licensed to you 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 http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under
// the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
// OF ANY KIND, either express or implied. See the License for the specific language
// governing permissions and limitations under the License.

package output

import (
"bytes"
"encoding/json"
"fmt"
)

// PrintPrettyJSON prints a JSON string with indentation.
// If the input is not valid JSON, it prints the original string.
func PrintPrettyJSON(jsonStr string) {
var prettyBuf bytes.Buffer
err := json.Indent(&prettyBuf, []byte(jsonStr), "", " ")
if err != nil {
// Not valid JSON, print as-is
fmt.Println(jsonStr)
return
}
fmt.Println(prettyBuf.String())
}
Loading