diff --git a/gmtest/.gitignore b/gmtest/.gitignore new file mode 100644 index 0000000..b9ecd2e --- /dev/null +++ b/gmtest/.gitignore @@ -0,0 +1 @@ +session.gob diff --git a/gmtest/go.mod b/gmtest/go.mod new file mode 100644 index 0000000..7ef1852 --- /dev/null +++ b/gmtest/go.mod @@ -0,0 +1,21 @@ +module go.mau.fi/mautrix-gmessages/gmtest + +go 1.20 + +require ( + github.com/mdp/qrterminal/v3 v3.1.1 + github.com/rs/zerolog v1.29.1 + go.mau.fi/mautrix-gmessages/libgm v0.1.0 +) + +require ( + github.com/google/uuid v1.3.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect + golang.org/x/sys v0.8.0 // indirect + google.golang.org/protobuf v1.31.0 // indirect + rsc.io/qr v0.2.0 // indirect +) + +replace go.mau.fi/mautrix-gmessages/libgm => ../libgm diff --git a/gmtest/go.sum b/gmtest/go.sum new file mode 100644 index 0000000..f68678e --- /dev/null +++ b/gmtest/go.sum @@ -0,0 +1,34 @@ +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mdp/qrterminal/v3 v3.1.1 h1:cIPwg3QU0OIm9+ce/lRfWXhPwEjOSKwk3HBwL3HBTyc= +github.com/mdp/qrterminal/v3 v3.1.1/go.mod h1:5lJlXe7Jdr8wlPDdcsJttv1/knsRgzXASyr4dcGZqNU= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc= +github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU= +golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME= +golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +rsc.io/qr v0.2.0 h1:6vBLea5/NRMVTz8V66gipeLycZMl/+UlFmk8DvqQ6WY= +rsc.io/qr v0.2.0/go.mod h1:IF+uZjkb9fqyeF/4tlBoynqmQxUoPfWEKh921coOuXs= diff --git a/gmtest/main.go b/gmtest/main.go new file mode 100644 index 0000000..6006fcd --- /dev/null +++ b/gmtest/main.go @@ -0,0 +1,137 @@ +package main + +import ( + "bufio" + "encoding/gob" + "errors" + "os" + "os/signal" + "strings" + "syscall" + "time" + + "github.com/mdp/qrterminal/v3" + "github.com/rs/zerolog" + + "go.mau.fi/mautrix-gmessages/libgm" + "go.mau.fi/mautrix-gmessages/libgm/binary" + "go.mau.fi/mautrix-gmessages/libgm/crypto" + "go.mau.fi/mautrix-gmessages/libgm/events" +) + +type Session struct { + *libgm.DevicePair + *crypto.Cryptor + *binary.WebAuthKey +} + +func must(err error) { + if err != nil { + panic(err) + } +} + +func mustReturn[T any](val T, err error) T { + must(err) + return val +} + +var cli *libgm.Client +var log zerolog.Logger +var sess Session + +func main() { + log = zerolog.New(zerolog.NewConsoleWriter(func(w *zerolog.ConsoleWriter) { + w.Out = os.Stdout + w.TimeFormat = time.Stamp + })).With().Timestamp().Logger() + file, err := os.Open("session.gob") + if err != nil { + if !errors.Is(err, os.ErrNotExist) { + panic(err) + } + } else { + must(gob.NewDecoder(file).Decode(&sess)) + log.Info().Msg("Loaded session?") + } + _ = file.Close() + if sess.Cryptor == nil { + sess.Cryptor = crypto.NewCryptor(nil, nil) + } + cli = libgm.NewClient(sess.DevicePair, sess.Cryptor, log, nil) + cli.SetEventHandler(evtHandler) + if sess.DevicePair == nil { + pairer := mustReturn(cli.NewPairer(nil, 20)) + registered := mustReturn(pairer.RegisterPhoneRelay()) + must(cli.Connect(registered.Field5.RpcKey)) + } else { + must(cli.Connect(sess.WebAuthKey.WebAuthKey)) + } + + c := make(chan os.Signal) + input := make(chan string) + signal.Notify(c, os.Interrupt, syscall.SIGTERM) + go func() { + defer close(input) + scan := bufio.NewScanner(os.Stdin) + for scan.Scan() { + line := strings.TrimSpace(scan.Text()) + if len(line) > 0 { + input <- line + } + } + }() + defer saveSession() + for { + select { + case <-c: + log.Info().Msg("Interrupt received, exiting") + return + case cmd := <-input: + if len(cmd) == 0 { + log.Info().Msg("Stdin closed, exiting") + return + } + args := strings.Fields(cmd) + cmd = args[0] + args = args[1:] + //go handleCmd(strings.ToLower(cmd), args) + } + } +} + +func saveSession() { + file := mustReturn(os.OpenFile("session.gob", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600)) + must(gob.NewEncoder(file).Encode(sess)) + _ = file.Close() +} + +func evtHandler(rawEvt any) { + switch evt := rawEvt.(type) { + case *events.ClientReady: + log.Debug().Any("simData", evt.Session.Settings).Msg("Client is ready!") + case *events.PairSuccessful: + log.Debug().Any("data", evt).Msg("Pair successful") + sess.DevicePair = &libgm.DevicePair{ + Mobile: evt.PairDeviceData.Mobile, + Browser: evt.PairDeviceData.Browser, + } + sess.WebAuthKey = evt.PairDeviceData.WebAuthKeyData + saveSession() + log.Debug().Msg("Wrote session") + case *binary.Event_MessageEvent: + log.Debug().Any("data", evt).Msg("Message event") + case *binary.Event_ConversationEvent: + log.Debug().Any("data", evt).Msg("Conversation event") + case *events.QR: + qrterminal.GenerateHalfBlock(evt.URL, qrterminal.L, os.Stdout) + case *events.BrowserActive: + log.Debug().Any("data", evt).Msg("Browser active") + case *events.Battery: + log.Debug().Any("data", evt).Msg("Battery") + case *events.DataConnection: + log.Debug().Any("data", evt).Msg("Data connection") + default: + log.Debug().Any("data", evt).Msg("Unknown event") + } +}