|
| 1 | +# Proposal: Public Suffix API |
| 2 | + |
| 3 | +**Summary** |
| 4 | + |
| 5 | +API to obtain the topmost *registrable domain / eTLD+1 (effective Top Level Domain+1)* |
| 6 | +from a domain name or URL. |
| 7 | + |
| 8 | +**Document Metadata** |
| 9 | + |
| 10 | +**Author:** [Francis McKenzie](https://github.com/mckenfra) |
| 11 | + |
| 12 | +**Sponsoring Browser:** Mozilla Firefox |
| 13 | + |
| 14 | +**Contributors:** N/A |
| 15 | + |
| 16 | +**Created:** 2024-08-19 |
| 17 | + |
| 18 | +**Related Issues:** [#231](https://github.com/w3c/webextensions/issues/231) |
| 19 | + |
| 20 | +## Motivation |
| 21 | + |
| 22 | +### Objective |
| 23 | + |
| 24 | +This API enables developers to obtain the topmost *registrable domain / eTLD+1* |
| 25 | +from a domain name or URL. This functionality is already implemented for internal |
| 26 | +use by all the major browsers. Therefore the effect of this API is to expose |
| 27 | +existing built-in browser functionality to extensions developers. |
| 28 | + |
| 29 | +The primary objective of this API is to eliminate the possibility of inconsistencies |
| 30 | +between the host browser and hosted extensions when deriving topmost |
| 31 | +*registrable domain / eTLD+1*s from domain names / URLs. |
| 32 | + |
| 33 | +Secondary objectives of this API are to: |
| 34 | + |
| 35 | +1. Improve extension developer experience by reducing complexity and maintenance overhead, |
| 36 | +since developers will no longer need to roll their own solutions for obtaining and parsing |
| 37 | +the [Public Suffix List (PSL)](https://publicsuffix.org/list/). |
| 38 | +2. Reduce extensions' resource usage (CPU, memory, disk space), since extensions |
| 39 | +will no longer be duplicating work already done by the host browser. |
| 40 | + |
| 41 | +#### Use Case #1: Wildcard Domains |
| 42 | + |
| 43 | +This API is relevant to any extension that gives the user control over which |
| 44 | +domain names / URLs the extension's functionality should apply to. For example, |
| 45 | +Mozilla's [multi-account-containers](https://github.com/mozilla/multi-account-containers) |
| 46 | +extension allows users to create containers for web pages as they visit them. |
| 47 | + |
| 48 | +Users may want the ability to apply the extension's functionality to a |
| 49 | +*wildcard domain*, such that all subdomains of some base domain are |
| 50 | +automatically included. |
| 51 | + |
| 52 | +This API allows the extension to automatically propose the topmost *registrable domain / eTLD+1* |
| 53 | +as a possible *wildcard domain* for the user to choose. It also allows the |
| 54 | +extension to prevent the user from accidentally choosing a *public suffix / eTLD* |
| 55 | +as a wildcard domain, e.g. `*.com`. |
| 56 | + |
| 57 | +#### Use Case #2: Grouping Domains in UI |
| 58 | + |
| 59 | +Where extensions present lists of domain names / URLs to users, it can be beneficial |
| 60 | +from a UX perspective to group them by their topmost *registrable domain / eTLD+1*s. |
| 61 | + |
| 62 | +##### Ungrouped domains |
| 63 | + |
| 64 | +| | |
| 65 | +| --------------------- | |
| 66 | +| example.co.uk | |
| 67 | +| example2.com | |
| 68 | +| foo.bar.example.co.uk | |
| 69 | +| foo.bar.example2.com | |
| 70 | +| www.example.co.uk | |
| 71 | +| www.example2.com | |
| 72 | + |
| 73 | +##### Grouped domains |
| 74 | + |
| 75 | +| example.co.uk | | |
| 76 | +| -------------- | --------------------- | |
| 77 | +| | example.co.uk | |
| 78 | +| | foo.bar.example.co.uk | |
| 79 | +| | www.example.co.uk | |
| 80 | + |
| 81 | +| example2.com | | |
| 82 | +| -------------- | --------------------- | |
| 83 | +| | example2.com | |
| 84 | +| | foo.bar.example2.com | |
| 85 | +| | www.example2.com | |
| 86 | + |
| 87 | +### Known Consumers |
| 88 | + |
| 89 | +Mozilla intends to make use of this API in its [multi-account-containers](https://github.com/mozilla/multi-account-containers) extension to allow users to create containers |
| 90 | +that include wildcard domain names: [PR #2352](https://github.com/mozilla/multi-account-containers/pull/2352). Currently, users must manually curate their containers to capture all |
| 91 | +anticipated subdomains of a base domain, and this manual approach is cumbersome and |
| 92 | +error-prone. |
| 93 | + |
| 94 | +Apart from this, any other extension that already rolls its own solution in order to parse |
| 95 | +the PSL could potentially benefit from this API, for example [uBlock Origin](https://github.com/gorhill/uBlock). |
| 96 | + |
| 97 | +## Specification |
| 98 | + |
| 99 | +### Schema |
| 100 | + |
| 101 | +A new API `publicSuffix` is added as follows: |
| 102 | + |
| 103 | +```ts |
| 104 | +// |
| 105 | +// Example: |
| 106 | +// |
| 107 | +// let domain = await browser.publicSuffix.getRegistrableDomain("www.example.co.uk"); |
| 108 | +// ==> 'example.co.uk' |
| 109 | +// |
| 110 | +Promise<string> browser.publicSuffix.getRegistrableDomain( |
| 111 | + // The domain name or URL whose registrable domain we want to find |
| 112 | + domainNameOrUrl: string, |
| 113 | +) |
| 114 | +``` |
| 115 | + |
| 116 | +### Behavior #1: Returned Promise |
| 117 | + |
| 118 | +The promise returned by `getRegistrableDomain()` method will either: |
| 119 | + |
| 120 | +1. Resolve with the topmost *registrable domain / eTLD+1* if it can be determined from |
| 121 | +the `domainNameOrUrl`. |
| 122 | +2. Reject with an `Error` / populate `browser.runtime.lastError`. |
| 123 | + |
| 124 | +### Behavior #2: Private Domains |
| 125 | + |
| 126 | +By default, the lookup performed by `getRegistrableDomain()` should **exclude** private domains |
| 127 | +contained in the PSL dataset. |
| 128 | + |
| 129 | +See [Future work](#1-extend-the-api). |
| 130 | + |
| 131 | +### New Permissions |
| 132 | + |
| 133 | +| Permission Added | Suggested Warning | |
| 134 | +| ---------------- | ----------------- | |
| 135 | +| publicSuffix | Read the public suffix list | |
| 136 | + |
| 137 | +### Manifest File Changes |
| 138 | + |
| 139 | +There are no changes to the manifest. |
| 140 | + |
| 141 | +## Security and Privacy |
| 142 | + |
| 143 | +### Exposed Sensitive Data |
| 144 | + |
| 145 | +The only data exposed by this API is the [public suffix list](https://publicsuffix.org/list/). |
| 146 | + |
| 147 | +### Abuse Mitigations |
| 148 | + |
| 149 | +This does not expose any new non-public data so there are no new abuse vectors. |
| 150 | + |
| 151 | +### Additional Security Considerations |
| 152 | + |
| 153 | +N/A |
| 154 | + |
| 155 | +## Alternatives |
| 156 | + |
| 157 | +### Existing Workarounds |
| 158 | + |
| 159 | +Developers can download the PSL dataset, bundle it with their extensions, and implement |
| 160 | +logic that parses and interprets the dataset in order to determine the topmost |
| 161 | +*registrable domain / eTLD+1* for a domain name. There are several drawbacks to |
| 162 | +this approach: |
| 163 | + |
| 164 | +1. Potential for inconsistencies in the determination of topmost *registrable domain / eTLD+1* |
| 165 | +by the extension and the host browser, due to differences in the version |
| 166 | +of the PSL dataset used, and differences in the implementations that the host |
| 167 | +browser and the extension use in order to interpret this dataset. |
| 168 | +2. Increased complexity and maintenance costs of extensions. |
| 169 | +3. Increased performance overhead of extensions due to bundling of bulky |
| 170 | +PSL dataset, leading to increase in memory, disk usage and increase in CPU usage |
| 171 | +due to possibly suboptimal extension implementations and repeating work already |
| 172 | +done by the host browser. |
| 173 | + |
| 174 | +### Open Web API |
| 175 | + |
| 176 | +The purpose of this API is to eliminate the potential for inconsistency between |
| 177 | +the host browser and its hosted extensions. The simplest way of achieving this |
| 178 | +is for extensions to access this functionality via the host browser itself rather |
| 179 | +than via some external source, such as an Open Web API. |
| 180 | + |
| 181 | +It is then a determination for the host browser itself as to whether |
| 182 | +the functionality (used by both the host browser and its extensions) |
| 183 | +should ultimately be obtained by means of an Open Web API. |
| 184 | + |
| 185 | +## Implementation Notes |
| 186 | + |
| 187 | +Since the major browsers all already implement internal methods for determining |
| 188 | +topmost *registrable domain / eTLD+1*s, it is hoped that the implementation will |
| 189 | +involve little more than providing the relevant mechanism for exposing these same methods |
| 190 | +to extensions: |
| 191 | + |
| 192 | +| Browser | Registrable Domain Method | |
| 193 | +| ------- | ------------------------- | |
| 194 | +| Chrome | [GetDomainAndRegistry](https://source.chromium.org/chromium/chromium/src/+/main:net/base/registry_controlled_domains/registry_controlled_domain.h;l=182;drc=4f516be19f2c1d35dc3240d050d84d10f0d6f726) | |
| 195 | +| Firefox | [getBaseDomain](https://searchfox.org/mozilla-central/rev/e9f9bf31d1c0057a1cd339b5a853a75d1b16db39/netwerk/dns/nsIEffectiveTLDService.idl#94) | |
| 196 | +| Safari | [topPrivatelyControlledDomain](https://github.com/WebKit/WebKit/blob/01eba7c416725cfd4eec57ab16daffa25b8124b4/Source/WebCore/platform/PublicSuffixStore.h#L43) | |
| 197 | + |
| 198 | +## Future Work |
| 199 | + |
| 200 | +### 1. Extend the API |
| 201 | + |
| 202 | +The major browsers provide additional methods/parameters internally for getting |
| 203 | +information related to the *registable domain / eTLD+1*. The API could be extended |
| 204 | +to expose more of these internal methods/parameters, for example: |
| 205 | + |
| 206 | +1. Provide an option to include private domains when getting the *registrable domain / eTLD+1*. |
| 207 | +2. Provide method `getPublicSuffix()` to get the *public suffix / eTLD*. |
| 208 | +3. Provide methods `isRegistrableDomain()` and/or `isPublicSuffix()` for possibly improved |
| 209 | +efficiency in certain use cases. |
| 210 | + |
| 211 | +### 2. Batching |
| 212 | + |
| 213 | +Extensions may want to obtain *registrable domain / eTLD+1*s for large numbers of |
| 214 | +domain names / URLs at once. A possible enhancement to the API would be to |
| 215 | +provide a method that performed a lookup on multiple domain names / URLs with a |
| 216 | +single method call. |
| 217 | + |
| 218 | +### 3. Change Notifications |
| 219 | + |
| 220 | +The PSL dataset, used by the browsers to determine *registrable domain / eTLD+1*s, |
| 221 | +is a dynamic dataset that can change at any time. This API proposal currently provides no |
| 222 | +mechanism for notifying extensions when the host browser's PSL dataset changes. |
| 223 | +It is understood that such changes are only made currently when a new browser version |
| 224 | +is released, however this may not always be the case. |
| 225 | + |
| 226 | +It may be useful to implement a notification mechanism so that extensions can take |
| 227 | +appropriate action when the host browser's PSL dataset changes. |
0 commit comments