Update mautrix-go and make it build without crypto

This commit is contained in:
Tulir Asokan 2020-07-30 14:32:59 +03:00
parent aac9db09d6
commit 2f5f0674b6
7 changed files with 323 additions and 253 deletions

4
go.mod
View File

@ -23,9 +23,7 @@ require (
golang.org/x/net v0.0.0-20200602114024-627f9648deb9 golang.org/x/net v0.0.0-20200602114024-627f9648deb9
gopkg.in/toast.v1 v1.0.0-20180812000517-0a84660828b2 gopkg.in/toast.v1 v1.0.0-20180812000517-0a84660828b2
gopkg.in/yaml.v2 v2.3.0 gopkg.in/yaml.v2 v2.3.0
maunium.net/go/mautrix v0.5.5 maunium.net/go/mautrix v0.7.0-rc.1
maunium.net/go/mauview v0.1.1 maunium.net/go/mauview v0.1.1
maunium.net/go/tcell v0.2.0 maunium.net/go/tcell v0.2.0
) )
replace maunium.net/go/mautrix => github.com/nikofil/mautrix-go v0.5.2-0.20200725175335-dd3f90913c4d

2
go.sum
View File

@ -112,6 +112,8 @@ maunium.net/go/mautrix v0.5.3 h1:Lu4PGZvKZwhXmdDnBdLwmiImNM3jNGwJI9Sk78P+Gys=
maunium.net/go/mautrix v0.5.3/go.mod h1:LnkFnB1yjCbb8V+upoEHDGvI/F38NHSTWYCe2RRJgSY= maunium.net/go/mautrix v0.5.3/go.mod h1:LnkFnB1yjCbb8V+upoEHDGvI/F38NHSTWYCe2RRJgSY=
maunium.net/go/mautrix v0.5.5 h1:e0Pql1FdxoNUudx2oXo1gZHMrqIh5MC72cdXEPIrYLA= maunium.net/go/mautrix v0.5.5 h1:e0Pql1FdxoNUudx2oXo1gZHMrqIh5MC72cdXEPIrYLA=
maunium.net/go/mautrix v0.5.5/go.mod h1:FLbMANzwqlsX2Fgm7SDe+E4I3wSa4UxJRKqS5wGkCwA= maunium.net/go/mautrix v0.5.5/go.mod h1:FLbMANzwqlsX2Fgm7SDe+E4I3wSa4UxJRKqS5wGkCwA=
maunium.net/go/mautrix v0.7.0-rc.1 h1:DT7bNR9q+HlFs5Oo9IqmtWPkE4WPKZdRfIWRtlqkXtM=
maunium.net/go/mautrix v0.7.0-rc.1/go.mod h1:Va/74MijqaS0DQ3aUqxmFO54/PMfr1LVsCOcGRHbYmo=
maunium.net/go/mauview v0.1.1 h1:wfTXyPx3LGAGpTskh+UbBv/QItUWnEpaneHmywoYnfY= maunium.net/go/mauview v0.1.1 h1:wfTXyPx3LGAGpTskh+UbBv/QItUWnEpaneHmywoYnfY=
maunium.net/go/mauview v0.1.1/go.mod h1:3QBUiuLct9moP1LgDhCGIg0Ovxn38Bd2sGndnUOuj4o= maunium.net/go/mauview v0.1.1/go.mod h1:3QBUiuLct9moP1LgDhCGIg0Ovxn38Bd2sGndnUOuj4o=
maunium.net/go/tcell v0.2.0 h1:1Q0kN3wCOGAIGu1r3QHADsjSUOPDylKREvCv3EzJpVg= maunium.net/go/tcell v0.2.0 h1:1Q0kN3wCOGAIGu1r3QHADsjSUOPDylKREvCv3EzJpVg=

View File

