├── .github ├── ISSUE_TEMPLATE │ └── .gitkeep ├── pull_request_template.md └── workflows │ └── deploy.yaml ├── .gitignore ├── LICENSE ├── README.md ├── generate-book.py ├── rfc-0000-template.md └── rfcs ├── .gitkeep ├── rfc-0001-webhooks.md └── rfc-0003-discriminators.md /.github/ISSUE_TEMPLATE/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/revoltchat/rfcs/1f107bfd40a688b22ea0fcca4874c2510d0ad494/.github/ISSUE_TEMPLATE/.gitkeep -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/revoltchat/rfcs/1f107bfd40a688b22ea0fcca4874c2510d0ad494/.github/pull_request_template.md -------------------------------------------------------------------------------- /.github/workflows/deploy.yaml: -------------------------------------------------------------------------------- 1 | # original code is from https://github.com/rust-lang/rfcs/blob/master/generate-book.py and is licensed under MIT+Apache 2 | 3 | name: Deploy 4 | on: 5 | push: 6 | branches: 7 | - master 8 | 9 | jobs: 10 | deploy: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v3 14 | with: 15 | fetch-depth: 0 16 | - name: Install mdbook 17 | run: | 18 | mkdir mdbook 19 | curl -Lf https://github.com/rust-lang/mdBook/releases/download/v0.4.26/mdbook-v0.4.26-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook 20 | echo `pwd`/mdbook >> $GITHUB_PATH 21 | - name: Generate Book 22 | run: | 23 | ./generate-book.py 24 | - name: Deploy GitHub Pages 25 | run: | 26 | git worktree add gh-pages gh-pages 27 | git config user.name "Deploy from CI" 28 | git config user.email "" 29 | cd gh-pages 30 | # Delete the ref to avoid keeping history. 31 | git update-ref -d refs/heads/gh-pages 32 | rm -rf * 33 | mv ../book/* . 34 | git add . 35 | git commit -m "Deploy $GITHUB_SHA to gh-pages" 36 | git push --force 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | book 2 | src -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Revolt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RFCs 2 | RFCs for changes to Revolt. This is a process for adding or changing anything in Revolt, in a formalised and clear manner, so that everyone understands clearly what is needed. 3 | 4 | ## When you need an RFC 5 | 6 | You must create an RFC if you intend to make a substantial change to Revolt, or any part of Revolt. This includes: 7 | 8 | - Any new features 9 | - Changes to existing ones which have a large impact 10 | - Removing features 11 | 12 | Some things don't need an RFC - these include: 13 | - Rewording, reorganising or refactoring text or code 14 | - Additions which improve the app in ways which do not add new features (e.g. performance improvements, bug fixes, better user experience in regards to errors) 15 | - Additions which do not affect users of Revolt but only the developers of Revolt 16 | 17 | If you attempt to open a pull request which would require an RFC without opening an RFC first, your pull request will be closed and you will be asked to submit an RFC before the pull request can be looked at. 18 | 19 | If applicable, you're allowed to start working on an implementation for a draft or in-progress RFC - however, if the RFC is denied, your pull request will be denied as well. 20 | 21 | ## Before creating an RFC 22 | 23 | Before submitting an RFC, it's a good idea to discuss your idea first - if your idea is declined, you won't have wasted any time writing an RFC. You can discuss in issues or discussions in Revolt's GitHub organisation or, preferably, [the Revolt API server](https://rvlt.gg/API). 24 | 25 | ## Creating an RFC 26 | 27 | To get a feature added to Revolt, you must get your RFC merged into this repository first. At this point, the RFC is "active" and can be discussed. 28 | 29 | - [Fork the RFC repo](https://github.com/revoltchat/rfcs/fork) 30 | - Copy the `rfc-0000-template.md` file into `rfcs/rfc-0000-name-of-feature.md`. **Don't give it a number yet** - this will be assigned once the RFC is opened. 31 | - Fill in the new RFC file. **Make sure to include as much detail as possible** - any ambiguties will slow down the RFC process and will likely need to be corrected. 32 | - Submit the RFC. Make sure to give the PR a relevant name - use the RFC's name or something similar which conveys a similar message. 33 | - Once the PR is open, you can update the RFC number to match the pull request's number - for example, if the pull request is `#36`, your RFC will be `0036`. 34 | - The RFC will be labelled by the team. 35 | - The RFC will then be discussed and commented on with queries or requests for changes by the team and community members. You can make inline edits to incoporate suggestions - **do not squash or edit existing commits**, as this can lead to confusion. 36 | - Once the RFC is close to being finalised, a member of the team will assign the RFC the Final Comment Period label. At this point, the RFC **should not be edited**. This stage will last 10 days; once it ends, the team will be in a position where a final decision on the RFC can be made (i.e. whether to merge it, close it or postpone it). This outcome does not need to match the concensus of all participants of the discussion - however, most (if not all) opinions expressed in the RFC's discussion will be taken into account. During the Final Comment Period, any final comments can be made to lodge any objections before a decision is made. 37 | - During the Final Comment Period, if any new substantial arguments or ideas are raised, the team or the RFC's author can cancel then Final Comment Period can be cancelled - the RFC will then go back into development. 38 | 39 | ## Active RFC lifecycle 40 | 41 | Once the RFC is merged, it will become "active". You can still make updates to the RFC via pull requests; however, the workflow above must be followed. 42 | 43 | Now that it is active, a developer can be assigned to implement the RFC. The author does **not** need to implement it themselves; however, this is the most effective way for the RFC to be implemented. Furthermore, the fact that the RFC is active does not mean it is guaranteed to be implemented or accepted. If, after this stage, it is found that the RFC is no longer deemed necessary or any major flaws are found in it, it can be still denied and closed. 44 | 45 | ## Implementing the RFC 46 | 47 | Depending on the RFC, an implemention must be made. Once the RFC is merged and active, a tracking issue can be made to track the status of the implemention and link to any currently open pull requests. This can also serve as a discussion area where the implemention or queries about the RFC can be made. If you would like to implement the RFC, comment on the tracking issue so a member of the team can assign you to it. If you are unsure as to whether someone is already working on implementing the RFC, feel free to leave a comment. 48 | 49 | ## RFC postponement 50 | 51 | RFCs can be postponed - if so, they will be labelled with the "postponed" label. This can be for various issues - for example, if the RFC is not being currently worked on, or if it is blocked by other RFCs that are not expected to be finished soon. 52 | -------------------------------------------------------------------------------- /generate-book.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | 4 | 5 | """ 6 | original code is from https://github.com/rust-lang/rfcs/blob/master/generate-book.py and is licensed under MIT+Apache 7 | 8 | This auto-generates the mdBook SUMMARY.md file based on the layout on the filesystem. 9 | This generates the `src` directory based on the contents of the `rfcs` directory. 10 | Most RFCs should be kept to a single chapter. However, in some rare cases it 11 | may be necessary to spread across multiple pages. In that case, place them in 12 | a subdirectory with the same name as the RFC. For example: 13 | 0123-my-awesome-feature.md 14 | 0123-my-awesome-feature/extra-material.md 15 | It is recommended that if you have static content like images that you use a similar layout: 16 | 0123-my-awesome-feature.md 17 | 0123-my-awesome-feature/diagram.svg 18 | The chapters are presented in sorted-order. 19 | """ 20 | 21 | from io import TextIOWrapper 22 | import os 23 | import shutil 24 | import subprocess 25 | 26 | def main(): 27 | if os.path.exists('src'): 28 | # Clear out src to remove stale links in case you switch branches. 29 | shutil.rmtree('src') 30 | os.mkdir('src') 31 | 32 | for path in os.listdir('rfcs'): 33 | symlink(f'../rfcs/{path}', f'src/{path}') 34 | 35 | symlink('../README.md', 'src/introduction.md') 36 | 37 | with open('src/SUMMARY.md', 'w') as summary: 38 | summary.write('[Introduction](introduction.md)\n\n') 39 | collect(summary, 'rfcs', 0) 40 | 41 | subprocess.call(['mdbook', 'build']) 42 | 43 | def collect(summary: TextIOWrapper, path: str, depth: int): 44 | entries = [e for e in os.scandir(path) if e.name.endswith('.md')] 45 | entries.sort(key=lambda e: e.name) 46 | for entry in entries: 47 | indent = ' '*depth 48 | name = entry.name[:-3] 49 | link_path = entry.path[5:] 50 | 51 | summary.write(f'{indent}- [{name}]({link_path})\n') 52 | maybe_subdir = os.path.join(path, name) 53 | 54 | if os.path.isdir(maybe_subdir): 55 | collect(summary, maybe_subdir, depth+1) 56 | 57 | def symlink(src: str, dst: str): 58 | if not os.path.exists(dst): 59 | os.symlink(src, dst) 60 | 61 | if __name__ == '__main__': 62 | main() -------------------------------------------------------------------------------- /rfc-0000-template.md: -------------------------------------------------------------------------------- 1 | - Feature Name: (The name of the RFC) 2 | - Start Date: (DD/MM/YYYY) 3 | - RFC PR: https://github.com/revoltchat/rfcs/issues/0000 4 | - Tracking Issue: https://github.com/revoltchat/revolt/issues/0000 5 | - Status: draft 6 | 7 | # Summary 8 | 9 | One paragraph overview of the feature 10 | 11 | # Motivation 12 | 13 | Why is this RFC being made, what does it achieve or solve, what is the expected outcome 14 | 15 | # Guide-level explanation 16 | 17 | Explain the proposal as if it's already in Revolt and you were teaching it to new users. 18 | - Introduce new concepts 19 | - Explain the feature with examples 20 | - What this fixes or adds and what users should think of the feature 21 | - Discuss how this impacts using Revolt, how it makes it harder or easier to use 22 | 23 | For internal oriented RFCs such as internal code changes, this should largely talk about how contributors should think about the change and give examples on the impacts. 24 | 25 | # Reference-level explanation 26 | 27 | This is the technical section of the RFC, it should go over in detail: 28 | - Its interaction with other features 29 | - How this will be implemented 30 | - Corner or edge cases 31 | 32 | This section should reference the examples in the previous section and disect them in more detail. 33 | 34 | # Drawbacks 35 | 36 | Why should this not be added. 37 | 38 | # Rationale and alternatives 39 | 40 | - Why is this design the best 41 | - Are there alternative ways to solve this 42 | - Could this be done with existing features or existing solutions 43 | 44 | # Prior art 45 | 46 | This should include both good and bad outlooks on the proposal. This could include how other platforms, software and hardware solve similar issues if relevent or how any existing proposals have tried to solve the same problem. 47 | 48 | # Unresolved questions 49 | 50 | - Are there any parts which are not yet designed or you believe need further discussion? 51 | - Do you expect any part of this proposal to change? 52 | - Are there any related issues which you believe are out of the scope of this RFC that could be addressed in a seperate RFC? 53 | 54 | # Security concerns 55 | 56 | How does this RFC impact security - This section might not always be applicable and if you believe it is not, please write your reasoning in this section. 57 | 58 | # Future ideas 59 | 60 | Are there any features or changes that this proposal could enable? How does this proposal impact the future of Revolt? 61 | -------------------------------------------------------------------------------- /rfcs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/revoltchat/rfcs/1f107bfd40a688b22ea0fcca4874c2510d0ad494/rfcs/.gitkeep -------------------------------------------------------------------------------- /rfcs/rfc-0001-webhooks.md: -------------------------------------------------------------------------------- 1 | - Feature Name: Webhooks 2 | - Start Date: 10/03/2023 3 | - RFC PR: https://github.com/revoltchat/rfcs/issues/0001 4 | - Tracking Issue: https://github.com/revoltchat/revolt/issues/0000 5 | - Status: accepted 6 | 7 | # Summary 8 | 9 | This RFC adds the ability to be able to send messages from external applications and 10 | services through webhooks, this allows intergration with other services. 11 | 12 | # Motivation 13 | 14 | Webhooks make it easy to intergrate with other services, this allows other services 15 | to take advantage of Revolt's to send infomation through revolt. A common example is 16 | GitHub Webhooks which allow you to send messages when a repository changes. 17 | 18 | # Guide-level explanation 19 | 20 | This RFC adds the ability to create, edit, delete webhooks and send messages with the 21 | webhook, webhooks have a name, id, channel id, avatar and token. The token and id are 22 | used to send messages with the webhook. 23 | 24 | Fetching the webhook can be done with or without authorization, if you fetch with 25 | authorization the token will be returned, as the token is secret it should not be 26 | given to people without permissions. 27 | 28 | There will be a built-in way to use GitHub webhooks from revolt as this is a very 29 | commonly used type of webhook, no other types of webhooks have been considered yet. 30 | 31 | Creating a webhook will give it a default name of "Webhook" and default to the first 32 | channel in the channel list, users can then edit the name, channel and avatar. 33 | 34 | # Reference-level explanation 35 | 36 | The database will have an additional document to store the webhooks 37 | 38 | ```rust 39 | struct Webhoook { 40 | // Unique Id 41 | id: String, 42 | 43 | // The name of the webhook - 1 to 32 chars 44 | name: String, 45 | 46 | // The avatar of the webhook, if it has one 47 | avatar: Option, 48 | 49 | // The ID of the channel which this webhook belongs to 50 | channel: String, 51 | 52 | // The permissions of the webhook 53 | permissions: u64, 54 | 55 | // The token of the webhook 56 | token: String 57 | } 58 | ``` 59 | 60 | Addition routes must be added to the API, this includes: 61 | 62 | ## Channel Routes 63 | 64 | ```http 65 | POST /channel//webhooks - Create webhook in the channel 66 | GET /channel//webhooks - Gets all webhooks in the channel 67 | ``` 68 | 69 | ## Webhook Routes 70 | 71 | ```http 72 | GET /webhooks// - Gets the webhook with a token, does not require permissions 73 | GET /webhooks/ - Gets the wehook, requires permissions 74 | PATCH /webhooks// - Edits the webhook with a token, does not require permissions 75 | PATCH /webhooks/ - Edits the webhooks, requires permissions 76 | DELETE /webhooks// - Deletes the webhook with a token, does not require permissions 77 | DELETE /webhooks/ - Deletes the wehook, requires permissions 78 | POST /webhooks// - Sends a message with the webhook 79 | POST /webhooks///github - GitHub compatible route for sending a message with the webhook 80 | ``` 81 | 82 | The PATCH routes take a json body with the data for editing the webhook: 83 | 84 | ```rust 85 | struct WebhookEditBody { 86 | // The new name for the webhook 87 | name: Option, 88 | 89 | // The new avatar for the webhook - Autumn ID 90 | avatar: Option, 91 | 92 | // The new permissions 93 | 94 | permissions: Option, 95 | 96 | // The fields to remove 97 | remove: Option> 98 | } 99 | 100 | pub enum RemoveFields { 101 | Avatar 102 | } 103 | ``` 104 | 105 | The POST routes take the same json body as the message send route. The data the GitHub compatible 106 | route takes can be seen on the [GitHub docs](https://docs.github.com/en/webhooks-and-events/webhooks/webhook-events-and-payloads) 107 | 108 | The message structure must be changed to accommodate these changes, this requires a breaking change 109 | of making `Message.author` either the user ID or the webhook ID, depending on what sent the message, 110 | when a webhook sends a message a `Message.webhook` field will contain the webhook's information. 111 | 112 | ```diff 113 | - author: String // User ID 114 | + author: String // Either user ID or webhook ID 115 | + webhook: Option 116 | ``` 117 | 118 | the webhook data inside a message will contain a stripped down version of the `Webhook` struct to avoid 119 | sending unessessary data: 120 | 121 | ```rust 122 | struct MessageWebhook { 123 | // The name of the webhook - 1 to 32 chars 124 | name: String, 125 | // The id of the avatar of the webhook, if it has one 126 | avatar: Option 127 | } 128 | ``` 129 | 130 | This will require an update to existing programs which use the API to ensure they do not break 131 | with this change. 132 | 133 | Information about the webhook which sent the message is included inside the message, you are also able to 134 | query `GET /webhooks/` route which returns the same infomation. 135 | 136 | There will be three new events to go along side this, these events do not contain the token as these events are 137 | sent to all people who have access to the channel and not just people with permissions 138 | 139 | ```rust 140 | enum Events { 141 | WebhookCreate(Webhook), // Contains all the info about the webhook which was created 142 | 143 | WebhookUpdate { 144 | id: String, // The ID of the updated webhook 145 | data: PartialWebhook, // Contains the data which was updated 146 | remove: Vec // A vec of the fields which where cleared 147 | }, 148 | 149 | WebhookDelete { 150 | id: String // The ID of the webhook which was deleted 151 | }, 152 | 153 | // existing events 154 | ... 155 | } 156 | ``` 157 | 158 | ## Permissions 159 | 160 | Webhooks are affected by permissions, to for example stop them from uploading files, 161 | webhooks will store the full `u64` set of permissions to keep consistancy but only 162 | a few permissions will affect the webhook, because of this the client will only show 163 | a select few permissions, this includes: 164 | 165 | - Send Messages 166 | - Send Embeds 167 | - Masquerade 168 | - React - affects interaction reactions 169 | 170 | When the webhook is created it defaults to having all of these permissions enabled. 171 | 172 | # Prior art 173 | 174 | [Discord](https://discord.com) and [Slack](https://slack.com) both have webhooks as well both with 175 | similar implementation, both work well and have wide adoption 176 | 177 | # Unresolved questions 178 | 179 | Currently this RFC includes a breaking change, if possible this would like to be avoided however 180 | no solution has been found yet. 181 | 182 | # Security concerns 183 | 184 | No security concerns have been found yet, however this does allow third-parties to send messages to revolt, 185 | this could be used maliciously however the affected scope is small as it can only send messages. 186 | 187 | # Future ideas 188 | 189 | Currently there is only a Github compatible route for pre-existing formats, in the future this could be 190 | expanded to support more formats such as slack for example. 191 | -------------------------------------------------------------------------------- /rfcs/rfc-0003-discriminators.md: -------------------------------------------------------------------------------- 1 | - Feature Name: Discriminators 2 | - Start Date: 06/05/2023 3 | - RFC PR: https://github.com/revoltchat/rfcs/pull/3 4 | - Tracking Issue: https://github.com/revoltchat/backend/issues/247 5 | - Status: accepted 6 | 7 | # Summary 8 | 9 | Revolt should introduce discriminators which serve as part of a semi-hidden extension to 10 | usernames which allows multiple users to have the same username, the discriminator would 11 | not be visible in most circumstances except when viewing a person's profile and if you 12 | were to add said person by their username. 13 | 14 | # Motivation 15 | 16 | This RFC aims to move forwards [prior discussion on the feature suggestions forum](https://github.com/orgs/revoltchat/discussions/61), 17 | it stands to solve multiple problems when implemented correctly: 18 | 19 | - Users should in most, if not all, cases be able to pick their chosen username. 20 | - This should curb any incentive to sell / steal accounts for "rare usernames". 21 | 22 | Certain "rare" discriminators can also be prohibited. 23 | 24 | - Allow users who do not want to be easily discoverable to stay hidden. 25 | 26 | Just a 4-digit discriminator provides 10,000 unique users. 27 | Expanding on this, we could for example, let users hide discriminators in servers and similar privacy features. 28 | 29 | # Guide-level explanation 30 | 31 | Revolt would be switching to a new username system made up of three parts: 32 | 33 | ``` 34 | myusername#1234 35 | ^ your chosen name (restricted character set) 36 | ^ separator between chosen name and discriminator 37 | ^ discriminator (4-digits in range 0001 to 9999) 38 | ``` 39 | 40 | Users will also be able to set an optional display name which overrides their username 41 | in various parts of the user interface. 42 | 43 | Usernames use a restricted character set of any Unicode alphabet excluding some lookalike 44 | characters from the Cyrillic alphabet, if you username does not currently fit the specification, 45 | then it will be automatically santised upon upgrade and copied to your display name. 46 | 47 | Discriminators for new users are generated randomly on sign up while existing users will 48 | get a randomly generated discriminators upon the server software being upgraded. 49 | 50 | > Revolt treats usernames as case-insensitive so a full username such as "Jason#1234" is 51 | > effectively the same as "jasON#1234" but only "Jason#1234" will display in the UI. 52 | 53 | Users may: 54 | 55 | - Change the case of their username at any moment, such as from "Jason" to "jasON". 56 | 57 | This will never affect their discriminator. 58 | 59 | - Change their username, but may have their discriminator regenerated if there is a conflict. 60 | 61 | Such as if you are changing from "Jason#1234" to "Phil", but "Phil#1234" is taken. 62 | 63 | ### User Opinion 64 | 65 | Prior discussions on the forums primarily seem to lean in favour of discriminators being 66 | implemented into Revolt, the internal team has not raised any complaints against it, and 67 | the primary community on Revolt ("Revolt Lounge") appears to be somewhat split on the 68 | issue. 69 | 70 | As a recent case study, Discord's change to unique usernames only has generated a lot of 71 | backlash and criticism from the community, it appears to be overwhemingly negative but 72 | these experiences are mostly coming from long-term users of Discord. The true opinion of 73 | the average user has not been gauged yet. 74 | 75 | ### Usability 76 | 77 | This may make it more difficult to understand how to add users on Revolt, however this 78 | shouldn't be an issue as long as it's clearly communicated through the user interface. 79 | Revolt already allows a wide range of Unicode in usernames so we are definitely not 80 | making a significant UX hit towards the usability of the friend system. 81 | 82 | > There are further considerations listed at the end of this document which must be 83 | > addressed if this RFC were to be implemented. 84 | 85 | # Reference-level explanation 86 | 87 | A new `discriminator` string field shall be added to the User object, as such the 88 | `UNIQUE IGNORE-CASE USERNAME` index will be replaced with a 89 | `UNIQUE (IGNORE-CASE USERNAME + DISCRIMINATOR)` index. 90 | 91 | A new `display_name` string field shall be added to the User object, this will be subject 92 | to all existing username restrictions. 93 | 94 | Existing clients may continue to display usernames but will no longer have the guarantee 95 | any one username is unique and must implement the discriminator field to distinguish them 96 | to end users, and they must also show the display name instead of username in the chat 97 | interface and include it in profiles. 98 | 99 | Discriminators shall be 4-digit identifiers (this may be expanded in the future if we reach 100 | a point at which they are no longer sustainable, or otherwise at least one username is becoming 101 | saturated). 102 | 103 | The friend add route, `POST /users/friend` will be updated to support parsing a discriminator, 104 | this will provide backwards compatibility for older clients to some limited extent. 105 | 106 | ```json 107 | { 108 | "username": "abc#1234" 109 | } 110 | ``` 111 | 112 | # Drawbacks 113 | 114 | The main drawbacks are: 115 | 116 | - Additional information to remember about your username 117 | 118 | Although this works both ways in the sense that, you can have a much simpler username. 119 | 120 | - Users may no longer have a completely 'unique' username on the platform 121 | 122 | But we're approaching this from the standpoint that usernames on platforms such as these should not have to compete for 'uniqueness'. 123 | 124 | I want to take this section to also discuss the case study of Discord's removal of the discriminator system and their [cited drawbacks](https://discord.com/blog/usernames#heading-3), 125 | it is worth noting however that Discord has not really specified how they've generated these statistics or this information, 126 | although for the sake of the following they are taken at face value: 127 | 128 | - > More than 40% of you either don’t remember your discriminator or don’t even know what a discriminator is. That’s a big problem when discriminators are required to add a new friend. 129 | 130 | This RFC cannot address this issue however further work can be done to ease these interactions: 131 | 132 | - R&D to determine how to build the UI to intuitively tell the user how to share their username with their discriminator 133 | - Implementation of friend links / codes to ease connecting users to each other 134 | 135 | This is not something that Discord has solved and to this day there is no way to create a friend request link. 136 | 137 | - Implementation of nearby find (prior art: Discord) / QR friend codes (prior art: Snapchat) / add by contact book (prior art: Signal, WhatsApp) 138 | 139 | These may help streamline IRL interactions by providing users with a simple flow to follow. 140 | 141 | - Implementation of add by connections 142 | 143 | Allow adding other people by common social media connections. 144 | 145 | - Global user search (prior art: Steam) 146 | 147 | Allow users to opt-in to a global username search / or otherwise also search through mutual members on servers, to avoid needing the discriminator altogether. 148 | 149 | - > Across Discord, almost half of all friend requests fail to connect the user with the person they wanted to match with, mostly because users enter an incorrect or invalid username due to a combination of missing discriminator and incorrect casing. 150 | 151 | - Issues with ease of adding are addressed in the point above, however incorrect casing is irrelevant to Revolt as-is because Revolt's usernames are already case-insensitive and this will not change. 152 | 153 | If we look at the given example: 154 | 155 | > You meet someone IRL that you want to talk to on Discord, and they say “I’m Phibi Eight Nine Three Six!” You go home and add “phibi#8936” only to find out you added the wrong “Phibi” because your new friend’s username is actually “PhIBI#8936”. 156 | 157 | Revolt does not permit a registration of both "PhIBI" and "phibi". 158 | 159 | - > You want to use a common name like “Mike” or “Jane” but there are already 9,999 Mikes or Janes so you’re blocked from that name altogether. 160 | 161 | We are not restricted to just 4-digit discriminators in our implementation. 162 | 163 | - > You like to change your username a lot and get rate limited. 164 | 165 | If we were also to add more stringent rate limits, this may be solved by also including display names. 166 | 167 | - > Your friend says they changed their name to “vernacular” but actually it’s “𝖛𝖊𝖗𝖓𝖆𝖈𝖚𝖑𝖆𝖗” and you have trouble finding them. 168 | 169 | While this is a valid concern, I would personally put this down as the user's own issue. 170 | 171 | # Rationale and alternatives 172 | 173 | Discriminators (with display names and a restricted character set) appear to show the least disadvantages out of all of the solutions discussed so far. 174 | 175 | | Solution | Description | Users have desired username | Selling disincentivized | Privacy | Usability | Difficulty | 176 | | ----------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | :-------------------------: | :---------------------: | :-----: | :-------: | :--------: | 177 | | **Discriminators** | Proposed in this RFC | ✅ | ✅ | ✅ | ⚠️ | Low | 178 | | **Discriminators**
w/ display names | Show display names with greater priority to username / discriminator combinations.
\* May be proposed in this RFC | ✅ | ✅ | ✅ | ⚠️ | Low | 179 | | **Discriminators**
w/ display names
w/ restricted character set | Also restrict the characters that you can use in the username itself.
\* May be proposed in this RFC | ✅ | ✅ | ✅ | ✅ | Medium † | 180 | | Unique usernames | Current system on Revolt
(but any unicode username is allowed) | ❌ | ❌ | ❌ | ⚠️ | Low | 181 | | Unique usernames
w/ restricted character set | Alphanumeric unique global usernames | ❌ | ❌ | ❌ | ✅ | Medium † | 182 | | Unique usernames
w/ display names | Either unique username solution but with added display names that show instead of the username | ⚠️ | ❌ | ⚠️ | ✅ | Low | 183 | | Remove usernames altogether
(only display names) | Resort to using friend codes, invite links, and the like exclusively. | ✅ | ✅ | ✅ | ⚠️ | High ¶ | 184 | | Unique cryptographic user identifiers with display names | Resort to using friend codes, invite links, and the like exclusively. | ⚠️ | ✅ | ⚠️ | ⚠️ | Medium | 185 | 186 | In regards to this table, 187 | 188 | - Privacy means whether users can avoid being discovered based on their common names. 189 | - Usability is whether users can practically and quickly add each other. 190 | - † Restricting existing usernames further would potentially require some users to change username. 191 | - ¶ Removing usernames altogether would require a complete redesign of how friends work on Revolt. 192 | 193 | Discriminators also help solve a couple of issues with regards to username abandonment, users may sign up and: 194 | 195 | 1. Forget their account credentials or otherwise get locked out, and never recover their account. 196 | 2. Forget that their account even exists. 197 | 3. Decide they don't want to keep using their account but never delete it. 198 | 199 | Revolt does not currently automatically delete old accounts with no activity which is why this poses an issue. 200 | 201 | Given Revolt's current size, 4-digit numeric discriminators currently pose the least issues. 202 | 203 | | Solution | Example | Description | Usability | Quantity | Safe | 204 | | -------------- | :----------------: | --------------------------------------------- | :-------: | :------: | :--: | 205 | | 4-digit | `#1234` | Any 4 digits | ✅ | Low | ✅ | 206 | | N-digit | `#123456` | Any N digits | ⚠️ | Medium | ⚠️ | 207 | | Variable Digit | `#123` ... `#1234` | Scale between n and N digits depending on use | ⚠️ | Infinite | ⚠️ | 208 | | 4-hex | `#12AF` | Any 4 hex characters | ✅ | Medium | ⚠️ | 209 | | 4-char | `#1ABZ` | Any 4 alphanumeric characters | ❌ † | High | ❌ | 210 | 211 | In regards to this table: 212 | 213 | - Usability is whether the solution is practical, i.e. reasonably sized and simple. 214 | - Quantity is how many possible discriminators may be housed under one username. 215 | - Safe is whether the solution is not susceptible to generating undesired combinations and phrases. 216 | - † Allowing any alphanumeric characters may cause confusion between similar charactres using certain fonts, e.g. `O` and `0`. 217 | 218 | We also choose to restrict usernames to any Unicode alphabet rather than the full range given this has the best compromise between reasonable usernames, users affected, and localisation: 219 | 220 | | Permissible Format | Regex | Users affected by change | Supports regional dialects | Potential for abuse | 221 | | ------------------------------------------------- | :-----------------------------------: | :----------------------: | :------------------------: | ------------------- | 222 | | Alphanumeric | `^[a-zA-Z\d]+$` | 18% | ❌ | Low | 223 | | Any alphabet ¶ or digit | `^(\p{L} \| \d)+$` | 17% | ✅ | Medium ¶ | 224 | | Alphanumeric with special characters † | `^([a-zA-Z\d_.-])+$` | 11% | ❌ | Low | 225 | | Any alphabet ¶ or digit with special characters † | `^(\p{L} \| [\d_.-])+$` | 9% | ✅ | Medium ¶ | 226 | | Current format | `^[^\u200BА-Яа-яΑ-Ωα-ω@#:\n\r\[\]]+$` | 0% | ✅ | High | 227 | 228 | - † Special characters include underscore, period and dash. 229 | - ¶ Certain lookalike characters will continue to be blocked, such as those from the cyrillic alphabet. 230 | 231 | # Prior art 232 | 233 | This has been implemented before on other platforms: 234 | 235 | - Discord's discriminator system 236 | - Blizzard's [BattleTag system](https://us.battle.net/support/en/article/75767) 237 | 238 | # Unresolved questions 239 | 240 | No currently unresolved questions. 241 | 242 | # Security concerns 243 | 244 | This should not impact security, since this is almost entirely a cosmetic change to usernames. 245 | 246 | This should not have any adverse effects for functionality such as blocking users as this is entirely handled using internal IDs. 247 | 248 | # Future ideas 249 | 250 | As discussed previously, we may look into implementing: 251 | 252 | - Friend links / codes 253 | - Nearby find / QR friend codes / add by contact book 254 | - Add users by social connections 255 | - Global user search 256 | - Better friend flow UX 257 | 258 | We may also want to look into implementing additional privacy settings for adding users. 259 | 260 | As per [discussion comment](https://github.com/revoltchat/rfcs/pull/3#discussion_r1199818589), we may want to warn users that 261 | their username contains weird unicode or other characters that may look similar or weird, that may prevent them from adding 262 | other people on the platform. 263 | --------------------------------------------------------------------------------