Skip to content

Commit

Permalink
Merge pull request #7 from cmars/feat/service-mgmt
Browse files Browse the repository at this point in the history
feat: service key management commands
  • Loading branch information
cmars committed Feb 6, 2022
2 parents 0e3e556 + b94e7d2 commit 2226eb0
Show file tree
Hide file tree
Showing 5 changed files with 309 additions and 103 deletions.
129 changes: 26 additions & 103 deletions app/app.go
Original file line number Diff line number Diff line change
@@ -1,22 +1,15 @@
package app

import (
"context"
"fmt"
"log"
"os"
"os/signal"
"path/filepath"
"strings"
"time"

"github.com/mitchellh/go-homedir"
"github.com/urfave/cli/v2"

"github.com/cmars/oniongrok/config"
"github.com/cmars/oniongrok/forwarding"
"github.com/cmars/oniongrok/secrets"
"github.com/cmars/oniongrok/tor"
)

var forwardFlags = []cli.Flag{
Expand Down Expand Up @@ -44,6 +37,7 @@ func defaultSecretsPath() string {
return filepath.Join(home, ".local", "share", "oniongrok", "secrets.json")
}

// App returns a new oniongrok command line app.
func App() *cli.App {
return &cli.App{
Name: "oniongrok",
Expand All @@ -56,6 +50,26 @@ func App() *cli.App {
Usage: "forward socket address through Tor network",
Flags: forwardFlags,
Action: Forward,
}, {
Name: "service",
Usage: "manage onion services",
Subcommands: []*cli.Command{{
Name: "list",
Aliases: []string{"ls"},
Usage: "list onion service keys",
Action: ListServiceKeys,
}, {
Name: "new",
Aliases: []string{"add", "create"},
Usage: "new onion service",
Action: NewServiceKey,
}, {
Name: "remove",
Aliases: []string{"rm", "delete", "del"},
Usage: "remove onion service",
Action: RemoveServiceKey,
}},
Action: ListServiceKeys,
}},
}
}
Expand All @@ -69,101 +83,10 @@ func secretsPath(path string, anonymous bool) string {
return path
}

var startTor = func(ctx context.Context, options ...tor.Option) (*tor.Tor, error) {
return tor.Start(ctx, options...)
}

var newForwardingService = func(t *tor.Tor, fwds ...*config.Forward) forwardingService {
return forwarding.New(t, fwds...)
}

type forwardingService interface {
Done() <-chan struct{}
Start(ctx context.Context, options ...forwarding.Option) (map[string]string, error)
}

