Add initial support for key file exporting and importing

Warning: the passphrase is currently hardcoded to "gomuks"
This commit is contained in:
Tulir Asokan 2020-08-25 21:09:44 +03:00
parent 167cc37b2d
commit 0a9612bf14
6 changed files with 83 additions and 5 deletions

2
go.mod
View File

@ -23,7 +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.7.1 maunium.net/go/mautrix v0.7.3
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
) )

3
go.sum
View File

@ -75,6 +75,7 @@ github.com/zyedidia/clipboard v0.0.0-20200421031010-7c45b8673834/go.mod h1:zykFn
github.com/zyedidia/poller v1.0.1/go.mod h1:vZXJOHGDcuK08GXhF6IAY0ZFd2WcgOR5DOTp84Uk5eE= github.com/zyedidia/poller v1.0.1/go.mod h1:vZXJOHGDcuK08GXhF6IAY0ZFd2WcgOR5DOTp84Uk5eE=
go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg= go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg=
go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20200430140353-33d19683fad8 h1:6WW6V3x1P/jokJBpRQYUJnMHRP6isStQwCozxnU7XQw= golang.org/x/image v0.0.0-20200430140353-33d19683fad8 h1:6WW6V3x1P/jokJBpRQYUJnMHRP6isStQwCozxnU7XQw=
@ -118,6 +119,8 @@ maunium.net/go/mautrix v0.7.0 h1:9Wxs5S4Wl4S99dbBwfLZYAe/sP7VKaFikw9Ocf88kfk=
maunium.net/go/mautrix v0.7.0/go.mod h1:Va/74MijqaS0DQ3aUqxmFO54/PMfr1LVsCOcGRHbYmo= maunium.net/go/mautrix v0.7.0/go.mod h1:Va/74MijqaS0DQ3aUqxmFO54/PMfr1LVsCOcGRHbYmo=
maunium.net/go/mautrix v0.7.1 h1:ctoAVWUPs0D1AADzuA3KLmaRONnSY61mdUoP2smNqe4= maunium.net/go/mautrix v0.7.1 h1:ctoAVWUPs0D1AADzuA3KLmaRONnSY61mdUoP2smNqe4=
maunium.net/go/mautrix v0.7.1/go.mod h1:Va/74MijqaS0DQ3aUqxmFO54/PMfr1LVsCOcGRHbYmo= maunium.net/go/mautrix v0.7.1/go.mod h1:Va/74MijqaS0DQ3aUqxmFO54/PMfr1LVsCOcGRHbYmo=
maunium.net/go/mautrix v0.7.3 h1:yC287SXL0pTZzAtpGIvwtlxPHZsWMuq2DmI5/POTKFE=
maunium.net/go/mautrix v0.7.3/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

@ -105,10 +105,13 @@ func NewCommandProcessor(parent *MainView) *CommandProcessor {
"o": {"open"}, "o": {"open"},
}, },
autocompleters: map[string]CommandAutocompleter{ autocompleters: map[string]CommandAutocompleter{
"devices": autocompleteDevice, "devices": autocompleteDevice,
"device": autocompleteDevice, "device": autocompleteDevice,
"verify": autocompleteDevice, "verify": autocompleteDevice,
"unverify": autocompleteDevice, "unverify": autocompleteDevice,
"import": autocompleteFile,
"export": autocompleteFile,
"export-room": autocompleteFile,
}, },
commands: map[string]CommandHandler{ commands: map[string]CommandHandler{
"unknown-command": cmdUnknownCommand, "unknown-command": cmdUnknownCommand,
@ -159,6 +162,9 @@ func NewCommandProcessor(parent *MainView) *CommandProcessor {
"unverify": cmdUnverify, "unverify": cmdUnverify,
"blacklist": cmdBlacklist, "blacklist": cmdBlacklist,
"reset-session": cmdResetSession, "reset-session": cmdResetSession,
"import": cmdImportKeys,
"export": cmdExportKeys,
"export-room": cmdExportRoomKeys,
}, },
} }
} }

View File

