Check spec versions supported by homeserver. Fixes #402

This commit is contained in:
Tulir Asokan 2022-11-21 22:42:42 +02:00
parent 5aa494dc5e
commit 6aaeb8c244
7 changed files with 100 additions and 12 deletions

1
go.mod
View File

@ -44,6 +44,7 @@ require (
golang.org/x/term v0.2.0 // indirect golang.org/x/term v0.2.0 // indirect
golang.org/x/text v0.4.0 // indirect golang.org/x/text v0.4.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
maunium.net/go/mauflag v1.0.0 // indirect
maunium.net/go/maulogger/v2 v2.3.2 // indirect maunium.net/go/maulogger/v2 v2.3.2 // indirect
) )

2
go.sum
View File

@ -119,6 +119,8 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M=
maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA=
maunium.net/go/maulogger/v2 v2.3.2 h1:1XmIYmMd3PoQfp9J+PaHhpt80zpfmMqaShzUTC7FwY0= maunium.net/go/maulogger/v2 v2.3.2 h1:1XmIYmMd3PoQfp9J+PaHhpt80zpfmMqaShzUTC7FwY0=
maunium.net/go/maulogger/v2 v2.3.2/go.mod h1:TYWy7wKwz/tIXTpsx8G3mZseIRiC5DoMxSZazOHy68A= maunium.net/go/maulogger/v2 v2.3.2/go.mod h1:TYWy7wKwz/tIXTpsx8G3mZseIRiC5DoMxSZazOHy68A=
maunium.net/go/mautrix v0.11.0 h1:B1FBHcvE4Mud+AC+zgNQQOw0JxSVrt40watCejhVA7w= maunium.net/go/mautrix v0.11.0 h1:B1FBHcvE4Mud+AC+zgNQQOw0JxSVrt40watCejhVA7w=

View File

@ -17,9 +17,12 @@
package main package main
import ( import (
"errors"
"fmt" "fmt"
"os" "os"
"os/signal" "os/signal"
"path/filepath"
"runtime"
"strings" "strings"
"syscall" "syscall"
"time" "time"
@ -60,7 +63,7 @@ func init() {
Version = fmt.Sprintf("%s%s.unknown", Version, suffix) Version = fmt.Sprintf("%s%s.unknown", Version, suffix)
} }
} }
VersionString = fmt.Sprintf("gomuks %s (%s)", Version, BuildTime) VersionString = fmt.Sprintf("gomuks %s (%s with %s)", Version, BuildTime, runtime.Version())
} }
// Gomuks is the wrapper for everything. // Gomuks is the wrapper for everything.
@ -142,7 +145,23 @@ func (gmx *Gomuks) internalStop(save bool) {
// If the tview app returns an error, it will be passed into panic(), which // If the tview app returns an error, it will be passed into panic(), which
// will be recovered as specified in Recover(). // will be recovered as specified in Recover().
func (gmx *Gomuks) Start() { func (gmx *Gomuks) Start() {
_ = gmx.matrix.InitClient() err := gmx.matrix.InitClient(true)
if err != nil {
if errors.Is(err, matrix.ErrServerOutdated) {
_, _ = fmt.Fprintln(os.Stderr, strings.Replace(err.Error(), "homeserver", gmx.config.HS, 1))
_, _ = fmt.Fprintln(os.Stderr)
_, _ = fmt.Fprintf(os.Stderr, "See `%s --help` if you want to skip this check or clear all data.\n", os.Args[0])
os.Exit(4)
} else if strings.HasPrefix(err.Error(), "failed to check server versions") {
_, _ = fmt.Fprintln(os.Stderr, "Failed to check versions supported by server:", errors.Unwrap(err))
_, _ = fmt.Fprintln(os.Stderr)
_, _ = fmt.Fprintf(os.Stderr, "Modify %s if the server has moved.\n", filepath.Join(gmx.config.Dir, "config.yaml"))
_, _ = fmt.Fprintf(os.Stderr, "See `%s --help` if you want to skip this check or clear all data.\n", os.Args[0])
os.Exit(5)
} else {
panic(err)
}
}
c := make(chan os.Signal, 1) c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM) signal.Notify(c, os.Interrupt, syscall.SIGTERM)
@ -152,7 +171,7 @@ func (gmx *Gomuks) Start() {
}() }()
go gmx.StartAutosave() go gmx.StartAutosave()
if err := gmx.ui.Start(); err != nil { if err = gmx.ui.Start(); err != nil {
panic(err) panic(err)
} }
} }

View File

