From 0a9612bf1454fd8e4f662e6f76fd622f81952d7a Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 25 Aug 2020 21:09:44 +0300 Subject: [PATCH] Add initial support for key file exporting and importing Warning: the passphrase is currently hardcoded to "gomuks" --- go.mod | 2 +- go.sum | 3 +++ ui/command-processor.go | 14 +++++++--- ui/commands.go | 5 ++++ ui/crypto-commands.go | 57 ++++++++++++++++++++++++++++++++++++++++ ui/no-crypto-commands.go | 7 +++++ 6 files changed, 83 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 96dde05..8d4dbe0 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( golang.org/x/net v0.0.0-20200602114024-627f9648deb9 gopkg.in/toast.v1 v1.0.0-20180812000517-0a84660828b2 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/tcell v0.2.0 ) diff --git a/go.sum b/go.sum index 4f4e398..ccdd1ff 100644 --- a/go.sum +++ b/go.sum @@ -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= go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg= 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/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 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.1 h1:ctoAVWUPs0D1AADzuA3KLmaRONnSY61mdUoP2smNqe4= 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/go.mod h1:3QBUiuLct9moP1LgDhCGIg0Ovxn38Bd2sGndnUOuj4o= maunium.net/go/tcell v0.2.0 h1:1Q0kN3wCOGAIGu1r3QHADsjSUOPDylKREvCv3EzJpVg= diff --git a/ui/command-processor.go b/ui/command-processor.go index 514d67b..ee2222f 100644 --- a/ui/command-processor.go +++ b/ui/command-processor.go @@ -105,10 +105,13 @@ func NewCommandProcessor(parent *MainView) *CommandProcessor { "o": {"open"}, }, autocompleters: map[string]CommandAutocompleter{ - "devices": autocompleteDevice, - "device": autocompleteDevice, - "verify": autocompleteDevice, - "unverify": autocompleteDevice, + "devices": autocompleteDevice, + "device": autocompleteDevice, + "verify": autocompleteDevice, + "unverify": autocompleteDevice, + "import": autocompleteFile, + "export": autocompleteFile, + "export-room": autocompleteFile, }, commands: map[string]CommandHandler{ "unknown-command": cmdUnknownCommand, @@ -159,6 +162,9 @@ func NewCommandProcessor(parent *MainView) *CommandProcessor { "unverify": cmdUnverify, "blacklist": cmdBlacklist, "reset-session": cmdResetSession, + "import": cmdImportKeys, + "export": cmdExportKeys, + "export-room": cmdExportRoomKeys, }, } } diff --git a/ui/commands.go b/ui/commands.go index d9469fc..3a77f67 100644 --- a/ui/commands.go +++ b/ui/commands.go @@ -461,6 +461,11 @@ Things: rooms, users, baremessages, images, typingnotif, unverified /verify [fingerprint] - Verify a device. If the fingerprint is not provided, interactive emoji verification will be started. +/reset-session - Reset the outbound Megolm session in the current room. + +/import - Import encryption keys +/export - Export encryption keys +/export-room - Export encryption keys for the current room. # Rooms /pm <...> - Create a private chat with the given user(s). diff --git a/ui/crypto-commands.go b/ui/crypto-commands.go index 232f508..f13217c 100644 --- a/ui/crypto-commands.go +++ b/ui/crypto-commands.go @@ -20,6 +20,7 @@ package ui import ( "fmt" + "io/ioutil" "strings" "time" "unicode" @@ -229,3 +230,59 @@ func cmdResetSession(cmd *Command) { 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) +} diff --git a/ui/no-crypto-commands.go b/ui/no-crypto-commands.go index dae85b4..781eb9f 100644 --- a/ui/no-crypto-commands.go +++ b/ui/no-crypto-commands.go @@ -22,6 +22,10 @@ func autocompleteDevice(cmd *CommandAutocomplete) ([]string, string) { return []string{}, "" } +func autocompleteFile(cmd *CommandAutocomplete) ([]string, string) { + return []string{}, "" +} + func cmdNoCrypto(cmd *Command) { cmd.Reply("This gomuks was built without encryption support") } @@ -33,4 +37,7 @@ var ( cmdUnverify = cmdNoCrypto cmdBlacklist = cmdNoCrypto cmdResetSession = cmdNoCrypto + cmdImportKeys = cmdNoCrypto + cmdExportKeys = cmdNoCrypto + cmdExportRoomKeys = cmdNoCrypto )