mirror of
https://github.com/passbolt/go-passbolt-cli.git
synced 2025-05-11 10:38:21 +00:00
Compare commits
7 commits
9af92a9a6a
...
ed63e2b274
Author | SHA1 | Date | |
---|---|---|---|
![]() |
ed63e2b274 | ||
6033d6bbb3 | |||
![]() |
78ed21f62b | ||
![]() |
0273cee2ba | ||
![]() |
72cfd79b77 | ||
![]() |
d5e2df49db | ||
![]() |
6070bf3cf4 |
5 changed files with 113 additions and 32 deletions
40
README.md
40
README.md
|
@ -1,10 +1,10 @@
|
|||
# go-passbolt-cli
|
||||
A CLI tool to interact with Passbolt, an Open source Password Manager for teams.
|
||||
|
||||
If you want to do something more complicated: [this Go Module](https://github.com/passbolt/go-passbolt) to Interact with Passbolt from Go might intrest you.
|
||||
If you want to do something more complicated: [this Go Module](https://github.com/passbolt/go-passbolt) to Interact with Passbolt from Go might interest you.
|
||||
|
||||
|
||||
Disclaimer: This project is community driven and not associated with Passbolt SA
|
||||
Disclaimer: This project is community-driven and not associated with Passbolt SA
|
||||
# Install
|
||||
|
||||
## Via Repository (Prefered):
|
||||
|
@ -28,7 +28,7 @@ Note: tab completion and manpages will need to be installed manually.
|
|||
Note: this will install the binary as go-passbolt-cli, also tab completion and manpages will be missing.
|
||||
|
||||
# Getting Started
|
||||
First you need to Setup basic information: the Server Address, your Private Key and your Password.
|
||||
First, you need to set up basic information: the Server Address, your Private Key, and your Password.
|
||||
You have these options:
|
||||
- Save it in the config file using
|
||||
```
|
||||
|
@ -43,23 +43,23 @@ passbolt configure --serverAddress https://passbolt.example.org --userPassword '
|
|||
|
||||
Notes:
|
||||
- You can set the Private Key using the flags `--userPrivateKey` or `--userPrivateKeyFile` where `--userPrivateKey` takes the actual private key and `--userPrivateKeyFile` loads the content of a file as the PrivateKey, `--userPrivateKeyFile` overwrites the value of `--userPrivateKey`.
|
||||
- You can also just store the serverAddress and your Private Key, if your Password is not set it will prompt you for it every time.
|
||||
- You can also just store the serverAddress and your Private Key, if your Password is not set, it will prompt you for it every time.
|
||||
- Passwordless PrivateKeys are unsupported
|
||||
- MFA settings can also be save permanently this ways
|
||||
- MFA settings can also be saved permanently these ways
|
||||
|
||||
# Usage
|
||||
|
||||
Generally the Structure of Commands is like this:
|
||||
Generally, the Structure of Commands is like this:
|
||||
```bash
|
||||
passbolt action entity [arguments]
|
||||
```
|
||||
|
||||
Action is the Action you want to perform like Creating, Updating or Deleting an Entity.
|
||||
Action is the Action you want to perform, like Creating, Updating, or Deleting an Entity.
|
||||
Entity is a Resource(Password), Folder, User or Group that you want to apply an action to.
|
||||
|
||||
In Passbolt a Password is usually revert to as a Resource.
|
||||
In Passbolt, a Password is usually referred to as a Resource.
|
||||
|
||||
To Create a Resource you can do this, it will return the ID of the newly created Resource:
|
||||
To Create a Resource, you can do this. It will return the ID of the newly created Resource:
|
||||
```bash
|
||||
passbolt create resource --name "Test Resource" --password "Strong Password"
|
||||
```
|
||||
|
@ -68,10 +68,10 @@ You can then list all users:
|
|||
```bash
|
||||
passbolt list user
|
||||
```
|
||||
Note: you can adjust which columns should be listed using the flag `--column` or its short from `-c`, if you want multiple column then you need to specify this flag multiple times.
|
||||
Note: you can adjust which columns should be listed using the flag `--column` or its short from `-c`, if you want multiple columns then you need to specify this flag multiple times.
|
||||
|
||||
|
||||
For sharing we will need to know how we want to share, for that there are these Permission Types:
|
||||
For sharing, we will need to know how we want to share. For that, there are these Permission Types:
|
||||
|
||||
| Code | Meaning |
|
||||
| --- | --- |
|
||||
|
@ -80,32 +80,32 @@ For sharing we will need to know how we want to share, for that there are these
|
|||
| `15` | "Owner" |
|
||||
| `-1` | Delete existing permission |
|
||||
|
||||
Now that we have a Resource ID, know the ID's of other Users and about know about Permission Types, we can share the Resource with them:
|
||||
Now that we have a Resource ID, know the ID's of other Users and know about Permission Types, we can share the Resource with them:
|
||||
```bash
|
||||
passbolt share resource --id id_of_resource_to_share --type type_of_permission --user id_of_user_to_share_with
|
||||
```
|
||||
Note: you can supply the the users argument multiple times to share with multiple users
|
||||
Note: you can supply the `user` argument multiple times to share with multiple users
|
||||
|
||||
For sharing with groups the `--group` argument exists.
|
||||
For sharing with groups, the `--group` argument exists.
|
||||
|
||||
# MFA
|
||||
You can setup MFA also using the configuration sub command, only TOTP is supported, there are multiple modes for MFA: `none`, `interactive-totp` and `noninteractive-totp`.
|
||||
You can also set up MFA using the configuration subcommand. Only TOTP is supported, and there are multiple modes for MFA: `none`, `interactive-totp`, and `noninteractive-totp`.
|
||||
| Mode | Description |
|
||||
| --- | --- |
|
||||
|`none`|just errors if challenged for MFA.
|
||||
|`interactive-totp` | prompts for interactive entry of TOTP Codes.
|
||||
|`noninteractive-totp` | automatically generates TOTP Codes when challenged, it requires the `mfaTotpToken` flag to be set to your totp Secret, you can configure the behavior using the `mfaDelay`, `mfaRetrys` and `mfaTotpOffset` flags
|
||||
|`noninteractive-totp` | automatically generates TOTP Codes when challenged. It requires the `mfaTotpToken` flag to be set to your totp Secret, you can configure the behavior using the `mfaDelay`, `mfaRetrys` and `mfaTotpOffset` flags
|
||||
|
||||
|
||||
# Server Verification
|
||||
To enable Server Verification you need to run `passbolt verify` once, after that the server will always be verified if the same config is used
|
||||
To enable Server Verification, you need to run `passbolt verify` once. After that, the server will always be verified if the same config is used
|
||||
|
||||
# Scripting
|
||||
For Scripting we have a -j or --json flag to convert the Output for the create, get and list commands to JSON for easier Parsing in Scripts.
|
||||
For Scripting, we have a -j or --json flag to convert the Output for the create, get and list commands to JSON for easier Parsing in Scripts.
|
||||
|
||||
Note: The JSON Output does not cover Error Messages, you can detect Errors by checking if the Exitcode is not 0
|
||||
Note: The JSON Output does not cover Error Messages. You can detect Errors by checking if the Exitcode is not 0
|
||||
|
||||
# Documentation
|
||||
Usage for all Subcommands is [here](https://github.com/passbolt/go-passbolt-cli/wiki/passbolt).
|
||||
And is also available via `man passbolt`
|
||||
It is also available via `man passbolt`
|
||||
|
||||
|
|
49
cmd/root.go
49
cmd/root.go
|
@ -2,7 +2,6 @@ package cmd
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
@ -60,6 +59,12 @@ func init() {
|
|||
rootCmd.PersistentFlags().Uint("mfaRetrys", 3, "How often to retry TOTP Auth, only used in nointeractive modes")
|
||||
rootCmd.PersistentFlags().Duration("mfaDelay", time.Second*10, "Delay between MFA Attempts, only used in noninteractive modes")
|
||||
|
||||
rootCmd.PersistentFlags().Bool("tlsSkipVerify", false, "Allow servers with self-signed certificates")
|
||||
rootCmd.PersistentFlags().String("tlsClientPrivateKeyFile", "", "Client private key path for mtls")
|
||||
rootCmd.PersistentFlags().String("tlsClientCertFile", "", "Client certificate path for mtls")
|
||||
rootCmd.PersistentFlags().String("tlsClientPrivateKey", "", "Client private key for mtls")
|
||||
rootCmd.PersistentFlags().String("tlsClientCert", "", "Client certificate for mtls")
|
||||
|
||||
viper.BindPFlag("debug", rootCmd.PersistentFlags().Lookup("debug"))
|
||||
viper.BindPFlag("timeout", rootCmd.PersistentFlags().Lookup("timeout"))
|
||||
viper.BindPFlag("serverAddress", rootCmd.PersistentFlags().Lookup("serverAddress"))
|
||||
|
@ -72,6 +77,22 @@ func init() {
|
|||
viper.BindPFlag("mfaTotpOffset", rootCmd.PersistentFlags().Lookup("mfaTotpOffset"))
|
||||
viper.BindPFlag("mfaRetrys", rootCmd.PersistentFlags().Lookup("mfaRetrys"))
|
||||
viper.BindPFlag("mfaDelay", rootCmd.PersistentFlags().Lookup("mfaDelay"))
|
||||
|
||||
viper.BindPFlag("tlsSkipVerify", rootCmd.PersistentFlags().Lookup("tlsSkipVerify"))
|
||||
viper.BindPFlag("tlsClientCert", rootCmd.PersistentFlags().Lookup("tlsClientCert"))
|
||||
viper.BindPFlag("tlsClientPrivateKey", rootCmd.PersistentFlags().Lookup("tlsClientPrivateKey"))
|
||||
}
|
||||
|
||||
func fileToContent(file, contentFlag string) {
|
||||
if viper.GetBool("debug") {
|
||||
fmt.Fprintln(os.Stderr, "Loading file:", file)
|
||||
}
|
||||
content, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "Error Loading File: ", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
viper.Set(contentFlag, string(content))
|
||||
}
|
||||
|
||||
// initConfig reads in config file and ENV variables if set.
|
||||
|
@ -107,18 +128,26 @@ func initConfig() {
|
|||
// Read in Private Key from File if userprivatekeyfile is set
|
||||
userprivatekeyfile, err := rootCmd.PersistentFlags().GetString("userPrivateKeyFile")
|
||||
if err == nil && userprivatekeyfile != "" {
|
||||
if viper.GetBool("debug") {
|
||||
fmt.Fprintln(os.Stderr, "Loading Private Key from File:", userprivatekeyfile)
|
||||
}
|
||||
content, err := ioutil.ReadFile(userprivatekeyfile)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "Error Loading Private Key from File: ", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
viper.Set("userprivatekey", string(content))
|
||||
fileToContent(userprivatekeyfile, "userPrivateKey")
|
||||
} else if err != nil && viper.GetBool("debug") {
|
||||
fmt.Fprintln(os.Stderr, "Getting Private Key File Flag:", err)
|
||||
}
|
||||
|
||||
// Read in Client Certificate Private Key from File if tlsClientPrivateKeyFile is set
|
||||
tlsclientprivatekeyfile, err := rootCmd.PersistentFlags().GetString("tlsClientPrivateKeyFile")
|
||||
if err == nil && tlsclientprivatekeyfile != "" {
|
||||
fileToContent(tlsclientprivatekeyfile, "tlsClientPrivateKey")
|
||||
} else if err != nil && viper.GetBool("debug") {
|
||||
fmt.Fprintln(os.Stderr, "Getting Client Certificate Private key File Flag:", err)
|
||||
}
|
||||
|
||||
// Read in Client Certificate from File if tlsClientCertFile is set
|
||||
tlsclientcertfile, err := rootCmd.PersistentFlags().GetString("tlsClientCertFile")
|
||||
if err == nil && tlsclientcertfile != "" {
|
||||
fileToContent(tlsclientcertfile, "tlsClientCert")
|
||||
} else if err != nil && viper.GetBool("debug") {
|
||||
fmt.Fprintln(os.Stderr, "Getting Client Certificate File Flag:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func SetVersionInfo(version, commit, date string, dirty bool) {
|
||||
|
|
|
@ -41,7 +41,11 @@ var verifyCMD = &cobra.Command{
|
|||
fmt.Println()
|
||||
}
|
||||
|
||||
client, err := api.NewClient(nil, "", serverAddress, userPrivateKey, userPassword)
|
||||
httpClient, err := util.GetHttpClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client, err := api.NewClient(httpClient, "", serverAddress, userPrivateKey, userPassword)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Creating Client: %w", err)
|
||||
}
|
||||
|
|
|
@ -65,7 +65,11 @@ func GetClient(ctx context.Context) (*api.Client, error) {
|
|||
fmt.Println()
|
||||
}
|
||||
|
||||
client, err := api.NewClient(nil, "", serverAddress, userPrivateKey, userPassword)
|
||||
httpClient, err := GetHttpClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err := api.NewClient(httpClient, "", serverAddress, userPrivateKey, userPassword)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Creating Client: %w", err)
|
||||
}
|
||||
|
|
44
util/http.go
Normal file
44
util/http.go
Normal file
|
@ -0,0 +1,44 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
func GetClientCertificate() (tls.Certificate, error) {
|
||||
cert := viper.GetString("tlsClientCert")
|
||||
certExists := cert != ""
|
||||
key := viper.GetString("tlsClientPrivateKey")
|
||||
keyExists := key != ""
|
||||
if !certExists && !keyExists {
|
||||
return tls.Certificate{}, nil
|
||||
}
|
||||
if certExists && !keyExists {
|
||||
return tls.Certificate{}, fmt.Errorf("Client TLS private key is empty, but client TLS cert was set.")
|
||||
}
|
||||
if !certExists && keyExists {
|
||||
return tls.Certificate{}, fmt.Errorf("Client TLS cert is empty, but client TLS private key was set.")
|
||||
}
|
||||
return tls.X509KeyPair([]byte(cert), []byte(key))
|
||||
}
|
||||
|
||||
func GetHttpClient() (*http.Client, error) {
|
||||
tlsSkipVerify := viper.GetBool("tlsSkipVerify")
|
||||
cert, err := GetClientCertificate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
httpClient := http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
InsecureSkipVerify: tlsSkipVerify,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return &httpClient, nil
|
||||
}
|
Loading…
Add table
Reference in a new issue