mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-11-30 13:21:11 +00:00
Merge remote-tracking branch 'yerba/main' into main
This commit is contained in:
commit
4de80dc29d
67 changed files with 1532 additions and 1294 deletions
142
Cargo.lock
generated
142
Cargo.lock
generated
|
@ -1113,12 +1113,6 @@ version = "1.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
|
checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "dotenv"
|
|
||||||
version = "0.15.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dtoa"
|
name = "dtoa"
|
||||||
version = "0.4.6"
|
version = "0.4.6"
|
||||||
|
@ -1809,6 +1803,92 @@ version = "1.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lemmy_api"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"actix",
|
||||||
|
"actix-rt",
|
||||||
|
"actix-web",
|
||||||
|
"anyhow",
|
||||||
|
"async-trait",
|
||||||
|
"awc",
|
||||||
|
"background-jobs",
|
||||||
|
"base64 0.12.3",
|
||||||
|
"bcrypt",
|
||||||
|
"captcha",
|
||||||
|
"chrono",
|
||||||
|
"diesel",
|
||||||
|
"futures",
|
||||||
|
"http",
|
||||||
|
"http-signature-normalization-actix",
|
||||||
|
"itertools",
|
||||||
|
"jsonwebtoken",
|
||||||
|
"lazy_static",
|
||||||
|
"lemmy_apub",
|
||||||
|
"lemmy_db",
|
||||||
|
"lemmy_rate_limit",
|
||||||
|
"lemmy_structs",
|
||||||
|
"lemmy_utils",
|
||||||
|
"lemmy_websocket",
|
||||||
|
"log",
|
||||||
|
"openssl",
|
||||||
|
"percent-encoding",
|
||||||
|
"rand 0.7.3",
|
||||||
|
"reqwest",
|
||||||
|
"serde 1.0.116",
|
||||||
|
"serde_json",
|
||||||
|
"sha2",
|
||||||
|
"strum",
|
||||||
|
"strum_macros",
|
||||||
|
"thiserror",
|
||||||
|
"tokio",
|
||||||
|
"url",
|
||||||
|
"uuid 0.8.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lemmy_apub"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"activitystreams",
|
||||||
|
"activitystreams-ext",
|
||||||
|
"actix",
|
||||||
|
"actix-rt",
|
||||||
|
"actix-web",
|
||||||
|
"anyhow",
|
||||||
|
"async-trait",
|
||||||
|
"awc",
|
||||||
|
"background-jobs",
|
||||||
|
"base64 0.12.3",
|
||||||
|
"bcrypt",
|
||||||
|
"chrono",
|
||||||
|
"diesel",
|
||||||
|
"futures",
|
||||||
|
"http",
|
||||||
|
"http-signature-normalization-actix",
|
||||||
|
"itertools",
|
||||||
|
"lazy_static",
|
||||||
|
"lemmy_db",
|
||||||
|
"lemmy_structs",
|
||||||
|
"lemmy_utils",
|
||||||
|
"lemmy_websocket",
|
||||||
|
"log",
|
||||||
|
"openssl",
|
||||||
|
"percent-encoding",
|
||||||
|
"rand 0.7.3",
|
||||||
|
"reqwest",
|
||||||
|
"serde 1.0.116",
|
||||||
|
"serde_json",
|
||||||
|
"sha2",
|
||||||
|
"strum",
|
||||||
|
"strum_macros",
|
||||||
|
"thiserror",
|
||||||
|
"tokio",
|
||||||
|
"url",
|
||||||
|
"uuid 0.8.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lemmy_db"
|
name = "lemmy_db"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -1844,58 +1924,41 @@ dependencies = [
|
||||||
name = "lemmy_server"
|
name = "lemmy_server"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"activitystreams",
|
|
||||||
"activitystreams-ext",
|
|
||||||
"actix",
|
"actix",
|
||||||
"actix-files",
|
"actix-files",
|
||||||
"actix-rt",
|
|
||||||
"actix-web",
|
"actix-web",
|
||||||
"actix-web-actors",
|
"actix-web-actors",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
|
||||||
"awc",
|
"awc",
|
||||||
"background-jobs",
|
|
||||||
"base64 0.12.3",
|
|
||||||
"bcrypt",
|
|
||||||
"captcha",
|
|
||||||
"cargo-husky",
|
"cargo-husky",
|
||||||
"chrono",
|
"chrono",
|
||||||
"diesel",
|
"diesel",
|
||||||
"diesel_migrations",
|
"diesel_migrations",
|
||||||
"dotenv",
|
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"futures",
|
|
||||||
"http",
|
|
||||||
"http-signature-normalization-actix",
|
"http-signature-normalization-actix",
|
||||||
"itertools",
|
|
||||||
"jsonwebtoken",
|
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
"lemmy_api",
|
||||||
|
"lemmy_apub",
|
||||||
"lemmy_db",
|
"lemmy_db",
|
||||||
"lemmy_rate_limit",
|
"lemmy_rate_limit",
|
||||||
"lemmy_structs",
|
"lemmy_structs",
|
||||||
"lemmy_utils",
|
"lemmy_utils",
|
||||||
|
"lemmy_websocket",
|
||||||
"log",
|
"log",
|
||||||
"openssl",
|
"openssl",
|
||||||
"percent-encoding",
|
|
||||||
"rand 0.7.3",
|
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"rss",
|
"rss",
|
||||||
"serde 1.0.116",
|
"serde 1.0.116",
|
||||||
"serde_json",
|
|
||||||
"sha2",
|
"sha2",
|
||||||
"strum",
|
"strum",
|
||||||
"strum_macros",
|
|
||||||
"thiserror",
|
|
||||||
"tokio",
|
"tokio",
|
||||||
"url",
|
"url",
|
||||||
"uuid 0.8.1",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lemmy_structs"
|
name = "lemmy_structs"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix",
|
|
||||||
"actix-web",
|
"actix-web",
|
||||||
"chrono",
|
"chrono",
|
||||||
"diesel",
|
"diesel",
|
||||||
|
@ -1903,8 +1966,7 @@ dependencies = [
|
||||||
"lemmy_utils",
|
"lemmy_utils",
|
||||||
"log",
|
"log",
|
||||||
"serde 1.0.116",
|
"serde 1.0.116",
|
||||||
"strum",
|
"serde_json",
|
||||||
"strum_macros",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1924,12 +1986,36 @@ dependencies = [
|
||||||
"openssl",
|
"openssl",
|
||||||
"rand 0.7.3",
|
"rand 0.7.3",
|
||||||
"regex",
|
"regex",
|
||||||
|
"reqwest",
|
||||||
"serde 1.0.116",
|
"serde 1.0.116",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lemmy_websocket"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"actix",
|
||||||
|
"anyhow",
|
||||||
|
"background-jobs",
|
||||||
|
"chrono",
|
||||||
|
"diesel",
|
||||||
|
"lemmy_db",
|
||||||
|
"lemmy_rate_limit",
|
||||||
|
"lemmy_structs",
|
||||||
|
"lemmy_utils",
|
||||||
|
"log",
|
||||||
|
"rand 0.7.3",
|
||||||
|
"reqwest",
|
||||||
|
"serde 1.0.116",
|
||||||
|
"serde_json",
|
||||||
|
"strum",
|
||||||
|
"strum_macros",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lettre"
|
name = "lettre"
|
||||||
version = "0.9.3"
|
version = "0.9.3"
|
||||||
|
|
25
Cargo.toml
25
Cargo.toml
|
@ -8,56 +8,43 @@ lto = true
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
|
"lemmy_api",
|
||||||
|
"lemmy_apub",
|
||||||
"lemmy_utils",
|
"lemmy_utils",
|
||||||
"lemmy_db",
|
"lemmy_db",
|
||||||
"lemmy_structs",
|
"lemmy_structs",
|
||||||
"lemmy_rate_limit",
|
"lemmy_rate_limit",
|
||||||
|
"lemmy_websocket",
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
lemmy_api = { path = "./lemmy_api" }
|
||||||
|
lemmy_apub = { path = "./lemmy_apub" }
|
||||||
lemmy_utils = { path = "./lemmy_utils" }
|
lemmy_utils = { path = "./lemmy_utils" }
|
||||||
lemmy_db = { path = "./lemmy_db" }
|
lemmy_db = { path = "./lemmy_db" }
|
||||||
lemmy_structs = { path = "./lemmy_structs" }
|
lemmy_structs = { path = "./lemmy_structs" }
|
||||||
lemmy_rate_limit = { path = "./lemmy_rate_limit" }
|
lemmy_rate_limit = { path = "./lemmy_rate_limit" }
|
||||||
|
lemmy_websocket = { path = "./lemmy_websocket" }
|
||||||
diesel = "1.4"
|
diesel = "1.4"
|
||||||
diesel_migrations = "1.4"
|
diesel_migrations = "1.4"
|
||||||
dotenv = "0.15"
|
|
||||||
activitystreams = "0.7.0-alpha.4"
|
|
||||||
activitystreams-ext = "0.1.0-alpha.2"
|
|
||||||
bcrypt = "0.8"
|
|
||||||
chrono = { version = "0.4", features = ["serde"] }
|
chrono = { version = "0.4", features = ["serde"] }
|
||||||
serde_json = { version = "1.0", features = ["preserve_order"]}
|
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
actix = "0.10"
|
actix = "0.10"
|
||||||
actix-web = { version = "3.0", default-features = false, features = ["rustls"] }
|
actix-web = { version = "3.0", default-features = false, features = ["rustls"] }
|
||||||
actix-files = { version = "0.3", default-features = false }
|
actix-files = { version = "0.3", default-features = false }
|
||||||
actix-web-actors = { version = "3.0", default-features = false }
|
actix-web-actors = { version = "3.0", default-features = false }
|
||||||
actix-rt = { version = "1.1", default-features = false }
|
|
||||||
awc = { version = "2.0", default-features = false }
|
awc = { version = "2.0", default-features = false }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
env_logger = "0.7"
|
env_logger = "0.7"
|
||||||
rand = "0.7"
|
|
||||||
strum = "0.19"
|
strum = "0.19"
|
||||||
strum_macros = "0.19"
|
|
||||||
jsonwebtoken = "7.0"
|
|
||||||
lazy_static = "1.3"
|
lazy_static = "1.3"
|
||||||
rss = "1.9"
|
rss = "1.9"
|
||||||
url = { version = "2.1", features = ["serde"] }
|
url = { version = "2.1", features = ["serde"] }
|
||||||
percent-encoding = "2.1"
|
|
||||||
openssl = "0.10"
|
openssl = "0.10"
|
||||||
http = "0.2"
|
|
||||||
http-signature-normalization-actix = { version = "0.4", default-features = false, features = ["sha-2"] }
|
http-signature-normalization-actix = { version = "0.4", default-features = false, features = ["sha-2"] }
|
||||||
base64 = "0.12"
|
|
||||||
tokio = "0.2"
|
tokio = "0.2"
|
||||||
futures = "0.3"
|
|
||||||
itertools = "0.9"
|
|
||||||
uuid = { version = "0.8", features = ["serde", "v4"] }
|
|
||||||
sha2 = "0.9"
|
sha2 = "0.9"
|
||||||
async-trait = "0.1"
|
|
||||||
captcha = "0.0"
|
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
thiserror = "1.0"
|
|
||||||
background-jobs = " 0.8"
|
|
||||||
reqwest = { version = "0.10", features = ["json"] }
|
reqwest = { version = "0.10", features = ["json"] }
|
||||||
|
|
||||||
[dev-dependencies.cargo-husky]
|
[dev-dependencies.cargo-husky]
|
||||||
|
|
|
@ -12,6 +12,9 @@ RUN mkdir -p lemmy_db/src/ \
|
||||||
lemmy_utils/src/ \
|
lemmy_utils/src/ \
|
||||||
lemmy_structs/src/ \
|
lemmy_structs/src/ \
|
||||||
lemmy_rate_limit/src/ \
|
lemmy_rate_limit/src/ \
|
||||||
|
lemmy_api/src/ \
|
||||||
|
lemmy_apub/src/ \
|
||||||
|
lemmy_websocket/src/ \
|
||||||
lemmy
|
lemmy
|
||||||
|
|
||||||
# Copy the cargo tomls
|
# Copy the cargo tomls
|
||||||
|
@ -20,6 +23,9 @@ COPY lemmy_db/Cargo.toml ./lemmy_db/
|
||||||
COPY lemmy_utils/Cargo.toml ./lemmy_utils/
|
COPY lemmy_utils/Cargo.toml ./lemmy_utils/
|
||||||
COPY lemmy_structs/Cargo.toml ./lemmy_structs/
|
COPY lemmy_structs/Cargo.toml ./lemmy_structs/
|
||||||
COPY lemmy_rate_limit/Cargo.toml ./lemmy_rate_limit/
|
COPY lemmy_rate_limit/Cargo.toml ./lemmy_rate_limit/
|
||||||
|
COPY lemmy_api/Cargo.toml ./lemmy_api/
|
||||||
|
COPY lemmy_apub/Cargo.toml ./lemmy_apub/
|
||||||
|
COPY lemmy_websocket/Cargo.toml ./lemmy_websocket/
|
||||||
|
|
||||||
# Cache the deps
|
# Cache the deps
|
||||||
RUN cargo build-deps
|
RUN cargo build-deps
|
||||||
|
@ -30,6 +36,9 @@ COPY lemmy_db/src ./lemmy_db/src/
|
||||||
COPY lemmy_utils/src/ ./lemmy_utils/src/
|
COPY lemmy_utils/src/ ./lemmy_utils/src/
|
||||||
COPY lemmy_structs/src/ ./lemmy_structs/src/
|
COPY lemmy_structs/src/ ./lemmy_structs/src/
|
||||||
COPY lemmy_rate_limit/src/ ./lemmy_rate_limit/src/
|
COPY lemmy_rate_limit/src/ ./lemmy_rate_limit/src/
|
||||||
|
COPY lemmy_api/src/ ./lemmy_api/src/
|
||||||
|
COPY lemmy_apub/src/ ./lemmy_apub/src/
|
||||||
|
COPY lemmy_websocket/src/ ./lemmy_websocket/src/
|
||||||
COPY migrations ./migrations/
|
COPY migrations ./migrations/
|
||||||
|
|
||||||
# Build for debug
|
# Build for debug
|
||||||
|
|
|
@ -15,11 +15,11 @@ services:
|
||||||
depends_on:
|
depends_on:
|
||||||
- pictrs
|
- pictrs
|
||||||
- iframely
|
- iframely
|
||||||
- lemmy-alpha
|
- lemmy-alpha-ui
|
||||||
- lemmy-beta
|
- lemmy-beta-ui
|
||||||
- lemmy-gamma
|
- lemmy-gamma-ui
|
||||||
- lemmy-delta
|
- lemmy-delta-ui
|
||||||
- lemmy-epsilon
|
- lemmy-epsilon-ui
|
||||||
|
|
||||||
pictrs:
|
pictrs:
|
||||||
restart: always
|
restart: always
|
||||||
|
|
|
@ -3,6 +3,12 @@ events {
|
||||||
}
|
}
|
||||||
|
|
||||||
http {
|
http {
|
||||||
|
upstream lemmy-alpha {
|
||||||
|
server "lemmy-alpha:8541";
|
||||||
|
}
|
||||||
|
upstream lemmy-alpha-ui {
|
||||||
|
server "lemmy-alpha-ui:1234";
|
||||||
|
}
|
||||||
server {
|
server {
|
||||||
listen 8540;
|
listen 8540;
|
||||||
server_name 127.0.0.1;
|
server_name 127.0.0.1;
|
||||||
|
@ -11,14 +17,19 @@ http {
|
||||||
# Upload limit for pictshare
|
# Upload limit for pictshare
|
||||||
client_max_body_size 50M;
|
client_max_body_size 50M;
|
||||||
|
|
||||||
location /api/v1 {
|
location ~ ^/(api|docs|pictrs|feeds|nodeinfo|.well-known) {
|
||||||
proxy_pass http://lemmy-alpha:8541/api/v1;
|
proxy_pass http://lemmy-alpha;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
proxy_set_header Connection "upgrade";
|
proxy_set_header Connection "upgrade";
|
||||||
}
|
}
|
||||||
location / {
|
location / {
|
||||||
proxy_pass http://lemmy-alpha-ui:1234;
|
set $proxpass http://lemmy-alpha-ui;
|
||||||
|
if ($http_accept = "application/activity+json") {
|
||||||
|
set $proxpass http://lemmy-alpha;
|
||||||
|
}
|
||||||
|
proxy_pass $proxpass;
|
||||||
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
@ -34,6 +45,12 @@ http {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
upstream lemmy-beta {
|
||||||
|
server "lemmy-beta:8551";
|
||||||
|
}
|
||||||
|
upstream lemmy-beta-ui {
|
||||||
|
server "lemmy-beta-ui:1234";
|
||||||
|
}
|
||||||
server {
|
server {
|
||||||
listen 8550;
|
listen 8550;
|
||||||
server_name 127.0.0.1;
|
server_name 127.0.0.1;
|
||||||
|
@ -42,14 +59,19 @@ http {
|
||||||
# Upload limit for pictshare
|
# Upload limit for pictshare
|
||||||
client_max_body_size 50M;
|
client_max_body_size 50M;
|
||||||
|
|
||||||
location /api/v1 {
|
location ~ ^/(api|docs|pictrs|feeds|nodeinfo|.well-known) {
|
||||||
proxy_pass http://lemmy-beta:8551/api/v1;
|
proxy_pass http://lemmy-beta;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
proxy_set_header Connection "upgrade";
|
proxy_set_header Connection "upgrade";
|
||||||
}
|
}
|
||||||
location / {
|
location / {
|
||||||
proxy_pass http://lemmy-beta-ui:1234;
|
set $proxpass http://lemmy-beta-ui;
|
||||||
|
if ($http_accept = "application/activity+json") {
|
||||||
|
set $proxpass http://lemmy-beta;
|
||||||
|
}
|
||||||
|
proxy_pass $proxpass;
|
||||||
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
@ -65,6 +87,12 @@ http {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
upstream lemmy-gamma {
|
||||||
|
server "lemmy-gamma:8561";
|
||||||
|
}
|
||||||
|
upstream lemmy-gamma-ui {
|
||||||
|
server "lemmy-gamma-ui:1234";
|
||||||
|
}
|
||||||
server {
|
server {
|
||||||
listen 8560;
|
listen 8560;
|
||||||
server_name 127.0.0.1;
|
server_name 127.0.0.1;
|
||||||
|
@ -73,14 +101,19 @@ http {
|
||||||
# Upload limit for pictshare
|
# Upload limit for pictshare
|
||||||
client_max_body_size 50M;
|
client_max_body_size 50M;
|
||||||
|
|
||||||
location /api/v1 {
|
location ~ ^/(api|docs|pictrs|feeds|nodeinfo|.well-known) {
|
||||||
proxy_pass http://lemmy-gamma:8561/api/v1;
|
proxy_pass http://lemmy-gamma;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
proxy_set_header Connection "upgrade";
|
proxy_set_header Connection "upgrade";
|
||||||
}
|
}
|
||||||
location / {
|
location / {
|
||||||
proxy_pass http://lemmy-gamma-ui:1234;
|
set $proxpass http://lemmy-gamma-ui;
|
||||||
|
if ($http_accept = "application/activity+json") {
|
||||||
|
set $proxpass http://lemmy-gamma;
|
||||||
|
}
|
||||||
|
proxy_pass $proxpass;
|
||||||
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
@ -96,6 +129,12 @@ http {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
upstream lemmy-delta {
|
||||||
|
server "lemmy-delta:8571";
|
||||||
|
}
|
||||||
|
upstream lemmy-delta-ui {
|
||||||
|
server "lemmy-delta-ui:1234";
|
||||||
|
}
|
||||||
server {
|
server {
|
||||||
listen 8570;
|
listen 8570;
|
||||||
server_name 127.0.0.1;
|
server_name 127.0.0.1;
|
||||||
|
@ -104,14 +143,19 @@ http {
|
||||||
# Upload limit for pictshare
|
# Upload limit for pictshare
|
||||||
client_max_body_size 50M;
|
client_max_body_size 50M;
|
||||||
|
|
||||||
location /api/v1 {
|
location ~ ^/(api|docs|pictrs|feeds|nodeinfo|.well-known) {
|
||||||
proxy_pass http://lemmy-delta:8571/api/v1;
|
proxy_pass http://lemmy-delta;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
proxy_set_header Connection "upgrade";
|
proxy_set_header Connection "upgrade";
|
||||||
}
|
}
|
||||||
location / {
|
location / {
|
||||||
proxy_pass http://lemmy-delta-ui:1234;
|
set $proxpass http://lemmy-delta-ui;
|
||||||
|
if ($http_accept = "application/activity+json") {
|
||||||
|
set $proxpass http://lemmy-delta;
|
||||||
|
}
|
||||||
|
proxy_pass $proxpass;
|
||||||
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
@ -127,6 +171,12 @@ http {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
upstream lemmy-epsilon {
|
||||||
|
server "lemmy-epsilon:8581";
|
||||||
|
}
|
||||||
|
upstream lemmy-epsilon-ui {
|
||||||
|
server "lemmy-epsilon-ui:1234";
|
||||||
|
}
|
||||||
server {
|
server {
|
||||||
listen 8580;
|
listen 8580;
|
||||||
server_name 127.0.0.1;
|
server_name 127.0.0.1;
|
||||||
|
@ -135,14 +185,19 @@ http {
|
||||||
# Upload limit for pictshare
|
# Upload limit for pictshare
|
||||||
client_max_body_size 50M;
|
client_max_body_size 50M;
|
||||||
|
|
||||||
location /api/v1 {
|
location ~ ^/(api|docs|pictrs|feeds|nodeinfo|.well-known) {
|
||||||
proxy_pass http://lemmy-epsilon:8581/api/v1;
|
proxy_pass http://lemmy-epsilon;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
proxy_set_header Connection "upgrade";
|
proxy_set_header Connection "upgrade";
|
||||||
}
|
}
|
||||||
location / {
|
location / {
|
||||||
proxy_pass http://lemmy-epsilon-ui:1234;
|
set $proxpass http://lemmy-epsilon-ui;
|
||||||
|
if ($http_accept = "application/activity+json") {
|
||||||
|
set $proxpass http://lemmy-epsilon;
|
||||||
|
}
|
||||||
|
proxy_pass $proxpass;
|
||||||
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
|
|
@ -15,6 +15,9 @@ COPY lemmy_db ./lemmy_db
|
||||||
COPY lemmy_utils ./lemmy_utils
|
COPY lemmy_utils ./lemmy_utils
|
||||||
COPY lemmy_structs ./lemmy_structs
|
COPY lemmy_structs ./lemmy_structs
|
||||||
COPY lemmy_rate_limit ./lemmy_rate_limit
|
COPY lemmy_rate_limit ./lemmy_rate_limit
|
||||||
|
COPY lemmy_api ./lemmy_api
|
||||||
|
COPY lemmy_apub ./lemmy_apub
|
||||||
|
COPY lemmy_websocket ./lemmy_websocket
|
||||||
RUN mkdir -p ./src/bin \
|
RUN mkdir -p ./src/bin \
|
||||||
&& echo 'fn main() { println!("Dummy") }' > ./src/bin/main.rs
|
&& echo 'fn main() { println!("Dummy") }' > ./src/bin/main.rs
|
||||||
RUN cargo build --release
|
RUN cargo build --release
|
||||||
|
|
|
@ -9,8 +9,8 @@ third_semver=$(echo $new_tag | cut -d "." -f 3)
|
||||||
# Setting the version on the front end
|
# Setting the version on the front end
|
||||||
cd ../../
|
cd ../../
|
||||||
# Setting the version on the backend
|
# Setting the version on the backend
|
||||||
echo "pub const VERSION: &str = \"$new_tag\";" > "src/version.rs"
|
echo "pub const VERSION: &str = \"$new_tag\";" > "lemmy_api/src/version.rs"
|
||||||
git add "src/version.rs"
|
git add "lemmy_api/src/version.rs"
|
||||||
# Setting the version for Ansible
|
# Setting the version for Ansible
|
||||||
echo $new_tag > "ansible/VERSION"
|
echo $new_tag > "ansible/VERSION"
|
||||||
git add "ansible/VERSION"
|
git add "ansible/VERSION"
|
||||||
|
|
|
@ -21,10 +21,12 @@ lemmy-epsilon | lemmy_epsilon | [127.0.0.1:8580](http://127.0.0.1:8580) | uses b
|
||||||
|
|
||||||
You can log into each using the instance name, and `lemmy` as the password, IE (`lemmy_alpha`, `lemmy`).
|
You can log into each using the instance name, and `lemmy` as the password, IE (`lemmy_alpha`, `lemmy`).
|
||||||
|
|
||||||
To start federation between instances, visit one of them and search for a user, community or post, like this:
|
To start federation between instances, visit one of them and search for a user, community or post, like this. Note that
|
||||||
- `!main@lemmy-alpha:8540`
|
the Lemmy backend runs on a different port than the frontend, so you have to increment the port number from
|
||||||
- `http://lemmy-beta:8550/post/3`
|
the URL bar by one.
|
||||||
- `@lemmy-gamma@lemmy-gamma:8560`
|
- `!main@lemmy-alpha:8541`
|
||||||
|
- `http://lemmy-beta:8551/post/3`
|
||||||
|
- `@lemmy-gamma@lemmy-gamma:8561`
|
||||||
|
|
||||||
Firefox containers are a good way to test them interacting.
|
Firefox containers are a good way to test them interacting.
|
||||||
|
|
||||||
|
|
49
lemmy_api/Cargo.toml
Normal file
49
lemmy_api/Cargo.toml
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
[package]
|
||||||
|
name = "lemmy_api"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Felix Ableitner <me@nutomic.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "lemmy_api"
|
||||||
|
path = "src/lib.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
lemmy_apub = { path = "../lemmy_apub" }
|
||||||
|
lemmy_utils = { path = "../lemmy_utils" }
|
||||||
|
lemmy_db = { path = "../lemmy_db" }
|
||||||
|
lemmy_structs = { path = "../lemmy_structs" }
|
||||||
|
lemmy_rate_limit = { path = "../lemmy_rate_limit" }
|
||||||
|
lemmy_websocket = { path = "../lemmy_websocket" }
|
||||||
|
diesel = "1.4"
|
||||||
|
bcrypt = "0.8"
|
||||||
|
chrono = { version = "0.4", features = ["serde"] }
|
||||||
|
serde_json = { version = "1.0", features = ["preserve_order"]}
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
actix = "0.10"
|
||||||
|
actix-web = { version = "3.0", default-features = false }
|
||||||
|
actix-rt = { version = "1.1", default-features = false }
|
||||||
|
awc = { version = "2.0", default-features = false }
|
||||||
|
log = "0.4"
|
||||||
|
rand = "0.7"
|
||||||
|
strum = "0.19"
|
||||||
|
strum_macros = "0.19"
|
||||||
|
jsonwebtoken = "7.0"
|
||||||
|
lazy_static = "1.3"
|
||||||
|
url = { version = "2.1", features = ["serde"] }
|
||||||
|
percent-encoding = "2.1"
|
||||||
|
openssl = "0.10"
|
||||||
|
http = "0.2"
|
||||||
|
http-signature-normalization-actix = { version = "0.4", default-features = false, features = ["sha-2"] }
|
||||||
|
base64 = "0.12"
|
||||||
|
tokio = "0.2"
|
||||||
|
futures = "0.3"
|
||||||
|
itertools = "0.9"
|
||||||
|
uuid = { version = "0.8", features = ["serde", "v4"] }
|
||||||
|
sha2 = "0.9"
|
||||||
|
async-trait = "0.1"
|
||||||
|
captcha = "0.0"
|
||||||
|
anyhow = "1.0"
|
||||||
|
thiserror = "1.0"
|
||||||
|
background-jobs = " 0.8"
|
||||||
|
reqwest = { version = "0.10", features = ["json"] }
|
|
@ -1,16 +1,13 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
api::{
|
check_community_ban,
|
||||||
check_community_ban,
|
get_post,
|
||||||
get_post,
|
get_user_from_jwt,
|
||||||
get_user_from_jwt,
|
get_user_from_jwt_opt,
|
||||||
get_user_from_jwt_opt,
|
is_mod_or_admin,
|
||||||
is_mod_or_admin,
|
Perform,
|
||||||
Perform,
|
|
||||||
},
|
|
||||||
apub::{ApubLikeableType, ApubObjectType},
|
|
||||||
LemmyContext,
|
|
||||||
};
|
};
|
||||||
use actix_web::web::Data;
|
use actix_web::web::Data;
|
||||||
|
use lemmy_apub::{ApubLikeableType, ApubObjectType};
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
comment::*,
|
comment::*,
|
||||||
comment_view::*,
|
comment_view::*,
|
||||||
|
@ -24,12 +21,7 @@ use lemmy_db::{
|
||||||
Saveable,
|
Saveable,
|
||||||
SortType,
|
SortType,
|
||||||
};
|
};
|
||||||
use lemmy_structs::{
|
use lemmy_structs::{blocking, comment::*, send_local_notifs};
|
||||||
blocking,
|
|
||||||
comment::*,
|
|
||||||
send_local_notifs,
|
|
||||||
websocket::{SendComment, UserOperation},
|
|
||||||
};
|
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
apub::{make_apub_endpoint, EndpointType},
|
apub::{make_apub_endpoint, EndpointType},
|
||||||
utils::{remove_slurs, scrape_text_for_mentions},
|
utils::{remove_slurs, scrape_text_for_mentions},
|
||||||
|
@ -37,6 +29,7 @@ use lemmy_utils::{
|
||||||
ConnectionId,
|
ConnectionId,
|
||||||
LemmyError,
|
LemmyError,
|
||||||
};
|
};
|
||||||
|
use lemmy_websocket::{messages::SendComment, LemmyContext, UserOperation};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
|
@ -1,10 +1,7 @@
|
||||||
use crate::{
|
use crate::{get_user_from_jwt, get_user_from_jwt_opt, is_admin, is_mod_or_admin, Perform};
|
||||||
api::{get_user_from_jwt, get_user_from_jwt_opt, is_admin, is_mod_or_admin, Perform},
|
|
||||||
apub::ActorType,
|
|
||||||
LemmyContext,
|
|
||||||
};
|
|
||||||
use actix_web::web::Data;
|
use actix_web::web::Data;
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
|
use lemmy_apub::ActorType;
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
comment::Comment,
|
comment::Comment,
|
||||||
comment_view::CommentQueryBuilder,
|
comment_view::CommentQueryBuilder,
|
||||||
|
@ -22,16 +19,7 @@ use lemmy_db::{
|
||||||
Joinable,
|
Joinable,
|
||||||
SortType,
|
SortType,
|
||||||
};
|
};
|
||||||
use lemmy_structs::{
|
use lemmy_structs::{blocking, community::*};
|
||||||
blocking,
|
|
||||||
community::*,
|
|
||||||
websocket::{
|
|
||||||
GetCommunityUsersOnline,
|
|
||||||
JoinCommunityRoom,
|
|
||||||
SendCommunityRoomMessage,
|
|
||||||
UserOperation,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
apub::{generate_actor_keypair, make_apub_endpoint, EndpointType},
|
apub::{generate_actor_keypair, make_apub_endpoint, EndpointType},
|
||||||
location_info,
|
location_info,
|
||||||
|
@ -40,6 +28,11 @@ use lemmy_utils::{
|
||||||
ConnectionId,
|
ConnectionId,
|
||||||
LemmyError,
|
LemmyError,
|
||||||
};
|
};
|
||||||
|
use lemmy_websocket::{
|
||||||
|
messages::{GetCommunityUsersOnline, JoinCommunityRoom, SendCommunityRoomMessage},
|
||||||
|
LemmyContext,
|
||||||
|
UserOperation,
|
||||||
|
};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
539
lemmy_api/src/lib.rs
Normal file
539
lemmy_api/src/lib.rs
Normal file
|
@ -0,0 +1,539 @@
|
||||||
|
use crate::claims::Claims;
|
||||||
|
use actix_web::{web, web::Data};
|
||||||
|
use anyhow::anyhow;
|
||||||
|
use lemmy_db::{
|
||||||
|
community::Community,
|
||||||
|
community_view::CommunityUserBanView,
|
||||||
|
post::Post,
|
||||||
|
user::User_,
|
||||||
|
Crud,
|
||||||
|
DbPool,
|
||||||
|
};
|
||||||
|
use lemmy_structs::{blocking, comment::*, community::*, post::*, site::*, user::*};
|
||||||
|
use lemmy_utils::{
|
||||||
|
apub::get_apub_protocol_string,
|
||||||
|
request::{retry, RecvError},
|
||||||
|
settings::Settings,
|
||||||
|
APIError,
|
||||||
|
ConnectionId,
|
||||||
|
LemmyError,
|
||||||
|
};
|
||||||
|
use lemmy_websocket::{serialize_websocket_message, LemmyContext, UserOperation};
|
||||||
|
use log::error;
|
||||||
|
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
|
||||||
|
use reqwest::Client;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use std::process::Command;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
pub mod claims;
|
||||||
|
pub mod comment;
|
||||||
|
pub mod community;
|
||||||
|
pub mod post;
|
||||||
|
pub mod site;
|
||||||
|
pub mod user;
|
||||||
|
pub mod version;
|
||||||
|
|
||||||
|
#[async_trait::async_trait(?Send)]
|
||||||
|
pub trait Perform {
|
||||||
|
type Response: serde::ser::Serialize + Send;
|
||||||
|
|
||||||
|
async fn perform(
|
||||||
|
&self,
|
||||||
|
context: &Data<LemmyContext>,
|
||||||
|
websocket_id: Option<ConnectionId>,
|
||||||
|
) -> Result<Self::Response, LemmyError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in crate) async fn is_mod_or_admin(
|
||||||
|
pool: &DbPool,
|
||||||
|
user_id: i32,
|
||||||
|
community_id: i32,
|
||||||
|
) -> Result<(), LemmyError> {
|
||||||
|
let is_mod_or_admin = blocking(pool, move |conn| {
|
||||||
|
Community::is_mod_or_admin(conn, user_id, community_id)
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
if !is_mod_or_admin {
|
||||||
|
return Err(APIError::err("not_a_mod_or_admin").into());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub async fn is_admin(pool: &DbPool, user_id: i32) -> Result<(), LemmyError> {
|
||||||
|
let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
|
||||||
|
if !user.admin {
|
||||||
|
return Err(APIError::err("not_an_admin").into());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in crate) async fn get_post(post_id: i32, pool: &DbPool) -> Result<Post, LemmyError> {
|
||||||
|
match blocking(pool, move |conn| Post::read(conn, post_id)).await? {
|
||||||
|
Ok(post) => Ok(post),
|
||||||
|
Err(_e) => Err(APIError::err("couldnt_find_post").into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in crate) async fn get_user_from_jwt(jwt: &str, pool: &DbPool) -> Result<User_, LemmyError> {
|
||||||
|
let claims = match Claims::decode(&jwt) {
|
||||||
|
Ok(claims) => claims.claims,
|
||||||
|
Err(_e) => return Err(APIError::err("not_logged_in").into()),
|
||||||
|
};
|
||||||
|
let user_id = claims.id;
|
||||||
|
let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
|
||||||
|
// Check for a site ban
|
||||||
|
if user.banned {
|
||||||
|
return Err(APIError::err("site_ban").into());
|
||||||
|
}
|
||||||
|
Ok(user)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in crate) async fn get_user_from_jwt_opt(
|
||||||
|
jwt: &Option<String>,
|
||||||
|
pool: &DbPool,
|
||||||
|
) -> Result<Option<User_>, LemmyError> {
|
||||||
|
match jwt {
|
||||||
|
Some(jwt) => Ok(Some(get_user_from_jwt(jwt, pool).await?)),
|
||||||
|
None => Ok(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in crate) async fn check_community_ban(
|
||||||
|
user_id: i32,
|
||||||
|
community_id: i32,
|
||||||
|
pool: &DbPool,
|
||||||
|
) -> Result<(), LemmyError> {
|
||||||
|
let is_banned = move |conn: &'_ _| CommunityUserBanView::get(conn, user_id, community_id).is_ok();
|
||||||
|
if blocking(pool, is_banned).await? {
|
||||||
|
Err(APIError::err("community_ban").into())
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in crate) async fn linked_instances(pool: &DbPool) -> Result<Vec<String>, LemmyError> {
|
||||||
|
let mut instances: Vec<String> = Vec::new();
|
||||||
|
|
||||||
|
if Settings::get().federation.enabled {
|
||||||
|
let distinct_communities = blocking(pool, move |conn| {
|
||||||
|
Community::distinct_federated_communities(conn)
|
||||||
|
})
|
||||||
|
.await??;
|
||||||
|
|
||||||
|
instances = distinct_communities
|
||||||
|
.iter()
|
||||||
|
.map(|actor_id| Ok(Url::parse(actor_id)?.host_str().unwrap_or("").to_string()))
|
||||||
|
.collect::<Result<Vec<String>, LemmyError>>()?;
|
||||||
|
|
||||||
|
instances.append(&mut Settings::get().get_allowed_instances());
|
||||||
|
instances.retain(|a| {
|
||||||
|
!Settings::get().get_blocked_instances().contains(a)
|
||||||
|
&& !a.eq("")
|
||||||
|
&& !a.eq(&Settings::get().hostname)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sort and remove dupes
|
||||||
|
instances.sort_unstable();
|
||||||
|
instances.dedup();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(instances)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn match_websocket_operation(
|
||||||
|
context: LemmyContext,
|
||||||
|
id: ConnectionId,
|
||||||
|
op: UserOperation,
|
||||||
|
data: &str,
|
||||||
|
) -> Result<String, LemmyError> {
|
||||||
|
match op {
|
||||||
|
// User ops
|
||||||
|
UserOperation::Login => do_websocket_operation::<Login>(context, id, op, data).await,
|
||||||
|
UserOperation::Register => do_websocket_operation::<Register>(context, id, op, data).await,
|
||||||
|
UserOperation::GetCaptcha => do_websocket_operation::<GetCaptcha>(context, id, op, data).await,
|
||||||
|
UserOperation::GetUserDetails => {
|
||||||
|
do_websocket_operation::<GetUserDetails>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::GetReplies => do_websocket_operation::<GetReplies>(context, id, op, data).await,
|
||||||
|
UserOperation::AddAdmin => do_websocket_operation::<AddAdmin>(context, id, op, data).await,
|
||||||
|
UserOperation::BanUser => do_websocket_operation::<BanUser>(context, id, op, data).await,
|
||||||
|
UserOperation::GetUserMentions => {
|
||||||
|
do_websocket_operation::<GetUserMentions>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::MarkUserMentionAsRead => {
|
||||||
|
do_websocket_operation::<MarkUserMentionAsRead>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::MarkAllAsRead => {
|
||||||
|
do_websocket_operation::<MarkAllAsRead>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::DeleteAccount => {
|
||||||
|
do_websocket_operation::<DeleteAccount>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::PasswordReset => {
|
||||||
|
do_websocket_operation::<PasswordReset>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::PasswordChange => {
|
||||||
|
do_websocket_operation::<PasswordChange>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::UserJoin => do_websocket_operation::<UserJoin>(context, id, op, data).await,
|
||||||
|
UserOperation::PostJoin => do_websocket_operation::<PostJoin>(context, id, op, data).await,
|
||||||
|
UserOperation::CommunityJoin => {
|
||||||
|
do_websocket_operation::<CommunityJoin>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::SaveUserSettings => {
|
||||||
|
do_websocket_operation::<SaveUserSettings>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
|
||||||
|
// Private Message ops
|
||||||
|
UserOperation::CreatePrivateMessage => {
|
||||||
|
do_websocket_operation::<CreatePrivateMessage>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::EditPrivateMessage => {
|
||||||
|
do_websocket_operation::<EditPrivateMessage>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::DeletePrivateMessage => {
|
||||||
|
do_websocket_operation::<DeletePrivateMessage>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::MarkPrivateMessageAsRead => {
|
||||||
|
do_websocket_operation::<MarkPrivateMessageAsRead>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::GetPrivateMessages => {
|
||||||
|
do_websocket_operation::<GetPrivateMessages>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
|
||||||
|
// Site ops
|
||||||
|
UserOperation::GetModlog => do_websocket_operation::<GetModlog>(context, id, op, data).await,
|
||||||
|
UserOperation::CreateSite => do_websocket_operation::<CreateSite>(context, id, op, data).await,
|
||||||
|
UserOperation::EditSite => do_websocket_operation::<EditSite>(context, id, op, data).await,
|
||||||
|
UserOperation::GetSite => do_websocket_operation::<GetSite>(context, id, op, data).await,
|
||||||
|
UserOperation::GetSiteConfig => {
|
||||||
|
do_websocket_operation::<GetSiteConfig>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::SaveSiteConfig => {
|
||||||
|
do_websocket_operation::<SaveSiteConfig>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::Search => do_websocket_operation::<Search>(context, id, op, data).await,
|
||||||
|
UserOperation::TransferCommunity => {
|
||||||
|
do_websocket_operation::<TransferCommunity>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::TransferSite => {
|
||||||
|
do_websocket_operation::<TransferSite>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::ListCategories => {
|
||||||
|
do_websocket_operation::<ListCategories>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
|
||||||
|
// Community ops
|
||||||
|
UserOperation::GetCommunity => {
|
||||||
|
do_websocket_operation::<GetCommunity>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::ListCommunities => {
|
||||||
|
do_websocket_operation::<ListCommunities>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::CreateCommunity => {
|
||||||
|
do_websocket_operation::<CreateCommunity>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::EditCommunity => {
|
||||||
|
do_websocket_operation::<EditCommunity>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::DeleteCommunity => {
|
||||||
|
do_websocket_operation::<DeleteCommunity>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::RemoveCommunity => {
|
||||||
|
do_websocket_operation::<RemoveCommunity>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::FollowCommunity => {
|
||||||
|
do_websocket_operation::<FollowCommunity>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::GetFollowedCommunities => {
|
||||||
|
do_websocket_operation::<GetFollowedCommunities>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::BanFromCommunity => {
|
||||||
|
do_websocket_operation::<BanFromCommunity>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::AddModToCommunity => {
|
||||||
|
do_websocket_operation::<AddModToCommunity>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post ops
|
||||||
|
UserOperation::CreatePost => do_websocket_operation::<CreatePost>(context, id, op, data).await,
|
||||||
|
UserOperation::GetPost => do_websocket_operation::<GetPost>(context, id, op, data).await,
|
||||||
|
UserOperation::GetPosts => do_websocket_operation::<GetPosts>(context, id, op, data).await,
|
||||||
|
UserOperation::EditPost => do_websocket_operation::<EditPost>(context, id, op, data).await,
|
||||||
|
UserOperation::DeletePost => do_websocket_operation::<DeletePost>(context, id, op, data).await,
|
||||||
|
UserOperation::RemovePost => do_websocket_operation::<RemovePost>(context, id, op, data).await,
|
||||||
|
UserOperation::LockPost => do_websocket_operation::<LockPost>(context, id, op, data).await,
|
||||||
|
UserOperation::StickyPost => do_websocket_operation::<StickyPost>(context, id, op, data).await,
|
||||||
|
UserOperation::CreatePostLike => {
|
||||||
|
do_websocket_operation::<CreatePostLike>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::SavePost => do_websocket_operation::<SavePost>(context, id, op, data).await,
|
||||||
|
|
||||||
|
// Comment ops
|
||||||
|
UserOperation::CreateComment => {
|
||||||
|
do_websocket_operation::<CreateComment>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::EditComment => {
|
||||||
|
do_websocket_operation::<EditComment>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::DeleteComment => {
|
||||||
|
do_websocket_operation::<DeleteComment>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::RemoveComment => {
|
||||||
|
do_websocket_operation::<RemoveComment>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::MarkCommentAsRead => {
|
||||||
|
do_websocket_operation::<MarkCommentAsRead>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::SaveComment => {
|
||||||
|
do_websocket_operation::<SaveComment>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::GetComments => {
|
||||||
|
do_websocket_operation::<GetComments>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::CreateCommentLike => {
|
||||||
|
do_websocket_operation::<CreateCommentLike>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn do_websocket_operation<'a, 'b, Data>(
|
||||||
|
context: LemmyContext,
|
||||||
|
id: ConnectionId,
|
||||||
|
op: UserOperation,
|
||||||
|
data: &str,
|
||||||
|
) -> Result<String, LemmyError>
|
||||||
|
where
|
||||||
|
for<'de> Data: Deserialize<'de> + 'a,
|
||||||
|
Data: Perform,
|
||||||
|
{
|
||||||
|
let parsed_data: Data = serde_json::from_str(&data)?;
|
||||||
|
let res = parsed_data
|
||||||
|
.perform(&web::Data::new(context), Some(id))
|
||||||
|
.await?;
|
||||||
|
serialize_websocket_message(&op, &res)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn captcha_espeak_wav_base64(captcha: &str) -> Result<String, LemmyError> {
|
||||||
|
let mut built_text = String::new();
|
||||||
|
|
||||||
|
// Building proper speech text for espeak
|
||||||
|
for mut c in captcha.chars() {
|
||||||
|
let new_str = if c.is_alphabetic() {
|
||||||
|
if c.is_lowercase() {
|
||||||
|
c.make_ascii_uppercase();
|
||||||
|
format!("lower case {} ... ", c)
|
||||||
|
} else {
|
||||||
|
c.make_ascii_uppercase();
|
||||||
|
format!("capital {} ... ", c)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
format!("{} ...", c)
|
||||||
|
};
|
||||||
|
|
||||||
|
built_text.push_str(&new_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
espeak_wav_base64(&built_text)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn espeak_wav_base64(text: &str) -> Result<String, LemmyError> {
|
||||||
|
// Make a temp file path
|
||||||
|
let uuid = uuid::Uuid::new_v4().to_string();
|
||||||
|
let file_path = format!("/tmp/lemmy_espeak_{}.wav", &uuid);
|
||||||
|
|
||||||
|
// Write the wav file
|
||||||
|
Command::new("espeak")
|
||||||
|
.arg("-w")
|
||||||
|
.arg(&file_path)
|
||||||
|
.arg(text)
|
||||||
|
.status()?;
|
||||||
|
|
||||||
|
// Read the wav file bytes
|
||||||
|
let bytes = std::fs::read(&file_path)?;
|
||||||
|
|
||||||
|
// Delete the file
|
||||||
|
std::fs::remove_file(file_path)?;
|
||||||
|
|
||||||
|
// Convert to base64
|
||||||
|
let base64 = base64::encode(bytes);
|
||||||
|
|
||||||
|
Ok(base64)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub(crate) struct IframelyResponse {
|
||||||
|
title: Option<String>,
|
||||||
|
description: Option<String>,
|
||||||
|
thumbnail_url: Option<String>,
|
||||||
|
html: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn fetch_iframely(
|
||||||
|
client: &Client,
|
||||||
|
url: &str,
|
||||||
|
) -> Result<IframelyResponse, LemmyError> {
|
||||||
|
let fetch_url = format!("http://iframely/oembed?url={}", url);
|
||||||
|
|
||||||
|
let response = retry(|| client.get(&fetch_url).send()).await?;
|
||||||
|
|
||||||
|
let res: IframelyResponse = response
|
||||||
|
.json()
|
||||||
|
.await
|
||||||
|
.map_err(|e| RecvError(e.to_string()))?;
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug, Clone)]
|
||||||
|
pub(crate) struct PictrsResponse {
|
||||||
|
files: Vec<PictrsFile>,
|
||||||
|
msg: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug, Clone)]
|
||||||
|
pub(crate) struct PictrsFile {
|
||||||
|
file: String,
|
||||||
|
delete_token: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn fetch_pictrs(
|
||||||
|
client: &Client,
|
||||||
|
image_url: &str,
|
||||||
|
) -> Result<PictrsResponse, LemmyError> {
|
||||||
|
is_image_content_type(client, image_url).await?;
|
||||||
|
|
||||||
|
let fetch_url = format!(
|
||||||
|
"http://pictrs:8080/image/download?url={}",
|
||||||
|
utf8_percent_encode(image_url, NON_ALPHANUMERIC) // TODO this might not be needed
|
||||||
|
);
|
||||||
|
|
||||||
|
let response = retry(|| client.get(&fetch_url).send()).await?;
|
||||||
|
|
||||||
|
let response: PictrsResponse = response
|
||||||
|
.json()
|
||||||
|
.await
|
||||||
|
.map_err(|e| RecvError(e.to_string()))?;
|
||||||
|
|
||||||
|
if response.msg == "ok" {
|
||||||
|
Ok(response)
|
||||||
|
} else {
|
||||||
|
Err(anyhow!("{}", &response.msg).into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn fetch_iframely_and_pictrs_data(
|
||||||
|
client: &Client,
|
||||||
|
url: Option<String>,
|
||||||
|
) -> (
|
||||||
|
Option<String>,
|
||||||
|
Option<String>,
|
||||||
|
Option<String>,
|
||||||
|
Option<String>,
|
||||||
|
) {
|
||||||
|
match &url {
|
||||||
|
Some(url) => {
|
||||||
|
// Fetch iframely data
|
||||||
|
let (iframely_title, iframely_description, iframely_thumbnail_url, iframely_html) =
|
||||||
|
match fetch_iframely(client, url).await {
|
||||||
|
Ok(res) => (res.title, res.description, res.thumbnail_url, res.html),
|
||||||
|
Err(e) => {
|
||||||
|
error!("iframely err: {}", e);
|
||||||
|
(None, None, None, None)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fetch pictrs thumbnail
|
||||||
|
let pictrs_hash = match iframely_thumbnail_url {
|
||||||
|
Some(iframely_thumbnail_url) => match fetch_pictrs(client, &iframely_thumbnail_url).await {
|
||||||
|
Ok(res) => Some(res.files[0].file.to_owned()),
|
||||||
|
Err(e) => {
|
||||||
|
error!("pictrs err: {}", e);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Try to generate a small thumbnail if iframely is not supported
|
||||||
|
None => match fetch_pictrs(client, &url).await {
|
||||||
|
Ok(res) => Some(res.files[0].file.to_owned()),
|
||||||
|
Err(e) => {
|
||||||
|
error!("pictrs err: {}", e);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// The full urls are necessary for federation
|
||||||
|
let pictrs_thumbnail = if let Some(pictrs_hash) = pictrs_hash {
|
||||||
|
Some(format!(
|
||||||
|
"{}://{}/pictrs/image/{}",
|
||||||
|
get_apub_protocol_string(),
|
||||||
|
Settings::get().hostname,
|
||||||
|
pictrs_hash
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
(
|
||||||
|
iframely_title,
|
||||||
|
iframely_description,
|
||||||
|
iframely_html,
|
||||||
|
pictrs_thumbnail,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
None => (None, None, None, None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn is_image_content_type(client: &Client, test: &str) -> Result<(), LemmyError> {
|
||||||
|
let response = retry(|| client.get(test).send()).await?;
|
||||||
|
|
||||||
|
if response
|
||||||
|
.headers()
|
||||||
|
.get("Content-Type")
|
||||||
|
.ok_or_else(|| anyhow!("No Content-Type header"))?
|
||||||
|
.to_str()?
|
||||||
|
.starts_with("image/")
|
||||||
|
{
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(anyhow!("Not an image type.").into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::{captcha_espeak_wav_base64, is_image_content_type};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_image() {
|
||||||
|
actix_rt::System::new("tset_image").block_on(async move {
|
||||||
|
let client = reqwest::Client::default();
|
||||||
|
assert!(is_image_content_type(&client, "https://1734811051.rsc.cdn77.org/data/images/full/365645/as-virus-kills-navajos-in-their-homes-tribal-women-provide-lifeline.jpg?w=600?w=650").await.is_ok());
|
||||||
|
assert!(is_image_content_type(&client,
|
||||||
|
"https://twitter.com/BenjaminNorton/status/1259922424272957440?s=20"
|
||||||
|
)
|
||||||
|
.await.is_err()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_espeak() {
|
||||||
|
assert!(captcha_espeak_wav_base64("WxRt2l").is_ok())
|
||||||
|
}
|
||||||
|
|
||||||
|
// These helped with testing
|
||||||
|
// #[test]
|
||||||
|
// fn test_iframely() {
|
||||||
|
// let res = fetch_iframely(client, "https://www.redspark.nu/?p=15341").await;
|
||||||
|
// assert!(res.is_ok());
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn test_pictshare() {
|
||||||
|
// let res = fetch_pictshare("https://upload.wikimedia.org/wikipedia/en/2/27/The_Mandalorian_logo.jpg");
|
||||||
|
// assert!(res.is_ok());
|
||||||
|
// let res_other = fetch_pictshare("https://upload.wikimedia.org/wikipedia/en/2/27/The_Mandalorian_logo.jpgaoeu");
|
||||||
|
// assert!(res_other.is_err());
|
||||||
|
// }
|
||||||
|
}
|
|
@ -1,10 +1,13 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
api::{check_community_ban, get_user_from_jwt, get_user_from_jwt_opt, is_mod_or_admin, Perform},
|
check_community_ban,
|
||||||
apub::{ApubLikeableType, ApubObjectType},
|
|
||||||
fetch_iframely_and_pictrs_data,
|
fetch_iframely_and_pictrs_data,
|
||||||
LemmyContext,
|
get_user_from_jwt,
|
||||||
|
get_user_from_jwt_opt,
|
||||||
|
is_mod_or_admin,
|
||||||
|
Perform,
|
||||||
};
|
};
|
||||||
use actix_web::web::Data;
|
use actix_web::web::Data;
|
||||||
|
use lemmy_apub::{ApubLikeableType, ApubObjectType};
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
comment_view::*,
|
comment_view::*,
|
||||||
community_view::*,
|
community_view::*,
|
||||||
|
@ -19,11 +22,7 @@ use lemmy_db::{
|
||||||
Saveable,
|
Saveable,
|
||||||
SortType,
|
SortType,
|
||||||
};
|
};
|
||||||
use lemmy_structs::{
|
use lemmy_structs::{blocking, post::*};
|
||||||
blocking,
|
|
||||||
post::*,
|
|
||||||
websocket::{GetPostUsersOnline, JoinPostRoom, SendPost, UserOperation},
|
|
||||||
};
|
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
apub::{make_apub_endpoint, EndpointType},
|
apub::{make_apub_endpoint, EndpointType},
|
||||||
utils::{check_slurs, check_slurs_opt, is_valid_post_title},
|
utils::{check_slurs, check_slurs_opt, is_valid_post_title},
|
||||||
|
@ -31,6 +30,11 @@ use lemmy_utils::{
|
||||||
ConnectionId,
|
ConnectionId,
|
||||||
LemmyError,
|
LemmyError,
|
||||||
};
|
};
|
||||||
|
use lemmy_websocket::{
|
||||||
|
messages::{GetPostUsersOnline, JoinPostRoom, SendPost},
|
||||||
|
LemmyContext,
|
||||||
|
UserOperation,
|
||||||
|
};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
api::{get_user_from_jwt, get_user_from_jwt_opt, is_admin, linked_instances, Perform},
|
get_user_from_jwt,
|
||||||
apub::fetcher::search_by_apub_id,
|
get_user_from_jwt_opt,
|
||||||
|
is_admin,
|
||||||
|
linked_instances,
|
||||||
version,
|
version,
|
||||||
LemmyContext,
|
Perform,
|
||||||
};
|
};
|
||||||
use actix_web::web::Data;
|
use actix_web::web::Data;
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
|
use lemmy_apub::fetcher::search_by_apub_id;
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
category::*,
|
category::*,
|
||||||
comment_view::*,
|
comment_view::*,
|
||||||
|
@ -22,12 +25,7 @@ use lemmy_db::{
|
||||||
SearchType,
|
SearchType,
|
||||||
SortType,
|
SortType,
|
||||||
};
|
};
|
||||||
use lemmy_structs::{
|
use lemmy_structs::{blocking, site::*, user::Register};
|
||||||
blocking,
|
|
||||||
site::*,
|
|
||||||
user::Register,
|
|
||||||
websocket::{GetUsersOnline, SendAllMessage, UserOperation},
|
|
||||||
};
|
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
location_info,
|
location_info,
|
||||||
settings::Settings,
|
settings::Settings,
|
||||||
|
@ -36,6 +34,11 @@ use lemmy_utils::{
|
||||||
ConnectionId,
|
ConnectionId,
|
||||||
LemmyError,
|
LemmyError,
|
||||||
};
|
};
|
||||||
|
use lemmy_websocket::{
|
||||||
|
messages::{GetUsersOnline, SendAllMessage},
|
||||||
|
LemmyContext,
|
||||||
|
UserOperation,
|
||||||
|
};
|
||||||
use log::{debug, info};
|
use log::{debug, info};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
api::{claims::Claims, get_user_from_jwt, get_user_from_jwt_opt, is_admin, Perform},
|
|
||||||
apub::ApubObjectType,
|
|
||||||
captcha_espeak_wav_base64,
|
captcha_espeak_wav_base64,
|
||||||
LemmyContext,
|
claims::Claims,
|
||||||
|
get_user_from_jwt,
|
||||||
|
get_user_from_jwt_opt,
|
||||||
|
is_admin,
|
||||||
|
Perform,
|
||||||
};
|
};
|
||||||
use actix_web::web::Data;
|
use actix_web::web::Data;
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use bcrypt::verify;
|
use bcrypt::verify;
|
||||||
use captcha::{gen, Difficulty};
|
use captcha::{gen, Difficulty};
|
||||||
use chrono::Duration;
|
use chrono::Duration;
|
||||||
|
use lemmy_apub::ApubObjectType;
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
comment::*,
|
comment::*,
|
||||||
comment_view::*,
|
comment_view::*,
|
||||||
|
@ -34,18 +37,7 @@ use lemmy_db::{
|
||||||
ListingType,
|
ListingType,
|
||||||
SortType,
|
SortType,
|
||||||
};
|
};
|
||||||
use lemmy_structs::{
|
use lemmy_structs::{blocking, user::*};
|
||||||
blocking,
|
|
||||||
user::*,
|
|
||||||
websocket::{
|
|
||||||
CaptchaItem,
|
|
||||||
CheckCaptcha,
|
|
||||||
JoinUserRoom,
|
|
||||||
SendAllMessage,
|
|
||||||
SendUserRoomMessage,
|
|
||||||
UserOperation,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
apub::{generate_actor_keypair, make_apub_endpoint, EndpointType},
|
apub::{generate_actor_keypair, make_apub_endpoint, EndpointType},
|
||||||
email::send_email,
|
email::send_email,
|
||||||
|
@ -63,6 +55,11 @@ use lemmy_utils::{
|
||||||
ConnectionId,
|
ConnectionId,
|
||||||
LemmyError,
|
LemmyError,
|
||||||
};
|
};
|
||||||
|
use lemmy_websocket::{
|
||||||
|
messages::{CaptchaItem, CheckCaptcha, JoinUserRoom, SendAllMessage, SendUserRoomMessage},
|
||||||
|
LemmyContext,
|
||||||
|
UserOperation,
|
||||||
|
};
|
||||||
use log::error;
|
use log::error;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
47
lemmy_apub/Cargo.toml
Normal file
47
lemmy_apub/Cargo.toml
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
[package]
|
||||||
|
name = "lemmy_apub"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Felix Ableitner <me@nutomic.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "lemmy_apub"
|
||||||
|
path = "src/lib.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
lemmy_utils = { path = "../lemmy_utils" }
|
||||||
|
lemmy_db = { path = "../lemmy_db" }
|
||||||
|
lemmy_structs = { path = "../lemmy_structs" }
|
||||||
|
lemmy_websocket = { path = "../lemmy_websocket" }
|
||||||
|
diesel = "1.4"
|
||||||
|
activitystreams = "0.7.0-alpha.4"
|
||||||
|
activitystreams-ext = "0.1.0-alpha.2"
|
||||||
|
bcrypt = "0.8"
|
||||||
|
chrono = { version = "0.4", features = ["serde"] }
|
||||||
|
serde_json = { version = "1.0", features = ["preserve_order"]}
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
actix = "0.10"
|
||||||
|
actix-web = { version = "3.0", default-features = false }
|
||||||
|
actix-rt = { version = "1.1", default-features = false }
|
||||||
|
awc = { version = "2.0", default-features = false }
|
||||||
|
log = "0.4"
|
||||||
|
rand = "0.7"
|
||||||
|
strum = "0.19"
|
||||||
|
strum_macros = "0.19"
|
||||||
|
lazy_static = "1.3"
|
||||||
|
url = { version = "2.1", features = ["serde"] }
|
||||||
|
percent-encoding = "2.1"
|
||||||
|
openssl = "0.10"
|
||||||
|
http = "0.2"
|
||||||
|
http-signature-normalization-actix = { version = "0.4", default-features = false, features = ["sha-2"] }
|
||||||
|
base64 = "0.12"
|
||||||
|
tokio = "0.2"
|
||||||
|
futures = "0.3"
|
||||||
|
itertools = "0.9"
|
||||||
|
uuid = { version = "0.8", features = ["serde", "v4"] }
|
||||||
|
sha2 = "0.9"
|
||||||
|
async-trait = "0.1"
|
||||||
|
anyhow = "1.0"
|
||||||
|
thiserror = "1.0"
|
||||||
|
background-jobs = " 0.8"
|
||||||
|
reqwest = { version = "0.10", features = ["json"] }
|
|
@ -1,13 +1,11 @@
|
||||||
use crate::{
|
use crate::{activity_queue::send_activity, community::do_announce, insert_activity};
|
||||||
apub::{activity_queue::send_activity, community::do_announce, insert_activity},
|
|
||||||
LemmyContext,
|
|
||||||
};
|
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
base::{Extends, ExtendsExt},
|
base::{Extends, ExtendsExt},
|
||||||
object::AsObject,
|
object::AsObject,
|
||||||
};
|
};
|
||||||
use lemmy_db::{community::Community, user::User_};
|
use lemmy_db::{community::Community, user::User_};
|
||||||
use lemmy_utils::{apub::get_apub_protocol_string, settings::Settings, LemmyError};
|
use lemmy_utils::{apub::get_apub_protocol_string, settings::Settings, LemmyError};
|
||||||
|
use lemmy_websocket::LemmyContext;
|
||||||
use serde::{export::fmt::Debug, Serialize};
|
use serde::{export::fmt::Debug, Serialize};
|
||||||
use url::{ParseError, Url};
|
use url::{ParseError, Url};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
@ -37,7 +35,7 @@ where
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(in crate::apub) fn generate_activity_id<T>(kind: T) -> Result<Url, ParseError>
|
pub(in crate) fn generate_activity_id<T>(kind: T) -> Result<Url, ParseError>
|
||||||
where
|
where
|
||||||
T: ToString,
|
T: ToString,
|
||||||
{
|
{
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::apub::{check_is_apub_id_valid, extensions::signatures::sign, ActorType};
|
use crate::{check_is_apub_id_valid, extensions::signatures::sign, ActorType};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
base::{Extends, ExtendsExt},
|
base::{Extends, ExtendsExt},
|
||||||
object::AsObject,
|
object::AsObject,
|
|
@ -1,24 +1,20 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
apub::{
|
activities::{generate_activity_id, send_activity_to_community},
|
||||||
activities::{generate_activity_id, send_activity_to_community},
|
check_actor_domain,
|
||||||
check_actor_domain,
|
create_apub_response,
|
||||||
create_apub_response,
|
create_apub_tombstone_response,
|
||||||
create_apub_tombstone_response,
|
create_tombstone,
|
||||||
create_tombstone,
|
fetch_webfinger_url,
|
||||||
fetch_webfinger_url,
|
fetcher::{
|
||||||
fetcher::{
|
get_or_fetch_and_insert_comment,
|
||||||
get_or_fetch_and_insert_comment,
|
get_or_fetch_and_insert_post,
|
||||||
get_or_fetch_and_insert_post,
|
get_or_fetch_and_upsert_user,
|
||||||
get_or_fetch_and_upsert_user,
|
|
||||||
},
|
|
||||||
ActorType,
|
|
||||||
ApubLikeableType,
|
|
||||||
ApubObjectType,
|
|
||||||
FromApub,
|
|
||||||
ToApub,
|
|
||||||
},
|
},
|
||||||
DbPool,
|
ActorType,
|
||||||
LemmyContext,
|
ApubLikeableType,
|
||||||
|
ApubObjectType,
|
||||||
|
FromApub,
|
||||||
|
ToApub,
|
||||||
};
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
activity::{
|
activity::{
|
||||||
|
@ -46,6 +42,7 @@ use lemmy_db::{
|
||||||
post::Post,
|
post::Post,
|
||||||
user::User_,
|
user::User_,
|
||||||
Crud,
|
Crud,
|
||||||
|
DbPool,
|
||||||
};
|
};
|
||||||
use lemmy_structs::blocking;
|
use lemmy_structs::blocking;
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
|
@ -53,6 +50,7 @@ use lemmy_utils::{
|
||||||
utils::{convert_datetime, remove_slurs, scrape_text_for_mentions, MentionData},
|
utils::{convert_datetime, remove_slurs, scrape_text_for_mentions, MentionData},
|
||||||
LemmyError,
|
LemmyError,
|
||||||
};
|
};
|
||||||
|
use lemmy_websocket::LemmyContext;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde_json::Error;
|
use serde_json::Error;
|
|
@ -1,21 +1,17 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
apub::{
|
activities::generate_activity_id,
|
||||||
activities::generate_activity_id,
|
activity_queue::send_activity,
|
||||||
activity_queue::send_activity,
|
check_actor_domain,
|
||||||
check_actor_domain,
|
create_apub_response,
|
||||||
create_apub_response,
|
create_apub_tombstone_response,
|
||||||
create_apub_tombstone_response,
|
create_tombstone,
|
||||||
create_tombstone,
|
extensions::group_extensions::GroupExtension,
|
||||||
extensions::group_extensions::GroupExtension,
|
fetcher::{get_or_fetch_and_upsert_actor, get_or_fetch_and_upsert_user},
|
||||||
fetcher::{get_or_fetch_and_upsert_actor, get_or_fetch_and_upsert_user},
|
insert_activity,
|
||||||
insert_activity,
|
ActorType,
|
||||||
ActorType,
|
FromApub,
|
||||||
FromApub,
|
GroupExt,
|
||||||
GroupExt,
|
ToApub,
|
||||||
ToApub,
|
|
||||||
},
|
|
||||||
DbPool,
|
|
||||||
LemmyContext,
|
|
||||||
};
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
activity::{
|
activity::{
|
||||||
|
@ -44,6 +40,7 @@ use lemmy_db::{
|
||||||
naive_now,
|
naive_now,
|
||||||
post::Post,
|
post::Post,
|
||||||
user::User_,
|
user::User_,
|
||||||
|
DbPool,
|
||||||
};
|
};
|
||||||
use lemmy_structs::blocking;
|
use lemmy_structs::blocking;
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
|
@ -52,6 +49,7 @@ use lemmy_utils::{
|
||||||
utils::{check_slurs, check_slurs_opt, convert_datetime},
|
utils::{check_slurs, check_slurs_opt, convert_datetime},
|
||||||
LemmyError,
|
LemmyError,
|
||||||
};
|
};
|
||||||
|
use lemmy_websocket::LemmyContext;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::apub::ActorType;
|
use crate::ActorType;
|
||||||
use activitystreams::unparsed::UnparsedMutExt;
|
use activitystreams::unparsed::UnparsedMutExt;
|
||||||
use activitystreams_ext::UnparsedExtension;
|
use activitystreams_ext::UnparsedExtension;
|
||||||
use actix_web::{client::ClientRequest, HttpRequest};
|
use actix_web::{client::ClientRequest, HttpRequest};
|
|
@ -1,15 +1,11 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
apub::{
|
check_is_apub_id_valid,
|
||||||
check_is_apub_id_valid,
|
ActorType,
|
||||||
ActorType,
|
FromApub,
|
||||||
FromApub,
|
GroupExt,
|
||||||
GroupExt,
|
PageExt,
|
||||||
PageExt,
|
PersonExt,
|
||||||
PersonExt,
|
APUB_JSON_CONTENT_TYPE,
|
||||||
APUB_JSON_CONTENT_TYPE,
|
|
||||||
},
|
|
||||||
request::{retry, RecvError},
|
|
||||||
LemmyContext,
|
|
||||||
};
|
};
|
||||||
use activitystreams::{base::BaseExt, collection::OrderedCollection, object::Note, prelude::*};
|
use activitystreams::{base::BaseExt, collection::OrderedCollection, object::Note, prelude::*};
|
||||||
use anyhow::{anyhow, Context};
|
use anyhow::{anyhow, Context};
|
||||||
|
@ -30,7 +26,13 @@ use lemmy_db::{
|
||||||
SearchType,
|
SearchType,
|
||||||
};
|
};
|
||||||
use lemmy_structs::{blocking, site::SearchResponse};
|
use lemmy_structs::{blocking, site::SearchResponse};
|
||||||
use lemmy_utils::{apub::get_apub_protocol_string, location_info, LemmyError};
|
use lemmy_utils::{
|
||||||
|
apub::get_apub_protocol_string,
|
||||||
|
location_info,
|
||||||
|
request::{retry, RecvError},
|
||||||
|
LemmyError,
|
||||||
|
};
|
||||||
|
use lemmy_websocket::LemmyContext;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
|
@ -1,17 +1,14 @@
|
||||||
use crate::{
|
use crate::inbox::{
|
||||||
apub::inbox::{
|
activities::{
|
||||||
activities::{
|
create::receive_create,
|
||||||
create::receive_create,
|
delete::receive_delete,
|
||||||
delete::receive_delete,
|
dislike::receive_dislike,
|
||||||
dislike::receive_dislike,
|
like::receive_like,
|
||||||
like::receive_like,
|
remove::receive_remove,
|
||||||
remove::receive_remove,
|
undo::receive_undo,
|
||||||
undo::receive_undo,
|
update::receive_update,
|
||||||
update::receive_update,
|
|
||||||
},
|
|
||||||
shared_inbox::{get_community_id_from_activity, receive_unhandled_activity},
|
|
||||||
},
|
},
|
||||||
LemmyContext,
|
shared_inbox::{get_community_id_from_activity, receive_unhandled_activity},
|
||||||
};
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
activity::*,
|
activity::*,
|
||||||
|
@ -21,6 +18,7 @@ use activitystreams::{
|
||||||
use actix_web::HttpResponse;
|
use actix_web::HttpResponse;
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use lemmy_utils::{location_info, LemmyError};
|
use lemmy_utils::{location_info, LemmyError};
|
||||||
|
use lemmy_websocket::LemmyContext;
|
||||||
|
|
||||||
pub async fn receive_announce(
|
pub async fn receive_announce(
|
||||||
activity: AnyBase,
|
activity: AnyBase,
|
|
@ -1,15 +1,12 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
apub::{
|
inbox::shared_inbox::{
|
||||||
inbox::shared_inbox::{
|
announce_if_community_is_local,
|
||||||
announce_if_community_is_local,
|
get_user_from_activity,
|
||||||
get_user_from_activity,
|
receive_unhandled_activity,
|
||||||
receive_unhandled_activity,
|
|
||||||
},
|
|
||||||
ActorType,
|
|
||||||
FromApub,
|
|
||||||
PageExt,
|
|
||||||
},
|
},
|
||||||
LemmyContext,
|
ActorType,
|
||||||
|
FromApub,
|
||||||
|
PageExt,
|
||||||
};
|
};
|
||||||
use activitystreams::{activity::Create, base::AnyBase, object::Note, prelude::*};
|
use activitystreams::{activity::Create, base::AnyBase, object::Note, prelude::*};
|
||||||
use actix_web::HttpResponse;
|
use actix_web::HttpResponse;
|
||||||
|
@ -20,14 +17,13 @@ use lemmy_db::{
|
||||||
post::{Post, PostForm},
|
post::{Post, PostForm},
|
||||||
post_view::PostView,
|
post_view::PostView,
|
||||||
};
|
};
|
||||||
use lemmy_structs::{
|
use lemmy_structs::{blocking, comment::CommentResponse, post::PostResponse, send_local_notifs};
|
||||||
blocking,
|
|
||||||
comment::CommentResponse,
|
|
||||||
post::PostResponse,
|
|
||||||
send_local_notifs,
|
|
||||||
websocket::{SendComment, SendPost, UserOperation},
|
|
||||||
};
|
|
||||||
use lemmy_utils::{location_info, utils::scrape_text_for_mentions, LemmyError};
|
use lemmy_utils::{location_info, utils::scrape_text_for_mentions, LemmyError};
|
||||||
|
use lemmy_websocket::{
|
||||||
|
messages::{SendComment, SendPost},
|
||||||
|
LemmyContext,
|
||||||
|
UserOperation,
|
||||||
|
};
|
||||||
|
|
||||||
pub async fn receive_create(
|
pub async fn receive_create(
|
||||||
activity: AnyBase,
|
activity: AnyBase,
|
|
@ -1,17 +1,14 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
apub::{
|
fetcher::{get_or_fetch_and_insert_comment, get_or_fetch_and_insert_post},
|
||||||
fetcher::{get_or_fetch_and_insert_comment, get_or_fetch_and_insert_post},
|
inbox::shared_inbox::{
|
||||||
inbox::shared_inbox::{
|
announce_if_community_is_local,
|
||||||
announce_if_community_is_local,
|
get_user_from_activity,
|
||||||
get_user_from_activity,
|
receive_unhandled_activity,
|
||||||
receive_unhandled_activity,
|
|
||||||
},
|
|
||||||
ActorType,
|
|
||||||
FromApub,
|
|
||||||
GroupExt,
|
|
||||||
PageExt,
|
|
||||||
},
|
},
|
||||||
LemmyContext,
|
ActorType,
|
||||||
|
FromApub,
|
||||||
|
GroupExt,
|
||||||
|
PageExt,
|
||||||
};
|
};
|
||||||
use activitystreams::{activity::Delete, base::AnyBase, object::Note, prelude::*};
|
use activitystreams::{activity::Delete, base::AnyBase, object::Note, prelude::*};
|
||||||
use actix_web::HttpResponse;
|
use actix_web::HttpResponse;
|
||||||
|
@ -31,9 +28,13 @@ use lemmy_structs::{
|
||||||
comment::CommentResponse,
|
comment::CommentResponse,
|
||||||
community::CommunityResponse,
|
community::CommunityResponse,
|
||||||
post::PostResponse,
|
post::PostResponse,
|
||||||
websocket::{SendComment, SendCommunityRoomMessage, SendPost, UserOperation},
|
|
||||||
};
|
};
|
||||||
use lemmy_utils::{location_info, LemmyError};
|
use lemmy_utils::{location_info, LemmyError};
|
||||||
|
use lemmy_websocket::{
|
||||||
|
messages::{SendComment, SendCommunityRoomMessage, SendPost},
|
||||||
|
LemmyContext,
|
||||||
|
UserOperation,
|
||||||
|
};
|
||||||
|
|
||||||
pub async fn receive_delete(
|
pub async fn receive_delete(
|
||||||
activity: AnyBase,
|
activity: AnyBase,
|
|
@ -1,15 +1,12 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
apub::{
|
fetcher::{get_or_fetch_and_insert_comment, get_or_fetch_and_insert_post},
|
||||||
fetcher::{get_or_fetch_and_insert_comment, get_or_fetch_and_insert_post},
|
inbox::shared_inbox::{
|
||||||
inbox::shared_inbox::{
|
announce_if_community_is_local,
|
||||||
announce_if_community_is_local,
|
get_user_from_activity,
|
||||||
get_user_from_activity,
|
receive_unhandled_activity,
|
||||||
receive_unhandled_activity,
|
|
||||||
},
|
|
||||||
FromApub,
|
|
||||||
PageExt,
|
|
||||||
},
|
},
|
||||||
LemmyContext,
|
FromApub,
|
||||||
|
PageExt,
|
||||||
};
|
};
|
||||||
use activitystreams::{activity::Dislike, base::AnyBase, object::Note, prelude::*};
|
use activitystreams::{activity::Dislike, base::AnyBase, object::Note, prelude::*};
|
||||||
use actix_web::HttpResponse;
|
use actix_web::HttpResponse;
|
||||||
|
@ -21,13 +18,13 @@ use lemmy_db::{
|
||||||
post_view::PostView,
|
post_view::PostView,
|
||||||
Likeable,
|
Likeable,
|
||||||
};
|
};
|
||||||
use lemmy_structs::{
|
use lemmy_structs::{blocking, comment::CommentResponse, post::PostResponse};
|
||||||
blocking,
|
|
||||||
comment::CommentResponse,
|
|
||||||
post::PostResponse,
|
|
||||||
websocket::{SendComment, SendPost, UserOperation},
|
|
||||||
};
|
|
||||||
use lemmy_utils::{location_info, LemmyError};
|
use lemmy_utils::{location_info, LemmyError};
|
||||||
|
use lemmy_websocket::{
|
||||||
|
messages::{SendComment, SendPost},
|
||||||
|
LemmyContext,
|
||||||
|
UserOperation,
|
||||||
|
};
|
||||||
|
|
||||||
pub async fn receive_dislike(
|
pub async fn receive_dislike(
|
||||||
activity: AnyBase,
|
activity: AnyBase,
|
|
@ -1,15 +1,12 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
apub::{
|
fetcher::{get_or_fetch_and_insert_comment, get_or_fetch_and_insert_post},
|
||||||
fetcher::{get_or_fetch_and_insert_comment, get_or_fetch_and_insert_post},
|
inbox::shared_inbox::{
|
||||||
inbox::shared_inbox::{
|
announce_if_community_is_local,
|
||||||
announce_if_community_is_local,
|
get_user_from_activity,
|
||||||
get_user_from_activity,
|
receive_unhandled_activity,
|
||||||
receive_unhandled_activity,
|
|
||||||
},
|
|
||||||
FromApub,
|
|
||||||
PageExt,
|
|
||||||
},
|
},
|
||||||
LemmyContext,
|
FromApub,
|
||||||
|
PageExt,
|
||||||
};
|
};
|
||||||
use activitystreams::{activity::Like, base::AnyBase, object::Note, prelude::*};
|
use activitystreams::{activity::Like, base::AnyBase, object::Note, prelude::*};
|
||||||
use actix_web::HttpResponse;
|
use actix_web::HttpResponse;
|
||||||
|
@ -21,13 +18,13 @@ use lemmy_db::{
|
||||||
post_view::PostView,
|
post_view::PostView,
|
||||||
Likeable,
|
Likeable,
|
||||||
};
|
};
|
||||||
use lemmy_structs::{
|
use lemmy_structs::{blocking, comment::CommentResponse, post::PostResponse};
|
||||||
blocking,
|
|
||||||
comment::CommentResponse,
|
|
||||||
post::PostResponse,
|
|
||||||
websocket::{SendComment, SendPost, UserOperation},
|
|
||||||
};
|
|
||||||
use lemmy_utils::{location_info, LemmyError};
|
use lemmy_utils::{location_info, LemmyError};
|
||||||
|
use lemmy_websocket::{
|
||||||
|
messages::{SendComment, SendPost},
|
||||||
|
LemmyContext,
|
||||||
|
UserOperation,
|
||||||
|
};
|
||||||
|
|
||||||
pub async fn receive_like(
|
pub async fn receive_like(
|
||||||
activity: AnyBase,
|
activity: AnyBase,
|
|
@ -1,18 +1,15 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
apub::{
|
fetcher::{get_or_fetch_and_insert_comment, get_or_fetch_and_insert_post},
|
||||||
fetcher::{get_or_fetch_and_insert_comment, get_or_fetch_and_insert_post},
|
inbox::shared_inbox::{
|
||||||
inbox::shared_inbox::{
|
announce_if_community_is_local,
|
||||||
announce_if_community_is_local,
|
get_community_id_from_activity,
|
||||||
get_community_id_from_activity,
|
get_user_from_activity,
|
||||||
get_user_from_activity,
|
receive_unhandled_activity,
|
||||||
receive_unhandled_activity,
|
|
||||||
},
|
|
||||||
ActorType,
|
|
||||||
FromApub,
|
|
||||||
GroupExt,
|
|
||||||
PageExt,
|
|
||||||
},
|
},
|
||||||
LemmyContext,
|
ActorType,
|
||||||
|
FromApub,
|
||||||
|
GroupExt,
|
||||||
|
PageExt,
|
||||||
};
|
};
|
||||||
use activitystreams::{activity::Remove, base::AnyBase, object::Note, prelude::*};
|
use activitystreams::{activity::Remove, base::AnyBase, object::Note, prelude::*};
|
||||||
use actix_web::HttpResponse;
|
use actix_web::HttpResponse;
|
||||||
|
@ -32,9 +29,13 @@ use lemmy_structs::{
|
||||||
comment::CommentResponse,
|
comment::CommentResponse,
|
||||||
community::CommunityResponse,
|
community::CommunityResponse,
|
||||||
post::PostResponse,
|
post::PostResponse,
|
||||||
websocket::{SendComment, SendCommunityRoomMessage, SendPost, UserOperation},
|
|
||||||
};
|
};
|
||||||
use lemmy_utils::{location_info, LemmyError};
|
use lemmy_utils::{location_info, LemmyError};
|
||||||
|
use lemmy_websocket::{
|
||||||
|
messages::{SendComment, SendCommunityRoomMessage, SendPost},
|
||||||
|
LemmyContext,
|
||||||
|
UserOperation,
|
||||||
|
};
|
||||||
|
|
||||||
pub async fn receive_remove(
|
pub async fn receive_remove(
|
||||||
activity: AnyBase,
|
activity: AnyBase,
|
|
@ -1,17 +1,14 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
apub::{
|
fetcher::{get_or_fetch_and_insert_comment, get_or_fetch_and_insert_post},
|
||||||
fetcher::{get_or_fetch_and_insert_comment, get_or_fetch_and_insert_post},
|
inbox::shared_inbox::{
|
||||||
inbox::shared_inbox::{
|
announce_if_community_is_local,
|
||||||
announce_if_community_is_local,
|
get_user_from_activity,
|
||||||
get_user_from_activity,
|
receive_unhandled_activity,
|
||||||
receive_unhandled_activity,
|
|
||||||
},
|
|
||||||
ActorType,
|
|
||||||
FromApub,
|
|
||||||
GroupExt,
|
|
||||||
PageExt,
|
|
||||||
},
|
},
|
||||||
LemmyContext,
|
ActorType,
|
||||||
|
FromApub,
|
||||||
|
GroupExt,
|
||||||
|
PageExt,
|
||||||
};
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
activity::*,
|
activity::*,
|
||||||
|
@ -37,9 +34,13 @@ use lemmy_structs::{
|
||||||
comment::CommentResponse,
|
comment::CommentResponse,
|
||||||
community::CommunityResponse,
|
community::CommunityResponse,
|
||||||
post::PostResponse,
|
post::PostResponse,
|
||||||
websocket::{SendComment, SendCommunityRoomMessage, SendPost, UserOperation},
|
|
||||||
};
|
};
|
||||||
use lemmy_utils::{location_info, LemmyError};
|
use lemmy_utils::{location_info, LemmyError};
|
||||||
|
use lemmy_websocket::{
|
||||||
|
messages::{SendComment, SendCommunityRoomMessage, SendPost},
|
||||||
|
LemmyContext,
|
||||||
|
UserOperation,
|
||||||
|
};
|
||||||
|
|
||||||
pub async fn receive_undo(
|
pub async fn receive_undo(
|
||||||
activity: AnyBase,
|
activity: AnyBase,
|
|
@ -1,16 +1,13 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
apub::{
|
fetcher::{get_or_fetch_and_insert_comment, get_or_fetch_and_insert_post},
|
||||||
fetcher::{get_or_fetch_and_insert_comment, get_or_fetch_and_insert_post},
|
inbox::shared_inbox::{
|
||||||
inbox::shared_inbox::{
|
announce_if_community_is_local,
|
||||||
announce_if_community_is_local,
|
get_user_from_activity,
|
||||||
get_user_from_activity,
|
receive_unhandled_activity,
|
||||||
receive_unhandled_activity,
|
|
||||||
},
|
|
||||||
ActorType,
|
|
||||||
FromApub,
|
|
||||||
PageExt,
|
|
||||||
},
|
},
|
||||||
LemmyContext,
|
ActorType,
|
||||||
|
FromApub,
|
||||||
|
PageExt,
|
||||||
};
|
};
|
||||||
use activitystreams::{activity::Update, base::AnyBase, object::Note, prelude::*};
|
use activitystreams::{activity::Update, base::AnyBase, object::Note, prelude::*};
|
||||||
use actix_web::HttpResponse;
|
use actix_web::HttpResponse;
|
||||||
|
@ -22,14 +19,13 @@ use lemmy_db::{
|
||||||
post_view::PostView,
|
post_view::PostView,
|
||||||
Crud,
|
Crud,
|
||||||
};
|
};
|
||||||
use lemmy_structs::{
|
use lemmy_structs::{blocking, comment::CommentResponse, post::PostResponse, send_local_notifs};
|
||||||
blocking,
|
|
||||||
comment::CommentResponse,
|
|
||||||
post::PostResponse,
|
|
||||||
send_local_notifs,
|
|
||||||
websocket::{SendComment, SendPost, UserOperation},
|
|
||||||
};
|
|
||||||
use lemmy_utils::{location_info, utils::scrape_text_for_mentions, LemmyError};
|
use lemmy_utils::{location_info, utils::scrape_text_for_mentions, LemmyError};
|
||||||
|
use lemmy_websocket::{
|
||||||
|
messages::{SendComment, SendPost},
|
||||||
|
LemmyContext,
|
||||||
|
UserOperation,
|
||||||
|
};
|
||||||
|
|
||||||
pub async fn receive_update(
|
pub async fn receive_update(
|
||||||
activity: AnyBase,
|
activity: AnyBase,
|
|
@ -1,12 +1,9 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
apub::{
|
check_is_apub_id_valid,
|
||||||
check_is_apub_id_valid,
|
extensions::signatures::verify,
|
||||||
extensions::signatures::verify,
|
fetcher::get_or_fetch_and_upsert_user,
|
||||||
fetcher::get_or_fetch_and_upsert_user,
|
insert_activity,
|
||||||
insert_activity,
|
ActorType,
|
||||||
ActorType,
|
|
||||||
},
|
|
||||||
LemmyContext,
|
|
||||||
};
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
activity::{ActorAndObject, Follow, Undo},
|
activity::{ActorAndObject, Follow, Undo},
|
||||||
|
@ -22,6 +19,7 @@ use lemmy_db::{
|
||||||
};
|
};
|
||||||
use lemmy_structs::blocking;
|
use lemmy_structs::blocking;
|
||||||
use lemmy_utils::{location_info, LemmyError};
|
use lemmy_utils::{location_info, LemmyError};
|
||||||
|
use lemmy_websocket::LemmyContext;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
|
@ -1,26 +1,23 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
apub::{
|
check_is_apub_id_valid,
|
||||||
check_is_apub_id_valid,
|
community::do_announce,
|
||||||
community::do_announce,
|
extensions::signatures::verify,
|
||||||
extensions::signatures::verify,
|
fetcher::{
|
||||||
fetcher::{
|
get_or_fetch_and_upsert_actor,
|
||||||
get_or_fetch_and_upsert_actor,
|
get_or_fetch_and_upsert_community,
|
||||||
get_or_fetch_and_upsert_community,
|
get_or_fetch_and_upsert_user,
|
||||||
get_or_fetch_and_upsert_user,
|
|
||||||
},
|
|
||||||
inbox::activities::{
|
|
||||||
announce::receive_announce,
|
|
||||||
create::receive_create,
|
|
||||||
delete::receive_delete,
|
|
||||||
dislike::receive_dislike,
|
|
||||||
like::receive_like,
|
|
||||||
remove::receive_remove,
|
|
||||||
undo::receive_undo,
|
|
||||||
update::receive_update,
|
|
||||||
},
|
|
||||||
insert_activity,
|
|
||||||
},
|
},
|
||||||
LemmyContext,
|
inbox::activities::{
|
||||||
|
announce::receive_announce,
|
||||||
|
create::receive_create,
|
||||||
|
delete::receive_delete,
|
||||||
|
dislike::receive_dislike,
|
||||||
|
like::receive_like,
|
||||||
|
remove::receive_remove,
|
||||||
|
undo::receive_undo,
|
||||||
|
update::receive_update,
|
||||||
|
},
|
||||||
|
insert_activity,
|
||||||
};
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
activity::{ActorAndObject, ActorAndObjectRef},
|
activity::{ActorAndObject, ActorAndObjectRef},
|
||||||
|
@ -32,6 +29,7 @@ use actix_web::{web, HttpRequest, HttpResponse};
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use lemmy_db::user::User_;
|
use lemmy_db::user::User_;
|
||||||
use lemmy_utils::{location_info, LemmyError};
|
use lemmy_utils::{location_info, LemmyError};
|
||||||
|
use lemmy_websocket::LemmyContext;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
@ -97,7 +95,7 @@ pub async fn shared_inbox(
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(in crate::apub::inbox) fn receive_unhandled_activity<A>(
|
pub(in crate::inbox) fn receive_unhandled_activity<A>(
|
||||||
activity: A,
|
activity: A,
|
||||||
) -> Result<HttpResponse, LemmyError>
|
) -> Result<HttpResponse, LemmyError>
|
||||||
where
|
where
|
||||||
|
@ -107,7 +105,7 @@ where
|
||||||
Ok(HttpResponse::NotImplemented().finish())
|
Ok(HttpResponse::NotImplemented().finish())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(in crate::apub::inbox) async fn get_user_from_activity<T, A>(
|
pub(in crate::inbox) async fn get_user_from_activity<T, A>(
|
||||||
activity: &T,
|
activity: &T,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
) -> Result<User_, LemmyError>
|
) -> Result<User_, LemmyError>
|
||||||
|
@ -119,7 +117,7 @@ where
|
||||||
get_or_fetch_and_upsert_user(&user_uri, context).await
|
get_or_fetch_and_upsert_user(&user_uri, context).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(in crate::apub::inbox) fn get_community_id_from_activity<T, A>(
|
pub(in crate::inbox) fn get_community_id_from_activity<T, A>(
|
||||||
activity: &T,
|
activity: &T,
|
||||||
) -> Result<Url, LemmyError>
|
) -> Result<Url, LemmyError>
|
||||||
where
|
where
|
||||||
|
@ -136,7 +134,7 @@ where
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(in crate::apub::inbox) async fn announce_if_community_is_local<T, Kind>(
|
pub(in crate::inbox) async fn announce_if_community_is_local<T, Kind>(
|
||||||
activity: T,
|
activity: T,
|
||||||
user: &User_,
|
user: &User_,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
|
@ -1,12 +1,9 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
apub::{
|
check_is_apub_id_valid,
|
||||||
check_is_apub_id_valid,
|
extensions::signatures::verify,
|
||||||
extensions::signatures::verify,
|
fetcher::{get_or_fetch_and_upsert_actor, get_or_fetch_and_upsert_community},
|
||||||
fetcher::{get_or_fetch_and_upsert_actor, get_or_fetch_and_upsert_community},
|
insert_activity,
|
||||||
insert_activity,
|
FromApub,
|
||||||
FromApub,
|
|
||||||
},
|
|
||||||
LemmyContext,
|
|
||||||
};
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
activity::{Accept, ActorAndObject, Create, Delete, Undo, Update},
|
activity::{Accept, ActorAndObject, Create, Delete, Undo, Update},
|
||||||
|
@ -25,12 +22,9 @@ use lemmy_db::{
|
||||||
Crud,
|
Crud,
|
||||||
Followable,
|
Followable,
|
||||||
};
|
};
|
||||||
use lemmy_structs::{
|
use lemmy_structs::{blocking, user::PrivateMessageResponse};
|
||||||
blocking,
|
|
||||||
user::PrivateMessageResponse,
|
|
||||||
websocket::{SendUserRoomMessage, UserOperation},
|
|
||||||
};
|
|
||||||
use lemmy_utils::{location_info, LemmyError};
|
use lemmy_utils::{location_info, LemmyError};
|
||||||
|
use lemmy_websocket::{messages::SendUserRoomMessage, LemmyContext, UserOperation};
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
|
@ -1,3 +1,6 @@
|
||||||
|
#[macro_use]
|
||||||
|
extern crate lazy_static;
|
||||||
|
|
||||||
pub mod activities;
|
pub mod activities;
|
||||||
pub mod activity_queue;
|
pub mod activity_queue;
|
||||||
pub mod comment;
|
pub mod comment;
|
||||||
|
@ -9,16 +12,10 @@ pub mod post;
|
||||||
pub mod private_message;
|
pub mod private_message;
|
||||||
pub mod user;
|
pub mod user;
|
||||||
|
|
||||||
use crate::{
|
use crate::extensions::{
|
||||||
apub::extensions::{
|
group_extensions::GroupExtension,
|
||||||
group_extensions::GroupExtension,
|
page_extension::PageExtension,
|
||||||
page_extension::PageExtension,
|
signatures::{PublicKey, PublicKeyExtension},
|
||||||
signatures::{PublicKey, PublicKeyExtension},
|
|
||||||
},
|
|
||||||
request::{retry, RecvError},
|
|
||||||
routes::webfinger::WebFingerResponse,
|
|
||||||
DbPool,
|
|
||||||
LemmyContext,
|
|
||||||
};
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
activity::Follow,
|
activity::Follow,
|
||||||
|
@ -32,15 +29,17 @@ use activitystreams_ext::{Ext1, Ext2};
|
||||||
use actix_web::{body::Body, HttpResponse};
|
use actix_web::{body::Body, HttpResponse};
|
||||||
use anyhow::{anyhow, Context};
|
use anyhow::{anyhow, Context};
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
use lemmy_db::{activity::do_insert_activity, user::User_};
|
use lemmy_db::{activity::do_insert_activity, user::User_, DbPool};
|
||||||
use lemmy_structs::blocking;
|
use lemmy_structs::{blocking, WebFingerResponse};
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
apub::get_apub_protocol_string,
|
apub::get_apub_protocol_string,
|
||||||
location_info,
|
location_info,
|
||||||
|
request::{retry, RecvError},
|
||||||
settings::Settings,
|
settings::Settings,
|
||||||
utils::{convert_datetime, MentionData},
|
utils::{convert_datetime, MentionData},
|
||||||
LemmyError,
|
LemmyError,
|
||||||
};
|
};
|
||||||
|
use lemmy_websocket::LemmyContext;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
@ -191,7 +190,7 @@ pub trait ApubObjectType {
|
||||||
async fn send_undo_remove(&self, mod_: &User_, context: &LemmyContext) -> Result<(), LemmyError>;
|
async fn send_undo_remove(&self, mod_: &User_, context: &LemmyContext) -> Result<(), LemmyError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(in crate::apub) fn check_actor_domain<T, Kind>(
|
pub(in crate) fn check_actor_domain<T, Kind>(
|
||||||
apub: &T,
|
apub: &T,
|
||||||
expected_domain: Option<Url>,
|
expected_domain: Option<Url>,
|
||||||
) -> Result<String, LemmyError>
|
) -> Result<String, LemmyError>
|
|
@ -1,21 +1,17 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
apub::{
|
activities::{generate_activity_id, send_activity_to_community},
|
||||||
activities::{generate_activity_id, send_activity_to_community},
|
check_actor_domain,
|
||||||
check_actor_domain,
|
create_apub_response,
|
||||||
create_apub_response,
|
create_apub_tombstone_response,
|
||||||
create_apub_tombstone_response,
|
create_tombstone,
|
||||||
create_tombstone,
|
extensions::page_extension::PageExtension,
|
||||||
extensions::page_extension::PageExtension,
|
fetcher::{get_or_fetch_and_upsert_community, get_or_fetch_and_upsert_user},
|
||||||
fetcher::{get_or_fetch_and_upsert_community, get_or_fetch_and_upsert_user},
|
ActorType,
|
||||||
ActorType,
|
ApubLikeableType,
|
||||||
ApubLikeableType,
|
ApubObjectType,
|
||||||
ApubObjectType,
|
FromApub,
|
||||||
FromApub,
|
PageExt,
|
||||||
PageExt,
|
ToApub,
|
||||||
ToApub,
|
|
||||||
},
|
|
||||||
DbPool,
|
|
||||||
LemmyContext,
|
|
||||||
};
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
activity::{
|
activity::{
|
||||||
|
@ -40,6 +36,7 @@ use lemmy_db::{
|
||||||
post::{Post, PostForm},
|
post::{Post, PostForm},
|
||||||
user::User_,
|
user::User_,
|
||||||
Crud,
|
Crud,
|
||||||
|
DbPool,
|
||||||
};
|
};
|
||||||
use lemmy_structs::blocking;
|
use lemmy_structs::blocking;
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
|
@ -47,6 +44,7 @@ use lemmy_utils::{
|
||||||
utils::{check_slurs, convert_datetime, remove_slurs},
|
utils::{check_slurs, convert_datetime, remove_slurs},
|
||||||
LemmyError,
|
LemmyError,
|
||||||
};
|
};
|
||||||
|
use lemmy_websocket::LemmyContext;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
|
@ -1,19 +1,15 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
apub::{
|
activities::generate_activity_id,
|
||||||
activities::generate_activity_id,
|
activity_queue::send_activity,
|
||||||
activity_queue::send_activity,
|
check_actor_domain,
|
||||||
check_actor_domain,
|
check_is_apub_id_valid,
|
||||||
check_is_apub_id_valid,
|
create_tombstone,
|
||||||
create_tombstone,
|
fetcher::get_or_fetch_and_upsert_user,
|
||||||
fetcher::get_or_fetch_and_upsert_user,
|
insert_activity,
|
||||||
insert_activity,
|
ActorType,
|
||||||
ActorType,
|
ApubObjectType,
|
||||||
ApubObjectType,
|
FromApub,
|
||||||
FromApub,
|
ToApub,
|
||||||
ToApub,
|
|
||||||
},
|
|
||||||
DbPool,
|
|
||||||
LemmyContext,
|
|
||||||
};
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
activity::{
|
activity::{
|
||||||
|
@ -31,9 +27,11 @@ use lemmy_db::{
|
||||||
private_message::{PrivateMessage, PrivateMessageForm},
|
private_message::{PrivateMessage, PrivateMessageForm},
|
||||||
user::User_,
|
user::User_,
|
||||||
Crud,
|
Crud,
|
||||||
|
DbPool,
|
||||||
};
|
};
|
||||||
use lemmy_structs::blocking;
|
use lemmy_structs::blocking;
|
||||||
use lemmy_utils::{location_info, utils::convert_datetime, LemmyError};
|
use lemmy_utils::{location_info, utils::convert_datetime, LemmyError};
|
||||||
|
use lemmy_websocket::LemmyContext;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
|
@ -1,18 +1,14 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
apub::{
|
activities::generate_activity_id,
|
||||||
activities::generate_activity_id,
|
activity_queue::send_activity,
|
||||||
activity_queue::send_activity,
|
check_actor_domain,
|
||||||
check_actor_domain,
|
create_apub_response,
|
||||||
create_apub_response,
|
fetcher::get_or_fetch_and_upsert_actor,
|
||||||
fetcher::get_or_fetch_and_upsert_actor,
|
insert_activity,
|
||||||
insert_activity,
|
ActorType,
|
||||||
ActorType,
|
FromApub,
|
||||||
FromApub,
|
PersonExt,
|
||||||
PersonExt,
|
ToApub,
|
||||||
ToApub,
|
|
||||||
},
|
|
||||||
DbPool,
|
|
||||||
LemmyContext,
|
|
||||||
};
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
activity::{
|
activity::{
|
||||||
|
@ -30,6 +26,7 @@ use anyhow::Context;
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
naive_now,
|
naive_now,
|
||||||
user::{UserForm, User_},
|
user::{UserForm, User_},
|
||||||
|
DbPool,
|
||||||
};
|
};
|
||||||
use lemmy_structs::blocking;
|
use lemmy_structs::blocking;
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
|
@ -37,6 +34,7 @@ use lemmy_utils::{
|
||||||
utils::{check_slurs, check_slurs_opt, convert_datetime},
|
utils::{check_slurs, check_slurs_opt, convert_datetime},
|
||||||
LemmyError,
|
LemmyError,
|
||||||
};
|
};
|
||||||
|
use lemmy_websocket::LemmyContext;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
|
@ -4,14 +4,6 @@ extern crate diesel;
|
||||||
extern crate strum_macros;
|
extern crate strum_macros;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
extern crate bcrypt;
|
|
||||||
extern crate chrono;
|
|
||||||
extern crate log;
|
|
||||||
extern crate regex;
|
|
||||||
extern crate serde;
|
|
||||||
extern crate serde_json;
|
|
||||||
extern crate sha2;
|
|
||||||
extern crate strum;
|
|
||||||
|
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
use diesel::{result::Error, *};
|
use diesel::{result::Error, *};
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate strum_macros;
|
extern crate strum_macros;
|
||||||
extern crate actix_web;
|
|
||||||
extern crate futures;
|
|
||||||
extern crate log;
|
|
||||||
extern crate tokio;
|
|
||||||
|
|
||||||
use actix_web::dev::{Service, ServiceRequest, ServiceResponse, Transform};
|
use actix_web::dev::{Service, ServiceRequest, ServiceResponse, Transform};
|
||||||
use futures::future::{ok, Ready};
|
use futures::future::{ok, Ready};
|
||||||
|
|
|
@ -14,8 +14,6 @@ lemmy_utils = { path = "../lemmy_utils" }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
diesel = "1.4"
|
diesel = "1.4"
|
||||||
actix = "0.10"
|
|
||||||
actix-web = { version = "3.0" }
|
actix-web = { version = "3.0" }
|
||||||
strum = "0.19"
|
|
||||||
strum_macros = "0.19"
|
|
||||||
chrono = { version = "0.4", features = ["serde"] }
|
chrono = { version = "0.4", features = ["serde"] }
|
||||||
|
serde_json = { version = "1.0", features = ["preserve_order"]}
|
||||||
|
|
|
@ -1,12 +1,3 @@
|
||||||
extern crate actix;
|
|
||||||
extern crate actix_web;
|
|
||||||
extern crate diesel;
|
|
||||||
extern crate log;
|
|
||||||
extern crate serde;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate strum_macros;
|
|
||||||
extern crate chrono;
|
|
||||||
|
|
||||||
pub mod comment;
|
pub mod comment;
|
||||||
pub mod community;
|
pub mod community;
|
||||||
pub mod post;
|
pub mod post;
|
||||||
|
@ -25,6 +16,24 @@ use lemmy_db::{
|
||||||
};
|
};
|
||||||
use lemmy_utils::{email::send_email, settings::Settings, utils::MentionData, LemmyError};
|
use lemmy_utils::{email::send_email, settings::Settings, utils::MentionData, LemmyError};
|
||||||
use log::error;
|
use log::error;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct WebFingerLink {
|
||||||
|
pub rel: Option<String>,
|
||||||
|
#[serde(rename(serialize = "type", deserialize = "type"))]
|
||||||
|
pub type_: Option<String>,
|
||||||
|
pub href: Option<String>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub template: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct WebFingerResponse {
|
||||||
|
pub subject: String,
|
||||||
|
pub aliases: Vec<String>,
|
||||||
|
pub links: Vec<WebFingerLink>,
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn blocking<F, T>(pool: &DbPool, f: F) -> Result<T, LemmyError>
|
pub async fn blocking<F, T>(pool: &DbPool, f: F) -> Result<T, LemmyError>
|
||||||
where
|
where
|
||||||
|
|
|
@ -1,195 +1 @@
|
||||||
use crate::{comment::CommentResponse, post::PostResponse};
|
|
||||||
use actix::{prelude::*, Recipient};
|
|
||||||
use lemmy_utils::{CommunityId, ConnectionId, IPAddr, PostId, UserId};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[derive(EnumString, ToString, Debug, Clone)]
|
|
||||||
pub enum UserOperation {
|
|
||||||
Login,
|
|
||||||
Register,
|
|
||||||
GetCaptcha,
|
|
||||||
CreateCommunity,
|
|
||||||
CreatePost,
|
|
||||||
ListCommunities,
|
|
||||||
ListCategories,
|
|
||||||
GetPost,
|
|
||||||
GetCommunity,
|
|
||||||
CreateComment,
|
|
||||||
EditComment,
|
|
||||||
DeleteComment,
|
|
||||||
RemoveComment,
|
|
||||||
MarkCommentAsRead,
|
|
||||||
SaveComment,
|
|
||||||
CreateCommentLike,
|
|
||||||
GetPosts,
|
|
||||||
CreatePostLike,
|
|
||||||
EditPost,
|
|
||||||
DeletePost,
|
|
||||||
RemovePost,
|
|
||||||
LockPost,
|
|
||||||
StickyPost,
|
|
||||||
SavePost,
|
|
||||||
EditCommunity,
|
|
||||||
DeleteCommunity,
|
|
||||||
RemoveCommunity,
|
|
||||||
FollowCommunity,
|
|
||||||
GetFollowedCommunities,
|
|
||||||
GetUserDetails,
|
|
||||||
GetReplies,
|
|
||||||
GetUserMentions,
|
|
||||||
MarkUserMentionAsRead,
|
|
||||||
GetModlog,
|
|
||||||
BanFromCommunity,
|
|
||||||
AddModToCommunity,
|
|
||||||
CreateSite,
|
|
||||||
EditSite,
|
|
||||||
GetSite,
|
|
||||||
AddAdmin,
|
|
||||||
BanUser,
|
|
||||||
Search,
|
|
||||||
MarkAllAsRead,
|
|
||||||
SaveUserSettings,
|
|
||||||
TransferCommunity,
|
|
||||||
TransferSite,
|
|
||||||
DeleteAccount,
|
|
||||||
PasswordReset,
|
|
||||||
PasswordChange,
|
|
||||||
CreatePrivateMessage,
|
|
||||||
EditPrivateMessage,
|
|
||||||
DeletePrivateMessage,
|
|
||||||
MarkPrivateMessageAsRead,
|
|
||||||
GetPrivateMessages,
|
|
||||||
UserJoin,
|
|
||||||
GetComments,
|
|
||||||
GetSiteConfig,
|
|
||||||
SaveSiteConfig,
|
|
||||||
PostJoin,
|
|
||||||
CommunityJoin,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Chat server sends this messages to session
|
|
||||||
#[derive(Message)]
|
|
||||||
#[rtype(result = "()")]
|
|
||||||
pub struct WSMessage(pub String);
|
|
||||||
|
|
||||||
/// Message for chat server communications
|
|
||||||
|
|
||||||
/// New chat session is created
|
|
||||||
#[derive(Message)]
|
|
||||||
#[rtype(usize)]
|
|
||||||
pub struct Connect {
|
|
||||||
pub addr: Recipient<WSMessage>,
|
|
||||||
pub ip: IPAddr,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Session is disconnected
|
|
||||||
#[derive(Message)]
|
|
||||||
#[rtype(result = "()")]
|
|
||||||
pub struct Disconnect {
|
|
||||||
pub id: ConnectionId,
|
|
||||||
pub ip: IPAddr,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The messages sent to websocket clients
|
|
||||||
#[derive(Serialize, Deserialize, Message)]
|
|
||||||
#[rtype(result = "Result<String, std::convert::Infallible>")]
|
|
||||||
pub struct StandardMessage {
|
|
||||||
/// Id of the client session
|
|
||||||
pub id: ConnectionId,
|
|
||||||
/// Peer message
|
|
||||||
pub msg: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Message)]
|
|
||||||
#[rtype(result = "()")]
|
|
||||||
pub struct SendAllMessage<Response> {
|
|
||||||
pub op: UserOperation,
|
|
||||||
pub response: Response,
|
|
||||||
pub websocket_id: Option<ConnectionId>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Message)]
|
|
||||||
#[rtype(result = "()")]
|
|
||||||
pub struct SendUserRoomMessage<Response> {
|
|
||||||
pub op: UserOperation,
|
|
||||||
pub response: Response,
|
|
||||||
pub recipient_id: UserId,
|
|
||||||
pub websocket_id: Option<ConnectionId>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Message)]
|
|
||||||
#[rtype(result = "()")]
|
|
||||||
pub struct SendCommunityRoomMessage<Response> {
|
|
||||||
pub op: UserOperation,
|
|
||||||
pub response: Response,
|
|
||||||
pub community_id: CommunityId,
|
|
||||||
pub websocket_id: Option<ConnectionId>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Message)]
|
|
||||||
#[rtype(result = "()")]
|
|
||||||
pub struct SendPost {
|
|
||||||
pub op: UserOperation,
|
|
||||||
pub post: PostResponse,
|
|
||||||
pub websocket_id: Option<ConnectionId>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Message)]
|
|
||||||
#[rtype(result = "()")]
|
|
||||||
pub struct SendComment {
|
|
||||||
pub op: UserOperation,
|
|
||||||
pub comment: CommentResponse,
|
|
||||||
pub websocket_id: Option<ConnectionId>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Message)]
|
|
||||||
#[rtype(result = "()")]
|
|
||||||
pub struct JoinUserRoom {
|
|
||||||
pub user_id: UserId,
|
|
||||||
pub id: ConnectionId,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Message)]
|
|
||||||
#[rtype(result = "()")]
|
|
||||||
pub struct JoinCommunityRoom {
|
|
||||||
pub community_id: CommunityId,
|
|
||||||
pub id: ConnectionId,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Message)]
|
|
||||||
#[rtype(result = "()")]
|
|
||||||
pub struct JoinPostRoom {
|
|
||||||
pub post_id: PostId,
|
|
||||||
pub id: ConnectionId,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Message)]
|
|
||||||
#[rtype(usize)]
|
|
||||||
pub struct GetUsersOnline;
|
|
||||||
|
|
||||||
#[derive(Message)]
|
|
||||||
#[rtype(usize)]
|
|
||||||
pub struct GetPostUsersOnline {
|
|
||||||
pub post_id: PostId,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Message)]
|
|
||||||
#[rtype(usize)]
|
|
||||||
pub struct GetCommunityUsersOnline {
|
|
||||||
pub community_id: CommunityId,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Message, Debug)]
|
|
||||||
#[rtype(result = "()")]
|
|
||||||
pub struct CaptchaItem {
|
|
||||||
pub uuid: String,
|
|
||||||
pub answer: String,
|
|
||||||
pub expires: chrono::NaiveDateTime,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Message)]
|
|
||||||
#[rtype(bool)]
|
|
||||||
pub struct CheckCaptcha {
|
|
||||||
pub uuid: String,
|
|
||||||
pub answer: String,
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,8 +7,6 @@ edition = "2018"
|
||||||
name = "lemmy_utils"
|
name = "lemmy_utils"
|
||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
regex = "1.3"
|
regex = "1.3"
|
||||||
config = { version = "0.10", default-features = false, features = ["hjson"] }
|
config = { version = "0.10", default-features = false, features = ["hjson"] }
|
||||||
|
@ -27,3 +25,4 @@ openssl = "0.10"
|
||||||
url = { version = "2.1", features = ["serde"] }
|
url = { version = "2.1", features = ["serde"] }
|
||||||
actix-web = { version = "3.0", default-features = false, features = ["rustls"] }
|
actix-web = { version = "3.0", default-features = false, features = ["rustls"] }
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
|
reqwest = { version = "0.10", features = ["json"] }
|
||||||
|
|
|
@ -1,19 +1,9 @@
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
extern crate actix_web;
|
|
||||||
extern crate anyhow;
|
|
||||||
extern crate comrak;
|
|
||||||
extern crate lettre;
|
|
||||||
extern crate lettre_email;
|
|
||||||
extern crate openssl;
|
|
||||||
extern crate rand;
|
|
||||||
extern crate regex;
|
|
||||||
extern crate serde_json;
|
|
||||||
extern crate thiserror;
|
|
||||||
extern crate url;
|
|
||||||
|
|
||||||
pub mod apub;
|
pub mod apub;
|
||||||
pub mod email;
|
pub mod email;
|
||||||
|
pub mod request;
|
||||||
pub mod settings;
|
pub mod settings;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test;
|
mod test;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
use crate::LemmyError;
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use lemmy_utils::LemmyError;
|
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
28
lemmy_websocket/Cargo.toml
Normal file
28
lemmy_websocket/Cargo.toml
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
[package]
|
||||||
|
name = "lemmy_websocket"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Felix Ableitner <me@nutomic.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "lemmy_websocket"
|
||||||
|
path = "src/lib.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
lemmy_utils = { path = "../lemmy_utils" }
|
||||||
|
lemmy_structs = { path = "../lemmy_structs" }
|
||||||
|
lemmy_db = { path = "../lemmy_db" }
|
||||||
|
lemmy_rate_limit = { path = "../lemmy_rate_limit" }
|
||||||
|
reqwest = { version = "0.10", features = ["json"] }
|
||||||
|
log = "0.4"
|
||||||
|
rand = "0.7"
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_json = { version = "1.0", features = ["preserve_order"]}
|
||||||
|
actix = "0.10"
|
||||||
|
anyhow = "1.0"
|
||||||
|
diesel = "1.4"
|
||||||
|
background-jobs = " 0.8"
|
||||||
|
tokio = "0.2"
|
||||||
|
strum = "0.19"
|
||||||
|
strum_macros = "0.19"
|
||||||
|
chrono = { version = "0.4", features = ["serde"] }
|
|
@ -1,7 +1,4 @@
|
||||||
use crate::{
|
use crate::{messages::*, serialize_websocket_message, LemmyContext, UserOperation};
|
||||||
websocket::handlers::{do_user_operation, to_json_string, Args},
|
|
||||||
LemmyContext,
|
|
||||||
};
|
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
use anyhow::Context as acontext;
|
use anyhow::Context as acontext;
|
||||||
use background_jobs::QueueHandle;
|
use background_jobs::QueueHandle;
|
||||||
|
@ -10,7 +7,7 @@ use diesel::{
|
||||||
PgConnection,
|
PgConnection,
|
||||||
};
|
};
|
||||||
use lemmy_rate_limit::RateLimit;
|
use lemmy_rate_limit::RateLimit;
|
||||||
use lemmy_structs::{comment::*, community::*, post::*, site::*, user::*, websocket::*};
|
use lemmy_structs::{comment::*, post::*};
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
location_info,
|
location_info,
|
||||||
APIError,
|
APIError,
|
||||||
|
@ -29,6 +26,14 @@ use std::{
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
};
|
};
|
||||||
|
use tokio::macros::support::Pin;
|
||||||
|
|
||||||
|
type MessageHandlerType = fn(
|
||||||
|
context: LemmyContext,
|
||||||
|
id: ConnectionId,
|
||||||
|
op: UserOperation,
|
||||||
|
data: &str,
|
||||||
|
) -> Pin<Box<dyn Future<Output = Result<String, LemmyError>> + '_>>;
|
||||||
|
|
||||||
/// `ChatServer` manages chat rooms and responsible for coordinating chat
|
/// `ChatServer` manages chat rooms and responsible for coordinating chat
|
||||||
/// session.
|
/// session.
|
||||||
|
@ -57,6 +62,8 @@ pub struct ChatServer {
|
||||||
/// A list of the current captchas
|
/// A list of the current captchas
|
||||||
pub(super) captchas: Vec<CaptchaItem>,
|
pub(super) captchas: Vec<CaptchaItem>,
|
||||||
|
|
||||||
|
message_handler: MessageHandlerType,
|
||||||
|
|
||||||
/// An HTTP Client
|
/// An HTTP Client
|
||||||
client: Client,
|
client: Client,
|
||||||
|
|
||||||
|
@ -75,6 +82,7 @@ impl ChatServer {
|
||||||
pub fn startup(
|
pub fn startup(
|
||||||
pool: Pool<ConnectionManager<PgConnection>>,
|
pool: Pool<ConnectionManager<PgConnection>>,
|
||||||
rate_limiter: RateLimit,
|
rate_limiter: RateLimit,
|
||||||
|
message_handler: MessageHandlerType,
|
||||||
client: Client,
|
client: Client,
|
||||||
activity_queue: QueueHandle,
|
activity_queue: QueueHandle,
|
||||||
) -> ChatServer {
|
) -> ChatServer {
|
||||||
|
@ -87,6 +95,7 @@ impl ChatServer {
|
||||||
pool,
|
pool,
|
||||||
rate_limiter,
|
rate_limiter,
|
||||||
captchas: Vec::new(),
|
captchas: Vec::new(),
|
||||||
|
message_handler,
|
||||||
client,
|
client,
|
||||||
activity_queue,
|
activity_queue,
|
||||||
}
|
}
|
||||||
|
@ -180,7 +189,7 @@ impl ChatServer {
|
||||||
where
|
where
|
||||||
Response: Serialize,
|
Response: Serialize,
|
||||||
{
|
{
|
||||||
let res_str = &to_json_string(op, response)?;
|
let res_str = &serialize_websocket_message(op, response)?;
|
||||||
if let Some(sessions) = self.post_rooms.get(&post_id) {
|
if let Some(sessions) = self.post_rooms.get(&post_id) {
|
||||||
for id in sessions {
|
for id in sessions {
|
||||||
if let Some(my_id) = websocket_id {
|
if let Some(my_id) = websocket_id {
|
||||||
|
@ -204,7 +213,7 @@ impl ChatServer {
|
||||||
where
|
where
|
||||||
Response: Serialize,
|
Response: Serialize,
|
||||||
{
|
{
|
||||||
let res_str = &to_json_string(op, response)?;
|
let res_str = &serialize_websocket_message(op, response)?;
|
||||||
if let Some(sessions) = self.community_rooms.get(&community_id) {
|
if let Some(sessions) = self.community_rooms.get(&community_id) {
|
||||||
for id in sessions {
|
for id in sessions {
|
||||||
if let Some(my_id) = websocket_id {
|
if let Some(my_id) = websocket_id {
|
||||||
|
@ -227,7 +236,7 @@ impl ChatServer {
|
||||||
where
|
where
|
||||||
Response: Serialize,
|
Response: Serialize,
|
||||||
{
|
{
|
||||||
let res_str = &to_json_string(op, response)?;
|
let res_str = &serialize_websocket_message(op, response)?;
|
||||||
for id in self.sessions.keys() {
|
for id in self.sessions.keys() {
|
||||||
if let Some(my_id) = websocket_id {
|
if let Some(my_id) = websocket_id {
|
||||||
if *id == my_id {
|
if *id == my_id {
|
||||||
|
@ -249,7 +258,7 @@ impl ChatServer {
|
||||||
where
|
where
|
||||||
Response: Serialize,
|
Response: Serialize,
|
||||||
{
|
{
|
||||||
let res_str = &to_json_string(op, response)?;
|
let res_str = &serialize_websocket_message(op, response)?;
|
||||||
if let Some(sessions) = self.user_rooms.get(&recipient_id) {
|
if let Some(sessions) = self.user_rooms.get(&recipient_id) {
|
||||||
for id in sessions {
|
for id in sessions {
|
||||||
if let Some(my_id) = websocket_id {
|
if let Some(my_id) = websocket_id {
|
||||||
|
@ -340,8 +349,6 @@ impl ChatServer {
|
||||||
msg: StandardMessage,
|
msg: StandardMessage,
|
||||||
ctx: &mut Context<Self>,
|
ctx: &mut Context<Self>,
|
||||||
) -> impl Future<Output = Result<String, LemmyError>> {
|
) -> impl Future<Output = Result<String, LemmyError>> {
|
||||||
let addr = ctx.address();
|
|
||||||
let pool = self.pool.clone();
|
|
||||||
let rate_limiter = self.rate_limiter.clone();
|
let rate_limiter = self.rate_limiter.clone();
|
||||||
|
|
||||||
let ip: IPAddr = match self.sessions.get(&msg.id) {
|
let ip: IPAddr = match self.sessions.get(&msg.id) {
|
||||||
|
@ -349,110 +356,27 @@ impl ChatServer {
|
||||||
None => "blank_ip".to_string(),
|
None => "blank_ip".to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let client = self.client.clone();
|
let context = LemmyContext {
|
||||||
let activity_queue = self.activity_queue.clone();
|
pool: self.pool.clone(),
|
||||||
|
chat_server: ctx.address(),
|
||||||
|
client: self.client.to_owned(),
|
||||||
|
activity_queue: self.activity_queue.to_owned(),
|
||||||
|
};
|
||||||
|
let message_handler = self.message_handler;
|
||||||
async move {
|
async move {
|
||||||
let msg = msg;
|
|
||||||
let json: Value = serde_json::from_str(&msg.msg)?;
|
let json: Value = serde_json::from_str(&msg.msg)?;
|
||||||
let data = &json["data"].to_string();
|
let data = &json["data"].to_string();
|
||||||
let op = &json["op"].as_str().ok_or(APIError {
|
let op = &json["op"].as_str().ok_or(APIError {
|
||||||
message: "Unknown op type".to_string(),
|
message: "Unknown op type".to_string(),
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let user_operation: UserOperation = UserOperation::from_str(&op)?;
|
let user_operation = UserOperation::from_str(&op)?;
|
||||||
|
let fut = (message_handler)(context, msg.id, user_operation.clone(), data);
|
||||||
let context = LemmyContext::new(pool, addr, client, activity_queue);
|
|
||||||
let args = Args {
|
|
||||||
context,
|
|
||||||
rate_limiter,
|
|
||||||
id: msg.id,
|
|
||||||
ip,
|
|
||||||
op: user_operation.clone(),
|
|
||||||
data,
|
|
||||||
};
|
|
||||||
|
|
||||||
match user_operation {
|
match user_operation {
|
||||||
// User ops
|
UserOperation::Register => rate_limiter.register().wrap(ip, fut).await,
|
||||||
UserOperation::Login => do_user_operation::<Login>(args).await,
|
UserOperation::CreatePost => rate_limiter.post().wrap(ip, fut).await,
|
||||||
UserOperation::Register => do_user_operation::<Register>(args).await,
|
UserOperation::CreateCommunity => rate_limiter.register().wrap(ip, fut).await,
|
||||||
UserOperation::GetCaptcha => do_user_operation::<GetCaptcha>(args).await,
|
_ => rate_limiter.message().wrap(ip, fut).await,
|
||||||
UserOperation::GetUserDetails => do_user_operation::<GetUserDetails>(args).await,
|
|
||||||
UserOperation::GetReplies => do_user_operation::<GetReplies>(args).await,
|
|
||||||
UserOperation::AddAdmin => do_user_operation::<AddAdmin>(args).await,
|
|
||||||
UserOperation::BanUser => do_user_operation::<BanUser>(args).await,
|
|
||||||
UserOperation::GetUserMentions => do_user_operation::<GetUserMentions>(args).await,
|
|
||||||
UserOperation::MarkUserMentionAsRead => {
|
|
||||||
do_user_operation::<MarkUserMentionAsRead>(args).await
|
|
||||||
}
|
|
||||||
UserOperation::MarkAllAsRead => do_user_operation::<MarkAllAsRead>(args).await,
|
|
||||||
UserOperation::DeleteAccount => do_user_operation::<DeleteAccount>(args).await,
|
|
||||||
UserOperation::PasswordReset => do_user_operation::<PasswordReset>(args).await,
|
|
||||||
UserOperation::PasswordChange => do_user_operation::<PasswordChange>(args).await,
|
|
||||||
UserOperation::UserJoin => do_user_operation::<UserJoin>(args).await,
|
|
||||||
UserOperation::PostJoin => do_user_operation::<PostJoin>(args).await,
|
|
||||||
UserOperation::CommunityJoin => do_user_operation::<CommunityJoin>(args).await,
|
|
||||||
UserOperation::SaveUserSettings => do_user_operation::<SaveUserSettings>(args).await,
|
|
||||||
|
|
||||||
// Private Message ops
|
|
||||||
UserOperation::CreatePrivateMessage => {
|
|
||||||
do_user_operation::<CreatePrivateMessage>(args).await
|
|
||||||
}
|
|
||||||
UserOperation::EditPrivateMessage => do_user_operation::<EditPrivateMessage>(args).await,
|
|
||||||
UserOperation::DeletePrivateMessage => {
|
|
||||||
do_user_operation::<DeletePrivateMessage>(args).await
|
|
||||||
}
|
|
||||||
UserOperation::MarkPrivateMessageAsRead => {
|
|
||||||
do_user_operation::<MarkPrivateMessageAsRead>(args).await
|
|
||||||
}
|
|
||||||
UserOperation::GetPrivateMessages => do_user_operation::<GetPrivateMessages>(args).await,
|
|
||||||
|
|
||||||
// Site ops
|
|
||||||
UserOperation::GetModlog => do_user_operation::<GetModlog>(args).await,
|
|
||||||
UserOperation::CreateSite => do_user_operation::<CreateSite>(args).await,
|
|
||||||
UserOperation::EditSite => do_user_operation::<EditSite>(args).await,
|
|
||||||
UserOperation::GetSite => do_user_operation::<GetSite>(args).await,
|
|
||||||
UserOperation::GetSiteConfig => do_user_operation::<GetSiteConfig>(args).await,
|
|
||||||
UserOperation::SaveSiteConfig => do_user_operation::<SaveSiteConfig>(args).await,
|
|
||||||
UserOperation::Search => do_user_operation::<Search>(args).await,
|
|
||||||
UserOperation::TransferCommunity => do_user_operation::<TransferCommunity>(args).await,
|
|
||||||
UserOperation::TransferSite => do_user_operation::<TransferSite>(args).await,
|
|
||||||
UserOperation::ListCategories => do_user_operation::<ListCategories>(args).await,
|
|
||||||
|
|
||||||
// Community ops
|
|
||||||
UserOperation::GetCommunity => do_user_operation::<GetCommunity>(args).await,
|
|
||||||
UserOperation::ListCommunities => do_user_operation::<ListCommunities>(args).await,
|
|
||||||
UserOperation::CreateCommunity => do_user_operation::<CreateCommunity>(args).await,
|
|
||||||
UserOperation::EditCommunity => do_user_operation::<EditCommunity>(args).await,
|
|
||||||
UserOperation::DeleteCommunity => do_user_operation::<DeleteCommunity>(args).await,
|
|
||||||
UserOperation::RemoveCommunity => do_user_operation::<RemoveCommunity>(args).await,
|
|
||||||
UserOperation::FollowCommunity => do_user_operation::<FollowCommunity>(args).await,
|
|
||||||
UserOperation::GetFollowedCommunities => {
|
|
||||||
do_user_operation::<GetFollowedCommunities>(args).await
|
|
||||||
}
|
|
||||||
UserOperation::BanFromCommunity => do_user_operation::<BanFromCommunity>(args).await,
|
|
||||||
UserOperation::AddModToCommunity => do_user_operation::<AddModToCommunity>(args).await,
|
|
||||||
|
|
||||||
// Post ops
|
|
||||||
UserOperation::CreatePost => do_user_operation::<CreatePost>(args).await,
|
|
||||||
UserOperation::GetPost => do_user_operation::<GetPost>(args).await,
|
|
||||||
UserOperation::GetPosts => do_user_operation::<GetPosts>(args).await,
|
|
||||||
UserOperation::EditPost => do_user_operation::<EditPost>(args).await,
|
|
||||||
UserOperation::DeletePost => do_user_operation::<DeletePost>(args).await,
|
|
||||||
UserOperation::RemovePost => do_user_operation::<RemovePost>(args).await,
|
|
||||||
UserOperation::LockPost => do_user_operation::<LockPost>(args).await,
|
|
||||||
UserOperation::StickyPost => do_user_operation::<StickyPost>(args).await,
|
|
||||||
UserOperation::CreatePostLike => do_user_operation::<CreatePostLike>(args).await,
|
|
||||||
UserOperation::SavePost => do_user_operation::<SavePost>(args).await,
|
|
||||||
|
|
||||||
// Comment ops
|
|
||||||
UserOperation::CreateComment => do_user_operation::<CreateComment>(args).await,
|
|
||||||
UserOperation::EditComment => do_user_operation::<EditComment>(args).await,
|
|
||||||
UserOperation::DeleteComment => do_user_operation::<DeleteComment>(args).await,
|
|
||||||
UserOperation::RemoveComment => do_user_operation::<RemoveComment>(args).await,
|
|
||||||
UserOperation::MarkCommentAsRead => do_user_operation::<MarkCommentAsRead>(args).await,
|
|
||||||
UserOperation::SaveComment => do_user_operation::<SaveComment>(args).await,
|
|
||||||
UserOperation::GetComments => do_user_operation::<GetComments>(args).await,
|
|
||||||
UserOperation::CreateCommentLike => do_user_operation::<CreateCommentLike>(args).await,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,59 +1,12 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
api::Perform,
|
chat_server::{ChatServer, SessionInfo},
|
||||||
websocket::chat_server::{ChatServer, SessionInfo},
|
messages::*,
|
||||||
LemmyContext,
|
|
||||||
};
|
};
|
||||||
use actix::{Actor, Context, Handler, ResponseFuture};
|
use actix::{Actor, Context, Handler, ResponseFuture};
|
||||||
use actix_web::web;
|
|
||||||
use lemmy_db::naive_now;
|
use lemmy_db::naive_now;
|
||||||
use lemmy_rate_limit::RateLimit;
|
|
||||||
use lemmy_structs::websocket::*;
|
|
||||||
use lemmy_utils::{ConnectionId, IPAddr, LemmyError};
|
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::Serialize;
|
||||||
|
|
||||||
pub(super) struct Args<'a> {
|
|
||||||
pub(super) context: LemmyContext,
|
|
||||||
pub(super) rate_limiter: RateLimit,
|
|
||||||
pub(super) id: ConnectionId,
|
|
||||||
pub(super) ip: IPAddr,
|
|
||||||
pub(super) op: UserOperation,
|
|
||||||
pub(super) data: &'a str,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) async fn do_user_operation<'a, 'b, Data>(args: Args<'b>) -> Result<String, LemmyError>
|
|
||||||
where
|
|
||||||
for<'de> Data: Deserialize<'de> + 'a,
|
|
||||||
Data: Perform,
|
|
||||||
{
|
|
||||||
let Args {
|
|
||||||
context,
|
|
||||||
rate_limiter,
|
|
||||||
id,
|
|
||||||
ip,
|
|
||||||
op,
|
|
||||||
data,
|
|
||||||
} = args;
|
|
||||||
|
|
||||||
let data = data.to_string();
|
|
||||||
let op2 = op.clone();
|
|
||||||
|
|
||||||
let fut = async move {
|
|
||||||
let parsed_data: Data = serde_json::from_str(&data)?;
|
|
||||||
let res = parsed_data
|
|
||||||
.perform(&web::Data::new(context), Some(id))
|
|
||||||
.await?;
|
|
||||||
to_json_string(&op, &res)
|
|
||||||
};
|
|
||||||
|
|
||||||
match op2 {
|
|
||||||
UserOperation::Register => rate_limiter.register().wrap(ip, fut).await,
|
|
||||||
UserOperation::CreatePost => rate_limiter.post().wrap(ip, fut).await,
|
|
||||||
UserOperation::CreateCommunity => rate_limiter.register().wrap(ip, fut).await,
|
|
||||||
_ => rate_limiter.message().wrap(ip, fut).await,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Make actor from `ChatServer`
|
/// Make actor from `ChatServer`
|
||||||
impl Actor for ChatServer {
|
impl Actor for ChatServer {
|
||||||
|
@ -241,26 +194,6 @@ impl Handler<GetCommunityUsersOnline> for ChatServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
|
||||||
struct WebsocketResponse<T> {
|
|
||||||
op: String,
|
|
||||||
data: T,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn to_json_string<Response>(
|
|
||||||
op: &UserOperation,
|
|
||||||
data: &Response,
|
|
||||||
) -> Result<String, LemmyError>
|
|
||||||
where
|
|
||||||
Response: Serialize,
|
|
||||||
{
|
|
||||||
let response = WebsocketResponse {
|
|
||||||
op: op.to_string(),
|
|
||||||
data,
|
|
||||||
};
|
|
||||||
Ok(serde_json::to_string(&response)?)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Handler<CaptchaItem> for ChatServer {
|
impl Handler<CaptchaItem> for ChatServer {
|
||||||
type Result = ();
|
type Result = ();
|
||||||
|
|
144
lemmy_websocket/src/lib.rs
Normal file
144
lemmy_websocket/src/lib.rs
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
#[macro_use]
|
||||||
|
extern crate strum_macros;
|
||||||
|
|
||||||
|
use crate::chat_server::ChatServer;
|
||||||
|
use actix::Addr;
|
||||||
|
use background_jobs::QueueHandle;
|
||||||
|
use lemmy_db::DbPool;
|
||||||
|
use lemmy_utils::LemmyError;
|
||||||
|
use reqwest::Client;
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
pub mod chat_server;
|
||||||
|
pub mod handlers;
|
||||||
|
pub mod messages;
|
||||||
|
|
||||||
|
pub struct LemmyContext {
|
||||||
|
pub pool: DbPool,
|
||||||
|
pub chat_server: Addr<ChatServer>,
|
||||||
|
pub client: Client,
|
||||||
|
pub activity_queue: QueueHandle,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LemmyContext {
|
||||||
|
pub fn create(
|
||||||
|
pool: DbPool,
|
||||||
|
chat_server: Addr<ChatServer>,
|
||||||
|
client: Client,
|
||||||
|
activity_queue: QueueHandle,
|
||||||
|
) -> LemmyContext {
|
||||||
|
LemmyContext {
|
||||||
|
pool,
|
||||||
|
chat_server,
|
||||||
|
client,
|
||||||
|
activity_queue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn pool(&self) -> &DbPool {
|
||||||
|
&self.pool
|
||||||
|
}
|
||||||
|
pub fn chat_server(&self) -> &Addr<ChatServer> {
|
||||||
|
&self.chat_server
|
||||||
|
}
|
||||||
|
pub fn client(&self) -> &Client {
|
||||||
|
&self.client
|
||||||
|
}
|
||||||
|
pub fn activity_queue(&self) -> &QueueHandle {
|
||||||
|
&self.activity_queue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for LemmyContext {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
LemmyContext {
|
||||||
|
pool: self.pool.clone(),
|
||||||
|
chat_server: self.chat_server.clone(),
|
||||||
|
client: self.client.clone(),
|
||||||
|
activity_queue: self.activity_queue.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct WebsocketResponse<T> {
|
||||||
|
op: String,
|
||||||
|
data: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn serialize_websocket_message<Response>(
|
||||||
|
op: &UserOperation,
|
||||||
|
data: &Response,
|
||||||
|
) -> Result<String, LemmyError>
|
||||||
|
where
|
||||||
|
Response: Serialize,
|
||||||
|
{
|
||||||
|
let response = WebsocketResponse {
|
||||||
|
op: op.to_string(),
|
||||||
|
data,
|
||||||
|
};
|
||||||
|
Ok(serde_json::to_string(&response)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(EnumString, ToString, Debug, Clone)]
|
||||||
|
pub enum UserOperation {
|
||||||
|
Login,
|
||||||
|
Register,
|
||||||
|
GetCaptcha,
|
||||||
|
CreateCommunity,
|
||||||
|
CreatePost,
|
||||||
|
ListCommunities,
|
||||||
|
ListCategories,
|
||||||
|
GetPost,
|
||||||
|
GetCommunity,
|
||||||
|
CreateComment,
|
||||||
|
EditComment,
|
||||||
|
DeleteComment,
|
||||||
|
RemoveComment,
|
||||||
|
MarkCommentAsRead,
|
||||||
|
SaveComment,
|
||||||
|
CreateCommentLike,
|
||||||
|
GetPosts,
|
||||||
|
CreatePostLike,
|
||||||
|
EditPost,
|
||||||
|
DeletePost,
|
||||||
|
RemovePost,
|
||||||
|
LockPost,
|
||||||
|
StickyPost,
|
||||||
|
SavePost,
|
||||||
|
EditCommunity,
|
||||||
|
DeleteCommunity,
|
||||||
|
RemoveCommunity,
|
||||||
|
FollowCommunity,
|
||||||
|
GetFollowedCommunities,
|
||||||
|
GetUserDetails,
|
||||||
|
GetReplies,
|
||||||
|
GetUserMentions,
|
||||||
|
MarkUserMentionAsRead,
|
||||||
|
GetModlog,
|
||||||
|
BanFromCommunity,
|
||||||
|
AddModToCommunity,
|
||||||
|
CreateSite,
|
||||||
|
EditSite,
|
||||||
|
GetSite,
|
||||||
|
AddAdmin,
|
||||||
|
BanUser,
|
||||||
|
Search,
|
||||||
|
MarkAllAsRead,
|
||||||
|
SaveUserSettings,
|
||||||
|
TransferCommunity,
|
||||||
|
TransferSite,
|
||||||
|
DeleteAccount,
|
||||||
|
PasswordReset,
|
||||||
|
PasswordChange,
|
||||||
|
CreatePrivateMessage,
|
||||||
|
EditPrivateMessage,
|
||||||
|
DeletePrivateMessage,
|
||||||
|
MarkPrivateMessageAsRead,
|
||||||
|
GetPrivateMessages,
|
||||||
|
UserJoin,
|
||||||
|
GetComments,
|
||||||
|
GetSiteConfig,
|
||||||
|
SaveSiteConfig,
|
||||||
|
PostJoin,
|
||||||
|
CommunityJoin,
|
||||||
|
}
|
132
lemmy_websocket/src/messages.rs
Normal file
132
lemmy_websocket/src/messages.rs
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
use crate::UserOperation;
|
||||||
|
use actix::{prelude::*, Recipient};
|
||||||
|
use lemmy_structs::{comment::CommentResponse, post::PostResponse};
|
||||||
|
use lemmy_utils::{CommunityId, ConnectionId, IPAddr, PostId, UserId};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
/// Chat server sends this messages to session
|
||||||
|
#[derive(Message)]
|
||||||
|
#[rtype(result = "()")]
|
||||||
|
pub struct WSMessage(pub String);
|
||||||
|
|
||||||
|
/// Message for chat server communications
|
||||||
|
|
||||||
|
/// New chat session is created
|
||||||
|
#[derive(Message)]
|
||||||
|
#[rtype(usize)]
|
||||||
|
pub struct Connect {
|
||||||
|
pub addr: Recipient<WSMessage>,
|
||||||
|
pub ip: IPAddr,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Session is disconnected
|
||||||
|
#[derive(Message)]
|
||||||
|
#[rtype(result = "()")]
|
||||||
|
pub struct Disconnect {
|
||||||
|
pub id: ConnectionId,
|
||||||
|
pub ip: IPAddr,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The messages sent to websocket clients
|
||||||
|
#[derive(Serialize, Deserialize, Message)]
|
||||||
|
#[rtype(result = "Result<String, std::convert::Infallible>")]
|
||||||
|
pub struct StandardMessage {
|
||||||
|
/// Id of the client session
|
||||||
|
pub id: ConnectionId,
|
||||||
|
/// Peer message
|
||||||
|
pub msg: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Message)]
|
||||||
|
#[rtype(result = "()")]
|
||||||
|
pub struct SendAllMessage<Response> {
|
||||||
|
pub op: UserOperation,
|
||||||
|
pub response: Response,
|
||||||
|
pub websocket_id: Option<ConnectionId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Message)]
|
||||||
|
#[rtype(result = "()")]
|
||||||
|
pub struct SendUserRoomMessage<Response> {
|
||||||
|
pub op: UserOperation,
|
||||||
|
pub response: Response,
|
||||||
|
pub recipient_id: UserId,
|
||||||
|
pub websocket_id: Option<ConnectionId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Message)]
|
||||||
|
#[rtype(result = "()")]
|
||||||
|
pub struct SendCommunityRoomMessage<Response> {
|
||||||
|
pub op: UserOperation,
|
||||||
|
pub response: Response,
|
||||||
|
pub community_id: CommunityId,
|
||||||
|
pub websocket_id: Option<ConnectionId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Message)]
|
||||||
|
#[rtype(result = "()")]
|
||||||
|
pub struct SendPost {
|
||||||
|
pub op: UserOperation,
|
||||||
|
pub post: PostResponse,
|
||||||
|
pub websocket_id: Option<ConnectionId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Message)]
|
||||||
|
#[rtype(result = "()")]
|
||||||
|
pub struct SendComment {
|
||||||
|
pub op: UserOperation,
|
||||||
|
pub comment: CommentResponse,
|
||||||
|
pub websocket_id: Option<ConnectionId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Message)]
|
||||||
|
#[rtype(result = "()")]
|
||||||
|
pub struct JoinUserRoom {
|
||||||
|
pub user_id: UserId,
|
||||||
|
pub id: ConnectionId,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Message)]
|
||||||
|
#[rtype(result = "()")]
|
||||||
|
pub struct JoinCommunityRoom {
|
||||||
|
pub community_id: CommunityId,
|
||||||
|
pub id: ConnectionId,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Message)]
|
||||||
|
#[rtype(result = "()")]
|
||||||
|
pub struct JoinPostRoom {
|
||||||
|
pub post_id: PostId,
|
||||||
|
pub id: ConnectionId,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Message)]
|
||||||
|
#[rtype(usize)]
|
||||||
|
pub struct GetUsersOnline;
|
||||||
|
|
||||||
|
#[derive(Message)]
|
||||||
|
#[rtype(usize)]
|
||||||
|
pub struct GetPostUsersOnline {
|
||||||
|
pub post_id: PostId,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Message)]
|
||||||
|
#[rtype(usize)]
|
||||||
|
pub struct GetCommunityUsersOnline {
|
||||||
|
pub community_id: CommunityId,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Message, Debug)]
|
||||||
|
#[rtype(result = "()")]
|
||||||
|
pub struct CaptchaItem {
|
||||||
|
pub uuid: String,
|
||||||
|
pub answer: String,
|
||||||
|
pub expires: chrono::NaiveDateTime,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Message)]
|
||||||
|
#[rtype(bool)]
|
||||||
|
pub struct CheckCaptcha {
|
||||||
|
pub uuid: String,
|
||||||
|
pub answer: String,
|
||||||
|
}
|
128
src/api/mod.rs
128
src/api/mod.rs
|
@ -1,128 +0,0 @@
|
||||||
use crate::{api::claims::Claims, DbPool, LemmyContext};
|
|
||||||
use actix_web::web::Data;
|
|
||||||
use lemmy_db::{
|
|
||||||
community::Community,
|
|
||||||
community_view::CommunityUserBanView,
|
|
||||||
post::Post,
|
|
||||||
user::User_,
|
|
||||||
Crud,
|
|
||||||
};
|
|
||||||
use lemmy_structs::blocking;
|
|
||||||
use lemmy_utils::{settings::Settings, APIError, ConnectionId, LemmyError};
|
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
pub mod claims;
|
|
||||||
pub mod comment;
|
|
||||||
pub mod community;
|
|
||||||
pub mod post;
|
|
||||||
pub mod site;
|
|
||||||
pub mod user;
|
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
|
||||||
pub trait Perform {
|
|
||||||
type Response: serde::ser::Serialize + Send;
|
|
||||||
|
|
||||||
async fn perform(
|
|
||||||
&self,
|
|
||||||
context: &Data<LemmyContext>,
|
|
||||||
websocket_id: Option<ConnectionId>,
|
|
||||||
) -> Result<Self::Response, LemmyError>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(in crate::api) async fn is_mod_or_admin(
|
|
||||||
pool: &DbPool,
|
|
||||||
user_id: i32,
|
|
||||||
community_id: i32,
|
|
||||||
) -> Result<(), LemmyError> {
|
|
||||||
let is_mod_or_admin = blocking(pool, move |conn| {
|
|
||||||
Community::is_mod_or_admin(conn, user_id, community_id)
|
|
||||||
})
|
|
||||||
.await?;
|
|
||||||
if !is_mod_or_admin {
|
|
||||||
return Err(APIError::err("not_a_mod_or_admin").into());
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
pub async fn is_admin(pool: &DbPool, user_id: i32) -> Result<(), LemmyError> {
|
|
||||||
let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
|
|
||||||
if !user.admin {
|
|
||||||
return Err(APIError::err("not_an_admin").into());
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(in crate::api) async fn get_post(post_id: i32, pool: &DbPool) -> Result<Post, LemmyError> {
|
|
||||||
match blocking(pool, move |conn| Post::read(conn, post_id)).await? {
|
|
||||||
Ok(post) => Ok(post),
|
|
||||||
Err(_e) => Err(APIError::err("couldnt_find_post").into()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(in crate::api) async fn get_user_from_jwt(
|
|
||||||
jwt: &str,
|
|
||||||
pool: &DbPool,
|
|
||||||
) -> Result<User_, LemmyError> {
|
|
||||||
let claims = match Claims::decode(&jwt) {
|
|
||||||
Ok(claims) => claims.claims,
|
|
||||||
Err(_e) => return Err(APIError::err("not_logged_in").into()),
|
|
||||||
};
|
|
||||||
let user_id = claims.id;
|
|
||||||
let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
|
|
||||||
// Check for a site ban
|
|
||||||
if user.banned {
|
|
||||||
return Err(APIError::err("site_ban").into());
|
|
||||||
}
|
|
||||||
Ok(user)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(in crate::api) async fn get_user_from_jwt_opt(
|
|
||||||
jwt: &Option<String>,
|
|
||||||
pool: &DbPool,
|
|
||||||
) -> Result<Option<User_>, LemmyError> {
|
|
||||||
match jwt {
|
|
||||||
Some(jwt) => Ok(Some(get_user_from_jwt(jwt, pool).await?)),
|
|
||||||
None => Ok(None),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(in crate::api) async fn check_community_ban(
|
|
||||||
user_id: i32,
|
|
||||||
community_id: i32,
|
|
||||||
pool: &DbPool,
|
|
||||||
) -> Result<(), LemmyError> {
|
|
||||||
let is_banned = move |conn: &'_ _| CommunityUserBanView::get(conn, user_id, community_id).is_ok();
|
|
||||||
if blocking(pool, is_banned).await? {
|
|
||||||
Err(APIError::err("community_ban").into())
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(in crate::api) async fn linked_instances(pool: &DbPool) -> Result<Vec<String>, LemmyError> {
|
|
||||||
let mut instances: Vec<String> = Vec::new();
|
|
||||||
|
|
||||||
if Settings::get().federation.enabled {
|
|
||||||
let distinct_communities = blocking(pool, move |conn| {
|
|
||||||
Community::distinct_federated_communities(conn)
|
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
|
|
||||||
instances = distinct_communities
|
|
||||||
.iter()
|
|
||||||
.map(|actor_id| Ok(Url::parse(actor_id)?.host_str().unwrap_or("").to_string()))
|
|
||||||
.collect::<Result<Vec<String>, LemmyError>>()?;
|
|
||||||
|
|
||||||
instances.append(&mut Settings::get().get_allowed_instances());
|
|
||||||
instances.retain(|a| {
|
|
||||||
!Settings::get().get_blocked_instances().contains(a)
|
|
||||||
&& !a.eq("")
|
|
||||||
&& !a.eq(&Settings::get().hostname)
|
|
||||||
});
|
|
||||||
|
|
||||||
// Sort and remove dupes
|
|
||||||
instances.sort_unstable();
|
|
||||||
instances.dedup();
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(instances)
|
|
||||||
}
|
|
303
src/lib.rs
303
src/lib.rs
|
@ -1,307 +1,4 @@
|
||||||
#![recursion_limit = "512"]
|
#![recursion_limit = "512"]
|
||||||
#[macro_use]
|
|
||||||
extern crate lazy_static;
|
|
||||||
extern crate actix;
|
|
||||||
extern crate actix_web;
|
|
||||||
extern crate base64;
|
|
||||||
extern crate bcrypt;
|
|
||||||
extern crate captcha;
|
|
||||||
extern crate chrono;
|
|
||||||
extern crate diesel;
|
|
||||||
extern crate dotenv;
|
|
||||||
extern crate jsonwebtoken;
|
|
||||||
extern crate log;
|
|
||||||
extern crate openssl;
|
|
||||||
extern crate reqwest;
|
|
||||||
extern crate rss;
|
|
||||||
extern crate serde;
|
|
||||||
extern crate serde_json;
|
|
||||||
extern crate sha2;
|
|
||||||
extern crate strum;
|
|
||||||
|
|
||||||
pub mod api;
|
|
||||||
pub mod apub;
|
|
||||||
pub mod code_migrations;
|
pub mod code_migrations;
|
||||||
pub mod request;
|
|
||||||
pub mod routes;
|
pub mod routes;
|
||||||
pub mod version;
|
|
||||||
pub mod websocket;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
request::{retry, RecvError},
|
|
||||||
websocket::chat_server::ChatServer,
|
|
||||||
};
|
|
||||||
use actix::Addr;
|
|
||||||
use anyhow::anyhow;
|
|
||||||
use background_jobs::QueueHandle;
|
|
||||||
use lemmy_db::DbPool;
|
|
||||||
use lemmy_utils::{apub::get_apub_protocol_string, settings::Settings, LemmyError};
|
|
||||||
use log::error;
|
|
||||||
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
|
|
||||||
use reqwest::Client;
|
|
||||||
use serde::Deserialize;
|
|
||||||
use std::process::Command;
|
|
||||||
|
|
||||||
pub struct LemmyContext {
|
|
||||||
pub pool: DbPool,
|
|
||||||
pub chat_server: Addr<ChatServer>,
|
|
||||||
pub client: Client,
|
|
||||||
pub activity_queue: QueueHandle,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LemmyContext {
|
|
||||||
pub fn new(
|
|
||||||
pool: DbPool,
|
|
||||||
chat_server: Addr<ChatServer>,
|
|
||||||
client: Client,
|
|
||||||
activity_queue: QueueHandle,
|
|
||||||
) -> LemmyContext {
|
|
||||||
LemmyContext {
|
|
||||||
pool,
|
|
||||||
chat_server,
|
|
||||||
client,
|
|
||||||
activity_queue,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn pool(&self) -> &DbPool {
|
|
||||||
&self.pool
|
|
||||||
}
|
|
||||||
pub fn chat_server(&self) -> &Addr<ChatServer> {
|
|
||||||
&self.chat_server
|
|
||||||
}
|
|
||||||
pub fn client(&self) -> &Client {
|
|
||||||
&self.client
|
|
||||||
}
|
|
||||||
pub fn activity_queue(&self) -> &QueueHandle {
|
|
||||||
&self.activity_queue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Clone for LemmyContext {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
LemmyContext::new(
|
|
||||||
self.pool.clone(),
|
|
||||||
self.chat_server.clone(),
|
|
||||||
self.client.clone(),
|
|
||||||
self.activity_queue.clone(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
pub struct IframelyResponse {
|
|
||||||
title: Option<String>,
|
|
||||||
description: Option<String>,
|
|
||||||
thumbnail_url: Option<String>,
|
|
||||||
html: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn fetch_iframely(client: &Client, url: &str) -> Result<IframelyResponse, LemmyError> {
|
|
||||||
let fetch_url = format!("http://iframely/oembed?url={}", url);
|
|
||||||
|
|
||||||
let response = retry(|| client.get(&fetch_url).send()).await?;
|
|
||||||
|
|
||||||
let res: IframelyResponse = response
|
|
||||||
.json()
|
|
||||||
.await
|
|
||||||
.map_err(|e| RecvError(e.to_string()))?;
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Debug, Clone)]
|
|
||||||
pub struct PictrsResponse {
|
|
||||||
files: Vec<PictrsFile>,
|
|
||||||
msg: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Debug, Clone)]
|
|
||||||
pub struct PictrsFile {
|
|
||||||
file: String,
|
|
||||||
delete_token: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn fetch_pictrs(client: &Client, image_url: &str) -> Result<PictrsResponse, LemmyError> {
|
|
||||||
is_image_content_type(client, image_url).await?;
|
|
||||||
|
|
||||||
let fetch_url = format!(
|
|
||||||
"http://pictrs:8080/image/download?url={}",
|
|
||||||
utf8_percent_encode(image_url, NON_ALPHANUMERIC) // TODO this might not be needed
|
|
||||||
);
|
|
||||||
|
|
||||||
let response = retry(|| client.get(&fetch_url).send()).await?;
|
|
||||||
|
|
||||||
let response: PictrsResponse = response
|
|
||||||
.json()
|
|
||||||
.await
|
|
||||||
.map_err(|e| RecvError(e.to_string()))?;
|
|
||||||
|
|
||||||
if response.msg == "ok" {
|
|
||||||
Ok(response)
|
|
||||||
} else {
|
|
||||||
Err(anyhow!("{}", &response.msg).into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn fetch_iframely_and_pictrs_data(
|
|
||||||
client: &Client,
|
|
||||||
url: Option<String>,
|
|
||||||
) -> (
|
|
||||||
Option<String>,
|
|
||||||
Option<String>,
|
|
||||||
Option<String>,
|
|
||||||
Option<String>,
|
|
||||||
) {
|
|
||||||
match &url {
|
|
||||||
Some(url) => {
|
|
||||||
// Fetch iframely data
|
|
||||||
let (iframely_title, iframely_description, iframely_thumbnail_url, iframely_html) =
|
|
||||||
match fetch_iframely(client, url).await {
|
|
||||||
Ok(res) => (res.title, res.description, res.thumbnail_url, res.html),
|
|
||||||
Err(e) => {
|
|
||||||
error!("iframely err: {}", e);
|
|
||||||
(None, None, None, None)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Fetch pictrs thumbnail
|
|
||||||
let pictrs_hash = match iframely_thumbnail_url {
|
|
||||||
Some(iframely_thumbnail_url) => match fetch_pictrs(client, &iframely_thumbnail_url).await {
|
|
||||||
Ok(res) => Some(res.files[0].file.to_owned()),
|
|
||||||
Err(e) => {
|
|
||||||
error!("pictrs err: {}", e);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// Try to generate a small thumbnail if iframely is not supported
|
|
||||||
None => match fetch_pictrs(client, &url).await {
|
|
||||||
Ok(res) => Some(res.files[0].file.to_owned()),
|
|
||||||
Err(e) => {
|
|
||||||
error!("pictrs err: {}", e);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// The full urls are necessary for federation
|
|
||||||
let pictrs_thumbnail = if let Some(pictrs_hash) = pictrs_hash {
|
|
||||||
Some(format!(
|
|
||||||
"{}://{}/pictrs/image/{}",
|
|
||||||
get_apub_protocol_string(),
|
|
||||||
Settings::get().hostname,
|
|
||||||
pictrs_hash
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
(
|
|
||||||
iframely_title,
|
|
||||||
iframely_description,
|
|
||||||
iframely_html,
|
|
||||||
pictrs_thumbnail,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
None => (None, None, None, None),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn is_image_content_type(client: &Client, test: &str) -> Result<(), LemmyError> {
|
|
||||||
let response = retry(|| client.get(test).send()).await?;
|
|
||||||
|
|
||||||
if response
|
|
||||||
.headers()
|
|
||||||
.get("Content-Type")
|
|
||||||
.ok_or_else(|| anyhow!("No Content-Type header"))?
|
|
||||||
.to_str()?
|
|
||||||
.starts_with("image/")
|
|
||||||
{
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(anyhow!("Not an image type.").into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn captcha_espeak_wav_base64(captcha: &str) -> Result<String, LemmyError> {
|
|
||||||
let mut built_text = String::new();
|
|
||||||
|
|
||||||
// Building proper speech text for espeak
|
|
||||||
for mut c in captcha.chars() {
|
|
||||||
let new_str = if c.is_alphabetic() {
|
|
||||||
if c.is_lowercase() {
|
|
||||||
c.make_ascii_uppercase();
|
|
||||||
format!("lower case {} ... ", c)
|
|
||||||
} else {
|
|
||||||
c.make_ascii_uppercase();
|
|
||||||
format!("capital {} ... ", c)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
format!("{} ...", c)
|
|
||||||
};
|
|
||||||
|
|
||||||
built_text.push_str(&new_str);
|
|
||||||
}
|
|
||||||
|
|
||||||
espeak_wav_base64(&built_text)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn espeak_wav_base64(text: &str) -> Result<String, LemmyError> {
|
|
||||||
// Make a temp file path
|
|
||||||
let uuid = uuid::Uuid::new_v4().to_string();
|
|
||||||
let file_path = format!("/tmp/lemmy_espeak_{}.wav", &uuid);
|
|
||||||
|
|
||||||
// Write the wav file
|
|
||||||
Command::new("espeak")
|
|
||||||
.arg("-w")
|
|
||||||
.arg(&file_path)
|
|
||||||
.arg(text)
|
|
||||||
.status()?;
|
|
||||||
|
|
||||||
// Read the wav file bytes
|
|
||||||
let bytes = std::fs::read(&file_path)?;
|
|
||||||
|
|
||||||
// Delete the file
|
|
||||||
std::fs::remove_file(file_path)?;
|
|
||||||
|
|
||||||
// Convert to base64
|
|
||||||
let base64 = base64::encode(bytes);
|
|
||||||
|
|
||||||
Ok(base64)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use crate::{captcha_espeak_wav_base64, is_image_content_type};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_image() {
|
|
||||||
actix_rt::System::new("tset_image").block_on(async move {
|
|
||||||
let client = reqwest::Client::default();
|
|
||||||
assert!(is_image_content_type(&client, "https://1734811051.rsc.cdn77.org/data/images/full/365645/as-virus-kills-navajos-in-their-homes-tribal-women-provide-lifeline.jpg?w=600?w=650").await.is_ok());
|
|
||||||
assert!(is_image_content_type(&client,
|
|
||||||
"https://twitter.com/BenjaminNorton/status/1259922424272957440?s=20"
|
|
||||||
)
|
|
||||||
.await.is_err()
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_espeak() {
|
|
||||||
assert!(captcha_espeak_wav_base64("WxRt2l").is_ok())
|
|
||||||
}
|
|
||||||
|
|
||||||
// These helped with testing
|
|
||||||
// #[test]
|
|
||||||
// fn test_iframely() {
|
|
||||||
// let res = fetch_iframely(client, "https://www.redspark.nu/?p=15341").await;
|
|
||||||
// assert!(res.is_ok());
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[test]
|
|
||||||
// fn test_pictshare() {
|
|
||||||
// let res = fetch_pictshare("https://upload.wikimedia.org/wikipedia/en/2/27/The_Mandalorian_logo.jpg");
|
|
||||||
// assert!(res.is_ok());
|
|
||||||
// let res_other = fetch_pictshare("https://upload.wikimedia.org/wikipedia/en/2/27/The_Mandalorian_logo.jpgaoeu");
|
|
||||||
// assert!(res_other.is_err());
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
14
src/main.rs
14
src/main.rs
|
@ -16,17 +16,14 @@ use diesel::{
|
||||||
PgConnection,
|
PgConnection,
|
||||||
};
|
};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
use lemmy_api::match_websocket_operation;
|
||||||
|
use lemmy_apub::activity_queue::create_activity_queue;
|
||||||
use lemmy_db::get_database_url_from_env;
|
use lemmy_db::get_database_url_from_env;
|
||||||
use lemmy_rate_limit::{rate_limiter::RateLimiter, RateLimit};
|
use lemmy_rate_limit::{rate_limiter::RateLimiter, RateLimit};
|
||||||
use lemmy_server::{
|
use lemmy_server::{code_migrations::run_advanced_migrations, routes::*};
|
||||||
apub::activity_queue::create_activity_queue,
|
|
||||||
code_migrations::run_advanced_migrations,
|
|
||||||
routes::*,
|
|
||||||
websocket::chat_server::ChatServer,
|
|
||||||
LemmyContext,
|
|
||||||
};
|
|
||||||
use lemmy_structs::blocking;
|
use lemmy_structs::blocking;
|
||||||
use lemmy_utils::{settings::Settings, LemmyError, CACHE_CONTROL_REGEX};
|
use lemmy_utils::{settings::Settings, LemmyError, CACHE_CONTROL_REGEX};
|
||||||
|
use lemmy_websocket::{chat_server::ChatServer, LemmyContext};
|
||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
@ -77,6 +74,7 @@ async fn main() -> Result<(), LemmyError> {
|
||||||
let chat_server = ChatServer::startup(
|
let chat_server = ChatServer::startup(
|
||||||
pool.clone(),
|
pool.clone(),
|
||||||
rate_limiter.clone(),
|
rate_limiter.clone(),
|
||||||
|
|c, i, o, d| Box::pin(match_websocket_operation(c, i, o, d)),
|
||||||
Client::default(),
|
Client::default(),
|
||||||
activity_queue.clone(),
|
activity_queue.clone(),
|
||||||
)
|
)
|
||||||
|
@ -84,7 +82,7 @@ async fn main() -> Result<(), LemmyError> {
|
||||||
|
|
||||||
// Create Http server with websocket support
|
// Create Http server with websocket support
|
||||||
HttpServer::new(move || {
|
HttpServer::new(move || {
|
||||||
let context = LemmyContext::new(
|
let context = LemmyContext::create(
|
||||||
pool.clone(),
|
pool.clone(),
|
||||||
chat_server.to_owned(),
|
chat_server.to_owned(),
|
||||||
Client::default(),
|
Client::default(),
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use crate::{api::Perform, LemmyContext};
|
|
||||||
use actix_web::{error::ErrorBadRequest, *};
|
use actix_web::{error::ErrorBadRequest, *};
|
||||||
|
use lemmy_api::Perform;
|
||||||
use lemmy_rate_limit::RateLimit;
|
use lemmy_rate_limit::RateLimit;
|
||||||
use lemmy_structs::{comment::*, community::*, post::*, site::*, user::*};
|
use lemmy_structs::{comment::*, community::*, post::*, site::*, user::*};
|
||||||
|
use lemmy_websocket::LemmyContext;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) {
|
pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) {
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
use crate::apub::{
|
use actix_web::*;
|
||||||
|
use http_signature_normalization_actix::digest::middleware::VerifyDigest;
|
||||||
|
use lemmy_apub::{
|
||||||
comment::get_apub_comment,
|
comment::get_apub_comment,
|
||||||
community::*,
|
community::*,
|
||||||
inbox::{community_inbox::community_inbox, shared_inbox::shared_inbox, user_inbox::user_inbox},
|
inbox::{community_inbox::community_inbox, shared_inbox::shared_inbox, user_inbox::user_inbox},
|
||||||
|
@ -6,8 +8,6 @@ use crate::apub::{
|
||||||
user::*,
|
user::*,
|
||||||
APUB_JSON_CONTENT_TYPE,
|
APUB_JSON_CONTENT_TYPE,
|
||||||
};
|
};
|
||||||
use actix_web::*;
|
|
||||||
use http_signature_normalization_actix::digest::middleware::VerifyDigest;
|
|
||||||
use lemmy_utils::settings::Settings;
|
use lemmy_utils::settings::Settings;
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::{api::claims::Claims, LemmyContext};
|
|
||||||
use actix_web::{error::ErrorBadRequest, *};
|
use actix_web::{error::ErrorBadRequest, *};
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use chrono::{DateTime, NaiveDateTime, Utc};
|
use chrono::{DateTime, NaiveDateTime, Utc};
|
||||||
use diesel::PgConnection;
|
use diesel::PgConnection;
|
||||||
|
use lemmy_api::claims::Claims;
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
comment_view::{ReplyQueryBuilder, ReplyView},
|
comment_view::{ReplyQueryBuilder, ReplyView},
|
||||||
community::Community,
|
community::Community,
|
||||||
|
@ -15,6 +15,7 @@ use lemmy_db::{
|
||||||
};
|
};
|
||||||
use lemmy_structs::blocking;
|
use lemmy_structs::blocking;
|
||||||
use lemmy_utils::{settings::Settings, utils::markdown_to_html, LemmyError};
|
use lemmy_utils::{settings::Settings, utils::markdown_to_html, LemmyError};
|
||||||
|
use lemmy_websocket::LemmyContext;
|
||||||
use rss::{CategoryBuilder, ChannelBuilder, GuidBuilder, Item, ItemBuilder};
|
use rss::{CategoryBuilder, ChannelBuilder, GuidBuilder, Item, ItemBuilder};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
use crate::{version, LemmyContext};
|
|
||||||
use actix_web::{body::Body, error::ErrorBadRequest, *};
|
use actix_web::{body::Body, error::ErrorBadRequest, *};
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
|
use lemmy_api::version;
|
||||||
use lemmy_db::site_view::SiteView;
|
use lemmy_db::site_view::SiteView;
|
||||||
use lemmy_structs::blocking;
|
use lemmy_structs::blocking;
|
||||||
use lemmy_utils::{apub::get_apub_protocol_string, settings::Settings, LemmyError};
|
use lemmy_utils::{apub::get_apub_protocol_string, settings::Settings, LemmyError};
|
||||||
|
use lemmy_websocket::LemmyContext;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
|
|
@ -1,38 +1,21 @@
|
||||||
use crate::LemmyContext;
|
|
||||||
use actix_web::{error::ErrorBadRequest, web::Query, *};
|
use actix_web::{error::ErrorBadRequest, web::Query, *};
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use lemmy_db::{community::Community, user::User_};
|
use lemmy_db::{community::Community, user::User_};
|
||||||
use lemmy_structs::blocking;
|
use lemmy_structs::{blocking, WebFingerLink, WebFingerResponse};
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
settings::Settings,
|
settings::Settings,
|
||||||
LemmyError,
|
LemmyError,
|
||||||
WEBFINGER_COMMUNITY_REGEX,
|
WEBFINGER_COMMUNITY_REGEX,
|
||||||
WEBFINGER_USER_REGEX,
|
WEBFINGER_USER_REGEX,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use lemmy_websocket::LemmyContext;
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct Params {
|
pub struct Params {
|
||||||
resource: String,
|
resource: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
|
||||||
pub struct WebFingerResponse {
|
|
||||||
pub subject: String,
|
|
||||||
pub aliases: Vec<String>,
|
|
||||||
pub links: Vec<WebFingerLink>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
|
||||||
pub struct WebFingerLink {
|
|
||||||
pub rel: Option<String>,
|
|
||||||
#[serde(rename(serialize = "type", deserialize = "type"))]
|
|
||||||
pub type_: Option<String>,
|
|
||||||
pub href: Option<String>,
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub template: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||||
if Settings::get().federation.enabled {
|
if Settings::get().federation.enabled {
|
||||||
cfg.route(
|
cfg.route(
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
use crate::{websocket::chat_server::ChatServer, LemmyContext};
|
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
use actix_web::*;
|
use actix_web::*;
|
||||||
use actix_web_actors::ws;
|
use actix_web_actors::ws;
|
||||||
use lemmy_structs::websocket::{Connect, Disconnect, StandardMessage, WSMessage};
|
|
||||||
use lemmy_utils::utils::get_ip;
|
use lemmy_utils::utils::get_ip;
|
||||||
|
use lemmy_websocket::{
|
||||||
|
chat_server::ChatServer,
|
||||||
|
messages::{Connect, Disconnect, StandardMessage, WSMessage},
|
||||||
|
LemmyContext,
|
||||||
|
};
|
||||||
use log::{debug, error, info};
|
use log::{debug, error, info};
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
pub mod chat_server;
|
|
||||||
pub mod handlers;
|
|
Loading…
Reference in a new issue