aboutsummaryrefslogtreecommitdiffstats
path: root/sym.go
blob: 5890850733623dd2cf4f0c97e1552495857259f3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// The sym command encrypts or decrypts files with a password.
//
// Sym has two subcommands, enc and dec, which perform encryption and
// decryption. The encryption key is derived from the user's password
// using argon2, and the data is then encrypted using ChaCha20-Poly1305
// in chunks of 1MiB.
//
// Run sym -h for detailed usage information.
//
// # Disclaimer
//
// PLEASE DO NOT USE THIS PROGRAM. It was written for me to learn about
// symmetric encryption, and likely contains critical
// security vulnerabilities.
package main

import (
	"context"
	"errors"
	"flag"
	"fmt"
	"io"
	"os"

	"github.com/google/subcommands"
)

var errUsage = errors.New("usage error")

type usageError struct {
	msg string
}

func usageErr(format string, args ...any) error {
	return &usageError{msg: fmt.Sprintf(format, args...)}
}

func (e *usageError) Error() string {
	return e.msg
}

func (e *usageError) Is(target error) bool { return target == errUsage }

func registerCommands(commander *subcommands.Commander, passwordIn func() (string, error), passwordOut io.Writer, stdin io.Reader, stdout io.Writer) {
	commander.Register(&encCmd{
		passwordIn:  passwordIn,
		passwordOut: passwordOut,
		stdin:       stdin,
		stdout:      stdout,
	}, "")
	commander.Register(&decCmd{
		passwordIn: passwordIn,
		stdin:      stdin,
		stdout:     stdout,
	}, "")
	commander.Register(commander.HelpCommand(), "")
	commander.Explain = func(w io.Writer) {
		fmt.Fprintf(w, `usage: sym <subcommand> [OPTION]... [FILE]...
Encrypt or decrypt files using a password.

Subcommands:
  enc    encrypt
  dec    decrypt

Try sym <subcommand> -h for command-specific help.
`)
	}
}

func main() {
	ctx := context.Background()
	registerCommands(subcommands.DefaultCommander, termReadPassword, os.Stderr, os.Stdin, os.Stdout)
	flag.Parse()
	os.Exit(int(subcommands.Execute(ctx)))
}