mirror of
https://github.com/cloudflare/redoctober.git
synced 2026-01-05 21:15:21 +00:00
246 lines
5.9 KiB
Go
246 lines
5.9 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"flag"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"log"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/cloudflare/redoctober/client"
|
|
"github.com/cloudflare/redoctober/cmd/ro/gopass"
|
|
"github.com/cloudflare/redoctober/core"
|
|
)
|
|
|
|
var action, user, pswd, userEnv, pswdEnv, server, caPath string
|
|
|
|
var owners, lefters, righters, inPath, labels, outPath, outEnv string
|
|
|
|
var uses int
|
|
|
|
var time, users string
|
|
|
|
type command struct {
|
|
Run func()
|
|
Desc string
|
|
}
|
|
|
|
var roServer *client.RemoteServer
|
|
|
|
var commandSet = map[string]command{
|
|
"create": command{Run: runCreate, Desc: "create a user account"},
|
|
"summary": command{Run: runSummary, Desc: "list the user and delegation summary"},
|
|
"delegate": command{Run: runDelegate, Desc: "do decryption delegation"},
|
|
"encrypt": command{Run: runEncrypt, Desc: "encrypt a file"},
|
|
"decrypt": command{Run: runDecrypt, Desc: "decrypt a file"},
|
|
"re-encrypt": command{Run: runReEncrypt, Desc: "re-encrypt a file"},
|
|
}
|
|
|
|
func registerFlags() {
|
|
flag.StringVar(&server, "server", "localhost:8080", "server address")
|
|
flag.StringVar(&caPath, "ca", "", "ca file path")
|
|
flag.StringVar(&owners, "owners", "", "comma separated owner list")
|
|
flag.StringVar(&users, "users", "", "comma separated user list")
|
|
flag.IntVar(&uses, "uses", 0, "number of delegated key uses")
|
|
flag.StringVar(&time, "time", "0h", "duration of delegated key uses")
|
|
flag.StringVar(&lefters, "left", "", "comma separated left owners")
|
|
flag.StringVar(&righters, "right", "", "comma separated right owners")
|
|
flag.StringVar(&labels, "labels", "", "comma separated labels")
|
|
flag.StringVar(&inPath, "in", "", "input data file")
|
|
flag.StringVar(&outPath, "out", "", "output data file")
|
|
flag.StringVar(&outEnv, "outenv", "", "env variable for output data")
|
|
flag.StringVar(&user, "user", "", "username")
|
|
flag.StringVar(&pswd, "password", "", "password")
|
|
flag.StringVar(&userEnv, "userenv", "RO_USER", "env variable for user name")
|
|
flag.StringVar(&pswdEnv, "pswdenv", "RO_PASS", "env variable for user password")
|
|
}
|
|
|
|
func getUserCredentials() {
|
|
user = os.Getenv(userEnv)
|
|
pswd = os.Getenv(pswdEnv)
|
|
if user == "" || pswd == "" {
|
|
fmt.Print("Username:")
|
|
fmt.Scan(&user)
|
|
var err error
|
|
pswd, err = gopass.GetPass("Password:")
|
|
processError(err)
|
|
}
|
|
}
|
|
|
|
func processError(err error) {
|
|
if err != nil {
|
|
log.Fatal("error:", err)
|
|
}
|
|
}
|
|
|
|
func processCSL(s string) []string {
|
|
if s == "" {
|
|
return nil
|
|
}
|
|
|
|
return strings.Split(s, ",")
|
|
}
|
|
|
|
func runCreate() {
|
|
req := core.CreateRequest{
|
|
Name: user,
|
|
Password: pswd,
|
|
}
|
|
resp, err := roServer.Create(req)
|
|
processError(err)
|
|
fmt.Println(resp.Status)
|
|
}
|
|
|
|
func runDelegate() {
|
|
req := core.DelegateRequest{
|
|
Name: user,
|
|
Password: pswd,
|
|
Uses: uses,
|
|
Time: time,
|
|
Users: processCSL(users),
|
|
Labels: processCSL(labels),
|
|
}
|
|
resp, err := roServer.Delegate(req)
|
|
processError(err)
|
|
fmt.Println(resp.Status)
|
|
}
|
|
|
|
// TODO: summary response needs better formatting
|
|
func runSummary() {
|
|
req := core.SummaryRequest{
|
|
Name: user,
|
|
Password: pswd,
|
|
}
|
|
resp, err := roServer.Summary(req)
|
|
processError(err)
|
|
fmt.Println(resp)
|
|
}
|
|
|
|
func runEncrypt() {
|
|
inBytes, err := ioutil.ReadFile(inPath)
|
|
processError(err)
|
|
req := core.EncryptRequest{
|
|
Name: user,
|
|
Password: pswd,
|
|
Owners: processCSL(owners),
|
|
LeftOwners: processCSL(lefters),
|
|
RightOwners: processCSL(righters),
|
|
Labels: processCSL(labels),
|
|
Data: inBytes,
|
|
}
|
|
|
|
resp, err := roServer.Encrypt(req)
|
|
processError(err)
|
|
if resp.Status != "ok" {
|
|
log.Fatal("response status error:", resp.Status)
|
|
return
|
|
}
|
|
fmt.Println("Response Status:", resp.Status)
|
|
outBytes := []byte(base64.StdEncoding.EncodeToString(resp.Response))
|
|
ioutil.WriteFile(outPath, outBytes, 0644)
|
|
}
|
|
|
|
func runReEncrypt() {
|
|
inBytes, err := ioutil.ReadFile(inPath)
|
|
processError(err)
|
|
|
|
// base64 decode the input
|
|
encBytes, err := base64.StdEncoding.DecodeString(string(inBytes))
|
|
if err != nil {
|
|
log.Println("fail to base64 decode the data, proceed with raw data")
|
|
encBytes = inBytes
|
|
}
|
|
|
|
req := core.ReEncryptRequest{
|
|
Name: user,
|
|
Password: pswd,
|
|
Owners: processCSL(owners),
|
|
LeftOwners: processCSL(lefters),
|
|
RightOwners: processCSL(righters),
|
|
Labels: processCSL(labels),
|
|
Data: encBytes,
|
|
}
|
|
|
|
resp, err := roServer.ReEncrypt(req)
|
|
processError(err)
|
|
if resp.Status != "ok" {
|
|
log.Fatal("response status error:", resp.Status)
|
|
return
|
|
}
|
|
fmt.Println("Response Status:", resp.Status)
|
|
outBytes := []byte(base64.StdEncoding.EncodeToString(resp.Response))
|
|
ioutil.WriteFile(outPath, outBytes, 0644)
|
|
}
|
|
|
|
func runDecrypt() {
|
|
inBytes, err := ioutil.ReadFile(inPath)
|
|
processError(err)
|
|
|
|
// base64 decode the input
|
|
encBytes, err := base64.StdEncoding.DecodeString(string(inBytes))
|
|
if err != nil {
|
|
log.Println("fail to base64 decode the data, proceed with raw data")
|
|
encBytes = inBytes
|
|
}
|
|
|
|
req := core.DecryptRequest{
|
|
Name: user,
|
|
Password: pswd,
|
|
Data: encBytes,
|
|
}
|
|
|
|
resp, err := roServer.Decrypt(req)
|
|
processError(err)
|
|
if resp.Status != "ok" {
|
|
log.Fatal("response status error:", resp.Status)
|
|
return
|
|
}
|
|
fmt.Println("Response Status:", resp.Status)
|
|
var msg core.DecryptWithDelegates
|
|
err = json.Unmarshal(resp.Response, &msg)
|
|
processError(err)
|
|
fmt.Println("Secure:", msg.Secure)
|
|
fmt.Println("Delegates:", msg.Delegates)
|
|
ioutil.WriteFile(outPath, msg.Data, 0644)
|
|
}
|
|
|
|
func main() {
|
|
flag.Usage = func() {
|
|
fmt.Println("Usage: ro [options] subcommand")
|
|
fmt.Println("Currently supported subcommands are:")
|
|
for key := range commandSet {
|
|
fmt.Println("\t", key, ":", commandSet[key].Desc)
|
|
}
|
|
|
|
fmt.Println("Options:")
|
|
flag.PrintDefaults()
|
|
}
|
|
|
|
registerFlags()
|
|
flag.Parse()
|
|
|
|
if flag.NArg() != 1 {
|
|
flag.Usage()
|
|
os.Exit(1)
|
|
}
|
|
|
|
action := flag.Arg(0)
|
|
|
|
cmd, found := commandSet[action]
|
|
if !found {
|
|
fmt.Println("Unsupported subcommand:", action)
|
|
flag.Usage()
|
|
os.Exit(1)
|
|
} else {
|
|
var err error
|
|
roServer, err = client.NewRemoteServer(server, caPath)
|
|
processError(err)
|
|
|
|
getUserCredentials()
|
|
cmd.Run()
|
|
}
|
|
}
|