@ -461,6 +461,11 @@ Things: rooms, users, baremessages, images, typingnotif, unverified
/verify <user id> <device id> [fingerprint] /verify <user id> <device id> [fingerprint]
- Verify a device. If the fingerprint is not provided, - Verify a device. If the fingerprint is not provided,
interactive emoji verification will be started. interactive emoji verification will be started.
/reset-session - Reset the outbound Megolm session in the current room.
/import <file> - Import encryption keys
/export <file> - Export encryption keys
/export-room <file> - Export encryption keys for the current room.
# Rooms # Rooms
/pm <user id> <...> - Create a private chat with the given user(s). /pm <user id> <...> - Create a private chat with the given user(s).

View File

@ -20,6 +20,7 @@ package ui
import ( import (
"fmt" "fmt"
"io/ioutil"
"strings" "strings"
"time" "time"
"unicode" "unicode"
@ -229,3 +230,59 @@ func cmdResetSession(cmd *Command) {
cmd.Reply("Removed outbound group session for this room") cmd.Reply("Removed outbound group session for this room")
} }
} }
func autocompleteFile(cmd *CommandAutocomplete) (completions []string, newText string) {
// TODO implement
return []string{}, ""
}
// TODO add dialog for asking passphrase
const extremelyTemporaryHardcodedPassphrase = "gomuks"
func cmdImportKeys(cmd *Command) {
data, err := ioutil.ReadFile(cmd.RawArgs)
if err != nil {
cmd.Reply("Failed to read %s: %v", cmd.RawArgs, err)
return
}
mach := cmd.Matrix.Crypto().(*crypto.OlmMachine)
imported, total, err := mach.ImportKeys(extremelyTemporaryHardcodedPassphrase, string(data))
if err != nil {
cmd.Reply("Failed to import sessions: %v", err)
} else {
cmd.Reply("Successfully imported %d/%d sessions", imported, total)
}
}
func exportKeys(cmd *Command, sessions []*crypto.InboundGroupSession) {
export, err := crypto.ExportKeys(extremelyTemporaryHardcodedPassphrase, sessions)
if err != nil {
cmd.Reply("Failed to export sessions: %v", err)
}
err = ioutil.WriteFile(cmd.RawArgs, []byte(export), 0400)
if err != nil {
cmd.Reply("Failed to write sessions to %s: %v", cmd.RawArgs, err)
} else {
cmd.Reply("Successfully exported %d sessions to %s", len(sessions), cmd.RawArgs)
}
}
func cmdExportKeys(cmd *Command) {
mach := cmd.Matrix.Crypto().(*crypto.OlmMachine)
sessions, err := mach.CryptoStore.GetAllGroupSessions()
if err != nil {
cmd.Reply("Failed to get sessions to export: %v", err)
return
}
exportKeys(cmd, sessions)
}
func cmdExportRoomKeys(cmd *Command) {
mach := cmd.Matrix.Crypto().(*crypto.OlmMachine)
sessions, err := mach.CryptoStore.GetGroupSessionsForRoom(cmd.Room.MxRoom().ID)
if err != nil {
cmd.Reply("Failed to get sessions to export: %v", err)
return
}
exportKeys(cmd, sessions)
}

View File

@ -22,6 +22,10 @@ func autocompleteDevice(cmd *CommandAutocomplete) ([]string, string) {
return []string{}, "" return []string{}, ""
} }
func autocompleteFile(cmd *CommandAutocomplete) ([]string, string) {
return []string{}, ""
}
func cmdNoCrypto(cmd *Command) { func cmdNoCrypto(cmd *Command) {
cmd.Reply("This gomuks was built without encryption support") cmd.Reply("This gomuks was built without encryption support")
} }
@ -33,4 +37,7 @@ var (
cmdUnverify = cmdNoCrypto cmdUnverify = cmdNoCrypto
cmdBlacklist = cmdNoCrypto cmdBlacklist = cmdNoCrypto
cmdResetSession = cmdNoCrypto cmdResetSession = cmdNoCrypto
cmdImportKeys = cmdNoCrypto
cmdExportKeys = cmdNoCrypto
cmdExportRoomKeys = cmdNoCrypto
) )