001-new-browser-integration.rst (8628B)
1 XX 01: New Browser Integration 2 ############################## 3 4 .. warning:: 5 6 We have decided not to follow through with the proposed solution in this 7 design doc. We care a lot about a nice upgrade path for when better 8 browser integration becomes available. Encouraging the ``#taler://`` fragment 9 based integration might lead merchant frontends to **only** support this type 10 of integration. 11 12 Instead, the following path will be taken: 13 14 1. CSS-based presence detection will be removed from the wallet, 15 as there is no satisfactory upgrade path to better mechanisms 16 2. Manual triggering will be implemented as described in this design doc. 17 3. The ``webRequest`` permission that allows ``"Taler: "`` header based 18 browser integration will become opt-in. 19 4. The interactive API will be put on hold. Instead, SPAs should 20 ask the user to open the wallet popup (and/or render a QR code for mobile wallets). 21 5. To enable easier integration for merchants, the reference merchant backend 22 might include a page to trigger payments, which displays the QR code 23 correctly, does long-polling via JS and serves the ``"Taler: "`` header. 24 6. The presence detection ``taler://`` URI described in this document 25 will **not** be supported, as allowing presence detection might 26 encourage merchants to treat mobile / detached wallets as 2nd class 27 citizens. 28 29 Summary 30 ======= 31 32 A new and improved mechanism for the integration of GNU Taler wallets with web 33 browsers is proposed. The mechanism is meant for browsers that support the 34 WebExtension API, but do not have native support for GNU Taler. 35 36 The new approach allows the wallet extension to be installed without 37 excessive, "scary" permissions, while being simpler and still flexible. 38 39 40 Motivation 41 ========== 42 43 The current browser integration of the GNU Taler wallet relies heavily being 44 able to hook into various browser mechanisms via the following mechanisms: 45 46 * A blocking ``webRequest`` handler that is run for every request the browser 47 makes, and looks at the status code and the presence of a "``Taler:``" HTTP header. 48 * A content script that's injected on every (!) page, which injects CSS (for 49 wallet presence detection) and JavaScript listeners into the page. The 50 injection is opt-in via a "data-taler" tag on the root html element. 51 52 This has multiple problems: 53 54 * It requires excessive permissions on **all** Websites. This is scary for us (in case we mess up) 55 and for users. It also slows down the publication of the extension on extension stores. 56 * We have not measured the performance implications, but our JavaScript code is executed for every 57 single request the browser is making. 58 * The CSS-based wallet detection integration is not very flexible. Only being able 59 to show/hide some element when the wallet is detected / not detected might not be 60 the optimal thing to do when we now have mobile wallets. 61 62 63 Requirements 64 ============ 65 66 * The new browser integration should require as few permissions as possible. 67 In particular, the wallet may not require "broad host" permissions. 68 * Fingerprinting via this API should be minimized. 69 * It must be possible for Websites to interact with the wallet without using JavaScript. 70 * Single Page Apps (using JavaScript) should be able to interact the wallet without 71 requiring a browser navigation. 72 73 74 Proposed Solution 75 ================= 76 77 We first have to accept the fundamental limitation that a WebExtension is not 78 able to read a page's HTTP request headers without intrusive permissions. 79 Instead, we need to rely on the content and/or URL of the fallback page that is 80 being rendered by the merchant backend. 81 82 To be compatible with mobile wallets, merchants and banks **must** always render a fallback 83 page that includes the same ``taler://`` URI. 84 85 Manual Triggering 86 ----------------- 87 88 Using the only the ``activeTab`` permission, we can access a page's content 89 *while and only while* the user is opening the popup (or a page action). 90 The extension should look at the DOM and search for ``taler://`` links. 91 If such a link as been found, the popup should display an appropriate 92 dialog to the user (e.g. "Pay with GNU Taler on the current page."). 93 94 Using manual triggering is not the best user experience, but works on every Website 95 that displays a ``taler://`` link. 96 97 .. note:: 98 99 Using additional permissions, we could also offer: 100 101 * A context ("right click") menu for ``taler://pay`` links 102 * A declarative pageAction, i.e. an additional clickable icon that shows up 103 on the right side of the address bar. Clicking it would lead to directly 104 processing the ``taler://`` link. 105 106 It's not clear if this improves the user experience though. 107 108 109 Fragment-based Triggering 110 ------------------------- 111 112 This mechanism improves the user experience, but requires extra support from merchants 113 and broader permissions, namely the ``tabs`` permission. This permission 114 is shown as "can read your history", which sounds relatively intrusive. 115 We might decide to make this mechanism opt-in. 116 117 The extension uses the ``tabs`` permission to listen to changes to the 118 URL displayed in the currently active tab. It then parses the fragment, 119 which can contain a ``taler://`` URI, such as: 120 121 .. code:: none 122 123 https://shop.taler.net/checkout#taler://pay/backend.shop.taler.net/-/-/2020.099-03C5F644XCNMR 124 125 The fragment is processed the same way a "Taler: " header is processed. 126 For examle, a ``taler://pay/...`` fragment navigates to an in-wallet page 127 and shows a payment request to the user. 128 129 130 Fragment-based detection 131 ------------------------ 132 133 To support fragment-based detection of the wallet, a special 134 ``taler://check-presence/${redir}`` URL can be used to cause a navigation to 135 ``${redir}`` if the wallet is installed. The redirect URL can be absolute or 136 relative to the current page and can contain a fragment. 137 138 For example: 139 140 .. code:: none 141 142 https://shop.taler.net/checkout#taler://check-presence/taler-installed 143 144 -> (when wallet installed) 145 146 https://shop.taler.net/taler-installed 147 148 149 To preserve correct browser history navigation, the wallet does not initiate the redirect if 150 the tab's URL changes from ``${redir}`` back to the page with the ``check-presence`` fragment. 151 152 153 Asynchronous API 154 ---------------- 155 156 The fragment-based triggering does not work well on single-page apps: It 157 interferes with the SPA's routing, as it requires a change to the navigation 158 location's fragment. 159 160 The only way to communicate with a WebExtension is by knowing its extension ID. 161 However, we want to allow users to build their own version of the WebExtension, 162 and extensions are assigned different IDs in different browsers. We thus need 163 a mechanism to obtain the wallet extension ID in order to asynchronously communicate 164 with it. 165 166 To allow the Website to obtain this extension ID, we can extend the redirection URL 167 of the ``taler://check-presence`` fragment to allow a placeholder for the extension ID. 168 169 .. code:: none 170 171 https://shop.taler.net/checkout#taler://check-presence/#taler-installed-${extid} 172 173 -> (when wallet installed) 174 175 https://shop.taler.net/checkout#taler-installed-12345ASDFG 176 177 .. warning:: 178 179 This allows fingerprinting, and thus should be an opt-in feature. 180 The wallet could also ask the user every time to allow a page to obtain the 181 182 .. note:: 183 184 To avoid navigating away from an SPA to find out the extension ID, the SPA 185 can open a new tab/window and communicate the updated extension ID back to 186 original SPA page. 187 188 Once the Website has obtained the extension ID, it can use the ``runtime.connect()`` function 189 to establish a communication channel to the extension. 190 191 192 Alternatives 193 ============ 194 195 * Manual copy&paste of ``taler://`` URIs :-) 196 * Integration of GNU Taler into all major browsers :-) 197 * Convincing Google and/or Mozilla to provide better support 198 for reacting to a limited subset of request headers in 199 a declarative way 200 * Convince Google and/or Mozilla to implement a general mechanism 201 where extensions can offer a "service" that websites can then 202 connect to without knowing some particular extension ID. 203 * Convince Google and/or Mozilla to add better support for 204 registering URI schemes from a WebExtension, so that 205 we can register a handler for ``taler://``. For a better user experience, 206 there should also be some way to check whether some particular URI scheme 207 has a handler. 208 209 Drawbacks 210 ========= 211 212 * Firefox currently does not support messages from a website to an extension, and currently 213 cannot support the asynchronous wallet API. 214 There is a bug open for this issue: https://bugzilla.mozilla.org/show_bug.cgi?id=1319168