@ -43,7 +43,7 @@ type UploadedMediaInfo struct {
type MatrixContainer interface { type MatrixContainer interface {
Client() *mautrix.Client Client() *mautrix.Client
Preferences() *config.UserPreferences Preferences() *config.UserPreferences
InitClient() error InitClient(isStartup bool) error
Initialized() bool Initialized() bool
Start() Start()

41
main.go
View File

@ -26,14 +26,38 @@ import (
"strings" "strings"
"time" "time"
flag "maunium.net/go/mauflag"
"maunium.net/go/gomuks/debug" "maunium.net/go/gomuks/debug"
ifc "maunium.net/go/gomuks/interface" ifc "maunium.net/go/gomuks/interface"
"maunium.net/go/gomuks/matrix"
"maunium.net/go/gomuks/ui" "maunium.net/go/gomuks/ui"
) )
var MainUIProvider ifc.UIProvider = ui.NewGomuksUI var MainUIProvider ifc.UIProvider = ui.NewGomuksUI
var wantVersion = flag.MakeFull("v", "version", "Show the version of gomuks", "false").Bool()
var clearCache = flag.MakeFull("c", "clear-cache", "Clear the cache directory instead of starting", "false").Bool()
var clearData = flag.Make().LongKey("clear-all-data").Usage("Clear all data instead of starting").Default("false").Bool()
var skipVersionCheck = flag.MakeFull("s", "skip-version-check", "Skip the homeserver version checks at startup and login", "false").Bool()
var wantHelp, _ = flag.MakeHelpFlag()
func main() { func main() {
flag.SetHelpTitles(
"gomuks - A terminal Matrix client written in Go.",
"gomuks [-vch] [--clear-all-data]",
)
err := flag.Parse()
if err != nil {
fmt.Println(err)
os.Exit(1)
} else if *wantHelp {
flag.PrintHelp()
return
} else if *wantVersion {
fmt.Println(VersionString)
return
}
debugDir := os.Getenv("DEBUG_DIR") debugDir := os.Getenv("DEBUG_DIR")
if len(debugDir) > 0 { if len(debugDir) > 0 {
debug.LogDirectory = debugDir debug.LogDirectory = debugDir
@ -51,7 +75,6 @@ func main() {
defer debug.Recover() defer debug.Recover()
var configDir, dataDir, cacheDir, downloadDir string var configDir, dataDir, cacheDir, downloadDir string
var err error
configDir, err = UserConfigDir() configDir, err = UserConfigDir()
if err != nil { if err != nil {
@ -79,11 +102,21 @@ func main() {
debug.Print("Cache directory:", cacheDir) debug.Print("Cache directory:", cacheDir)
debug.Print("Download directory:", downloadDir) debug.Print("Download directory:", downloadDir)
matrix.SkipVersionCheck = *skipVersionCheck
gmx := NewGomuks(MainUIProvider, configDir, dataDir, cacheDir, downloadDir) gmx := NewGomuks(MainUIProvider, configDir, dataDir, cacheDir, downloadDir)
if len(os.Args) > 1 && (os.Args[1] == "--version" || os.Args[1] == "-v") { if *clearCache {
fmt.Println(VersionString) debug.Print("Clearing cache as requested by CLI flag")
os.Exit(0) gmx.config.Clear()
fmt.Printf("Cleared cache at %s\n", gmx.config.CacheDir)
return
} else if *clearData {
debug.Print("Clearing all data as requested by CLI flag")
gmx.config.Clear()
gmx.config.ClearData()
_ = os.RemoveAll(gmx.config.Dir)
fmt.Printf("Cleared cache at %s, data at %s and config at %s\n", gmx.config.CacheDir, gmx.config.DataDir, gmx.config.Dir)
return
} }
gmx.Start() gmx.Start()

View File

@ -92,10 +92,21 @@ func (c *Container) Crypto() ifc.Crypto {
return c.crypto return c.crypto
} }
var (
ErrNoHomeserver = errors.New("no homeserver entered")
ErrServerOutdated = errors.New("homeserver is outdated")
)
var MinSpecVersion = mautrix.SpecV11
var SkipVersionCheck = false
// InitClient initializes the mautrix client and connects to the homeserver specified in the config. // InitClient initializes the mautrix client and connects to the homeserver specified in the config.
func (c *Container) InitClient() error { func (c *Container) InitClient(isStartup bool) error {
if len(c.config.HS) == 0 { if len(c.config.HS) == 0 {
return fmt.Errorf("no homeserver entered") if isStartup {
return nil
}
return ErrNoHomeserver
} }
if c.client != nil { if c.client != nil {
@ -139,6 +150,28 @@ func (c *Container) InitClient() error {
} }
} }
if !SkipVersionCheck && (!isStartup || len(c.client.AccessToken) > 0) {
debug.Printf("Checking versions that %s supports", c.client.HomeserverURL)
resp, err := c.client.Versions()
if err != nil {
debug.Print("Error checking supported versions:", err)
return fmt.Errorf("failed to check server versions: %w", err)
} else if !resp.ContainsGreaterOrEqual(MinSpecVersion) {
debug.Print("Server doesn't support modern spec versions")
bestVersionStr := "nothing"
bestVersion := mautrix.MustParseSpecVersion("r0.0.0")
for _, ver := range resp.Versions {
if ver.GreaterThan(bestVersion) {
bestVersion = ver
bestVersionStr = ver.String()
}
}
return fmt.Errorf("%w (it only supports %s, while gomuks requires %s)", ErrServerOutdated, bestVersionStr, MinSpecVersion.String())
} else {
debug.Print("Server supports modern spec versions")
}
}
c.stop = make(chan bool, 1) c.stop = make(chan bool, 1)
if len(accessToken) > 0 { if len(accessToken) > 0 {

View File

@ -149,7 +149,7 @@ func (view *LoginView) Error(err string) {
view.AddComponent(view.error, 1, 11, 3, 1) view.AddComponent(view.error, 1, 11, 3, 1)
} }
view.error.SetText(err) view.error.SetText(err)
errorHeight := int(math.Ceil(float64(runewidth.StringWidth(err)) / 45)) errorHeight := int(math.Ceil(float64(runewidth.StringWidth(err)) / 41))
view.container.SetHeight(14 + errorHeight) view.container.SetHeight(14 + errorHeight)
view.SetRow(11, errorHeight) view.SetRow(11, errorHeight)
} }
@ -161,7 +161,7 @@ func (view *LoginView) actuallyLogin(hs, mxid, password string) {
debug.Printf("Logging into %s as %s...", hs, mxid) debug.Printf("Logging into %s as %s...", hs, mxid)
view.config.HS = hs view.config.HS = hs
if err := view.matrix.InitClient(); err != nil { if err := view.matrix.InitClient(false); err != nil {
debug.Print("Init error:", err) debug.Print("Init error:", err)
view.Error(err.Error()) view.Error(err.Error())
} else if err = view.matrix.Login(mxid, password); err != nil { } else if err = view.matrix.Login(mxid, password); err != nil {