Remove all schollz/* dependencies: fork pake, replicate logger and CLI

- src/pake: trimmed fork of schollz/pake/v3, P256-only (stdlib
  crypto/elliptic), dropping the tscholl2/siec and filippo.io/edwards25519
  transitive deps along with it.
- src/logger: minimal in-repo replacement for schollz/logger with the
  same leveled-logging call surface.
- src/cli: replaced schollz/cli (urfave/cli fork) with a small
  flag-package-based parser for the send/relay/receive commands actually
  in use; subcommand keyword can appear before or after its flags.
- Dropped schollz/progressbar entirely (its show-progress code paths were
  already unreachable dead code since no CLI flag wired them up).

go.mod/go.sum no longer reference any schollz/* module.
This commit is contained in:
2026-07-20 11:26:59 +08:00
parent 3a0ab392c0
commit 34ce1f4e65
14 changed files with 451 additions and 263 deletions
-12
View File
@@ -7,23 +7,11 @@ require (
github.com/kalafut/imohash v1.1.1
github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b
github.com/minio/highwayhash v1.0.4
github.com/schollz/cli/v2 v2.2.1
github.com/schollz/logger v1.2.0
github.com/schollz/pake/v3 v3.1.1
github.com/schollz/progressbar/v3 v3.19.1
golang.org/x/crypto v0.53.0
golang.org/x/net v0.56.0
)
require (
filippo.io/edwards25519 v1.2.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/stretchr/testify v1.11.1 // indirect
github.com/tscholl2/siec v0.0.0-20240310163802-c2c6f6198406 // indirect
github.com/twmb/murmur3 v1.1.8 // indirect
golang.org/x/sys v0.46.0 // indirect
golang.org/x/term v0.44.0 // indirect
)
-40
View File
@@ -1,45 +1,11 @@
filippo.io/edwards25519 v1.2.0 h1:crnVqOiS4jqYleHd9vaKZ+HKtHfllngJIiOpNpoJsjo=
filippo.io/edwards25519 v1.2.0/go.mod h1:xzAOLCNug/yB62zG1bQ8uziwrIqIuxhctzJT18Q77mc=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chengxilo/virtualterm v1.0.4 h1:Z6IpERbRVlfB8WkOmtbHiDbBANU7cimRIof7mk9/PwM=
github.com/chengxilo/virtualterm v1.0.4/go.mod h1:DyxxBZz/x1iqJjFxTFcr6/x+jSpqN0iwWCOK1q10rlY=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo=
github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/kalafut/imohash v1.1.1 h1:G/HYtKgteQSVU96LidSJEbUGoZOMiBcuXYxbeb2W9e4=
github.com/kalafut/imohash v1.1.1/go.mod h1:6cn9lU0Sj8M4eu9UaQm1kR/5y3k/ayB68yntRhGloL4=
github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b h1:xZ59n7Frzh8CwyfAapUZLSg+gXH5m63YEaFCMpDHhpI=
github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b/go.mod h1:uDd4sYVYsqcxAB8j+Q7uhL6IJCs/r1kxib1HV4bgOMg=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/minio/highwayhash v1.0.4 h1:asJizugGgchQod2ja9NJlGOWq4s7KsAWr5XUc9Clgl4=
github.com/minio/highwayhash v1.0.4/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/schollz/cli/v2 v2.2.1 h1:ou22Mj7ZPjrKz+8k2iDTWaHskEEV5NiAxGrdsCL36VU=
github.com/schollz/cli/v2 v2.2.1/go.mod h1:My6bfphRLZUhZdlFUK8scAxMWHydE7k4s2ed2Dtnn+s=
github.com/schollz/logger v1.2.0 h1:5WXfINRs3lEUTCZ7YXhj0uN+qukjizvITLm3Ca2m0Ho=
github.com/schollz/logger v1.2.0/go.mod h1:P6F4/dGMGcx8wh+kG1zrNEd4vnNpEBY/mwEMd/vn6AM=
github.com/schollz/pake/v3 v3.1.1 h1:lyoU5uNQ3thfjEzrahgxWWBm6+pbI1F2KAZ3gs6LIV8=
github.com/schollz/pake/v3 v3.1.1/go.mod h1:420+m3AakXcS0n7Uwc7eRs2CosQ2YfE/vKcIkilvqZc=
github.com/schollz/progressbar/v3 v3.19.1 h1:iv8BgwOvdML/S3p84uBpy/IMigv4U9594vPZYa2EdrU=
github.com/schollz/progressbar/v3 v3.19.1/go.mod h1:LFL7jqimKxfhero4K1eCkUr/6R39AgQeiPCJtlTWIW8=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/tscholl2/siec v0.0.0-20240310163802-c2c6f6198406 h1:sDWDZkwYqX0jvLWstKzFwh+pYhQNaVg65BgSkCP/f7U=
github.com/tscholl2/siec v0.0.0-20240310163802-c2c6f6198406/go.mod h1:KL9+ubr1JZdaKjgAaHr+tCytEncXBa1pR6FjbTsOJnw=
github.com/twmb/murmur3 v1.1.5/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ=
github.com/twmb/murmur3 v1.1.8 h1:8Yt9taO/WN3l08xErzjeschgZU2QSrwm1kclYq+0aRg=
github.com/twmb/murmur3 v1.1.8/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ=
@@ -50,9 +16,3 @@ golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc=
golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
BIN
View File
Binary file not shown.
+133 -106
View File
@@ -1,33 +1,24 @@
package cli
import (
"flag"
"fmt"
"os"
"runtime"
"time"
"strconv"
"github.com/schollz/cli/v2"
log "github.com/tzgyn/share/src/logger"
"github.com/tzgyn/share/src/models"
"github.com/tzgyn/share/src/swarm"
"github.com/tzgyn/share/src/tcp"
"github.com/tzgyn/share/src/utils"
log "github.com/schollz/logger"
)
var Version string
func Run() (err error) {
runtime.GOMAXPROCS(runtime.NumCPU())
const usage = `share [GLOBAL OPTIONS] [COMMAND] [COMMAND OPTIONS] [filename(s)]
app := cli.NewApp()
app.Name = "share"
if Version == "" {
Version = "v0.1.0"
}
app.Version = Version
app.Compiled = time.Now()
app.Usage = "a torrent-like swarm: everyone who joins a room can send and receive"
app.UsageText = `share [GLOBAL OPTIONS] [COMMAND] [COMMAND OPTIONS] [filename(s)]
a torrent-like swarm: everyone who joins a room can send and receive
USAGE EXAMPLES:
Seed a file into a new room (prints a code):
@@ -37,129 +28,165 @@ func Run() (err error) {
share send --code secret-code file1.txt file2.txt
Join a room to receive whatever's shared there (and help re-share it):
share secret-code`
app.Commands = []*cli.Command{
{
Name: "send",
Usage: "seed file(s) into a room (see options with share send -h)",
Description: "seed file(s) into a swarm room so others can join and receive them",
ArgsUsage: "[filename(s)]",
Flags: []cli.Flag{
&cli.StringFlag{Name: "code", Aliases: []string{"c"}, Usage: "room codephrase (generated if not given)"},
},
HelpName: "share send",
Action: send,
},
{
Name: "relay",
Usage: "start your own relay (optional)",
Description: "start relay",
HelpName: "share relay",
Action: relay,
Flags: []cli.Flag{
&cli.StringFlag{Name: "host", Usage: "host of the relay"},
&cli.IntFlag{Name: "port", Value: 9009, Usage: "port of the relay", EnvVars: []string{"SHARE_PORT"}},
},
},
}
app.Flags = []cli.Flag{
&cli.BoolFlag{Name: "internal-dns", Usage: "use a built-in DNS stub resolver rather than the host operating system"},
&cli.BoolFlag{Name: "classic", Usage: "toggle between the classic mode (insecure due to local attack vector) and new mode (secure)"},
&cli.BoolFlag{Name: "remember", Usage: "save these settings to reuse next time"},
&cli.BoolFlag{Name: "debug", Usage: "toggle debug mode"},
&cli.BoolFlag{Name: "yes", Usage: "automatically agree to all prompts"},
&cli.BoolFlag{Name: "stdout", Usage: "redirect file to stdout"},
&cli.BoolFlag{Name: "no-compress", Usage: "disable compression"},
&cli.BoolFlag{Name: "ask", Usage: "make sure sender and recipient are prompted"},
&cli.BoolFlag{Name: "local", Usage: "force to use only local connections"},
&cli.BoolFlag{Name: "ignore-stdin", Usage: "ignore piped stdin"},
&cli.BoolFlag{Name: "overwrite", Usage: "do not prompt to overwrite or resume"},
&cli.BoolFlag{Name: "testing", Usage: "flag for testing purposes"},
&cli.BoolFlag{Name: "quiet", Usage: "disable all output"},
&cli.BoolFlag{Name: "disable-clipboard", Usage: "disable copy to clipboard"},
&cli.BoolFlag{Name: "extended-clipboard", Usage: "copy full command with secret as env variable to clipboard"},
&cli.StringFlag{Name: "multicast", Value: "239.255.255.250", Usage: "multicast address to use for local discovery"},
&cli.StringFlag{Name: "curve", Value: "p256", Usage: "choose an encryption curve"},
&cli.StringFlag{Name: "ip", Value: "", Usage: "set sender ip if known e.g. 10.0.0.1:9009, [::1]:9009"},
&cli.StringFlag{Name: "relay", Value: models.DEFAULT_RELAY, Usage: "address of the relay", EnvVars: []string{"SHARE_RELAY"}},
&cli.StringFlag{Name: "relay6", Value: models.DEFAULT_RELAY6, Usage: "ipv6 address of the relay", EnvVars: []string{"SHARE_RELAY6"}},
&cli.StringFlag{Name: "out", Value: ".", Usage: "specify an output folder to receive the file"},
&cli.BoolFlag{Name: "one-time", Usage: "exit once everything currently in the room is downloaded, instead of staying to help reseed it"},
&cli.StringFlag{Name: "socks5", Value: "", Usage: "add a socks5 proxy", EnvVars: []string{"SOCKS5_PROXY"}},
&cli.StringFlag{Name: "connect", Value: "", Usage: "add a http proxy", EnvVars: []string{"HTTP_PROXY"}},
&cli.StringFlag{Name: "throttleUpload", Value: "", Usage: "throttle the upload speed e.g. 500k"},
}
app.EnableBashCompletion = true
app.HideHelp = false
app.HideVersion = false
app.Action = func(c *cli.Context) error {
return receive(c)
share secret-code
COMMANDS:
send seed file(s) into a room (see options with: share send -h)
relay start your own relay (optional; see options with: share relay -h)
Run "share [command] -h" for the options of a given command.
`
// Run parses os.Args and dispatches to the send, relay, or default
// (receive) command. The subcommand keyword ("send"/"relay") is found
// wherever it appears, not just as the very first argument, so flags can
// come before or after it (e.g. both "share --relay X send file" and
// "share send --code X file" work).
func Run() error {
runtime.GOMAXPROCS(runtime.NumCPU())
if Version == "" {
Version = "v0.1.0"
}
return app.Run(os.Args)
args := os.Args[1:]
if len(args) > 0 {
switch args[0] {
case "-h", "--help", "help":
fmt.Print(usage)
return nil
case "-v", "--version":
fmt.Println(Version)
return nil
}
}
func setDebugLevel(c *cli.Context) {
if c.Bool("quiet") {
for i, a := range args {
switch a {
case "send":
return runSend(splice(args, i))
case "relay":
return runRelay(splice(args, i))
}
}
return runReceive(args)
}
// splice removes the subcommand keyword at index i, leaving flags that
// appeared before and after it in one list for that subcommand's own
// flag.FlagSet to parse.
func splice(args []string, i int) []string {
out := make([]string, 0, len(args)-1)
out = append(out, args[:i]...)
out = append(out, args[i+1:]...)
return out
}
func setDebugLevel(quiet, debug bool) {
switch {
case quiet:
log.SetLevel("error")
} else if c.Bool("debug") {
case debug:
log.SetLevel("debug")
log.Debug("debug mode on")
} else {
default:
log.SetLevel("info")
}
}
func send(c *cli.Context) (err error) {
setDebugLevel(c)
files := c.Args().Slice()
func defaultRelay() string {
if v := os.Getenv("SHARE_RELAY"); v != "" {
return v
}
return models.DEFAULT_RELAY
}
func runSend(args []string) error {
fs := flag.NewFlagSet("send", flag.ExitOnError)
fs.Usage = func() {
fmt.Fprintln(os.Stderr, "share send [options] file1 [file2 ...]")
fs.PrintDefaults()
}
code := fs.String("code", "", "room codephrase (generated if not given)")
relay := fs.String("relay", defaultRelay(), "address of the relay")
debug := fs.Bool("debug", false, "toggle debug mode")
quiet := fs.Bool("quiet", false, "disable all output")
if err := fs.Parse(args); err != nil {
return err
}
setDebugLevel(*quiet, *debug)
files := fs.Args()
if len(files) == 0 {
return fmt.Errorf("no files specified; usage: share send file1 [file2 ...]")
}
code := c.String("code")
if code == "" {
code = utils.GetRandomName()
roomCode := *code
if roomCode == "" {
roomCode = utils.GetRandomName()
}
fmt.Printf("Code is: %s\n", code)
fmt.Printf("Code is: %s\n", roomCode)
fmt.Println("On the other computer, run:")
fmt.Printf("\tshare %s\n", code)
fmt.Printf("\tshare %s\n", roomCode)
return swarm.Run(swarm.Options{
RelayAddress: c.String("relay"),
Code: code,
RelayAddress: *relay,
Code: roomCode,
Files: files,
})
}
func receive(c *cli.Context) (err error) {
setDebugLevel(c)
code := c.Args().First()
if code == "" {
return cli.ShowAppHelp(c)
func runReceive(args []string) error {
fs := flag.NewFlagSet("share", flag.ExitOnError)
fs.Usage = func() {
fmt.Print(usage)
fs.PrintDefaults()
}
outDir := c.String("out")
if outDir == "" {
outDir = "."
relay := fs.String("relay", defaultRelay(), "address of the relay")
out := fs.String("out", ".", "specify an output folder to receive the file")
oneTime := fs.Bool("one-time", false, "exit once everything currently in the room is downloaded, instead of staying to help reseed it")
debug := fs.Bool("debug", false, "toggle debug mode")
quiet := fs.Bool("quiet", false, "disable all output")
if err := fs.Parse(args); err != nil {
return err
}
setDebugLevel(*quiet, *debug)
code := fs.Arg(0)
if code == "" {
fs.Usage()
return nil
}
return swarm.Run(swarm.Options{
RelayAddress: c.String("relay"),
RelayAddress: *relay,
Code: code,
OutDir: outDir,
OneTime: c.Bool("one-time"),
OutDir: *out,
OneTime: *oneTime,
})
}
func relay(c *cli.Context) (err error) {
log.Infof("starting share relay version %v", Version)
func runRelay(args []string) error {
fs := flag.NewFlagSet("relay", flag.ExitOnError)
fs.Usage = func() {
fmt.Fprintln(os.Stderr, "share relay [options]")
fs.PrintDefaults()
}
defaultPort := 9009
if v := os.Getenv("SHARE_PORT"); v != "" {
if p, err := strconv.Atoi(v); err == nil {
defaultPort = p
}
}
host := fs.String("host", "", "host of the relay")
port := fs.Int("port", defaultPort, "port of the relay")
debug := fs.Bool("debug", false, "toggle debug mode")
if err := fs.Parse(args); err != nil {
return err
}
debugString := "info"
if c.Bool("debug") {
if *debug {
debugString = "debug"
}
host := c.String("host")
port := c.Int("port")
if port == 0 {
port = 9009
}
return tcp.Run(debugString, host, fmt.Sprintf("%d", port))
log.Infof("starting share relay version %v", Version)
return tcp.Run(debugString, *host, strconv.Itoa(*port))
}
+1 -1
View File
@@ -13,7 +13,7 @@ import (
"github.com/magisterquis/connectproxy"
"github.com/tzgyn/share/src/utils"
log "github.com/schollz/logger"
log "github.com/tzgyn/share/src/logger"
"golang.org/x/net/proxy"
)
+78
View File
@@ -0,0 +1,78 @@
// Package logger is a minimal leveled logger, replacing the schollz/logger
// dependency with an in-repo equivalent covering the same call surface
// (SetLevel/SetOutput and Trace/Debug/Info/Warn/Error, each with an -f
// variant) used throughout this project.
package logger
import (
"fmt"
"io"
"log"
"os"
)
type level int
const (
levelTrace level = iota
levelDebug
levelInfo
levelWarn
levelError
)
var (
current level = levelInfo
loggers = map[level]*log.Logger{
levelTrace: log.New(os.Stdout, "[trace]\t", log.Ltime|log.Lmicroseconds|log.Lshortfile),
levelDebug: log.New(os.Stdout, "[debug]\t", log.Ltime|log.Lshortfile),
levelInfo: log.New(os.Stdout, "[info]\t", log.Ldate|log.Ltime),
levelWarn: log.New(os.Stdout, "[warn]\t", log.Ldate|log.Ltime),
levelError: log.New(os.Stdout, "[error]\t", log.Ldate|log.Ltime|log.Lshortfile),
}
)
// SetOutput redirects all log levels to w.
func SetOutput(w io.Writer) {
for _, l := range loggers {
l.SetOutput(w)
}
}
// SetLevel sets the minimum level that will be printed: one of
// "trace", "debug", "info", "warn", "error". Unrecognized values are
// treated as "trace" (print everything), matching the previous dependency's
// behavior.
func SetLevel(s string) {
switch s {
case "debug":
current = levelDebug
case "info":
current = levelInfo
case "warn":
current = levelWarn
case "error":
current = levelError
default:
current = levelTrace
}
}
func output(lvl level, s string) {
if lvl < current {
return
}
loggers[lvl].Output(3, s)
}
func Tracef(format string, v ...interface{}) { output(levelTrace, fmt.Sprintf(format, v...)) }
func Debugf(format string, v ...interface{}) { output(levelDebug, fmt.Sprintf(format, v...)) }
func Infof(format string, v ...interface{}) { output(levelInfo, fmt.Sprintf(format, v...)) }
func Warnf(format string, v ...interface{}) { output(levelWarn, fmt.Sprintf(format, v...)) }
func Errorf(format string, v ...interface{}) { output(levelError, fmt.Sprintf(format, v...)) }
func Trace(v ...interface{}) { output(levelTrace, fmt.Sprint(v...)) }
func Debug(v ...interface{}) { output(levelDebug, fmt.Sprint(v...)) }
func Info(v ...interface{}) { output(levelInfo, fmt.Sprint(v...)) }
func Warn(v ...interface{}) { output(levelWarn, fmt.Sprint(v...)) }
func Error(v ...interface{}) { output(levelError, fmt.Sprint(v...)) }
+1 -1
View File
@@ -9,7 +9,7 @@ import (
"time"
"github.com/tzgyn/share/src/utils"
log "github.com/schollz/logger"
log "github.com/tzgyn/share/src/logger"
)
// TCP_BUFFER_SIZE is the maximum packet size
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Zack
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+197
View File
@@ -0,0 +1,197 @@
// Package pake implements a password-authenticated key exchange (a
// SPAKE2-style protocol) over the NIST P256 curve from Go's standard
// library. It's a trimmed fork of github.com/schollz/pake/v3, kept only
// for the P256 case this project actually uses, so no external module
// dependency (and no extra elliptic-curve implementations) are needed for
// it. See LICENSE for the original project's MIT license.
package pake
import (
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"encoding/json"
"errors"
"fmt"
"math/big"
)
// curve is fixed at P256; every peer link in this project uses the same
// curve, so there's no need for the multi-curve selection the original
// library offered.
var curve = elliptic.P256()
// generator points U and V, fixed and known to both sides ahead of time
// (not sent over the wire). Same values as upstream pake's "p256" curve,
// verified below at init to still be valid P256 points.
var (
Uᵤ, _ = new(big.Int).SetString("793136080485469241208656611513609866400481671852", 10)
Uᵥ, _ = new(big.Int).SetString("59748757929350367369315811184980635230185250460108398961713395032485227207304", 10)
Vᵤ, _ = new(big.Int).SetString("1086685267857089638167386722555472967068468061489", 10)
Vᵥ, _ = new(big.Int).SetString("9157340230202296554417312816309453883742349874205386245733062928888341584123", 10)
P = elliptic.P256().Params().P
)
func init() {
if !curve.IsOnCurve(Uᵤ, Uᵥ) {
panic("pake: U is not on curve")
}
if !curve.IsOnCurve(Vᵤ, Vᵥ) {
panic("pake: V is not on curve")
}
}
// Pake keeps public and private variables by only transmitting between
// parties after marshaling.
//
// This method follows
// https://crypto.stanford.edu/~dabo/cryptobook/BonehShoup_0_4.pdf
// Figure 21/15
// http://www.lothar.com/~warner/MagicWormhole-PyCon2016.pdf
// Slide 11
type Pake struct {
// Public variables
Role int
Xᵤ, Xᵥ *big.Int
Yᵤ, Yᵥ *big.Int
// Private variables
Pw []byte
Vpwᵤ, Vpwᵥ *big.Int
Upwᵤ, Upwᵥ *big.Int
Aα []byte
Aαᵤ, Aαᵥ *big.Int
Zᵤ, Zᵥ *big.Int
K []byte
}
// Public returns the public variables of Pake, safe to marshal and send.
func (p *Pake) Public() *Pake {
return &Pake{
Role: p.Role,
Xᵤ: p.Xᵤ,
Xᵥ: p.Xᵥ,
Yᵤ: p.Yᵤ,
Yᵥ: p.Yᵥ,
}
}
// InitCurve takes the shared weak passphrase (pw) to initialize the points
// on the curve. role is 0 for the side that goes first (e.g. the dialer)
// and 1 for the other side.
func InitCurve(pw []byte, role int) (p *Pake, err error) {
p = new(Pake)
p.Pw = pw
if role == 1 {
p.Role = 1
return
}
p.Role = 0
// STEP: A computes X
p.Vpwᵤ, p.Vpwᵥ = curve.ScalarMult(Vᵤ, Vᵥ, p.Pw)
p.Upwᵤ, p.Upwᵥ = curve.ScalarMult(Uᵤ, Uᵥ, p.Pw)
p.Aα = make([]byte, 32) // randomly generated secret
if _, err = rand.Read(p.Aα); err != nil {
return
}
p.Aαᵤ, p.Aαᵥ = curve.ScalarBaseMult(p.Aα)
p.Xᵤ, p.Xᵥ = curve.Add(p.Upwᵤ, p.Upwᵥ, p.Aαᵤ, p.Aαᵥ) // "X"
// now X should be sent to B
return
}
// Bytes marshals the Pake structure so that private variables are hidden.
func (p *Pake) Bytes() (b []byte) {
if p == nil {
panic("pake is not initialized")
}
b, err := json.Marshal(p.Public())
if err != nil {
panic(err)
}
return
}
// Update updates itself with the other party's marshaled Pake and
// automatically determines what stage it's at and what to generate next.
func (p *Pake) Update(qBytes []byte) (err error) {
if p == nil {
return fmt.Errorf("pake is not initialized")
}
var q *Pake
if err = json.Unmarshal(qBytes, &q); err != nil {
return
}
if p.Role == q.Role {
return errors.New("can't have its own role")
}
if p.Role == 1 {
// copy over public variables
p.Xᵤ, p.Xᵥ = q.Xᵤ, q.Xᵥ
if !curve.IsOnCurve(p.Xᵤ, p.Xᵥ) {
return errors.New("X values not on curve")
}
// STEP: B computes Y
p.Vpwᵤ, p.Vpwᵥ = curve.ScalarMult(Vᵤ, Vᵥ, p.Pw)
p.Upwᵤ, p.Upwᵥ = curve.ScalarMult(Uᵤ, Uᵥ, p.Pw)
p.Aα = make([]byte, 32) // randomly generated secret
if _, err = rand.Read(p.Aα); err != nil {
return
}
p.Aαᵤ, p.Aαᵥ = curve.ScalarBaseMult(p.Aα)
p.Yᵤ, p.Yᵥ = curve.Add(p.Vpwᵤ, p.Vpwᵥ, p.Aαᵤ, p.Aαᵥ) // "Y"
// STEP: B computes Z
v := new(big.Int).Neg(p.Upwᵥ)
v.Mod(v, P)
p.Zᵤ, p.Zᵥ = curve.Add(p.Xᵤ, p.Xᵥ, p.Upwᵤ, v)
p.Zᵤ, p.Zᵥ = curve.ScalarMult(p.Zᵤ, p.Zᵥ, p.Aα)
// STEP: B computes k
// H(pw,id_P,id_Q,X,Y,Z)
p.K = sessionKey(p.Pw, p.Xᵤ, p.Xᵥ, p.Yᵤ, p.Yᵥ, p.Zᵤ, p.Zᵥ)
} else {
p.Yᵤ, p.Yᵥ = q.Yᵤ, q.Yᵥ
if !curve.IsOnCurve(p.Yᵤ, p.Yᵥ) {
return errors.New("Y values not on curve")
}
// STEP: A computes Z
v := new(big.Int).Neg(p.Vpwᵥ)
v.Mod(v, P)
p.Zᵤ, p.Zᵥ = curve.Add(p.Yᵤ, p.Yᵥ, p.Vpwᵤ, v)
p.Zᵤ, p.Zᵥ = curve.ScalarMult(p.Zᵤ, p.Zᵥ, p.Aα)
// STEP: A computes k
// H(pw,id_P,id_Q,X,Y,Z)
p.K = sessionKey(p.Pw, p.Xᵤ, p.Xᵥ, p.Yᵤ, p.Yᵥ, p.Zᵤ, p.Zᵥ)
}
return
}
func sessionKey(pw []byte, xu, xv, yu, yv, zu, zv *big.Int) []byte {
h := sha256.New()
h.Write(pw)
h.Write(xu.Bytes())
h.Write(xv.Bytes())
h.Write(yu.Bytes())
h.Write(yv.Bytes())
h.Write(zu.Bytes())
h.Write(zv.Bytes())
return h.Sum(nil)
}
// SessionKey returns the derived session key, or an error if one hasn't
// been generated yet (i.e. Update hasn't completed the exchange).
func (p *Pake) SessionKey() ([]byte, error) {
if p == nil {
return nil, fmt.Errorf("pake is not initialized")
}
if p.K == nil {
return nil, errors.New("session key not generated")
}
return p.K, nil
}
+1 -1
View File
@@ -11,7 +11,7 @@ import (
"sync"
"time"
log "github.com/schollz/logger"
log "github.com/tzgyn/share/src/logger"
"github.com/tzgyn/share/src/comm"
"github.com/tzgyn/share/src/tcp"
+2 -3
View File
@@ -1,9 +1,8 @@
package swarm
import (
"github.com/schollz/pake/v3"
"github.com/tzgyn/share/src/comm"
"github.com/tzgyn/share/src/pake"
)
// handshake runs a PAKE key exchange over c using the room's codephrase as
@@ -16,7 +15,7 @@ func handshake(c *comm.Comm, codephrase string, initiator bool) (key []byte, err
if initiator {
role = 0
}
p, err := pake.InitCurve([]byte(codephrase), role, "siec")
p, err := pake.InitCurve([]byte(codephrase), role)
if err != nil {
return nil, err
}
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"net"
"sync"
log "github.com/schollz/logger"
log "github.com/tzgyn/share/src/logger"
)
type stop struct {
+1 -1
View File
@@ -9,7 +9,7 @@ import (
"sync"
"time"
log "github.com/schollz/logger"
log "github.com/tzgyn/share/src/logger"
"github.com/tzgyn/share/src/comm"
)
+8 -90
View File
@@ -26,8 +26,7 @@ import (
"github.com/kalafut/imohash"
"github.com/minio/highwayhash"
"github.com/tzgyn/share/src/mnemonicode"
log "github.com/schollz/logger"
"github.com/schollz/progressbar/v3"
log "github.com/tzgyn/share/src/logger"
)
const NbPinNumbers = 4
@@ -74,11 +73,7 @@ func GetInput(prompt string) string {
return strings.TrimSpace(text)
}
func HashFile(fname string, algorithm string, showProgress ...bool) (hash256 []byte, err error) {
doShowProgress := false
if len(showProgress) > 0 {
doShowProgress = showProgress[0]
}
func HashFile(fname string, algorithm string) (hash256 []byte, err error) {
var fstats os.FileInfo
fstats, err = os.Lstat(fname)
if err != nil {
@@ -96,17 +91,17 @@ func HashFile(fname string, algorithm string, showProgress ...bool) (hash256 []b
case "imohash":
return IMOHashFile(fname)
case "md5":
return MD5HashFile(fname, doShowProgress)
return MD5HashFile(fname)
case "xxhash":
return XXHashFile(fname, doShowProgress)
return XXHashFile(fname)
case "highway":
return HighwayHashFile(fname, doShowProgress)
return HighwayHashFile(fname)
}
err = fmt.Errorf("unspecified algorithm")
return
}
func HighwayHashFile(fname string, doShowProgress bool) (hashHighway []byte, err error) {
func HighwayHashFile(fname string) (hashHighway []byte, err error) {
f, err := os.Open(fname)
if err != nil {
return
@@ -121,33 +116,15 @@ func HighwayHashFile(fname string, doShowProgress bool) (hashHighway []byte, err
err = fmt.Errorf("could not create highwayhash: %s", err.Error())
return
}
if doShowProgress {
stat, _ := f.Stat()
fnameShort := path.Base(fname)
if len(fnameShort) > 20 {
fnameShort = fnameShort[:20] + "..."
}
bar := progressbar.NewOptions64(stat.Size(),
progressbar.OptionSetWriter(os.Stderr),
progressbar.OptionShowBytes(true),
progressbar.OptionSetDescription(fmt.Sprintf("Hashing %s", fnameShort)),
progressbar.OptionClearOnFinish(),
progressbar.OptionFullWidth(),
)
if _, err = io.Copy(io.MultiWriter(h, bar), f); err != nil {
return
}
} else {
if _, err = io.Copy(h, f); err != nil {
return
}
}
hashHighway = h.Sum(nil)
return
}
func MD5HashFile(fname string, doShowProgress bool) (hash256 []byte, err error) {
func MD5HashFile(fname string) (hash256 []byte, err error) {
f, err := os.Open(fname)
if err != nil {
return
@@ -155,27 +132,9 @@ func MD5HashFile(fname string, doShowProgress bool) (hash256 []byte, err error)
defer f.Close()
h := md5.New()
if doShowProgress {
stat, _ := f.Stat()
fnameShort := path.Base(fname)
if len(fnameShort) > 20 {
fnameShort = fnameShort[:20] + "..."
}
bar := progressbar.NewOptions64(stat.Size(),
progressbar.OptionSetWriter(os.Stderr),
progressbar.OptionShowBytes(true),
progressbar.OptionSetDescription(fmt.Sprintf("Hashing %s", fnameShort)),
progressbar.OptionClearOnFinish(),
progressbar.OptionFullWidth(),
)
if _, err = io.Copy(io.MultiWriter(h, bar), f); err != nil {
return
}
} else {
if _, err = io.Copy(h, f); err != nil {
return
}
}
hash256 = h.Sum(nil)
return
@@ -196,7 +155,7 @@ func IMOHashFileFull(fname string) (hash []byte, err error) {
return
}
func XXHashFile(fname string, doShowProgress bool) (hash256 []byte, err error) {
func XXHashFile(fname string) (hash256 []byte, err error) {
f, err := os.Open(fname)
if err != nil {
return
@@ -204,27 +163,9 @@ func XXHashFile(fname string, doShowProgress bool) (hash256 []byte, err error) {
defer f.Close()
h := xxhash.New()
if doShowProgress {
stat, _ := f.Stat()
fnameShort := path.Base(fname)
if len(fnameShort) > 20 {
fnameShort = fnameShort[:20] + "..."
}
bar := progressbar.NewOptions64(stat.Size(),
progressbar.OptionSetWriter(os.Stderr),
progressbar.OptionShowBytes(true),
progressbar.OptionSetDescription(fmt.Sprintf("Hashing %s", fnameShort)),
progressbar.OptionClearOnFinish(),
progressbar.OptionFullWidth(),
)
if _, err = io.Copy(io.MultiWriter(h, bar), f); err != nil {
return
}
} else {
if _, err = io.Copy(h, f); err != nil {
return
}
}
hash256 = h.Sum(nil)
return
@@ -310,23 +251,6 @@ func MissingChunks(fname string, fsize int64, chunkSize int) (chunkRanges []int6
return
}
var bar *progressbar.ProgressBar
showProgress := fsize > 10*1024*1024
if showProgress {
fnameShort := path.Base(fname)
if len(fnameShort) > 20 {
fnameShort = fnameShort[:20] + "..."
}
bar = progressbar.NewOptions64(fsize,
progressbar.OptionSetWriter(os.Stderr),
progressbar.OptionShowBytes(true),
progressbar.OptionSetDescription(fmt.Sprintf("Checking %s", fnameShort)),
progressbar.OptionClearOnFinish(),
progressbar.OptionFullWidth(),
progressbar.OptionThrottle(100*time.Millisecond),
)
}
emptyBuffer := make([]byte, chunkSize)
chunkNum := 0
chunks := make([]int64, int64(math.Ceil(float64(fsize)/float64(chunkSize))))
@@ -342,12 +266,6 @@ func MissingChunks(fname string, fsize int64, chunkSize int) (chunkRanges []int6
chunkNum++
}
currentLocation += int64(bytesread)
if showProgress && bar != nil {
bar.Add(bytesread)
}
}
if showProgress && bar != nil {
bar.Finish()
}
if chunkNum == 0 {
chunkRanges = []int64{}