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
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,16 @@ make install

## Quick Start

> **Prerequisites:** You need a Google Cloud OAuth credential before adding an account.
> Follow the **[OAuth Setup Guide](https://msgvault.io/guides/oauth-setup/)** to create one (~5 minutes).

```bash
msgvault init-db
msgvault add-account you@gmail.com # opens browser for OAuth
msgvault sync-full you@gmail.com --limit 100
msgvault tui
```

OAuth requires a Google Cloud project with the Gmail API enabled.
See the **[Setup Guide](https://msgvault.io/guides/oauth-setup/)** for step-by-step instructions.

## Commands

| Command | Description |
Expand Down
4 changes: 2 additions & 2 deletions cmd/msgvault/cmd/addaccount.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Example:

// Validate config
if cfg.OAuth.ClientSecrets == "" {
return fmt.Errorf("oauth.client_secrets not configured in config.toml")
return errOAuthNotConfigured()
}

// Initialize database (in case it's new)
Expand All @@ -47,7 +47,7 @@ Example:
// Create OAuth manager
oauthMgr, err := oauth.NewManager(cfg.OAuth.ClientSecrets, cfg.TokensDir(), logger)
if err != nil {
return fmt.Errorf("create oauth manager: %w", err)
return wrapOAuthError(fmt.Errorf("create oauth manager: %w", err))
}

// Check if already authorized
Expand Down
4 changes: 2 additions & 2 deletions cmd/msgvault/cmd/deletions.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ Examples:

// Validate config
if cfg.OAuth.ClientSecrets == "" {
return fmt.Errorf("oauth.client_secrets not configured in config.toml")
return errOAuthNotConfigured()
}

// Collect unique accounts from manifests
Expand Down Expand Up @@ -280,7 +280,7 @@ Examples:
// Create OAuth manager with appropriate scopes
oauthMgr, err := oauth.NewManagerWithScopes(cfg.OAuth.ClientSecrets, cfg.TokensDir(), logger, scopes)
if err != nil {
return fmt.Errorf("create oauth manager: %w", err)
return wrapOAuthError(fmt.Errorf("create oauth manager: %w", err))
}

tokenSource, err := oauthMgr.TokenSource(ctx, account)
Expand Down
24 changes: 24 additions & 0 deletions cmd/msgvault/cmd/root.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cmd

import (
"errors"
"fmt"
"log/slog"
"os"
Expand Down Expand Up @@ -54,6 +55,29 @@ func Execute() error {
return rootCmd.Execute()
}

// oauthSetupHint is the common help text for OAuth configuration issues.
const oauthSetupHint = `
To use msgvault, you need a Google Cloud OAuth credential:
1. Follow the setup guide: https://msgvault.io/guides/oauth-setup/
2. Download the client_secret.json file
3. Add to your config.toml:
[oauth]
client_secrets = "/path/to/client_secret.json"`

// errOAuthNotConfigured returns a helpful error when OAuth client secrets are missing.
func errOAuthNotConfigured() error {
return fmt.Errorf("OAuth client secrets not configured." + oauthSetupHint)
}

// wrapOAuthError wraps an oauth/client-secrets error with setup instructions
// if the root cause is a missing or unreadable secrets file.
func wrapOAuthError(err error) error {
if errors.Is(err, os.ErrNotExist) {
return fmt.Errorf("OAuth client secrets file not found." + oauthSetupHint)
}
return err
}

func init() {
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default: ~/.msgvault/config.toml)")
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "verbose output")
Expand Down
4 changes: 2 additions & 2 deletions cmd/msgvault/cmd/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Examples:

// Validate config
if cfg.OAuth.ClientSecrets == "" {
return fmt.Errorf("oauth.client_secrets not configured in config.toml")
return errOAuthNotConfigured()
}

// Open database
Expand Down Expand Up @@ -65,7 +65,7 @@ Examples:
// Create OAuth manager and get token source
oauthMgr, err := oauth.NewManager(cfg.OAuth.ClientSecrets, cfg.TokensDir(), logger)
if err != nil {
return fmt.Errorf("create oauth manager: %w", err)
return wrapOAuthError(fmt.Errorf("create oauth manager: %w", err))
}

// Set up context with cancellation
Expand Down
4 changes: 2 additions & 2 deletions cmd/msgvault/cmd/syncfull.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Examples:

// Validate config
if cfg.OAuth.ClientSecrets == "" {
return fmt.Errorf("oauth.client_secrets not configured in config.toml")
return errOAuthNotConfigured()
}

// Open database
Expand All @@ -64,7 +64,7 @@ Examples:
// Create OAuth manager and get token source
oauthMgr, err := oauth.NewManager(cfg.OAuth.ClientSecrets, cfg.TokensDir(), logger)
if err != nil {
return fmt.Errorf("create oauth manager: %w", err)
return wrapOAuthError(fmt.Errorf("create oauth manager: %w", err))
}

// Set up context with cancellation
Expand Down
4 changes: 2 additions & 2 deletions cmd/msgvault/cmd/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Examples:

// Validate config
if cfg.OAuth.ClientSecrets == "" {
return fmt.Errorf("oauth.client_secrets not configured in config.toml")
return errOAuthNotConfigured()
}

// Open database
Expand All @@ -51,7 +51,7 @@ Examples:
// Create OAuth manager and get token source
oauthMgr, err := oauth.NewManager(cfg.OAuth.ClientSecrets, cfg.TokensDir(), logger)
if err != nil {
return fmt.Errorf("create oauth manager: %w", err)
return wrapOAuthError(fmt.Errorf("create oauth manager: %w", err))
}

// Set up context with cancellation
Expand Down