Extremely WIP cross-signing and SSSS support
This commit is contained in:
		
							
								
								
									
										3
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								go.mod
									
									
									
									
									
								
							@@ -27,3 +27,6 @@ require (
 | 
			
		||||
	maunium.net/go/mauview v0.1.1
 | 
			
		||||
	maunium.net/go/tcell v0.2.0
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//replace maunium.net/go/mautrix => ../mautrix-go
 | 
			
		||||
replace maunium.net/go/mautrix => github.com/nikofil/mautrix-go v0.5.2-0.20200911223256-b40ab761fadc
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										50
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										50
									
								
								go.sum
									
									
									
									
									
								
							@@ -1,28 +1,42 @@
 | 
			
		||||
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
 | 
			
		||||
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U=
 | 
			
		||||
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
 | 
			
		||||
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI=
 | 
			
		||||
github.com/alecthomas/chroma v0.8.0 h1:HS+HE97sgcqjQGu5uVr8jIE55Mmh5UeQ7kckAhHg2pY=
 | 
			
		||||
github.com/alecthomas/chroma v0.8.0/go.mod h1:sko8vR34/90zvl5QdcUdvzL3J8NKjAUx9va9jPuFNoM=
 | 
			
		||||
github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721 h1:JHZL0hZKJ1VENNfmXvHbgYlbUOvpzYzvy2aZU5gXVeo=
 | 
			
		||||
github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0=
 | 
			
		||||
github.com/alecthomas/kong v0.2.4/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE=
 | 
			
		||||
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 h1:p9Sln00KOTlrYkxI1zYWl1QLnEqAqEARBEYa8FQnQcY=
 | 
			
		||||
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
 | 
			
		||||
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
 | 
			
		||||
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
 | 
			
		||||
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
 | 
			
		||||
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
 | 
			
		||||
github.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2uts=
 | 
			
		||||
github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts=
 | 
			
		||||
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
 | 
			
		||||
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
 | 
			
		||||
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
 | 
			
		||||
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
 | 
			
		||||
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
 | 
			
		||||
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ=
 | 
			
		||||
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk=
 | 
			
		||||
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 | 
			
		||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 | 
			
		||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 | 
			
		||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 | 
			
		||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
 | 
			
		||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
 | 
			
		||||
github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk=
 | 
			
		||||
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
 | 
			
		||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 | 
			
		||||
github.com/gabriel-vasile/mimetype v1.1.1 h1:qbN9MPuRf3bstHu9zkI9jDWNfH//9+9kHxr9oRBBBOA=
 | 
			
		||||
github.com/gabriel-vasile/mimetype v1.1.1/go.mod h1:6CDPel/o/3/s4+bp6kIbsWATq8pmgOisOPG40CJa6To=
 | 
			
		||||
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
 | 
			
		||||
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
 | 
			
		||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 | 
			
		||||
github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
 | 
			
		||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 | 
			
		||||
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
 | 
			
		||||
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
 | 
			
		||||
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
 | 
			
		||||
github.com/kyokomi/emoji v2.2.2+incompatible h1:gaQFbK2+uSxOR4iGZprJAbpmtqTrHhSdgOyIMD6Oidc=
 | 
			
		||||
github.com/kyokomi/emoji v2.2.2+incompatible/go.mod h1:mZ6aGCD7yk8j6QY6KICwnZ2pxoszVseX1DNoGtU2tBA=
 | 
			
		||||
github.com/lib/pq v1.7.0 h1:h93mCPfUSkaul3Ka/VG8uZdmW1uMHDGxzu0NWHuJmHY=
 | 
			
		||||
@@ -32,20 +46,21 @@ github.com/lithammer/fuzzysearch v1.1.0/go.mod h1:Bqx4wo8lTOFcJr3ckpY6HA9lEIOO0H
 | 
			
		||||
github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac=
 | 
			
		||||
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
 | 
			
		||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
 | 
			
		||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
 | 
			
		||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
 | 
			
		||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
 | 
			
		||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
 | 
			
		||||
github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
 | 
			
		||||
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
 | 
			
		||||
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ=
 | 
			
		||||
github.com/nikofil/mautrix-go v0.5.2-0.20200911223256-b40ab761fadc h1:Un166sriSTE07vajPm+iv+oHmBIH3b4PW2LO1fhRyKc=
 | 
			
		||||
github.com/nikofil/mautrix-go v0.5.2-0.20200911223256-b40ab761fadc/go.mod h1:xd0D0ekVts/UDBbjeDSs4wGlBfcarJDg0MMhVgHbxhs=
 | 
			
		||||
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U=
 | 
			
		||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 | 
			
		||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 | 
			
		||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
 | 
			
		||||
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ=
 | 
			
		||||
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o=
 | 
			
		||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 | 
			
		||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 | 
			
		||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 | 
			
		||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 | 
			
		||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 | 
			
		||||
github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY=
 | 
			
		||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
 | 
			
		||||
@@ -53,15 +68,12 @@ github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0
 | 
			
		||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 | 
			
		||||
github.com/sasha-s/go-deadlock v0.2.0 h1:lMqc+fUb7RrFS3gQLtoQsJ7/6TV/pAIFvBsqX73DK8Y=
 | 
			
		||||
github.com/sasha-s/go-deadlock v0.2.0/go.mod h1:StQn567HiB1fF2yJ44N9au7wOhrPS3iZqiDbRupzT10=
 | 
			
		||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
 | 
			
		||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
 | 
			
		||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
 | 
			
		||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
 | 
			
		||||
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
 | 
			
		||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 | 
			
		||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 | 
			
		||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 | 
			
		||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
 | 
			
		||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 | 
			
		||||
github.com/tidwall/gjson v1.6.0 h1:9VEQWz6LLMUsUl6PueE49ir4Ka6CzLymOAZDxpFsTDc=
 | 
			
		||||
github.com/tidwall/gjson v1.6.0/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls=
 | 
			
		||||
@@ -74,25 +86,27 @@ github.com/tidwall/sjson v1.1.1 h1:7h1vk049Jnd5EH9NyzNiEuwYW4b5qgreBbqRC19AS3U=
 | 
			
		||||
github.com/tidwall/sjson v1.1.1/go.mod h1:yvVuSnpEQv5cYIrO+AT6kw4QVfd5SDZoGIS7/5+fZFs=
 | 
			
		||||
github.com/zyedidia/clipboard v0.0.0-20200421031010-7c45b8673834 h1:0nOfq3JwYRiY3+nwfWVQYEaXDmGCQgj3RKoqTifLzP4=
 | 
			
		||||
github.com/zyedidia/clipboard v0.0.0-20200421031010-7c45b8673834/go.mod h1:zykFnZUXX0ErxqvYLUFEq7QDJKId8rmh2FgD0/Y8cjA=
 | 
			
		||||
github.com/zyedidia/poller v1.0.1 h1:Tt9S3AxAjXwWGNiC2TUdRJkQDZSzCBNVQ4xXiQ7440s=
 | 
			
		||||
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-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 | 
			
		||||
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/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 | 
			
		||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 | 
			
		||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 | 
			
		||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 | 
			
		||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 | 
			
		||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 | 
			
		||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM=
 | 
			
		||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 | 
			
		||||
golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
 | 
			
		||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 | 
			
		||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 | 
			
		||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 | 
			
		||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 | 
			
		||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
@@ -106,19 +120,17 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
			
		||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
 | 
			
		||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 | 
			
		||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 | 
			
		||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 | 
			
		||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 | 
			
		||||
gopkg.in/toast.v1 v1.0.0-20180812000517-0a84660828b2 h1:MZF6J7CV6s/h0HBkfqebrYfKCVEo5iN+wzE4QhV3Evo=
 | 
			
		||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
 | 
			
		||||
gopkg.in/toast.v1 v1.0.0-20180812000517-0a84660828b2/go.mod h1:s1Sn2yZos05Qfs7NKt867Xe18emOmtsO3eAKbDaon0o=
 | 
			
		||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
 | 
			
		||||
gopkg.in/vansante/go-ffprobe.v2 v2.0.2 h1:DdxSfFnlqeawPIVbIQEI6LR6OQHQNR7tNgWb2mWuC4w=
 | 
			
		||||
gopkg.in/vansante/go-ffprobe.v2 v2.0.2/go.mod h1:qF0AlAjk7Nqzqf3y333Ly+KxN3cKF2JqA3JT5ZheUGE=
 | 
			
		||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 | 
			
		||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
 | 
			
		||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 | 
			
		||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
 | 
			
		||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 | 
			
		||||
maunium.net/go/maulogger/v2 v2.1.1/go.mod h1:TYWy7wKwz/tIXTpsx8G3mZseIRiC5DoMxSZazOHy68A=
 | 
			
		||||
maunium.net/go/mautrix v0.7.6 h1:jB9oCimPq0mVyolwQBC/9N1fu21AU+Ryq837cLf4gOo=
 | 
			
		||||
maunium.net/go/mautrix v0.7.6/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=
 | 
			
		||||
 
 | 
			
		||||
@@ -51,6 +51,7 @@ type MatrixContainer interface {
 | 
			
		||||
 | 
			
		||||
	Login(user, password string) error
 | 
			
		||||
	Logout()
 | 
			
		||||
	UIAFallback(authType mautrix.AuthType, sessionID string) error
 | 
			
		||||
 | 
			
		||||
	SendPreferencesToMatrix()
 | 
			
		||||
	PrepareMarkdownMessage(roomID id.RoomID, msgtype event.MessageType, text, html string, relation *Relation) *muksevt.Event
 | 
			
		||||
 
 | 
			
		||||
@@ -429,8 +429,8 @@ func (c *Container) Start() {
 | 
			
		||||
			return
 | 
			
		||||
		default:
 | 
			
		||||
			if err := c.client.Sync(); err != nil {
 | 
			
		||||
				if httpErr, ok := err.(mautrix.HTTPError); ok && httpErr.Code == http.StatusUnauthorized {
 | 
			
		||||
					debug.Print("Sync() errored with ", err, " -> logging out")
 | 
			
		||||
				if errors.Is(err, mautrix.MUnknownToken) {
 | 
			
		||||
					debug.Print("Sync() errored with", err, "-> logging out")
 | 
			
		||||
					c.Logout()
 | 
			
		||||
				} else {
 | 
			
		||||
					debug.Print("Sync() errored", err)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										114
									
								
								matrix/uia-fallback.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								matrix/uia-fallback.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,114 @@
 | 
			
		||||
// 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/>.
 | 
			
		||||
 | 
			
		||||
package matrix
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"maunium.net/go/mautrix"
 | 
			
		||||
 | 
			
		||||
	"maunium.net/go/gomuks/debug"
 | 
			
		||||
	"maunium.net/go/gomuks/lib/open"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const uiaFallbackPage = `<!DOCTYPE html>
 | 
			
		||||
<html lang="en">
 | 
			
		||||
<head>
 | 
			
		||||
	<title>gomuks user-interactive auth</title>
 | 
			
		||||
	<meta charset="utf-8"/>
 | 
			
		||||
	<style>
 | 
			
		||||
		body {
 | 
			
		||||
			text-align: center;
 | 
			
		||||
		}
 | 
			
		||||
	</style>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
	<h2>Please complete the login in the popup window</h2>
 | 
			
		||||
	<button onclick="openPopup()">Open popup</button>
 | 
			
		||||
	<button onclick="finish(false)">Cancel</button>
 | 
			
		||||
	<script>
 | 
			
		||||
		const url = location.hash.substr(1)
 | 
			
		||||
		let popupWindow
 | 
			
		||||
 | 
			
		||||
		function finish(success) {
 | 
			
		||||
			if (popupWindow) {
 | 
			
		||||
				popupWindow.close()
 | 
			
		||||
			}
 | 
			
		||||
			fetch("", {method: success ? "POST" : "DELETE"}).then(() => window.close())
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		function openPopup() {
 | 
			
		||||
			popupWindow = window.open(url)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		window.addEventListener("message", evt => evt.data === "authDone" && finish(true))
 | 
			
		||||
	</script>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
`
 | 
			
		||||
 | 
			
		||||
func (c *Container) UIAFallback(loginType mautrix.AuthType, sessionID string) error {
 | 
			
		||||
	errChan := make(chan error, 1)
 | 
			
		||||
	server := &http.Server{Addr: ":29325"}
 | 
			
		||||
	server.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		if r.Method == "GET" {
 | 
			
		||||
			w.Header().Add("Content-Type", "text/html")
 | 
			
		||||
			w.WriteHeader(http.StatusOK)
 | 
			
		||||
			_, _ = w.Write([]byte(uiaFallbackPage))
 | 
			
		||||
		} else if r.Method == "POST" || r.Method == "DELETE" {
 | 
			
		||||
			w.Header().Add("Content-Type", "text/html")
 | 
			
		||||
			w.WriteHeader(http.StatusOK)
 | 
			
		||||
 | 
			
		||||
			go func() {
 | 
			
		||||
				ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
 | 
			
		||||
				defer cancel()
 | 
			
		||||
				err := server.Shutdown(ctx)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					debug.Printf("Failed to shut down SSO server: %v\n", err)
 | 
			
		||||
				}
 | 
			
		||||
				if r.Method == "DELETE" {
 | 
			
		||||
					errChan <- errors.New("login cancelled")
 | 
			
		||||
				} else {
 | 
			
		||||
					errChan <- nil
 | 
			
		||||
				}
 | 
			
		||||
			}()
 | 
			
		||||
		} else {
 | 
			
		||||
			w.WriteHeader(http.StatusMethodNotAllowed)
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	go server.ListenAndServe()
 | 
			
		||||
	defer server.Close()
 | 
			
		||||
	authURL := c.client.BuildURLWithQuery(mautrix.URLPath{"auth", loginType, "fallback", "web"}, map[string]string{
 | 
			
		||||
		"session": sessionID,
 | 
			
		||||
	})
 | 
			
		||||
	link := url.URL{
 | 
			
		||||
		Scheme:   "http",
 | 
			
		||||
		Host:     "localhost:29325",
 | 
			
		||||
		Path:     "/",
 | 
			
		||||
		Fragment: authURL,
 | 
			
		||||
	}
 | 
			
		||||
	err := open.Open(link.String())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	err = <-errChan
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
@@ -104,6 +104,9 @@ func NewCommandProcessor(parent *MainView) *CommandProcessor {
 | 
			
		||||
			"e":          {"edit"},
 | 
			
		||||
			"dl":         {"download"},
 | 
			
		||||
			"o":          {"open"},
 | 
			
		||||
			"4s":         {"ssss"},
 | 
			
		||||
			"s4":         {"ssss"},
 | 
			
		||||
			"cs":         {"cross-signing"},
 | 
			
		||||
		},
 | 
			
		||||
		autocompleters: map[string]CommandAutocompleter{
 | 
			
		||||
			"devices":     autocompleteDevice,
 | 
			
		||||
@@ -172,6 +175,8 @@ func NewCommandProcessor(parent *MainView) *CommandProcessor {
 | 
			
		||||
			"import":        cmdImportKeys,
 | 
			
		||||
			"export":        cmdExportKeys,
 | 
			
		||||
			"export-room":   cmdExportRoomKeys,
 | 
			
		||||
			"ssss":          cmdSSSS,
 | 
			
		||||
			"cross-signing": cmdCrossSigning,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,7 @@
 | 
			
		||||
package ui
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
@@ -26,7 +27,10 @@ import (
 | 
			
		||||
	"time"
 | 
			
		||||
	"unicode"
 | 
			
		||||
 | 
			
		||||
	ifc "maunium.net/go/gomuks/interface"
 | 
			
		||||
	"maunium.net/go/mautrix"
 | 
			
		||||
	"maunium.net/go/mautrix/crypto"
 | 
			
		||||
	"maunium.net/go/mautrix/crypto/ssss"
 | 
			
		||||
	"maunium.net/go/mautrix/id"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -243,7 +247,7 @@ func cmdImportKeys(cmd *Command) {
 | 
			
		||||
		cmd.Reply("Failed to read %s: %v", path, err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	passphrase, ok := cmd.MainView.AskPassword("Key import", false)
 | 
			
		||||
	passphrase, ok := cmd.MainView.AskPassword("Key import", "passphrase", "", false)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		cmd.Reply("Passphrase entry cancelled")
 | 
			
		||||
		return
 | 
			
		||||
@@ -263,7 +267,7 @@ func exportKeys(cmd *Command, sessions []*crypto.InboundGroupSession) {
 | 
			
		||||
		cmd.Reply("Failed to get absolute path: %v", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	passphrase, ok := cmd.MainView.AskPassword("Key export", true)
 | 
			
		||||
	passphrase, ok := cmd.MainView.AskPassword("Key export", "passphrase", "", true)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		cmd.Reply("Passphrase entry cancelled")
 | 
			
		||||
		return
 | 
			
		||||
@@ -299,3 +303,341 @@ func cmdExportRoomKeys(cmd *Command) {
 | 
			
		||||
	}
 | 
			
		||||
	exportKeys(cmd, sessions)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const ssssHelp = `Usage: /%s <subcommand> [...]
 | 
			
		||||
 | 
			
		||||
Subcommands:
 | 
			
		||||
* status [key ID] - Check the status of your SSSS.
 | 
			
		||||
* generate [--set-default] - Generate a SSSS key and optionally set it as the default.
 | 
			
		||||
* set-default <key ID> - Set a SSSS key as the default.`
 | 
			
		||||
 | 
			
		||||
func cmdSSSS(cmd *Command) {
 | 
			
		||||
	if len(cmd.Args) == 0 {
 | 
			
		||||
		cmd.Reply(ssssHelp, cmd.OrigCommand)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mach := cmd.Matrix.Crypto().(*crypto.OlmMachine)
 | 
			
		||||
 | 
			
		||||
	switch strings.ToLower(cmd.Args[0]) {
 | 
			
		||||
	case "status":
 | 
			
		||||
		keyID := ""
 | 
			
		||||
		if len(cmd.Args) > 1 {
 | 
			
		||||
			keyID = cmd.Args[1]
 | 
			
		||||
		}
 | 
			
		||||
		cmdS4Status(cmd, mach, keyID)
 | 
			
		||||
	case "generate":
 | 
			
		||||
		setDefault := len(cmd.Args) > 1 && strings.ToLower(cmd.Args[1]) == "--set-default"
 | 
			
		||||
		cmdS4Generate(cmd, mach, setDefault)
 | 
			
		||||
	case "set-default":
 | 
			
		||||
		if len(cmd.Args) < 2 {
 | 
			
		||||
			cmd.Reply("Usage: /%s set-default <key ID>", cmd.OrigCommand)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		cmdS4SetDefault(cmd, mach, cmd.Args[1])
 | 
			
		||||
	default:
 | 
			
		||||
		cmd.Reply(ssssHelp, cmd.OrigCommand)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func cmdS4Status(cmd *Command, mach *crypto.OlmMachine, keyID string) {
 | 
			
		||||
	var keyData *ssss.KeyMetadata
 | 
			
		||||
	var err error
 | 
			
		||||
	if len(keyID) == 0 {
 | 
			
		||||
		keyID, keyData, err = mach.SSSS.GetDefaultKeyData()
 | 
			
		||||
	} else {
 | 
			
		||||
		keyData, err = mach.SSSS.GetKeyData(keyID)
 | 
			
		||||
	}
 | 
			
		||||
	if errors.Is(err, ssss.ErrNoDefaultKeyAccountDataEvent) {
 | 
			
		||||
		cmd.Reply("SSSS is not set up: no default key set")
 | 
			
		||||
	} else if err != nil {
 | 
			
		||||
		cmd.Reply("Failed to get key data: %v", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	hasPassphrase := "no"
 | 
			
		||||
	if keyData.Passphrase != nil {
 | 
			
		||||
		hasPassphrase = fmt.Sprintf("yes (alg=%s,bits=%d,iter=%d)", keyData.Passphrase.Algorithm, keyData.Passphrase.Bits, keyData.Passphrase.Iterations)
 | 
			
		||||
	}
 | 
			
		||||
	algorithm := keyData.Algorithm
 | 
			
		||||
	if algorithm != ssss.AlgorithmAESHMACSHA2 {
 | 
			
		||||
		algorithm += " (not supported!)"
 | 
			
		||||
	}
 | 
			
		||||
	cmd.Reply("Default key is set.\n  Key ID: %s\n  Has passphrase: %s\n  Algorithm: %s", keyID, hasPassphrase, algorithm)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func cmdS4Generate(cmd *Command, mach *crypto.OlmMachine, setDefault bool) {
 | 
			
		||||
	passphrase, ok := cmd.MainView.AskPassword("Passphrase", "", "", false)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	key, err := ssss.NewKey(passphrase)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		cmd.Reply("Failed to generate new key: %v", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = mach.SSSS.SetKeyData(key.ID, key.Metadata)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		cmd.Reply("Failed to upload key metadata: %v", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO if we start persisting command replies, the recovery key needs to be moved into a popup
 | 
			
		||||
	cmd.Reply("Successfully generated key %s\nRecovery key: %s", key.ID, key.RecoveryKey())
 | 
			
		||||
 | 
			
		||||
	if setDefault {
 | 
			
		||||
		err = mach.SSSS.SetDefaultKeyID(key.ID)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			cmd.Reply("Failed to set key as default: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		cmd.Reply("You can use `/%s set-default %s` to set it as the default", cmd.OrigCommand, key.ID)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func cmdS4SetDefault(cmd *Command, mach *crypto.OlmMachine, keyID string) {
 | 
			
		||||
	_, err := mach.SSSS.GetKeyData(keyID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if errors.Is(err, mautrix.MNotFound) {
 | 
			
		||||
			cmd.Reply("Couldn't find key data on server")
 | 
			
		||||
		} else {
 | 
			
		||||
			cmd.Reply("Failed to fetch key data: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = mach.SSSS.SetDefaultKeyID(keyID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		cmd.Reply("Failed to set key as default: %v", err)
 | 
			
		||||
	} else {
 | 
			
		||||
		cmd.Reply("Successfully set key %s as default", keyID)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const crossSigningHelp = `Usage: /%s <subcommand> [...]
 | 
			
		||||
 | 
			
		||||
Subcommands:
 | 
			
		||||
* status
 | 
			
		||||
    Check the status of your own cross-signing keys.
 | 
			
		||||
* generate [--force]
 | 
			
		||||
    Generate and upload new cross-signing keys.
 | 
			
		||||
    This will prompt you to enter your account password.
 | 
			
		||||
    If you already have existing keys, --force is required.
 | 
			
		||||
* fetch [--save-to-disk]
 | 
			
		||||
    Fetch your cross-signing keys from SSSS and decrypt them.
 | 
			
		||||
    If --save-to-disk is specified, the keys are saved to disk.
 | 
			
		||||
* upload
 | 
			
		||||
    Upload your cross-signing keys to SSSS.`
 | 
			
		||||
 | 
			
		||||
func cmdCrossSigning(cmd *Command) {
 | 
			
		||||
	if len(cmd.Args) == 0 {
 | 
			
		||||
		cmd.Reply(crossSigningHelp, cmd.OrigCommand)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	client := cmd.Matrix.Client()
 | 
			
		||||
	mach := cmd.Matrix.Crypto().(*crypto.OlmMachine)
 | 
			
		||||
 | 
			
		||||
	switch strings.ToLower(cmd.Args[0]) {
 | 
			
		||||
	case "status":
 | 
			
		||||
		cmdCrossSigningStatus(cmd, mach, client)
 | 
			
		||||
	case "generate":
 | 
			
		||||
		force := len(cmd.Args) > 1 && strings.ToLower(cmd.Args[1]) == "--force"
 | 
			
		||||
		cmdCrossSigningGenerate(cmd, cmd.Matrix, mach, client, force)
 | 
			
		||||
	case "fetch":
 | 
			
		||||
		saveToDisk := len(cmd.Args) > 1 && strings.ToLower(cmd.Args[1]) == "--save-to-disk"
 | 
			
		||||
		cmdCrossSigningFetch(cmd, mach, saveToDisk)
 | 
			
		||||
	case "upload":
 | 
			
		||||
		cmdCrossSigningUpload(cmd, mach)
 | 
			
		||||
	default:
 | 
			
		||||
		cmd.Reply(crossSigningHelp, cmd.OrigCommand)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func parseKeyResp(keys *mautrix.RespQueryKeys, userID id.UserID) (id.Ed25519, id.Ed25519, id.Ed25519, bool) {
 | 
			
		||||
	masterKeys, ok := keys.MasterKeys[userID]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return "", "", "", false
 | 
			
		||||
	}
 | 
			
		||||
	selfSigningKeys, ok := keys.SelfSigningKeys[userID]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return "", "", "", false
 | 
			
		||||
	}
 | 
			
		||||
	userSigningKeys, ok := keys.UserSigningKeys[userID]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return masterKeys.FirstKey(), selfSigningKeys.FirstKey(), "", true
 | 
			
		||||
	}
 | 
			
		||||
	return masterKeys.FirstKey(), userSigningKeys.FirstKey(), selfSigningKeys.FirstKey(), true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func cmdCrossSigningStatus(cmd *Command, mach *crypto.OlmMachine, client *mautrix.Client) {
 | 
			
		||||
	if mach.CrossSigningKeys != nil {
 | 
			
		||||
		cmd.Reply("Cross-signing is set up and private keys are cached")
 | 
			
		||||
		cmd.Reply("Master key: %s", mach.CrossSigningKeys.MasterKey.PublicKey)
 | 
			
		||||
		cmd.Reply("User signing key: %s", mach.CrossSigningKeys.UserSigningKey.PublicKey)
 | 
			
		||||
		cmd.Reply("Self-signing key: %s", mach.CrossSigningKeys.SelfSigningKey.PublicKey)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	keys, err := client.QueryKeys(&mautrix.ReqQueryKeys{
 | 
			
		||||
		DeviceKeys: mautrix.DeviceKeysRequest{
 | 
			
		||||
			client.UserID: mautrix.DeviceIDList{client.DeviceID},
 | 
			
		||||
		},
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		cmd.Reply("Failed to query own keys: %v", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	masterKey, selfSigningKey, userSigningKey, ok := parseKeyResp(keys, client.UserID)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		cmd.Reply("Didn't find published cross-signing keys")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	cmd.Reply("Cross-signing is set up, but private keys are not cached")
 | 
			
		||||
	cmd.Reply("Master key: %s", masterKey)
 | 
			
		||||
	cmd.Reply("User signing key: %s", userSigningKey)
 | 
			
		||||
	cmd.Reply("Self-signing key: %s", selfSigningKey)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func cmdCrossSigningFetch(cmd *Command, mach *crypto.OlmMachine, saveToDisk bool) {
 | 
			
		||||
	key := getSSSS(cmd, mach)
 | 
			
		||||
	if key == nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := mach.FetchCrossSigningKeysFromSSSS(key)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		cmd.Reply("Error fetching cross-signing keys: %v", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if saveToDisk {
 | 
			
		||||
		cmd.Reply("Saving keys to disk is not yet implemented")
 | 
			
		||||
	}
 | 
			
		||||
	cmd.Reply("Successfully unlocked cross-signing keys")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func cmdCrossSigningGenerate(cmd *Command, container ifc.MatrixContainer, mach *crypto.OlmMachine, client *mautrix.Client, force bool) {
 | 
			
		||||
	if !force {
 | 
			
		||||
		keys, err := client.QueryKeys(&mautrix.ReqQueryKeys{
 | 
			
		||||
			DeviceKeys: mautrix.DeviceKeysRequest{
 | 
			
		||||
				client.UserID: mautrix.DeviceIDList{client.DeviceID},
 | 
			
		||||
			},
 | 
			
		||||
		})
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			_, _, _, ok := parseKeyResp(keys, client.UserID)
 | 
			
		||||
			if ok {
 | 
			
		||||
				cmd.Reply("Found existing cross-signing keys. Use `--force` if you want to overwrite them.")
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	keys, err := mach.GenerateCrossSigningKeys()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		cmd.Reply("Failed to generate cross-signing keys: %v", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = mach.PublishCrossSigningKeys(keys, func(uia *mautrix.RespUserInteractive) interface{} {
 | 
			
		||||
		if !uia.HasSingleStageFlow(mautrix.AuthTypePassword) {
 | 
			
		||||
			for _, flow := range uia.Flows {
 | 
			
		||||
				if len(flow.Stages) != 1 {
 | 
			
		||||
					return nil
 | 
			
		||||
				}
 | 
			
		||||
				cmd.Reply("Opening browser for authentication")
 | 
			
		||||
				err := container.UIAFallback(flow.Stages[0], uia.Session)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					cmd.Reply("Authentication failed: %v", err)
 | 
			
		||||
					return nil
 | 
			
		||||
				}
 | 
			
		||||
				return &mautrix.BaseAuthData{
 | 
			
		||||
					Type:    flow.Stages[0],
 | 
			
		||||
					Session: uia.Session,
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			cmd.Reply("No supported authentication mechanisms found")
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
		password, ok := cmd.MainView.AskPassword("Account password", "", "correct horse battery staple", false)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
		return &mautrix.ReqUIAuthLogin{
 | 
			
		||||
			BaseAuthData: mautrix.BaseAuthData{
 | 
			
		||||
				Type:    mautrix.AuthTypePassword,
 | 
			
		||||
				Session: uia.Session,
 | 
			
		||||
			},
 | 
			
		||||
			User:     mach.Client.UserID.String(),
 | 
			
		||||
			Password: password,
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		cmd.Reply("Failed to publish cross-signing keys: %v", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mach.CrossSigningKeys = keys
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getSSSS(cmd *Command, mach *crypto.OlmMachine) *ssss.Key {
 | 
			
		||||
	_, keyData, err := mach.SSSS.GetDefaultKeyData()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if errors.Is(err, mautrix.MNotFound) {
 | 
			
		||||
			cmd.Reply("SSSS not set up, use `!ssss generate --set-default` first")
 | 
			
		||||
		} else {
 | 
			
		||||
			cmd.Reply("Failed to fetch default SSSS key data: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var key *ssss.Key
 | 
			
		||||
	if keyData.Passphrase != nil && keyData.Passphrase.Algorithm == ssss.PassphraseAlgorithmPBKDF2 {
 | 
			
		||||
		passphrase, ok := cmd.MainView.AskPassword("Passphrase", "", "correct horse battery staple", false)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
		key, err = keyData.VerifyPassphrase(passphrase)
 | 
			
		||||
		if errors.Is(err, ssss.ErrIncorrectSSSSKey) {
 | 
			
		||||
			cmd.Reply("Incorrect passphrase")
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		recoveryKey, ok := cmd.MainView.AskPassword("Recovery key", "", "tDAK LMRH PiYE bdzi maCe xLX5 wV6P Nmfd c5mC wLef 15Fs VVSc", false)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
		key, err = keyData.VerifyRecoveryKey(recoveryKey)
 | 
			
		||||
		if errors.Is(err, ssss.ErrInvalidRecoveryKey) {
 | 
			
		||||
			cmd.Reply("Malformed recovery key")
 | 
			
		||||
			return nil
 | 
			
		||||
		} else if errors.Is(err, ssss.ErrIncorrectSSSSKey) {
 | 
			
		||||
			cmd.Reply("Incorrect recovery key")
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// All the errors should already be handled above, this is just for backup
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		cmd.Reply("Failed to get SSSS key: %v", err)
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return key
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func cmdCrossSigningUpload(cmd *Command, mach *crypto.OlmMachine) {
 | 
			
		||||
	if mach.CrossSigningKeys == nil {
 | 
			
		||||
		cmd.Reply("Cross-signing keys not cached, use `!%s generate` first", cmd.OrigCommand)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	key := getSSSS(cmd, mach)
 | 
			
		||||
	if key == nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := mach.UploadCrossSigningKeysToSSSS(key, mach.CrossSigningKeys)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		cmd.Reply("Failed to upload keys to SSSS: %v", err)
 | 
			
		||||
	} else {
 | 
			
		||||
		cmd.Reply("Successfully uploaded cross-signing keys to SSSS")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,9 @@
 | 
			
		||||
package ui
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"maunium.net/go/mauview"
 | 
			
		||||
	"maunium.net/go/tcell"
 | 
			
		||||
)
 | 
			
		||||
@@ -41,13 +44,20 @@ type PasswordModal struct {
 | 
			
		||||
	parent *MainView
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MainView) AskPassword(title string, isNew bool) (string, bool) {
 | 
			
		||||
	pwm := NewPasswordModal(view, title, isNew)
 | 
			
		||||
func (view *MainView) AskPassword(title, thing, placeholder string, isNew bool) (string, bool) {
 | 
			
		||||
	pwm := NewPasswordModal(view, title, thing, placeholder, isNew)
 | 
			
		||||
	view.ShowModal(pwm)
 | 
			
		||||
	view.parent.Render()
 | 
			
		||||
	return pwm.Wait()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewPasswordModal(parent *MainView, title string, isNew bool) *PasswordModal {
 | 
			
		||||
func NewPasswordModal(parent *MainView, title, thing, placeholder string, isNew bool) *PasswordModal {
 | 
			
		||||
	if placeholder == "" {
 | 
			
		||||
		placeholder = "correct horse battery staple"
 | 
			
		||||
	}
 | 
			
		||||
	if thing == "" {
 | 
			
		||||
		thing = strings.ToLower(title)
 | 
			
		||||
	}
 | 
			
		||||
	pwm := &PasswordModal{
 | 
			
		||||
		parent:     parent,
 | 
			
		||||
		form:       mauview.NewForm(),
 | 
			
		||||
@@ -64,13 +74,13 @@ func NewPasswordModal(parent *MainView, title string, isNew bool) *PasswordModal
 | 
			
		||||
 | 
			
		||||
	pwm.text = mauview.NewTextField()
 | 
			
		||||
	if isNew {
 | 
			
		||||
		pwm.text.SetText("Create a passphrase")
 | 
			
		||||
		pwm.text.SetText(fmt.Sprintf("Create a %s", thing))
 | 
			
		||||
	} else {
 | 
			
		||||
		pwm.text.SetText("Enter the passphrase")
 | 
			
		||||
		pwm.text.SetText(fmt.Sprintf("Enter the %s", thing))
 | 
			
		||||
	}
 | 
			
		||||
	pwm.input = mauview.NewInputField().
 | 
			
		||||
		SetMaskCharacter('*').
 | 
			
		||||
		SetPlaceholder("correct horse battery staple")
 | 
			
		||||
		SetPlaceholder(placeholder)
 | 
			
		||||
	pwm.form.AddComponent(pwm.text, 1, 1, 3, 1)
 | 
			
		||||
	pwm.form.AddFormItem(pwm.input, 1, 2, 3, 1)
 | 
			
		||||
 | 
			
		||||
@@ -78,10 +88,10 @@ func NewPasswordModal(parent *MainView, title string, isNew bool) *PasswordModal
 | 
			
		||||
		height += 3
 | 
			
		||||
		pwm.confirmInput = mauview.NewInputField().
 | 
			
		||||
			SetMaskCharacter('*').
 | 
			
		||||
			SetPlaceholder("correct horse battery staple").
 | 
			
		||||
			SetPlaceholder(placeholder).
 | 
			
		||||
			SetChangedFunc(pwm.HandleChange)
 | 
			
		||||
		pwm.input.SetChangedFunc(pwm.HandleChange)
 | 
			
		||||
		pwm.confirmText = mauview.NewTextField().SetText("Confirm passphrase")
 | 
			
		||||
		pwm.confirmText = mauview.NewTextField().SetText(fmt.Sprintf("Confirm %s", thing))
 | 
			
		||||
 | 
			
		||||
		pwm.form.SetRow(3, 1).SetRow(4, 1).SetRow(5, 1)
 | 
			
		||||
		pwm.form.AddComponent(pwm.confirmText, 1, 4, 3, 1)
 | 
			
		||||
@@ -125,9 +135,9 @@ func (pwm *PasswordModal) ClickSubmit() {
 | 
			
		||||
 | 
			
		||||
func (pwm *PasswordModal) Wait() (string, bool) {
 | 
			
		||||
	select {
 | 
			
		||||
	case result := <- pwm.outputChan:
 | 
			
		||||
	case result := <-pwm.outputChan:
 | 
			
		||||
		return result, true
 | 
			
		||||
	case <- pwm.cancelChan:
 | 
			
		||||
	case <-pwm.cancelChan:
 | 
			
		||||
		return "", false
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user