@ -37,7 +37,6 @@ import (
"github.com/russross/blackfriday/v2" "github.com/russross/blackfriday/v2"
"maunium.net/go/mautrix" "maunium.net/go/mautrix"
"maunium.net/go/mautrix/crypto"
"maunium.net/go/mautrix/event" "maunium.net/go/mautrix/event"
"maunium.net/go/mautrix/format" "maunium.net/go/mautrix/format"
"maunium.net/go/mautrix/id" "maunium.net/go/mautrix/id"
@ -366,212 +365,6 @@ func cmdFingerprint(cmd *Command) {
} }
} }
// region TODO these four functions currently use the crypto internals directly. switch to interfaces before releasing
func autocompleteDeviceUserID(cmd *CommandAutocomplete) (completions []string, newText string) {
userCompletions := cmd.Room.AutocompleteUser(cmd.Args[0])
if len(userCompletions) == 1 {
newText = fmt.Sprintf("/%s %s ", cmd.OrigCommand, userCompletions[0].id)
} else {
completions = make([]string, len(userCompletions))
for i, completion := range userCompletions {
completions[i] = completion.id
}
}
return
}
func autocompleteDeviceDeviceID(cmd *CommandAutocomplete) (completions []string, newText string) {
mach := cmd.Matrix.Crypto().(*crypto.OlmMachine)
devices, err := mach.CryptoStore.GetDevices(id.UserID(cmd.Args[0]))
if len(devices) == 0 || err != nil {
return
}
var completedDeviceID id.DeviceID
if len(cmd.Args) > 1 {
existingID := strings.ToUpper(cmd.Args[1])
for _, device := range devices {
deviceIDStr := string(device.DeviceID)
if deviceIDStr == existingID {
// We don't want to do any autocompletion if there's already a full device ID there.
return []string{}, ""
} else if strings.HasPrefix(strings.ToUpper(device.Name), existingID) || strings.HasPrefix(deviceIDStr, existingID) {
completedDeviceID = device.DeviceID
completions = append(completions, fmt.Sprintf("%s (%s)", device.DeviceID, device.Name))
}
}
} else {
completions = make([]string, len(devices))
i := 0
for _, device := range devices {
completedDeviceID = device.DeviceID
completions[i] = fmt.Sprintf("%s (%s)", device.DeviceID, device.Name)
i++
}
}
if len(completions) == 1 {
newText = fmt.Sprintf("/%s %s %s ", cmd.OrigCommand, cmd.Args[0], completedDeviceID)
}
return
}
func autocompleteDevice(cmd *CommandAutocomplete) ([]string, string) {
if len(cmd.Args) == 0 {
return []string{}, ""
} else if len(cmd.Args) == 1 && !unicode.IsSpace(rune(cmd.RawArgs[len(cmd.RawArgs)-1])) {
return autocompleteDeviceUserID(cmd)
} else if cmd.Command != "devices" {
return autocompleteDeviceDeviceID(cmd)
}
return []string{}, ""
}
func getDevice(cmd *Command) *crypto.DeviceIdentity {
if len(cmd.Args) < 2 {
cmd.Reply("Usage: /%s <user id> <device id> [fingerprint]", cmd.Command)
return nil
}
mach := cmd.Matrix.Crypto().(*crypto.OlmMachine)
device, err := mach.GetOrFetchDevice(id.UserID(cmd.Args[0]), id.DeviceID(cmd.Args[1]))
if err != nil {
cmd.Reply("Failed to get device: %v", err)
return nil
}
return device
}
func putDevice(cmd *Command, device *crypto.DeviceIdentity, action string) {
mach := cmd.Matrix.Crypto().(*crypto.OlmMachine)
err := mach.CryptoStore.PutDevice(device.UserID, device)
if err != nil {
cmd.Reply("Failed to save device: %v", err)
} else {
cmd.Reply("Successfully %s %s/%s (%s)", action, device.UserID, device.DeviceID, device.Name)
}
mach.OnDevicesChanged(device.UserID)
}
func cmdDevices(cmd *Command) {
if len(cmd.Args) == 0 {
cmd.Reply("Usage: /devices <user id>")
return
}
userID := id.UserID(cmd.Args[0])
mach := cmd.Matrix.Crypto().(*crypto.OlmMachine)
devices, err := mach.CryptoStore.GetDevices(userID)
if err != nil {
cmd.Reply("Failed to get device list: %v", err)
}
if len(devices) == 0 {
cmd.Reply("Fetching device list from server...")
devices = mach.LoadDevices(userID)
}
if len(devices) == 0 {
cmd.Reply("No devices found for %s", userID)
return
}
var buf strings.Builder
for _, device := range devices {
_, _ = fmt.Fprintf(&buf, "%s (%s) - %s\n Fingerprint: %s\n", device.DeviceID, device.Name, device.Trust.String(), device.Fingerprint())
}
resp := buf.String()
cmd.Reply("%s", resp[:len(resp)-1])
}
func cmdDevice(cmd *Command) {
device := getDevice(cmd)
if device == nil {
return
}
deviceType := "Device"
if device.Deleted {
deviceType = "Deleted device"
}
cmd.Reply("%s %s of %s\nFingerprint: %s\nIdentity key: %s\nDevice name: %s\nTrust state: %s",
deviceType, device.DeviceID, device.UserID,
device.Fingerprint(), device.IdentityKey,
device.Name, device.Trust.String())
}
func cmdVerify(cmd *Command) {
device := getDevice(cmd)
if device == nil {
return
}
if device.Trust == crypto.TrustStateVerified {
cmd.Reply("That device is already verified")
return
}
if len(cmd.Args) == 2 {
mach := cmd.Matrix.Crypto().(*crypto.OlmMachine)
mach.DefaultSASTimeout = 120 * time.Second
modal := NewVerificationModal(cmd.MainView, device, mach.DefaultSASTimeout)
cmd.MainView.ShowModal(modal)
err := mach.NewSimpleSASVerificationWith(device, modal)
if err != nil {
cmd.Reply("Failed to start interactive verification: %v", err)
return
}
} else {
fingerprint := strings.Join(cmd.Args[2:], "")
if string(device.SigningKey) != fingerprint {
cmd.Reply("Mismatching fingerprint")
return
}
action := "verified"
if device.Trust == crypto.TrustStateBlacklisted {
action = "unblacklisted and verified"
}
device.Trust = crypto.TrustStateVerified
putDevice(cmd, device, action)
}
}
func cmdUnverify(cmd *Command) {
device := getDevice(cmd)
if device == nil {
return
}
if device.Trust == crypto.TrustStateUnset {
cmd.Reply("That device is already not verified")
return
}
action := "unverified"
if device.Trust == crypto.TrustStateBlacklisted {
action = "unblacklisted"
}
device.Trust = crypto.TrustStateUnset
putDevice(cmd, device, action)
}
func cmdBlacklist(cmd *Command) {
device := getDevice(cmd)
if device == nil {
return
}
if device.Trust == crypto.TrustStateBlacklisted {
cmd.Reply("That device is already blacklisted")
return
}
action := "blacklisted"
if device.Trust == crypto.TrustStateVerified {
action = "unverified and blacklisted"
}
device.Trust = crypto.TrustStateBlacklisted
putDevice(cmd, device, action)
}
func cmdResetSession(cmd *Command) {
err := cmd.Matrix.Crypto().(*crypto.OlmMachine).CryptoStore.RemoveOutboundGroupSession(cmd.Room.Room.ID)
if err != nil {
cmd.Reply("Failed to remove outbound group session: %v", err)
} else {
cmd.Reply("Removed outbound group session for this room")
}
}
// endregion
func cmdHeapProfile(cmd *Command) { func cmdHeapProfile(cmd *Command) {
if len(cmd.Args) == 0 || cmd.Args[0] != "nogc" { if len(cmd.Args) == 0 || cmd.Args[0] != "nogc" {
runtime.GC() runtime.GC()

231
ui/crypto-commands.go Normal file
View File

@ -0,0 +1,231 @@
// gomuks - A terminal Matrix client written in Go.
// Copyright (C) 2020 Tulir Asokan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// +build cgo
package ui
import (
"fmt"
"strings"
"time"
"unicode"
"maunium.net/go/mautrix/crypto"
"maunium.net/go/mautrix/id"
)
func autocompleteDeviceUserID(cmd *CommandAutocomplete) (completions []string, newText string) {
userCompletions := cmd.Room.AutocompleteUser(cmd.Args[0])
if len(userCompletions) == 1 {
newText = fmt.Sprintf("/%s %s ", cmd.OrigCommand, userCompletions[0].id)
} else {
completions = make([]string, len(userCompletions))
for i, completion := range userCompletions {
completions[i] = completion.id
}
}
return
}
func autocompleteDeviceDeviceID(cmd *CommandAutocomplete) (completions []string, newText string) {
mach := cmd.Matrix.Crypto().(*crypto.OlmMachine)
devices, err := mach.CryptoStore.GetDevices(id.UserID(cmd.Args[0]))
if len(devices) == 0 || err != nil {
return
}
var completedDeviceID id.DeviceID
if len(cmd.Args) > 1 {
existingID := strings.ToUpper(cmd.Args[1])
for _, device := range devices {
deviceIDStr := string(device.DeviceID)
if deviceIDStr == existingID {
// We don't want to do any autocompletion if there's already a full device ID there.
return []string{}, ""
} else if strings.HasPrefix(strings.ToUpper(device.Name), existingID) || strings.HasPrefix(deviceIDStr, existingID) {
completedDeviceID = device.DeviceID
completions = append(completions, fmt.Sprintf("%s (%s)", device.DeviceID, device.Name))
}
}
} else {
completions = make([]string, len(devices))
i := 0
for _, device := range devices {
completedDeviceID = device.DeviceID
completions[i] = fmt.Sprintf("%s (%s)", device.DeviceID, device.Name)
i++
}
}
if len(completions) == 1 {
newText = fmt.Sprintf("/%s %s %s ", cmd.OrigCommand, cmd.Args[0], completedDeviceID)
}
return
}
func autocompleteDevice(cmd *CommandAutocomplete) ([]string, string) {
if len(cmd.Args) == 0 {
return []string{}, ""
} else if len(cmd.Args) == 1 && !unicode.IsSpace(rune(cmd.RawArgs[len(cmd.RawArgs)-1])) {
return autocompleteDeviceUserID(cmd)
} else if cmd.Command != "devices" {
return autocompleteDeviceDeviceID(cmd)
}
return []string{}, ""
}
func getDevice(cmd *Command) *crypto.DeviceIdentity {
if len(cmd.Args) < 2 {
cmd.Reply("Usage: /%s <user id> <device id> [fingerprint]", cmd.Command)
return nil
}
mach := cmd.Matrix.Crypto().(*crypto.OlmMachine)
device, err := mach.GetOrFetchDevice(id.UserID(cmd.Args[0]), id.DeviceID(cmd.Args[1]))
if err != nil {
cmd.Reply("Failed to get device: %v", err)
return nil
}
return device
}
func putDevice(cmd *Command, device *crypto.DeviceIdentity, action string) {
mach := cmd.Matrix.Crypto().(*crypto.OlmMachine)
err := mach.CryptoStore.PutDevice(device.UserID, device)
if err != nil {
cmd.Reply("Failed to save device: %v", err)
} else {
cmd.Reply("Successfully %s %s/%s (%s)", action, device.UserID, device.DeviceID, device.Name)
}
mach.OnDevicesChanged(device.UserID)
}
func cmdDevices(cmd *Command) {
if len(cmd.Args) == 0 {
cmd.Reply("Usage: /devices <user id>")
return
}
userID := id.UserID(cmd.Args[0])
mach := cmd.Matrix.Crypto().(*crypto.OlmMachine)
devices, err := mach.CryptoStore.GetDevices(userID)
if err != nil {
cmd.Reply("Failed to get device list: %v", err)
}
if len(devices) == 0 {
cmd.Reply("Fetching device list from server...")
devices = mach.LoadDevices(userID)
}
if len(devices) == 0 {
cmd.Reply("No devices found for %s", userID)
return
}
var buf strings.Builder
for _, device := range devices {
_, _ = fmt.Fprintf(&buf, "%s (%s) - %s\n Fingerprint: %s\n", device.DeviceID, device.Name, device.Trust.String(), device.Fingerprint())
}
resp := buf.String()
cmd.Reply("%s", resp[:len(resp)-1])
}
func cmdDevice(cmd *Command) {
device := getDevice(cmd)
if device == nil {
return
}
deviceType := "Device"
if device.Deleted {
deviceType = "Deleted device"
}
cmd.Reply("%s %s of %s\nFingerprint: %s\nIdentity key: %s\nDevice name: %s\nTrust state: %s",
deviceType, device.DeviceID, device.UserID,
device.Fingerprint(), device.IdentityKey,
device.Name, device.Trust.String())
}
func cmdVerify(cmd *Command) {
device := getDevice(cmd)
if device == nil {
return
}
if device.Trust == crypto.TrustStateVerified {
cmd.Reply("That device is already verified")
return
}
if len(cmd.Args) == 2 {
mach := cmd.Matrix.Crypto().(*crypto.OlmMachine)
mach.DefaultSASTimeout = 120 * time.Second
modal := NewVerificationModal(cmd.MainView, device, mach.DefaultSASTimeout)
cmd.MainView.ShowModal(modal)
_, err := mach.NewSimpleSASVerificationWith(device, modal)
if err != nil {
cmd.Reply("Failed to start interactive verification: %v", err)
return
}
} else {
fingerprint := strings.Join(cmd.Args[2:], "")
if string(device.SigningKey) != fingerprint {
cmd.Reply("Mismatching fingerprint")
return
}
action := "verified"
if device.Trust == crypto.TrustStateBlacklisted {
action = "unblacklisted and verified"
}
device.Trust = crypto.TrustStateVerified
putDevice(cmd, device, action)
}
}
func cmdUnverify(cmd *Command) {
device := getDevice(cmd)
if device == nil {
return
}
if device.Trust == crypto.TrustStateUnset {
cmd.Reply("That device is already not verified")
return
}
action := "unverified"
if device.Trust == crypto.TrustStateBlacklisted {
action = "unblacklisted"
}
device.Trust = crypto.TrustStateUnset
putDevice(cmd, device, action)
}
func cmdBlacklist(cmd *Command) {
device := getDevice(cmd)
if device == nil {
return
}
if device.Trust == crypto.TrustStateBlacklisted {
cmd.Reply("That device is already blacklisted")
return
}
action := "blacklisted"
if device.Trust == crypto.TrustStateVerified {
action = "unverified and blacklisted"
}
device.Trust = crypto.TrustStateBlacklisted
putDevice(cmd, device, action)
}
func cmdResetSession(cmd *Command) {
err := cmd.Matrix.Crypto().(*crypto.OlmMachine).CryptoStore.RemoveOutboundGroupSession(cmd.Room.Room.ID)
if err != nil {
cmd.Reply("Failed to remove outbound group session: %v", err)
} else {
cmd.Reply("Removed outbound group session for this room")
}
}

36
ui/no-crypto-commands.go Normal file
View File

@ -0,0 +1,36 @@
// gomuks - A terminal Matrix client written in Go.
// Copyright (C) 2020 Tulir Asokan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// +build !cgo
package ui
func autocompleteDevice(cmd *CommandAutocomplete) ([]string, string) {
return []string{}, ""
}
func cmdNoCrypto(cmd *Command) {
cmd.Reply("This gomuks was built without encryption support")
}
var (
cmdDevices = cmdNoCrypto
cmdDevice = cmdNoCrypto
cmdVerify = cmdNoCrypto
cmdUnverify = cmdNoCrypto
cmdBlacklist = cmdNoCrypto
cmdResetSession = cmdNoCrypto
)

View File

@ -629,8 +629,6 @@ func (view *RoomView) InputTabComplete(text string, cursorOffset int) {
return return
} }
debug.Print("Tab completing", cursorOffset, text)
str := runewidth.Truncate(text, cursorOffset, "") str := runewidth.Truncate(text, cursorOffset, "")
word := findWordToTabComplete(str) word := findWordToTabComplete(str)
startIndex := len(str) - len(word) startIndex := len(str) - len(word)

View File

@ -14,6 +14,8 @@
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
// +build cgo
package ui package ui
import ( import (
@ -32,14 +34,17 @@ import (
type EmojiView struct { type EmojiView struct {
mauview.SimpleEventHandler mauview.SimpleEventHandler
Numbers *[3]uint Data crypto.SASData
Emojis *[7]crypto.VerificationEmoji
} }
func (e *EmojiView) Draw(screen mauview.Screen) { func (e *EmojiView) Draw(screen mauview.Screen) {
if e.Emojis != nil { if e.Data == nil {
return
}
switch e.Data.Type() {
case event.SASEmoji:
width := 10 width := 10
for i, emoji := range e.Emojis { for i, emoji := range e.Data.(crypto.EmojiSASData) {
x := i*width + i x := i*width + i
y := 0 y := 0
if i >= 4 { if i >= 4 {
@ -49,9 +54,9 @@ func (e *EmojiView) Draw(screen mauview.Screen) {
mauview.Print(screen, string(emoji.Emoji), x, y, width, mauview.AlignCenter, tcell.ColorDefault) mauview.Print(screen, string(emoji.Emoji), x, y, width, mauview.AlignCenter, tcell.ColorDefault)
mauview.Print(screen, emoji.Description, x, y+1, width, mauview.AlignCenter, tcell.ColorDefault) mauview.Print(screen, emoji.Description, x, y+1, width, mauview.AlignCenter, tcell.ColorDefault)
} }
} else if e.Numbers != nil { case event.SASDecimal:
maxWidth := 43 maxWidth := 43
for i, number := range e.Numbers { for i, number := range e.Data.(crypto.DecimalSASData) {
mauview.Print(screen, strconv.FormatUint(uint64(number), 10), 0, i, maxWidth, mauview.AlignCenter, tcell.ColorDefault) mauview.Print(screen, strconv.FormatUint(uint64(number), 10), 0, i, maxWidth, mauview.AlignCenter, tcell.ColorDefault)
} }
} }
@ -69,6 +74,8 @@ type VerificationModal struct {
emojiText *EmojiView emojiText *EmojiView
inputBar *mauview.InputField inputBar *mauview.InputField
progress int
progressMax int
stopWaiting chan struct{} stopWaiting chan struct{}
confirmChan chan bool confirmChan chan bool
done bool done bool
@ -85,14 +92,15 @@ func NewVerificationModal(mainView *MainView, device *crypto.DeviceIdentity, tim
done: false, done: false,
} }
progress := int(timeout.Seconds()) vm.progressMax = int(timeout.Seconds())
vm.progress = vm.progressMax
vm.waitingBar = mauview.NewProgressBar(). vm.waitingBar = mauview.NewProgressBar().
SetMax(progress). SetMax(vm.progressMax).
SetProgress(progress). SetProgress(vm.progress).
SetIndeterminate(false) SetIndeterminate(false)
vm.infoText = mauview.NewTextView() vm.infoText = mauview.NewTextView()
vm.infoText.SetText(fmt.Sprintf("Waiting for %s to accept", device.UserID)) vm.infoText.SetText(fmt.Sprintf("Waiting for %s\nto accept", device.UserID))
vm.emojiText = &EmojiView{} vm.emojiText = &EmojiView{}
@ -113,59 +121,58 @@ func NewVerificationModal(mainView *MainView, device *crypto.DeviceIdentity, tim
vm.Component = mauview.Center(vm.container, 45, 12).SetAlwaysFocusChild(true) vm.Component = mauview.Center(vm.container, 45, 12).SetAlwaysFocusChild(true)
go vm.decrementWaitingBar(progress) go vm.decrementWaitingBar()
return vm return vm
} }
func (vm *VerificationModal) decrementWaitingBar(progress int) { func (vm *VerificationModal) decrementWaitingBar() {
for { for {
select { select {
case <-time.Tick(time.Second): case <-time.Tick(time.Second):
if progress <= 0 { if vm.progress <= 0 {
vm.waitingBar.SetIndeterminate(true)
vm.parent.parent.app.SetRedrawTicker(100 * time.Millisecond)
return return
} }
progress-- vm.progress--
vm.waitingBar.SetProgress(progress) vm.waitingBar.SetProgress(vm.progress)
vm.parent.parent.Render() vm.parent.parent.Render()
case <-vm.stopWaiting: case <-vm.stopWaiting:
vm.waitingBar.SetIndeterminate(true)
vm.parent.parent.app.SetRedrawTicker(100 * time.Millisecond)
return return
} }
} }
} }
func (vm *VerificationModal) VerifyEmojisMatch(emojis [7]crypto.VerificationEmoji) bool { func (vm *VerificationModal) VerificationMethods() []crypto.VerificationMethod {
vm.infoText.SetText("Check if the other device is showing the\nsame emojis as below, then type \"yes\" to\naccept, or \"no\" to reject") return []crypto.VerificationMethod{crypto.VerificationMethodEmoji{}, crypto.VerificationMethodDecimal{}}
vm.inputBar.
SetTextColor(tcell.ColorWhite).
SetBackgroundColor(tcell.ColorDarkCyan).
SetPlaceholder("Type \"yes\" or \"no\"").
Focus()
vm.emojiText.Emojis = &emojis
vm.parent.parent.Render()
vm.stopWaiting <- struct{}{}
confirm := <-vm.confirmChan
vm.emojiText.Emojis = nil
vm.infoText.SetText(fmt.Sprintf("Waiting for %s to accept", vm.device.UserID))
vm.parent.parent.Render()
return confirm
} }
func (vm *VerificationModal) VerifyNumbersMatch(numbers [3]uint) bool { func (vm *VerificationModal) VerifySASMatch(_ *crypto.DeviceIdentity, data crypto.SASData) bool {
vm.infoText.SetText("Check if the other device is showing the\nsame numbers as below, then type \"yes\" to\naccept, or \"no\" to reject") var typeName string
if data.Type() == event.SASDecimal {
typeName = "numbers"
} else if data.Type() == event.SASEmoji {
typeName = "emojis"
} else {
return false
}
vm.infoText.SetText(fmt.Sprintf(
"Check if the other device is showing the\n"+
"same %s as below, then type \"yes\" to\n"+
"accept, or \"no\" to reject", typeName))
vm.inputBar. vm.inputBar.
SetTextColor(tcell.ColorWhite). SetTextColor(tcell.ColorWhite).
SetBackgroundColor(tcell.ColorDarkCyan). SetBackgroundColor(tcell.ColorDarkCyan).
SetPlaceholder("Type \"yes\" or \"no\""). SetPlaceholder("Type \"yes\" or \"no\"").
Focus() Focus()
vm.emojiText.Numbers = &numbers vm.emojiText.Data = data
vm.parent.parent.Render() vm.parent.parent.Render()
vm.stopWaiting <- struct{}{} vm.progress = vm.progressMax
confirm := <-vm.confirmChan confirm := <-vm.confirmChan
vm.emojiText.Numbers = nil vm.progress = vm.progressMax
vm.infoText.SetText(fmt.Sprintf("Waiting for %s to accept", vm.device.UserID)) vm.emojiText.Data = nil
vm.infoText.SetText(fmt.Sprintf("Waiting for %s\nto confirm", vm.device.UserID))
vm.parent.parent.Render() vm.parent.parent.Render()
return confirm return confirm
} }
@ -179,6 +186,7 @@ func (vm *VerificationModal) OnCancel(cancelledByUs bool, reason string, _ event
vm.infoText.SetText(fmt.Sprintf("Verification cancelled by %s: %s", vm.device.UserID, reason)) vm.infoText.SetText(fmt.Sprintf("Verification cancelled by %s: %s", vm.device.UserID, reason))
} }
vm.inputBar.SetPlaceholder("Press enter to close the dialog") vm.inputBar.SetPlaceholder("Press enter to close the dialog")
vm.stopWaiting <- struct{}{}
vm.done = true vm.done = true
vm.parent.parent.Render() vm.parent.parent.Render()
} }
@ -188,6 +196,7 @@ func (vm *VerificationModal) OnSuccess() {
vm.parent.parent.app.SetRedrawTicker(1 * time.Minute) vm.parent.parent.app.SetRedrawTicker(1 * time.Minute)
vm.infoText.SetText(fmt.Sprintf("Successfully verified %s (%s) of %s", vm.device.Name, vm.device.DeviceID, vm.device.UserID)) vm.infoText.SetText(fmt.Sprintf("Successfully verified %s (%s) of %s", vm.device.Name, vm.device.DeviceID, vm.device.UserID))
vm.inputBar.SetPlaceholder("Press enter to close the dialog") vm.inputBar.SetPlaceholder("Press enter to close the dialog")
vm.stopWaiting <- struct{}{}
vm.done = true vm.done = true
vm.parent.parent.Render() vm.parent.parent.Render()
if vm.parent.config.SendToVerifiedOnly { if vm.parent.config.SendToVerifiedOnly {
@ -203,7 +212,7 @@ func (vm *VerificationModal) OnKeyEvent(event mauview.KeyEvent) bool {
return true return true
} }
return false return false
} else if vm.emojiText.Emojis == nil && vm.emojiText.Numbers == nil { } else if vm.emojiText.Data == nil {
debug.Print("Ignoring pre-emoji key event") debug.Print("Ignoring pre-emoji key event")
return false return false
} }
@ -216,8 +225,11 @@ func (vm *VerificationModal) OnKeyEvent(event mauview.KeyEvent) bool {
debug.Print("Rejecting verification") debug.Print("Rejecting verification")
vm.confirmChan <- false vm.confirmChan <- false
} }
vm.inputBar.SetPlaceholder("") vm.inputBar.
vm.inputBar.SetTextAndMoveCursor("") SetPlaceholder("").
SetTextAndMoveCursor("").
SetBackgroundColor(tcell.ColorDefault).
SetTextColor(tcell.ColorDefault)
return true return true
} else { } else {
return vm.inputBar.OnKeyEvent(event) return vm.inputBar.OnKeyEvent(event)