Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ It supports authenticated publishing, subscribing, rate-limited usage tracking,
- [x] Forward messages to webhook endpoints (POST method) with flexible JSON template formatting
- [x] Health monitoring and system metrics
- [x] Debug mode with detailed timing and proxy information
- [x] Development mode with `--disable-auth` flag for testing

---

Expand Down Expand Up @@ -46,6 +47,13 @@ Download from [releases](https://github.com/getoptimum/mump2p-cli/releases/lates
./mump2p whoami # Check your session
```

**Development/Testing Mode:**
```sh
# Skip authentication for testing (all commands work without login)
./mump2p --disable-auth publish --topic=test --message="Hello"
./mump2p --disable-auth subscribe --topic=test
```

### 3. Basic Usage

```sh
Expand Down
20 changes: 20 additions & 0 deletions cmd/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,21 @@ var whoamiCmd = &cobra.Command{
Short: "Show current authentication status",
Long: `Display information about the current authentication token.`,
RunE: func(cmd *cobra.Command, args []string) error {
if IsAuthDisabled() {
// Display mock authentication status when auth is disabled
fmt.Println("Authentication Status:")
fmt.Println("----------------------")
fmt.Println("Client ID: N/A (auth disabled)")
fmt.Println("Is Active: true (auth disabled)")
fmt.Println("Rate Limits:")
fmt.Println(" Max Publish Per Hour: unlimited")
fmt.Println(" Max Publish Per Sec: unlimited")
fmt.Println(" Max Message Size: unlimited")
fmt.Println(" Daily Quota: unlimited")
fmt.Println("Token Expires: N/A (auth disabled)")
return nil
}

// load token
storage := auth.NewStorageWithPath(GetAuthPath())
token, err := storage.LoadToken()
Expand Down Expand Up @@ -105,6 +120,11 @@ var refreshCmd = &cobra.Command{
Short: "Refresh the authentication token",
Long: `Manually refresh the authentication token before it expires.`,
RunE: func(cmd *cobra.Command, args []string) error {
if IsAuthDisabled() {
fmt.Println("Token refresh skipped (auth disabled)")
return nil
}

// create auth client and storage
authClient := auth.NewClient()
storage := auth.NewStorageWithPath(GetAuthPath())
Expand Down
9 changes: 9 additions & 0 deletions cmd/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ var listCmd = &cobra.Command{
Long: `List all topics that the authenticated client is currently subscribed to.
This command shows your active topics and their count.`,
RunE: func(cmd *cobra.Command, args []string) error {
if IsAuthDisabled() {
// Display empty list when auth is disabled
fmt.Println("Topics (Auth Disabled):")
fmt.Println(" Client ID: N/A")
fmt.Println(" Topics: []")
fmt.Println(" Count: 0")
return nil
}

// Authenticate
authClient := auth.NewClient()
storage := auth.NewStorageWithPath(GetAuthPath())
Expand Down
65 changes: 43 additions & 22 deletions cmd/publish.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,21 +69,39 @@ var publishCmd = &cobra.Command{
return errors.New("only one of --message or --file should be used at a time")
}

authClient := auth.NewClient()
storage := auth.NewStorageWithPath(GetAuthPath())
token, err := authClient.GetValidToken(storage)
if err != nil {
return fmt.Errorf("authentication required: %v", err)
}
// parse token to check if the account is active
parser := auth.NewTokenParser()
claims, err := parser.ParseToken(token.Token)
if err != nil {
return fmt.Errorf("error parsing token: %v", err)
}
// check if the account is active
if !claims.IsActive {
return fmt.Errorf("your account is inactive, please contact support")
var claims *auth.TokenClaims
var token *auth.StoredToken
if !IsAuthDisabled() {
authClient := auth.NewClient()
storage := auth.NewStorageWithPath(GetAuthPath())
var err error
token, err = authClient.GetValidToken(storage)
if err != nil {
return fmt.Errorf("authentication required: %v", err)
}
// parse token to check if the account is active
parser := auth.NewTokenParser()
claims, err = parser.ParseToken(token.Token)
if err != nil {
return fmt.Errorf("error parsing token: %v", err)
}
// check if the account is active
if !claims.IsActive {
return fmt.Errorf("your account is inactive, please contact support")
}
} else {
// Create mock claims and token for disabled auth
Comment thread
swarna1101 marked this conversation as resolved.
Outdated
claims = &auth.TokenClaims{
IsActive: true,
MaxPublishPerHour: 1000,
MaxPublishPerSec: 100,
MaxMessageSize: 1024 * 1024, // 1MB
DailyQuota: 100 * 1024 * 1024, // 100MB
ClientID: "mock-client-id",
}
Comment thread
swarna1101 marked this conversation as resolved.
Outdated
token = &auth.StoredToken{
Token: "mock-token-for-disabled-auth",
Comment thread
swarna1101 marked this conversation as resolved.
Outdated
}
}
var (
data []byte
Expand All @@ -104,14 +122,17 @@ var publishCmd = &cobra.Command{
// message size
messageSize := int64(len(data))

limiter, err := ratelimit.NewRateLimiterWithDir(claims, GetAuthDir())
if err != nil {
return fmt.Errorf("rate limiter setup failed: %v", err)
}
// Skip rate limiting if auth is disabled
if !IsAuthDisabled() {
limiter, err := ratelimit.NewRateLimiterWithDir(claims, GetAuthDir())
if err != nil {
return fmt.Errorf("rate limiter setup failed: %v", err)
}

// check all rate limits: size, quota, per-hr, per-sec
if err := limiter.CheckPublishAllowed(messageSize); err != nil {
return err
// check all rate limits: size, quota, per-hr, per-sec
if err := limiter.CheckPublishAllowed(messageSize); err != nil {
return err
}
Comment thread
hpsing marked this conversation as resolved.
}

// use custom service URL if provided, otherwise use the default
Expand Down
15 changes: 11 additions & 4 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package cmd

import (
"fmt"
"os"
"path/filepath"

"github.com/spf13/cobra"
)

var (
authPath string // Global flag for custom authentication file path
debug bool // Global flag for debug mode
authPath string // Global flag for custom authentication file path
debug bool // Global flag for debug mode
disableAuth bool // Global flag to disable authentication checks
)

var rootCmd = &cobra.Command{
Expand All @@ -22,7 +22,6 @@ without relying on the HTTP server. It directly invokes Go services.`,

func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Println("Error:", err)
os.Exit(1)
}
}
Expand All @@ -34,6 +33,9 @@ func init() {
// Add global debug flag
rootCmd.PersistentFlags().BoolVar(&debug, "debug", false, "Enable debug mode with detailed timing and proxy information")

// Add global disable auth flag
rootCmd.PersistentFlags().BoolVar(&disableAuth, "disable-auth", false, "Disable authentication checks (for testing/development)")

// disable completion option
rootCmd.CompletionOptions.DisableDefaultCmd = true
}
Expand All @@ -56,3 +58,8 @@ func GetAuthDir() string {
func IsDebugMode() bool {
return debug
}

// IsAuthDisabled returns true if authentication is disabled
func IsAuthDisabled() bool {
return disableAuth
}
46 changes: 30 additions & 16 deletions cmd/subscribe.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,22 +66,36 @@ var subscribeCmd = &cobra.Command{
Use: "subscribe",
Short: "Subscribe to a topic via WebSocket or gRPC stream",
RunE: func(cmd *cobra.Command, args []string) error {
// auth
authClient := auth.NewClient()
storage := auth.NewStorageWithPath(GetAuthPath())
token, err := authClient.GetValidToken(storage)
if err != nil {
return fmt.Errorf("authentication required: %v", err)
}
// parse token to check if the account is active
parser := auth.NewTokenParser()
claims, err := parser.ParseToken(token.Token)
if err != nil {
return fmt.Errorf("error parsing token: %v", err)
}
// check if the account is active
if !claims.IsActive {
return fmt.Errorf("your account is inactive, please contact support")
var claims *auth.TokenClaims
var token *auth.StoredToken
if !IsAuthDisabled() {
// auth
authClient := auth.NewClient()
storage := auth.NewStorageWithPath(GetAuthPath())
var err error
token, err = authClient.GetValidToken(storage)
if err != nil {
return fmt.Errorf("authentication required: %v", err)
}
// parse token to check if the account is active
parser := auth.NewTokenParser()
claims, err = parser.ParseToken(token.Token)
if err != nil {
return fmt.Errorf("error parsing token: %v", err)
}
// check if the account is active
if !claims.IsActive {
return fmt.Errorf("your account is inactive, please contact support")
}
} else {
// Create mock claims and token for disabled auth
claims = &auth.TokenClaims{
IsActive: true,
ClientID: "mock-client-id",
}
token = &auth.StoredToken{
Token: "mock-token-for-disabled-auth",
}
}

// setup persistence if path is provided
Expand Down
12 changes: 12 additions & 0 deletions cmd/usages.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@ var usageCmd = &cobra.Command{
Use: "usage",
Short: "Display usage statistics and rate limits",
RunE: func(cmd *cobra.Command, args []string) error {
if IsAuthDisabled() {
// Display mock usage statistics when auth is disabled
fmt.Println("Usage Statistics (Auth Disabled):")
fmt.Println(" Publish (hour): 0 / unlimited")
fmt.Println(" Publish (second): 0 / unlimited")
fmt.Println(" Data Used: 0.0000 MB / unlimited MB")
fmt.Println(" Next Reset: N/A (auth disabled)")
fmt.Println(" Last Publish: N/A")
fmt.Println(" Last Subscribe: N/A")
return nil
}

// get valid token (refreshes if needed)
authClient := auth.NewClient()
storage := auth.NewStorageWithPath(GetAuthPath())
Expand Down
20 changes: 20 additions & 0 deletions docs/guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
After completing the README's quick start, this guide will teach you:

- **Authentication Management**: Token management, refresh, and troubleshooting
- **Development Mode**: Testing without authentication using `--disable-auth` flag
- **Service Configuration**: Using different proxy servers and custom URLs
- **Protocol Deep Dive**: When to use HTTP/WebSocket vs gRPC
- **Advanced Features**: Message persistence, webhooks, and monitoring
Expand Down Expand Up @@ -100,6 +101,25 @@ export MUMP2P_AUTH_PATH="/opt/mump2p/auth/token.yml"
- Rate limiting usage files will be stored in the same directory
- Ensure the user has write permissions to the specified directory

### Development/Testing Mode

For development and testing scenarios, you can bypass authentication entirely using the `--disable-auth` flag:

```sh
# All commands work without login
./mump2p --disable-auth whoami
./mump2p --disable-auth publish --topic=test --message="Hello"
./mump2p --disable-auth subscribe --topic=test
Comment thread
paiva marked this conversation as resolved.
Outdated
./mump2p --disable-auth list
Comment thread
swarna1101 marked this conversation as resolved.
Outdated
./mump2p --disable-auth usage
Comment thread
paiva marked this conversation as resolved.
```

**When using `--disable-auth`:**
- Uses mock client ID (`mock-client-id`)
- Unlimited rate limits for testing
- All functionality works without authentication
- Perfect for development,and testing

### Logout

To remove your stored authentication token:
Expand Down
Loading