gsoc-23-ivan-avalos-report.md (9220B)
1 [Link to the Android source code](https://git.taler.net/taler-android.git/tree/anastasis?h=dev/ivan-avalos/anastasis) 2 3 # Goals of the project 4 5 Anastasis is a key recovery system that allows users to create 6 encrypted backups of their keys or secrets, split across multiple 7 service providers, that can be recovered without needing a 8 password. The keys are protected using a key derived from the identity 9 attributes of the user, and can only be recovered by answering a 10 series of verification steps defined by the user. 11 12 The main goal of this Google Summer of Code project was to integrate 13 Anastasis into the Taler Android wallet, in order to allow users to 14 create encrypted and distributed backups of their wallet keys. This 15 could only be achieved by either implementing Anastasis functionality 16 within the wallet app, or creating a separate Anastasis app and 17 enabling integration between the two apps. 18 19 # What I did 20 21 I went for the second option and created a separate Anastasis app, 22 which has the advantage of allowing Anastasis to be easily used for 23 other use cases that don't involve the wallet. Besides, it gave me the 24 freedom to build the app with a more suitable architecture. 25 26 The core functionality for both the wallet and the Anastasis client is 27 built into the same component: “wallet-core”, written in 28 TypeScript. The Taler mobile apps and the web extension communicate 29 with wallet-core using a consistent and well-documented JSON API. 30 31 * [wallet-core.git](https://git.taler.net/wallet-core.git) 32 * [wallet-core API docs](https://docs.taler.net/wallet/wallet-core.html) 33 34 In order to run wallet-core in the mobile apps, a TypeScript runtime 35 needs to be embedded. There are many embedable runtimes, but some of 36 them are too big, and not all of them are optimal for the purposes of 37 Taler. QuickJS was chosen because of its small size and footprint, 38 while having good standards compatibility (ES2020). 39 40 * [QuickJS](https://bellard.org/quickjs/) 41 42 The Taler developers then created a cross-platform library built on 43 top of QuickJS, tailor-made for running wallet-core in mobile, called 44 “quickjs-tart” (nicknamed “qtart,” which stands for “**Q**uickJS 45 **TA**ler **R**un**T**ime”). This library implements native QuickJS 46 modules for cryptographic functions used by wallet-core, pre-compiles 47 wallet-core to C, and provides a simple callback-based API that can be 48 easily used from the mobile apps using native bridges (e.g. JNI). 49 50 * [quickjs-tart.git](https://git.taler.net/quickjs-tart.git) 51 52 The repository also includes qtart bindings for Android and iOS, which 53 handle the bridging so that the apps don't have to. The Android 54 bindings are available as a Maven library in Maven Central. 55 56 The main challenge for the Anastasis app was that Anastasis uses a 57 different API within wallet-core, that was originally not exposed to 58 qtart. This API is designed as a stateless reducer, that takes a state 59 and a transition and returns another state. 60 61 * [Reducer API docs](https://docs.anastasis.lu/reducer.html) 62 63 This is where things start to get interesting. In order to add 64 Anastasis support to qtart, I had to expose the Anastasis API in 65 wallet-core, implement a native QuickJS module for the Argon2 hash 66 function required by Anastasis, and ensure that the “anastasis-core” 67 subpackage compiles for QuickJS. 68 69 Once I had initial Anastasis support in qtart, the next step was to 70 add support for the API in the new Android app. I reused from the 71 wallet the code that manages the runtime and abstracts the API 72 operations as requests, but modified it to work with the stateless 73 model of the reducer. I also wrote Kotlin data structures and 74 serialization logic for all the JSON objects in the API. 75 76 At this point, I already had the starting point for the rest of the 77 app. I wrote the app using Jetpack Compose, a technology that I wasn't 78 very familiar with, so I had to learn it on the go, using the code of 79 other free-software apps I've used before as examples. 80 81 After some time, I managed to successfully create an abstraction for 82 the reducer on top of Compose, using a global view model injected to 83 the composables with Hilt. This view model contains the reducer state 84 as a StateFlow, and a ReducerManager object that allows the views to 85 safely interact with the API and update the state accordingly. 86 87 The routing part was easy, as the reducer state contains a property 88 that indicates the current step in the backup/recovery flow. The root 89 composable listens to this property and shows the screen that 90 corresponds to the backup/recovery step. 91 92 At some point when implementing the backup flow, I realized that I had 93 to use another (undocumented) API, separate to the reducer API, to 94 contact the backup providers and fetch the list of supported 95 verification methods. Again, I had to expose this API from 96 wallet-core, build quickjs-tart with this modification, and implement 97 this API on the app. 98 99 And, at some point when implementing the recovery flow, I learned 100 about YET another undocumented API, also separate to the reducer API, 101 that was needed to contact the backup providers and fetch the list of 102 secrets and recovery policies that match the identity attributes of 103 the user. 104 105 This resulted in another adventure, as this time, there was an issue 106 with data encoding and decoding in qtart related to some cryptographic 107 function that resulted in this API returning garbage. Florian helped 108 me fix this issue, and soon afterwards, the API was working just fine! 109 110 After some more work, I managed to have fully working backup and 111 recovery, with many missing features, of course, but with the basics 112 working just fine. The deadline was two days away, and I still had to 113 implement the Taler integration! Oh, no! 114 115 Well, unfortunately I couldn't get Taler integration working before 116 the deadline, but at least I got the backup fees showing in the UI, 117 and also added support for adding and removing backup providers, so 118 that users can choose where to backup their keys and learn about the 119 fees each provider demands beforehand. Isn't it cool? 120 121 # The current state 122 123 The Anastasis app, as it stands now, provides basic support for backup 124 and recovery of plain text keys (no files!). It allows users to manage 125 the backup providers and learn about the fees they demand, as well as 126 the fees per verification challenge (e.g. e-mail, SMS, question). 127 128 # What's left to do 129 130 There are many missing features: 131 132 * Some challenge types are not yet supported, such as IBAN, physical 133 mail, and TOTP. 134 * It is only possible to backup plain-text secrets, as there's no 135 functionality in the app to upload and download files. 136 * There's no support for paying backup providers with Taler. 137 * There's no mechanism to trigger a key backup from the wallet. 138 * The reducer state can't be saved or restored from a JSON file, nor 139 is it stored in shared preferences. 140 141 I already have a working Anastasis instance that requires payments 142 with Taler, which I've been using to test Taler integration and 143 implement it in the app. This shouldn't take too long to fully 144 implement, but afterwards, better integration with the wallet would 145 still be needed to make the UX simpler. 146 147 Of course, a mechanism to trigger a backup or recovery from the wallet 148 is also missing. This will be implemented with an intent to the 149 Anastasis app with the data to backup or recover, and another intent 150 to the wallet app to hand-in the recovered data. Not too difficult! 151 152 # Merged code 153 154 All the required code in wallet-core and qtart has already been 155 merged. However, the latest wallet-core release (v0.9.3-dev.19, as of 156 now) still doesn't include them. The code for the Anastasis app, 157 present in the branch `dev/ivan-avalos/anastasis` of the taler-android 158 mono-repo, hasn't been merged yet, and it's still pending review from 159 the Taler developers. 160 161 * [taler-android.git](https://git.taler.net/taler-android.git) 162 163 # What I learned / challenges 164 165 One of the hardest parts, and the one that took me the longest, was 166 getting familiar with Jetpack Compose, especially creating an entire 167 app using only Compose. How would the architecture look like? How was 168 I supposed to translate the reducer model, not only to a screen, but 169 to an entire app? 170 171 I had to look in a lot of places for inspiration, as I wanted 172 something clean, easy to work with, and above all, something that 173 actually made sense. I ended up modelling the app after the 174 architecture of the existing Anastasis web UI, written in React. As it 175 turned out, Compose is not too different from React! 176 177 Once I solved the initial challenges, I had a burst of creativity, 178 which helped me work fast on implementing most of the functionality of 179 the app. I refactored the app multiple times, and it always resulted 180 in a cleaner codebase and a better architecture. I did my best to have 181 a solid and sleek initial version, and so far it has paid off: less 182 headaches when working with my own code, and a modern and good-looking 183 app that I hope that will be a pleasure to use in the future. 184 185 During this Google Summer of Code, I learned to not be afraid of new 186 things, as in the end, there's always a way to figure them out. With 187 enough help from other people, and enough exploration, it's possible 188 for this process to be much shorter.