func Forward(ctx *cli.Context) (cmdErr error) {
var fwds []*config.Forward
var sec *secrets.Secrets
for i := 0; i < ctx.Args().Len(); i++ {
fwd, err := config.ParseForward(ctx.Args().Get(i))
if err != nil {
return err
}
if fwd.Destination().Alias() != "" {
if sec == nil {
secPath := ctx.Path("secrets")
if secPath == "" {
secPath = defaultSecretsPath()
}
sec, err = secrets.ReadFile(secretsPath(secPath, ctx.Bool("anonymous")))
if err != nil {
return err
}
}
privkey, err := sec.EnsureServiceKey(fwd.Destination().Alias())
if err != nil {
return err
}
fwd.Destination().SetServiceKey(privkey)
}
fwds = append(fwds, fwd)
}
// If we added any service keys, persist them now.
if sec != nil {
if err := sec.WriteFile(); err != nil {
return err
}
}

fwdCtx, cancel := signal.NotifyContext(ctx.Context, os.Interrupt)
defer cancel()

var torOptions []tor.Option
var fwdOptions []forwarding.Option
if ctx.Bool("debug") {
torOptions = append(torOptions, tor.Debug(os.Stderr))
}
if !ctx.Bool("anonymous") {
torOptions = append(torOptions, tor.NonAnonymous)
fwdOptions = append(fwdOptions, forwarding.NonAnonymous)
}

var stopped bool
log.Println("starting tor...")
t, err := startTor(nil, torOptions...)
if err != nil {
return fmt.Errorf("failed to start tor: %v", err)
}
svc := newForwardingService(t, fwds...)
defer func() {
<-svc.Done()
if !stopped {
if err := t.Close(); err != nil {
log.Println(err)
}
}
}()

onionIDs, err := svc.Start(fwdCtx, fwdOptions...)
if err != nil {
return err
}

for _, fwd := range fwds {
fmt.Println(fwd.Description(onionIDs))
}

fmt.Println()
fmt.Println("press Ctrl-C to exit")
select {
case <-svc.Done():
log.Println("shutting down tor...")
if err := t.Close(); err != nil {
log.Println(err)
}
stopped = true
func openSecrets(ctx *cli.Context) (*secrets.Secrets, error) {
secPath := ctx.Path("secrets")
if secPath == "" {
secPath = defaultSecretsPath()
}
log.Println("shutdown complete")
return nil
return secrets.ReadFile(secretsPath(secPath, ctx.Bool("anonymous")))
}
112 changes: 112 additions & 0 deletions app/forward.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package app

import (
"context"
"fmt"
"log"
"os"
"os/signal"

"github.com/urfave/cli/v2"

"github.com/cmars/oniongrok/config"
"github.com/cmars/oniongrok/forwarding"
"github.com/cmars/oniongrok/secrets"
"github.com/cmars/oniongrok/tor"
)

var startTor = func(ctx context.Context, options ...tor.Option) (*tor.Tor, error) {
return tor.Start(ctx, options...)
}

var newForwardingService = func(t *tor.Tor, fwds ...*config.Forward) forwardingService {
return forwarding.New(t, fwds...)
}

type forwardingService interface {
Done() <-chan struct{}
Start(ctx context.Context, options ...forwarding.Option) (map[string]string, error)
}

// Forward sets up and operates oniongrok forwards.
func Forward(ctx *cli.Context) (cmdErr error) {
var fwds []*config.Forward
var sec *secrets.Secrets
for i := 0; i < ctx.Args().Len(); i++ {
fwd, err := config.ParseForward(ctx.Args().Get(i))
if err != nil {
return err
}
if fwd.Destination().Alias() != "" {
if sec == nil {
sec, err = openSecrets(ctx)
if err != nil {
return err
}
}
privkey, err := sec.EnsureServiceKey(fwd.Destination().Alias())
if err != nil {
return err
}
fwd.Destination().SetServiceKey(privkey)
}
fwds = append(fwds, fwd)
}
// If we added any service keys, persist them now.
if sec != nil {
if err := sec.WriteFile(); err != nil {
return err
}
}

fwdCtx, cancel := signal.NotifyContext(ctx.Context, os.Interrupt)
defer cancel()

var torOptions []tor.Option
var fwdOptions []forwarding.Option
if ctx.Bool("debug") {
torOptions = append(torOptions, tor.Debug(os.Stderr))
}
if !ctx.Bool("anonymous") {
torOptions = append(torOptions, tor.NonAnonymous)
fwdOptions = append(fwdOptions, forwarding.NonAnonymous)
}

var stopped bool
log.Println("starting tor...")
t, err := startTor(nil, torOptions...)
if err != nil {
return fmt.Errorf("failed to start tor: %v", err)
}
svc := newForwardingService(t, fwds...)
defer func() {
<-svc.Done()
if !stopped {
if err := t.Close(); err != nil {
log.Println(err)
}
}
}()

onionIDs, err := svc.Start(fwdCtx, fwdOptions...)
if err != nil {
return err
}

for _, fwd := range fwds {
fmt.Println(fwd.Description(onionIDs))
}

fmt.Println()
fmt.Println("press Ctrl-C to exit")
select {
case <-svc.Done():
log.Println("shutting down tor...")
if err := t.Close(); err != nil {
log.Println(err)
}
stopped = true
}
log.Println("shutdown complete")
return nil
}
69 changes: 69 additions & 0 deletions app/service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package app

import (
"encoding/json"
"fmt"
"os"

"github.com/cmars/oniongrok/secrets"
"github.com/urfave/cli/v2"
)

// ListServiceKeys implements the `service ls` command.
func ListServiceKeys(ctx *cli.Context) error {
sec, err := openSecrets(ctx)
if err != nil {
return err
}
services := sec.ServicesPublic()
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
return enc.Encode(&services)
}

// NewServiceKey implements the `service new` command.
func NewServiceKey(ctx *cli.Context) error {
name := ctx.Args().Get(0)
if name == "" {
return fmt.Errorf("missing service name")
}
sec, err := openSecrets(ctx)
if err != nil {
return err
}
services := sec.ServicesPublic()
if _, ok := services[name]; ok {
return fmt.Errorf("service %q already exists", name)
}
_, err = sec.EnsureServiceKey(name)
if err != nil {
return err
}
err = sec.WriteFile()
if err != nil {
return err
}
services = sec.ServicesPublic()
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
return enc.Encode(map[string]secrets.ServicePublic{
name: services[name],
})
}

// RemoveServiceKey implements the `service rm` command.
func RemoveServiceKey(ctx *cli.Context) error {
name := ctx.Args().Get(0)
if name == "" {
return fmt.Errorf("missing service name")
}
sec, err := openSecrets(ctx)
if err != nil {
return err
}
err = sec.RemoveServiceKey(name)
if err != nil {
return err
}
return sec.WriteFile()
}
Loading

0 comments on commit 2226eb0

Please sign in to comment.