diff --git a/.drone.yml b/.drone.yml index 790806f..bd9eac4 100644 --- a/.drone.yml +++ b/.drone.yml @@ -10,7 +10,7 @@ pipeline: - wget https://git.openprivacy.ca/openprivacy/buildfiles/raw/master/tor/torrc - chmod a+x tor - go list ./... | xargs go get - - go get -u github.com/golang/lint/golint + - go get -u golang.org/x/lint/golint quality: image: golang commands: diff --git a/app/cli/main.go b/app/cli/main.go index 7197b60..ec12f1e 100644 --- a/app/cli/main.go +++ b/app/cli/main.go @@ -529,6 +529,18 @@ func main() { } else { fmt.Printf("Error exporting group, usage: %s\n", usages[commands[0]]) } + case "/import-group": + if len(commands) == 2 { + groupID, err := peer.ImportGroup(commands[1]) + if err != nil { + fmt.Printf("Error importing group: %v\n", err) + } else { + fmt.Printf("Imported group: %s\n", groupID) + } + } else { + fmt.Printf("%v", commands) + fmt.Printf("Error importing group, usage: %s\n", usages[commands[0]]) + } case "/save": peer.Save() case "/help": diff --git a/app/cwtchutil/main.go b/app/cwtchutil/main.go new file mode 100644 index 0000000..6062552 --- /dev/null +++ b/app/cwtchutil/main.go @@ -0,0 +1,186 @@ +package main + +import ( + "bufio" + "crypto/rand" + libpeer "cwtch.im/cwtch/peer" + "fmt" + "git.openprivacy.ca/openprivacy/libricochet-go/utils" + "github.com/sethvargo/go-diceware/diceware" + "golang.org/x/crypto/ed25519" + "io/ioutil" + "log" + "os" + "strconv" + "strings" + "time" +) + +func convertCwtchFile(filename string, password string) { + peer, err := libpeer.LoadCwtchPeer(filename, password) + if err != nil { + log.Fatalf("%v", err) + } + + b := []byte("== ed25519v1-secret: type0 ==") + b = append(b, peer.GetProfile().Ed25519PrivateKey...) + err = ioutil.WriteFile("hs_ed25519_secret_key", b, 0600) + if err != nil { + log.Fatalf("%v", err) + } + + b = []byte("== ed25519v1-public: type0 ==") + b = append(b, peer.GetProfile().Ed25519PublicKey...) + err = ioutil.WriteFile("hs_ed25519_public_key", b, 0600) + if err != nil { + log.Fatalf("%v", err) + } + + b = []byte(peer.GetProfile().Onion + ".onion\n") + err = ioutil.WriteFile("hostname", b, 0600) + if err != nil { + log.Fatalf("%v", err) + } + + fmt.Println("success!") +} + +func convertTorFile(filename string, password string) { + log.Fatalf("this code doesn't work and can never work :( it's a math thing") + + name, _ := diceware.Generate(2) + sk, err := ioutil.ReadFile("hs_ed25519_secret_key") + if err != nil { + log.Fatalf("%v", err) + } + sk = sk[32:] + + pk, err := ioutil.ReadFile("hs_ed25519_public_key") + if err != nil { + log.Fatalf("%v", err) + } + pk = pk[32:] + + onion, err := ioutil.ReadFile("hostname") + if err != nil { + log.Fatalf("%v", err) + } + onion = onion[:56] + + peer, err := libpeer.NewCwtchPeer(strings.Join(name, "-"), password, filename) + if err != nil { + log.Fatalf("%v", err) + } + + fmt.Printf("%d %d %s\n", len(peer.GetProfile().Ed25519PublicKey), len(peer.GetProfile().Ed25519PrivateKey), peer.GetProfile().Onion) + peer.GetProfile().Ed25519PrivateKey = sk + peer.GetProfile().Ed25519PublicKey = pk + peer.GetProfile().Onion = string(onion) + peer.Save() + + log.Printf("success! loaded %d byte pk and %d byte sk for %s.onion\n", len(pk), len(sk), onion) +} + +func vanity() { + for { + pk, sk, err := ed25519.GenerateKey(rand.Reader) + if err != nil { + continue + } + onion := utils.GetTorV3Hostname(pk) + for i := 4; i < len(os.Args); i++ { + if strings.HasPrefix(onion, os.Args[i]) { + peer, err := libpeer.NewCwtchPeer(os.Args[i], os.Args[3], onion+".cwtch") + if err != nil { + log.Fatalf("%v", err) + } + peer.GetProfile().Ed25519PrivateKey = sk + peer.GetProfile().Ed25519PublicKey = pk + peer.GetProfile().Onion = onion + peer.Save() + log.Printf("found %s.onion\n", onion) + } + } + } +} + +func printHelp() { + log.Println("usage: cwtchutil {help, convert-cwtch-file, convert-tor-file, changepw, vanity}") +} + +func main() { + if len(os.Args) < 2 { + printHelp() + os.Exit(1) + } + + switch os.Args[1] { + default: + printHelp() + case "help": + printHelp() + case "convert-cwtch-file": + if len(os.Args) != 4 { + log.Println("example: cwtchutil convert-cwtch-file ~/.cwtch/profiles/11ddd78a9918c064e742d5e36a8b8fd4 passw0rd") + os.Exit(1) + } + convertCwtchFile(os.Args[2], os.Args[3]) + case "convert-tor-file": + if len(os.Args) != 4 { + log.Println("example: cwtchutil convert-tor-file /var/lib/tor/hs1 passw0rd") + os.Exit(1) + } + convertTorFile(os.Args[2], os.Args[3]) + case "vanity": + if len(os.Args) < 5 { + log.Println("example: cwtchutil vanity 4 passw0rd erinn openpriv") + os.Exit(1) + } + + goroutines, err := strconv.Atoi(os.Args[2]) + if err != nil { + log.Printf("first parameter after vanity should be a number\n") + os.Exit(1) + } + log.Println("searching. press ctrl+c to stop") + for i := 0; i < goroutines; i++ { + go vanity() + } + + for { // run until ctrl+c + time.Sleep(time.Hour * 24) + } + case "changepw": + if len(os.Args) != 3 { + log.Fatalf("example: cwtch changepw ~/.cwtch/profiles/XXX") + } + + fmt.Printf("old password: ") + reader := bufio.NewReader(os.Stdin) + pw, err := reader.ReadString('\n') + if err != nil { + log.Fatalf("%v", err) + } + pw = pw[:len(pw)-1] + + peer, err := libpeer.LoadCwtchPeer(os.Args[2], pw) + if err != nil { + log.Fatalf("%v", err) + } + + fmt.Printf("new password: ") + newpw1, err := reader.ReadString('\n') + if err != nil { + log.Fatalf("%v", err) + } + newpw1 = newpw1[:len(newpw1)-1] // fuck go with this linebreak shit ^ea + + err = peer.ChangePassword(newpw1) + if err != nil { + log.Fatalf("%v", err) + } + + log.Println("success!") + peer.Save() + } +} diff --git a/peer/connections/peerpeerconnection.go b/peer/connections/peerpeerconnection.go index 04124e1..8368fd3 100644 --- a/peer/connections/peerpeerconnection.go +++ b/peer/connections/peerpeerconnection.go @@ -95,7 +95,7 @@ func (ppc *PeerPeerConnection) WaitTilAuthenticated() { if ppc.GetState() == AUTHENTICATED { break } - time.Sleep(time.Second * 5) + time.Sleep(time.Second * 1) } } diff --git a/peer/connections/peerserverconnection.go b/peer/connections/peerserverconnection.go index 1ab8547..0b5bcce 100644 --- a/peer/connections/peerserverconnection.go +++ b/peer/connections/peerserverconnection.go @@ -39,6 +39,16 @@ func (psc *PeerServerConnection) GetState() ConnectionState { return psc.state } +// WaitTilAuthenticated waits until the underlying connection is authenticated +func (psc *PeerServerConnection) WaitTilAuthenticated() { + for { + if psc.GetState() == AUTHENTICATED { + break + } + time.Sleep(time.Second * 1) + } +} + // Run manages the setup and teardown of a peer server connection func (psc *PeerServerConnection) Run() error { log.Printf("Connecting to %v", psc.Server) diff --git a/peer/cwtch_peer.go b/peer/cwtch_peer.go index acef58e..e7c11e5 100644 --- a/peer/cwtch_peer.go +++ b/peer/cwtch_peer.go @@ -47,6 +47,7 @@ type cwtchPeer struct { // directly implement a cwtchPeer. type CwtchPeer interface { Save() error + ChangePassword(string) error PeerWithOnion(string) *connections.PeerPeerConnection InviteOnionToGroup(string, string) error @@ -154,6 +155,16 @@ func NewCwtchPeer(name string, password string, profilefile string) (CwtchPeer, return cp, nil } +func (cp *cwtchPeer) ChangePassword(password string) error { + key, salt, err := createKey(password) + if err != nil { + return err + } + cp.key = key + cp.salt = salt + return nil +} + // Save saves the cwtchPeer profile state to a file. func (cp *cwtchPeer) Save() error { cp.mutex.Lock() diff --git a/server/server.go b/server/server.go index fc2138a..11fd3f4 100644 --- a/server/server.go +++ b/server/server.go @@ -8,8 +8,8 @@ import ( "cwtch.im/cwtch/storage" "git.openprivacy.ca/openprivacy/libricochet-go/application" "git.openprivacy.ca/openprivacy/libricochet-go/channels" - "log" "git.openprivacy.ca/openprivacy/libricochet-go/utils" + "log" ) // Server encapsulates a complete, compliant Cwtch server.