Compare commits

..
23 Commits
Author SHA1 Message Date
Paul Makles e0b918771d chore: ensure restrict_reactions is used in conjunction with reactions list 2023-01-20 18:06:44 +00:00
Paul Makles 7a6bd70dcd feat: add route to fetch user flags
chore: bump rauth to change disabled account behaviour
2023-01-20 17:47:26 +00:00
Paul Makles c0ef3d295a fix: fallback if vergen cannot generate data 2023-01-20 17:14:25 +00:00
Paul Makles f5c95f9d12 chore: bump rauth for lockout reset on pwd reset 2023-01-20 15:57:58 +00:00
Paul Makles fed1da72fd feat: support rauth events
feat: add platform user wipe event
2023-01-20 15:43:45 +00:00
Paul Makles cf9c0bc5e1 chore: bump rauth 2023-01-20 14:00:19 +00:00
Paul Makles cc2054838a chore: swap okapi for revolt_okapi 2023-01-20 14:00:19 +00:00
Paul MaklesandTheBobBobs d9d2735efa fix(ratelimiter): re-calculate reset time
closes #204

Co-authored-by: TheBobBobs <84781603+TheBobBobs@users.noreply.github.com>
2023-01-18 18:26:00 +00:00
Ryan 94b0472934 feat: pass server flags with invite data (#203) 2023-01-18 18:17:59 +00:00
Sophie L 4a7917e9ea feat: enable reactions by default in servers/DMs 2023-01-18 18:17:37 +00:00
Lea ce6b454874 fix: raise masquerade avatar URL length limit 2023-01-18 18:17:05 +00:00
ToastXC fc32996b51 chore: remove clippy warnings (#213) 2023-01-18 18:16:27 +00:00
Paul Makles 32d3683013 fix(ci): re-order docker-compose arguments
chore(ci): prevent running gen on PR
2023-01-14 15:53:09 +00:00
Paul Makles 0cebb69e02 feat: automate generating OpenAPI specification 2023-01-14 15:42:30 +00:00
Paul Makles 117958d8cd feat: include build information in root api call 2023-01-14 15:42:06 +00:00
Paul Makles c5b823ad13 chore: clippy warnings 2023-01-03 21:06:43 +00:00
Paul Makles 27b4699299 fix: unify foreign user fetch into one method 2023-01-03 21:04:04 +00:00
Paul Makles ee1c4cc2d5 chore: bump quark
feat: update email templates to include recipient
2022-11-19 16:52:51 +00:00
Paul Makles 0e0daf86f7 feat: update emails to not look garbage 2022-10-23 21:23:29 +01:00
Paul Makles 572e08c733 chore: update rauth 2022-10-23 21:08:08 +01:00
Paul Makles 9011939344 chore: remove .env file 2022-10-23 20:55:45 +01:00
Paul Makles f4dcd091cc feat: add 'Focus' presence status 2022-09-18 12:12:31 +01:00
Paul Makles 86ad72b426 fix: strip unknown channels from categories (fixes #201) 2022-09-12 21:39:29 +01:00
64 changed files with 1062 additions and 479 deletions
-79
View File
@@ -1,79 +0,0 @@
# MongoDB URI
MONGODB=mongodb://localhost
# URL to where the Revolt app is publicly accessible
REVOLT_APP_URL=http://local.revolt.chat:5000
# URL to where the API is publicly accessible
REVOLT_PUBLIC_URL=http://local.revolt.chat:8000
VITE_API_URL=http://local.revolt.chat:8000
# URL to where the WebSocket server is publicly accessible
REVOLT_EXTERNAL_WS_URL=ws://local.revolt.chat:9000
# URL to where Autumn is publicly available
AUTUMN_PUBLIC_URL=http://local.revolt.chat:3000
# URL to where January is publicly available
JANUARY_PUBLIC_URL=http://local.revolt.chat:7000
# URL to where Vortex is publicly available
# VOSO_PUBLIC_URL=https://voso.revolt.chat
##
## hCaptcha Settings
##
# If you are sure that you don't want to use hCaptcha, set to 1.
REVOLT_UNSAFE_NO_CAPTCHA=1
# hCaptcha API key
# REVOLT_HCAPTCHA_KEY=0x0000000000000000000000000000000000000000
# hCaptcha site key
# REVOLT_HCAPTCHA_SITEKEY=10000000-ffff-ffff-ffff-000000000001
##
## Email Settings
##
# If you are sure that you don't want to use email verification, set to 1.
REVOLT_UNSAFE_NO_EMAIL=1
# SMTP host
# REVOLT_SMTP_HOST=smtp.example.com
# SMTP username
# REVOLT_SMTP_USERNAME=noreply@example.com
# SMTP password
# REVOLT_SMTP_PASSWORD=CHANGEME
# SMTP From header
# REVOLT_SMTP_FROM=Revolt <noreply@example.com>
##
## Application Settings
##
# Whether to only allow users to sign up if they have an invite code
REVOLT_INVITE_ONLY=0
# Maximum number of people that can be in a group chat
REVOLT_MAX_GROUP_SIZE=150
# VAPID keys for push notifications
# Generate using this guide: https://gitlab.insrt.uk/revolt/delta/-/wikis/vapid
# --> Please replace these keys before going into production! <--
REVOLT_VAPID_PRIVATE_KEY=LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUJSUWpyTWxLRnBiVWhsUHpUbERvcEliYk1yeVNrNXpKYzVYVzIxSjJDS3hvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFWnkrQkg2TGJQZ2hEa3pEempXOG0rUXVPM3pCajRXT1phdkR6ZU00c0pqbmFwd1psTFE0WAp1ZDh2TzVodU94QWhMQlU3WWRldVovWHlBdFpWZmNyQi9BPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=
REVOLT_VAPID_PUBLIC_KEY=BGcvgR-i2z4IQ5Mw841vJvkLjt8wY-FjmWrw83jOLCY52qcGZS0OF7nfLzuYbjsQISwVO2HXrmf18gLWVX3Kwfw=
##
## Vortex configuration
##
# VOSO_MANAGE_TOKEN=CHANGEME
+48 -6
View File
@@ -1,10 +1,10 @@
name: Rust build and test name: Rust build, test, and generate specification
on: on:
push: push:
branches: [ master ] branches: [master]
pull_request: pull_request:
branches: [ master ] branches: [master]
env: env:
CARGO_TERM_COLOR: always CARGO_TERM_COLOR: always
@@ -18,9 +18,9 @@ jobs:
- name: Install latest nightly - name: Install latest nightly
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: nightly toolchain: nightly
override: true override: true
components: rustfmt, clippy components: rustfmt, clippy
- name: Run cargo build - name: Run cargo build
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
@@ -31,3 +31,45 @@ jobs:
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: test command: test
- name: Copy .env.example
if: github.event_name != 'pull_request'
run: |
cp .env.example .env
- name: Run services in background
if: github.event_name != 'pull_request'
run: |
docker-compose -f docker-compose.db.yml up -d
- name: Start API in background
if: github.event_name != 'pull_request'
run: |
cargo run --bin revolt-delta &
- name: Wait for API to go up
if: github.event_name != 'pull_request'
uses: nev7n/wait_for_response@v1
with:
url: "http://localhost:8000/"
- name: Checkout API repository
if: github.event_name != 'pull_request'
uses: actions/checkout@v3
with:
repository: revoltchat/api
path: api
- name: Download OpenAPI specification
if: github.event_name != 'pull_request'
run: curl http://localhost:8000/openapi.json -o api/OpenAPI.json
- name: Commit changes
if: github.event_name != 'pull_request'
uses: EndBug/add-and-commit@v4
with:
cwd: "api"
add: "*.json"
message: "chore: generate OpenAPI specification"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+3
View File
@@ -1,3 +1,6 @@
Rocket.toml Rocket.toml
target target
.data .data
.env
.vercel
Generated
+220 -85
View File
@@ -81,6 +81,12 @@ dependencies = [
"winapi 0.3.9", "winapi 0.3.9",
] ]
[[package]]
name = "anyhow"
version = "1.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61"
[[package]] [[package]]
name = "arrayref" name = "arrayref"
version = "0.3.6" version = "0.3.6"
@@ -517,6 +523,9 @@ name = "cc"
version = "1.0.73" version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
dependencies = [
"jobserver",
]
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
@@ -606,7 +615,7 @@ dependencies = [
"rand 0.8.5", "rand 0.8.5",
"sha2", "sha2",
"subtle", "subtle",
"time 0.3.9", "time 0.3.17",
"version_check", "version_check",
] ]
@@ -875,6 +884,26 @@ dependencies = [
"syn 1.0.96", "syn 1.0.96",
] ]
[[package]]
name = "enum-iterator"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91a4ec26efacf4aeff80887a175a419493cb6f8b5480d26387eb0bd038976187"
dependencies = [
"enum-iterator-derive",
]
[[package]]
name = "enum-iterator-derive"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "828de45d0ca18782232dfb8f3ea9cc428e8ced380eb26a520baaacfc70de39ce"
dependencies = [
"proc-macro2",
"quote 1.0.18",
"syn 1.0.96",
]
[[package]] [[package]]
name = "env_logger" name = "env_logger"
version = "0.7.1" version = "0.7.1"
@@ -1138,6 +1167,18 @@ dependencies = [
"wasi 0.10.0+wasi-snapshot-preview1", "wasi 0.10.0+wasi-snapshot-preview1",
] ]
[[package]]
name = "getset"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e45727250e75cc04ff2846a66397da8ef2b3db8e40e0cef4df67950a07621eb9"
dependencies = [
"proc-macro-error",
"proc-macro2",
"quote 1.0.18",
"syn 1.0.96",
]
[[package]] [[package]]
name = "ghash" name = "ghash"
version = "0.4.4" version = "0.4.4"
@@ -1154,6 +1195,19 @@ version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
[[package]]
name = "git2"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2994bee4a3a6a51eb90c218523be382fd7ea09b16380b9312e9dbe955ff7c7d1"
dependencies = [
"bitflags",
"libc",
"libgit2-sys",
"log",
"url",
]
[[package]] [[package]]
name = "glob" name = "glob"
version = "0.3.0" version = "0.3.0"
@@ -1514,7 +1568,7 @@ dependencies = [
"generic-array 0.14.5", "generic-array 0.14.5",
"schemars", "schemars",
"serde", "serde",
"time 0.3.9", "time 0.3.17",
] ]
[[package]] [[package]]
@@ -1529,6 +1583,15 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
[[package]]
name = "jobserver"
version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.57" version = "0.3.57"
@@ -1590,6 +1653,30 @@ version = "0.2.126"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
[[package]]
name = "libgit2-sys"
version = "0.14.1+1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a07fb2692bc3593bda59de45a502bb3071659f2c515e28c71e728306b038e17"
dependencies = [
"cc",
"libc",
"libz-sys",
"pkg-config",
]
[[package]]
name = "libz-sys"
version = "1.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf"
dependencies = [
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]] [[package]]
name = "linked-hash-map" name = "linked-hash-map"
version = "0.5.4" version = "0.5.4"
@@ -1914,6 +2001,15 @@ dependencies = [
"minimal-lexical", "minimal-lexical",
] ]
[[package]]
name = "ntapi"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc51db7b362b205941f71232e56c625156eb9a929f8cf74a428fd5bc094a4afc"
dependencies = [
"winapi 0.3.9",
]
[[package]] [[package]]
name = "num-integer" name = "num-integer"
version = "0.1.45" version = "0.1.45"
@@ -1964,15 +2060,6 @@ dependencies = [
"syn 1.0.96", "syn 1.0.96",
] ]
[[package]]
name = "num_threads"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "object" name = "object"
version = "0.28.4" version = "0.28.4"
@@ -1982,17 +2069,6 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "okapi"
version = "0.7.0-rc.1"
source = "git+https://github.com/insertish/okapi?rev=a1048d0c8cd771e424ec97d33d825c32e06aa120#a1048d0c8cd771e424ec97d33d825c32e06aa120"
dependencies = [
"log",
"schemars",
"serde",
"serde_json",
]
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.13.0" version = "1.13.0"
@@ -2504,8 +2580,8 @@ dependencies = [
[[package]] [[package]]
name = "rauth" name = "rauth"
version = "1.0.0" version = "1.0.4"
source = "git+https://github.com/insertish/rauth?rev=9c3f9bb58a549a51546bd748274130ac4a667cb4#9c3f9bb58a549a51546bd748274130ac4a667cb4" source = "git+https://github.com/insertish/rauth?tag=1.0.4#2d3bc59623672e3ff57c49a90c4d3cd20780dbba"
dependencies = [ dependencies = [
"async-std", "async-std",
"async-trait", "async-trait",
@@ -2520,12 +2596,12 @@ dependencies = [
"log", "log",
"mongodb", "mongodb",
"nanoid", "nanoid",
"okapi",
"rand 0.8.5", "rand 0.8.5",
"regex", "regex",
"reqwest", "reqwest",
"revolt_okapi",
"revolt_rocket_okapi",
"rocket", "rocket",
"rocket_okapi",
"rust-argon2", "rust-argon2",
"schemars", "schemars",
"serde", "serde",
@@ -2714,7 +2790,7 @@ dependencies = [
[[package]] [[package]]
name = "revolt-bonfire" name = "revolt-bonfire"
version = "0.5.5" version = "0.5.6"
dependencies = [ dependencies = [
"async-std", "async-std",
"async-tungstenite", "async-tungstenite",
@@ -2730,7 +2806,7 @@ dependencies = [
[[package]] [[package]]
name = "revolt-delta" name = "revolt-delta"
version = "0.5.5" version = "0.5.6"
dependencies = [ dependencies = [
"async-channel", "async-channel",
"async-std", "async-std",
@@ -2755,9 +2831,9 @@ dependencies = [
"regex", "regex",
"reqwest", "reqwest",
"revolt-quark", "revolt-quark",
"revolt_rocket_okapi",
"rocket", "rocket",
"rocket_empty", "rocket_empty",
"rocket_okapi",
"rocket_rauth", "rocket_rauth",
"schemars", "schemars",
"serde", "serde",
@@ -2765,11 +2841,12 @@ dependencies = [
"ulid 0.4.1", "ulid 0.4.1",
"url", "url",
"validator 0.14.0", "validator 0.14.0",
"vergen",
] ]
[[package]] [[package]]
name = "revolt-quark" name = "revolt-quark"
version = "0.1.0" version = "0.5.6"
dependencies = [ dependencies = [
"async-recursion", "async-recursion",
"async-std", "async-std",
@@ -2792,7 +2869,6 @@ dependencies = [
"mongodb", "mongodb",
"nanoid", "nanoid",
"num_enum", "num_enum",
"okapi",
"once_cell", "once_cell",
"optional_struct", "optional_struct",
"pretty_env_logger", "pretty_env_logger",
@@ -2800,11 +2876,12 @@ dependencies = [
"redis-kiss", "redis-kiss",
"regex", "regex",
"reqwest", "reqwest",
"revolt_okapi",
"revolt_rocket_okapi",
"rocket", "rocket",
"rocket_cors", "rocket_cors",
"rocket_empty", "rocket_empty",
"rocket_http", "rocket_http",
"rocket_okapi",
"schemars", "schemars",
"sentry", "sentry",
"serde", "serde",
@@ -2814,6 +2891,47 @@ dependencies = [
"web-push", "web-push",
] ]
[[package]]
name = "revolt_okapi"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23bfdf7ae769c3042fe727f6e5c17363b02a64b4b33ad60c3e5f73b26df7835b"
dependencies = [
"log",
"schemars",
"serde",
"serde_json",
]
[[package]]
name = "revolt_rocket_okapi"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "275e1e9bd3343f75225cafa64f4bfb939c8b21c5f861141180fc0e24769ff6cf"
dependencies = [
"either",
"log",
"revolt_okapi",
"revolt_rocket_okapi_codegen",
"rocket",
"schemars",
"serde",
"serde_json",
]
[[package]]
name = "revolt_rocket_okapi_codegen"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc6620569d8ac8f0a1690fcca13f488503807a60e96ebf729749b59aca1dbef9"
dependencies = [
"darling",
"proc-macro2",
"quote 1.0.18",
"rocket_http",
"syn 1.0.96",
]
[[package]] [[package]]
name = "ring" name = "ring"
version = "0.16.20" version = "0.16.20"
@@ -2881,7 +2999,7 @@ dependencies = [
"serde_json", "serde_json",
"state", "state",
"tempfile", "tempfile",
"time 0.3.9", "time 0.3.17",
"tokio 1.18.2", "tokio 1.18.2",
"tokio-stream", "tokio-stream",
"tokio-util 0.7.2", "tokio-util 0.7.2",
@@ -2908,9 +3026,10 @@ dependencies = [
[[package]] [[package]]
name = "rocket_cors" name = "rocket_cors"
version = "0.5.2" version = "0.6.0-alpha1"
source = "git+https://github.com/lawliet89/rocket_cors?rev=5843861a88958c16bfaa0b40f0d8910772bcd2f6#5843861a88958c16bfaa0b40f0d8910772bcd2f6" source = "git+https://github.com/lawliet89/rocket_cors?rev=c17e8145baa4790319fdb6a473e465b960f55e7c#c17e8145baa4790319fdb6a473e465b960f55e7c"
dependencies = [ dependencies = [
"http",
"log", "log",
"regex", "regex",
"rocket", "rocket",
@@ -2923,12 +3042,13 @@ dependencies = [
[[package]] [[package]]
name = "rocket_empty" name = "rocket_empty"
version = "0.1.0" version = "0.1.1"
source = "git+https://github.com/insertish/rocket_empty?branch=master#9d8234fc3bb215ea241b787301e8cff68ae53652" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c0922e47f981204fee38578a8efcf47a5c1a4ac0eb7f59e6bdfa3e61c8e3d69"
dependencies = [ dependencies = [
"okapi", "revolt_okapi",
"revolt_rocket_okapi",
"rocket", "rocket",
"rocket_okapi",
] ]
[[package]] [[package]]
@@ -2953,48 +3073,22 @@ dependencies = [
"smallvec", "smallvec",
"stable-pattern", "stable-pattern",
"state", "state",
"time 0.3.9", "time 0.3.17",
"tokio 1.18.2", "tokio 1.18.2",
"uncased", "uncased",
] ]
[[package]]
name = "rocket_okapi"
version = "0.8.0-rc.1"
source = "git+https://github.com/insertish/okapi?rev=a1048d0c8cd771e424ec97d33d825c32e06aa120#a1048d0c8cd771e424ec97d33d825c32e06aa120"
dependencies = [
"either",
"log",
"okapi",
"rocket",
"rocket_okapi_codegen",
"schemars",
"serde",
"serde_json",
]
[[package]]
name = "rocket_okapi_codegen"
version = "0.8.0-rc.1"
source = "git+https://github.com/insertish/okapi?rev=a1048d0c8cd771e424ec97d33d825c32e06aa120#a1048d0c8cd771e424ec97d33d825c32e06aa120"
dependencies = [
"darling",
"proc-macro2",
"quote 1.0.18",
"rocket_http",
"syn 1.0.96",
]
[[package]] [[package]]
name = "rocket_rauth" name = "rocket_rauth"
version = "1.0.0" version = "1.0.4"
source = "git+https://github.com/insertish/rauth?rev=9c3f9bb58a549a51546bd748274130ac4a667cb4#9c3f9bb58a549a51546bd748274130ac4a667cb4" source = "git+https://github.com/insertish/rauth?tag=1.0.4#2d3bc59623672e3ff57c49a90c4d3cd20780dbba"
dependencies = [ dependencies = [
"okapi", "iso8601-timestamp",
"rauth", "rauth",
"revolt_okapi",
"revolt_rocket_okapi",
"rocket", "rocket",
"rocket_empty", "rocket_empty",
"rocket_okapi",
"schemars", "schemars",
"serde", "serde",
] ]
@@ -3068,9 +3162,9 @@ dependencies = [
[[package]] [[package]]
name = "rustversion" name = "rustversion"
version = "1.0.6" version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70"
[[package]] [[package]]
name = "ryu" name = "ryu"
@@ -3260,7 +3354,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"thiserror", "thiserror",
"time 0.3.9", "time 0.3.17",
"url", "url",
"uuid", "uuid",
] ]
@@ -3544,6 +3638,20 @@ dependencies = [
"unicode-xid 0.0.4", "unicode-xid 0.0.4",
] ]
[[package]]
name = "sysinfo"
version = "0.27.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c215311383d25d03753375c53ab9fad8fc0cf46953c409211e065edeabf577ee"
dependencies = [
"cfg-if 1.0.0",
"core-foundation-sys",
"libc",
"ntapi",
"once_cell",
"winapi 0.3.9",
]
[[package]] [[package]]
name = "take_mut" name = "take_mut"
version = "0.2.2" version = "0.2.2"
@@ -3575,18 +3683,18 @@ dependencies = [
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.31" version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.31" version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote 1.0.18", "quote 1.0.18",
@@ -3615,21 +3723,30 @@ dependencies = [
[[package]] [[package]]
name = "time" name = "time"
version = "0.3.9" version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd" checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376"
dependencies = [ dependencies = [
"itoa 1.0.2", "itoa 1.0.2",
"libc", "serde",
"num_threads", "time-core",
"time-macros", "time-macros",
] ]
[[package]] [[package]]
name = "time-macros" name = "time-core"
version = "0.2.4" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd"
[[package]]
name = "time-macros"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2"
dependencies = [
"time-core",
]
[[package]] [[package]]
name = "tinyvec" name = "tinyvec"
@@ -4203,6 +4320,24 @@ version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "vergen"
version = "7.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "571b69f690c855821462709b6f41d42ceccc316fbd17b60bd06d06928cfe6a99"
dependencies = [
"anyhow",
"cfg-if 1.0.0",
"enum-iterator",
"getset",
"git2",
"rustc_version 0.4.0",
"rustversion",
"sysinfo",
"thiserror",
"time 0.3.17",
]
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.4" version = "0.9.4"
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "revolt-bonfire" name = "revolt-bonfire"
version = "0.5.5" version = "0.5.6"
license = "AGPL-3.0-or-later" license = "AGPL-3.0-or-later"
edition = "2021" edition = "2021"
+7 -5
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "revolt-delta" name = "revolt-delta"
version = "0.5.5" version = "0.5.6"
license = "AGPL-3.0-or-later" license = "AGPL-3.0-or-later"
authors = ["Paul Makles <paulmakles@gmail.com>"] authors = ["Paul Makles <paulmakles@gmail.com>"]
edition = "2018" edition = "2018"
@@ -51,13 +51,15 @@ mobc-redis = { version = "0.7.0", default-features = false, features = ["async-s
# web # web
rocket = { version = "0.5.0-rc.2", default-features = false, features = ["json"] } rocket = { version = "0.5.0-rc.2", default-features = false, features = ["json"] }
rocket_empty = { git = "https://github.com/insertish/rocket_empty", branch = "master" } rocket_empty = { version = "0.1.1", features = ["schema"] }
rocket_rauth = { git = "https://github.com/insertish/rauth", rev = "9c3f9bb58a549a51546bd748274130ac4a667cb4" } rocket_rauth = { git = "https://github.com/insertish/rauth", tag = "1.0.4" }
# spec generation # spec generation
schemars = "0.8.8" schemars = "0.8.8"
# rocket_okapi = "0.8.0-rc.1" revolt_rocket_okapi = { version = "0.9.1", features = [ "swagger" ] }
rocket_okapi = { git = "https://github.com/insertish/okapi", rev = "a1048d0c8cd771e424ec97d33d825c32e06aa120", features = [ "swagger" ] }
# quark # quark
revolt-quark = { path = "../quark" } revolt-quark = { path = "../quark" }
[build-dependencies]
vergen = "7.5.0"
+16
View File
@@ -0,0 +1,16 @@
use vergen::{vergen, Config};
use std::process::Command;
fn main() {
if let Ok(output) = Command::new("git")
.args(["config", "--get", "remote.origin.url"])
.output()
{
if let Ok(git_origin) = String::from_utf8(output.stdout) {
println!("cargo:rustc-env=GIT_ORIGIN_URL={}", git_origin);
}
}
vergen(Config::default()).ok();
}
+25 -3
View File
@@ -1,7 +1,7 @@
#[macro_use] #[macro_use]
extern crate rocket; extern crate rocket;
#[macro_use] #[macro_use]
extern crate rocket_okapi; extern crate revolt_rocket_okapi;
#[macro_use] #[macro_use]
extern crate serde_json; extern crate serde_json;
#[macro_use] #[macro_use]
@@ -10,7 +10,9 @@ extern crate lazy_static;
pub mod routes; pub mod routes;
pub mod util; pub mod util;
use revolt_quark::rauth::RAuth; use async_std::channel::unbounded;
use revolt_quark::events::client::EventV1;
use revolt_quark::rauth::{RAuth, RAuthEvent};
use revolt_quark::DatabaseInfo; use revolt_quark::DatabaseInfo;
#[launch] #[launch]
@@ -25,13 +27,33 @@ async fn rocket() -> _ {
let db = DatabaseInfo::Auto.connect().await.unwrap(); let db = DatabaseInfo::Auto.connect().await.unwrap();
db.migrate_database().await.unwrap(); db.migrate_database().await.unwrap();
// Setup rAuth event channel
let (sender, receiver) = unbounded();
// Setup rAuth // Setup rAuth
let rauth = RAuth { let rauth = RAuth {
database: db.clone().into(), database: db.clone().into(),
config: revolt_quark::util::rauth::config(), config: revolt_quark::util::rauth::config(),
event_channel: Some(sender),
}; };
// Launch background task workers. // Launch a listener for rAuth events
async_std::task::spawn(async move {
while let Ok(event) = receiver.recv().await {
match &event {
RAuthEvent::CreateSession { .. } | RAuthEvent::CreateAccount { .. } => {
EventV1::Auth(event).global().await
}
RAuthEvent::DeleteSession { user_id, .. }
| RAuthEvent::DeleteAllSessions { user_id, .. } => {
let id = user_id.to_string();
EventV1::Auth(event).private(id).await
}
}
}
});
// Launch background task workers
async_std::task::spawn(revolt_quark::tasks::start_workers(db.clone())); async_std::task::spawn(revolt_quark::tasks::start_workers(db.clone()));
// Configure CORS // Configure CORS
+1 -1
View File
@@ -1,5 +1,5 @@
use revolt_rocket_okapi::revolt_okapi::openapi3::OpenApi;
use rocket::Route; use rocket::Route;
use rocket_okapi::okapi::openapi3::OpenApi;
mod create; mod create;
mod delete; mod delete;
@@ -65,16 +65,20 @@ pub async fn message_send(
data.validate() data.validate()
.map_err(|error| Error::FailedValidation { error })?; .map_err(|error| Error::FailedValidation { error })?;
// Validate Message is within reasonable length limits
Message::validate_sum(&data.content, &data.embeds)?; Message::validate_sum(&data.content, &data.embeds)?;
// Ensure the request is unique
idempotency.consume_nonce(data.nonce).await?; idempotency.consume_nonce(data.nonce).await?;
// Ensure we have permissions to send a message
let channel = target.as_channel(db).await?; let channel = target.as_channel(db).await?;
let mut permissions = perms(&user).channel(&channel); let mut permissions = perms(&user).channel(&channel);
permissions permissions
.throw_permission_and_view_channel(db, Permission::SendMessage) .throw_permission_and_view_channel(db, Permission::SendMessage)
.await?; .await?;
// Check the message is not empty
if (data.content.as_ref().map_or(true, |v| v.is_empty())) if (data.content.as_ref().map_or(true, |v| v.is_empty()))
&& (data.attachments.as_ref().map_or(true, |v| v.is_empty())) && (data.attachments.as_ref().map_or(true, |v| v.is_empty()))
&& (data.embeds.as_ref().map_or(true, |v| v.is_empty())) && (data.embeds.as_ref().map_or(true, |v| v.is_empty()))
@@ -82,6 +86,22 @@ pub async fn message_send(
return Err(Error::EmptyMessage); return Err(Error::EmptyMessage);
} }
// Ensure restrict_reactions is not specified without reactions list
if let Some(interactions) = &data.interactions {
if interactions.restrict_reactions {
let disallowed = if let Some(list) = &interactions.reactions {
list.len() == 0
} else {
true
};
if disallowed {
return Err(Error::InvalidProperty);
}
}
}
// Start constructing the message
let message_id = Ulid::new().to_string(); let message_id = Ulid::new().to_string();
let mut message = Message { let mut message = Message {
id: message_id.clone(), id: message_id.clone(),
+1 -1
View File
@@ -1,5 +1,5 @@
use revolt_rocket_okapi::revolt_okapi::openapi3::OpenApi;
use rocket::Route; use rocket::Route;
use rocket_okapi::okapi::openapi3::OpenApi;
mod channel_ack; mod channel_ack;
mod channel_delete; mod channel_delete;
+1 -1
View File
@@ -1,5 +1,5 @@
use revolt_rocket_okapi::revolt_okapi::openapi3::OpenApi;
use rocket::Route; use rocket::Route;
use rocket_okapi::okapi::openapi3::OpenApi;
mod emoji_create; mod emoji_create;
mod emoji_delete; mod emoji_delete;
@@ -23,6 +23,9 @@ pub enum InviteResponse {
/// Attachment for server banner /// Attachment for server banner
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
server_banner: Option<File>, server_banner: Option<File>,
/// Enum of server flags
#[serde(skip_serializing_if = "Option::is_none")]
server_flags: Option<i32>,
/// Id of server channel /// Id of server channel
channel_id: String, channel_id: String,
/// Name of server channel /// Name of server channel
@@ -94,6 +97,7 @@ pub async fn req(db: &Db, target: Ref) -> Result<Json<InviteResponse>> {
server_name: server.name, server_name: server.name,
server_icon: server.icon, server_icon: server.icon,
server_banner: server.banner, server_banner: server.banner,
server_flags: server.flags,
channel_id: id, channel_id: id,
channel_name: name, channel_name: name,
channel_description: description, channel_description: description,
+1 -1
View File
@@ -1,5 +1,5 @@
use revolt_rocket_okapi::revolt_okapi::openapi3::OpenApi;
use rocket::Route; use rocket::Route;
use rocket_okapi::okapi::openapi3::OpenApi;
mod invite_delete; mod invite_delete;
mod invite_fetch; mod invite_fetch;
+2 -2
View File
@@ -1,7 +1,7 @@
use revolt_rocket_okapi::{revolt_okapi::openapi3::OpenApi, settings::OpenApiSettings};
pub use rocket::http::Status; pub use rocket::http::Status;
pub use rocket::response::Redirect; pub use rocket::response::Redirect;
use rocket::{Build, Rocket}; use rocket::{Build, Rocket};
use rocket_okapi::{okapi::openapi3::OpenApi, settings::OpenApiSettings};
mod bots; mod bots;
mod channels; mod channels;
@@ -39,7 +39,7 @@ pub fn mount(mut rocket: Rocket<Build>) -> Rocket<Build> {
} }
fn custom_openapi_spec() -> OpenApi { fn custom_openapi_spec() -> OpenApi {
use rocket_okapi::okapi::openapi3::*; use revolt_rocket_okapi::revolt_okapi::openapi3::*;
let mut extensions = schemars::Map::new(); let mut extensions = schemars::Map::new();
extensions.insert( extensions.insert(
+1 -1
View File
@@ -1,5 +1,5 @@
use revolt_rocket_okapi::revolt_okapi::openapi3::OpenApi;
use rocket::Route; use rocket::Route;
use rocket_okapi::okapi::openapi3::OpenApi;
mod complete; mod complete;
mod hello; mod hello;
+1 -1
View File
@@ -1,5 +1,5 @@
use revolt_rocket_okapi::revolt_okapi::openapi3::OpenApi;
use rocket::Route; use rocket::Route;
use rocket_okapi::okapi::openapi3::OpenApi;
mod subscribe; mod subscribe;
mod unsubscribe; mod unsubscribe;
+1 -1
View File
@@ -22,7 +22,7 @@ pub async fn req(
) -> Result<EmptyResponse> { ) -> Result<EmptyResponse> {
session.subscription = Some(data.into_inner()); session.subscription = Some(data.into_inner());
session session
.save(&rauth) .save(rauth)
.await .await
.map(|_| EmptyResponse) .map(|_| EmptyResponse)
.map_err(|_| Error::DatabaseError { .map_err(|_| Error::DatabaseError {
+1 -1
View File
@@ -13,7 +13,7 @@ use rocket::State;
pub async fn req(rauth: &State<RAuth>, mut session: Session) -> Result<EmptyResponse> { pub async fn req(rauth: &State<RAuth>, mut session: Session) -> Result<EmptyResponse> {
session.subscription = None; session.subscription = None;
session session
.save(&rauth) .save(rauth)
.await .await
.map(|_| EmptyResponse) .map(|_| EmptyResponse)
.map_err(|_| Error::DatabaseError { .map_err(|_| Error::DatabaseError {
+25
View File
@@ -54,6 +54,21 @@ pub struct RevoltFeatures {
pub voso: VoiceFeature, pub voso: VoiceFeature,
} }
/// # Build Information
#[derive(Serialize, JsonSchema, Debug)]
pub struct BuildInformation {
/// Commit Hash
pub commit_sha: String,
/// Commit Timestamp
pub commit_timestamp: String,
/// Git Semver
pub semver: String,
/// Git Origin URL
pub origin_url: String,
/// Build Timestamp
pub timestamp: String,
}
/// # Server Configuration /// # Server Configuration
#[derive(Serialize, JsonSchema, Debug)] #[derive(Serialize, JsonSchema, Debug)]
pub struct RevoltConfig { pub struct RevoltConfig {
@@ -67,6 +82,8 @@ pub struct RevoltConfig {
pub app: String, pub app: String,
/// Web Push VAPID public key /// Web Push VAPID public key
pub vapid: String, pub vapid: String,
/// Build information
pub build: BuildInformation,
} }
/// # Query Node /// # Query Node
@@ -101,6 +118,14 @@ pub async fn root() -> Result<Json<RevoltConfig>> {
ws: EXTERNAL_WS_URL.to_string(), ws: EXTERNAL_WS_URL.to_string(),
app: APP_URL.to_string(), app: APP_URL.to_string(),
vapid: VAPID_PUBLIC_KEY.to_string(), vapid: VAPID_PUBLIC_KEY.to_string(),
build: BuildInformation {
commit_sha: env!("VERGEN_GIT_SHA", "<failed to generate>").to_string(),
commit_timestamp: env!("VERGEN_GIT_COMMIT_TIMESTAMP", "<failed to generate>")
.to_string(),
semver: env!("VERGEN_GIT_SEMVER", "<failed to generate>").to_string(),
origin_url: env!("GIT_ORIGIN_URL", "<failed to generate>").to_string(),
timestamp: env!("VERGEN_BUILD_TIMESTAMP", "<failed to generate>").to_string(),
},
})) }))
} }
@@ -1,8 +1,6 @@
use revolt_quark::{ use revolt_quark::{
models::{Member, User}, models::{Member, User},
perms, perms, Db, Ref, Result,
presence::presence_filter_online,
Db, Ref, Result,
}; };
use rocket::serde::json::Json; use rocket::serde::json::Json;
@@ -47,16 +45,7 @@ pub async fn req(
user_ids.push(member.id.user.clone()); user_ids.push(member.id.user.clone());
} }
let online_ids = presence_filter_online(&user_ids).await; let mut users = User::fetch_foreign_users(db, &user_ids).await?;
let mut users = db
.fetch_users(&user_ids)
.await?
.into_iter()
.map(|mut user| {
user.online = Some(online_ids.contains(&user.id));
user.foreign()
})
.collect::<Vec<User>>();
// Ensure the lists match up exactly. // Ensure the lists match up exactly.
members.sort_by(|a, b| a.id.user.cmp(&b.id.user)); members.sort_by(|a, b| a.id.user.cmp(&b.id.user));
+1 -1
View File
@@ -1,5 +1,5 @@
use revolt_rocket_okapi::revolt_okapi::openapi3::OpenApi;
use rocket::Route; use rocket::Route;
use rocket_okapi::okapi::openapi3::OpenApi;
mod ban_create; mod ban_create;
mod ban_list; mod ban_list;
+10 -9
View File
@@ -138,12 +138,15 @@ pub async fn req(
} }
// 2. Validate changes // 2. Validate changes
let mut unknown_channels = HashSet::new();
if let Some(system_messages) = &partial.system_messages { if let Some(system_messages) = &partial.system_messages {
unknown_channels = system_messages.clone().into_channel_ids(); for id in system_messages.clone().into_channel_ids() {
if !server.channels.contains(&id) {
return Err(Error::NotFound);
}
}
} }
if let Some(categories) = &partial.categories { if let Some(categories) = &mut partial.categories {
let mut channel_ids = HashSet::new(); let mut channel_ids = HashSet::new();
for category in categories { for category in categories {
for channel in &category.channels { for channel in &category.channels {
@@ -153,13 +156,11 @@ pub async fn req(
channel_ids.insert(channel.to_string()); channel_ids.insert(channel.to_string());
} }
category
.channels
.retain(|item| server.channels.contains(item));
} }
unknown_channels.extend(channel_ids);
}
if !db.check_channels_exist(&unknown_channels).await? {
return Err(Error::NotFound);
} }
// 3. Apply new icon // 3. Apply new icon
+1 -1
View File
@@ -1,5 +1,5 @@
use revolt_rocket_okapi::revolt_okapi::openapi3::OpenApi;
use rocket::Route; use rocket::Route;
use rocket_okapi::okapi::openapi3::OpenApi;
mod get_settings; mod get_settings;
mod get_unreads; mod get_unreads;
@@ -0,0 +1,26 @@
use revolt_quark::{Database, Ref, Result};
use rocket::{serde::json::Json, State};
use serde::Serialize;
/// # Flag Response
#[derive(Serialize, JsonSchema)]
pub struct FlagResponse {
/// Flags
flags: i32,
}
/// # Fetch User Flags
///
/// Retrieve a user's flags.
#[openapi(tag = "User Information")]
#[get("/<target>/flags")]
pub async fn fetch_user_flags(db: &State<Database>, target: Ref) -> Result<Json<FlagResponse>> {
let flags = if let Ok(target) = target.as_user(db).await {
target.flags.unwrap_or_default()
} else {
0
};
Ok(Json(FlagResponse { flags }))
}
@@ -1,7 +1,7 @@
use revolt_rocket_okapi::revolt_okapi::openapi3::{self, MediaType, RefOr};
use rocket::http::ContentType; use rocket::http::ContentType;
use rocket::response::{self, Responder}; use rocket::response::{self, Responder};
use rocket::{Request, Response}; use rocket::{Request, Response};
use rocket_okapi::okapi::openapi3::{self, MediaType, RefOr};
use schemars::schema::{InstanceType, SchemaObject, SingleOrVec}; use schemars::schema::{InstanceType, SchemaObject, SingleOrVec};
pub struct CachedFile((ContentType, Vec<u8>)); pub struct CachedFile((ContentType, Vec<u8>));
@@ -16,10 +16,10 @@ impl<'r> Responder<'r, 'static> for CachedFile {
} }
} }
impl rocket_okapi::response::OpenApiResponderInner for CachedFile { impl revolt_rocket_okapi::response::OpenApiResponderInner for CachedFile {
fn responses( fn responses(
_gen: &mut rocket_okapi::gen::OpenApiGenerator, _gen: &mut revolt_rocket_okapi::gen::OpenApiGenerator,
) -> std::result::Result<openapi3::Responses, rocket_okapi::OpenApiError> { ) -> std::result::Result<openapi3::Responses, revolt_rocket_okapi::OpenApiError> {
let mut responses = schemars::Map::new(); let mut responses = schemars::Map::new();
let mut content = schemars::Map::new(); let mut content = schemars::Map::new();
+3 -1
View File
@@ -1,5 +1,5 @@
use revolt_rocket_okapi::revolt_okapi::openapi3::OpenApi;
use rocket::Route; use rocket::Route;
use rocket_okapi::okapi::openapi3::OpenApi;
mod add_friend; mod add_friend;
mod block_user; mod block_user;
@@ -9,6 +9,7 @@ mod fetch_dms;
mod fetch_profile; mod fetch_profile;
mod fetch_self; mod fetch_self;
mod fetch_user; mod fetch_user;
mod fetch_user_flags;
mod find_mutual; mod find_mutual;
mod get_default_avatar; mod get_default_avatar;
mod open_dm; mod open_dm;
@@ -21,6 +22,7 @@ pub fn routes() -> (Vec<Route>, OpenApi) {
// User Information // User Information
fetch_self::req, fetch_self::req,
fetch_user::req, fetch_user::req,
fetch_user_flags::fetch_user_flags,
edit_user::req, edit_user::req,
change_username::req, change_username::req,
get_default_avatar::req, get_default_avatar::req,
+6 -8
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "revolt-quark" name = "revolt-quark"
version = "0.1.0" version = "0.5.6"
license = "AGPL-3.0-or-later" license = "AGPL-3.0-or-later"
edition = "2021" edition = "2021"
@@ -38,10 +38,8 @@ bson = { version = "2.1.0", features = ["chrono-0_4"] }
# Spec Generation # Spec Generation
schemars = "0.8.8" schemars = "0.8.8"
okapi = { git = "https://github.com/insertish/okapi", rev = "a1048d0c8cd771e424ec97d33d825c32e06aa120" } revolt_okapi = "0.9.1"
rocket_okapi = { git = "https://github.com/insertish/okapi", rev = "a1048d0c8cd771e424ec97d33d825c32e06aa120" } revolt_rocket_okapi = { version = "0.9.1", features = [ "swagger" ] }
# okapi = "0.7.0-rc.1"
# rocket_okapi = "0.8.0-rc.1"
# Databases # Databases
redis-kiss = { version = "0.1.3" } redis-kiss = { version = "0.1.3" }
@@ -82,11 +80,11 @@ web-push = "0.7.2"
# Implementations # Implementations
rocket_http = { optional = true, version = "0.5.0-rc.2" } rocket_http = { optional = true, version = "0.5.0-rc.2" }
rocket = { optional = true, version = "0.5.0-rc.2", default-features = false, features = ["json"] } rocket = { optional = true, version = "0.5.0-rc.2", default-features = false, features = ["json"] }
rocket_empty = { optional = true, git = "https://github.com/insertish/rocket_empty", branch = "master" } rocket_empty = { version = "0.1.1", optional = true, features = [ "schema" ] }
rocket_cors = { optional = true, git = "https://github.com/lawliet89/rocket_cors", rev = "5843861a88958c16bfaa0b40f0d8910772bcd2f6" } rocket_cors = { optional = true, git = "https://github.com/lawliet89/rocket_cors", rev = "c17e8145baa4790319fdb6a473e465b960f55e7c" }
# rAuth # rAuth
rauth = { git = "https://github.com/insertish/rauth", rev = "9c3f9bb58a549a51546bd748274130ac4a667cb4", features = [ "async-std-runtime" ] } rauth = { git = "https://github.com/insertish/rauth", tag = "1.0.4", features = [ "async-std-runtime" ] }
# Sentry # Sentry
sentry = "0.25.0" sentry = "0.25.0"
+138
View File
@@ -0,0 +1,138 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<!-- Compiled with Bootstrap Email version: 1.3.1 --><meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="x-apple-disable-message-reformatting">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="format-detection" content="telephone=no, date=no, address=no, email=no">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
body,table,td{font-family:Helvetica,Arial,sans-serif !important}.ExternalClass{width:100%}.ExternalClass,.ExternalClass p,.ExternalClass span,.ExternalClass font,.ExternalClass td,.ExternalClass div{line-height:150%}a{text-decoration:none}*{color:inherit}a[x-apple-data-detectors],u+#body a,#MessageViewBody a{color:inherit;text-decoration:none;font-size:inherit;font-family:inherit;font-weight:inherit;line-height:inherit}img{-ms-interpolation-mode:bicubic}table:not([class^=s-]){font-family:Helvetica,Arial,sans-serif;mso-table-lspace:0pt;mso-table-rspace:0pt;border-spacing:0px;border-collapse:collapse}table:not([class^=s-]) td{border-spacing:0px;border-collapse:collapse}@media screen and (max-width: 600px){.w-full,.w-full>tbody>tr>td{width:100% !important}.w-24,.w-24>tbody>tr>td{width:96px !important}.p-lg-10:not(table),.p-lg-10:not(.btn)>tbody>tr>td,.p-lg-10.btn td a{padding:0 !important}.p-3:not(table),.p-3:not(.btn)>tbody>tr>td,.p-3.btn td a{padding:12px !important}.p-6:not(table),.p-6:not(.btn)>tbody>tr>td,.p-6.btn td a{padding:24px !important}*[class*=s-lg-]>tbody>tr>td{font-size:0 !important;line-height:0 !important;height:0 !important}.s-4>tbody>tr>td{font-size:16px !important;line-height:16px !important;height:16px !important}.s-6>tbody>tr>td{font-size:24px !important;line-height:24px !important;height:24px !important}.s-10>tbody>tr>td{font-size:40px !important;line-height:40px !important;height:40px !important}}
</style>
</head>
<body class="bg-light" style="outline: 0; width: 100%; min-width: 100%; height: 100%; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; font-family: Helvetica, Arial, sans-serif; line-height: 24px; font-weight: normal; font-size: 16px; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; color: #000000; margin: 0; padding: 0; border-width: 0;" bgcolor="#f7fafc">
<table class="bg-light body" valign="top" role="presentation" border="0" cellpadding="0" cellspacing="0" style="outline: 0; width: 100%; min-width: 100%; height: 100%; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; font-family: Helvetica, Arial, sans-serif; line-height: 24px; font-weight: normal; font-size: 16px; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; color: #000000; margin: 0; padding: 0; border-width: 0;" bgcolor="#f7fafc">
<tbody>
<tr>
<td valign="top" style="line-height: 24px; font-size: 16px; margin: 0;" align="left" bgcolor="#f7fafc">
<table class="container" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;">
<tbody>
<tr>
<td align="center" style="line-height: 24px; font-size: 16px; margin: 0; padding: 0 16px;">
<!--[if (gte mso 9)|(IE)]>
<table align="center" role="presentation">
<tbody>
<tr>
<td width="600">
<![endif]-->
<table align="center" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%; max-width: 600px; margin: 0 auto;">
<tbody>
<tr>
<td style="line-height: 24px; font-size: 16px; margin: 0;" align="left">
<table class="s-10 w-full" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;" width="100%">
<tbody>
<tr>
<td style="line-height: 40px; font-size: 40px; width: 100%; height: 40px; margin: 0;" align="left" width="100%" height="40">
&#160;
</td>
</tr>
</tbody>
</table>
<table class="ax-center" role="presentation" align="center" border="0" cellpadding="0" cellspacing="0" style="margin: 0 auto;">
<tbody>
<tr>
<td style="line-height: 24px; font-size: 16px; margin: 0;" align="left">
<img alt="Revolt Logo" class="w-24" src="https://app.revolt.chat/assets/logo_round.png" style="height: auto; line-height: 100%; outline: none; text-decoration: none; display: block; width: 96px; border-style: none; border-width: 0;" width="96">
</td>
</tr>
</tbody>
</table>
<table class="s-10 w-full" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;" width="100%">
<tbody>
<tr>
<td style="line-height: 40px; font-size: 40px; width: 100%; height: 40px; margin: 0;" align="left" width="100%" height="40">
&#160;
</td>
</tr>
</tbody>
</table>
<table class="card p-6 p-lg-10 space-y-4" role="presentation" border="0" cellpadding="0" cellspacing="0" style="border-radius: 6px; border-collapse: separate !important; width: 100%; overflow: hidden; border: 1px solid #e2e8f0;" bgcolor="#ffffff">
<tbody>
<tr>
<td style="line-height: 24px; font-size: 16px; width: 100%; margin: 0; padding: 40px;" align="left" bgcolor="#ffffff">
<h1 class="h3 fw-700" style="padding-top: 0; padding-bottom: 0; font-weight: 700 !important; vertical-align: baseline; font-size: 28px; line-height: 33.6px; margin: 0;" align="left">Account Deletion</h1>
<table class="s-4 w-full" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;" width="100%">
<tbody>
<tr>
<td style="line-height: 16px; font-size: 16px; width: 100%; height: 16px; margin: 0;" align="left" width="100%" height="16">
&#160;
</td>
</tr>
</tbody>
</table>
<p class="" style="line-height: 24px; font-size: 16px; width: 100%; margin: 0;" align="left">You requested to have your account deleted, if you did not perform this action please take measures to secure your account immediately.</p>
<table class="s-4 w-full" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;" width="100%">
<tbody>
<tr>
<td style="line-height: 16px; font-size: 16px; width: 100%; height: 16px; margin: 0;" align="left" width="100%" height="16">
&#160;
</td>
</tr>
</tbody>
</table>
<table class="btn btn-primary p-3 fw-700" role="presentation" border="0" cellpadding="0" cellspacing="0" style="border-radius: 6px; border-collapse: separate !important; font-weight: 700 !important;">
<tbody>
<tr>
<td style="line-height: 24px; font-size: 16px; border-radius: 6px; font-weight: 700 !important; margin: 0;" align="center" bgcolor="#0d6efd">
<a href="{{url}}" style="color: #ffffff; font-size: 16px; font-family: Helvetica, Arial, sans-serif; text-decoration: none; border-radius: 6px; line-height: 20px; display: block; font-weight: 700 !important; white-space: nowrap; background-color: #0d6efd; padding: 12px; border: 1px solid #0d6efd;">Confirm</a>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<table class="s-6 w-full" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;" width="100%">
<tbody>
<tr>
<td style="line-height: 24px; font-size: 24px; width: 100%; height: 24px; margin: 0;" align="left" width="100%" height="24">
&#160;
</td>
</tr>
</tbody>
</table>
<div class="text-muted text-center" style="color: #718096;" align="center">
This email is intended for {{email}}<br>
Sent from Revolt<br>
Made in the EU
</div>
<table class="s-6 w-full" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;" width="100%">
<tbody>
<tr>
<td style="line-height: 24px; font-size: 24px; width: 100%; height: 24px; margin: 0;" align="left" width="100%" height="24">
&#160;
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<!--[if (gte mso 9)|(IE)]>
</td>
</tr>
</tbody>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</body>
</html>
@@ -0,0 +1,30 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
/* Add custom classes and styles that you want inlined here */
</style>
</head>
<body class="bg-light">
<div class="container">
<img
alt="Revolt Logo"
class="ax-center my-10 w-24"
src="https://app.revolt.chat/assets/logo_round.png"
/>
<div class="card p-6 p-lg-10 space-y-4">
<h1 class="h3 fw-700">Account Deletion</h1>
<p>
You requested to have your account deleted, if you did not perform
this action please take measures to secure your account immediately.
</p>
<a class="btn btn-primary p-3 fw-700" href="{{url}}">Confirm</a>
</div>
<div class="text-muted text-center my-6">
This email is intended for {{email}}<br />
Sent from Revolt<br />
Made in the EU
</div>
</div>
</body>
</html>
+4 -2
View File
@@ -1,5 +1,7 @@
You requested to have your account deleted, if you did not perform this action please take measures to secure your account immediately. You requested to have your account deleted, if you did not perform this action please take measures to secure your account immediately.
Confirm here: {{url}} Please navigate to: {{url}}
Sent by Revolt. This email is intended for {{email}}
Sent by Revolt
Made in the EU
+137 -62
View File
@@ -1,63 +1,138 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-GB"> <html>
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <!-- Compiled with Bootstrap Email version: 1.3.1 --><meta http-equiv="x-ua-compatible" content="ie=edge">
<title>Reset your password.</title> <meta name="x-apple-disable-message-reformatting">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="format-detection" content="telephone=no, date=no, address=no, email=no">
<style type="text/css"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
a[x-apple-data-detectors] {color: inherit !important;} <style type="text/css">
</style> body,table,td{font-family:Helvetica,Arial,sans-serif !important}.ExternalClass{width:100%}.ExternalClass,.ExternalClass p,.ExternalClass span,.ExternalClass font,.ExternalClass td,.ExternalClass div{line-height:150%}a{text-decoration:none}*{color:inherit}a[x-apple-data-detectors],u+#body a,#MessageViewBody a{color:inherit;text-decoration:none;font-size:inherit;font-family:inherit;font-weight:inherit;line-height:inherit}img{-ms-interpolation-mode:bicubic}table:not([class^=s-]){font-family:Helvetica,Arial,sans-serif;mso-table-lspace:0pt;mso-table-rspace:0pt;border-spacing:0px;border-collapse:collapse}table:not([class^=s-]) td{border-spacing:0px;border-collapse:collapse}@media screen and (max-width: 600px){.w-full,.w-full>tbody>tr>td{width:100% !important}.w-24,.w-24>tbody>tr>td{width:96px !important}.p-lg-10:not(table),.p-lg-10:not(.btn)>tbody>tr>td,.p-lg-10.btn td a{padding:0 !important}.p-3:not(table),.p-3:not(.btn)>tbody>tr>td,.p-3.btn td a{padding:12px !important}.p-6:not(table),.p-6:not(.btn)>tbody>tr>td,.p-6.btn td a{padding:24px !important}*[class*=s-lg-]>tbody>tr>td{font-size:0 !important;line-height:0 !important;height:0 !important}.s-4>tbody>tr>td{font-size:16px !important;line-height:16px !important;height:16px !important}.s-6>tbody>tr>td{font-size:24px !important;line-height:24px !important;height:24px !important}.s-10>tbody>tr>td{font-size:40px !important;line-height:40px !important;height:40px !important}}
</style>
</head> </head>
<body style="margin: 0; padding: 0;"> <body class="bg-light" style="outline: 0; width: 100%; min-width: 100%; height: 100%; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; font-family: Helvetica, Arial, sans-serif; line-height: 24px; font-weight: normal; font-size: 16px; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; color: #000000; margin: 0; padding: 0; border-width: 0;" bgcolor="#f7fafc">
<table border="0" cellpadding="0" cellspacing="0" width="100%"> <table class="bg-light body" valign="top" role="presentation" border="0" cellpadding="0" cellspacing="0" style="outline: 0; width: 100%; min-width: 100%; height: 100%; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; font-family: Helvetica, Arial, sans-serif; line-height: 24px; font-weight: normal; font-size: 16px; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; color: #000000; margin: 0; padding: 0; border-width: 0;" bgcolor="#f7fafc">
<tr> <tbody>
<td style="padding: 20px 0 30px 0;"> <tr>
<td valign="top" style="line-height: 24px; font-size: 16px; margin: 0;" align="left" bgcolor="#f7fafc">
<table align="center" border="0" cellpadding="0" cellspacing="0" width="600" style="border-collapse: collapse; border: 1px solid #cccccc;"> <table class="container" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;">
<tr> <tbody>
<td align="center" bgcolor="#ff4654"> <tr>
<img src="https://revolt.chat/header.png" alt="Revolt logo" width="600" height="168" style="display: block;" /> <td align="center" style="line-height: 24px; font-size: 16px; margin: 0; padding: 0 16px;">
</td> <!--[if (gte mso 9)|(IE)]>
</tr> <table align="center" role="presentation">
<tr> <tbody>
<td bgcolor="#ffffff" style="padding: 40px 30px 40px 30px;"> <tr>
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;"> <td width="600">
<tr> <![endif]-->
<td style="color: #153643; font-family: Arial, sans-serif;"> <table align="center" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%; max-width: 600px; margin: 0 auto;">
<h1 style="font-size: 24px; margin: 0;">Reset your password!</h1> <tbody>
</td> <tr>
</tr> <td style="line-height: 24px; font-size: 16px; margin: 0;" align="left">
<tr> <table class="s-10 w-full" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;" width="100%">
<td style="color: #153643; font-family: Arial, sans-serif; font-size: 16px; line-height: 24px; padding: 20px 0 0 0;"> <tbody>
<p> <tr>
You requested a password reset, if you didn't perform this action you can safely ignore this email. <td style="line-height: 40px; font-size: 40px; width: 100%; height: 40px; margin: 0;" align="left" width="100%" height="40">
</p> &#160;
<p style="margin: 0;"> </td>
Reset your password by navigating to <a href="{{url}}">{{url}}</a>. </tr>
</p> </tbody>
</td> </table>
</tr> <table class="ax-center" role="presentation" align="center" border="0" cellpadding="0" cellspacing="0" style="margin: 0 auto;">
</table> <tbody>
</td> <tr>
</tr> <td style="line-height: 24px; font-size: 16px; margin: 0;" align="left">
<tr> <img alt="Revolt Logo" class="w-24" src="https://app.revolt.chat/assets/logo_round.png" style="height: auto; line-height: 100%; outline: none; text-decoration: none; display: block; width: 96px; border-style: none; border-width: 0;" width="96">
<td bgcolor="#ff4654" style="padding: 30px 30px;"> </td>
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;"> </tr>
<tr> </tbody>
<td style="color: #ffffff; font-family: Arial, sans-serif; font-size: 14px;"> </table>
<p style="margin: 0;">Sent by Revolt. &middot; Website: <a style="color: white;" href="https://revolt.chat">https://revolt.chat</a></p> <table class="s-10 w-full" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;" width="100%">
<p>Revolt is a user-first chat platform built with modern web technologies.</p> <tbody>
</td> <tr>
</tr> <td style="line-height: 40px; font-size: 40px; width: 100%; height: 40px; margin: 0;" align="left" width="100%" height="40">
</table> &#160;
</td> </td>
</tr> </tr>
</table> </tbody>
</table>
</td> <table class="card p-6 p-lg-10 space-y-4" role="presentation" border="0" cellpadding="0" cellspacing="0" style="border-radius: 6px; border-collapse: separate !important; width: 100%; overflow: hidden; border: 1px solid #e2e8f0;" bgcolor="#ffffff">
</tr> <tbody>
</table> <tr>
</body> <td style="line-height: 24px; font-size: 16px; width: 100%; margin: 0; padding: 40px;" align="left" bgcolor="#ffffff">
<h1 class="h3 fw-700" style="padding-top: 0; padding-bottom: 0; font-weight: 700 !important; vertical-align: baseline; font-size: 28px; line-height: 33.6px; margin: 0;" align="left">Password Reset</h1>
<table class="s-4 w-full" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;" width="100%">
<tbody>
<tr>
<td style="line-height: 16px; font-size: 16px; width: 100%; height: 16px; margin: 0;" align="left" width="100%" height="16">
&#160;
</td>
</tr>
</tbody>
</table>
<p class="" style="line-height: 24px; font-size: 16px; width: 100%; margin: 0;" align="left">You requested a password reset, click below to continue.</p>
<table class="s-4 w-full" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;" width="100%">
<tbody>
<tr>
<td style="line-height: 16px; font-size: 16px; width: 100%; height: 16px; margin: 0;" align="left" width="100%" height="16">
&#160;
</td>
</tr>
</tbody>
</table>
<table class="btn btn-primary p-3 fw-700" role="presentation" border="0" cellpadding="0" cellspacing="0" style="border-radius: 6px; border-collapse: separate !important; font-weight: 700 !important;">
<tbody>
<tr>
<td style="line-height: 24px; font-size: 16px; border-radius: 6px; font-weight: 700 !important; margin: 0;" align="center" bgcolor="#0d6efd">
<a href="{{url}}" style="color: #ffffff; font-size: 16px; font-family: Helvetica, Arial, sans-serif; text-decoration: none; border-radius: 6px; line-height: 20px; display: block; font-weight: 700 !important; white-space: nowrap; background-color: #0d6efd; padding: 12px; border: 1px solid #0d6efd;">Reset</a>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<table class="s-6 w-full" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;" width="100%">
<tbody>
<tr>
<td style="line-height: 24px; font-size: 24px; width: 100%; height: 24px; margin: 0;" align="left" width="100%" height="24">
&#160;
</td>
</tr>
</tbody>
</table>
<div class="text-muted text-center" style="color: #718096;" align="center">
This email is intended for {{email}}<br>
Sent from Revolt<br>
Made in the EU
</div>
<table class="s-6 w-full" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;" width="100%">
<tbody>
<tr>
<td style="line-height: 24px; font-size: 24px; width: 100%; height: 24px; margin: 0;" align="left" width="100%" height="24">
&#160;
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<!--[if (gte mso 9)|(IE)]>
</td>
</tr>
</tbody>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</body>
</html> </html>
@@ -0,0 +1,26 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
/* Add custom classes and styles that you want inlined here */
</style>
</head>
<body class="bg-light">
<div class="container">
<img
class="ax-center my-10 w-24"
src="https://app.revolt.chat/assets/logo_round.png"
/>
<div class="card p-6 p-lg-10 space-y-4">
<h1 class="h3 fw-700">Password Reset</h1>
<p>You requested a password reset, click below to continue.</p>
<a class="btn btn-primary p-3 fw-700" href="{{url}}">Reset</a>
</div>
<div class="text-muted text-center my-6">
This email is intended for {{email}}<br />
Sent from Revolt<br />
Made in the EU
</div>
</div>
</body>
</html>
+4 -2
View File
@@ -1,5 +1,7 @@
You requested a password reset, if you did not perform this action you can safely ignore this email. You requested a password reset, if you did not perform this action you can safely ignore this email.
Reset your password here: {{url}} Please navigate to: {{url}}
Sent by Revolt. This email is intended for {{email}}
Sent by Revolt
Made in the EU
@@ -1,14 +0,0 @@
<h2>Reset your password.</h2>
<p>
You requested a password reset, if you did not perform this action you can safely ignore this email.
</p>
<p>
Reset your password here: <a href="{{url}}">{{url}}</a>
</p>
<br/>
<p>
Sent by Revolt. · Website: <a href="https://revolt.chat">https://revolt.chat</a>
</p>
<p>
Revolt is a user-first chat platform built with modern web technologies.
</p>
+137 -62
View File
@@ -1,63 +1,138 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-GB"> <html>
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <!-- Compiled with Bootstrap Email version: 1.3.1 --><meta http-equiv="x-ua-compatible" content="ie=edge">
<title>Verify your account.</title> <meta name="x-apple-disable-message-reformatting">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="format-detection" content="telephone=no, date=no, address=no, email=no">
<style type="text/css"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
a[x-apple-data-detectors] {color: inherit !important;} <style type="text/css">
</style> body,table,td{font-family:Helvetica,Arial,sans-serif !important}.ExternalClass{width:100%}.ExternalClass,.ExternalClass p,.ExternalClass span,.ExternalClass font,.ExternalClass td,.ExternalClass div{line-height:150%}a{text-decoration:none}*{color:inherit}a[x-apple-data-detectors],u+#body a,#MessageViewBody a{color:inherit;text-decoration:none;font-size:inherit;font-family:inherit;font-weight:inherit;line-height:inherit}img{-ms-interpolation-mode:bicubic}table:not([class^=s-]){font-family:Helvetica,Arial,sans-serif;mso-table-lspace:0pt;mso-table-rspace:0pt;border-spacing:0px;border-collapse:collapse}table:not([class^=s-]) td{border-spacing:0px;border-collapse:collapse}@media screen and (max-width: 600px){.w-full,.w-full>tbody>tr>td{width:100% !important}.w-24,.w-24>tbody>tr>td{width:96px !important}.p-lg-10:not(table),.p-lg-10:not(.btn)>tbody>tr>td,.p-lg-10.btn td a{padding:0 !important}.p-3:not(table),.p-3:not(.btn)>tbody>tr>td,.p-3.btn td a{padding:12px !important}.p-6:not(table),.p-6:not(.btn)>tbody>tr>td,.p-6.btn td a{padding:24px !important}*[class*=s-lg-]>tbody>tr>td{font-size:0 !important;line-height:0 !important;height:0 !important}.s-4>tbody>tr>td{font-size:16px !important;line-height:16px !important;height:16px !important}.s-6>tbody>tr>td{font-size:24px !important;line-height:24px !important;height:24px !important}.s-10>tbody>tr>td{font-size:40px !important;line-height:40px !important;height:40px !important}}
</style>
</head> </head>
<body style="margin: 0; padding: 0;"> <body class="bg-light" style="outline: 0; width: 100%; min-width: 100%; height: 100%; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; font-family: Helvetica, Arial, sans-serif; line-height: 24px; font-weight: normal; font-size: 16px; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; color: #000000; margin: 0; padding: 0; border-width: 0;" bgcolor="#f7fafc">
<table border="0" cellpadding="0" cellspacing="0" width="100%"> <table class="bg-light body" valign="top" role="presentation" border="0" cellpadding="0" cellspacing="0" style="outline: 0; width: 100%; min-width: 100%; height: 100%; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; font-family: Helvetica, Arial, sans-serif; line-height: 24px; font-weight: normal; font-size: 16px; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; color: #000000; margin: 0; padding: 0; border-width: 0;" bgcolor="#f7fafc">
<tr> <tbody>
<td style="padding: 20px 0 30px 0;"> <tr>
<td valign="top" style="line-height: 24px; font-size: 16px; margin: 0;" align="left" bgcolor="#f7fafc">
<table align="center" border="0" cellpadding="0" cellspacing="0" width="600" style="border-collapse: collapse; border: 1px solid #cccccc;"> <table class="container" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;">
<tr> <tbody>
<td align="center" bgcolor="#ff4654"> <tr>
<img src="https://revolt.chat/header.png" alt="Revolt logo" width="600" height="168" style="display: block;" /> <td align="center" style="line-height: 24px; font-size: 16px; margin: 0; padding: 0 16px;">
</td> <!--[if (gte mso 9)|(IE)]>
</tr> <table align="center" role="presentation">
<tr> <tbody>
<td bgcolor="#ffffff" style="padding: 40px 30px 40px 30px;"> <tr>
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;"> <td width="600">
<tr> <![endif]-->
<td style="color: #153643; font-family: Arial, sans-serif;"> <table align="center" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%; max-width: 600px; margin: 0 auto;">
<h1 style="font-size: 24px; margin: 0;">You're almost there!</h1> <tbody>
</td> <tr>
</tr> <td style="line-height: 24px; font-size: 16px; margin: 0;" align="left">
<tr> <table class="s-10 w-full" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;" width="100%">
<td style="color: #153643; font-family: Arial, sans-serif; font-size: 16px; line-height: 24px; padding: 20px 0 0 0;"> <tbody>
<p> <tr>
Verify your account to be able to log into the platform. If you didn't perform this action you can safely ignore this email. <td style="line-height: 40px; font-size: 40px; width: 100%; height: 40px; margin: 0;" align="left" width="100%" height="40">
</p> &#160;
<p style="margin: 0;"> </td>
Please verify your account by navigating to <a href="{{url}}">{{url}}</a>. </tr>
</p> </tbody>
</td> </table>
</tr> <table class="ax-center" role="presentation" align="center" border="0" cellpadding="0" cellspacing="0" style="margin: 0 auto;">
</table> <tbody>
</td> <tr>
</tr> <td style="line-height: 24px; font-size: 16px; margin: 0;" align="left">
<tr> <img alt="Revolt Logo" class="w-24" src="https://app.revolt.chat/assets/logo_round.png" style="height: auto; line-height: 100%; outline: none; text-decoration: none; display: block; width: 96px; border-style: none; border-width: 0;" width="96">
<td bgcolor="#ff4654" style="padding: 30px 30px;"> </td>
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;"> </tr>
<tr> </tbody>
<td style="color: #ffffff; font-family: Arial, sans-serif; font-size: 14px;"> </table>
<p style="margin: 0;">Sent by Revolt. &middot; Website: <a style="color: white;" href="https://revolt.chat">https://revolt.chat</a></p> <table class="s-10 w-full" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;" width="100%">
<p>Revolt is a user-first chat platform built with modern web technologies.</p> <tbody>
</td> <tr>
</tr> <td style="line-height: 40px; font-size: 40px; width: 100%; height: 40px; margin: 0;" align="left" width="100%" height="40">
</table> &#160;
</td> </td>
</tr> </tr>
</table> </tbody>
</table>
</td> <table class="card p-6 p-lg-10 space-y-4" role="presentation" border="0" cellpadding="0" cellspacing="0" style="border-radius: 6px; border-collapse: separate !important; width: 100%; overflow: hidden; border: 1px solid #e2e8f0;" bgcolor="#ffffff">
</tr> <tbody>
</table> <tr>
</body> <td style="line-height: 24px; font-size: 16px; width: 100%; margin: 0; padding: 40px;" align="left" bgcolor="#ffffff">
<h1 class="h3 fw-700" style="padding-top: 0; padding-bottom: 0; font-weight: 700 !important; vertical-align: baseline; font-size: 28px; line-height: 33.6px; margin: 0;" align="left">Almost there!</h1>
<table class="s-4 w-full" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;" width="100%">
<tbody>
<tr>
<td style="line-height: 16px; font-size: 16px; width: 100%; height: 16px; margin: 0;" align="left" width="100%" height="16">
&#160;
</td>
</tr>
</tbody>
</table>
<p class="" style="line-height: 24px; font-size: 16px; width: 100%; margin: 0;" align="left">To complete your sign up, we just need to verify your email.</p>
<table class="s-4 w-full" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;" width="100%">
<tbody>
<tr>
<td style="line-height: 16px; font-size: 16px; width: 100%; height: 16px; margin: 0;" align="left" width="100%" height="16">
&#160;
</td>
</tr>
</tbody>
</table>
<table class="btn btn-primary p-3 fw-700" role="presentation" border="0" cellpadding="0" cellspacing="0" style="border-radius: 6px; border-collapse: separate !important; font-weight: 700 !important;">
<tbody>
<tr>
<td style="line-height: 24px; font-size: 16px; border-radius: 6px; font-weight: 700 !important; margin: 0;" align="center" bgcolor="#0d6efd">
<a href="{{url}}" style="color: #ffffff; font-size: 16px; font-family: Helvetica, Arial, sans-serif; text-decoration: none; border-radius: 6px; line-height: 20px; display: block; font-weight: 700 !important; white-space: nowrap; background-color: #0d6efd; padding: 12px; border: 1px solid #0d6efd;">Confirm</a>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<table class="s-6 w-full" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;" width="100%">
<tbody>
<tr>
<td style="line-height: 24px; font-size: 24px; width: 100%; height: 24px; margin: 0;" align="left" width="100%" height="24">
&#160;
</td>
</tr>
</tbody>
</table>
<div class="text-muted text-center" style="color: #718096;" align="center">
This email is intended for {{email}}<br>
Sent from Revolt<br>
Made in the EU
</div>
<table class="s-6 w-full" role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;" width="100%">
<tbody>
<tr>
<td style="line-height: 24px; font-size: 24px; width: 100%; height: 24px; margin: 0;" align="left" width="100%" height="24">
&#160;
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<!--[if (gte mso 9)|(IE)]>
</td>
</tr>
</tbody>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</body>
</html> </html>
@@ -0,0 +1,27 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
/* Add custom classes and styles that you want inlined here */
</style>
</head>
<body class="bg-light">
<div class="container">
<img
alt="Revolt Logo"
class="ax-center my-10 w-24"
src="https://app.revolt.chat/assets/logo_round.png"
/>
<div class="card p-6 p-lg-10 space-y-4">
<h1 class="h3 fw-700">Almost there!</h1>
<p>To complete your sign up, we just need to verify your email.</p>
<a class="btn btn-primary p-3 fw-700" href="{{url}}">Confirm</a>
</div>
<div class="text-muted text-center my-6">
This email is intended for {{email}}<br />
Sent from Revolt<br />
Made in the EU
</div>
</div>
</body>
</html>
+6 -4
View File
@@ -1,6 +1,8 @@
You're almost there! Almost there!
If you did not perform this action you can safely ignore this email. To complete your sign up, we just need to verify your email.
Please verify your account here: {{url}} Please navigate to: {{url}}
Sent by Revolt. This email is intended for {{email}}
Sent by Revolt
Made in the EU
@@ -1,15 +0,0 @@
<h2>You're almost there!</h2>
<p>
Verify your account to be able to log into the platform.<br/>
If you did not perform this action you can safely ignore this email.
</p>
<p>
Please verify your account here: <a href="{{url}}">{{url}}</a>
</p>
<br/>
<p>
Sent by Revolt. · Website: <a href="https://revolt.chat">https://revolt.chat</a>
</p>
<p>
Revolt is a user-first chat platform built with modern web technologies.
</p>
+15
View File
@@ -1,3 +1,4 @@
use rauth::RAuthEvent;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::models::channel::{FieldsChannel, PartialChannel}; use crate::models::channel::{FieldsChannel, PartialChannel};
@@ -195,9 +196,23 @@ pub enum EventV1 {
/// Settings updated remotely /// Settings updated remotely
UserSettingsUpdate { id: String, update: UserSettings }, UserSettingsUpdate { id: String, update: UserSettings },
/// User has been platform banned or deleted their account
///
/// Clients should remove the following associated data:
/// - Messages
/// - DM Channels
/// - Relationships
/// - Server Memberships
///
/// User flags are specified to explain why a wipe is occurring though not all reasons will necessarily ever appear.
UserPlatformWipe { user_id: String, flags: i32 },
/// New emoji /// New emoji
EmojiCreate(Emoji), EmojiCreate(Emoji),
/// Delete emoji /// Delete emoji
EmojiDelete { id: String }, EmojiDelete { id: String },
/// Auth events
Auth(RAuthEvent),
} }
+6 -5
View File
@@ -23,11 +23,7 @@ impl Cache {
pub async fn can_view_channel(&self, db: &Database, channel: &Channel) -> bool { pub async fn can_view_channel(&self, db: &Database, channel: &Channel) -> bool {
match &channel { match &channel {
Channel::TextChannel { server, .. } | Channel::VoiceChannel { server, .. } => { Channel::TextChannel { server, .. } | Channel::VoiceChannel { server, .. } => {
let member = self let member = self.members.values().find(|x| &x.id.server == server);
.members
.iter()
.map(|(_, x)| x)
.find(|x| &x.id.server == server);
let server = self.servers.get(server); let server = self.servers.get(server);
let mut perms = perms(self.users.get(&self.user_id).unwrap()).channel(channel); let mut perms = perms(self.users.get(&self.user_id).unwrap()).channel(channel);
@@ -563,4 +559,9 @@ impl EventV1 {
pub async fn private(self, id: String) { pub async fn private(self, id: String) {
self.p(format!("{}!", id)).await; self.p(format!("{}!", id)).await;
} }
/// Publish internal global event
pub async fn global(self) {
self.p("global".to_string()).await;
}
} }
@@ -1,5 +1,3 @@
use std::collections::HashSet;
use crate::models::channel::{Channel, FieldsChannel, PartialChannel}; use crate::models::channel::{Channel, FieldsChannel, PartialChannel};
use crate::{AbstractAttachment, AbstractChannel, Error, OverrideField, Result}; use crate::{AbstractAttachment, AbstractChannel, Error, OverrideField, Result};
@@ -83,8 +81,4 @@ impl AbstractChannel for DummyDb {
info!("Updating permissions for role {role} in {channel} with {permissions:?}"); info!("Updating permissions for role {role} in {channel} with {permissions:?}");
Ok(()) Ok(())
} }
async fn check_channels_exist(&self, _channels: &HashSet<String>) -> Result<bool> {
Ok(true)
}
} }
@@ -383,7 +383,7 @@ impl BulkMessageResponse {
) -> Result<BulkMessageResponse> { ) -> Result<BulkMessageResponse> {
if let Some(true) = include_users { if let Some(true) = include_users {
let user_ids = messages.get_user_ids(); let user_ids = messages.get_user_ids();
let users = db.fetch_users(&user_ids).await?; let users = User::fetch_foreign_users(db, &user_ids).await?;
Ok(match channel { Ok(match channel {
Channel::TextChannel { server, .. } | Channel::VoiceChannel { server, .. } => { Channel::TextChannel { server, .. } | Channel::VoiceChannel { server, .. } => {
@@ -4,6 +4,7 @@ use crate::models::user::{
}; };
use crate::permissions::defn::UserPerms; use crate::permissions::defn::UserPerms;
use crate::permissions::r#impl::user::get_relationship; use crate::permissions::r#impl::user::get_relationship;
use crate::presence::presence_filter_online;
use crate::{perms, Database, Error, Result}; use crate::{perms, Database, Error, Result};
use futures::try_join; use futures::try_join;
@@ -67,6 +68,7 @@ impl User {
} }
/// Mutate the user object to remove redundant information /// Mutate the user object to remove redundant information
#[must_use]
pub fn foreign(mut self) -> User { pub fn foreign(mut self) -> User {
self.profile = None; self.profile = None;
self.relations = None; self.relations = None;
@@ -94,6 +96,21 @@ impl User {
self self
} }
/// Fetch foreign users by a list of IDs
pub async fn fetch_foreign_users(db: &Database, user_ids: &[String]) -> Result<Vec<User>> {
let online_ids = presence_filter_online(user_ids).await;
Ok(db
.fetch_users(user_ids)
.await?
.into_iter()
.map(|mut user| {
user.online = Some(online_ids.contains(&user.id));
user.foreign()
})
.collect::<Vec<User>>())
}
/// Mutate the user object to include relationship (if it does not already exist) /// Mutate the user object to include relationship (if it does not already exist)
#[must_use] #[must_use]
pub fn with_relationship(self, perspective: &User) -> User { pub fn with_relationship(self, perspective: &User) -> User {
@@ -1,5 +1,3 @@
use std::collections::HashSet;
use bson::{Bson, Document}; use bson::{Bson, Document};
use crate::models::channel::{Channel, FieldsChannel, PartialChannel}; use crate::models::channel::{Channel, FieldsChannel, PartialChannel};
@@ -291,25 +289,6 @@ impl AbstractChannel for MongoDb {
with: "channel", with: "channel",
}) })
} }
async fn check_channels_exist(&self, channels: &HashSet<String>) -> Result<bool> {
let count = channels.len() as u64;
self.col::<Document>(COL)
.count_documents(
doc! {
"_id": {
"$in": channels.iter().cloned().collect::<Vec<String>>()
}
},
None,
)
.await
.map(|x| x == count)
.map_err(|_| Error::DatabaseError {
operation: "count_documents",
with: "channel",
})
}
} }
impl IntoDocumentPath for FieldsChannel { impl IntoDocumentPath for FieldsChannel {
+4 -4
View File
@@ -1,7 +1,7 @@
use okapi::openapi3::{SecurityScheme, SecuritySchemeData};
use rauth::models::Session; use rauth::models::Session;
use rocket_okapi::gen::OpenApiGenerator; use revolt_okapi::openapi3::{SecurityScheme, SecuritySchemeData};
use rocket_okapi::request::{OpenApiFromRequest, RequestHeaderInput}; use revolt_rocket_okapi::gen::OpenApiGenerator;
use revolt_rocket_okapi::request::{OpenApiFromRequest, RequestHeaderInput};
use rocket::http::Status; use rocket::http::Status;
use rocket::request::{self, FromRequest, Outcome, Request}; use rocket::request::{self, FromRequest, Outcome, Request};
@@ -53,7 +53,7 @@ impl<'r> OpenApiFromRequest<'r> for User {
_gen: &mut OpenApiGenerator, _gen: &mut OpenApiGenerator,
_name: String, _name: String,
_required: bool, _required: bool,
) -> rocket_okapi::Result<RequestHeaderInput> { ) -> revolt_rocket_okapi::Result<RequestHeaderInput> {
let mut requirements = schemars::Map::new(); let mut requirements = schemars::Map::new();
requirements.insert("Session Token".to_owned(), vec![]); requirements.insert("Session Token".to_owned(), vec![]);
+1 -1
View File
@@ -161,7 +161,7 @@ pub struct PartialChannel {
} }
/// Optional fields on channel object /// Optional fields on channel object
#[derive(Serialize, Deserialize, JsonSchema, Debug, PartialEq, Clone)] #[derive(Serialize, Deserialize, JsonSchema, Debug, PartialEq, Eq, Clone)]
pub enum FieldsChannel { pub enum FieldsChannel {
Description, Description,
Icon, Icon,
+3 -1
View File
@@ -81,7 +81,7 @@ pub struct Masquerade {
pub name: Option<String>, pub name: Option<String>,
/// Replace the avatar shown on this message (URL to image file) /// Replace the avatar shown on this message (URL to image file)
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
#[validate(length(min = 1, max = 128))] #[validate(length(min = 1, max = 256))]
pub avatar: Option<String>, pub avatar: Option<String>,
/// Replace the display role colour shown on this message /// Replace the display role colour shown on this message
/// ///
@@ -98,6 +98,8 @@ pub struct Interactions {
#[serde(skip_serializing_if = "Option::is_none", default)] #[serde(skip_serializing_if = "Option::is_none", default)]
pub reactions: Option<IndexSet<String>>, pub reactions: Option<IndexSet<String>>,
/// Whether reactions should be restricted to the given list /// Whether reactions should be restricted to the given list
///
/// Can only be set to true if reactions list is of at least length 1
#[serde(skip_serializing_if = "if_false", default)] #[serde(skip_serializing_if = "if_false", default)]
pub restrict_reactions: bool, pub restrict_reactions: bool,
} }
+2 -2
View File
@@ -134,7 +134,7 @@ pub struct Server {
} }
/// Optional fields on server object /// Optional fields on server object
#[derive(Serialize, Deserialize, JsonSchema, Debug, PartialEq, Clone)] #[derive(Serialize, Deserialize, JsonSchema, Debug, PartialEq, Eq, Clone)]
pub enum FieldsServer { pub enum FieldsServer {
Description, Description,
Categories, Categories,
@@ -144,7 +144,7 @@ pub enum FieldsServer {
} }
/// Optional fields on server object /// Optional fields on server object
#[derive(Serialize, Deserialize, JsonSchema, Debug, PartialEq, Clone)] #[derive(Serialize, Deserialize, JsonSchema, Debug, PartialEq, Eq, Clone)]
pub enum FieldsRole { pub enum FieldsRole {
Colour, Colour,
} }
@@ -42,7 +42,7 @@ pub struct Member {
} }
/// Optional fields on server member object /// Optional fields on server member object
#[derive(Serialize, Deserialize, JsonSchema, Debug, PartialEq, Clone)] #[derive(Serialize, Deserialize, JsonSchema, Debug, PartialEq, Eq, Clone)]
pub enum FieldsMember { pub enum FieldsMember {
Nickname, Nickname,
Avatar, Avatar,
+1 -1
View File
@@ -56,7 +56,7 @@ pub struct Bot {
} }
/// Optional fields on bot object /// Optional fields on bot object
#[derive(Serialize, Deserialize, JsonSchema, Debug, PartialEq)] #[derive(Serialize, Deserialize, JsonSchema, Debug, PartialEq, Eq)]
pub enum FieldsBot { pub enum FieldsBot {
Token, Token,
InteractionsURL, InteractionsURL,
+11 -3
View File
@@ -10,7 +10,7 @@ pub fn if_false(t: &bool) -> bool {
} }
/// User's relationship with another user (or themselves) /// User's relationship with another user (or themselves)
#[derive(Serialize, Deserialize, JsonSchema, Debug, Clone, PartialEq)] #[derive(Serialize, Deserialize, JsonSchema, Debug, Clone, PartialEq, Eq)]
pub enum RelationshipStatus { pub enum RelationshipStatus {
None, None,
User, User,
@@ -30,11 +30,17 @@ pub struct Relationship {
} }
/// Presence status /// Presence status
#[derive(Serialize, Deserialize, JsonSchema, Debug, Clone, PartialEq)] #[derive(Serialize, Deserialize, JsonSchema, Debug, Clone, PartialEq, Eq)]
pub enum Presence { pub enum Presence {
/// User is online
Online, Online,
/// User is not currently available
Idle, Idle,
/// User is focusing / will only receive mentions
Focus,
/// User is busy / will not receive any notifications
Busy, Busy,
/// User appears to be offline
Invisible, Invisible,
} }
@@ -99,6 +105,8 @@ pub enum Flags {
Deleted = 2, Deleted = 2,
/// User was banned off the platform /// User was banned off the platform
Banned = 4, Banned = 4,
/// User was marked as spam and removed from platform
Spam = 8,
} }
/// Bot information for if the user is a bot /// Bot information for if the user is a bot
@@ -157,7 +165,7 @@ pub struct User {
} }
/// Optional fields on user object /// Optional fields on user object
#[derive(Serialize, Deserialize, JsonSchema, Debug, PartialEq, Clone)] #[derive(Serialize, Deserialize, JsonSchema, Debug, PartialEq, Eq, Clone)]
pub enum FieldsUser { pub enum FieldsUser {
Avatar, Avatar,
StatusText, StatusText,
+1 -1
View File
@@ -97,7 +97,7 @@ impl From<i64> for PermissionValue {
impl From<u64> for PermissionValue { impl From<u64> for PermissionValue {
fn from(v: u64) -> Self { fn from(v: u64) -> Self {
Self(v as u64) Self(v)
} }
} }
@@ -24,7 +24,7 @@ pub enum Permission {
/// Manage server customisation (includes emoji) /// Manage server customisation (includes emoji)
ManageCustomisation = 1 << 4, ManageCustomisation = 1 << 4,
// % 1 bits reserved // % 1 bit reserved
// * Member permissions // * Member permissions
/// Kick other members below their ranking /// Kick other members below their ranking
@@ -109,10 +109,11 @@ lazy_static! {
+ Permission::Connect + Permission::Connect
+ Permission::Speak; + Permission::Speak;
pub static ref DEFAULT_PERMISSION_SAVED_MESSAGES: u64 = Permission::GrantAllSafe as u64; pub static ref DEFAULT_PERMISSION_SAVED_MESSAGES: u64 = Permission::GrantAllSafe as u64;
pub static ref DEFAULT_PERMISSION_DIRECT_MESSAGE: u64 = pub static ref DEFAULT_PERMISSION_DIRECT_MESSAGE: u64 = *DEFAULT_PERMISSION
*DEFAULT_PERMISSION + Permission::ManageChannel; + Permission::ManageChannel
+ Permission::React;
pub static ref DEFAULT_PERMISSION_SERVER: u64 = pub static ref DEFAULT_PERMISSION_SERVER: u64 =
*DEFAULT_PERMISSION + Permission::ChangeNickname + Permission::ChangeAvatar; *DEFAULT_PERMISSION + Permission::React + Permission::ChangeNickname + Permission::ChangeAvatar;
} }
bitfield! { bitfield! {
+3 -3
View File
@@ -35,7 +35,7 @@ pub async fn presence_create_session(user_id: &str, flags: u8) -> (bool, u8) {
__set_key_presence_entry(&mut conn, user_id, entry).await; __set_key_presence_entry(&mut conn, user_id, entry).await;
// Add to region set in case of failure. // Add to region set in case of failure.
__add_to_set_sessions(&mut conn, &*REGION_KEY, user_id, session_id).await; __add_to_set_sessions(&mut conn, &REGION_KEY, user_id, session_id).await;
(was_empty, session_id) (was_empty, session_id)
} }
@@ -74,7 +74,7 @@ async fn presence_delete_session_internal(
// Remove from region set. // Remove from region set.
if !skip_region { if !skip_region {
__remove_from_set_sessions(&mut conn, &*REGION_KEY, user_id, session_id).await; __remove_from_set_sessions(&mut conn, &REGION_KEY, user_id, session_id).await;
} }
} }
@@ -147,7 +147,7 @@ pub async fn presence_clear_region(region_id: Option<&str>) {
// also send out any relevant events. // also send out any relevant events.
for session in sessions { for session in sessions {
let parts = session.split(':').collect::<Vec<&str>>(); let parts = session.split(':').collect::<Vec<&str>>();
if let (Some(user_id), Some(session_id)) = (parts.get(0), parts.get(1)) { if let (Some(user_id), Some(session_id)) = (parts.first(), parts.get(1)) {
if let Ok(session_id) = session_id.parse() { if let Ok(session_id) = session_id.parse() {
presence_delete_session_internal(user_id, session_id, true).await; presence_delete_session_internal(user_id, session_id, true).await;
} }
+1 -1
View File
@@ -53,5 +53,5 @@ pub async fn __get_set_sessions(conn: &mut Conn, region_id: &str) -> Vec<String>
/// Delete region session set /// Delete region session set
pub async fn __delete_set_sessions(conn: &mut Conn, region_id: &str) { pub async fn __delete_set_sessions(conn: &mut Conn, region_id: &str) {
let _: () = conn.del(region_id).await.unwrap(); conn.del::<_, ()>(region_id).await.unwrap();
} }
+1 -1
View File
@@ -38,7 +38,7 @@ pub async fn queue(channel: String, id: String, content: String) {
pub async fn worker(db: Database) { pub async fn worker(db: Database) {
loop { loop {
let task = Q.pop().await; let task = Q.pop().await;
if let Ok(embeds) = Embed::generate(task.content, &*JANUARY_URL, *MAX_EMBED_COUNT).await { if let Ok(embeds) = Embed::generate(task.content, &JANUARY_URL, *MAX_EMBED_COUNT).await {
if let Err(err) = Message::append( if let Err(err) = Message::append(
&db, &db,
task.id, task.id,
@@ -1,5 +1,3 @@
use std::collections::HashSet;
use crate::models::channel::{Channel, FieldsChannel, PartialChannel}; use crate::models::channel::{Channel, FieldsChannel, PartialChannel};
use crate::{OverrideField, Result}; use crate::{OverrideField, Result};
@@ -55,7 +53,4 @@ pub trait AbstractChannel: Sync + Send {
role: &str, role: &str,
permissions: OverrideField, permissions: OverrideField,
) -> Result<()>; ) -> Result<()>;
/// Validate existence of channels
async fn check_channels_exist(&self, channels: &HashSet<String>) -> Result<bool>;
} }
+3 -3
View File
@@ -26,19 +26,19 @@ pub fn config() -> Config {
title: "Verify your Revolt account.".into(), title: "Verify your Revolt account.".into(),
text: include_str!(crate::asset!("templates/verify.txt")).into(), text: include_str!(crate::asset!("templates/verify.txt")).into(),
url: format!("{}/login/verify/", *APP_URL), url: format!("{}/login/verify/", *APP_URL),
html: None, html: Some(include_str!(crate::asset!("templates/verify.html")).into()),
}, },
reset: Template { reset: Template {
title: "Reset your Revolt password.".into(), title: "Reset your Revolt password.".into(),
text: include_str!(crate::asset!("templates/reset.txt")).into(), text: include_str!(crate::asset!("templates/reset.txt")).into(),
url: format!("{}/login/reset/", *APP_URL), url: format!("{}/login/reset/", *APP_URL),
html: None, html: Some(include_str!(crate::asset!("templates/reset.html")).into()),
}, },
deletion: Template { deletion: Template {
title: "Confirm account deletion.".into(), title: "Confirm account deletion.".into(),
text: include_str!(crate::asset!("templates/deletion.txt")).into(), text: include_str!(crate::asset!("templates/deletion.txt")).into(),
url: format!("{}/delete/", *APP_URL), url: format!("{}/delete/", *APP_URL),
html: None, html: Some(include_str!(crate::asset!("templates/deletion.html")).into()),
}, },
welcome: None, welcome: None,
}, },
+15 -12
View File
@@ -1,4 +1,5 @@
use okapi::openapi3::{self, SchemaObject}; use revolt_okapi::openapi3::SchemaObject;
use revolt_rocket_okapi::revolt_okapi::openapi3;
use rocket::{ use rocket::{
http::{ContentType, Status}, http::{ContentType, Status},
response::{self, Responder}, response::{self, Responder},
@@ -19,10 +20,10 @@ pub enum Error {
/// This error was not labeled :( /// This error was not labeled :(
LabelMe, LabelMe,
// ? Onboarding related errors. // ? Onboarding related errors
AlreadyOnboarded, AlreadyOnboarded,
// ? User related errors. // ? User related errors
UsernameTaken, UsernameTaken,
InvalidUsername, InvalidUsername,
UnknownUser, UnknownUser,
@@ -32,7 +33,7 @@ pub enum Error {
BlockedByOther, BlockedByOther,
NotFriends, NotFriends,
// ? Channel related errors. // ? Channel related errors
UnknownChannel, UnknownChannel,
UnknownAttachment, UnknownAttachment,
UnknownMessage, UnknownMessage,
@@ -49,7 +50,7 @@ pub enum Error {
AlreadyInGroup, AlreadyInGroup,
NotInGroup, NotInGroup,
// ? Server related errors. // ? Server related errors
UnknownServer, UnknownServer,
InvalidRole, InvalidRole,
Banned, Banned,
@@ -58,12 +59,12 @@ pub enum Error {
}, },
TooManyEmoji, TooManyEmoji,
// ? Bot related errors. // ? Bot related errors
ReachedMaximumBots, ReachedMaximumBots,
IsBot, IsBot,
BotIsPrivate, BotIsPrivate,
// ? Permission errors. // ? Permission errors
MissingPermission { MissingPermission {
permission: Permission, permission: Permission,
}, },
@@ -74,7 +75,7 @@ pub enum Error {
CannotGiveMissingPermissions, CannotGiveMissingPermissions,
NotOwner, NotOwner,
// ? General errors. // ? General errors
DatabaseError { DatabaseError {
operation: &'static str, operation: &'static str,
with: &'static str, with: &'static str,
@@ -82,6 +83,7 @@ pub enum Error {
InternalError, InternalError,
InvalidOperation, InvalidOperation,
InvalidCredentials, InvalidCredentials,
InvalidProperty,
InvalidSession, InvalidSession,
DuplicateNonce, DuplicateNonce,
VosoUnavailable, VosoUnavailable,
@@ -174,6 +176,7 @@ impl<'r> Responder<'r, 'static> for Error {
Error::InternalError => Status::InternalServerError, Error::InternalError => Status::InternalServerError,
Error::InvalidOperation => Status::BadRequest, Error::InvalidOperation => Status::BadRequest,
Error::InvalidCredentials => Status::Unauthorized, Error::InvalidCredentials => Status::Unauthorized,
Error::InvalidProperty => Status::BadRequest,
Error::InvalidSession => Status::Unauthorized, Error::InvalidSession => Status::Unauthorized,
Error::DuplicateNonce => Status::Conflict, Error::DuplicateNonce => Status::Conflict,
Error::VosoUnavailable => Status::BadRequest, Error::VosoUnavailable => Status::BadRequest,
@@ -194,11 +197,11 @@ impl<'r> Responder<'r, 'static> for Error {
} }
} }
impl rocket_okapi::response::OpenApiResponderInner for Error { impl revolt_rocket_okapi::response::OpenApiResponderInner for Error {
fn responses( fn responses(
gen: &mut rocket_okapi::gen::OpenApiGenerator, gen: &mut revolt_rocket_okapi::gen::OpenApiGenerator,
) -> std::result::Result<openapi3::Responses, rocket_okapi::OpenApiError> { ) -> std::result::Result<openapi3::Responses, revolt_rocket_okapi::OpenApiError> {
let mut content = okapi::Map::new(); let mut content = revolt_okapi::Map::new();
let settings = schemars::gen::SchemaSettings::default().with(|s| { let settings = schemars::gen::SchemaSettings::default().with(|s| {
s.option_nullable = true; s.option_nullable = true;
+4 -4
View File
@@ -1,11 +1,11 @@
use crate::{Error, Result}; use crate::{Error, Result};
use async_std::sync::Mutex; use async_std::sync::Mutex;
use revolt_rocket_okapi::gen::OpenApiGenerator;
use revolt_rocket_okapi::request::{OpenApiFromRequest, RequestHeaderInput};
use revolt_rocket_okapi::revolt_okapi::openapi3::{Parameter, ParameterValue};
use rocket::http::Status; use rocket::http::Status;
use rocket::request::{FromRequest, Outcome}; use rocket::request::{FromRequest, Outcome};
use rocket_okapi::gen::OpenApiGenerator;
use rocket_okapi::okapi::openapi3::{Parameter, ParameterValue};
use rocket_okapi::request::{OpenApiFromRequest, RequestHeaderInput};
use schemars::schema::{InstanceType, SchemaObject, SingleOrVec}; use schemars::schema::{InstanceType, SchemaObject, SingleOrVec};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use validator::Validate; use validator::Validate;
@@ -47,7 +47,7 @@ impl<'r> OpenApiFromRequest<'r> for IdempotencyKey {
_gen: &mut OpenApiGenerator, _gen: &mut OpenApiGenerator,
_name: String, _name: String,
_required: bool, _required: bool,
) -> rocket_okapi::Result<RequestHeaderInput> { ) -> revolt_rocket_okapi::Result<RequestHeaderInput> {
Ok(RequestHeaderInput::Parameter(Parameter { Ok(RequestHeaderInput::Parameter(Parameter {
name: "Idempotency-Key".to_string(), name: "Idempotency-Key".to_string(),
description: Some("Unique key to prevent duplicate requests".to_string()), description: Some("Unique key to prevent duplicate requests".to_string()),
+13 -8
View File
@@ -16,8 +16,8 @@ use rocket::request::{FromRequest, Outcome};
use rocket::serde::json::Json; use rocket::serde::json::Json;
use rocket::{Data, Request, Response}; use rocket::{Data, Request, Response};
use rocket_okapi::gen::OpenApiGenerator; use revolt_rocket_okapi::gen::OpenApiGenerator;
use rocket_okapi::request::{OpenApiFromRequest, RequestHeaderInput}; use revolt_rocket_okapi::request::{OpenApiFromRequest, RequestHeaderInput};
use serde::Serialize; use serde::Serialize;
@@ -51,7 +51,7 @@ impl Entry {
} }
/// Deduct one unit from the bucket and save /// Deduct one unit from the bucket and save
pub fn deduct(mut self, key: u64) { pub fn deduct(mut self) {
let current_time = now().as_millis(); let current_time = now().as_millis();
if current_time > self.reset { if current_time > self.reset {
self.used = 1; self.used = 1;
@@ -59,7 +59,10 @@ impl Entry {
} else { } else {
self.used += 1; self.used += 1;
} }
}
/// Save information
pub fn save(self, key: u64) {
MAP.insert(key, self); MAP.insert(key, self);
} }
@@ -189,10 +192,12 @@ impl Ratelimiter {
let entry = Entry::from(key); let entry = Entry::from(key);
let remaining = entry.get_remaining(limit); let remaining = entry.get_remaining(limit);
let reset = entry.left_until_reset();
if remaining > 0 { if remaining > 0 {
entry.deduct(key); entry.deduct();
let reset = entry.left_until_reset();
entry.save(key);
Ok(Ratelimiter { Ok(Ratelimiter {
key, key,
limit, limit,
@@ -200,7 +205,7 @@ impl Ratelimiter {
reset, reset,
}) })
} else { } else {
Err(reset) Err(entry.left_until_reset())
} }
} }
} }
@@ -236,7 +241,7 @@ impl<'r> OpenApiFromRequest<'r> for Ratelimiter {
_gen: &mut OpenApiGenerator, _gen: &mut OpenApiGenerator,
_name: String, _name: String,
_required: bool, _required: bool,
) -> rocket_okapi::Result<RequestHeaderInput> { ) -> revolt_rocket_okapi::Result<RequestHeaderInput> {
Ok(RequestHeaderInput::None) Ok(RequestHeaderInput::None)
} }
} }
+1 -1
View File
@@ -1,7 +1,7 @@
use rocket::Route; use rocket::Route;
pub fn routes() -> Vec<Route> { pub fn routes() -> Vec<Route> {
rocket_okapi::swagger_ui::make_swagger_ui(&rocket_okapi::swagger_ui::SwaggerUIConfig { revolt_rocket_okapi::swagger_ui::make_swagger_ui(&revolt_rocket_okapi::swagger_ui::SwaggerUIConfig {
url: "../openapi.json".to_owned(), url: "../openapi.json".to_owned(),
..Default::default() ..Default::default()
}) })
+9
View File
@@ -0,0 +1,9 @@
version: "3.3"
services:
# MongoDB
database:
image: mongo
ports:
- "27017:27017"
volumes:
- ./.data/db:/data/db