forked from GitHub-Mirror/riotX-android
Compare commits
1332 Commits
feature/fi
...
v0.11.0
Author | SHA1 | Date | |
---|---|---|---|
358fcb6b34 | |||
92315a4189 | |||
156cc1aa4a | |||
0d36e9d8a6 | |||
13439769a1 | |||
bf69810f8f | |||
bb9510e59b | |||
4b0dfa49f4 | |||
6652965e48 | |||
b0ff2cb4bb | |||
648691656a | |||
7eae85a394 | |||
123ffe9f9c | |||
c48a439eea | |||
9d26ba3186 | |||
08970ad8c1 | |||
79f11ad686 | |||
7fa76b9d35 | |||
65faedb06b | |||
1ceddd9607 | |||
42cdb1db11 | |||
1c727c1ee4 | |||
a4aa38ee43 | |||
4a11d028c0 | |||
c286f2a744 | |||
e2b4899b36 | |||
aa82cd2064 | |||
bc568343a2 | |||
abf0796794 | |||
02febfb01b | |||
91c98d4bfb | |||
cfee6a43fd | |||
f14f1db0e0 | |||
3feb2d8980 | |||
9fc3093c2c | |||
7d910f2566 | |||
0a0eda3e34 | |||
cecef5b8da | |||
c9ed95ed21 | |||
3dfd6f5a69 | |||
8fc1400bab | |||
3e4b07cec3 | |||
fbb1846694 | |||
b435212c87 | |||
1108ad5705 | |||
f073342954 | |||
38b40efac3 | |||
e60bda7806 | |||
92e60c939d | |||
6e4830e325 | |||
c6b98f3654 | |||
12d54140e5 | |||
1de85daad9 | |||
050519e998 | |||
1af44ce5f7 | |||
8d1a36425d | |||
4e74b545ad | |||
183d6b53bd | |||
14562f7285 | |||
17bcd680b0 | |||
954019547d | |||
782635ec8e | |||
e609f4a57e | |||
907fa35547 | |||
00d0c34363 | |||
6811d31a6d | |||
a464c910f8 | |||
d69881f321 | |||
efc1f38f8c | |||
b9e8da1fbb | |||
d2fea275d8 | |||
a5af949c15 | |||
261b4be287 | |||
205fc0d9d6 | |||
7699560458 | |||
a193b2659d | |||
bb85d41f05 | |||
9bfe904745 | |||
284dc8602f | |||
29087d4a87 | |||
18649ebddb | |||
d5935a13ac | |||
670d4dc34e | |||
5435a1739e | |||
853518fbb2 | |||
0b93f34fa0 | |||
902a9aa243 | |||
5915cebd6d | |||
d91ff87fb9 | |||
79ef055bfb | |||
3a761be6b4 | |||
a9e2c31c32 | |||
3ac53d20e9 | |||
3c18fd5335 | |||
f00f34b244 | |||
63e0b15f3d | |||
80306f20df | |||
2972177541 | |||
1ad8f47dc1 | |||
8527d3f162 | |||
99423bacb2 | |||
edc6c3dd4f | |||
a761a0dbd2 | |||
d431ab23c8 | |||
f0aa34774e | |||
742136abe8 | |||
36aba8554d | |||
da14ae432a | |||
9a01b4ace9 | |||
109c1fe482 | |||
dbd4525404 | |||
c714266a81 | |||
8b1701e537 | |||
41d1b77370 | |||
ac75fe12bf | |||
2f26f4b8bb | |||
6d82ac7c59 | |||
411afb0bf3 | |||
57354cbd69 | |||
03d51281a2 | |||
415511f3e0 | |||
e0e778909d | |||
b9efc9f4bd | |||
872b14373b | |||
d28700e2bf | |||
18beef14cf | |||
e73923dca3 | |||
94afd3e66d | |||
5f540a5b45 | |||
a41617e8aa | |||
ff1745b5dc | |||
8e3e9876b8 | |||
9a4d8f87f6 | |||
aef76241a3 | |||
0768bd5c88 | |||
65333e6031 | |||
849e7c613c | |||
60169d53d7 | |||
4234c27af9 | |||
f9c0256afd | |||
b9eb85e0a6 | |||
6d8850b3d6 | |||
d88edd578f | |||
5373d9aa21 | |||
ad4d5e5c02 | |||
eb9775e307 | |||
aa9d66b991 | |||
4ff12605e9 | |||
7c561ae622 | |||
cec08a20e5 | |||
fb8ba32fb4 | |||
8e9ac8198d | |||
7a05207ae4 | |||
6b39cf3b70 | |||
994759e11a | |||
f31c1b69cb | |||
bdb9d2fbb8 | |||
9fb50dde32 | |||
a145aae0aa | |||
3623072f08 | |||
2717ad475a | |||
a6f8fe9317 | |||
f9eb80b4ec | |||
9510d71cd3 | |||
e7a47ae32a | |||
7890b929a7 | |||
0376de08f4 | |||
90c472fef9 | |||
8e873672a9 | |||
bba52e77d1 | |||
64d73ae8e6 | |||
d9982076f9 | |||
ab489df83d | |||
5e07e96bdb | |||
c495aa4914 | |||
ff267ba9bc | |||
69f923383c | |||
c69852c849 | |||
6d7f2670df | |||
71de8fdad3 | |||
998d9f2c59 | |||
4f3da353e4 | |||
4154cb2b85 | |||
3c6eb4bccf | |||
7b4398404b | |||
9b882978ed | |||
49178dc633 | |||
490ce4b51d | |||
5b63856d96 | |||
538c4d1a64 | |||
1cadbb8eed | |||
3f4f7457c7 | |||
ebf21fe9d8 | |||
a343da594f | |||
938289e8eb | |||
e23763e6db | |||
c06b8486ea | |||
67fe776d91 | |||
10cc270273 | |||
46d96429e0 | |||
9f9c418085 | |||
c412006f0e | |||
5d3c376267 | |||
a3f8f138a6 | |||
4b273e8746 | |||
f11cd47df3 | |||
f984758d37 | |||
97766404d6 | |||
38b93c527b | |||
62bae67080 | |||
2a4cdec020 | |||
6bd7257cf2 | |||
500eb113b6 | |||
1bec8c29b8 | |||
0ecb23199c | |||
33925fcf57 | |||
bf9ce4f690 | |||
d2a4163dff | |||
a0d7aef92e | |||
29f32cf8eb | |||
bb1c988a49 | |||
f063abe068 | |||
db87d8f644 | |||
efa858a337 | |||
fd90f3b9fc | |||
aa51764068 | |||
0a19ded167 | |||
2e3763e8b4 | |||
0c4e0890b1 | |||
e532d97ec1 | |||
fbde8d7d18 | |||
f96bea742e | |||
86bfdd011e | |||
d5c2c1938c | |||
7ce8a13ddf | |||
9bd4dbb65f | |||
ee875b359b | |||
3eb2e1655f | |||
9b207dd5dc | |||
3f1540b54e | |||
2b30925163 | |||
4690754f5f | |||
a9526cdd92 | |||
ab4d42fb20 | |||
0014e8ef06 | |||
311d8ddf7b | |||
6cb3c222a9 | |||
f84ec08847 | |||
9d0188cbf1 | |||
73462a3045 | |||
3eebf965e5 | |||
bba58d25e1 | |||
fedb45b019 | |||
9b83f08654 | |||
91fcf428dd | |||
7e1a279fd9 | |||
8de1fa835b | |||
af45c554fd | |||
11bc7051fd | |||
489a594027 | |||
3f83c161e4 | |||
e0a36b794f | |||
d2b516bdc2 | |||
37166caea2 | |||
9fa131c297 | |||
71ae3c4a8c | |||
f87526e615 | |||
51f53e2ae9 | |||
ef35f0a044 | |||
5db3f51ddb | |||
49f7ce3554 | |||
a3111dc2d8 | |||
be95542110 | |||
6723a566c2 | |||
90027cc4d5 | |||
810b226f21 | |||
42c5adf08d | |||
5edfb78721 | |||
491a38a79f | |||
051f77087e | |||
1a603742d0 | |||
edb65f1787 | |||
9af8355c07 | |||
dd44078297 | |||
a1f96a5b5a | |||
5770023593 | |||
2789268c23 | |||
eb4355890e | |||
4e41156db3 | |||
1a0b8b35f8 | |||
5f9cdcb4b4 | |||
2e4c3f850a | |||
127916a8d9 | |||
248a584e1a | |||
b8a3ad0c43 | |||
1f161b7e23 | |||
23315ede92 | |||
20ad3abb60 | |||
ac377fceba | |||
abbe56acfa | |||
f74cabd145 | |||
0e2237226f | |||
62d5aba796 | |||
f12e6c941d | |||
7caa8ce3bc | |||
20f969d563 | |||
a8f24e5c39 | |||
8ae9544b48 | |||
3758334824 | |||
6d8e5b892e | |||
c18c140ec9 | |||
1dc7dfc896 | |||
1c03163a33 | |||
9aa270c7ad | |||
3f80076fb1 | |||
dfbf448bb7 | |||
95fc20dca0 | |||
381084b2ab | |||
41ac2c6d70 | |||
08ea3d049e | |||
f24889230c | |||
b5f9549a8b | |||
e3e38d4c8a | |||
416bef7903 | |||
823acebf78 | |||
3e91125872 | |||
9a628c7b5d | |||
fb46a14172 | |||
ca4e75a1a0 | |||
2871e4f5b1 | |||
b7bfb20a2e | |||
a1aa16715d | |||
55add4734d | |||
2849e1f846 | |||
5b9876a20c | |||
adf299081d | |||
d50b690523 | |||
c6b0ae63ea | |||
3c93807fe6 | |||
7f1f98c2e5 | |||
6525314af8 | |||
da8d6fb4f4 | |||
fa6a9cab7e | |||
bdfc4ad8a7 | |||
6ab7209e4d | |||
4485d1c685 | |||
8b63f78d76 | |||
2e87e0b4c1 | |||
507134407b | |||
7663cd4e23 | |||
ec2954200e | |||
eb32c5455f | |||
fc367b3c3e | |||
57dcd569f3 | |||
3673520ef6 | |||
fe17050580 | |||
ec40a8c969 | |||
6b1b3bec85 | |||
6bd6ececb7 | |||
c7db695e67 | |||
4cefdfedce | |||
6ce241163e | |||
79350899c5 | |||
f265724a3c | |||
2e50d2a36e | |||
643c062858 | |||
0e0db67aef | |||
6dc5b126d6 | |||
d2acabddd9 | |||
ec71b53c1e | |||
fc3d4187d1 | |||
a25f309990 | |||
5449592422 | |||
19b415871d | |||
6463f3439f | |||
f2320f9571 | |||
fc91694bdd | |||
dbb41108ef | |||
08c864bad7 | |||
9c5c65a243 | |||
b6199b1f27 | |||
38da54119a | |||
65b09ad4f0 | |||
603b8fae45 | |||
50e2e6a823 | |||
bb237e3bbb | |||
1bd2c0d220 | |||
bcb811a7e8 | |||
ec4d7e29ec | |||
a6df63f6d9 | |||
ea7213a5ae | |||
590a13334d | |||
631448335d | |||
12376368c7 | |||
f17564d743 | |||
a6fcc7dca6 | |||
70bce9e7dd | |||
17f3614288 | |||
238d1d87c6 | |||
82f639b91f | |||
c8bc553caa | |||
fa5d44af65 | |||
cbdbe5033f | |||
61ac250e2b | |||
04f72dfcb8 | |||
10ca5d94ea | |||
c5b8c69ae5 | |||
d3d7f7cc61 | |||
b6bb714264 | |||
a87310ac15 | |||
032e1b3d19 | |||
d9f15c1d21 | |||
99d09f71ad | |||
9c952b6bc8 | |||
fbae3d27c2 | |||
2f7d1f9f01 | |||
114101699d | |||
f5c0dcb5ea | |||
241220ce1f | |||
98d97e574c | |||
96e610970a | |||
2027802f82 | |||
54f93db632 | |||
3af7ca9ab0 | |||
93ef3edab3 | |||
c85852262e | |||
d0c3271628 | |||
ad9a48d5fa | |||
219d1383e5 | |||
8871280fab | |||
fb3e953e28 | |||
10712fd6ab | |||
9d478dbfe2 | |||
3013d67c16 | |||
bee8c2d159 | |||
945e5d5a74 | |||
93df8c56a8 | |||
cd1a964067 | |||
e4b829f0cf | |||
7206d84a6b | |||
b3233d3eb7 | |||
3c4c0ed46a | |||
24f1262005 | |||
86667a6d8a | |||
42e0d0f769 | |||
e976055253 | |||
84d6c8ec16 | |||
9fdfd091ac | |||
e66766f41c | |||
6177e69855 | |||
5c71cabb5f | |||
6ebe5532c5 | |||
8030c44f44 | |||
a85b5af761 | |||
d780c74abf | |||
5d7efa7f8f | |||
7e467443ed | |||
8439c337f7 | |||
151ad01038 | |||
73267442bb | |||
43fd794c96 | |||
36060fe332 | |||
3483debcc1 | |||
4324f6abbd | |||
43f8d8d8aa | |||
fb1ff77ec4 | |||
e355a7f6dd | |||
33e35368fc | |||
0e49a11e5e | |||
d47cf7e932 | |||
101057520b | |||
30b2e53002 | |||
5ab31a0ef5 | |||
b4ae331086 | |||
3f447df13c | |||
3517873156 | |||
118870bc41 | |||
d001ab5bef | |||
7496a88dcd | |||
6567c5e6c7 | |||
361427488f | |||
7272343e6d | |||
f0b3151d71 | |||
035359cb35 | |||
57b640622b | |||
de4c389c76 | |||
199456487c | |||
00ca5dc70a | |||
a04802b238 | |||
cb275aee37 | |||
fbf73c7c8e | |||
0040f8e924 | |||
6cca242f77 | |||
2929b8f617 | |||
8422c6de17 | |||
7c567b04bb | |||
1ac99e92a6 | |||
5ab975cc5c | |||
2cf63ea92a | |||
9e8d8ce878 | |||
b766bce07d | |||
01452efd8d | |||
0a0af221f0 | |||
af08759af6 | |||
e52f0faaa7 | |||
8fa676d034 | |||
b6594599c4 | |||
8be8cc9ef7 | |||
9762d5be40 | |||
b17b54d218 | |||
187e2a26db | |||
2f5fdbb7e2 | |||
8b1411f533 | |||
bdee5e0687 | |||
ce4e244a3b | |||
ff81715783 | |||
3196dcb57e | |||
50bf6df7fe | |||
02914495ce | |||
70a14f6350 | |||
cac5fb725a | |||
dbc17ae515 | |||
1de02c2fbb | |||
6d55c15761 | |||
377a228f88 | |||
2974f8b200 | |||
7388a408b8 | |||
f43dcb1183 | |||
492ed3954a | |||
7890e83204 | |||
00d1a2c380 | |||
78dfd6b3e6 | |||
3abce34484 | |||
4204ab262c | |||
c7a4d34192 | |||
7416fec93e | |||
3c40f64fb7 | |||
b57c71b1c9 | |||
fea54952d3 | |||
3dc5ef54ab | |||
9092b97fb8 | |||
cebd8136da | |||
64b3568d51 | |||
5e4e54153c | |||
d071324694 | |||
2c8cd89533 | |||
11b5c2c3ba | |||
9d7c4abb97 | |||
8e3234d188 | |||
b253722b98 | |||
fce576e3a4 | |||
7ed7b18ccd | |||
053bf7aeac | |||
6ccd083451 | |||
e39c4a7925 | |||
abdb83b9fd | |||
0bcc84cbd6 | |||
b2f6fb8c91 | |||
36042ed145 | |||
6ad1932fe5 | |||
4a6237b50e | |||
a7a19dab11 | |||
8d0aa0437c | |||
0a79b8b315 | |||
1dacfa6744 | |||
723a007c39 | |||
eaa1b04a4a | |||
b1710fde60 | |||
cd0a40c18d | |||
17636019e0 | |||
8078c39d6e | |||
be94b2f90a | |||
eff04be247 | |||
3986839801 | |||
9e436483de | |||
05a069be04 | |||
a1a71e2f1d | |||
203da0f37e | |||
6cd04525aa | |||
3c3c6aeac6 | |||
e71311f576 | |||
e4d0e0b0bf | |||
28e5e42ab1 | |||
b860c3b0e3 | |||
f7f97e2098 | |||
e28e2dadb9 | |||
c28be6adb0 | |||
c57af9cf3e | |||
679b0fff98 | |||
946fc36a26 | |||
13a5f784dc | |||
0ca8696e88 | |||
3622c0ecb4 | |||
116d569fa8 | |||
ee5ebb4b83 | |||
0a0c344bfb | |||
82fc97f619 | |||
20696353b8 | |||
ae5b6bd2b9 | |||
1e11d4492b | |||
6e39164b20 | |||
0a9ebb6bf6 | |||
db009ce683 | |||
55c80d3743 | |||
fbb23dfb66 | |||
e5779d425a | |||
99d9704a50 | |||
3f8ddbe880 | |||
30e43e47cd | |||
15dc4d6369 | |||
dceb5ffd8d | |||
eec470f2ce | |||
68db9c1cc0 | |||
cdfc402599 | |||
72d3f1e909 | |||
255fa11e89 | |||
119e4c0d32 | |||
a9c474105a | |||
6de64cbedd | |||
546c537e3b | |||
36c5f9af13 | |||
c2682c7f4b | |||
3073470c38 | |||
549f749682 | |||
d4dfb76e80 | |||
e80191b2e0 | |||
c62c77f14c | |||
d6e5c5a857 | |||
50a0660ab6 | |||
ecdb3c3326 | |||
2cd1d697fe | |||
3f9b7813bc | |||
f34f28b668 | |||
53572a3be6 | |||
90b6199e10 | |||
0aa299aa37 | |||
d387c310c8 | |||
8bd1fb08f7 | |||
ac6aff9175 | |||
adf0382d28 | |||
51554f7be0 | |||
c1c1c3f999 | |||
8b04fdab77 | |||
f8b665a245 | |||
d68a9a5342 | |||
5d2ff589f8 | |||
e85a0783fc | |||
d6c278288d | |||
4ad86a13a0 | |||
4f7ec91255 | |||
979b42aa30 | |||
fc49de080c | |||
d2b9668d4e | |||
0632870be1 | |||
8e39fd2a70 | |||
abbc62dd35 | |||
77de059dc9 | |||
1931a1a4a4 | |||
9c5987b682 | |||
4e4fb4c565 | |||
0582d0f641 | |||
ef2af14529 | |||
525da17678 | |||
aab41d7358 | |||
5db3c81aa9 | |||
c763635845 | |||
11d72b81f6 | |||
53543453b3 | |||
d4be68191c | |||
7ef471ad0d | |||
73dd735ba6 | |||
2f6d3adb17 | |||
2edfd4e830 | |||
ff7856c535 | |||
650a151b18 | |||
275dd20412 | |||
44f6391cb4 | |||
588e5d6e63 | |||
716999eec6 | |||
42e0a45f3f | |||
31397869b2 | |||
e842bf13b2 | |||
aea34da81e | |||
0814f53fed | |||
b5c6c1af0d | |||
de30e7c1c6 | |||
2d95fe921d | |||
84542326f4 | |||
53b1b89c47 | |||
28315be7b9 | |||
8605095668 | |||
737959f616 | |||
7817f49072 | |||
a060431aaf | |||
a3f561d788 | |||
0ea878af8a | |||
99de40c980 | |||
810a97c639 | |||
f02f16d9c5 | |||
62b7a83a31 | |||
4a80df082c | |||
60f6b3ef02 | |||
a0b1ef3216 | |||
1b66d1f746 | |||
643a2baabf | |||
cd62e87266 | |||
17cba1a432 | |||
f077cc8467 | |||
f3039601bf | |||
4c04014e4d | |||
ae8bceacba | |||
9b91b6ea87 | |||
b24a372262 | |||
63b43de4b8 | |||
d1a61f29e4 | |||
f6373221de | |||
ec0974f72c | |||
b5f2f01c8d | |||
21d808c1ce | |||
1e963bc0dc | |||
0d80750507 | |||
1c9cf7a810 | |||
c6d01fbcf4 | |||
9e1ded941f | |||
af433266c8 | |||
05d09bf950 | |||
6890f83810 | |||
51568c30a6 | |||
cc832633a5 | |||
e019ec6596 | |||
eadea9016b | |||
6422d946c9 | |||
5cc3dc00e3 | |||
5a2a9f908a | |||
c1f2e9f171 | |||
f6d34ec7fd | |||
620ba279d8 | |||
3fcfa33364 | |||
546da0f173 | |||
001711d5a3 | |||
8e1a964679 | |||
b25a130db1 | |||
8a9e6497e8 | |||
47e3797b7e | |||
5cbc90e06a | |||
b6e18e4a8f | |||
7e29665fd0 | |||
e04bf31faa | |||
d25cf79b07 | |||
faa8e6bbb2 | |||
d3d4deb884 | |||
f6b8e0c479 | |||
2a726f54a2 | |||
1197d4021d | |||
03f8120b7d | |||
acd7a709de | |||
5651ea515b | |||
9794b3a49d | |||
b3e1c3969d | |||
90eeb68d36 | |||
d1ff3314a7 | |||
f24bed17a2 | |||
a993a30203 | |||
ea0809ff87 | |||
9668487b6b | |||
91cc78d2ad | |||
562acc9702 | |||
dfab88ed95 | |||
36866dd24e | |||
c728834273 | |||
f5020d0f63 | |||
7da9cafcc2 | |||
6f09eea248 | |||
468bd5bcc9 | |||
3169093c50 | |||
d60d766354 | |||
0ffb5e627e | |||
b4a13f9504 | |||
88fb9667a3 | |||
ffa8b7e73a | |||
528958b3de | |||
3ffe2f7d40 | |||
3066d5f303 | |||
bf42b73713 | |||
ed93f4a6c1 | |||
b3d649a4d9 | |||
3739e50d46 | |||
9bf484cf1e | |||
6c2faff1f0 | |||
07fca0922b | |||
282de21708 | |||
ba9d119892 | |||
4453f0ced9 | |||
77168bfd6a | |||
25e9a179d2 | |||
73ec0f5a83 | |||
993fa74252 | |||
38fc4984fe | |||
695d8cce00 | |||
07e99901e1 | |||
20f53e9a58 | |||
ced72aff4f | |||
fdaaca49c2 | |||
3485f023b0 | |||
384dd100e9 | |||
1ba8a58219 | |||
69fb7bdf95 | |||
c8010561fc | |||
1f127335bc | |||
138a210a73 | |||
ca6bcde82d | |||
6bda437f5d | |||
5d6d0202a9 | |||
3e6b65e174 | |||
137dcab734 | |||
b22b8fba02 | |||
3ccdf4a244 | |||
5fbd271b1c | |||
db8ea0f5e8 | |||
a47a3ead1f | |||
05b2092ffc | |||
f4ab770be9 | |||
6249a59203 | |||
d4111d053d | |||
618e9a4f52 | |||
b8ebe3570b | |||
f2c8d4ad02 | |||
be524472ec | |||
1b82a1a24d | |||
cf0b331c3b | |||
2a92a3dc80 | |||
012840abba | |||
a5975a099e | |||
38da4b9ee5 | |||
242e60fcaa | |||
a23be05cbf | |||
ed39b02924 | |||
fe931b5361 | |||
90d9cd0587 | |||
9cedb18921 | |||
e89ba7b87b | |||
902657c22a | |||
eec2abf164 | |||
6879cc8ca8 | |||
fd6bbbd3b5 | |||
0ff0b014a9 | |||
a89f0ddd1d | |||
fdc9e84dd5 | |||
58f878fca9 | |||
88095e4bd9 | |||
47d22a3d5e | |||
28e82cb8ea | |||
35817245cb | |||
75266f42bb | |||
95c4c9ce56 | |||
ce5570105d | |||
188a9aebfa | |||
c95223f5d2 | |||
ef0362ba9c | |||
ea242f6737 | |||
cbc08d834b | |||
0ab6b33fb6 | |||
1b394527b6 | |||
a8f1388721 | |||
166be4e289 | |||
b49ccefe63 | |||
825760d17e | |||
b5af62c3ea | |||
a51d96bf00 | |||
7e142d201d | |||
2be6058971 | |||
49d73f360e | |||
bd88d85a21 | |||
be4fc5cce6 | |||
704da1be55 | |||
5d002532d3 | |||
d4161e9a1a | |||
7966ebef03 | |||
ed5faca5d2 | |||
51a4c93676 | |||
d8f449388c | |||
8ca829d538 | |||
e7819ce678 | |||
5402902bc2 | |||
bc1350aaf5 | |||
fd74e3dfb1 | |||
e0628da1cb | |||
aa4e74e986 | |||
6cc0c0672e | |||
501474b720 | |||
e11c66035c | |||
3d2d219d79 | |||
63af03bedd | |||
d3827b8673 | |||
4ca2531e47 | |||
4e8dc72439 | |||
25a4240a5a | |||
b9cfda23b6 | |||
06dcf75a32 | |||
21deb2551d | |||
70639f180c | |||
1dbb02a80d | |||
825463d9cd | |||
c313ce78cb | |||
39f58d048b | |||
3f792c7a84 | |||
347dcb469a | |||
9cd69d1e33 | |||
79fb1985aa | |||
e216cd15a8 | |||
37fde374b3 | |||
f7b471f141 | |||
93fd56a7ca | |||
5a9d88e791 | |||
eaf6a9923a | |||
d98567045c | |||
b4ce8748cb | |||
9d5433a857 | |||
6d4ee83e65 | |||
6e44cca17d | |||
0a73887c70 | |||
7fef063e15 | |||
24f391dac0 | |||
81c7f694d6 | |||
80e2fc0ca3 | |||
9f53406e99 | |||
3584658c36 | |||
12a0cbb400 | |||
20437446b4 | |||
35229882e3 | |||
a04f4421f6 | |||
af1e81f65e | |||
63f6081fa5 | |||
ee2e575211 | |||
0949d29f9c | |||
23466fb5a4 | |||
7f09e64d63 | |||
585f0ba4b7 | |||
245fbe86d9 | |||
456908c851 | |||
b79fdf6a85 | |||
d9f448c9aa | |||
7a6fc4936b | |||
d82fd10f3b | |||
4009f2c176 | |||
15c4b03340 | |||
7b5dff3dcf | |||
357123743f | |||
bb04af1e2c | |||
2f94fbd7eb | |||
f2a3bdb68e | |||
097e9714ff | |||
acae0fad3e | |||
4deb7eb865 | |||
f910cd6f97 | |||
652ac81fa1 | |||
99f4196388 | |||
c0b94f4111 | |||
1462fa0484 | |||
dafdc1d3ad | |||
394b89e76b | |||
0db8e7da43 | |||
dae8b5c196 | |||
215324a03e | |||
d3ce4c491c | |||
ed6d28bd3b | |||
c2e053b62b | |||
c450849cc3 | |||
fe884dba2d | |||
3fa4dbaa25 | |||
4a74f58516 | |||
c413321a22 | |||
d696bd2830 | |||
a2b6bd0f62 | |||
9cc922a8a2 | |||
c36d1bcd06 | |||
85499c6b33 | |||
8076eab4b5 | |||
d47c0f5ebc | |||
fd09a1224e | |||
c300c50093 | |||
77c4355aed | |||
1a92562182 | |||
9c390dcc0c | |||
95089b91b8 | |||
eb446d7b49 | |||
dc4786ecf0 | |||
e245023add | |||
90fad23493 | |||
000db4b192 | |||
2a16c36a59 | |||
ef6c1cfc63 | |||
4b4156996d | |||
087cc0e6e3 | |||
f4df27c2dc | |||
ab25980c4e | |||
77b402ce70 | |||
2763fbb496 | |||
6deba31111 | |||
ff6ce8a4b7 | |||
d0cff219aa | |||
65f0af918f | |||
ac38a6461c | |||
9a1e16a170 | |||
9e5c70dda3 | |||
0255696c88 | |||
76a9625f25 | |||
5af6bf3762 | |||
507bc2f622 | |||
125eacb20b | |||
6176520805 | |||
3aea0a50ca | |||
ab87a3caea | |||
c58328f94e | |||
03974c8bdf | |||
151ae7f4dd | |||
a34b053efe | |||
02e342849f | |||
b59017938b | |||
2c81e41288 | |||
cb44ab547c | |||
6d01a570fd | |||
4a2bf0d6c6 | |||
36af8a6a9f | |||
40a68c3e9f | |||
1a4ec34bb2 | |||
10490e3aa6 | |||
cd6624a8a6 | |||
3965218bf9 | |||
d78ff7ab08 | |||
cb274d6a33 | |||
c00dbce536 | |||
db88caf7fa | |||
c3d945d6bb | |||
df6080b1da | |||
4c128602b2 | |||
d609c49b31 | |||
001603cf9a | |||
d87ee32422 | |||
f0671b9e73 | |||
e218691bf2 | |||
9c67036c08 | |||
62657538af | |||
5438207fba | |||
fe88aaffbd | |||
21ba72e5e7 | |||
d48ae967bd | |||
0afde3b021 | |||
49ae954183 | |||
64bee91f7a | |||
4341b0d0f5 | |||
51fdccb393 | |||
7e3b300130 | |||
a98b324c89 | |||
977721881f | |||
838003b68a | |||
7d41352918 | |||
077396a832 | |||
32b79bd50e | |||
844f6d16a4 | |||
fc9ef579ca | |||
77fa5af1b8 | |||
2948018453 | |||
90d25ff45e | |||
173452d38c | |||
a9f9083745 | |||
22dc2a6790 | |||
927cd7285d | |||
4d5bdecec6 | |||
0be987ac0d | |||
4bfaa00be4 | |||
8e78d8a58d | |||
e3e86c0a41 | |||
8a5fddd952 | |||
208460850e | |||
0ddef67cc9 | |||
896e582a9c | |||
477920f411 | |||
c647648e79 | |||
b654025a3b | |||
786a7d7560 | |||
b935b9311e | |||
8e12f71535 | |||
7eea2ccfb4 | |||
c32ef02a12 | |||
3651ec4870 | |||
87de7bd3e6 | |||
9494174c33 | |||
b7e0b400fb | |||
a8f06f609b | |||
d469299f42 | |||
9bdea5b325 | |||
2f01ad99b3 | |||
bb3b5788ba | |||
45f7d3e9c4 | |||
0f7a56d005 | |||
63d2861bc8 | |||
6bbc784c29 | |||
c6fd625761 | |||
d8092abc4e | |||
6effb90361 | |||
42584fc55a | |||
30d9ddb3e8 | |||
020c32bb1a | |||
efd973208f | |||
30a6c98c08 | |||
1440080d04 | |||
61bb4c0427 | |||
3c25088243 | |||
fc1c0caea3 | |||
8901a5e09a | |||
25f1d21bc7 | |||
4d2ab9fa31 | |||
0289d2ee87 | |||
222201cc64 | |||
b15dea6de3 | |||
2ba83e456d | |||
1822fc4fbb | |||
e6dd1fbfec | |||
e2ea76f871 | |||
9182f2ce4e | |||
34d14eb304 | |||
3625c462f0 | |||
fe69206340 | |||
f9885fd04c | |||
316c8ec27e | |||
41465450d8 | |||
bd009caaf1 | |||
33252c3b65 | |||
10e4d0190f | |||
b77310fe92 | |||
919dec4a56 | |||
43b3680774 | |||
bfb5fce809 | |||
1f3731aae7 | |||
52dced43ff | |||
ff80c3c8d5 | |||
34e4d27573 | |||
6522148e63 | |||
252b2ea30a | |||
f493ce44f2 | |||
c4c5069ee5 | |||
423125b5d9 | |||
9e3d29b7d7 | |||
f65becf7c0 | |||
80a61cf6b5 | |||
77056aff94 | |||
65e123d87f | |||
d0b145d031 | |||
98306e223b | |||
c9fe1adb77 | |||
1b95336ad3 | |||
f007fb04b8 | |||
141434e8f8 | |||
b8669d5ed2 | |||
7a08a11b19 | |||
54b1d18812 | |||
3aa30e5f15 | |||
ddf4a81905 | |||
794fd650a4 | |||
9a57a02996 | |||
7e8cd07e1e | |||
d613abf4b4 | |||
06699eaefc | |||
e5082f662c | |||
c8ab53e39c | |||
d424a135a9 | |||
e6409d4c60 | |||
19c7de687e | |||
1918302297 | |||
92e3a02389 | |||
0a54801fcc | |||
228ee52563 | |||
e6c74dc1fe | |||
fe82ad2002 | |||
f66739491a | |||
c5dc9d4a9a | |||
8f858f8119 | |||
6e036c24b8 | |||
5e832e07cd | |||
e9700e04d8 | |||
c19b1f917f | |||
4281b5967a | |||
aa743d8469 | |||
a09850b16c | |||
6cb94dd4d6 | |||
c9931e3ba3 | |||
fc302c1b5a | |||
34ac987494 | |||
24b2387703 | |||
8a0c9ae9b0 | |||
a79227424f | |||
ffe0b9712c | |||
d92c090c30 | |||
1a4157a663 | |||
fa81d1a9c7 | |||
dba4df6836 | |||
4aae1f78d8 | |||
8159a52bd7 | |||
95d83db90c | |||
ac5b0af63e | |||
e80473903e | |||
d08778c674 | |||
0919b9460d | |||
66a018c79e | |||
dcd64de4b8 | |||
a0bd206308 | |||
ba589e7961 | |||
5dc83d64c1 | |||
9a4eb8e9a4 | |||
058e7153a1 | |||
d7b2371854 | |||
b0c939866f | |||
a07f8b615e | |||
12bd85e0a9 | |||
1b82ed5abb | |||
c13ab62187 | |||
ea77686746 | |||
8a5612be3d | |||
d24ce27903 | |||
2099965508 | |||
829e8da8dc | |||
e149ee53de | |||
b73d3b15f8 | |||
61d7f23870 | |||
b5650b2b8f | |||
8777d13d8b | |||
d52613d723 | |||
7ce476f858 | |||
dd07f5c2a6 | |||
7e6e09bc19 | |||
1d11a163af | |||
57bd103de8 | |||
25bc5001f9 | |||
e4c52484b1 | |||
a30da07fd1 | |||
ee27d3e047 | |||
7096094224 | |||
443fb41d18 | |||
94b4351e19 | |||
e90aeff417 | |||
e50dd265d4 | |||
4521ea14ee | |||
535b41d818 | |||
21357a1ec7 | |||
8c872caf78 | |||
62a81a556e | |||
568e8c8bc0 | |||
98a7652403 | |||
78951b9155 | |||
8c86a653b2 | |||
ea0526821e | |||
c503445092 | |||
205af8b122 | |||
3abb7c8de6 | |||
a40510da3b | |||
a6ab4a349d | |||
79a704d240 | |||
e5adf174a8 | |||
f01e796271 | |||
302d23ba96 | |||
03050c3f25 | |||
cbfd2af74b | |||
f3fab0dc08 | |||
4a512d2425 | |||
07f80f43bd | |||
87dec337d8 | |||
b37877746a | |||
b0e5612bdc | |||
25b0cd0e4b | |||
2800d86a57 | |||
01bc0de2c2 | |||
857a4c5a26 | |||
063c35380a | |||
5322251bc0 | |||
c21b9df9a5 | |||
f2a52f0253 | |||
baaf493cb4 | |||
6cbd6d3a33 | |||
72e5aa981a | |||
c0f085cdf8 | |||
10bc2297d4 | |||
8fa5e63b07 | |||
9d0c50907c | |||
e5958983d8 | |||
ab23ec3f35 | |||
a79a6443e7 | |||
9ff24cbf2a | |||
2eee25bbc1 | |||
2a2431e490 | |||
4041e2e8ca | |||
031c4e5746 | |||
b4ea85fc76 | |||
480f14902d | |||
20c8e8d922 | |||
9cdecced57 | |||
60d46538de | |||
223295c2f1 | |||
f789fb275d | |||
a7c12aeb93 | |||
0ca9a5f68b | |||
842345df9b | |||
7d5c31c510 | |||
1ee1c31b9c | |||
e9eada77f9 | |||
93ce0cc5e9 | |||
eefd09d022 | |||
ef597cc67a | |||
5d171e0240 | |||
39070820be | |||
1fdad38b9d | |||
f41c0311fa | |||
a476ac71da | |||
4b971a9e67 | |||
bc2d321a84 | |||
9adeab6bae | |||
0f3a63e366 | |||
d90698fe92 | |||
af0af6e260 | |||
6e71fb565a | |||
6c66ab1568 | |||
0d329f0338 | |||
2f66321c2a | |||
5b102485bc | |||
698fc35704 | |||
37199da52f | |||
1c69d8e425 | |||
11bf00030d | |||
9378d30601 | |||
41ed4b23d8 | |||
de9a5a3d12 | |||
19202cfca6 |
@ -1,43 +1,68 @@
|
||||
# Use Docker file from https://hub.docker.com/r/runmymind/docker-android-sdk
|
||||
# Last docker plugin version can be found here:
|
||||
# https://github.com/buildkite-plugins/docker-buildkite-plugin/releases
|
||||
|
||||
# Build debug version of the RiotX application, from the develop branch and the features branches
|
||||
# We propagate the environment to the container (sse https://github.com/buildkite-plugins/docker-buildkite-plugin#propagate-environment-optional-boolean)
|
||||
|
||||
steps:
|
||||
- label: "Assemble GPlay Debug version"
|
||||
- label: "Compile and run Unit tests"
|
||||
agents:
|
||||
# We use a medium sized instance instead of the normal small ones because
|
||||
# gradle build is long
|
||||
# gradle build can be memory hungry
|
||||
queue: "medium"
|
||||
commands:
|
||||
- "./gradlew clean test --stacktrace"
|
||||
plugins:
|
||||
- docker#v3.1.0:
|
||||
image: "runmymind/docker-android-sdk"
|
||||
propagate-environment: true
|
||||
|
||||
- label: "Compile Android tests"
|
||||
agents:
|
||||
# We use a medium sized instance instead of the normal small ones because
|
||||
# gradle build can be memory hungry
|
||||
queue: "medium"
|
||||
commands:
|
||||
- "./gradlew clean assembleAndroidTest --stacktrace"
|
||||
plugins:
|
||||
- docker#v3.1.0:
|
||||
image: "runmymind/docker-android-sdk"
|
||||
propagate-environment: true
|
||||
|
||||
- label: "Assemble GPlay Debug version"
|
||||
agents:
|
||||
# We use a xlarge sized instance instead of the normal small ones because
|
||||
# gradle build can be memory hungry
|
||||
queue: "xlarge"
|
||||
commands:
|
||||
- "./gradlew clean lintGplayRelease assembleGplayDebug --stacktrace"
|
||||
artifact_paths:
|
||||
- "vector/build/outputs/apk/gplay/debug/*.apk"
|
||||
branches: "develop feature/*"
|
||||
branches: "!master"
|
||||
plugins:
|
||||
- docker#v3.1.0:
|
||||
image: "runmymind/docker-android-sdk"
|
||||
propagate-environment: true
|
||||
|
||||
- label: "Assemble FDroid Debug version"
|
||||
agents:
|
||||
# We use a medium sized instance instead of the normal small ones because
|
||||
# gradle build is long
|
||||
queue: "medium"
|
||||
# We use a xlarge sized instance instead of the normal small ones because
|
||||
# gradle build can be memory hungry
|
||||
queue: "xlarge"
|
||||
commands:
|
||||
- "./gradlew clean lintFdroidRelease assembleFdroidDebug --stacktrace"
|
||||
artifact_paths:
|
||||
- "vector/build/outputs/apk/fdroid/debug/*.apk"
|
||||
branches: "develop feature/*"
|
||||
branches: "!master"
|
||||
plugins:
|
||||
- docker#v3.1.0:
|
||||
image: "runmymind/docker-android-sdk"
|
||||
propagate-environment: true
|
||||
|
||||
- label: "Build Google Play unsigned APK"
|
||||
agents:
|
||||
# We use a medium sized instance instead of the normal small ones because
|
||||
# gradle build is long
|
||||
queue: "medium"
|
||||
# We use a xlarge sized instance instead of the normal small ones because
|
||||
# gradle build can be memory hungry
|
||||
queue: "xlarge"
|
||||
commands:
|
||||
- "./gradlew clean assembleGplayRelease --stacktrace"
|
||||
artifact_paths:
|
||||
@ -45,9 +70,19 @@ steps:
|
||||
branches: "master"
|
||||
plugins:
|
||||
- docker#v3.1.0:
|
||||
image: "runmymind/docker-android-sdk"
|
||||
image: "runmymind/docker-android-sdk"
|
||||
propagate-environment: true
|
||||
|
||||
# Code quality
|
||||
|
||||
- label: "Code quality"
|
||||
command: "./tools/check/check_code_quality.sh"
|
||||
command:
|
||||
- "./tools/check/check_code_quality.sh"
|
||||
|
||||
- label: "ktlint"
|
||||
command:
|
||||
- "curl -sSLO https://github.com/pinterest/ktlint/releases/download/0.34.2/ktlint && chmod a+x ktlint"
|
||||
- "./ktlint --android --experimental -v"
|
||||
plugins:
|
||||
- docker#v3.1.0:
|
||||
image: "openjdk"
|
||||
|
32
.editorconfig
Normal file
32
.editorconfig
Normal file
@ -0,0 +1,32 @@
|
||||
# For ktlint configuration. Ref: https://ktlint.github.io/
|
||||
|
||||
[*.{kt,kts}]
|
||||
# possible values: number (e.g. 2), "unset" (makes ktlint ignore indentation completely)
|
||||
indent_size=unset
|
||||
# true (recommended) / false
|
||||
insert_final_newline=true
|
||||
# possible values: number (e.g. 120) (package name, imports & comments are ignored), "off"
|
||||
# it's automatically set to 100 on `ktlint --android ...` (per Android Kotlin Style Guide)
|
||||
max_line_length=off
|
||||
|
||||
# Comma-separated list of rules to disable (Since 0.34.0)
|
||||
# Note that rules in any ruleset other than the standard ruleset will need to be prefixed
|
||||
# by the ruleset identifier.
|
||||
disabled_rules=no-wildcard-imports,no-multi-spaces,colon-spacing,chain-wrapping,import-ordering,experimental:annotation
|
||||
|
||||
# The following (so far identified) rules are kept:
|
||||
# no-blank-line-before-rbrace
|
||||
# final-newline
|
||||
# no-consecutive-blank-lines
|
||||
# comment-spacing
|
||||
# filename
|
||||
# comma-spacing
|
||||
# paren-spacing
|
||||
# op-spacing
|
||||
# string-template
|
||||
# no-unused-imports
|
||||
# curly-spacing
|
||||
# no-semi
|
||||
# no-empty-class-body
|
||||
# experimental:multiline-if-else
|
||||
# experimental:no-empty-first-line-in-method-block
|
14
.gitignore
vendored
14
.gitignore
vendored
@ -1,14 +1,18 @@
|
||||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
.idea/*
|
||||
/.idea/*
|
||||
/.idea/libraries
|
||||
/.idea/modules.xml
|
||||
/.idea/workspace.xml
|
||||
# idea files: exclude everything except dictionnaries
|
||||
.idea/caches
|
||||
.idea/codeStyles
|
||||
.idea/libraries
|
||||
.idea/*.xml
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
|
||||
/tmp
|
||||
|
||||
ktlint
|
||||
.idea/copyright/New_vector.xml
|
||||
.idea/copyright/profiles_settings.xml
|
||||
|
25
.idea/dictionaries/bmarty.xml
generated
Normal file
25
.idea/dictionaries/bmarty.xml
generated
Normal file
@ -0,0 +1,25 @@
|
||||
<component name="ProjectDictionaryState">
|
||||
<dictionary name="bmarty">
|
||||
<words>
|
||||
<w>backstack</w>
|
||||
<w>bytearray</w>
|
||||
<w>checkables</w>
|
||||
<w>ciphertext</w>
|
||||
<w>coroutine</w>
|
||||
<w>decryptor</w>
|
||||
<w>emoji</w>
|
||||
<w>emojis</w>
|
||||
<w>hmac</w>
|
||||
<w>ktlint</w>
|
||||
<w>linkified</w>
|
||||
<w>linkify</w>
|
||||
<w>megolm</w>
|
||||
<w>msisdn</w>
|
||||
<w>pbkdf</w>
|
||||
<w>pkcs</w>
|
||||
<w>signin</w>
|
||||
<w>signout</w>
|
||||
<w>signup</w>
|
||||
</words>
|
||||
</dictionary>
|
||||
</component>
|
258
CHANGES.md
258
CHANGES.md
@ -1,24 +1,254 @@
|
||||
Changes in RiotX 0.XX (2019-XX-XX)
|
||||
Changes in RiotX 0.11.0 (2019-12-19)
|
||||
===================================================
|
||||
|
||||
Features ✨:
|
||||
- Implement soft logout (#281)
|
||||
|
||||
Improvements 🙌:
|
||||
- Handle navigation to room via room alias (#201)
|
||||
- Open matrix.to link in RiotX (#57)
|
||||
- Limit sticker size in the timeline
|
||||
|
||||
Other changes:
|
||||
- Use same default room colors than Riot-Web
|
||||
|
||||
Bugfix 🐛:
|
||||
- Scroll breadcrumbs to top when opened
|
||||
- Render default room name when it starts with an emoji (#477)
|
||||
- Do not display " (IRC)" in display names https://github.com/vector-im/riot-android/issues/444
|
||||
- Fix rendering issue with HTML formatted body
|
||||
- Disable click on Stickers (#703)
|
||||
|
||||
Build 🧱:
|
||||
- Include diff-match-patch sources as dependency
|
||||
|
||||
Changes in RiotX 0.10.0 (2019-12-10)
|
||||
===================================================
|
||||
|
||||
Features ✨:
|
||||
- Breadcrumbs: switch from one room to another quickly (#571)
|
||||
|
||||
Improvements 🙌:
|
||||
- Support entering a RiotWeb client URL instead of the homeserver URL during connection (#744)
|
||||
|
||||
Other changes:
|
||||
- Add reason for all membership events (https://github.com/matrix-org/matrix-doc/pull/2367)
|
||||
|
||||
Bugfix 🐛:
|
||||
- When automardown is ON, pills are sent as MD in body (#739)
|
||||
- "ban" event are not rendered correctly (#716)
|
||||
- Fix crash when rotating screen in Room timeline
|
||||
|
||||
Changes in RiotX 0.9.1 (2019-12-05)
|
||||
===================================================
|
||||
|
||||
Bugfix 🐛:
|
||||
- Fix an issue with DB transaction (#740)
|
||||
|
||||
Changes in RiotX 0.9.0 (2019-12-05)
|
||||
===================================================
|
||||
|
||||
Features ✨:
|
||||
- Account creation. It's now possible to create account on any homeserver with RiotX (#34)
|
||||
- Iteration of the login flow (#613)
|
||||
|
||||
Improvements 🙌:
|
||||
- Send mention Pills from composer
|
||||
- Links in message preview in the bottom sheet are now active.
|
||||
- Rework the read marker to make it more usable
|
||||
|
||||
Other changes:
|
||||
- Fix a small grammatical error when an empty room list is shown.
|
||||
|
||||
Bugfix 🐛:
|
||||
- Do not show long click help if only invitation are displayed
|
||||
- Fix emoji filtering not working
|
||||
- Fix issue of closing Realm in another thread (#725)
|
||||
- Attempt to properly cancel the crypto module when user signs out (#724)
|
||||
|
||||
Changes in RiotX 0.8.0 (2019-11-19)
|
||||
===================================================
|
||||
|
||||
Features ✨:
|
||||
- Handle long click on room in the room list (#395)
|
||||
- Ignore/UnIgnore users, and display list of ignored users (#542, #617)
|
||||
|
||||
Improvements 🙌:
|
||||
- Search reaction by name or keyword in emoji picker
|
||||
- Handle code tags (#567)
|
||||
- Support spoiler messages
|
||||
- Support m.sticker and m.room.join_rules events in timeline
|
||||
|
||||
Other changes:
|
||||
- Markdown set to off by default (#412)
|
||||
- Accessibility improvements to the attachment file type chooser
|
||||
|
||||
Bugfix 🐛:
|
||||
- Fix issues with some member events rendering (#498)
|
||||
- Passphrase does not match (Export room keys) (#644)
|
||||
- Ask for permission to write external storage when uri comes from the keyboard (#658)
|
||||
- Fix issue with english US/GB translation (#671)
|
||||
|
||||
Changes in RiotX 0.7.0 (2019-10-24)
|
||||
===================================================
|
||||
|
||||
Features:
|
||||
- Contextual action menu for messages in room
|
||||
- Share elements from other app to RiotX (#58)
|
||||
- Read marker (#84)
|
||||
- Add ability to report content (#515)
|
||||
|
||||
Improvements:
|
||||
-
|
||||
- Persist active tab between sessions (#503)
|
||||
- Do not upload file too big for the homeserver (#587)
|
||||
- Attachments: start using system pickers (#52)
|
||||
- Mark all messages as read (#396)
|
||||
|
||||
|
||||
Other changes:
|
||||
-
|
||||
- Accessibility improvements to read receipts in the room timeline and reactions emoji chooser
|
||||
|
||||
Bugfix:
|
||||
-
|
||||
- Fix issue on upload error in loop (#587)
|
||||
- Fix opening a permalink: the targeted event is displayed twice (#556)
|
||||
- Fix opening a permalink paginates all the history up to the last event (#282)
|
||||
- after login, the icon in the top left is a green 'A' for (all communities) rather than my avatar (#267)
|
||||
- Picture uploads are unreliable, pictures are shown in wrong aspect ratio on desktop client (#517)
|
||||
- Invitation notifications are not dismissed automatically if room is joined from another client (#347)
|
||||
- Opening links from RiotX reuses browser tab (#599)
|
||||
|
||||
Translations:
|
||||
-
|
||||
Changes in RiotX 0.6.1 (2019-09-24)
|
||||
===================================================
|
||||
|
||||
Bugfix:
|
||||
- Fix crash: MergedHeaderItem was missing dimensionConverter
|
||||
|
||||
Changes in RiotX 0.6.0 (2019-09-24)
|
||||
===================================================
|
||||
|
||||
Features:
|
||||
- Save draft of a message when exiting a room with non empty composer (#329)
|
||||
|
||||
Improvements:
|
||||
- Add unread indent on room list (#485)
|
||||
- Message Editing: Update notifications (#128)
|
||||
- Remove any notification of a redacted event (#563)
|
||||
|
||||
Other changes:
|
||||
- Fix a few accessibility issues
|
||||
|
||||
Bugfix:
|
||||
- Fix characters erased from the Search field when the result are coming (#545)
|
||||
- "No connection" banner was displayed by mistake
|
||||
- Leaving community (from another client) has no effect on RiotX (#497)
|
||||
- Push rules was not retrieved after a clear cache
|
||||
- m.notice messages trigger push notifications (#238)
|
||||
- Embiggen messages with multiple emojis also for edited messages (#458)
|
||||
|
||||
Build:
|
||||
-
|
||||
- Fix (again) issue with bad versionCode generated by Buildkite (#553)
|
||||
|
||||
Changes in RiotX 0.5.0 (2019-09-17)
|
||||
===================================================
|
||||
|
||||
Features:
|
||||
- Implementation of login to homeserver with SSO (#557)
|
||||
- Handle M_CONSENT_NOT_GIVEN error (#64)
|
||||
- Auto configure homeserver and identity server URLs of LoginActivity with a magic link
|
||||
|
||||
Improvements:
|
||||
- Reduce default release build log level, and lab option to enable more logs.
|
||||
- Display a no network indicator when there is no network (#559)
|
||||
|
||||
Bugfix:
|
||||
- Fix crash due to missing informationData (#535)
|
||||
- Progress in initial sync dialog is decreasing for a step and should not (#532)
|
||||
- Fix rendering issue of accepted third party invitation event
|
||||
- All current notifications were dismissed by mistake when the app is launched from the launcher
|
||||
|
||||
Build:
|
||||
- Fix issue with version name (#533)
|
||||
- Fix issue with bad versionCode generated by Buildkite (#553)
|
||||
|
||||
Changes in RiotX 0.4.0 (2019-08-30)
|
||||
===================================================
|
||||
|
||||
Features:
|
||||
- Display read receipts in timeline (#81)
|
||||
|
||||
Improvements:
|
||||
- Reactions: Reinstate the ability to react with non-unicode keys (#307)
|
||||
|
||||
Bugfix:
|
||||
- Fix text diff linebreak display (#441)
|
||||
- Date change message repeats for each redaction until a normal message (#358)
|
||||
- Slide-in reply icon is distorted (#423)
|
||||
- Regression / e2e replies not encrypted
|
||||
- Some video won't play
|
||||
- Privacy: remove log of notifiable event (#519)
|
||||
- Fix crash with EmojiCompat (#530)
|
||||
|
||||
Changes in RiotX 0.3.0 (2019-08-08)
|
||||
===================================================
|
||||
|
||||
Features:
|
||||
- Create Direct Room flow
|
||||
- Handle `/markdown` command
|
||||
|
||||
Improvements:
|
||||
- UI for pending edits (#193)
|
||||
- UX image preview screen transition (#393)
|
||||
- Basic support for resending failed messages (retry/remove)
|
||||
- Enable proper cancellation of suspending functions (including db transaction)
|
||||
- Enhances network connectivity checks in SDK
|
||||
- Add "View Edit History" item in the message bottom sheet (#401)
|
||||
- Cancel sync request on pause and timeout to 0 after pause (#404)
|
||||
|
||||
Other changes:
|
||||
- Show sync progress also in room detail screen (#403)
|
||||
|
||||
Bugfix:
|
||||
- Edited message: link confusion when (edited) appears in body (#398)
|
||||
- Close detail room screen when the room is left with another client (#256)
|
||||
- Clear notification for a room left on another client
|
||||
- Fix messages with empty `in_reply_to` not rendering (#447)
|
||||
- Fix clear cache (#408) and Logout (#205)
|
||||
- Fix `(edited)` link can be copied to clipboard (#402)
|
||||
|
||||
Build:
|
||||
- Split APK: generate one APK per arch, to reduce APK size of about 30%
|
||||
|
||||
|
||||
Changes in RiotX 0.2.0 (2019-07-18)
|
||||
===================================================
|
||||
|
||||
Features:
|
||||
- Message Editing: View edit history (#121)
|
||||
- Rooms filtering (#304)
|
||||
- Edit in encrypted room
|
||||
|
||||
Improvements:
|
||||
- Handle click on redacted events: view source and create permalink
|
||||
- Improve long tap menu: reply on top, more compact (#368)
|
||||
- Quick reply in timeline with swipe gesture (#167)
|
||||
- Improve edit of replies
|
||||
- Improve performance on Room Members and Users management (#381)
|
||||
|
||||
Other changes:
|
||||
- migrate from rxbinding 2 to rxbinding 3
|
||||
|
||||
Bugfix:
|
||||
- Fix regression on permalink click
|
||||
- Fix crash reported by the PlayStore (#341)
|
||||
- Fix Chat composer separator color in dark/black theme
|
||||
- Fix bad layout for room directory filter (#349)
|
||||
- Fix Copying link from a message shouldn't open context menu (#364)
|
||||
|
||||
Changes in RiotX 0.1.0 (2019-07-11)
|
||||
===================================================
|
||||
|
||||
First release!
|
||||
|
||||
Mode details here: https://medium.com/@RiotChat/introducing-the-riotx-beta-for-android-b17952e8f771
|
||||
|
||||
|
||||
=======================================================
|
||||
@ -26,24 +256,24 @@ Build:
|
||||
=======================================================
|
||||
|
||||
|
||||
Changes in RiotX 0.XX (2019-XX-XX)
|
||||
Changes in RiotX 0.0.0 (2019-XX-XX)
|
||||
===================================================
|
||||
|
||||
Features:
|
||||
Features ✨:
|
||||
-
|
||||
|
||||
Improvements:
|
||||
Improvements 🙌:
|
||||
-
|
||||
|
||||
Other changes:
|
||||
-
|
||||
|
||||
Bugfix:
|
||||
Bugfix 🐛:
|
||||
-
|
||||
|
||||
Translations:
|
||||
Translations 🗣:
|
||||
-
|
||||
|
||||
Build:
|
||||
Build 🧱:
|
||||
-
|
||||
|
||||
|
@ -40,19 +40,45 @@ Please add a line to the top of the file `CHANGES.md` describing your change.
|
||||
|
||||
Make sure the following commands execute without any error:
|
||||
|
||||
> ./tools/check/check_code_quality.sh
|
||||
#### Internal tool
|
||||
|
||||
> ./gradlew lintGplayRelease
|
||||
<pre>
|
||||
./tools/check/check_code_quality.sh
|
||||
</pre>
|
||||
|
||||
#### ktlint
|
||||
|
||||
<pre>
|
||||
curl -sSLO https://github.com/pinterest/ktlint/releases/download/0.34.2/ktlint && chmod a+x ktlint
|
||||
./ktlint --android --experimental -v
|
||||
</pre>
|
||||
|
||||
Note that you can run
|
||||
|
||||
<pre>
|
||||
./ktlint --android --experimental -v -F
|
||||
</pre>
|
||||
|
||||
For ktlint to fix some detected errors for you (you still have to check and commit the fix of course)
|
||||
|
||||
#### lint
|
||||
|
||||
<pre>
|
||||
./gradlew lintGplayRelease
|
||||
./gradlew lintFdroidRelease
|
||||
</pre>
|
||||
|
||||
### Unit tests
|
||||
|
||||
Make sure the following commands execute without any error:
|
||||
|
||||
> ./gradlew testGplayReleaseUnitTest
|
||||
<pre>
|
||||
./gradlew testGplayReleaseUnitTest
|
||||
</pre>
|
||||
|
||||
### Tests
|
||||
|
||||
RiotX is currently supported on Android Jelly Bean (API 16+): please test your change on an Android device (or Android emulator) running with API 16. Many issues can happen (including crashes) on older devices.
|
||||
RiotX is currently supported on Android KitKat (API 19+): please test your change on an Android device (or Android emulator) running with API 19. Many issues can happen (including crashes) on older devices.
|
||||
Also, if possible, please test your change on a real device. Testing on Android emulator may not be sufficient.
|
||||
|
||||
### Internationalisation
|
||||
@ -60,6 +86,10 @@ Also, if possible, please test your change on a real device. Testing on Android
|
||||
When adding new string resources, please only add new entries in file `value/strings.xml`. Translations will be added later by the community of translators with a specific tool named [Weblate](https://translate.riot.im/projects/riot-android/).
|
||||
Do not hesitate to use plurals when appropriate.
|
||||
|
||||
### Accessibility
|
||||
|
||||
Please consider accessibility as an important point. As a minimum requirement, in layout XML files please use attributes such as `android:contentDescription` and `android:importantForAccessibility`, and test with a screen reader if it's working well. You can add new string resources, dedicated to accessibility, in this case, please prefix theirs id with `a11y_`.
|
||||
|
||||
### Layout
|
||||
|
||||
When adding or editing layouts, make sure the layout will render correctly if device uses a RTL (Right To Left) language.
|
||||
|
29
README.md
29
README.md
@ -1,4 +1,4 @@
|
||||
[](https://buildkite.com/matrix-dot-org/riotx-android)
|
||||
[](https://buildkite.com/matrix-dot-org/riotx-android/builds?branch=develop)
|
||||
[](https://translate.riot.im/engage/riot-android/?utm_source=widget)
|
||||
[](https://matrix.to/#/#riotx:matrix.org)
|
||||
[](https://sonarcloud.io/dashboard?id=vector.android.riotx)
|
||||
@ -7,14 +7,31 @@
|
||||
|
||||
# RiotX Android
|
||||
|
||||
RiotX is an Android Matrix Client currently in development. The application is not yet available on the PlayStore.
|
||||
RiotX is an Android Matrix Client currently in beta but in active development.
|
||||
|
||||
It's based on a new Matrix SDK, written in Kotlin.
|
||||
It is a total rewrite of [Riot-Android](https://github.com/vector-im/riot-android) with a new user experience. RiotX will become the official replacement as soon as all features are implemented.
|
||||
|
||||
Download nightly build here: [](https://buildkite.com/matrix-dot-org/riotx-android/builds?branch=develop)
|
||||
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png" alt="Get it on Google Play" height="60">](https://play.google.com/store/apps/details?id=im.vector.riotx)
|
||||
|
||||
Nightly build: [](https://buildkite.com/matrix-dot-org/riotx-android/builds?branch=develop)
|
||||
|
||||
# New Android SDK
|
||||
|
||||
RiotX is based on a new Android SDK fully written in Kotlin (like RiotX). In order to make the early development as fast as possible, RiotX and the new SDK currently share the same git repository. We will make separate repos once the API is stable enough.
|
||||
|
||||
|
||||
# Roadmap
|
||||
|
||||
The current target is to release an application out of beta with the same level of features (and even more) as Riot.
|
||||
The roadmap has 3 phases:
|
||||
|
||||
- [phase 0](https://github.com/vector-im/riotX-android/labels/phase0): Prototyping / Project setup
|
||||
- [phase 1](https://github.com/vector-im/riotX-android/labels/phase1): Beta release to the Play Store
|
||||
- [phase 2](https://github.com/vector-im/riotX-android/labels/phase2): Out of beta
|
||||
|
||||
Matrix Room: [](https://matrix.to/#/#riotx:matrix.org)
|
||||
|
||||
## Contributing
|
||||
|
||||
Please refer to [CONTRIBUTING.md](https://github.com/vector-im/riotX-android/blob/develop/CONTRIBUTING.md) if you want to contribute the Matrix on Android projects!
|
||||
Please refer to [CONTRIBUTING.md](https://github.com/vector-im/riotX-android/blob/develop/CONTRIBUTING.md) if you want to contribute on Matrix Android projects!
|
||||
|
||||
Come chat with the community in the dedicated Matrix [room](https://matrix.to/#/#riotx:matrix.org).
|
||||
|
76
build.gradle
76
build.gradle
@ -1,9 +1,7 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.3.21'
|
||||
ext.koin_version = '1.0.2'
|
||||
// TODO ext.koin_version = '2.0.0-GA'
|
||||
ext.kotlin_version = '1.3.50'
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
@ -12,11 +10,11 @@ buildscript {
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.4.1'
|
||||
classpath 'com.google.gms:google-services:4.2.0'
|
||||
classpath "com.airbnb.okreplay:gradle-plugin:1.4.0"
|
||||
classpath 'com.android.tools.build:gradle:3.5.3'
|
||||
classpath 'com.google.gms:google-services:4.3.2'
|
||||
classpath "com.airbnb.okreplay:gradle-plugin:1.5.0"
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.6.2'
|
||||
classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.7.1'
|
||||
classpath 'com.google.android.gms:oss-licenses-plugin:0.9.5'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
@ -26,16 +24,46 @@ buildscript {
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
maven { url "http://dl.bintray.com/piasy/maven" }
|
||||
maven { url 'https://jitpack.io' }
|
||||
// For olm library. This has to be declared first, to ensure that Olm library is not downloaded from another repo
|
||||
maven {
|
||||
url 'https://jitpack.io'
|
||||
content {
|
||||
// Use this repo only for olm library
|
||||
includeGroupByRegex "org\\.matrix\\.gitlab\\.matrix-org"
|
||||
// And also for FilePicker
|
||||
includeGroupByRegex "com\\.github\\.jaiselrahman"
|
||||
// And monarchy
|
||||
includeGroupByRegex "com\\.github\\.Zhuinden"
|
||||
}
|
||||
}
|
||||
maven {
|
||||
url "http://dl.bintray.com/piasy/maven"
|
||||
content {
|
||||
includeGroupByRegex "com\\.github\\.piasy"
|
||||
}
|
||||
}
|
||||
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
|
||||
google()
|
||||
jcenter()
|
||||
// For Olm SDK
|
||||
maven {
|
||||
url 'https://jitpack.io'
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).all {
|
||||
options.compilerArgs += [
|
||||
'-Adagger.gradle.incremental=enabled'
|
||||
]
|
||||
}
|
||||
|
||||
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
|
||||
// Warnings are potential errors, so stop ignoring them
|
||||
kotlinOptions.allWarningsAsErrors = true
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
extensions.findByName("kapt")?.arguments {
|
||||
arg("dagger.gradle.incremental", "enabled")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
@ -44,6 +72,10 @@ task clean(type: Delete) {
|
||||
|
||||
apply plugin: 'org.sonarqube'
|
||||
|
||||
// To run a sonar analysis:
|
||||
// Run './gradlew sonarqube -Dsonar.login=<REPLACE_WITH_SONAR_KEY>'
|
||||
// The SONAR_KEY is stored in passbolt
|
||||
|
||||
sonarqube {
|
||||
properties {
|
||||
property "sonar.projectName", "RiotX-Android"
|
||||
@ -69,3 +101,23 @@ project(":vector") {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//project(":matrix-sdk-android") {
|
||||
// sonarqube {
|
||||
// properties {
|
||||
// property "sonar.sources", project(":matrix-sdk-android").android.sourceSets.main.java.srcDirs
|
||||
// // exclude source code from analyses separated by a colon (:)
|
||||
// // property "sonar.exclusions", "**/*.*"
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//project(":matrix-sdk-android-rx") {
|
||||
// sonarqube {
|
||||
// properties {
|
||||
// property "sonar.sources", project(":matrix-sdk-android-rx").android.sourceSets.main.java.srcDirs
|
||||
// // exclude source code from analyses separated by a colon (:)
|
||||
// // property "sonar.exclusions", "**/*.*"
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
1
diff-match-patch/.gitignore
vendored
Normal file
1
diff-match-patch/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/build
|
8
diff-match-patch/build.gradle
Normal file
8
diff-match-patch/build.gradle
Normal file
@ -0,0 +1,8 @@
|
||||
apply plugin: 'java-library'
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
}
|
||||
|
||||
sourceCompatibility = "8"
|
||||
targetCompatibility = "8"
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
This document aims to describe how Riot X android displays notifications to the end user. It also clarifies notifications and background settings in the app.
|
||||
This document aims to describe how RiotX android displays notifications to the end user. It also clarifies notifications and background settings in the app.
|
||||
|
||||
# Table of Contents
|
||||
1. [Prerequisites Knowledge](#prerequisites-knowledge)
|
||||
@ -50,7 +50,7 @@ By default, this is 0, so the server will return immediately even if the respons
|
||||
|
||||
**delay** is a client preference. When the server responds to a sync request, the client waits for `delay`before calling a new sync.
|
||||
|
||||
When the Riot X Android app is open (i.e in foreground state), the default timeout is 30 seconds, and delay is 0.
|
||||
When the RiotX Android app is open (i.e in foreground state), the default timeout is 30 seconds, and delay is 0.
|
||||
|
||||
## How does a mobile app receives push notification
|
||||
|
||||
@ -86,7 +86,7 @@ This need some disambiguation, because it is the source of common confusion:
|
||||
In order to send a push to a mobile, App developers need to have a server that will use the FCM APIs, and these APIs requires authentication!
|
||||
This server is called a **Push Gateway** in the matrix world
|
||||
|
||||
That means that Riot X Android, a matrix client created by New Vector, is using a **Push Gateway** with the needed credentials (FCM API secret Key) in order to send push to the New Vector client.
|
||||
That means that RiotX Android, a matrix client created by New Vector, is using a **Push Gateway** with the needed credentials (FCM API secret Key) in order to send push to the New Vector client.
|
||||
|
||||
If you create your own matrix client, you will also need to deploy an instance of a **Push Gateway** with the credentials needed to use FCM for your app.
|
||||
|
||||
@ -223,7 +223,7 @@ Upon reception of the FCM push, RiotX will perform a sync call to the Home Serve
|
||||
* The sync generates additional notifications (e.g an encrypted message where the user is mentioned detected locally)
|
||||
* The sync takes too long and the process is killed before completion, or network is not reliable and the sync fails.
|
||||
|
||||
Riot X implements several strategies in these cases (TODO document)
|
||||
RiotX implements several strategies in these cases (TODO document)
|
||||
|
||||
## FCM Fallback mode
|
||||
|
||||
|
260
docs/signin.md
Normal file
260
docs/signin.md
Normal file
@ -0,0 +1,260 @@
|
||||
# Sign in to a homeserver
|
||||
|
||||
This document describes the flow of signin to a homeserver, and also the flow when user want to reset his password. Examples come from the `matrix.org` homeserver.
|
||||
|
||||
## Sign up flows
|
||||
|
||||
### Get the flow
|
||||
|
||||
Client request the sign-in flows, once the homeserver is chosen by the user and its url is known (in the example it's `https://matrix.org`)
|
||||
|
||||
> curl -X GET 'https://matrix.org/_matrix/client/r0/login'
|
||||
|
||||
200
|
||||
|
||||
```json
|
||||
{
|
||||
"flows": [
|
||||
{
|
||||
"type": "m.login.password"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Login with username
|
||||
|
||||
The user is able to connect using `m.login.password`
|
||||
|
||||
> curl -X POST --data $'{"identifier":{"type":"m.id.user","user":"alice"},"password":"weak_password","type":"m.login.password","initial_device_display_name":"Portable"}' 'https://matrix.org/_matrix/client/r0/login'
|
||||
|
||||
```json
|
||||
{
|
||||
"identifier": {
|
||||
"type": "m.id.user",
|
||||
"user": "alice"
|
||||
},
|
||||
"password": "weak_password",
|
||||
"type": "m.login.password",
|
||||
"initial_device_display_name": "Portable"
|
||||
}
|
||||
```
|
||||
|
||||
#### Incorrect password
|
||||
|
||||
403
|
||||
|
||||
```json
|
||||
{
|
||||
"errcode": "M_FORBIDDEN",
|
||||
"error": "Invalid password"
|
||||
}
|
||||
```
|
||||
|
||||
#### Correct password:
|
||||
|
||||
We get credential (200)
|
||||
|
||||
```json
|
||||
{
|
||||
"user_id": "@benoit0816:matrix.org",
|
||||
"access_token": "MDAxOGxvY2F0aW9uIG1hdHREDACTEDb2l0MDgxNjptYXRyaXgub3JnCjAwMTZjaWQgdHlwZSA9IGFjY2VzcwowMDIxY2lkIG5vbmNlID0gfnYrSypfdTtkNXIuNWx1KgowMDJmc2lnbmF0dXJlIOsh1XqeAkXexh4qcofl_aR4kHJoSOWYGOhE7-ubX-DZCg",
|
||||
"home_server": "matrix.org",
|
||||
"device_id": "GTVREDALBF",
|
||||
"well_known": {
|
||||
"m.homeserver": {
|
||||
"base_url": "https:\/\/matrix.org\/"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Login with email
|
||||
|
||||
If the user has associated an email with its account, he can signin using the email.
|
||||
|
||||
> curl -X POST --data $'{"identifier":{"type":"m.id.thirdparty","medium":"email","address":"alice@yopmail.com"},"password":"weak_password","type":"m.login.password","initial_device_display_name":"Portable"}' 'https://matrix.org/_matrix/client/r0/login'
|
||||
|
||||
```json
|
||||
{
|
||||
"identifier": {
|
||||
"type": "m.id.thirdparty",
|
||||
"medium": "email",
|
||||
"address": "alice@yopmail.com"
|
||||
},
|
||||
"password": "weak_password",
|
||||
"type": "m.login.password",
|
||||
"initial_device_display_name": "Portable"
|
||||
}
|
||||
```
|
||||
|
||||
#### Unknown email
|
||||
|
||||
403
|
||||
|
||||
```json
|
||||
{
|
||||
"errcode": "M_FORBIDDEN",
|
||||
"error": ""
|
||||
}
|
||||
```
|
||||
|
||||
#### Known email, wrong password
|
||||
|
||||
403
|
||||
|
||||
```json
|
||||
{
|
||||
"errcode": "M_FORBIDDEN",
|
||||
"error": "Invalid password"
|
||||
}
|
||||
```
|
||||
|
||||
##### Known email, correct password
|
||||
|
||||
We get the credentials (200)
|
||||
|
||||
```json
|
||||
{
|
||||
"user_id": "@alice:matrix.org",
|
||||
"access_token": "MDAxOGxvY2F0aW9uIG1hdHJpeC5vcmREDACTEDZXJfaWQgPSBAYmVub2l0MDgxNjptYXRyaXgub3JnCjAwMTZjaWQgdHlwZSA9IGFjY2VzcwowMDIxY2lkIG5vbmNlID0gNjtDY0MwRlNPSFFoOC5wOgowMDJmc2lnbmF0dXJlIGiTRm1mYLLxQywxOh3qzQVT8HoEorSokEP2u-bAwtnYCg",
|
||||
"home_server": "matrix.org",
|
||||
"device_id": "WBSREDASND",
|
||||
"well_known": {
|
||||
"m.homeserver": {
|
||||
"base_url": "https:\/\/matrix.org\/"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Login with Msisdn
|
||||
|
||||
Not supported yet in RiotX
|
||||
|
||||
### Login with SSO
|
||||
|
||||
> curl -X GET 'https://homeserver.with.sso/_matrix/client/r0/login'
|
||||
|
||||
200
|
||||
|
||||
```json
|
||||
{
|
||||
"flows": [
|
||||
{
|
||||
"type": "m.login.sso"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
In this case, the user can click on "Sign in with SSO" and the web screen will be displayed on the page `https://homeserver.with.sso/_matrix/static/client/login/` and the credentials will be passed back to the native code through the JS bridge
|
||||
|
||||
## Reset password
|
||||
|
||||
Ref: `https://matrix.org/docs/spec/client_server/latest#post-matrix-client-r0-account-password-email-requesttoken`
|
||||
|
||||
When the user has forgotten his password, he can reset it by providing an email and a new password.
|
||||
|
||||
Here is the flow:
|
||||
|
||||
### Send email
|
||||
|
||||
User is asked to enter the email linked to his account and a new password.
|
||||
We display a warning regarding e2e.
|
||||
|
||||
At the first step, we do not send the password, only the email and a client secret, generated by the application
|
||||
|
||||
> curl -X POST --data $'{"client_secret":"6c57f284-85e2-421b-8270-fb1795a120a7","send_attempt":0,"email":"user@domain.com"}' 'https://matrix.org/_matrix/client/r0/account/password/email/requestToken'
|
||||
|
||||
```json
|
||||
{
|
||||
"client_secret": "6c57f284-85e2-421b-8270-fb1795a120a7",
|
||||
"send_attempt": 0,
|
||||
"email": "user@domain.com"
|
||||
}
|
||||
```
|
||||
|
||||
#### When the email is not known
|
||||
|
||||
We get a 400
|
||||
|
||||
```json
|
||||
{
|
||||
"errcode": "M_THREEPID_NOT_FOUND",
|
||||
"error": "Email not found"
|
||||
}
|
||||
```
|
||||
|
||||
#### When the email is known
|
||||
|
||||
We get a 200 with a `sid`
|
||||
|
||||
```json
|
||||
{
|
||||
"sid": "tQNbrREDACTEDldA"
|
||||
}
|
||||
```
|
||||
|
||||
Then the user is asked to click on the link in the email he just received, and to confirm when it's done.
|
||||
|
||||
During this step, the new password is sent to the homeserver.
|
||||
|
||||
If the user confirms before the link is clicked, we get an error:
|
||||
|
||||
> curl -X POST --data $'{"auth":{"type":"m.login.email.identity","threepid_creds":{"client_secret":"6c57f284-85e2-421b-8270-fb1795a120a7","sid":"tQNbrREDACTEDldA"}},"new_password":"weak_password"}' 'https://matrix.org/_matrix/client/r0/account/password'
|
||||
|
||||
```json
|
||||
{
|
||||
"auth": {
|
||||
"type": "m.login.email.identity",
|
||||
"threepid_creds": {
|
||||
"client_secret": "6c57f284-85e2-421b-8270-fb1795a120a7",
|
||||
"sid": "tQNbrREDACTEDldA"
|
||||
}
|
||||
},
|
||||
"new_password": "weak_password"
|
||||
}
|
||||
```
|
||||
|
||||
401
|
||||
|
||||
```json
|
||||
{
|
||||
"errcode": "M_UNAUTHORIZED",
|
||||
"error": ""
|
||||
}
|
||||
```
|
||||
|
||||
### User clicks on the link
|
||||
|
||||
The link has the form:
|
||||
|
||||
https://matrix.org/_matrix/client/unstable/password_reset/email/submit_token?token=fzZLBlcqhTKeaFQFSRbsQnQCkzbwtGAD&client_secret=6c57f284-85e2-421b-8270-fb1795a120a7&sid=tQNbrREDACTEDldA
|
||||
|
||||
It contains the client secret, a token and the sid
|
||||
|
||||
When the user click the link, if validate his ownership and the new password can now be ent by the application (on user demand):
|
||||
|
||||
> curl -X POST --data $'{"auth":{"type":"m.login.email.identity","threepid_creds":{"client_secret":"6c57f284-85e2-421b-8270-fb1795a120a7","sid":"tQNbrREDACTEDldA"}},"new_password":"weak_password"}' 'https://matrix.org/_matrix/client/r0/account/password'
|
||||
|
||||
```json
|
||||
{
|
||||
"auth": {
|
||||
"type": "m.login.email.identity",
|
||||
"threepid_creds": {
|
||||
"client_secret": "6c57f284-85e2-421b-8270-fb1795a120a7",
|
||||
"sid": "tQNbrREDACTEDldA"
|
||||
}
|
||||
},
|
||||
"new_password": "weak_password"
|
||||
}
|
||||
```
|
||||
|
||||
200
|
||||
|
||||
```json
|
||||
{}
|
||||
```
|
||||
|
||||
The password has been changed, and all the existing token are invalidated. User can now login with the new password.
|
579
docs/signup.md
Normal file
579
docs/signup.md
Normal file
@ -0,0 +1,579 @@
|
||||
# Sign up to a homeserver
|
||||
|
||||
This document describes the flow of registration to a homeserver. Examples come from the `matrix.org` homeserver.
|
||||
|
||||
*Ref*: https://matrix.org/docs/spec/client_server/latest#account-registration-and-management
|
||||
|
||||
## Sign up flows
|
||||
|
||||
### First step
|
||||
|
||||
Client request the sign-up flows, once the homeserver is chosen by the user and its url is known (in the example it's `https://matrix.org`)
|
||||
|
||||
> curl -X POST --data $'{}' 'https://matrix.org/_matrix/client/r0/register'
|
||||
|
||||
```json
|
||||
{
|
||||
}
|
||||
```
|
||||
|
||||
We get the flows with a 401, which also means that the registration is possible on this homeserver.
|
||||
|
||||
```json
|
||||
{
|
||||
"session": "vwehdKMtkRedactedAMwgCACZ",
|
||||
"flows": [
|
||||
{
|
||||
"stages": [
|
||||
"m.login.recaptcha",
|
||||
"m.login.terms",
|
||||
"m.login.dummy"
|
||||
]
|
||||
},
|
||||
{
|
||||
"stages": [
|
||||
"m.login.recaptcha",
|
||||
"m.login.terms",
|
||||
"m.login.email.identity"
|
||||
]
|
||||
}
|
||||
],
|
||||
"params": {
|
||||
"m.login.recaptcha": {
|
||||
"public_key": "6LcgI54UAAAAAoREDACTEDoDdOocFpYVdjYBRe4zb"
|
||||
},
|
||||
"m.login.terms": {
|
||||
"policies": {
|
||||
"privacy_policy": {
|
||||
"version": "1.0",
|
||||
"en": {
|
||||
"name": "Terms and Conditions",
|
||||
"url": "https:\/\/matrix.org\/_matrix\/consent?v=1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If the registration is not possible, we get a 403
|
||||
|
||||
```json
|
||||
{
|
||||
"errcode": "M_FORBIDDEN",
|
||||
"error": "Registration is disabled"
|
||||
}
|
||||
```
|
||||
|
||||
### Step 1: entering user name and password
|
||||
|
||||
The app is displaying a form to enter username and password.
|
||||
|
||||
> curl -X POST --data $'{"initial_device_display_name":"Mobile device","username":"alice","password": "weak_password"}' 'https://matrix.org/_matrix/client/r0/register'
|
||||
|
||||
```json
|
||||
{
|
||||
"initial_device_display_name": "Mobile device",
|
||||
"username": "alice",
|
||||
"password": "weak_password"
|
||||
}
|
||||
```
|
||||
|
||||
401. Note that the `session` value has changed (because we did not provide the previous value in the request body), but it's ok, we will use the new value for the next steps.
|
||||
|
||||
```json
|
||||
{
|
||||
"session": "xptUYoREDACTEDogOWAGVnbJQ",
|
||||
"flows": [
|
||||
{
|
||||
"stages": [
|
||||
"m.login.recaptcha",
|
||||
"m.login.terms",
|
||||
"m.login.dummy"
|
||||
]
|
||||
},
|
||||
{
|
||||
"stages": [
|
||||
"m.login.recaptcha",
|
||||
"m.login.terms",
|
||||
"m.login.email.identity"
|
||||
]
|
||||
}
|
||||
],
|
||||
"params": {
|
||||
"m.login.recaptcha": {
|
||||
"public_key": "6LcgI54UAAAAAoREDACTEDoDdOocFpYVdjYBRe4zb"
|
||||
},
|
||||
"m.login.terms": {
|
||||
"policies": {
|
||||
"privacy_policy": {
|
||||
"version": "1.0",
|
||||
"en": {
|
||||
"name": "Terms and Conditions",
|
||||
"url": "https:\/\/matrix.org\/_matrix\/consent?v=1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### If username already exists
|
||||
|
||||
We get a 400:
|
||||
|
||||
```json
|
||||
{
|
||||
"errcode": "M_USER_IN_USE",
|
||||
"error": "User ID already taken."
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2: entering email
|
||||
|
||||
User is proposed to enter an email. We skip this step.
|
||||
|
||||
> curl -X POST --data $'{"auth":{"session":"xptUYoREDACTEDogOWAGVnbJQ","type":"m.login.dummy"}}' 'https://matrix.org/_matrix/client/r0/register'
|
||||
|
||||
```json
|
||||
{
|
||||
"auth": {
|
||||
"session": "xptUYoREDACTEDogOWAGVnbJQ",
|
||||
"type": "m.login.dummy"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
401
|
||||
|
||||
```json
|
||||
{
|
||||
"session": "xptUYoREDACTEDogOWAGVnbJQ",
|
||||
"flows": [
|
||||
{
|
||||
"stages": [
|
||||
"m.login.recaptcha",
|
||||
"m.login.terms",
|
||||
"m.login.dummy"
|
||||
]
|
||||
},
|
||||
{
|
||||
"stages": [
|
||||
"m.login.recaptcha",
|
||||
"m.login.terms",
|
||||
"m.login.email.identity"
|
||||
]
|
||||
}
|
||||
],
|
||||
"params": {
|
||||
"m.login.recaptcha": {
|
||||
"public_key": "6LcgI54UAAAAAoREDACTEDoDdOocFpYVdjYBRe4zb"
|
||||
},
|
||||
"m.login.terms": {
|
||||
"policies": {
|
||||
"privacy_policy": {
|
||||
"version": "1.0",
|
||||
"en": {
|
||||
"name": "Terms and Conditions",
|
||||
"url": "https:\/\/matrix.org\/_matrix\/consent?v=1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"completed": [
|
||||
"m.login.dummy"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2 bis: we enter an email
|
||||
|
||||
We request a token to the homeserver. The `client_secret` is generated by the application
|
||||
|
||||
> curl -X POST --data $'{"client_secret":"53e679ea-oRED-ACTED-92b8-3012c49c6cfa","email":"alice@yopmail.com","send_attempt":0}' 'https://matrix.org/_matrix/client/r0/register/email/requestToken'
|
||||
|
||||
```json
|
||||
{
|
||||
"client_secret": "53e679ea-oRED-ACTED-92b8-3012c49c6cfa",
|
||||
"email": "alice@yopmail.com",
|
||||
"send_attempt": 0
|
||||
}
|
||||
```
|
||||
|
||||
200
|
||||
|
||||
```json
|
||||
{
|
||||
"sid": "qlBCREDACTEDEtgxD"
|
||||
}
|
||||
```
|
||||
|
||||
And
|
||||
|
||||
> curl -X POST --data $'{"auth":{"threepid_creds":{"client_secret":"53e679ea-oRED-ACTED-92b8-3012c49c6cfa","sid":"qlBCREDACTEDEtgxD"},"session":"xptUYoREDACTEDogOWAGVnbJQ","type":"m.login.email.identity"}}' 'https://matrix.org/_matrix/client/r0/register'
|
||||
|
||||
```json
|
||||
{
|
||||
"auth": {
|
||||
"threepid_creds": {
|
||||
"client_secret": "53e679ea-oRED-ACTED-92b8-3012c49c6cfa",
|
||||
"sid": "qlBCREDACTEDEtgxD"
|
||||
},
|
||||
"session": "xptUYoREDACTEDogOWAGVnbJQ",
|
||||
"type": "m.login.email.identity"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
We get 401 since the email is not validated yet:
|
||||
|
||||
```json
|
||||
{
|
||||
"errcode": "M_UNAUTHORIZED",
|
||||
"error": ""
|
||||
}
|
||||
```
|
||||
|
||||
The app is now polling on
|
||||
|
||||
> curl -X POST --data $'{"auth":{"threepid_creds":{"client_secret":"53e679ea-oRED-ACTED-92b8-3012c49c6cfa","sid":"qlBCREDACTEDEtgxD"},"session":"xptUYoREDACTEDogOWAGVnbJQ","type":"m.login.email.identity"}}' 'https://matrix.org/_matrix/client/r0/register'
|
||||
|
||||
```json
|
||||
{
|
||||
"auth": {
|
||||
"threepid_creds": {
|
||||
"client_secret": "53e679ea-oRED-ACTED-92b8-3012c49c6cfa",
|
||||
"sid": "qlBCREDACTEDEtgxD"
|
||||
},
|
||||
"session": "xptUYoREDACTEDogOWAGVnbJQ",
|
||||
"type": "m.login.email.identity"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
We click on the link received by email `https://matrix.org/_matrix/client/unstable/registration/email/submit_token?token=vtQjQIZfwdoREDACTEDozrmKYSWlCXsJ&client_secret=53e679ea-oRED-ACTED-92b8-3012c49c6cfa&sid=qlBCREDACTEDEtgxD` which contains:
|
||||
- A `token` vtQjQIZfwdoREDACTEDozrmKYSWlCXsJ
|
||||
- The `client_secret`: 53e679ea-oRED-ACTED-92b8-3012c49c6cfa
|
||||
- A `sid`: qlBCREDACTEDEtgxD
|
||||
|
||||
Once the link is clicked, the registration request (polling) returns a 401 with the following content:
|
||||
|
||||
```json
|
||||
{
|
||||
"session": "xptUYoREDACTEDogOWAGVnbJQ",
|
||||
"flows": [
|
||||
{
|
||||
"stages": [
|
||||
"m.login.recaptcha",
|
||||
"m.login.terms",
|
||||
"m.login.dummy"
|
||||
]
|
||||
},
|
||||
{
|
||||
"stages": [
|
||||
"m.login.recaptcha",
|
||||
"m.login.terms",
|
||||
"m.login.email.identity"
|
||||
]
|
||||
}
|
||||
],
|
||||
"params": {
|
||||
"m.login.recaptcha": {
|
||||
"public_key": "6LcgI54UAAAAAoREDACTEDoDdOocFpYVdjYBRe4zb"
|
||||
},
|
||||
"m.login.terms": {
|
||||
"policies": {
|
||||
"privacy_policy": {
|
||||
"version": "1.0",
|
||||
"en": {
|
||||
"name": "Terms and Conditions",
|
||||
"url": "https:\/\/matrix.org\/_matrix\/consent?v=1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"completed": [
|
||||
"m.login.email.identity"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: Accepting T&C
|
||||
|
||||
User is proposed to accept T&C and he accepts them
|
||||
|
||||
> curl -X POST --data $'{"auth":{"session":"xptUYoREDACTEDogOWAGVnbJQ","type":"m.login.terms"}}' 'https://matrix.org/_matrix/client/r0/register'
|
||||
|
||||
```json
|
||||
{
|
||||
"auth": {
|
||||
"session": "xptUYoREDACTEDogOWAGVnbJQ",
|
||||
"type": "m.login.terms"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
401
|
||||
|
||||
```json
|
||||
{
|
||||
"session": "xptUYoREDACTEDogOWAGVnbJQ",
|
||||
"flows": [
|
||||
{
|
||||
"stages": [
|
||||
"m.login.recaptcha",
|
||||
"m.login.terms",
|
||||
"m.login.dummy"
|
||||
]
|
||||
},
|
||||
{
|
||||
"stages": [
|
||||
"m.login.recaptcha",
|
||||
"m.login.terms",
|
||||
"m.login.email.identity"
|
||||
]
|
||||
}
|
||||
],
|
||||
"params": {
|
||||
"m.login.recaptcha": {
|
||||
"public_key": "6LcgI54UAAAAAoREDACTEDoDdOocFpYVdjYBRe4zb"
|
||||
},
|
||||
"m.login.terms": {
|
||||
"policies": {
|
||||
"privacy_policy": {
|
||||
"version": "1.0",
|
||||
"en": {
|
||||
"name": "Terms and Conditions",
|
||||
"url": "https:\/\/matrix.org\/_matrix\/consent?v=1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"completed": [
|
||||
"m.login.dummy",
|
||||
"m.login.terms"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Step 4: Captcha
|
||||
|
||||
User is proposed to prove he is not a robot and he does it:
|
||||
|
||||
> curl -X POST --data $'{"auth":{"response":"03AOLTBLSiGS9GhFDpAMblJ2nlXOmHXqAYJ5OvHCPUjiVLBef3k9snOYI_BDC32-t4D2jv-tpvkaiEI_uloobFd9RUTPpJ7con2hMddbKjSCYqXqcUQFhzhbcX6kw8uBnh2sbwBe80_ihrHGXEoACXQkL0ki1Q0uEtOeW20YBRjbNABsZPpLNZhGIWC0QVXnQ4FouAtZrl3gOAiyM-oG3cgP6M9pcANIAC_7T2P2amAHbtsTlSR9CsazNyS-rtDR9b5MywdtnWN9Aw8fTJb8cXQk_j7nvugMxzofPjSOrPKcr8h5OqPlpUCyxxnFtag6cuaPSUwh43D2L0E-ZX7djzaY2Yh_U2n6HegFNPOQ22CJmfrKwDlodmAfMPvAXyq77n3HpoREDACTEDo3830RHF4BfkGXUaZjctgg-A1mvC17hmQmQpkG7IhDqyw0onU-0vF_-ehCjq_CcQEDpS_O3uiHJaG5xGf-0rhLm57v_wA3deugbsZuO4uTuxZZycN_mKxZ97jlDVBetl9hc_5REPbhcT1w3uzTCSx7Q","session":"xptUYoREDACTEDogOWAGVnbJQ","type":"m.login.recaptcha"}}' 'https://matrix.org/_matrix/client/r0/register'
|
||||
|
||||
```json
|
||||
{
|
||||
"auth": {
|
||||
"response": "03AOLTBLSiGS9GhFDpAMblJ2nlXOmHXqAYJ5OvHCPUjiVLBef3k9snOYI_BDC32-t4D2jv-tpvkaiEI_uloobFd9RUTPpJ7con2hMddbKjSCYqXqcUQFhzhbcX6kw8uBnh2sbwBe80_ihrHGXEoACXQkL0ki1Q0uEtOeW20YBRjbNABsZPpLNZhGIWC0QVXnQ4FouAtZrl3gOAiyM-oG3cgP6M9pcANIAC_7T2P2amAHbtsTlSR9CsazNyS-rtDR9b5MywdtnWN9Aw8fTJb8cXQk_j7nvugMxzofPjSOrPKcr8h5OqPlpUCyxxnFtag6cuaPSUwh43D2L0E-ZX7djzaY2Yh_U2n6HegFNPOQ22CJmfrKwDlodmAfMPvAXyq77n3HpoREDACTEDo3830RHF4BfkGXUaZjctgg-A1mvC17hmQmQpkG7IhDqyw0onU-0vF_-ehCjq_CcQEDpS_O3uiHJaG5xGf-0rhLm57v_wA3deugbsZuO4uTuxZZycN_mKxZ97jlDVBetl9hc_5REPbhcT1w3uzTCSx7Q",
|
||||
"session": "xptUYoREDACTEDogOWAGVnbJQ",
|
||||
"type": "m.login.recaptcha"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
200
|
||||
|
||||
```json
|
||||
{
|
||||
"user_id": "@alice:matrix.org",
|
||||
"home_server": "matrix.org",
|
||||
"access_token": "MDAxOGxvY2F0aW9uIG1hdHJpeC5vcmcKMoREDACTEDo50aWZpZXIga2V5CjAwMTBjaWQgZ2VuID0gMQowMDI5Y2lkIHVzZXJfaWQgPSBAYmVub2l0eHh4eDptYXRoREDACTEDoCjAwMTZjaWQgdHlwZSA9IGFjY2VzcwowMDIxY2lkIG5vbmNlID0gNHVSVm00aVFDaWlKdoREDACTEDoJmc2lnbmF0dXJlIOmHnTLRfxiPjhrWhS-dThUX-qAzZktfRThzH1YyAsxaCg",
|
||||
"device_id": "FLBAREDAJZ"
|
||||
}
|
||||
```
|
||||
|
||||
The account is created!
|
||||
|
||||
### Step 5: MSISDN
|
||||
|
||||
Some homeservers may require the user to enter MSISDN.
|
||||
|
||||
On matrix.org, it's not required, and not even optional, but it's still possible for the app to add a MSISDN during the registration.
|
||||
|
||||
The user enter a phone number and select a country, the `client_secret` is generated by the application
|
||||
|
||||
> curl -X POST --data $'{"client_secret":"d3e285f6-972a-496c-9a22-7915a2db57c7","send_attempt":1,"country":"FR","phone_number":"+33611223344"}' 'https://matrix.org/_matrix/client/r0/register/msisdn/requestToken'
|
||||
|
||||
```json
|
||||
{
|
||||
"client_secret": "d3e285f6-972a-496c-9a22-7915a2db57c7",
|
||||
"send_attempt": 1,
|
||||
"country": "FR",
|
||||
"phone_number": "+33611223344"
|
||||
}
|
||||
```
|
||||
|
||||
If the msisdn is already associated to another account, you will received an error:
|
||||
|
||||
```json
|
||||
{
|
||||
"errcode": "M_THREEPID_IN_USE",
|
||||
"error": "Phone number is already in use"
|
||||
}
|
||||
```
|
||||
|
||||
If it is not the case, the homeserver send the SMS and returns some data, especially a `sid` and a `submit_url`:
|
||||
|
||||
```json
|
||||
{
|
||||
"msisdn": "33611223344",
|
||||
"intl_fmt": "+336 11 22 33 44",
|
||||
"success": true,
|
||||
"sid": "1678881798",
|
||||
"submit_url": "https:\/\/matrix.org\/_matrix\/client\/unstable\/add_threepid\/msisdn\/submit_token"
|
||||
}
|
||||
```
|
||||
|
||||
When you execute the register request, with the received `sid`, you get an error since the MSISDN is not validated yet:
|
||||
|
||||
> curl -X POST --data $'{"auth":{"type":"m.login.msisdn","session":"xptUYoREDACTEDogOWAGVnbJQ","threepid_creds":{"client_secret":"d3e285f6-972a-496c-9a22-7915a2db57c7","sid":"1678881798"}}}' 'https://matrix.org/_matrix/client/r0/register'
|
||||
|
||||
|
||||
```json
|
||||
"auth": {
|
||||
"type": "m.login.msisdn",
|
||||
"session": "xptUYoREDACTEDogOWAGVnbJQ",
|
||||
"threepid_creds": {
|
||||
"client_secret": "d3e285f6-972a-496c-9a22-7915a2db57c7",
|
||||
"sid": "1678881798"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
There is an issue on Synapse, which return a 401, it sends too much data along with the classical MatrixError fields:
|
||||
|
||||
```json
|
||||
{
|
||||
"session": "xptUYoREDACTEDogOWAGVnbJQ",
|
||||
"flows": [
|
||||
{
|
||||
"stages": [
|
||||
"m.login.recaptcha",
|
||||
"m.login.terms",
|
||||
"m.login.dummy"
|
||||
]
|
||||
},
|
||||
{
|
||||
"stages": [
|
||||
"m.login.recaptcha",
|
||||
"m.login.terms",
|
||||
"m.login.email.identity"
|
||||
]
|
||||
}
|
||||
],
|
||||
"params": {
|
||||
"m.login.recaptcha": {
|
||||
"public_key": "6LcgI54UAAAAABGdGmruw6DdOocFpYVdjYBRe4zb"
|
||||
},
|
||||
"m.login.terms": {
|
||||
"policies": {
|
||||
"privacy_policy": {
|
||||
"version": "1.0",
|
||||
"en": {
|
||||
"name": "Terms and Conditions",
|
||||
"url": "https:\/\/matrix.org\/_matrix\/consent?v=1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"completed": [],
|
||||
"error": "",
|
||||
"errcode": "M_UNAUTHORIZED"
|
||||
}
|
||||
```
|
||||
|
||||
The user receive the SMS, he can enter the SMS code in the app, which is sent using the "submit_url" received ie the response of the `requestToken` request:
|
||||
|
||||
> curl -X POST --data $'{"client_secret":"d3e285f6-972a-496c-9a22-7915a2db57c7","sid":"1678881798","token":"123456"}' 'https://matrix.org/_matrix/client/unstable/add_threepid/msisdn/submit_token'
|
||||
|
||||
```json
|
||||
{
|
||||
"client_secret": "d3e285f6-972a-496c-9a22-7915a2db57c7",
|
||||
"sid": "1678881798",
|
||||
"token": "123456"
|
||||
}
|
||||
```
|
||||
|
||||
If the code is not correct, we get a 200 with:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false
|
||||
}
|
||||
```
|
||||
|
||||
And if the code is correct we get a 200 with:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
We can now execute the registration request, to the homeserver
|
||||
|
||||
> curl -X POST --data $'{"auth":{"type":"m.login.msisdn","session":"xptUYoREDACTEDogOWAGVnbJQ","threepid_creds":{"client_secret":"d3e285f6-972a-496c-9a22-7915a2db57c7","sid":"1678881798"}}}' 'https://matrix.org/_matrix/client/r0/register'
|
||||
|
||||
```json
|
||||
{
|
||||
"auth": {
|
||||
"type": "m.login.msisdn",
|
||||
"session": "xptUYoREDACTEDogOWAGVnbJQ",
|
||||
"threepid_creds": {
|
||||
"client_secret": "d3e285f6-972a-496c-9a22-7915a2db57c7",
|
||||
"sid": "1678881798"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now the homeserver consider that the `m.login.msisdn` step is completed (401):
|
||||
|
||||
```json
|
||||
{
|
||||
"session": "xptUYoREDACTEDogOWAGVnbJQ",
|
||||
"flows": [
|
||||
{
|
||||
"stages": [
|
||||
"m.login.recaptcha",
|
||||
"m.login.terms",
|
||||
"m.login.dummy"
|
||||
]
|
||||
},
|
||||
{
|
||||
"stages": [
|
||||
"m.login.recaptcha",
|
||||
"m.login.terms",
|
||||
"m.login.email.identity"
|
||||
]
|
||||
}
|
||||
],
|
||||
"params": {
|
||||
"m.login.recaptcha": {
|
||||
"public_key": "6LcgI54UAAAAABGdGmruw6DdOocFpYVdjYBRe4zb"
|
||||
},
|
||||
"m.login.terms": {
|
||||
"policies": {
|
||||
"privacy_policy": {
|
||||
"version": "1.0",
|
||||
"en": {
|
||||
"name": "Terms and Conditions",
|
||||
"url": "https:\/\/matrix.org\/_matrix\/consent?v=1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"completed": [
|
||||
"m.login.msisdn"
|
||||
]
|
||||
}
|
||||
```
|
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,6 +1,6 @@
|
||||
#Tue Mar 19 09:53:05 CET 2019
|
||||
#Fri Sep 27 10:10:35 CEST 2019
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
|
||||
|
@ -5,16 +5,15 @@ apply plugin: 'kotlin-kapt'
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
|
||||
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 28
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
// Multidex is useful for tests
|
||||
multiDexEnabled true
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
@ -29,17 +28,20 @@ android {
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation project(":matrix-sdk-android")
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0-alpha01'
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
implementation 'io.reactivex.rxjava2:rxkotlin:2.3.0'
|
||||
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
|
||||
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
|
||||
// Paging
|
||||
implementation "androidx.paging:paging-runtime-ktx:2.1.0"
|
||||
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'androidx.test:runner:1.1.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
|
||||
androidTestImplementation 'androidx.test:runner:1.2.0'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
}
|
||||
|
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.rx;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest {
|
||||
@Test
|
||||
public void useAppContext() {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getTargetContext();
|
||||
|
||||
assertEquals("im.vector.matrix.rx.test", appContext.getPackageName());
|
||||
}
|
||||
}
|
@ -20,6 +20,7 @@ import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.Observer
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.android.MainThreadDisposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
|
||||
private class LiveDataObservable<T>(
|
||||
private val liveData: LiveData<T>,
|
||||
@ -56,6 +57,6 @@ private class LiveDataObservable<T>(
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> LiveData<T>.asObservable(defaultValue: T? = null): Observable<T> {
|
||||
return LiveDataObservable(this, defaultValue)
|
||||
}
|
||||
fun <T> LiveData<T>.asObservable(): Observable<T> {
|
||||
return LiveDataObservable(this).observeOn(Schedulers.computation())
|
||||
}
|
||||
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.rx
|
||||
|
||||
import im.vector.matrix.android.api.util.Optional
|
||||
import io.reactivex.Observable
|
||||
|
||||
fun <T : Any> Observable<Optional<T>>.unwrap(): Observable<T> {
|
||||
return filter { it.hasValue() }.map { it.get() }
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.rx
|
||||
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Single
|
||||
|
||||
fun <T> singleBuilder(builder: (callback: MatrixCallback<T>) -> Cancelable): Single<T> = Single.create {
|
||||
val callback: MatrixCallback<T> = object : MatrixCallback<T> {
|
||||
override fun onSuccess(data: T) {
|
||||
it.onSuccess(data)
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
it.tryOnError(failure)
|
||||
}
|
||||
}
|
||||
val cancelable = builder(callback)
|
||||
it.setCancellable {
|
||||
cancelable.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> completableBuilder(builder: (callback: MatrixCallback<T>) -> Cancelable): Completable = Completable.create {
|
||||
val callback: MatrixCallback<T> = object : MatrixCallback<T> {
|
||||
override fun onSuccess(data: T) {
|
||||
it.onComplete()
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
it.tryOnError(failure)
|
||||
}
|
||||
}
|
||||
val cancelable = builder(callback)
|
||||
it.setCancellable {
|
||||
cancelable.cancel()
|
||||
}
|
||||
}
|
@ -18,30 +18,63 @@ package im.vector.matrix.rx
|
||||
|
||||
import im.vector.matrix.android.api.session.room.Room
|
||||
import im.vector.matrix.android.api.session.room.model.EventAnnotationsSummary
|
||||
import im.vector.matrix.android.api.session.room.model.ReadReceipt
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.room.notification.RoomNotificationState
|
||||
import im.vector.matrix.android.api.session.room.send.UserDraft
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||
import im.vector.matrix.android.api.util.Optional
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.Single
|
||||
|
||||
class RxRoom(private val room: Room) {
|
||||
|
||||
fun liveRoomSummary(): Observable<RoomSummary> {
|
||||
return room.liveRoomSummary.asObservable()
|
||||
fun liveRoomSummary(): Observable<Optional<RoomSummary>> {
|
||||
return room.getRoomSummaryLive().asObservable()
|
||||
}
|
||||
|
||||
fun liveRoomMemberIds(): Observable<List<String>> {
|
||||
return room.getRoomMemberIdsLive().asObservable()
|
||||
}
|
||||
|
||||
fun liveAnnotationSummary(eventId: String): Observable<EventAnnotationsSummary> {
|
||||
fun liveAnnotationSummary(eventId: String): Observable<Optional<EventAnnotationsSummary>> {
|
||||
return room.getEventSummaryLive(eventId).asObservable()
|
||||
}
|
||||
|
||||
fun liveTimelineEvent(eventId: String): Observable<TimelineEvent> {
|
||||
return room.liveTimeLineEvent(eventId).asObservable()
|
||||
fun liveTimelineEvent(eventId: String): Observable<Optional<TimelineEvent>> {
|
||||
return room.getTimeLineEventLive(eventId).asObservable()
|
||||
}
|
||||
|
||||
fun liveReadMarker(): Observable<Optional<String>> {
|
||||
return room.getReadMarkerLive().asObservable()
|
||||
}
|
||||
|
||||
fun liveReadReceipt(): Observable<Optional<String>> {
|
||||
return room.getMyReadReceiptLive().asObservable()
|
||||
}
|
||||
|
||||
fun loadRoomMembersIfNeeded(): Single<Unit> = singleBuilder {
|
||||
room.loadRoomMembersIfNeeded(it)
|
||||
}
|
||||
|
||||
fun joinRoom(reason: String? = null,
|
||||
viaServers: List<String> = emptyList()): Single<Unit> = singleBuilder {
|
||||
room.join(reason, viaServers, it)
|
||||
}
|
||||
|
||||
fun liveEventReadReceipts(eventId: String): Observable<List<ReadReceipt>> {
|
||||
return room.getEventReadReceiptsLive(eventId).asObservable()
|
||||
}
|
||||
|
||||
fun liveDrafts(): Observable<List<UserDraft>> {
|
||||
return room.getDraftsLive().asObservable()
|
||||
}
|
||||
|
||||
fun liveNotificationState(): Observable<RoomNotificationState> {
|
||||
return room.getLiveRoomNotificationState().asObservable()
|
||||
}
|
||||
}
|
||||
|
||||
fun Room.rx(): RxRoom {
|
||||
return RxRoom(this)
|
||||
}
|
||||
}
|
||||
|
@ -16,13 +16,17 @@
|
||||
|
||||
package im.vector.matrix.rx
|
||||
|
||||
import androidx.paging.PagedList
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.session.group.model.GroupSummary
|
||||
import im.vector.matrix.android.api.session.pushers.Pusher
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
|
||||
import im.vector.matrix.android.api.session.sync.SyncState
|
||||
import im.vector.matrix.android.api.session.user.model.User
|
||||
import im.vector.matrix.android.api.util.Optional
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.Single
|
||||
|
||||
class RxSession(private val session: Session) {
|
||||
|
||||
@ -34,6 +38,10 @@ class RxSession(private val session: Session) {
|
||||
return session.liveGroupSummaries().asObservable()
|
||||
}
|
||||
|
||||
fun liveBreadcrumbs(): Observable<List<RoomSummary>> {
|
||||
return session.liveBreadcrumbs().asObservable()
|
||||
}
|
||||
|
||||
fun liveSyncState(): Observable<SyncState> {
|
||||
return session.syncState().asObservable()
|
||||
}
|
||||
@ -42,12 +50,44 @@ class RxSession(private val session: Session) {
|
||||
return session.livePushers().asObservable()
|
||||
}
|
||||
|
||||
fun liveUser(userId: String): Observable<User?> {
|
||||
return session.observeUser(userId).asObservable(User(userId))
|
||||
fun liveUser(userId: String): Observable<Optional<User>> {
|
||||
return session.liveUser(userId).asObservable().distinctUntilChanged()
|
||||
}
|
||||
|
||||
fun liveUsers(): Observable<List<User>> {
|
||||
return session.liveUsers().asObservable()
|
||||
}
|
||||
|
||||
fun liveIgnoredUsers(): Observable<List<User>> {
|
||||
return session.liveIgnoredUsers().asObservable()
|
||||
}
|
||||
|
||||
fun livePagedUsers(filter: String? = null): Observable<PagedList<User>> {
|
||||
return session.livePagedUsers(filter).asObservable()
|
||||
}
|
||||
|
||||
fun createRoom(roomParams: CreateRoomParams): Single<String> = singleBuilder {
|
||||
session.createRoom(roomParams, it)
|
||||
}
|
||||
|
||||
fun searchUsersDirectory(search: String,
|
||||
limit: Int,
|
||||
excludedUserIds: Set<String>): Single<List<User>> = singleBuilder {
|
||||
session.searchUsersDirectory(search, limit, excludedUserIds, it)
|
||||
}
|
||||
|
||||
fun joinRoom(roomId: String,
|
||||
reason: String? = null,
|
||||
viaServers: List<String> = emptyList()): Single<Unit> = singleBuilder {
|
||||
session.joinRoom(roomId, reason, viaServers, it)
|
||||
}
|
||||
|
||||
fun getRoomIdByAlias(roomAlias: String,
|
||||
searchOnServer: Boolean): Single<Optional<String>> = singleBuilder {
|
||||
session.getRoomIdByAlias(roomAlias, searchOnServer, it)
|
||||
}
|
||||
}
|
||||
|
||||
fun Session.rx(): RxSession {
|
||||
return RxSession(this)
|
||||
}
|
||||
}
|
||||
|
@ -6,20 +6,14 @@ apply plugin: 'realm-android'
|
||||
apply plugin: 'okreplay'
|
||||
|
||||
buildscript {
|
||||
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath "io.realm:realm-gradle-plugin:5.9.0"
|
||||
classpath "io.realm:realm-gradle-plugin:5.12.0"
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
|
||||
androidExtensions {
|
||||
experimental = true
|
||||
}
|
||||
@ -33,6 +27,8 @@ android {
|
||||
targetSdkVersion 28
|
||||
versionCode 1
|
||||
versionName "0.0.1"
|
||||
// Multidex is useful for tests
|
||||
multiDexEnabled true
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
buildConfigField "String", "GIT_SDK_REVISION", "\"${gitRevision()}\""
|
||||
@ -66,6 +62,15 @@ android {
|
||||
lintOptions {
|
||||
lintConfig file("lint.xml")
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
}
|
||||
|
||||
static def gitRevision() {
|
||||
@ -85,49 +90,47 @@ static def gitRevisionDate() {
|
||||
|
||||
dependencies {
|
||||
|
||||
def arrow_version = "0.8.0"
|
||||
def support_version = '1.1.0-alpha03'
|
||||
def arrow_version = "0.8.2"
|
||||
def moshi_version = '1.8.0'
|
||||
def lifecycle_version = '2.0.0'
|
||||
def coroutines_version = "1.0.1"
|
||||
def markwon_version = '3.0.0'
|
||||
def daggerVersion = '2.23.1'
|
||||
def lifecycle_version = '2.1.0'
|
||||
def coroutines_version = "1.3.2"
|
||||
def markwon_version = '3.1.0'
|
||||
def daggerVersion = '2.24'
|
||||
|
||||
implementation fileTree(dir: 'libs', include: ['*.aar'])
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
|
||||
|
||||
implementation "androidx.appcompat:appcompat:$support_version"
|
||||
implementation "androidx.recyclerview:recyclerview:$support_version"
|
||||
implementation "androidx.appcompat:appcompat:1.1.0"
|
||||
implementation "androidx.recyclerview:recyclerview:1.1.0-beta05"
|
||||
|
||||
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
|
||||
kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
|
||||
|
||||
// Network
|
||||
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
|
||||
implementation 'com.squareup.retrofit2:converter-moshi:2.4.0'
|
||||
implementation 'com.squareup.okhttp3:okhttp:3.11.0'
|
||||
implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0'
|
||||
implementation 'com.novoda:merlin:1.1.6'
|
||||
implementation 'com.squareup.retrofit2:retrofit:2.6.2'
|
||||
implementation 'com.squareup.retrofit2:converter-moshi:2.6.2'
|
||||
implementation 'com.squareup.okhttp3:okhttp:4.2.2'
|
||||
implementation 'com.squareup.okhttp3:logging-interceptor:4.2.2'
|
||||
implementation 'com.novoda:merlin:1.2.0'
|
||||
implementation "com.squareup.moshi:moshi-adapters:$moshi_version"
|
||||
kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version"
|
||||
|
||||
implementation "ru.noties.markwon:core:$markwon_version"
|
||||
|
||||
// Image
|
||||
implementation 'androidx.exifinterface:exifinterface:1.0.0'
|
||||
|
||||
// Database
|
||||
implementation 'com.github.Zhuinden:realm-monarchy:0.5.1'
|
||||
kapt 'dk.ilios:realmfieldnameshelper:1.1.1'
|
||||
|
||||
// Work
|
||||
implementation "androidx.work:work-runtime-ktx:2.1.0-beta01"
|
||||
implementation "androidx.work:work-runtime-ktx:2.3.0-alpha01"
|
||||
|
||||
// FP
|
||||
implementation "io.arrow-kt:arrow-core:$arrow_version"
|
||||
implementation "io.arrow-kt:arrow-instances-core:$arrow_version"
|
||||
implementation "io.arrow-kt:arrow-effects:$arrow_version"
|
||||
implementation "io.arrow-kt:arrow-effects-instances:$arrow_version"
|
||||
implementation "io.arrow-kt:arrow-integration-retrofit-adapter:$arrow_version"
|
||||
|
||||
// olm lib is now hosted by jitpack: https://jitpack.io/#org.matrix.gitlab.matrix-org/olm
|
||||
implementation 'org.matrix.gitlab.matrix-org:olm:3.1.2'
|
||||
@ -135,33 +138,36 @@ dependencies {
|
||||
// DI
|
||||
implementation "com.google.dagger:dagger:$daggerVersion"
|
||||
kapt "com.google.dagger:dagger-compiler:$daggerVersion"
|
||||
compileOnly 'com.squareup.inject:assisted-inject-annotations-dagger2:0.4.0'
|
||||
kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.4.0'
|
||||
compileOnly 'com.squareup.inject:assisted-inject-annotations-dagger2:0.5.0'
|
||||
kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.5.0'
|
||||
|
||||
// Logging
|
||||
implementation 'com.jakewharton.timber:timber:4.7.1'
|
||||
implementation 'com.facebook.stetho:stetho-okhttp3:1.5.0'
|
||||
implementation 'com.facebook.stetho:stetho-okhttp3:1.5.1'
|
||||
|
||||
debugImplementation 'com.airbnb.okreplay:okreplay:1.4.0'
|
||||
releaseImplementation 'com.airbnb.okreplay:noop:1.4.0'
|
||||
androidTestImplementation 'com.airbnb.okreplay:espresso:1.4.0'
|
||||
// Bus
|
||||
implementation 'org.greenrobot:eventbus:3.1.1'
|
||||
|
||||
debugImplementation 'com.airbnb.okreplay:okreplay:1.5.0'
|
||||
releaseImplementation 'com.airbnb.okreplay:noop:1.5.0'
|
||||
androidTestImplementation 'com.airbnb.okreplay:espresso:1.5.0'
|
||||
|
||||
testImplementation 'junit:junit:4.12'
|
||||
testImplementation 'org.robolectric:robolectric:4.0.2'
|
||||
testImplementation "org.koin:koin-test:$koin_version"
|
||||
testImplementation 'org.robolectric:robolectric:4.3'
|
||||
//testImplementation 'org.robolectric:shadows-support-v4:3.0'
|
||||
testImplementation "io.mockk:mockk:1.8.13.kotlin13"
|
||||
// Note: version sticks to 1.9.2 due to https://github.com/mockk/mockk/issues/281
|
||||
testImplementation 'io.mockk:mockk:1.9.2.kotlin12'
|
||||
testImplementation 'org.amshove.kluent:kluent-android:1.44'
|
||||
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
|
||||
|
||||
androidTestImplementation "org.koin:koin-test:$koin_version"
|
||||
androidTestImplementation 'androidx.test:core:1.1.0'
|
||||
androidTestImplementation 'androidx.test:runner:1.1.1'
|
||||
androidTestImplementation 'androidx.test:rules:1.1.1'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
|
||||
androidTestImplementation 'androidx.test:core:1.2.0'
|
||||
androidTestImplementation 'androidx.test:runner:1.2.0'
|
||||
androidTestImplementation 'androidx.test:rules:1.2.0'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
androidTestImplementation 'org.amshove.kluent:kluent-android:1.44'
|
||||
androidTestImplementation "io.mockk:mockk-android:1.8.13.kotlin13"
|
||||
// Note: version sticks to 1.9.2 due to https://github.com/mockk/mockk/issues/281
|
||||
androidTestImplementation 'io.mockk:mockk-android:1.9.2.kotlin12'
|
||||
androidTestImplementation "androidx.arch.core:core-testing:$lifecycle_version"
|
||||
androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
|
||||
|
||||
|
Binary file not shown.
@ -17,15 +17,15 @@
|
||||
package im.vector.matrix.android
|
||||
|
||||
import android.content.Context
|
||||
import androidx.test.InstrumentationRegistry
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import java.io.File
|
||||
|
||||
interface InstrumentedTest {
|
||||
fun context(): Context {
|
||||
return InstrumentationRegistry.getTargetContext()
|
||||
return ApplicationProvider.getApplicationContext()
|
||||
}
|
||||
|
||||
fun cacheDir(): File {
|
||||
return context().cacheDir
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,10 +16,10 @@
|
||||
|
||||
package im.vector.matrix.android;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.Observer;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
@ -29,4 +29,4 @@ class OkReplayRuleChainNoActivity(
|
||||
return RuleChain.outerRule(PermissionRule(configuration))
|
||||
.around(RecorderRule(configuration))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,4 +19,4 @@ package im.vector.matrix.android
|
||||
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
|
||||
internal val testCoroutineDispatchers = MatrixCoroutineDispatchers(Main, Main, Main, Main)
|
||||
internal val testCoroutineDispatchers = MatrixCoroutineDispatchers(Main, Main, Main, Main, Main)
|
||||
|
@ -17,29 +17,21 @@
|
||||
package im.vector.matrix.android.auth
|
||||
|
||||
import androidx.test.annotation.UiThreadTest
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.rule.GrantPermissionRule
|
||||
import androidx.test.runner.AndroidJUnit4
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.InstrumentedTest
|
||||
import im.vector.matrix.android.OkReplayRuleChainNoActivity
|
||||
import im.vector.matrix.android.api.auth.Authenticator
|
||||
import im.vector.matrix.android.internal.auth.AuthModule
|
||||
import im.vector.matrix.android.internal.di.MatrixModule
|
||||
import im.vector.matrix.android.internal.di.NetworkModule
|
||||
import im.vector.matrix.android.api.auth.AuthenticationService
|
||||
import okreplay.*
|
||||
import org.junit.ClassRule
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.koin.standalone.StandAloneContext.loadKoinModules
|
||||
import org.koin.standalone.inject
|
||||
import org.koin.test.KoinTest
|
||||
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
internal class AuthenticatorTest : InstrumentedTest, KoinTest {
|
||||
internal class AuthenticationServiceTest : InstrumentedTest {
|
||||
|
||||
lateinit var authenticator: Authenticator
|
||||
lateinit var authenticationService: AuthenticationService
|
||||
lateinit var okReplayInterceptor: OkReplayInterceptor
|
||||
|
||||
private val okReplayConfig = OkReplayConfig.Builder()
|
||||
@ -57,7 +49,6 @@ internal class AuthenticatorTest : InstrumentedTest, KoinTest {
|
||||
@UiThreadTest
|
||||
@OkReplay(tape = "auth", mode = TapeMode.READ_WRITE)
|
||||
fun auth() {
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
@ -66,6 +57,4 @@ internal class AuthenticatorTest : InstrumentedTest, KoinTest {
|
||||
val grantExternalStoragePermissionRule: GrantPermissionRule =
|
||||
GrantPermissionRule.grant(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -21,7 +21,7 @@ import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
||||
import im.vector.matrix.android.internal.crypto.store.db.RealmCryptoStore
|
||||
import im.vector.matrix.android.internal.crypto.store.db.RealmCryptoStoreModule
|
||||
import io.realm.RealmConfiguration
|
||||
import java.util.*
|
||||
import kotlin.random.Random
|
||||
|
||||
internal class CryptoStoreHelper {
|
||||
|
||||
@ -35,10 +35,10 @@ internal class CryptoStoreHelper {
|
||||
}
|
||||
|
||||
fun createCredential() = Credentials(
|
||||
userId = "userId_" + Random().nextInt(),
|
||||
userId = "userId_" + Random.nextInt(),
|
||||
homeServer = "http://matrix.org",
|
||||
accessToken = "access_token",
|
||||
refreshToken = null,
|
||||
deviceId = "deviceId_sample"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -114,4 +114,4 @@ class CryptoStoreTest {
|
||||
olmAccount1.releaseAccount()
|
||||
olmAccount2.releaseAccount()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ internal class JsonCanonicalizerTest : InstrumentedTest {
|
||||
|
||||
@Test
|
||||
fun realSampleTest() {
|
||||
assertEquals("""{"algorithms":["m.megolm.v1.aes-sha2","m.olm.v1.curve25519-aes-sha2"],"device_id":"VSCUNFSOUI","keys":{"curve25519:VSCUNFSOUI":"utyOjnhiQ73qNhi9HlN0OgWIowe5gthTS8r0r9TcJ3o","ed25519:VSCUNFSOUI":"qNhEt+Yggaajet0hX/FjTRLfySgs65ldYyomm7PIx6U"},"user_id":"@benoitx:matrix.org"}""",
|
||||
assertEquals("""{"algorithms":["m.megolm.v1.aes-sha2","m.olm.v1.curve25519-aes-sha2"],"device_id":"VSCUNFSOUI","keys":{"curve25519:VSCUNFSOUI":"utyOjnhiQ73qNhi9HlN0OgWIowe5gthTS8r0r9TcJ3o","ed25519:VSCUNFSOUI":"qNhEt+Yggaajet0hX\/FjTRLfySgs65ldYyomm7PIx6U"},"user_id":"@benoitx:matrix.org"}""",
|
||||
JsonCanonicalizer.canonicalize("""{"algorithms":["m.megolm.v1.aes-sha2","m.olm.v1.curve25519-aes-sha2"],"device_id":"VSCUNFSOUI","user_id":"@benoitx:matrix.org","keys":{"curve25519:VSCUNFSOUI":"utyOjnhiQ73qNhi9HlN0OgWIowe5gthTS8r0r9TcJ3o","ed25519:VSCUNFSOUI":"qNhEt+Yggaajet0hX/FjTRLfySgs65ldYyomm7PIx6U"}}"""))
|
||||
}
|
||||
|
||||
@ -62,8 +62,6 @@ internal class JsonCanonicalizerTest : InstrumentedTest {
|
||||
JsonCanonicalizer.canonicalize("{\"a\":\"\\\"\"}"))
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ==========================================================================================
|
||||
* Test from https://matrix.org/docs/spec/appendices.html#examples
|
||||
* ========================================================================================== */
|
||||
@ -74,7 +72,6 @@ internal class JsonCanonicalizerTest : InstrumentedTest {
|
||||
JsonCanonicalizer.canonicalize("""{}"""))
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun matrixOrg002Test() {
|
||||
assertEquals("""{"one":1,"two":"Two"}""",
|
||||
@ -84,7 +81,6 @@ internal class JsonCanonicalizerTest : InstrumentedTest {
|
||||
}"""))
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun matrixOrg003Test() {
|
||||
assertEquals("""{"a":"1","b":"2"}""",
|
||||
@ -94,14 +90,12 @@ internal class JsonCanonicalizerTest : InstrumentedTest {
|
||||
}"""))
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun matrixOrg004Test() {
|
||||
assertEquals("""{"a":"1","b":"2"}""",
|
||||
JsonCanonicalizer.canonicalize("""{"b":"2","a":"1"}"""))
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun matrixOrg005Test() {
|
||||
assertEquals("""{"auth":{"mxid":"@john.doe:example.com","profile":{"display_name":"John Doe","three_pids":[{"address":"john.doe@example.org","medium":"email"},{"address":"123456789","medium":"msisdn"}]},"success":true}}""",
|
||||
@ -126,7 +120,6 @@ internal class JsonCanonicalizerTest : InstrumentedTest {
|
||||
}"""))
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun matrixOrg006Test() {
|
||||
assertEquals("""{"a":"日本語"}""",
|
||||
@ -135,7 +128,6 @@ internal class JsonCanonicalizerTest : InstrumentedTest {
|
||||
}"""))
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun matrixOrg007Test() {
|
||||
assertEquals("""{"日":1,"本":2}""",
|
||||
@ -145,7 +137,6 @@ internal class JsonCanonicalizerTest : InstrumentedTest {
|
||||
}"""))
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun matrixOrg008Test() {
|
||||
assertEquals("""{"a":"日"}""",
|
||||
@ -159,4 +150,4 @@ internal class JsonCanonicalizerTest : InstrumentedTest {
|
||||
"a": null
|
||||
}"""))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,11 +19,7 @@ package im.vector.matrix.android.session.room.timeline
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.InstrumentedTest
|
||||
import im.vector.matrix.android.internal.database.helper.add
|
||||
import im.vector.matrix.android.internal.database.helper.addAll
|
||||
import im.vector.matrix.android.internal.database.helper.isUnlinked
|
||||
import im.vector.matrix.android.internal.database.helper.lastStateIndex
|
||||
import im.vector.matrix.android.internal.database.helper.merge
|
||||
import im.vector.matrix.android.internal.database.helper.*
|
||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||
import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection
|
||||
import im.vector.matrix.android.session.room.timeline.RoomDataHelper.createFakeListOfEvents
|
||||
@ -39,7 +35,6 @@ import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
internal class ChunkEntityTest : InstrumentedTest {
|
||||
|
||||
@ -52,14 +47,13 @@ internal class ChunkEntityTest : InstrumentedTest {
|
||||
monarchy = Monarchy.Builder().setRealmConfiguration(testConfig).build()
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun add_shouldAdd_whenNotAlreadyIncluded() {
|
||||
monarchy.runTransactionSync { realm ->
|
||||
val chunk: ChunkEntity = realm.createObject()
|
||||
val fakeEvent = createFakeMessageEvent()
|
||||
chunk.add("roomId", fakeEvent, PaginationDirection.FORWARDS)
|
||||
chunk.events.size shouldEqual 1
|
||||
chunk.timelineEvents.size shouldEqual 1
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,7 +64,7 @@ internal class ChunkEntityTest : InstrumentedTest {
|
||||
val fakeEvent = createFakeMessageEvent()
|
||||
chunk.add("roomId", fakeEvent, PaginationDirection.FORWARDS)
|
||||
chunk.add("roomId", fakeEvent, PaginationDirection.FORWARDS)
|
||||
chunk.events.size shouldEqual 1
|
||||
chunk.timelineEvents.size shouldEqual 1
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,7 +120,7 @@ internal class ChunkEntityTest : InstrumentedTest {
|
||||
chunk1.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
|
||||
chunk2.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
|
||||
chunk1.merge("roomId", chunk2, PaginationDirection.BACKWARDS)
|
||||
chunk1.events.size shouldEqual 60
|
||||
chunk1.timelineEvents.size shouldEqual 60
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,7 +136,7 @@ internal class ChunkEntityTest : InstrumentedTest {
|
||||
chunk1.addAll("roomId", eventsForChunk1, PaginationDirection.FORWARDS)
|
||||
chunk2.addAll("roomId", eventsForChunk2, PaginationDirection.BACKWARDS)
|
||||
chunk1.merge("roomId", chunk2, PaginationDirection.BACKWARDS)
|
||||
chunk1.events.size shouldEqual 40
|
||||
chunk1.timelineEvents.size shouldEqual 40
|
||||
chunk1.isLastForward.shouldBeTrue()
|
||||
}
|
||||
}
|
||||
@ -198,5 +192,4 @@ internal class ChunkEntityTest : InstrumentedTest {
|
||||
chunk1.nextToken shouldEqual nextToken
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,6 @@
|
||||
|
||||
package im.vector.matrix.android.session.room.timeline
|
||||
|
||||
import arrow.core.Try
|
||||
import im.vector.matrix.android.internal.session.room.timeline.GetContextOfEventTask
|
||||
import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection
|
||||
import im.vector.matrix.android.internal.session.room.timeline.TokenChunkEventPersistor
|
||||
@ -24,7 +23,7 @@ import kotlin.random.Random
|
||||
|
||||
internal class FakeGetContextOfEventTask constructor(private val tokenChunkEventPersistor: TokenChunkEventPersistor) : GetContextOfEventTask {
|
||||
|
||||
override suspend fun execute(params: GetContextOfEventTask.Params): Try<TokenChunkEventPersistor.Result> {
|
||||
override suspend fun execute(params: GetContextOfEventTask.Params): TokenChunkEventPersistor.Result {
|
||||
val fakeEvents = RoomDataHelper.createFakeListOfEvents(30)
|
||||
val tokenChunkEvent = FakeTokenChunkEvent(
|
||||
Random.nextLong(System.currentTimeMillis()).toString(),
|
||||
@ -33,6 +32,4 @@ internal class FakeGetContextOfEventTask constructor(private val tokenChunkEvent
|
||||
)
|
||||
return tokenChunkEventPersistor.insertInDb(tokenChunkEvent, params.roomId, PaginationDirection.BACKWARDS)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,6 @@
|
||||
|
||||
package im.vector.matrix.android.session.room.timeline
|
||||
|
||||
import arrow.core.Try
|
||||
import im.vector.matrix.android.internal.session.room.timeline.PaginationTask
|
||||
import im.vector.matrix.android.internal.session.room.timeline.TokenChunkEventPersistor
|
||||
import javax.inject.Inject
|
||||
@ -24,11 +23,9 @@ import kotlin.random.Random
|
||||
|
||||
internal class FakePaginationTask @Inject constructor(private val tokenChunkEventPersistor: TokenChunkEventPersistor) : PaginationTask {
|
||||
|
||||
override suspend fun execute(params: PaginationTask.Params): Try<TokenChunkEventPersistor.Result> {
|
||||
override suspend fun execute(params: PaginationTask.Params): TokenChunkEventPersistor.Result {
|
||||
val fakeEvents = RoomDataHelper.createFakeListOfEvents(30)
|
||||
val tokenChunkEvent = FakeTokenChunkEvent(params.from, Random.nextLong(System.currentTimeMillis()).toString(), fakeEvents)
|
||||
return tokenChunkEventPersistor.insertInDb(tokenChunkEvent, params.roomId, params.direction)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -23,4 +23,4 @@ internal data class FakeTokenChunkEvent(override val start: String?,
|
||||
override val end: String?,
|
||||
override val events: List<Event> = emptyList(),
|
||||
override val stateEvents: List<Event> = emptyList()
|
||||
) : TokenChunkEvent
|
||||
) : TokenChunkEvent
|
||||
|
@ -88,6 +88,4 @@ object RoomDataHelper {
|
||||
roomEntity.addOrUpdate(chunkEntity)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -18,25 +18,6 @@ package im.vector.matrix.android.session.room.timeline
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.InstrumentedTest
|
||||
import im.vector.matrix.android.api.session.crypto.CryptoService
|
||||
import im.vector.matrix.android.api.session.room.timeline.Timeline
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||
import im.vector.matrix.android.internal.crypto.CryptoManager
|
||||
import im.vector.matrix.android.internal.database.model.SessionRealmModule
|
||||
import im.vector.matrix.android.internal.session.room.EventRelationExtractor
|
||||
import im.vector.matrix.android.internal.session.room.membership.SenderRoomMemberExtractor
|
||||
import im.vector.matrix.android.internal.session.room.timeline.DefaultTimeline
|
||||
import im.vector.matrix.android.internal.session.room.timeline.TimelineEventFactory
|
||||
import im.vector.matrix.android.internal.session.room.timeline.TokenChunkEventPersistor
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
import im.vector.matrix.android.testCoroutineDispatchers
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmConfiguration
|
||||
import org.amshove.kluent.shouldEqual
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import timber.log.Timber
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
||||
internal class TimelineTest : InstrumentedTest {
|
||||
|
||||
@ -100,6 +81,4 @@ internal class TimelineTest : InstrumentedTest {
|
||||
// timelineEvents.size shouldEqual initialLoad + paginationCount
|
||||
// timeline.dispose()
|
||||
// }
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import okio.Buffer
|
||||
import timber.log.Timber
|
||||
import java.io.IOException
|
||||
import java.nio.charset.Charset
|
||||
import javax.inject.Inject
|
||||
@ -51,27 +52,33 @@ internal class CurlLoggingInterceptor @Inject constructor(private val logger: Ht
|
||||
var compressed = false
|
||||
|
||||
var curlCmd = "curl"
|
||||
if (curlOptions != null) {
|
||||
curlCmd += " " + curlOptions!!
|
||||
curlOptions?.let {
|
||||
curlCmd += " $it"
|
||||
}
|
||||
curlCmd += " -X " + request.method()
|
||||
curlCmd += " -X " + request.method
|
||||
|
||||
val requestBody = request.body()
|
||||
val requestBody = request.body
|
||||
if (requestBody != null) {
|
||||
val buffer = Buffer()
|
||||
requestBody.writeTo(buffer)
|
||||
var charset: Charset? = UTF8
|
||||
val contentType = requestBody.contentType()
|
||||
if (contentType != null) {
|
||||
charset = contentType.charset(UTF8)
|
||||
if (requestBody.contentLength() > 100_000) {
|
||||
Timber.w("Unable to log curl command data, size is too big (${requestBody.contentLength()})")
|
||||
// Ensure the curl command will failed
|
||||
curlCmd += "DATA IS TOO BIG"
|
||||
} else {
|
||||
val buffer = Buffer()
|
||||
requestBody.writeTo(buffer)
|
||||
var charset: Charset? = UTF8
|
||||
val contentType = requestBody.contentType()
|
||||
if (contentType != null) {
|
||||
charset = contentType.charset(UTF8)
|
||||
}
|
||||
// try to keep to a single line and use a subshell to preserve any line breaks
|
||||
curlCmd += " --data $'" + buffer.readString(charset!!).replace("\n", "\\n") + "'"
|
||||
}
|
||||
// try to keep to a single line and use a subshell to preserve any line breaks
|
||||
curlCmd += " --data $'" + buffer.readString(charset!!).replace("\n", "\\n") + "'"
|
||||
}
|
||||
|
||||
val headers = request.headers()
|
||||
val headers = request.headers
|
||||
var i = 0
|
||||
val count = headers.size()
|
||||
val count = headers.size
|
||||
while (i < count) {
|
||||
val name = headers.name(i)
|
||||
val value = headers.value(i)
|
||||
@ -82,7 +89,7 @@ internal class CurlLoggingInterceptor @Inject constructor(private val logger: Ht
|
||||
i++
|
||||
}
|
||||
|
||||
curlCmd += ((if (compressed) " --compressed " else " ") + "'" + request.url().toString()
|
||||
curlCmd += ((if (compressed) " --compressed " else " ") + "'" + request.url.toString()
|
||||
// Replace localhost for emulator by localhost for shell
|
||||
.replace("://10.0.2.2:8080/".toRegex(), "://127.0.0.1:8080/")
|
||||
+ "'")
|
||||
@ -90,7 +97,7 @@ internal class CurlLoggingInterceptor @Inject constructor(private val logger: Ht
|
||||
// Add Json formatting
|
||||
curlCmd += " | python -m json.tool"
|
||||
|
||||
logger.log("--- cURL (" + request.url() + ")")
|
||||
logger.log("--- cURL (" + request.url + ")")
|
||||
logger.log(curlCmd)
|
||||
|
||||
return chain.proceed(request)
|
||||
|
@ -51,7 +51,6 @@ class FormattedJsonHttpLogger : HttpLoggingInterceptor.Logger {
|
||||
// Finally this is not a JSON string...
|
||||
Timber.e(e)
|
||||
}
|
||||
|
||||
} else if (message.startsWith("[")) {
|
||||
// JSON Array detected
|
||||
try {
|
||||
@ -61,7 +60,6 @@ class FormattedJsonHttpLogger : HttpLoggingInterceptor.Logger {
|
||||
// Finally not JSON...
|
||||
Timber.e(e)
|
||||
}
|
||||
|
||||
}
|
||||
// Else not a json string to log
|
||||
}
|
||||
@ -73,4 +71,4 @@ class FormattedJsonHttpLogger : HttpLoggingInterceptor.Logger {
|
||||
Timber.v(s)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ import androidx.work.Configuration
|
||||
import androidx.work.WorkManager
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.BuildConfig
|
||||
import im.vector.matrix.android.api.auth.Authenticator
|
||||
import im.vector.matrix.android.api.auth.AuthenticationService
|
||||
import im.vector.matrix.android.internal.SessionManager
|
||||
import im.vector.matrix.android.internal.di.DaggerMatrixComponent
|
||||
import im.vector.matrix.android.internal.network.UserAgentHolder
|
||||
@ -38,7 +38,6 @@ data class MatrixConfiguration(
|
||||
interface Provider {
|
||||
fun providesMatrixConfiguration(): MatrixConfiguration
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -47,7 +46,7 @@ data class MatrixConfiguration(
|
||||
*/
|
||||
class Matrix private constructor(context: Context, matrixConfiguration: MatrixConfiguration) {
|
||||
|
||||
@Inject internal lateinit var authenticator: Authenticator
|
||||
@Inject internal lateinit var authenticationService: AuthenticationService
|
||||
@Inject internal lateinit var userAgentHolder: UserAgentHolder
|
||||
@Inject internal lateinit var backgroundDetectionObserver: BackgroundDetectionObserver
|
||||
@Inject internal lateinit var olmManager: OlmManager
|
||||
@ -65,8 +64,8 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo
|
||||
|
||||
fun getUserAgent() = userAgentHolder.userAgent
|
||||
|
||||
fun authenticator(): Authenticator {
|
||||
return authenticator
|
||||
fun authenticationService(): AuthenticationService {
|
||||
return authenticationService
|
||||
}
|
||||
|
||||
companion object {
|
||||
@ -87,7 +86,8 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo
|
||||
val matrixConfiguration = (appContext as MatrixConfiguration.Provider).providesMatrixConfiguration()
|
||||
instance = Matrix(appContext, matrixConfiguration)
|
||||
} else {
|
||||
throw IllegalStateException("Matrix is not initialized properly. You should call Matrix.initialize or let your application implements MatrixConfiguration.Provider.")
|
||||
throw IllegalStateException("Matrix is not initialized properly." +
|
||||
" You should call Matrix.initialize or let your application implements MatrixConfiguration.Provider.")
|
||||
}
|
||||
}
|
||||
return instance
|
||||
@ -97,5 +97,4 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo
|
||||
return BuildConfig.VERSION_NAME + " (" + BuildConfig.GIT_SDK_REVISION + ")"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ interface MatrixCallback<in T> {
|
||||
* @param data the data successfully returned from the async function
|
||||
*/
|
||||
fun onSuccess(data: T) {
|
||||
//no-op
|
||||
// no-op
|
||||
}
|
||||
|
||||
/**
|
||||
@ -35,7 +35,6 @@ interface MatrixCallback<in T> {
|
||||
* @param failure the failure data returned from the async function
|
||||
*/
|
||||
fun onFailure(failure: Throwable) {
|
||||
//no-op
|
||||
// no-op
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -16,8 +16,6 @@
|
||||
|
||||
package im.vector.matrix.android.api
|
||||
|
||||
import java.util.regex.Pattern
|
||||
|
||||
/**
|
||||
* This class contains pattern to match the different Matrix ids
|
||||
*/
|
||||
@ -29,31 +27,31 @@ object MatrixPatterns {
|
||||
// regex pattern to find matrix user ids in a string.
|
||||
// See https://matrix.org/speculator/spec/HEAD/appendices.html#historical-user-ids
|
||||
private const val MATRIX_USER_IDENTIFIER_REGEX = "@[A-Z0-9\\x21-\\x39\\x3B-\\x7F]+$DOMAIN_REGEX"
|
||||
private val PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER = Pattern.compile(MATRIX_USER_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE)
|
||||
val PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER = MATRIX_USER_IDENTIFIER_REGEX.toRegex(RegexOption.IGNORE_CASE)
|
||||
|
||||
// regex pattern to find room ids in a string.
|
||||
private const val MATRIX_ROOM_IDENTIFIER_REGEX = "![A-Z0-9]+$DOMAIN_REGEX"
|
||||
private val PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER = Pattern.compile(MATRIX_ROOM_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE)
|
||||
private val PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER = MATRIX_ROOM_IDENTIFIER_REGEX.toRegex(RegexOption.IGNORE_CASE)
|
||||
|
||||
// regex pattern to find room aliases in a string.
|
||||
private const val MATRIX_ROOM_ALIAS_REGEX = "#[A-Z0-9._%#@=+-]+$DOMAIN_REGEX"
|
||||
private val PATTERN_CONTAIN_MATRIX_ALIAS = Pattern.compile(MATRIX_ROOM_ALIAS_REGEX, Pattern.CASE_INSENSITIVE)
|
||||
private val PATTERN_CONTAIN_MATRIX_ALIAS = MATRIX_ROOM_ALIAS_REGEX.toRegex(RegexOption.IGNORE_CASE)
|
||||
|
||||
// regex pattern to find message ids in a string.
|
||||
private const val MATRIX_EVENT_IDENTIFIER_REGEX = "\\$[A-Z0-9]+$DOMAIN_REGEX"
|
||||
private val PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER = Pattern.compile(MATRIX_EVENT_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE)
|
||||
private val PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER = MATRIX_EVENT_IDENTIFIER_REGEX.toRegex(RegexOption.IGNORE_CASE)
|
||||
|
||||
// regex pattern to find message ids in a string.
|
||||
private const val MATRIX_EVENT_IDENTIFIER_V3_REGEX = "\\$[A-Z0-9/+]+"
|
||||
private val PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V3 = Pattern.compile(MATRIX_EVENT_IDENTIFIER_V3_REGEX, Pattern.CASE_INSENSITIVE)
|
||||
private val PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V3 = MATRIX_EVENT_IDENTIFIER_V3_REGEX.toRegex(RegexOption.IGNORE_CASE)
|
||||
|
||||
// Ref: https://matrix.org/docs/spec/rooms/v4#event-ids
|
||||
private const val MATRIX_EVENT_IDENTIFIER_V4_REGEX = "\\$[A-Z0-9\\-_]+"
|
||||
private val PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V4 = Pattern.compile(MATRIX_EVENT_IDENTIFIER_V4_REGEX, Pattern.CASE_INSENSITIVE)
|
||||
private val PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V4 = MATRIX_EVENT_IDENTIFIER_V4_REGEX.toRegex(RegexOption.IGNORE_CASE)
|
||||
|
||||
// regex pattern to find group ids in a string.
|
||||
private const val MATRIX_GROUP_IDENTIFIER_REGEX = "\\+[A-Z0-9=_\\-./]+$DOMAIN_REGEX"
|
||||
private val PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER = Pattern.compile(MATRIX_GROUP_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE)
|
||||
private val PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER = MATRIX_GROUP_IDENTIFIER_REGEX.toRegex(RegexOption.IGNORE_CASE)
|
||||
|
||||
// regex pattern to find permalink with message id.
|
||||
// Android does not support in URL so extract it.
|
||||
@ -62,16 +60,16 @@ object MatrixPatterns {
|
||||
const val SEP_REGEX = "/"
|
||||
|
||||
private const val LINK_TO_ROOM_ID_REGEXP = PERMALINK_BASE_REGEX + MATRIX_ROOM_IDENTIFIER_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX
|
||||
private val PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ID = Pattern.compile(LINK_TO_ROOM_ID_REGEXP, Pattern.CASE_INSENSITIVE)
|
||||
private val PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ID = LINK_TO_ROOM_ID_REGEXP.toRegex(RegexOption.IGNORE_CASE)
|
||||
|
||||
private const val LINK_TO_ROOM_ALIAS_REGEXP = PERMALINK_BASE_REGEX + MATRIX_ROOM_ALIAS_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX
|
||||
private val PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ALIAS = Pattern.compile(LINK_TO_ROOM_ALIAS_REGEXP, Pattern.CASE_INSENSITIVE)
|
||||
private val PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ALIAS = LINK_TO_ROOM_ALIAS_REGEXP.toRegex(RegexOption.IGNORE_CASE)
|
||||
|
||||
private const val LINK_TO_APP_ROOM_ID_REGEXP = APP_BASE_REGEX + MATRIX_ROOM_IDENTIFIER_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX
|
||||
private val PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ID = Pattern.compile(LINK_TO_APP_ROOM_ID_REGEXP, Pattern.CASE_INSENSITIVE)
|
||||
private val PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ID = LINK_TO_APP_ROOM_ID_REGEXP.toRegex(RegexOption.IGNORE_CASE)
|
||||
|
||||
private const val LINK_TO_APP_ROOM_ALIAS_REGEXP = APP_BASE_REGEX + MATRIX_ROOM_ALIAS_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX
|
||||
private val PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ALIAS = Pattern.compile(LINK_TO_APP_ROOM_ALIAS_REGEXP, Pattern.CASE_INSENSITIVE)
|
||||
private val PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ALIAS = LINK_TO_APP_ROOM_ALIAS_REGEXP.toRegex(RegexOption.IGNORE_CASE)
|
||||
|
||||
// list of patterns to find some matrix item.
|
||||
val MATRIX_PATTERNS = listOf(
|
||||
@ -93,7 +91,7 @@ object MatrixPatterns {
|
||||
* @return true if the string is a valid user id
|
||||
*/
|
||||
fun isUserId(str: String?): Boolean {
|
||||
return str != null && PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER.matcher(str).matches()
|
||||
return str != null && str matches PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER
|
||||
}
|
||||
|
||||
/**
|
||||
@ -103,7 +101,7 @@ object MatrixPatterns {
|
||||
* @return true if the string is a valid room Id
|
||||
*/
|
||||
fun isRoomId(str: String?): Boolean {
|
||||
return str != null && PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER.matcher(str).matches()
|
||||
return str != null && str matches PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER
|
||||
}
|
||||
|
||||
/**
|
||||
@ -113,7 +111,7 @@ object MatrixPatterns {
|
||||
* @return true if the string is a valid room alias.
|
||||
*/
|
||||
fun isRoomAlias(str: String?): Boolean {
|
||||
return str != null && PATTERN_CONTAIN_MATRIX_ALIAS.matcher(str).matches()
|
||||
return str != null && str matches PATTERN_CONTAIN_MATRIX_ALIAS
|
||||
}
|
||||
|
||||
/**
|
||||
@ -124,9 +122,9 @@ object MatrixPatterns {
|
||||
*/
|
||||
fun isEventId(str: String?): Boolean {
|
||||
return str != null
|
||||
&& (PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER.matcher(str).matches()
|
||||
|| PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V3.matcher(str).matches()
|
||||
|| PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V4.matcher(str).matches())
|
||||
&& (str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER
|
||||
|| str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V3
|
||||
|| str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V4)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -136,6 +134,24 @@ object MatrixPatterns {
|
||||
* @return true if the string is a valid group id.
|
||||
*/
|
||||
fun isGroupId(str: String?): Boolean {
|
||||
return str != null && PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER.matcher(str).matches()
|
||||
return str != null && str matches PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract server name from a matrix id
|
||||
*
|
||||
* @param matrixId
|
||||
* @return null if not found or if matrixId is null
|
||||
*/
|
||||
fun extractServerNameFromId(matrixId: String?): String? {
|
||||
if (matrixId == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
val index = matrixId.indexOf(":")
|
||||
|
||||
return if (index == -1) {
|
||||
null
|
||||
} else matrixId.substring(index + 1)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.api.auth
|
||||
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig
|
||||
import im.vector.matrix.android.api.auth.data.LoginFlowResult
|
||||
import im.vector.matrix.android.api.auth.data.SessionParams
|
||||
import im.vector.matrix.android.api.auth.login.LoginWizard
|
||||
import im.vector.matrix.android.api.auth.registration.RegistrationWizard
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
|
||||
/**
|
||||
* This interface defines methods to authenticate or to create an account to a matrix server.
|
||||
*/
|
||||
interface AuthenticationService {
|
||||
|
||||
/**
|
||||
* Request the supported login flows for this homeserver.
|
||||
* This is the first method to call to be able to get a wizard to login or the create an account
|
||||
*/
|
||||
fun getLoginFlow(homeServerConnectionConfig: HomeServerConnectionConfig, callback: MatrixCallback<LoginFlowResult>): Cancelable
|
||||
|
||||
/**
|
||||
* Return a LoginWizard, to login to the homeserver. The login flow has to be retrieved first.
|
||||
*/
|
||||
fun getLoginWizard(): LoginWizard
|
||||
|
||||
/**
|
||||
* Return a RegistrationWizard, to create an matrix account on the homeserver. The login flow has to be retrieved first.
|
||||
*/
|
||||
fun getRegistrationWizard(): RegistrationWizard
|
||||
|
||||
/**
|
||||
* True when login and password has been sent with success to the homeserver
|
||||
*/
|
||||
val isRegistrationStarted: Boolean
|
||||
|
||||
/**
|
||||
* Cancel pending login or pending registration
|
||||
*/
|
||||
fun cancelPendingLoginOrRegistration()
|
||||
|
||||
/**
|
||||
* Reset all pending settings, including current HomeServerConnectionConfig
|
||||
*/
|
||||
fun reset()
|
||||
|
||||
/**
|
||||
* Check if there is an authenticated [Session].
|
||||
* @return true if there is at least one active session.
|
||||
*/
|
||||
fun hasAuthenticatedSessions(): Boolean
|
||||
|
||||
/**
|
||||
* Get the last authenticated [Session], if there is an active session.
|
||||
* @return the last active session if any, or null
|
||||
*/
|
||||
fun getLastAuthenticatedSession(): Session?
|
||||
|
||||
/**
|
||||
* Get an authenticated session. You should at least call authenticate one time before.
|
||||
* If you logout, this session will no longer be valid.
|
||||
*
|
||||
* @param sessionParams the sessionParams to open with.
|
||||
* @return the associated session if any, or null
|
||||
*/
|
||||
fun getSession(sessionParams: SessionParams): Session?
|
||||
|
||||
/**
|
||||
* Create a session after a SSO successful login
|
||||
*/
|
||||
fun createSessionFromSso(homeServerConnectionConfig: HomeServerConnectionConfig,
|
||||
credentials: Credentials,
|
||||
callback: MatrixCallback<Session>): Cancelable
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.api.auth
|
||||
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig
|
||||
import im.vector.matrix.android.api.auth.data.SessionParams
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
|
||||
/**
|
||||
* This interface defines methods to authenticate to a matrix server.
|
||||
*/
|
||||
interface Authenticator {
|
||||
|
||||
/**
|
||||
* @param homeServerConnectionConfig this param is used to configure the Homeserver
|
||||
* @param login the login field
|
||||
* @param password the password field
|
||||
* @param callback the matrix callback on which you'll receive the result of authentication.
|
||||
* @return return a [Cancelable]
|
||||
*/
|
||||
fun authenticate(homeServerConnectionConfig: HomeServerConnectionConfig, login: String, password: String, callback: MatrixCallback<Session>): Cancelable
|
||||
|
||||
//TODO remove this method. Shouldn't be managed like that.
|
||||
/**
|
||||
* Check if there is an active [Session].
|
||||
* @return true if there is at least one active session.
|
||||
*/
|
||||
fun hasAuthenticatedSessions(): Boolean
|
||||
|
||||
//TODO remove this method. Shouldn't be managed like that.
|
||||
/**
|
||||
* Get the last active [Session], if there is an active session.
|
||||
* @return the lastActive session if any, or null
|
||||
*/
|
||||
fun getLastAuthenticatedSession(): Session?
|
||||
|
||||
/**
|
||||
* Get an authenticated session. You should at least call authenticate one time before.
|
||||
* If you logout, this session will no longer be valid.
|
||||
*
|
||||
* @param sessionParams the sessionParams to open with.
|
||||
* @return the associated session if any, or null
|
||||
*/
|
||||
fun getSession(sessionParams: SessionParams): Session?
|
||||
|
||||
|
||||
|
||||
}
|
@ -30,4 +30,7 @@ data class Credentials(
|
||||
@Json(name = "home_server") val homeServer: String,
|
||||
@Json(name = "access_token") val accessToken: String,
|
||||
@Json(name = "refresh_token") val refreshToken: String?,
|
||||
@Json(name = "device_id") val deviceId: String?)
|
||||
@Json(name = "device_id") val deviceId: String?,
|
||||
// Optional data that may contain info to override home server and/or identity server
|
||||
@Json(name = "well_known") val wellKnown: WellKnown? = null
|
||||
)
|
||||
|
@ -25,13 +25,13 @@ import okhttp3.TlsVersion
|
||||
|
||||
/**
|
||||
* This data class holds how to connect to a specific Homeserver.
|
||||
* It's used with [im.vector.matrix.android.api.auth.Authenticator] class.
|
||||
* It's used with [im.vector.matrix.android.api.auth.AuthenticationService] class.
|
||||
* You should use the [Builder] to create one.
|
||||
*/
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class HomeServerConnectionConfig(
|
||||
val homeServerUri: Uri,
|
||||
val identityServerUri: Uri,
|
||||
val identityServerUri: Uri? = null,
|
||||
val antiVirusServerUri: Uri? = null,
|
||||
val allowedFingerprints: MutableList<Fingerprint> = ArrayList(),
|
||||
val shouldPin: Boolean = false,
|
||||
@ -48,7 +48,7 @@ data class HomeServerConnectionConfig(
|
||||
class Builder {
|
||||
|
||||
private lateinit var homeServerUri: Uri
|
||||
private lateinit var identityServerUri: Uri
|
||||
private var identityServerUri: Uri? = null
|
||||
private var antiVirusServerUri: Uri? = null
|
||||
private val allowedFingerprints: MutableList<Fingerprint> = ArrayList()
|
||||
private var shouldPin: Boolean = false
|
||||
@ -253,13 +253,5 @@ data class HomeServerConnectionConfig(
|
||||
forceUsageTlsVersions
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.api.auth.data
|
||||
|
||||
import im.vector.matrix.android.internal.auth.data.LoginFlowResponse
|
||||
|
||||
// Either a LoginFlowResponse, or an error if the homeserver is outdated
|
||||
sealed class LoginFlowResult {
|
||||
data class Success(
|
||||
val loginFlowResponse: LoginFlowResponse,
|
||||
val isLoginAndRegistrationSupported: Boolean,
|
||||
val homeServerUrl: String
|
||||
) : LoginFlowResult()
|
||||
|
||||
object OutdatedHomeserver : LoginFlowResult()
|
||||
}
|
@ -22,5 +22,6 @@ package im.vector.matrix.android.api.auth.data
|
||||
*/
|
||||
data class SessionParams(
|
||||
val credentials: Credentials,
|
||||
val homeServerConnectionConfig: HomeServerConnectionConfig
|
||||
val homeServerConnectionConfig: HomeServerConnectionConfig,
|
||||
val isTokenValid: Boolean
|
||||
)
|
||||
|
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2018 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.api.auth.data
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
/**
|
||||
* Model for https://matrix.org/docs/spec/client_server/latest#get-matrix-client-versions
|
||||
*
|
||||
* Ex:
|
||||
* <pre>
|
||||
* {
|
||||
* "unstable_features": {
|
||||
* "m.lazy_load_members": true
|
||||
* },
|
||||
* "versions": [
|
||||
* "r0.0.1",
|
||||
* "r0.1.0",
|
||||
* "r0.2.0",
|
||||
* "r0.3.0"
|
||||
* ]
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class Versions(
|
||||
@Json(name = "versions")
|
||||
val supportedVersions: List<String>? = null,
|
||||
|
||||
@Json(name = "unstable_features")
|
||||
val unstableFeatures: Map<String, Boolean>? = null
|
||||
)
|
||||
|
||||
// MatrixClientServerAPIVersion
|
||||
private const val r0_0_1 = "r0.0.1"
|
||||
private const val r0_1_0 = "r0.1.0"
|
||||
private const val r0_2_0 = "r0.2.0"
|
||||
private const val r0_3_0 = "r0.3.0"
|
||||
private const val r0_4_0 = "r0.4.0"
|
||||
private const val r0_5_0 = "r0.5.0"
|
||||
private const val r0_6_0 = "r0.6.0"
|
||||
|
||||
// MatrixVersionsFeature
|
||||
private const val FEATURE_LAZY_LOAD_MEMBERS = "m.lazy_load_members"
|
||||
private const val FEATURE_REQUIRE_IDENTITY_SERVER = "m.require_identity_server"
|
||||
private const val FEATURE_ID_ACCESS_TOKEN = "m.id_access_token"
|
||||
private const val FEATURE_SEPARATE_ADD_AND_BIND = "m.separate_add_and_bind"
|
||||
|
||||
/**
|
||||
* Return true if the SDK supports this homeserver version
|
||||
*/
|
||||
fun Versions.isSupportedBySdk(): Boolean {
|
||||
return supportLazyLoadMembers()
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the SDK supports this homeserver version for login and registration
|
||||
*/
|
||||
fun Versions.isLoginAndRegistrationSupportedBySdk(): Boolean {
|
||||
return !doesServerRequireIdentityServerParam()
|
||||
&& doesServerAcceptIdentityAccessToken()
|
||||
&& doesServerSeparatesAddAndBind()
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the server support the lazy loading of room members
|
||||
*
|
||||
* @return true if the server support the lazy loading of room members
|
||||
*/
|
||||
private fun Versions.supportLazyLoadMembers(): Boolean {
|
||||
return supportedVersions?.contains(r0_5_0) == true
|
||||
|| unstableFeatures?.get(FEATURE_LAZY_LOAD_MEMBERS) == true
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate if the `id_server` parameter is required when registering with an 3pid,
|
||||
* adding a 3pid or resetting password.
|
||||
*/
|
||||
private fun Versions.doesServerRequireIdentityServerParam(): Boolean {
|
||||
if (supportedVersions?.contains(r0_6_0) == true) return false
|
||||
return unstableFeatures?.get(FEATURE_REQUIRE_IDENTITY_SERVER) ?: true
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate if the `id_access_token` parameter can be safely passed to the homeserver.
|
||||
* Some homeservers may trigger errors if they are not prepared for the new parameter.
|
||||
*/
|
||||
private fun Versions.doesServerAcceptIdentityAccessToken(): Boolean {
|
||||
return supportedVersions?.contains(r0_6_0) == true
|
||||
|| unstableFeatures?.get(FEATURE_ID_ACCESS_TOKEN) ?: false
|
||||
}
|
||||
|
||||
private fun Versions.doesServerSeparatesAddAndBind(): Boolean {
|
||||
return supportedVersions?.contains(r0_6_0) == true
|
||||
|| unstableFeatures?.get(FEATURE_SEPARATE_ADD_AND_BIND) ?: false
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.api.auth.data
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
/**
|
||||
* https://matrix.org/docs/spec/client_server/r0.4.0.html#server-discovery
|
||||
* <pre>
|
||||
* {
|
||||
* "m.homeserver": {
|
||||
* "base_url": "https://matrix.org"
|
||||
* },
|
||||
* "m.identity_server": {
|
||||
* "base_url": "https://vector.im"
|
||||
* }
|
||||
* "m.integrations": {
|
||||
* "managers": [
|
||||
* {
|
||||
* "api_url": "https://integrations.example.org",
|
||||
* "ui_url": "https://integrations.example.org/ui"
|
||||
* },
|
||||
* {
|
||||
* "api_url": "https://bots.example.org"
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class WellKnown(
|
||||
@Json(name = "m.homeserver")
|
||||
var homeServer: WellKnownBaseConfig? = null,
|
||||
|
||||
@Json(name = "m.identity_server")
|
||||
var identityServer: WellKnownBaseConfig? = null,
|
||||
|
||||
@Json(name = "m.integrations")
|
||||
var integrations: Map<String, @JvmSuppressWildcards Any>? = null
|
||||
) {
|
||||
/**
|
||||
* Returns the list of integration managers proposed
|
||||
*/
|
||||
fun getIntegrationManagers(): List<WellKnownManagerConfig> {
|
||||
val managers = ArrayList<WellKnownManagerConfig>()
|
||||
integrations?.get("managers")?.let {
|
||||
(it as? ArrayList<*>)?.let { configs ->
|
||||
configs.forEach { config ->
|
||||
(config as? Map<*, *>)?.let { map ->
|
||||
val apiUrl = map["api_url"] as? String
|
||||
val uiUrl = map["ui_url"] as? String ?: apiUrl
|
||||
if (apiUrl != null
|
||||
&& apiUrl.startsWith("https://")
|
||||
&& uiUrl!!.startsWith("https://")) {
|
||||
managers.add(WellKnownManagerConfig(
|
||||
apiUrl = apiUrl,
|
||||
uiUrl = uiUrl
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return managers
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.api.auth.data
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
/**
|
||||
* https://matrix.org/docs/spec/client_server/r0.4.0.html#server-discovery
|
||||
* <pre>
|
||||
* {
|
||||
* "base_url": "https://vector.im"
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class WellKnownBaseConfig(
|
||||
@Json(name = "base_url")
|
||||
val baseURL: String? = null
|
||||
)
|
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package im.vector.matrix.android.api.auth.data
|
||||
|
||||
data class WellKnownManagerConfig(
|
||||
val apiUrl : String,
|
||||
val uiUrl: String
|
||||
)
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.api.auth.login
|
||||
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
|
||||
interface LoginWizard {
|
||||
|
||||
/**
|
||||
* @param login the login field
|
||||
* @param password the password field
|
||||
* @param deviceName the initial device name
|
||||
* @param callback the matrix callback on which you'll receive the result of authentication.
|
||||
* @return return a [Cancelable]
|
||||
*/
|
||||
fun login(login: String,
|
||||
password: String,
|
||||
deviceName: String,
|
||||
callback: MatrixCallback<Session>): Cancelable
|
||||
|
||||
/**
|
||||
* Reset user password
|
||||
*/
|
||||
fun resetPassword(email: String,
|
||||
newPassword: String,
|
||||
callback: MatrixCallback<Unit>): Cancelable
|
||||
|
||||
/**
|
||||
* Confirm the new password, once the user has checked his email
|
||||
*/
|
||||
fun resetPasswordMailConfirmed(callback: MatrixCallback<Unit>): Cancelable
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.api.auth.registration
|
||||
|
||||
sealed class RegisterThreePid {
|
||||
data class Email(val email: String) : RegisterThreePid()
|
||||
data class Msisdn(val msisdn: String, val countryCode: String) : RegisterThreePid()
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.api.auth.registration
|
||||
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
|
||||
// Either a session or an object containing data about registration stages
|
||||
sealed class RegistrationResult {
|
||||
data class Success(val session: Session) : RegistrationResult()
|
||||
data class FlowResponse(val flowResult: FlowResult) : RegistrationResult()
|
||||
}
|
||||
|
||||
data class FlowResult(
|
||||
val missingStages: List<Stage>,
|
||||
val completedStages: List<Stage>
|
||||
)
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.api.auth.registration
|
||||
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
|
||||
interface RegistrationWizard {
|
||||
|
||||
fun getRegistrationFlow(callback: MatrixCallback<RegistrationResult>): Cancelable
|
||||
|
||||
fun createAccount(userName: String, password: String, initialDeviceDisplayName: String?, callback: MatrixCallback<RegistrationResult>): Cancelable
|
||||
|
||||
fun performReCaptcha(response: String, callback: MatrixCallback<RegistrationResult>): Cancelable
|
||||
|
||||
fun acceptTerms(callback: MatrixCallback<RegistrationResult>): Cancelable
|
||||
|
||||
fun dummy(callback: MatrixCallback<RegistrationResult>): Cancelable
|
||||
|
||||
fun addThreePid(threePid: RegisterThreePid, callback: MatrixCallback<RegistrationResult>): Cancelable
|
||||
|
||||
fun sendAgainThreePid(callback: MatrixCallback<RegistrationResult>): Cancelable
|
||||
|
||||
fun handleValidateThreePid(code: String, callback: MatrixCallback<RegistrationResult>): Cancelable
|
||||
|
||||
fun checkIfEmailHasBeenValidated(delayMillis: Long, callback: MatrixCallback<RegistrationResult>): Cancelable
|
||||
|
||||
val currentThreePid: String?
|
||||
|
||||
// True when login and password has been sent with success to the homeserver
|
||||
val isRegistrationStarted: Boolean
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.api.auth.registration
|
||||
|
||||
sealed class Stage(open val mandatory: Boolean) {
|
||||
|
||||
// m.login.recaptcha
|
||||
data class ReCaptcha(override val mandatory: Boolean, val publicKey: String) : Stage(mandatory)
|
||||
|
||||
// m.login.oauth2
|
||||
// m.login.email.identity
|
||||
data class Email(override val mandatory: Boolean) : Stage(mandatory)
|
||||
|
||||
// m.login.msisdn
|
||||
data class Msisdn(override val mandatory: Boolean) : Stage(mandatory)
|
||||
|
||||
// m.login.token
|
||||
|
||||
// m.login.dummy, can be mandatory if there is no other stages. In this case the account cannot be created by just sending a username
|
||||
// and a password, the dummy stage has to be done
|
||||
data class Dummy(override val mandatory: Boolean) : Stage(mandatory)
|
||||
|
||||
// Undocumented yet: m.login.terms
|
||||
data class Terms(override val mandatory: Boolean, val policies: TermPolicies) : Stage(mandatory)
|
||||
|
||||
// For unknown stages
|
||||
data class Other(override val mandatory: Boolean, val type: String, val params: Map<*, *>?) : Stage(mandatory)
|
||||
}
|
||||
|
||||
typealias TermPolicies = Map<*, *>
|
@ -17,7 +17,6 @@
|
||||
package im.vector.matrix.android.api.comparators
|
||||
|
||||
import im.vector.matrix.android.api.interfaces.DatedObject
|
||||
import java.util.*
|
||||
|
||||
object DatedObjectComparators {
|
||||
|
||||
@ -38,4 +37,4 @@ object DatedObjectComparators {
|
||||
(datedObject2.date - datedObject1.date).toInt()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.api.crypto
|
||||
|
||||
import im.vector.matrix.android.api.session.crypto.sas.EmojiRepresentation
|
||||
import im.vector.matrix.android.internal.crypto.verification.getEmojiForCode
|
||||
|
||||
/**
|
||||
* Provide all the emojis used for SAS verification (for debug purpose)
|
||||
*/
|
||||
fun getAllVerificationEmojis(): List<EmojiRepresentation> {
|
||||
return (0..63).map { getEmojiForCode(it) }
|
||||
}
|
@ -19,7 +19,6 @@ package im.vector.matrix.android.api.extensions
|
||||
import im.vector.matrix.android.api.comparators.DatedObjectComparators
|
||||
import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo
|
||||
import java.util.*
|
||||
|
||||
/* ==========================================================================================
|
||||
* MXDeviceInfo
|
||||
@ -29,7 +28,6 @@ fun MXDeviceInfo.getFingerprintHumanReadable() = fingerprint()
|
||||
?.chunked(4)
|
||||
?.joinToString(separator = " ")
|
||||
|
||||
|
||||
fun List<DeviceInfo>.sortByLastSeen() {
|
||||
Collections.sort(this, DatedObjectComparators.descComparator)
|
||||
}
|
||||
fun MutableList<DeviceInfo>.sortByLastSeen() {
|
||||
sortWith(DatedObjectComparators.descComparator)
|
||||
}
|
||||
|
@ -31,15 +31,16 @@ import java.io.IOException
|
||||
*/
|
||||
sealed class Failure(cause: Throwable? = null) : Throwable(cause = cause) {
|
||||
data class Unknown(val throwable: Throwable? = null) : Failure(throwable)
|
||||
data class Cancelled(val throwable: Throwable? = null) : Failure(throwable)
|
||||
data class NetworkConnection(val ioException: IOException? = null) : Failure(ioException)
|
||||
data class ServerError(val error: MatrixError, val httpCode: Int) : Failure(RuntimeException(error.toString()))
|
||||
object SuccessError : Failure(RuntimeException(RuntimeException("SuccessResult is false")))
|
||||
// When server send an error, but it cannot be interpreted as a MatrixError
|
||||
data class OtherServerError(val errorBody: String, val httpCode: Int) : Failure(RuntimeException(errorBody))
|
||||
data class OtherServerError(val errorBody: String, val httpCode: Int) : Failure(RuntimeException("HTTP $httpCode: $errorBody"))
|
||||
|
||||
data class RegistrationFlowError(val registrationFlowResponse: RegistrationFlowResponse) : Failure(RuntimeException(registrationFlowResponse.toString()))
|
||||
|
||||
data class CryptoError(val error: MXCryptoError) : Failure(RuntimeException(error.toString()))
|
||||
data class CryptoError(val error: MXCryptoError) : Failure(error)
|
||||
|
||||
abstract class FeatureFailure : Failure()
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.api.failure
|
||||
|
||||
// This class will be sent to the bus
|
||||
sealed class GlobalError {
|
||||
data class InvalidToken(val softLogout: Boolean) : GlobalError()
|
||||
data class ConsentNotGivenError(val consentUri: String) : GlobalError()
|
||||
}
|
@ -22,38 +22,114 @@ import com.squareup.moshi.JsonClass
|
||||
/**
|
||||
* This data class holds the error defined by the matrix specifications.
|
||||
* You shouldn't have to instantiate it.
|
||||
* Ref: https://matrix.org/docs/spec/client_server/latest#api-standards
|
||||
*/
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class MatrixError(
|
||||
/** unique string which can be used to handle an error message */
|
||||
@Json(name = "errcode") val code: String,
|
||||
@Json(name = "error") val message: String
|
||||
/** human-readable error message */
|
||||
@Json(name = "error") val message: String,
|
||||
|
||||
// For M_CONSENT_NOT_GIVEN
|
||||
@Json(name = "consent_uri") val consentUri: String? = null,
|
||||
// For M_RESOURCE_LIMIT_EXCEEDED
|
||||
@Json(name = "limit_type") val limitType: String? = null,
|
||||
@Json(name = "admin_contact") val adminUri: String? = null,
|
||||
// For M_LIMIT_EXCEEDED
|
||||
@Json(name = "retry_after_ms") val retryAfterMillis: Long? = null,
|
||||
// For M_UNKNOWN_TOKEN
|
||||
@Json(name = "soft_logout") val isSoftLogout: Boolean = false
|
||||
) {
|
||||
|
||||
companion object {
|
||||
const val FORBIDDEN = "M_FORBIDDEN"
|
||||
const val UNKNOWN = "M_UNKNOWN"
|
||||
const val UNKNOWN_TOKEN = "M_UNKNOWN_TOKEN"
|
||||
const val MISSING_TOKEN = "M_MISSING_TOKEN"
|
||||
const val BAD_JSON = "M_BAD_JSON"
|
||||
const val NOT_JSON = "M_NOT_JSON"
|
||||
const val NOT_FOUND = "M_NOT_FOUND"
|
||||
const val LIMIT_EXCEEDED = "M_LIMIT_EXCEEDED"
|
||||
const val USER_IN_USE = "M_USER_IN_USE"
|
||||
const val ROOM_IN_USE = "M_ROOM_IN_USE"
|
||||
const val BAD_PAGINATION = "M_BAD_PAGINATION"
|
||||
const val UNAUTHORIZED = "M_UNAUTHORIZED"
|
||||
const val OLD_VERSION = "M_OLD_VERSION"
|
||||
const val UNRECOGNIZED = "M_UNRECOGNIZED"
|
||||
/** Forbidden access, e.g. joining a room without permission, failed login. */
|
||||
const val M_FORBIDDEN = "M_FORBIDDEN"
|
||||
/** An unknown error has occurred. */
|
||||
const val M_UNKNOWN = "M_UNKNOWN"
|
||||
/** The access token specified was not recognised. */
|
||||
const val M_UNKNOWN_TOKEN = "M_UNKNOWN_TOKEN"
|
||||
/** No access token was specified for the request. */
|
||||
const val M_MISSING_TOKEN = "M_MISSING_TOKEN"
|
||||
/** Request contained valid JSON, but it was malformed in some way, e.g. missing required keys, invalid values for keys. */
|
||||
const val M_BAD_JSON = "M_BAD_JSON"
|
||||
/** Request did not contain valid JSON. */
|
||||
const val M_NOT_JSON = "M_NOT_JSON"
|
||||
/** No resource was found for this request. */
|
||||
const val M_NOT_FOUND = "M_NOT_FOUND"
|
||||
/** Too many requests have been sent in a short period of time. Wait a while then try again. */
|
||||
const val M_LIMIT_EXCEEDED = "M_LIMIT_EXCEEDED"
|
||||
|
||||
const val LOGIN_EMAIL_URL_NOT_YET = "M_LOGIN_EMAIL_URL_NOT_YET"
|
||||
const val THREEPID_AUTH_FAILED = "M_THREEPID_AUTH_FAILED"
|
||||
// Error code returned by the server when no account matches the given 3pid
|
||||
const val THREEPID_NOT_FOUND = "M_THREEPID_NOT_FOUND"
|
||||
const val THREEPID_IN_USE = "M_THREEPID_IN_USE"
|
||||
const val SERVER_NOT_TRUSTED = "M_SERVER_NOT_TRUSTED"
|
||||
const val TOO_LARGE = "M_TOO_LARGE"
|
||||
/* ==========================================================================================
|
||||
* Other error codes the client might encounter are
|
||||
* ========================================================================================== */
|
||||
|
||||
/** Encountered when trying to register a user ID which has been taken. */
|
||||
const val M_USER_IN_USE = "M_USER_IN_USE"
|
||||
/** Sent when the room alias given to the createRoom API is already in use. */
|
||||
const val M_ROOM_IN_USE = "M_ROOM_IN_USE"
|
||||
/** (Not documented yet) */
|
||||
const val M_BAD_PAGINATION = "M_BAD_PAGINATION"
|
||||
/** The request was not correctly authorized. Usually due to login failures. */
|
||||
const val M_UNAUTHORIZED = "M_UNAUTHORIZED"
|
||||
/** (Not documented yet) */
|
||||
const val M_OLD_VERSION = "M_OLD_VERSION"
|
||||
/** The server did not understand the request. */
|
||||
const val M_UNRECOGNIZED = "M_UNRECOGNIZED"
|
||||
/** (Not documented yet) */
|
||||
const val M_LOGIN_EMAIL_URL_NOT_YET = "M_LOGIN_EMAIL_URL_NOT_YET"
|
||||
/** Authentication could not be performed on the third party identifier. */
|
||||
const val M_THREEPID_AUTH_FAILED = "M_THREEPID_AUTH_FAILED"
|
||||
/** Sent when a threepid given to an API cannot be used because no record matching the threepid was found. */
|
||||
const val M_THREEPID_NOT_FOUND = "M_THREEPID_NOT_FOUND"
|
||||
/** Sent when a threepid given to an API cannot be used because the same threepid is already in use. */
|
||||
const val M_THREEPID_IN_USE = "M_THREEPID_IN_USE"
|
||||
/** The client's request used a third party server, eg. identity server, that this server does not trust. */
|
||||
const val M_SERVER_NOT_TRUSTED = "M_SERVER_NOT_TRUSTED"
|
||||
/** The request or entity was too large. */
|
||||
const val M_TOO_LARGE = "M_TOO_LARGE"
|
||||
/** (Not documented yet) */
|
||||
const val M_CONSENT_NOT_GIVEN = "M_CONSENT_NOT_GIVEN"
|
||||
const val RESOURCE_LIMIT_EXCEEDED = "M_RESOURCE_LIMIT_EXCEEDED"
|
||||
const val WRONG_ROOM_KEYS_VERSION = "M_WRONG_ROOM_KEYS_VERSION"
|
||||
/** The request cannot be completed because the homeserver has reached a resource limit imposed on it. For example,
|
||||
* a homeserver held in a shared hosting environment may reach a resource limit if it starts using too much memory
|
||||
* or disk space. The error MUST have an admin_contact field to provide the user receiving the error a place to reach
|
||||
* out to. Typically, this error will appear on routes which attempt to modify state (eg: sending messages, account
|
||||
* data, etc) and not routes which only read state (eg: /sync, get account data, etc). */
|
||||
const val M_RESOURCE_LIMIT_EXCEEDED = "M_RESOURCE_LIMIT_EXCEEDED"
|
||||
/** The user ID associated with the request has been deactivated. Typically for endpoints that prove authentication, such as /login. */
|
||||
const val M_USER_DEACTIVATED = "M_USER_DEACTIVATED"
|
||||
/** Encountered when trying to register a user ID which is not valid. */
|
||||
const val M_INVALID_USERNAME = "M_INVALID_USERNAME"
|
||||
/** Sent when the initial state given to the createRoom API is invalid. */
|
||||
const val M_INVALID_ROOM_STATE = "M_INVALID_ROOM_STATE"
|
||||
/** The server does not permit this third party identifier. This may happen if the server only permits,
|
||||
* for example, email addresses from a particular domain. */
|
||||
const val M_THREEPID_DENIED = "M_THREEPID_DENIED"
|
||||
/** The client's request to create a room used a room version that the server does not support. */
|
||||
const val M_UNSUPPORTED_ROOM_VERSION = "M_UNSUPPORTED_ROOM_VERSION"
|
||||
/** The client attempted to join a room that has a version the server does not support.
|
||||
* Inspect the room_version property of the error response for the room's version. */
|
||||
const val M_INCOMPATIBLE_ROOM_VERSION = "M_INCOMPATIBLE_ROOM_VERSION"
|
||||
/** The state change requested cannot be performed, such as attempting to unban a user who is not banned. */
|
||||
const val M_BAD_STATE = "M_BAD_STATE"
|
||||
/** The room or resource does not permit guests to access it. */
|
||||
const val M_GUEST_ACCESS_FORBIDDEN = "M_GUEST_ACCESS_FORBIDDEN"
|
||||
/** A Captcha is required to complete the request. */
|
||||
const val M_CAPTCHA_NEEDED = "M_CAPTCHA_NEEDED"
|
||||
/** The Captcha provided did not match what was expected. */
|
||||
const val M_CAPTCHA_INVALID = "M_CAPTCHA_INVALID"
|
||||
/** A required parameter was missing from the request. */
|
||||
const val M_MISSING_PARAM = "M_MISSING_PARAM"
|
||||
/** A parameter that was specified has the wrong value. For example, the server expected an integer and instead received a string. */
|
||||
const val M_INVALID_PARAM = "M_INVALID_PARAM"
|
||||
/** The resource being requested is reserved by an application service, or the application service making the request has not created the resource. */
|
||||
const val M_EXCLUSIVE = "M_EXCLUSIVE"
|
||||
/** The user is unable to reject an invite to join the server notices room. See the Server Notices module for more information. */
|
||||
const val M_CANNOT_LEAVE_SERVER_NOTICE_ROOM = "M_CANNOT_LEAVE_SERVER_NOTICE_ROOM"
|
||||
/** (Not documented yet) */
|
||||
const val M_WRONG_ROOM_KEYS_VERSION = "M_WRONG_ROOM_KEYS_VERSION"
|
||||
|
||||
// Possible value for "limit_type"
|
||||
const val LIMIT_TYPE_MAU = "monthly_active_user"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,4 +25,4 @@ interface ProgressListener {
|
||||
* @param total
|
||||
*/
|
||||
fun onProgress(progress: Int, total: Int)
|
||||
}
|
||||
}
|
||||
|
@ -31,4 +31,4 @@ interface StepProgressListener {
|
||||
* @param step The current step, containing progress data if available. Else you should consider progress as indeterminate
|
||||
*/
|
||||
fun onStepProgress(step: Step)
|
||||
}
|
||||
}
|
||||
|
@ -30,22 +30,20 @@ object MatrixLinkify {
|
||||
*
|
||||
* @param spannable the text in which the matrix items has to be clickable.
|
||||
*/
|
||||
fun addLinks(spannable: Spannable?, callback: MatrixPermalinkSpan.Callback?): Boolean {
|
||||
fun addLinks(spannable: Spannable, callback: MatrixPermalinkSpan.Callback?): Boolean {
|
||||
// sanity checks
|
||||
if (spannable.isNullOrEmpty()) {
|
||||
if (spannable.isEmpty()) {
|
||||
return false
|
||||
}
|
||||
val text = spannable.toString()
|
||||
var hasMatch = false
|
||||
for (index in MatrixPatterns.MATRIX_PATTERNS.indices) {
|
||||
val pattern = MatrixPatterns.MATRIX_PATTERNS[index]
|
||||
val matcher = pattern.matcher(spannable)
|
||||
while (matcher.find()) {
|
||||
for (pattern in MatrixPatterns.MATRIX_PATTERNS) {
|
||||
for (match in pattern.findAll(spannable)) {
|
||||
hasMatch = true
|
||||
val startPos = matcher.start(0)
|
||||
val startPos = match.range.first
|
||||
if (startPos == 0 || text[startPos - 1] != '/') {
|
||||
val endPos = matcher.end(0)
|
||||
val url = text.substring(matcher.start(0), matcher.end(0))
|
||||
val endPos = match.range.last + 1
|
||||
val url = text.substring(match.range)
|
||||
val span = MatrixPermalinkSpan(url, callback)
|
||||
spannable.setSpan(span, startPos, endPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
}
|
||||
@ -53,5 +51,4 @@ object MatrixLinkify {
|
||||
}
|
||||
return hasMatch
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ package im.vector.matrix.android.api.permalinks
|
||||
|
||||
import android.text.style.ClickableSpan
|
||||
import android.view.View
|
||||
import im.vector.matrix.android.api.permalinks.MatrixPermalinkSpan.Callback
|
||||
|
||||
/**
|
||||
* This MatrixPermalinkSpan is a clickable span which use a [Callback] to communicate back.
|
||||
@ -34,6 +35,4 @@ class MatrixPermalinkSpan(private val url: String,
|
||||
override fun onClick(widget: View) {
|
||||
callback?.onUrlClicked(url)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -24,14 +24,11 @@ import android.net.Uri
|
||||
*/
|
||||
sealed class PermalinkData {
|
||||
|
||||
data class EventLink(val roomIdOrAlias: String, val eventId: String) : PermalinkData()
|
||||
|
||||
data class RoomLink(val roomIdOrAlias: String) : PermalinkData()
|
||||
data class RoomLink(val roomIdOrAlias: String, val isRoomAlias: Boolean, val eventId: String?) : PermalinkData()
|
||||
|
||||
data class UserLink(val userId: String) : PermalinkData()
|
||||
|
||||
data class GroupLink(val groupId: String) : PermalinkData()
|
||||
|
||||
data class FallbackLink(val uri: Uri) : PermalinkData()
|
||||
|
||||
}
|
||||
|
@ -16,7 +16,6 @@
|
||||
|
||||
package im.vector.matrix.android.api.permalinks
|
||||
|
||||
import android.text.TextUtils
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
|
||||
/**
|
||||
@ -48,10 +47,9 @@ object PermalinkFactory {
|
||||
* @return the permalink, or null in case of error
|
||||
*/
|
||||
fun createPermalink(id: String): String? {
|
||||
return if (TextUtils.isEmpty(id)) {
|
||||
return if (id.isEmpty()) {
|
||||
null
|
||||
} else MATRIX_TO_URL_BASE + escape(id)
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -72,16 +70,14 @@ object PermalinkFactory {
|
||||
* @param url the universal link, Ex: "https://matrix.to/#/@benoit:matrix.org"
|
||||
* @return the id from the url, ex: "@benoit:matrix.org", or null if the url is not a permalink
|
||||
*/
|
||||
fun getLinkedId(url: String?): String? {
|
||||
val isSupported = url != null && url.startsWith(MATRIX_TO_URL_BASE)
|
||||
fun getLinkedId(url: String): String? {
|
||||
val isSupported = url.startsWith(MATRIX_TO_URL_BASE)
|
||||
|
||||
return if (isSupported) {
|
||||
url!!.substring(MATRIX_TO_URL_BASE.length)
|
||||
url.substring(MATRIX_TO_URL_BASE.length)
|
||||
} else null
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Escape '/' in id, because it is used as a separator
|
||||
*
|
||||
@ -89,6 +85,6 @@ object PermalinkFactory {
|
||||
* @return the escaped id
|
||||
*/
|
||||
private fun escape(id: String): String {
|
||||
return id.replace("/".toRegex(), "%2F")
|
||||
return id.replace("/", "%2F")
|
||||
}
|
||||
}
|
||||
|
@ -60,17 +60,21 @@ object PermalinkParser {
|
||||
return PermalinkData.FallbackLink(uri)
|
||||
}
|
||||
return when {
|
||||
MatrixPatterns.isUserId(identifier) -> PermalinkData.UserLink(userId = identifier)
|
||||
MatrixPatterns.isGroupId(identifier) -> PermalinkData.GroupLink(groupId = identifier)
|
||||
MatrixPatterns.isRoomId(identifier) -> {
|
||||
if (!extraParameter.isNullOrEmpty() && MatrixPatterns.isEventId(extraParameter)) {
|
||||
PermalinkData.EventLink(roomIdOrAlias = identifier, eventId = extraParameter)
|
||||
} else {
|
||||
PermalinkData.RoomLink(roomIdOrAlias = identifier)
|
||||
MatrixPatterns.isUserId(identifier) -> PermalinkData.UserLink(userId = identifier)
|
||||
MatrixPatterns.isGroupId(identifier) -> PermalinkData.GroupLink(groupId = identifier)
|
||||
MatrixPatterns.isRoomId(identifier) -> {
|
||||
val eventId = extraParameter.takeIf {
|
||||
!it.isNullOrEmpty() && MatrixPatterns.isEventId(it)
|
||||
}
|
||||
PermalinkData.RoomLink(roomIdOrAlias = identifier, isRoomAlias = false, eventId = eventId)
|
||||
}
|
||||
else -> PermalinkData.FallbackLink(uri)
|
||||
MatrixPatterns.isRoomAlias(identifier) -> {
|
||||
val eventId = extraParameter.takeIf {
|
||||
!it.isNullOrEmpty() && MatrixPatterns.isEventId(it)
|
||||
}
|
||||
PermalinkData.RoomLink(roomIdOrAlias = identifier, isRoomAlias = true, eventId = eventId)
|
||||
}
|
||||
else -> PermalinkData.FallbackLink(uri)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -18,78 +18,111 @@ package im.vector.matrix.android.api.pushrules
|
||||
import im.vector.matrix.android.api.pushrules.rest.PushRule
|
||||
import timber.log.Timber
|
||||
|
||||
sealed class Action {
|
||||
object Notify : Action()
|
||||
object DoNotNotify : Action()
|
||||
data class Sound(val sound: String = ACTION_OBJECT_VALUE_VALUE_DEFAULT) : Action()
|
||||
data class Highlight(val highlight: Boolean) : Action()
|
||||
}
|
||||
|
||||
class Action(val type: Type) {
|
||||
private const val ACTION_NOTIFY = "notify"
|
||||
private const val ACTION_DONT_NOTIFY = "dont_notify"
|
||||
private const val ACTION_COALESCE = "coalesce"
|
||||
|
||||
enum class Type(val value: String) {
|
||||
NOTIFY("notify"),
|
||||
DONT_NOTIFY("dont_notify"),
|
||||
COALESCE("coalesce"),
|
||||
SET_TWEAK("set_tweak");
|
||||
// Ref: https://matrix.org/docs/spec/client_server/latest#tweaks
|
||||
private const val ACTION_OBJECT_SET_TWEAK_KEY = "set_tweak"
|
||||
|
||||
companion object {
|
||||
private const val ACTION_OBJECT_SET_TWEAK_VALUE_SOUND = "sound"
|
||||
private const val ACTION_OBJECT_SET_TWEAK_VALUE_HIGHLIGHT = "highlight"
|
||||
|
||||
fun safeValueOf(value: String): Type? {
|
||||
try {
|
||||
return valueOf(value)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
return null
|
||||
}
|
||||
private const val ACTION_OBJECT_VALUE_KEY = "value"
|
||||
private const val ACTION_OBJECT_VALUE_VALUE_DEFAULT = "default"
|
||||
|
||||
/**
|
||||
* Ref: https://matrix.org/docs/spec/client_server/latest#actions
|
||||
*
|
||||
* Convert
|
||||
* <pre>
|
||||
* "actions": [
|
||||
* "notify",
|
||||
* {
|
||||
* "set_tweak": "sound",
|
||||
* "value": "default"
|
||||
* },
|
||||
* {
|
||||
* "set_tweak": "highlight"
|
||||
* }
|
||||
* ]
|
||||
*
|
||||
* To
|
||||
* [
|
||||
* Action.Notify,
|
||||
* Action.Sound("default"),
|
||||
* Action.Highlight(true)
|
||||
* ]
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
@Suppress("IMPLICIT_CAST_TO_ANY")
|
||||
fun List<Action>.toJson(): List<Any> {
|
||||
return map { action ->
|
||||
when (action) {
|
||||
is Action.Notify -> ACTION_NOTIFY
|
||||
is Action.DoNotNotify -> ACTION_DONT_NOTIFY
|
||||
is Action.Sound -> {
|
||||
mapOf(
|
||||
ACTION_OBJECT_SET_TWEAK_KEY to ACTION_OBJECT_SET_TWEAK_VALUE_SOUND,
|
||||
ACTION_OBJECT_VALUE_KEY to action.sound
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var tweak_action: String? = null
|
||||
var stringValue: String? = null
|
||||
var boolValue: Boolean? = null
|
||||
|
||||
companion object {
|
||||
fun mapFrom(pushRule: PushRule): List<Action>? {
|
||||
val actions = ArrayList<Action>()
|
||||
pushRule.actions.forEach { actionStrOrObj ->
|
||||
if (actionStrOrObj is String) {
|
||||
when (actionStrOrObj) {
|
||||
Action.Type.NOTIFY.value -> Action(Action.Type.NOTIFY)
|
||||
Action.Type.DONT_NOTIFY.value -> Action(Action.Type.DONT_NOTIFY)
|
||||
else -> {
|
||||
Timber.w("Unsupported action type ${actionStrOrObj}")
|
||||
null
|
||||
}
|
||||
}?.let {
|
||||
actions.add(it)
|
||||
}
|
||||
} else if (actionStrOrObj is Map<*, *>) {
|
||||
val tweakAction = actionStrOrObj["set_tweak"] as? String
|
||||
when (tweakAction) {
|
||||
"sound" -> {
|
||||
(actionStrOrObj["value"] as? String)?.let { stringValue ->
|
||||
Action(Action.Type.SET_TWEAK).also {
|
||||
it.tweak_action = "sound"
|
||||
it.stringValue = stringValue
|
||||
actions.add(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
"highlight" -> {
|
||||
(actionStrOrObj["value"] as? Boolean)?.let { boolValue ->
|
||||
Action(Action.Type.SET_TWEAK).also {
|
||||
it.tweak_action = "highlight"
|
||||
it.boolValue = boolValue
|
||||
actions.add(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
Timber.w("Unsupported action type ${actionStrOrObj}")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Timber.w("Unsupported action type ${actionStrOrObj}")
|
||||
return null
|
||||
}
|
||||
is Action.Highlight -> {
|
||||
mapOf(
|
||||
ACTION_OBJECT_SET_TWEAK_KEY to ACTION_OBJECT_SET_TWEAK_VALUE_HIGHLIGHT,
|
||||
ACTION_OBJECT_VALUE_KEY to action.highlight
|
||||
)
|
||||
}
|
||||
return if (actions.isEmpty()) null else actions
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun PushRule.getActions(): List<Action> {
|
||||
val result = ArrayList<Action>()
|
||||
|
||||
actions.forEach { actionStrOrObj ->
|
||||
when (actionStrOrObj) {
|
||||
ACTION_NOTIFY -> Action.Notify
|
||||
ACTION_DONT_NOTIFY -> Action.DoNotNotify
|
||||
is Map<*, *> -> {
|
||||
when (actionStrOrObj[ACTION_OBJECT_SET_TWEAK_KEY]) {
|
||||
ACTION_OBJECT_SET_TWEAK_VALUE_SOUND -> {
|
||||
(actionStrOrObj[ACTION_OBJECT_VALUE_KEY] as? String)?.let { stringValue ->
|
||||
Action.Sound(stringValue)
|
||||
}
|
||||
// When the value is not there, default sound (not specified by the spec)
|
||||
?: Action.Sound(ACTION_OBJECT_VALUE_VALUE_DEFAULT)
|
||||
}
|
||||
ACTION_OBJECT_SET_TWEAK_VALUE_HIGHLIGHT -> {
|
||||
(actionStrOrObj[ACTION_OBJECT_VALUE_KEY] as? Boolean)?.let { boolValue ->
|
||||
Action.Highlight(boolValue)
|
||||
}
|
||||
// When the value is not there, default is true, says the spec
|
||||
?: Action.Highlight(true)
|
||||
}
|
||||
else -> {
|
||||
Timber.w("Unsupported set_tweak value ${actionStrOrObj[ACTION_OBJECT_SET_TWEAK_KEY]}")
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
Timber.w("Unsupported action type $actionStrOrObj")
|
||||
null
|
||||
}
|
||||
}?.let {
|
||||
result.add(it)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
@ -35,9 +35,7 @@ abstract class Condition(val kind: Kind) {
|
||||
else -> UNRECOGNIZE
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
abstract fun isSatisfied(conditionResolver: ConditionResolver): Boolean
|
||||
@ -45,4 +43,4 @@ abstract class Condition(val kind: Kind) {
|
||||
open fun technicalDescription(): String {
|
||||
return "Kind: $kind"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,4 +25,4 @@ interface ConditionResolver {
|
||||
fun resolveRoomMemberCountCondition(roomMemberCountCondition: RoomMemberCountCondition): Boolean
|
||||
fun resolveSenderNotificationPermissionCondition(senderNotificationPermissionCondition: SenderNotificationPermissionCondition): Boolean
|
||||
fun resolveContainsDisplayNameCondition(containsDisplayNameCondition: ContainsDisplayNameCondition) : Boolean
|
||||
}
|
||||
}
|
||||
|
@ -15,14 +15,11 @@
|
||||
*/
|
||||
package im.vector.matrix.android.api.pushrules
|
||||
|
||||
import android.text.TextUtils
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.events.model.toModel
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageContent
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||
import timber.log.Timber
|
||||
import java.util.regex.Pattern
|
||||
|
||||
class ContainsDisplayNameCondition : Condition(Kind.contains_display_name) {
|
||||
|
||||
@ -35,22 +32,21 @@ class ContainsDisplayNameCondition : Condition(Kind.contains_display_name) {
|
||||
}
|
||||
|
||||
fun isSatisfied(event: Event, displayName: String): Boolean {
|
||||
//TODO the spec says:
|
||||
// Matches any message whose content is unencrypted and contains the user's current display name
|
||||
var message = when (event.type) {
|
||||
EventType.MESSAGE -> {
|
||||
val message = when (event.type) {
|
||||
EventType.MESSAGE -> {
|
||||
event.content.toModel<MessageContent>()
|
||||
}
|
||||
// EventType.ENCRYPTED -> {
|
||||
// event.root.getClearContent()?.toModel<MessageContent>()
|
||||
// }
|
||||
else -> null
|
||||
// TODO the spec says:
|
||||
// Matches any message whose content is unencrypted and contains the user's current display name
|
||||
// EventType.ENCRYPTED -> {
|
||||
// event.root.getClearContent()?.toModel<MessageContent>()
|
||||
// }
|
||||
else -> null
|
||||
} ?: return false
|
||||
|
||||
return caseInsensitiveFind(displayName, message.body)
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Returns whether a string contains an occurrence of another, as a standalone word, regardless of case.
|
||||
@ -61,20 +57,18 @@ class ContainsDisplayNameCondition : Condition(Kind.contains_display_name) {
|
||||
*/
|
||||
fun caseInsensitiveFind(subString: String, longString: String): Boolean {
|
||||
// add sanity checks
|
||||
if (TextUtils.isEmpty(subString) || TextUtils.isEmpty(longString)) {
|
||||
if (subString.isEmpty() || longString.isEmpty()) {
|
||||
return false
|
||||
}
|
||||
|
||||
var res = false
|
||||
|
||||
try {
|
||||
val pattern = Pattern.compile("(\\W|^)" + Pattern.quote(subString) + "(\\W|$)", Pattern.CASE_INSENSITIVE)
|
||||
res = pattern.matcher(longString).find()
|
||||
val regex = Regex("(\\W|^)" + Regex.escape(subString) + "(\\W|$)", RegexOption.IGNORE_CASE)
|
||||
return regex.containsMatchIn(longString)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## caseInsensitiveFind() : failed")
|
||||
}
|
||||
|
||||
return res
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,28 +29,25 @@ class EventMatchCondition(val key: String, val pattern: String) : Condition(Kind
|
||||
return "'$key' Matches '$pattern'"
|
||||
}
|
||||
|
||||
|
||||
fun isSatisfied(event: Event): Boolean {
|
||||
//TODO encrypted events?
|
||||
// TODO encrypted events?
|
||||
val rawJson = MoshiProvider.providesMoshi().adapter(Event::class.java).toJsonValue(event) as? Map<*, *>
|
||||
?: return false
|
||||
val value = extractField(rawJson, key) ?: return false
|
||||
|
||||
//Patterns with no special glob characters should be treated as having asterisks prepended
|
||||
// Patterns with no special glob characters should be treated as having asterisks prepended
|
||||
// and appended when testing the condition.
|
||||
try {
|
||||
val modPattern = if (hasSpecialGlobChar(pattern)) simpleGlobToRegExp(pattern) else simpleGlobToRegExp("*$pattern*")
|
||||
val regex = Regex(modPattern, RegexOption.DOT_MATCHES_ALL)
|
||||
return regex.containsMatchIn(value)
|
||||
} catch (e: Throwable) {
|
||||
//e.g PatternSyntaxException
|
||||
// e.g PatternSyntaxException
|
||||
Timber.e(e, "Failed to evaluate push condition")
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private fun extractField(jsonObject: Map<*, *>, fieldPath: String): String? {
|
||||
val fieldParts = fieldPath.split(".")
|
||||
if (fieldParts.isEmpty()) return null
|
||||
@ -77,9 +74,9 @@ class EventMatchCondition(val key: String, val pattern: String) : Condition(Kind
|
||||
return glob.contains("*") || glob.contains("?")
|
||||
}
|
||||
|
||||
//Very simple glob to regexp converter
|
||||
// Very simple glob to regexp converter
|
||||
private fun simpleGlobToRegExp(glob: String): String {
|
||||
var out = ""//"^"
|
||||
var out = "" // "^"
|
||||
for (i in 0 until glob.length) {
|
||||
val c = glob[i]
|
||||
when (c) {
|
||||
@ -90,8 +87,8 @@ class EventMatchCondition(val key: String, val pattern: String) : Condition(Kind
|
||||
else -> out += c
|
||||
}
|
||||
}
|
||||
out += ""//'$'.toString()
|
||||
out += "" // '$'.toString()
|
||||
return out
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,20 +18,25 @@ package im.vector.matrix.android.api.pushrules
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.pushrules.rest.PushRule
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
|
||||
interface PushRuleService {
|
||||
|
||||
/**
|
||||
* Fetch the push rules from the server
|
||||
*/
|
||||
fun fetchPushRules(scope: String = "global")
|
||||
fun fetchPushRules(scope: String = RuleScope.GLOBAL)
|
||||
|
||||
//TODO get push rule set
|
||||
fun getPushRules(scope: String = "global"): List<PushRule>
|
||||
// TODO get push rule set
|
||||
fun getPushRules(scope: String = RuleScope.GLOBAL): List<PushRule>
|
||||
|
||||
//TODO update rule
|
||||
// TODO update rule
|
||||
|
||||
fun updatePushRuleEnableStatus(kind: String, pushRule: PushRule, enabled: Boolean, callback: MatrixCallback<Unit>)
|
||||
fun updatePushRuleEnableStatus(kind: RuleKind, pushRule: PushRule, enabled: Boolean, callback: MatrixCallback<Unit>): Cancelable
|
||||
|
||||
fun addPushRule(kind: RuleKind, pushRule: PushRule, callback: MatrixCallback<Unit>): Cancelable
|
||||
|
||||
fun removePushRule(kind: RuleKind, pushRule: PushRule, callback: MatrixCallback<Unit>): Cancelable
|
||||
|
||||
fun addPushRuleListener(listener: PushRuleListener)
|
||||
|
||||
@ -41,6 +46,9 @@ interface PushRuleService {
|
||||
|
||||
interface PushRuleListener {
|
||||
fun onMatchRule(event: Event, actions: List<Action>)
|
||||
fun onRoomJoined(roomId: String)
|
||||
fun onRoomLeft(roomId: String)
|
||||
fun onEventRedacted(redactedEventId: String)
|
||||
fun batchFinish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,18 +18,17 @@ package im.vector.matrix.android.api.pushrules
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.api.session.room.RoomService
|
||||
import timber.log.Timber
|
||||
import java.util.regex.Pattern
|
||||
|
||||
private val regex = Pattern.compile("^(==|<=|>=|<|>)?(\\d*)$")
|
||||
private val regex = Regex("^(==|<=|>=|<|>)?(\\d*)$")
|
||||
|
||||
class RoomMemberCountCondition(val `is`: String) : Condition(Kind.room_member_count) {
|
||||
class RoomMemberCountCondition(val iz: String) : Condition(Kind.room_member_count) {
|
||||
|
||||
override fun isSatisfied(conditionResolver: ConditionResolver): Boolean {
|
||||
return conditionResolver.resolveRoomMemberCountCondition(this)
|
||||
}
|
||||
|
||||
override fun technicalDescription(): String {
|
||||
return "Room member count is $`is`"
|
||||
return "Room member count is $iz"
|
||||
}
|
||||
|
||||
fun isSatisfied(event: Event, session: RoomService?): Boolean {
|
||||
@ -56,16 +55,12 @@ class RoomMemberCountCondition(val `is`: String) : Condition(Kind.room_member_co
|
||||
*/
|
||||
private fun parseIsField(): Pair<String?, Int>? {
|
||||
try {
|
||||
val match = regex.matcher(`is`)
|
||||
if (match.find()) {
|
||||
val prefix = match.group(1)
|
||||
val count = match.group(2).toInt()
|
||||
return prefix to count
|
||||
}
|
||||
val match = regex.find(iz) ?: return null
|
||||
val (prefix, count) = match.destructured
|
||||
return prefix to count.toInt()
|
||||
} catch (t: Throwable) {
|
||||
Timber.d(t)
|
||||
}
|
||||
return null
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ object RuleIds {
|
||||
|
||||
// Default Underride Rules
|
||||
const val RULE_ID_CALL = ".m.rule.call"
|
||||
const val RULE_ID_one_to_one_encrypted_room = ".m.rule.encrypted_room_one_to_one"
|
||||
const val RULE_ID_ONE_TO_ONE_ENCRYPTED_ROOM = ".m.rule.encrypted_room_one_to_one"
|
||||
const val RULE_ID_ONE_TO_ONE_ROOM = ".m.rule.room_one_to_one"
|
||||
const val RULE_ID_ALL_OTHER_MESSAGES_ROOMS = ".m.rule.message"
|
||||
const val RULE_ID_ENCRYPTED = ".m.rule.encrypted"
|
||||
|
@ -13,9 +13,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package im.vector.matrix.android.api.pushrules
|
||||
|
||||
package im.vector.riotx.features.home.room
|
||||
|
||||
import im.vector.riotx.core.utils.RxStore
|
||||
|
||||
class VisibleRoomStore : RxStore<String>()
|
||||
object RuleScope {
|
||||
const val GLOBAL = "global"
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.api.pushrules
|
||||
|
||||
/**
|
||||
* Ref: https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-pushrules
|
||||
*/
|
||||
enum class RuleSetKey(val value: String) {
|
||||
CONTENT("content"),
|
||||
OVERRIDE("override"),
|
||||
ROOM("room"),
|
||||
SENDER("sender"),
|
||||
UNDERRIDE("underride")
|
||||
}
|
||||
|
||||
/**
|
||||
* Ref: https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-pushrules-scope-kind-ruleid
|
||||
*/
|
||||
typealias RuleKind = RuleSetKey
|
@ -18,7 +18,6 @@ package im.vector.matrix.android.api.pushrules
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.api.session.room.model.PowerLevels
|
||||
|
||||
|
||||
class SenderNotificationPermissionCondition(val key: String) : Condition(Kind.sender_notification_permission) {
|
||||
|
||||
override fun isSatisfied(conditionResolver: ConditionResolver): Boolean {
|
||||
@ -29,8 +28,7 @@ class SenderNotificationPermissionCondition(val key: String) : Condition(Kind.se
|
||||
return "User power level <$key>"
|
||||
}
|
||||
|
||||
|
||||
fun isSatisfied(event: Event, powerLevels: PowerLevels): Boolean {
|
||||
return event.senderId != null && powerLevels.getUserPowerLevel(event.senderId) >= powerLevels.notificationLevel(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,8 @@ data class PushCondition(
|
||||
/**
|
||||
* Required for room_member_count conditions.
|
||||
* A decimal integer optionally prefixed by one of, ==, <, >, >= or <=.
|
||||
* A prefix of < matches rooms where the member count is strictly less than the given number and so forth. If no prefix is present, this parameter defaults to ==.
|
||||
* A prefix of < matches rooms where the member count is strictly less than the given number and so forth.
|
||||
* If no prefix is present, this parameter defaults to ==.
|
||||
*/
|
||||
@Json(name = "is") val iz: String? = null
|
||||
) {
|
||||
@ -70,9 +71,9 @@ data class PushCondition(
|
||||
this.key?.let { SenderNotificationPermissionCondition(it) }
|
||||
}
|
||||
Condition.Kind.UNRECOGNIZE -> {
|
||||
Timber.e("Unknwon kind $kind")
|
||||
Timber.e("Unknown kind $kind")
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,6 @@ package im.vector.matrix.android.api.pushrules.rest
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class PushRule(
|
||||
/**
|
||||
@ -47,4 +46,3 @@ data class PushRule(
|
||||
*/
|
||||
val pattern: String? = null
|
||||
)
|
||||
|
||||
|
@ -24,4 +24,4 @@ data class Ruleset(
|
||||
val room: List<PushRule>? = null,
|
||||
val sender: List<PushRule>? = null,
|
||||
val underride: List<PushRule>? = null
|
||||
)
|
||||
)
|
||||
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package im.vector.matrix.android.api.session
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.lifecycle.LiveData
|
||||
|
||||
interface InitialSyncProgressService {
|
||||
|
||||
fun getInitialSyncProgressStatus() : LiveData<Status?>
|
||||
|
||||
data class Status(
|
||||
@StringRes val statusText: Int,
|
||||
val percentProgress: Int = 0
|
||||
)
|
||||
}
|
@ -19,15 +19,19 @@ package im.vector.matrix.android.api.session
|
||||
import androidx.annotation.MainThread
|
||||
import androidx.lifecycle.LiveData
|
||||
import im.vector.matrix.android.api.auth.data.SessionParams
|
||||
import im.vector.matrix.android.api.failure.GlobalError
|
||||
import im.vector.matrix.android.api.pushrules.PushRuleService
|
||||
import im.vector.matrix.android.api.session.cache.CacheService
|
||||
import im.vector.matrix.android.api.session.content.ContentUploadStateTracker
|
||||
import im.vector.matrix.android.api.session.content.ContentUrlResolver
|
||||
import im.vector.matrix.android.api.session.crypto.CryptoService
|
||||
import im.vector.matrix.android.api.session.file.FileService
|
||||
import im.vector.matrix.android.api.session.group.GroupService
|
||||
import im.vector.matrix.android.api.session.homeserver.HomeServerCapabilitiesService
|
||||
import im.vector.matrix.android.api.session.pushers.PushersService
|
||||
import im.vector.matrix.android.api.session.room.RoomDirectoryService
|
||||
import im.vector.matrix.android.api.session.room.RoomService
|
||||
import im.vector.matrix.android.api.session.securestorage.SecureStorageService
|
||||
import im.vector.matrix.android.api.session.signout.SignOutService
|
||||
import im.vector.matrix.android.api.session.sync.FilterService
|
||||
import im.vector.matrix.android.api.session.sync.SyncState
|
||||
@ -46,17 +50,28 @@ interface Session :
|
||||
CacheService,
|
||||
SignOutService,
|
||||
FilterService,
|
||||
FileService,
|
||||
PushRuleService,
|
||||
PushersService {
|
||||
PushersService,
|
||||
InitialSyncProgressService,
|
||||
HomeServerCapabilitiesService,
|
||||
SecureStorageService {
|
||||
|
||||
/**
|
||||
* The params associated to the session
|
||||
*/
|
||||
val sessionParams: SessionParams
|
||||
|
||||
val myUserId : String
|
||||
get() = sessionParams.credentials.userId
|
||||
/**
|
||||
* The session is valid, i.e. it has a valid token so far
|
||||
*/
|
||||
val isOpenable: Boolean
|
||||
|
||||
/**
|
||||
* Useful shortcut to get access to the userId
|
||||
*/
|
||||
val myUserId: String
|
||||
get() = sessionParams.credentials.userId
|
||||
|
||||
/**
|
||||
* This method allow to open a session. It does start some service on the background.
|
||||
@ -71,7 +86,7 @@ interface Session :
|
||||
|
||||
/**
|
||||
* Launches infinite periodic background syncs
|
||||
* THis does not work in doze mode :/
|
||||
* This does not work in doze mode :/
|
||||
* If battery optimization is on it can work in app standby but that's all :/
|
||||
*/
|
||||
fun startAutomaticBackgroundSync(repeatDelay: Long = 30_000L)
|
||||
@ -81,7 +96,7 @@ interface Session :
|
||||
/**
|
||||
* This method start the sync thread.
|
||||
*/
|
||||
fun startSync()
|
||||
fun startSync(fromForeground: Boolean)
|
||||
|
||||
/**
|
||||
* This method stop the sync thread.
|
||||
@ -126,10 +141,10 @@ interface Session :
|
||||
*/
|
||||
interface Listener {
|
||||
/**
|
||||
* The access token is not valid anymore
|
||||
* Possible cases:
|
||||
* - The access token is not valid anymore,
|
||||
* - a M_CONSENT_NOT_GIVEN error has been received from the homeserver
|
||||
*/
|
||||
fun onInvalidToken()
|
||||
|
||||
fun onGlobalError(globalError: GlobalError)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ package im.vector.matrix.android.api.session.cache
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
|
||||
/**
|
||||
* This interface defines a method to sign out. It's implemented at the session level.
|
||||
* This interface defines a method to clear the cache. It's implemented at the session level.
|
||||
*/
|
||||
interface CacheService {
|
||||
|
||||
@ -27,5 +27,4 @@ interface CacheService {
|
||||
* Clear the whole cached data, except credentials. Once done, the session is closed and has to be opened again
|
||||
*/
|
||||
fun clearCache(callback: MatrixCallback<Unit>)
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
package im.vector.matrix.android.api.session.content
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.exifinterface.media.ExifInterface
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
|
||||
@Parcelize
|
||||
@ -26,9 +27,10 @@ data class ContentAttachmentData(
|
||||
val date: Long = 0,
|
||||
val height: Long? = 0,
|
||||
val width: Long? = 0,
|
||||
val exifOrientation: Int = ExifInterface.ORIENTATION_UNDEFINED,
|
||||
val name: String? = null,
|
||||
val path: String,
|
||||
val mimeType: String,
|
||||
val mimeType: String?,
|
||||
val type: Type
|
||||
) : Parcelable {
|
||||
|
||||
@ -38,5 +40,4 @@ data class ContentAttachmentData(
|
||||
AUDIO,
|
||||
VIDEO
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -22,16 +22,19 @@ interface ContentUploadStateTracker {
|
||||
|
||||
fun untrack(key: String, updateListener: UpdateListener)
|
||||
|
||||
fun clear()
|
||||
|
||||
interface UpdateListener {
|
||||
fun onUpdate(state: State)
|
||||
}
|
||||
|
||||
sealed class State {
|
||||
object Idle : State()
|
||||
data class ProgressData(val current: Long, val total: Long) : State()
|
||||
object EncryptingThumbnail : State()
|
||||
data class UploadingThumbnail(val current: Long, val total: Long) : State()
|
||||
object Encrypting : State()
|
||||
data class Uploading(val current: Long, val total: Long) : State()
|
||||
object Success : State()
|
||||
object Failure : State()
|
||||
data class Failure(val throwable: Throwable) : State()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -44,4 +44,4 @@ interface ContentUrlResolver {
|
||||
* @return the URL to access the described resource, or null if the url is invalid.
|
||||
*/
|
||||
fun resolveThumbnail(contentUrl: String?, width: Int, height: Int, method: ThumbnailMethod): String?
|
||||
}
|
||||
}
|
||||
|
@ -85,6 +85,8 @@ interface CryptoService {
|
||||
|
||||
fun addRoomKeysRequestListener(listener: RoomKeysRequestListener)
|
||||
|
||||
fun removeRoomKeysRequestListener(listener: RoomKeysRequestListener)
|
||||
|
||||
fun getDevicesList(callback: MatrixCallback<DevicesListResponse>)
|
||||
|
||||
fun inboundGroupSessionsCount(onlyBackedUp: Boolean): Int
|
||||
@ -96,9 +98,10 @@ interface CryptoService {
|
||||
roomId: String,
|
||||
callback: MatrixCallback<MXEncryptEventContentResult>)
|
||||
|
||||
fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult?
|
||||
@Throws(MXCryptoError::class)
|
||||
fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult
|
||||
|
||||
fun decryptEventAsync(event: Event, timeline: String, callback: MatrixCallback<MXEventDecryptionResult?>)
|
||||
fun decryptEventAsync(event: Event, timeline: String, callback: MatrixCallback<MXEventDecryptionResult>)
|
||||
|
||||
fun getEncryptionAlgorithm(roomId: String): String?
|
||||
|
||||
@ -106,10 +109,7 @@ interface CryptoService {
|
||||
|
||||
fun downloadKeys(userIds: List<String>, forceDownload: Boolean, callback: MatrixCallback<MXUsersDevicesMap<MXDeviceInfo>>)
|
||||
|
||||
fun clearCryptoCache(callback: MatrixCallback<Unit>)
|
||||
|
||||
fun addNewSessionListener(newSessionListener: NewSessionListener)
|
||||
|
||||
fun removeSessionListener(listener: NewSessionListener)
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -18,106 +18,65 @@
|
||||
|
||||
package im.vector.matrix.android.api.session.crypto
|
||||
|
||||
import android.text.TextUtils
|
||||
import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
|
||||
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
|
||||
import org.matrix.olm.OlmException
|
||||
|
||||
/**
|
||||
* Represents a crypto error response.
|
||||
*/
|
||||
class MXCryptoError(var code: String,
|
||||
var message: String) {
|
||||
sealed class MXCryptoError : Throwable() {
|
||||
|
||||
/**
|
||||
* Describe the error with more details
|
||||
*/
|
||||
private var mDetailedErrorDescription: String? = null
|
||||
data class Base(val errorType: ErrorType,
|
||||
val technicalMessage: String,
|
||||
/**
|
||||
* Describe the error with more details
|
||||
*/
|
||||
val detailedErrorDescription: String? = null) : MXCryptoError()
|
||||
|
||||
/**
|
||||
* Data exception.
|
||||
* Some exceptions provide some data to describe the exception
|
||||
*/
|
||||
var mExceptionData: Any? = null
|
||||
data class OlmError(val olmException: OlmException) : MXCryptoError()
|
||||
|
||||
/**
|
||||
* @return true if the current error is an olm one.
|
||||
*/
|
||||
val isOlmError: Boolean
|
||||
get() = OLM_ERROR_CODE == code
|
||||
data class UnknownDevice(val deviceList: MXUsersDevicesMap<MXDeviceInfo>) : MXCryptoError()
|
||||
|
||||
|
||||
/**
|
||||
* @return the detailed error description
|
||||
*/
|
||||
val detailedErrorDescription: String?
|
||||
get() = if (TextUtils.isEmpty(mDetailedErrorDescription)) {
|
||||
message
|
||||
} else mDetailedErrorDescription
|
||||
|
||||
/**
|
||||
* Create a crypto error
|
||||
*
|
||||
* @param code the error code (see XX_ERROR_CODE)
|
||||
* @param shortErrorDescription the short error description
|
||||
* @param detailedErrorDescription the detailed error description
|
||||
*/
|
||||
constructor(code: String, shortErrorDescription: String, detailedErrorDescription: String?) : this(code, shortErrorDescription) {
|
||||
mDetailedErrorDescription = detailedErrorDescription
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a crypto error
|
||||
*
|
||||
* @param code the error code (see XX_ERROR_CODE)
|
||||
* @param shortErrorDescription the short error description
|
||||
* @param detailedErrorDescription the detailed error description
|
||||
* @param exceptionData the exception data
|
||||
*/
|
||||
constructor(code: String, shortErrorDescription: String, detailedErrorDescription: String?, exceptionData: Any) : this(code, shortErrorDescription) {
|
||||
mDetailedErrorDescription = detailedErrorDescription
|
||||
mExceptionData = exceptionData
|
||||
enum class ErrorType {
|
||||
ENCRYPTING_NOT_ENABLED,
|
||||
UNABLE_TO_ENCRYPT,
|
||||
UNABLE_TO_DECRYPT,
|
||||
UNKNOWN_INBOUND_SESSION_ID,
|
||||
INBOUND_SESSION_MISMATCH_ROOM_ID,
|
||||
MISSING_FIELDS,
|
||||
BAD_EVENT_FORMAT,
|
||||
MISSING_SENDER_KEY,
|
||||
MISSING_CIPHER_TEXT,
|
||||
BAD_DECRYPTED_FORMAT,
|
||||
NOT_INCLUDE_IN_RECIPIENTS,
|
||||
BAD_RECIPIENT,
|
||||
BAD_RECIPIENT_KEY,
|
||||
FORWARDED_MESSAGE,
|
||||
BAD_ROOM,
|
||||
BAD_ENCRYPTED_MESSAGE,
|
||||
DUPLICATED_MESSAGE_INDEX,
|
||||
MISSING_PROPERTY,
|
||||
OLM,
|
||||
UNKNOWN_DEVICES,
|
||||
UNKNOWN_MESSAGE_INDEX
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* Error codes
|
||||
* Resource for technicalMessage
|
||||
*/
|
||||
const val ENCRYPTING_NOT_ENABLED_ERROR_CODE = "ENCRYPTING_NOT_ENABLED"
|
||||
const val UNABLE_TO_ENCRYPT_ERROR_CODE = "UNABLE_TO_ENCRYPT"
|
||||
const val UNABLE_TO_DECRYPT_ERROR_CODE = "UNABLE_TO_DECRYPT"
|
||||
const val UNKNOWN_INBOUND_SESSION_ID_ERROR_CODE = "UNKNOWN_INBOUND_SESSION_ID"
|
||||
const val INBOUND_SESSION_MISMATCH_ROOM_ID_ERROR_CODE = "INBOUND_SESSION_MISMATCH_ROOM_ID"
|
||||
const val MISSING_FIELDS_ERROR_CODE = "MISSING_FIELDS"
|
||||
const val MISSING_CIPHER_TEXT_ERROR_CODE = "MISSING_CIPHER_TEXT"
|
||||
const val NOT_INCLUDE_IN_RECIPIENTS_ERROR_CODE = "NOT_INCLUDE_IN_RECIPIENTS"
|
||||
const val BAD_RECIPIENT_ERROR_CODE = "BAD_RECIPIENT"
|
||||
const val BAD_RECIPIENT_KEY_ERROR_CODE = "BAD_RECIPIENT_KEY"
|
||||
const val FORWARDED_MESSAGE_ERROR_CODE = "FORWARDED_MESSAGE"
|
||||
const val BAD_ROOM_ERROR_CODE = "BAD_ROOM"
|
||||
const val BAD_ENCRYPTED_MESSAGE_ERROR_CODE = "BAD_ENCRYPTED_MESSAGE"
|
||||
const val DUPLICATED_MESSAGE_INDEX_ERROR_CODE = "DUPLICATED_MESSAGE_INDEX"
|
||||
const val MISSING_PROPERTY_ERROR_CODE = "MISSING_PROPERTY"
|
||||
const val OLM_ERROR_CODE = "OLM_ERROR_CODE"
|
||||
const val UNKNOWN_DEVICES_CODE = "UNKNOWN_DEVICES_CODE"
|
||||
const val UNKNOWN_MESSAGE_INDEX = "UNKNOWN_MESSAGE_INDEX"
|
||||
|
||||
/**
|
||||
* short error reasons
|
||||
*/
|
||||
const val UNABLE_TO_DECRYPT = "Unable to decrypt"
|
||||
const val UNABLE_TO_ENCRYPT = "Unable to encrypt"
|
||||
|
||||
/**
|
||||
* Detailed error reasons
|
||||
*/
|
||||
const val ENCRYPTING_NOT_ENABLED_REASON = "Encryption not enabled"
|
||||
const val UNABLE_TO_ENCRYPT_REASON = "Unable to encrypt %s"
|
||||
const val UNABLE_TO_DECRYPT_REASON = "Unable to decrypt %1\$s. Algorithm: %2\$s"
|
||||
const val OLM_REASON = "OLM error: %1\$s"
|
||||
const val DETAILLED_OLM_REASON = "Unable to decrypt %1\$s. OLM error: %2\$s"
|
||||
const val DETAILED_OLM_REASON = "Unable to decrypt %1\$s. OLM error: %2\$s"
|
||||
const val UNKNOWN_INBOUND_SESSION_ID_REASON = "Unknown inbound session id"
|
||||
const val INBOUND_SESSION_MISMATCH_ROOM_ID_REASON = "Mismatched room_id for inbound group session (expected %1\$s, was %2\$s)"
|
||||
const val MISSING_FIELDS_REASON = "Missing fields in input"
|
||||
const val BAD_EVENT_FORMAT_TEXT_REASON = "Bad event format"
|
||||
const val MISSING_SENDER_KEY_TEXT_REASON = "Missing senderKey"
|
||||
const val MISSING_CIPHER_TEXT_REASON = "Missing ciphertext"
|
||||
const val BAD_DECRYPTED_FORMAT_TEXT_REASON = "Bad decrypted event format"
|
||||
const val NOT_INCLUDED_IN_RECIPIENT_REASON = "Not included in recipients"
|
||||
const val BAD_RECIPIENT_REASON = "Message was intended for %1\$s"
|
||||
const val BAD_RECIPIENT_KEY_REASON = "Message not intended for this device"
|
||||
@ -126,7 +85,9 @@ class MXCryptoError(var code: String,
|
||||
const val BAD_ENCRYPTED_MESSAGE_REASON = "Bad Encrypted Message"
|
||||
const val DUPLICATE_MESSAGE_INDEX_REASON = "Duplicate message index, possible replay attack %1\$s"
|
||||
const val ERROR_MISSING_PROPERTY_REASON = "No '%1\$s' property. Cannot prevent unknown-key attack"
|
||||
const val UNKNOWN_DEVICES_REASON = "This room contains unknown devices which have not been verified.\n" + "We strongly recommend you verify them before continuing."
|
||||
const val NO_MORE_ALGORITHM_REASON = "Room was previously configured to use encryption, but is no longer." + " Perhaps the homeserver is hiding the configuration event."
|
||||
const val UNKNOWN_DEVICES_REASON = "This room contains unknown devices which have not been verified.\n" +
|
||||
"We strongly recommend you verify them before continuing."
|
||||
const val NO_MORE_ALGORITHM_REASON = "Room was previously configured to use encryption, but is no longer." +
|
||||
" Perhaps the homeserver is hiding the configuration event."
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,8 @@ interface KeysBackupService {
|
||||
* @param keysBackupCreationInfo the info object from [prepareKeysBackupVersion].
|
||||
* @param callback Asynchronous callback
|
||||
*/
|
||||
fun createKeysBackupVersion(keysBackupCreationInfo: MegolmBackupCreationInfo, callback: MatrixCallback<KeysVersion>)
|
||||
fun createKeysBackupVersion(keysBackupCreationInfo: MegolmBackupCreationInfo,
|
||||
callback: MatrixCallback<KeysVersion>)
|
||||
|
||||
/**
|
||||
* Facility method to get the total number of locally stored keys
|
||||
@ -58,7 +59,8 @@ interface KeysBackupService {
|
||||
* @param progressListener the callback to follow the progress
|
||||
* @param callback the main callback
|
||||
*/
|
||||
fun backupAllGroupSessions(progressListener: ProgressListener?, callback: MatrixCallback<Unit>?)
|
||||
fun backupAllGroupSessions(progressListener: ProgressListener?,
|
||||
callback: MatrixCallback<Unit>?)
|
||||
|
||||
/**
|
||||
* Check trust on a key backup version.
|
||||
@ -66,7 +68,8 @@ interface KeysBackupService {
|
||||
* @param keysBackupVersion the backup version to check.
|
||||
* @param callback block called when the operations completes.
|
||||
*/
|
||||
fun getKeysBackupTrust(keysBackupVersion: KeysVersionResult, callback: MatrixCallback<KeysBackupVersionTrust>)
|
||||
fun getKeysBackupTrust(keysBackupVersion: KeysVersionResult,
|
||||
callback: MatrixCallback<KeysBackupVersionTrust>)
|
||||
|
||||
/**
|
||||
* Return the current progress of the backup
|
||||
@ -80,7 +83,8 @@ interface KeysBackupService {
|
||||
* @param version the backup version
|
||||
* @param callback
|
||||
*/
|
||||
fun getVersion(version: String, callback: MatrixCallback<KeysVersionResult?>)
|
||||
fun getVersion(version: String,
|
||||
callback: MatrixCallback<KeysVersionResult?>)
|
||||
|
||||
/**
|
||||
* This method fetches the last backup version on the server, then compare to the currently backup version use.
|
||||
@ -114,7 +118,9 @@ interface KeysBackupService {
|
||||
* @param progressListener a progress listener, as generating private key from password may take a while
|
||||
* @param callback Asynchronous callback
|
||||
*/
|
||||
fun prepareKeysBackupVersion(password: String?, progressListener: ProgressListener?, callback: MatrixCallback<MegolmBackupCreationInfo>)
|
||||
fun prepareKeysBackupVersion(password: String?,
|
||||
progressListener: ProgressListener?,
|
||||
callback: MatrixCallback<MegolmBackupCreationInfo>)
|
||||
|
||||
/**
|
||||
* Delete a keys backup version. It will delete all backed up keys on the server, and the backup itself.
|
||||
@ -123,7 +129,8 @@ interface KeysBackupService {
|
||||
* @param version the backup version to delete.
|
||||
* @param callback Asynchronous callback
|
||||
*/
|
||||
fun deleteBackup(version: String, callback: MatrixCallback<Unit>?)
|
||||
fun deleteBackup(version: String,
|
||||
callback: MatrixCallback<Unit>?)
|
||||
|
||||
/**
|
||||
* Ask if the backup on the server contains keys that we may do not have locally.
|
||||
@ -139,7 +146,9 @@ interface KeysBackupService {
|
||||
* @param trust the trust to set to the keys backup.
|
||||
* @param callback block called when the operations completes.
|
||||
*/
|
||||
fun trustKeysBackupVersion(keysBackupVersion: KeysVersionResult, trust: Boolean, callback: MatrixCallback<Unit>)
|
||||
fun trustKeysBackupVersion(keysBackupVersion: KeysVersionResult,
|
||||
trust: Boolean,
|
||||
callback: MatrixCallback<Unit>)
|
||||
|
||||
/**
|
||||
* Set trust on a keys backup version.
|
||||
@ -148,7 +157,9 @@ interface KeysBackupService {
|
||||
* @param recoveryKey the recovery key to challenge with the key backup public key.
|
||||
* @param callback block called when the operations completes.
|
||||
*/
|
||||
fun trustKeysBackupVersionWithRecoveryKey(keysBackupVersion: KeysVersionResult, recoveryKey: String, callback: MatrixCallback<Unit>)
|
||||
fun trustKeysBackupVersionWithRecoveryKey(keysBackupVersion: KeysVersionResult,
|
||||
recoveryKey: String,
|
||||
callback: MatrixCallback<Unit>)
|
||||
|
||||
/**
|
||||
* Set trust on a keys backup version.
|
||||
@ -157,7 +168,9 @@ interface KeysBackupService {
|
||||
* @param password the pass phrase to challenge with the keyBackupVersion public key.
|
||||
* @param callback block called when the operations completes.
|
||||
*/
|
||||
fun trustKeysBackupVersionWithPassphrase(keysBackupVersion: KeysVersionResult, password: String, callback: MatrixCallback<Unit>)
|
||||
fun trustKeysBackupVersionWithPassphrase(keysBackupVersion: KeysVersionResult,
|
||||
password: String,
|
||||
callback: MatrixCallback<Unit>)
|
||||
|
||||
/**
|
||||
* Restore a backup with a recovery key from a given backup version stored on the homeserver.
|
||||
@ -169,7 +182,11 @@ interface KeysBackupService {
|
||||
* @param stepProgressListener the step progress listener
|
||||
* @param callback Callback. It provides the number of found keys and the number of successfully imported keys.
|
||||
*/
|
||||
fun restoreKeysWithRecoveryKey(keysVersionResult: KeysVersionResult, recoveryKey: String, roomId: String?, sessionId: String?, stepProgressListener: StepProgressListener?, callback: MatrixCallback<ImportRoomKeysResult>)
|
||||
fun restoreKeysWithRecoveryKey(keysVersionResult: KeysVersionResult,
|
||||
recoveryKey: String, roomId: String?,
|
||||
sessionId: String?,
|
||||
stepProgressListener: StepProgressListener?,
|
||||
callback: MatrixCallback<ImportRoomKeysResult>)
|
||||
|
||||
/**
|
||||
* Restore a backup with a password from a given backup version stored on the homeserver.
|
||||
@ -181,12 +198,16 @@ interface KeysBackupService {
|
||||
* @param stepProgressListener the step progress listener
|
||||
* @param callback Callback. It provides the number of found keys and the number of successfully imported keys.
|
||||
*/
|
||||
fun restoreKeyBackupWithPassword(keysBackupVersion: KeysVersionResult, password: String, roomId: String?, sessionId: String?, stepProgressListener: StepProgressListener?, callback: MatrixCallback<ImportRoomKeysResult>)
|
||||
fun restoreKeyBackupWithPassword(keysBackupVersion: KeysVersionResult,
|
||||
password: String,
|
||||
roomId: String?,
|
||||
sessionId: String?,
|
||||
stepProgressListener: StepProgressListener?,
|
||||
callback: MatrixCallback<ImportRoomKeysResult>)
|
||||
|
||||
val keysBackupVersion: KeysVersionResult?
|
||||
val currentBackupVersion: String?
|
||||
val isEnabled: Boolean
|
||||
val isStucked: Boolean
|
||||
val state: KeysBackupState
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -72,4 +72,4 @@ enum class KeysBackupState {
|
||||
WillBackUp,
|
||||
// e2e keys are being sent to the homeserver
|
||||
BackingUp
|
||||
}
|
||||
}
|
||||
|
@ -23,4 +23,4 @@ interface KeysBackupStateListener {
|
||||
* @param newState the new state
|
||||
*/
|
||||
fun onStateChange(newState: KeysBackupState)
|
||||
}
|
||||
}
|
||||
|
@ -30,4 +30,4 @@ enum class CancelCode(val value: String, val humanReadable: String) {
|
||||
|
||||
fun safeValueOf(code: String?): CancelCode {
|
||||
return CancelCode.values().firstOrNull { code == it.value } ?: CancelCode.User
|
||||
}
|
||||
}
|
||||
|
@ -19,4 +19,4 @@ package im.vector.matrix.android.api.session.crypto.sas
|
||||
import androidx.annotation.StringRes
|
||||
|
||||
data class EmojiRepresentation(val emoji: String,
|
||||
@StringRes val nameResId: Int)
|
||||
@StringRes val nameResId: Int)
|
||||
|
@ -31,4 +31,4 @@ interface IncomingSasVerificationTransaction {
|
||||
CANCELLED_BY_ME,
|
||||
CANCELLED_BY_OTHER
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,4 +29,4 @@ interface OutgoingSasVerificationRequest {
|
||||
CANCELLED_BY_ME,
|
||||
CANCELLED_BY_OTHER
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user