Skip to content
Draft
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
26 changes: 26 additions & 0 deletions cmd/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
package cmd

import (
"io"

"github.com/urfave/cli/v2"
)

Expand All @@ -25,6 +27,7 @@ var All = []*cli.Command{
Usage: "List profiles for subcommands",
UsageText: "gosop list-profiles SUBCOMMAND",
Flags: []cli.Flag{},
Before: BeforeListProfiles,
Action: func(c *cli.Context) error {
return ListProfiles(c.Args().Slice()...)
},
Expand All @@ -39,6 +42,7 @@ var All = []*cli.Command{
keyPasswordFlag,
signingOnlyFlag,
},
Before: BeforeGenerateKey,
Action: func(c *cli.Context) error {
return GenerateKey(c.Args().Slice()...)
},
Expand All @@ -63,6 +67,7 @@ var All = []*cli.Command{
asFlag,
keyPasswordFlag,
},
Before: BeforeSign,
Action: func(c *cli.Context) error {
return Sign(c.Args().Slice()...)
},
Expand All @@ -75,6 +80,7 @@ var All = []*cli.Command{
notBeforeFlag,
notAfterFlag,
},
Before: BeforeVerify,
Action: func(c *cli.Context) error {
return Verify(c.Args().Slice()...)
},
Expand All @@ -88,6 +94,7 @@ var All = []*cli.Command{
asSignedFlag,
keyPasswordFlag,
},
Before: BeforeInlineSign,
Action: func(c *cli.Context) error {
return InlineSign(c.Args().Slice()...)
},
Expand All @@ -101,6 +108,7 @@ var All = []*cli.Command{
notAfterFlag,
verificationsOutFlag,
},
Before: BeforeInlineVerify,
Action: func(c *cli.Context) error {
return InlineVerify(c.Args().Slice()...)
},
Expand Down Expand Up @@ -129,6 +137,7 @@ var All = []*cli.Command{
signWithFlag,
keyPasswordFlag,
},
Before: BeforeEncrypt,
Action: func(c *cli.Context) error {
return Encrypt(c.Args().Slice()...)
},
Expand All @@ -147,6 +156,7 @@ var All = []*cli.Command{
verifyNotAfterFlag,
keyPasswordFlag,
},
Before: BeforeDecrypt,
Action: func(c *cli.Context) error {
return Decrypt(c.Args().Slice()...)
},
Expand All @@ -167,4 +177,20 @@ var All = []*cli.Command{
return DearmorComm()
},
},
{
Name: "supports",
Usage: "Check whether gosop supports the given subcommand and options",
UsageText: "gosop supports COMMAND",
Action: func(c *cli.Context) error {
for _, c := range c.App.Commands {
c.Action = func(ctx *cli.Context) error {
return nil // Don't run the actual action.
}
}
c.App.Writer = io.Discard // Discard help text.
args := []string{"gosop"}
args = append(args, c.Args().Slice()...)
return c.App.Run(args)
},
},
}
23 changes: 18 additions & 5 deletions cmd/decrypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ package cmd
import (
"encoding/hex"
"errors"
"fmt"
"io"
"os"
"strconv"
"strings"

"github.com/urfave/cli/v2"

"github.com/ProtonMail/gosop/utils"

"github.com/ProtonMail/gopenpgp/v3/constants"
Expand All @@ -24,17 +27,27 @@ var symKeyAlgos = map[packet.CipherFunction]string{
packet.CipherAES256: constants.AES256,
}

func BeforeDecrypt(c *cli.Context) error {
if !c.Args().Present() && password == "" && sessionKey == "" {
fmt.Fprintln(os.Stderr, "Please provide decryption keys, passphrase, or session key.")
return Err19
}
if c.Args().Present() && password != "" ||
c.Args().Present() && sessionKey != "" ||
password != "" && sessionKey != "" {
fmt.Fprintln(os.Stderr, "Can't decrypt with more than one of keys, passphrase and session key.")
return Err37
}
return nil
}

// Decrypt takes the data from stdin and decrypts it with the key file passed as
// argument, or a passphrase in a file passed with the --with-password flag.
// Note: Can't encrypt both symmetrically (passphrase) and keys.
// Note: Can't decrypt with more than one of keys, passphrase and session key.
// TODO: Multiple signers?
//
// --session-key-out=file flag: Outputs session key byte stream to given file.
func Decrypt(keyFilenames ...string) error {
if len(keyFilenames) == 0 && password == "" && sessionKey == "" {
println("Please provide decryption keys, session key, or passphrase")
return Err69
}
var err error

pgp := crypto.PGP()
Expand Down
23 changes: 18 additions & 5 deletions cmd/encrypt.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package cmd

import (
"io"
"bufio"
"fmt"
"io"
"os"
"unicode"

Expand All @@ -17,15 +18,27 @@ const (
textOpt = "text"
)

func BeforeEncrypt(c *cli.Context) error {
if !c.Args().Present() && password == "" {
fmt.Fprintln(os.Stderr, "Please provide encryption keys or passphrase (--with-password).")
return Err19
}
if c.Args().Present() && password != "" {
fmt.Fprintln(os.Stderr, "Can't encrypt with both keys and passphrase.")
return Err37
}
profile := utils.SelectEncryptionProfile(selectedProfile)
if profile == nil {
return Err89
}
return nil
}

// Encrypt takes the data from stdin and encrypts it with the keys passed as
// argument, or a passphrase passed with the --with-password flag. It signs
// with the given private keys.
// Note: Can't encrypt both symmetrically (passphrase) and keys.
func Encrypt(keyFilenames ...string) error {
if len(keyFilenames) == 0 && password == "" {
println("Please provide recipients and/or passphrase (--with-password)")
return Err19
}
profile := utils.SelectEncryptionProfile(selectedProfile)
if profile == nil {
return Err89
Expand Down
25 changes: 25 additions & 0 deletions cmd/generate_key.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,41 @@
package cmd

import (
"fmt"
"os"
"strings"

"github.com/urfave/cli/v2"

"github.com/ProtonMail/gosop/utils"

"github.com/ProtonMail/gopenpgp/v3/crypto"

"github.com/ProtonMail/go-crypto/openpgp/v2"
)

func BeforeGenerateKey(c *cli.Context) error {
profile := utils.SelectKeyGenerationProfile(selectedProfile)
if profile == nil {
return Err89
}
if !profile.PgpProfile.V6 && !c.Args().Present() {
fmt.Fprintln(os.Stderr, "Non-v6 key requires a User ID.")
return Err19
}
for _, userID := range c.Args().Slice() {
_, comment, _, err := utils.ParseUserID(userID)
if err != nil {
return kgErr(err)
}
if comment != "" {
fmt.Fprintln(os.Stderr, "Comments in User IDs are not supported.")
return Err37
}
}
return nil
}

// GenerateKey creates a single default OpenPGP certificate with zero or more
// User IDs. Given that go-crypto expects name, comment, email parameters, we
// force the USERID of this implementation to be of the form "name (comment)
Expand Down
23 changes: 14 additions & 9 deletions cmd/inline_sign.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package cmd

import (
"fmt"
"io/ioutil"
"os"
"unicode/utf8"

"github.com/urfave/cli/v2"

"github.com/ProtonMail/gosop/utils"

"github.com/ProtonMail/gopenpgp/v3/crypto"
Expand All @@ -14,14 +17,20 @@ const (
clearsignedOpt = "clearsigned"
)

// InlineSign takes the data from stdin and signs it with the key passed as argument.
// TODO: Exactly one signature should be made by each supplied "KEY".
func InlineSign(keyFilenames ...string) error {
if len(keyFilenames) == 0 {
println("Please provide keys to create detached signature")
func BeforeInlineSign(c *cli.Context) error {
if !c.Args().Present() {
fmt.Fprintln(os.Stderr, "Please provide keys to create detached signature")
return Err19
}
if noArmor && asType == clearsignedOpt {
return Err83
}
return nil
}

// InlineSign takes the data from stdin and signs it with the key passed as argument.
// TODO: Exactly one signature should be made by each supplied "KEY".
func InlineSign(keyFilenames ...string) error {
// Signer keyring
var keyRing *crypto.KeyRing
var err error
Expand Down Expand Up @@ -56,10 +65,6 @@ func InlineSign(keyFilenames ...string) error {
return Err53
}

if noArmor && asType == clearsignedOpt {
return Err83
}

encoding := crypto.Armor
if noArmor {
encoding = crypto.Bytes
Expand Down
14 changes: 10 additions & 4 deletions cmd/inline_verify.go
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
package cmd

import (
"fmt"
"io/ioutil"
"os"
"strings"

"github.com/urfave/cli/v2"

"github.com/ProtonMail/gosop/utils"

"github.com/ProtonMail/gopenpgp/v3/crypto"
)

// InlineVerify checks the validity of a signed message against a set of certificates.
func InlineVerify(input ...string) error {
if len(input) == 0 {
println("Please provide a certificate (public key)")
func BeforeInlineVerify(c *cli.Context) error {
if !c.Args().Present() {
fmt.Fprintln(os.Stderr, "Please provide a certificate (public key)")
return Err19
}
return nil
}

// InlineVerify checks the validity of a signed message against a set of certificates.
func InlineVerify(input ...string) error {
timeFrom, timeTo, err := utils.ParseDates(notBefore, notAfter)
if err != nil {
return inlineVerErr(err)
Expand Down
15 changes: 13 additions & 2 deletions cmd/list_profiles.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,27 @@ import (
"fmt"
"strings"

"github.com/urfave/cli/v2"

"github.com/ProtonMail/gosop/utils"
)

const encryptCommand = "encrypt"
const keyGenCommand = "generate-key"

func ListProfiles(commands ...string) error {
if len(commands) < 1 {
func BeforeListProfiles(c *cli.Context) error {
if !c.Args().Present() {
return Err89
}
switch c.Args().First() {
case keyGenCommand, encryptCommand:
return nil
default:
return Err89
}
}

func ListProfiles(commands ...string) error {
command := commands[0]
switch command {
case keyGenCommand:
Expand Down
15 changes: 11 additions & 4 deletions cmd/sign.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
package cmd

import (
"fmt"
"io"
"os"

"github.com/urfave/cli/v2"

"github.com/ProtonMail/gosop/utils"

"github.com/ProtonMail/gopenpgp/v3/crypto"
)

func BeforeSign(c *cli.Context) error {
if !c.Args().Present() {
fmt.Fprintln(os.Stderr, "Please provide keys to create detached signature")
return Err19
}
return nil
}

// Sign takes the data from stdin and signs it with the key passed as argument.
// TODO: Exactly one signature will be made by each supplied "KEY".
func Sign(keyFilenames ...string) error {
if len(keyFilenames) == 0 {
println("Please provide keys to create detached signature")
return Err19
}
pgp := crypto.PGP()

// Signer keyring
Expand Down
Loading