Merge remote-tracking branch 'origin/main' into 1462-jwt-revocation-on-pwd-change

* origin/main:
  revert Compose file version from 3.3 to 2.2
  Adding more mem limits
  bump memory limit of iframely
  Remove extra category_id s . Fixes #1429
  Fixing wrong user_ and community icon and banner urls.
  Remove category from activitypub context
  Adding a password length check to other API actions. (#1474)
  Update test script
  Use URL type in most outstanding struct fields (#1468)
  Forbid usage of unwrap
  Upgrade Rust version
  Rewrite settings implementation. Fixes #1270 (#1433)
  Rename `lemmy_structs` to `lemmy_api_structs`

# Conflicts:
#	crates/db_schema/src/source/user.rs
pull/1493/head
Bogdan Mart 2021-03-13 20:19:55 +02:00
commit 7b0a09e84e
122 changed files with 1212 additions and 925 deletions

View File

@ -9,7 +9,7 @@ platform:
steps:
- name: chown repo
image: ekidd/rust-musl-builder:1.47.0
image: ekidd/rust-musl-builder:1.50.0
user: root
commands:
- chown 1000:1000 . -R
@ -20,12 +20,13 @@ steps:
- /root/.cargo/bin/cargo fmt -- --check
- name: cargo clippy
image: ekidd/rust-musl-builder:1.47.0
image: ekidd/rust-musl-builder:1.50.0
commands:
- cargo clippy --workspace --tests --all-targets --all-features -- -D warnings -D deprecated -D clippy::perf -D clippy::complexity -D clippy::dbg_macro
- cargo clippy --workspace -- -D clippy::unwrap_used
- name: cargo test
image: ekidd/rust-musl-builder:1.47.0
image: ekidd/rust-musl-builder:1.50.0
environment:
LEMMY_DATABASE_URL: postgres://lemmy:password@database:5432/lemmy
RUST_BACKTRACE: 1
@ -35,7 +36,7 @@ steps:
- cargo test --workspace --no-fail-fast
- name: cargo build
image: ekidd/rust-musl-builder:1.47.0
image: ekidd/rust-musl-builder:1.50.0
commands:
- cargo build
- mv target/x86_64-unknown-linux-musl/debug/lemmy_server target/lemmy_server
@ -102,7 +103,7 @@ platform:
steps:
- name: cargo test
image: rust:1.47-slim-buster
image: rust:1.50-slim-buster
environment:
LEMMY_DATABASE_URL: postgres://lemmy:password@database:5432/lemmy
RUST_BACKTRACE: 1
@ -114,7 +115,7 @@ steps:
# Using Debian here because there seems to be no official Alpine-based Rust docker image for ARM.
- name: cargo build
image: rust:1.47-slim-buster
image: rust:1.50-slim-buster
commands:
- apt-get update
- apt-get -y install --no-install-recommends libssl-dev pkg-config libpq-dev

293
Cargo.lock generated
View File

@ -10,7 +10,7 @@ checksum = "fe7ceed015dfca322d3bcec3653909c77557e7e57df72e98cb8806e2c93cc919"
dependencies = [
"chrono",
"mime",
"serde 1.0.123",
"serde",
"serde_json",
"thiserror",
"url",
@ -23,7 +23,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb8e19a0810cc25df3535061a08b7d8f8a734d309ea4411c57a9767e4a2ffa0e"
dependencies = [
"activitystreams",
"serde 1.0.123",
"serde",
"serde_json",
]
@ -130,7 +130,7 @@ dependencies = [
"pin-project 1.0.4",
"rand 0.7.3",
"regex",
"serde 1.0.123",
"serde",
"serde_json",
"serde_urlencoded",
"sha-1 0.9.3",
@ -158,7 +158,7 @@ dependencies = [
"http",
"log",
"regex",
"serde 1.0.123",
"serde",
]
[[package]]
@ -302,7 +302,7 @@ dependencies = [
"pin-project 1.0.4",
"regex",
"rustls",
"serde 1.0.123",
"serde",
"serde_json",
"serde_urlencoded",
"socket2",
@ -391,12 +391,6 @@ version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1"
[[package]]
name = "arrayvec"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
[[package]]
name = "async-mutex"
version = "1.4.0"
@ -466,7 +460,7 @@ dependencies = [
"percent-encoding",
"rand 0.7.3",
"rustls",
"serde 1.0.123",
"serde",
"serde_json",
"serde_urlencoded",
]
@ -496,7 +490,7 @@ dependencies = [
"log",
"num_cpus",
"rand 0.7.3",
"serde 1.0.123",
"serde",
"serde_json",
"thiserror",
"tokio 0.2.25",
@ -515,7 +509,7 @@ dependencies = [
"async-trait",
"chrono",
"log",
"serde 1.0.123",
"serde",
"serde_json",
"thiserror",
"tokio 0.2.25",
@ -735,8 +729,8 @@ checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
dependencies = [
"libc",
"num-integer",
"num-traits 0.2.14",
"serde 1.0.123",
"num-traits",
"serde",
"time 0.1.44",
"winapi 0.3.9",
]
@ -783,18 +777,6 @@ dependencies = [
"xdg",
]
[[package]]
name = "config"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b076e143e1d9538dde65da30f8481c2a6c44040edb8e02b9bf1351edb92ce3"
dependencies = [
"lazy_static",
"nom 5.1.2",
"serde 1.0.123",
"serde-hjson",
]
[[package]]
name = "const_fn"
version = "0.4.5"
@ -997,6 +979,15 @@ dependencies = [
"syn",
]
[[package]]
name = "deser-hjson"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d995b60ff81bc6af01a98f0bf5db70a7418a1ac8bd74ada633968f388139da5e"
dependencies = [
"serde",
]
[[package]]
name = "diesel"
version = "1.4.5"
@ -1112,6 +1103,15 @@ dependencies = [
"termcolor",
]
[[package]]
name = "envy"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f47e0157f2cb54f5ae1bd371b30a2ae4311e1c028f575cd4e81de7353215965"
dependencies = [
"serde",
]
[[package]]
name = "event-listener"
version = "2.5.1"
@ -1592,7 +1592,7 @@ dependencies = [
"jpeg-decoder",
"num-iter",
"num-rational",
"num-traits 0.2.14",
"num-traits",
"png",
"scoped_threadpool",
"tiff",
@ -1686,7 +1686,7 @@ dependencies = [
"base64 0.12.3",
"pem",
"ring",
"serde 1.0.123",
"serde",
"serde_json",
"simple_asn1",
]
@ -1734,20 +1734,20 @@ dependencies = [
"http-signature-normalization-actix",
"itertools",
"lazy_static",
"lemmy_api_structs",
"lemmy_apub",
"lemmy_db_queries",
"lemmy_db_schema",
"lemmy_db_views",
"lemmy_db_views_actor",
"lemmy_db_views_moderator",
"lemmy_structs",
"lemmy_utils",
"lemmy_websocket",
"log",
"openssl",
"rand 0.8.3",
"reqwest",
"serde 1.0.123",
"serde",
"serde_json",
"sha2",
"strum",
@ -1758,6 +1758,25 @@ dependencies = [
"uuid",
]
[[package]]
name = "lemmy_api_structs"
version = "0.1.0"
dependencies = [
"actix-web",
"chrono",
"diesel",
"lemmy_db_queries",
"lemmy_db_schema",
"lemmy_db_views",
"lemmy_db_views_actor",
"lemmy_db_views_moderator",
"lemmy_utils",
"log",
"serde",
"serde_json",
"url",
]
[[package]]
name = "lemmy_apub"
version = "0.1.0"
@ -1782,11 +1801,11 @@ dependencies = [
"http-signature-normalization-reqwest",
"itertools",
"lazy_static",
"lemmy_api_structs",
"lemmy_db_queries",
"lemmy_db_schema",
"lemmy_db_views",
"lemmy_db_views_actor",
"lemmy_structs",
"lemmy_utils",
"lemmy_websocket",
"log",
@ -1794,7 +1813,7 @@ dependencies = [
"percent-encoding",
"rand 0.8.3",
"reqwest",
"serde 1.0.123",
"serde",
"serde_json",
"sha2",
"strum",
@ -1818,7 +1837,7 @@ dependencies = [
"lemmy_utils",
"log",
"regex",
"serde 1.0.123",
"serde",
"serde_json",
"serial_test",
"sha2",
@ -1834,7 +1853,7 @@ dependencies = [
"chrono",
"diesel",
"log",
"serde 1.0.123",
"serde",
"serde_json",
"url",
]
@ -1847,7 +1866,7 @@ dependencies = [
"lemmy_db_queries",
"lemmy_db_schema",
"log",
"serde 1.0.123",
"serde",
"serial_test",
"url",
]
@ -1859,7 +1878,7 @@ dependencies = [
"diesel",
"lemmy_db_queries",
"lemmy_db_schema",
"serde 1.0.123",
"serde",
]
[[package]]
@ -1869,7 +1888,7 @@ dependencies = [
"diesel",
"lemmy_db_queries",
"lemmy_db_schema",
"serde 1.0.123",
"serde",
]
[[package]]
@ -1884,16 +1903,16 @@ dependencies = [
"chrono",
"diesel",
"lazy_static",
"lemmy_api_structs",
"lemmy_db_queries",
"lemmy_db_schema",
"lemmy_db_views",
"lemmy_db_views_actor",
"lemmy_structs",
"lemmy_utils",
"lemmy_websocket",
"log",
"rss",
"serde 1.0.123",
"serde",
"sha2",
"strum",
"url",
@ -1916,6 +1935,7 @@ dependencies = [
"env_logger",
"http-signature-normalization-actix",
"lemmy_api",
"lemmy_api_structs",
"lemmy_apub",
"lemmy_db_queries",
"lemmy_db_schema",
@ -1923,38 +1943,18 @@ dependencies = [
"lemmy_db_views_actor",
"lemmy_db_views_moderator",
"lemmy_routes",
"lemmy_structs",
"lemmy_utils",
"lemmy_websocket",
"log",
"openssl",
"reqwest",
"serde 1.0.123",
"serde",
"serde_json",
"strum",
"tokio 0.3.7",
"url",
]
[[package]]
name = "lemmy_structs"
version = "0.1.0"
dependencies = [
"actix-web",
"chrono",
"diesel",
"lemmy_db_queries",
"lemmy_db_schema",
"lemmy_db_views",
"lemmy_db_views_actor",
"lemmy_db_views_moderator",
"lemmy_utils",
"log",
"serde 1.0.123",
"serde_json",
"url",
]
[[package]]
name = "lemmy_utils"
version = "0.1.0"
@ -1964,8 +1964,9 @@ dependencies = [
"anyhow",
"chrono",
"comrak",
"config",
"deser-hjson",
"diesel",
"envy",
"futures",
"http",
"itertools",
@ -1973,12 +1974,13 @@ dependencies = [
"lazy_static",
"lettre",
"log",
"merge",
"openssl",
"percent-encoding",
"rand 0.8.3",
"regex",
"reqwest",
"serde 1.0.123",
"serde",
"serde_json",
"strum",
"strum_macros",
@ -1998,14 +2000,14 @@ dependencies = [
"background-jobs",
"chrono",
"diesel",
"lemmy_api_structs",
"lemmy_db_queries",
"lemmy_db_schema",
"lemmy_structs",
"lemmy_utils",
"log",
"rand 0.8.3",
"reqwest",
"serde 1.0.123",
"serde",
"serde_json",
"strum",
"strum_macros",
@ -2024,46 +2026,23 @@ dependencies = [
"idna",
"mime",
"native-tls",
"nom 6.1.0",
"nom",
"once_cell",
"quoted_printable",
"r2d2",
"rand 0.8.3",
"regex",
"serde 1.0.123",
"serde",
"serde_json",
"uuid",
]
[[package]]
name = "lexical-core"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db65c6da02e61f55dae90a0ae427b2a5f6b3e8db09f58d10efab23af92592616"
dependencies = [
"arrayvec",
"bitflags",
"cfg-if 0.1.10",
"ryu",
"static_assertions",
]
[[package]]
name = "libc"
version = "0.2.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cca32fa0182e8c0989459524dc356b8f2b5c10f1b9eb521b7d182c03cf8c5ff"
[[package]]
name = "linked-hash-map"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd"
dependencies = [
"serde 0.8.23",
"serde_test",
]
[[package]]
name = "linked-hash-map"
version = "0.5.4"
@ -2106,7 +2085,7 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c"
dependencies = [
"linked-hash-map 0.5.4",
"linked-hash-map",
]
[[package]]
@ -2148,6 +2127,28 @@ dependencies = [
"autocfg",
]
[[package]]
name = "merge"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10bbef93abb1da61525bbc45eeaff6473a41907d19f8f9aa5168d214e10693e9"
dependencies = [
"merge_derive",
"num-traits",
]
[[package]]
name = "merge_derive"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "209d075476da2e63b4b29e72a2ef627b840589588e71400a25e3565c4f849d07"
dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "migrations_internals"
version = "1.4.1"
@ -2275,17 +2276,6 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "nom"
version = "5.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af"
dependencies = [
"lexical-core",
"memchr",
"version_check",
]
[[package]]
name = "nom"
version = "6.1.0"
@ -2305,7 +2295,7 @@ checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304"
dependencies = [
"autocfg",
"num-integer",
"num-traits 0.2.14",
"num-traits",
]
[[package]]
@ -2315,7 +2305,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
dependencies = [
"autocfg",
"num-traits 0.2.14",
"num-traits",
]
[[package]]
@ -2326,7 +2316,7 @@ checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59"
dependencies = [
"autocfg",
"num-integer",
"num-traits 0.2.14",
"num-traits",
]
[[package]]
@ -2337,16 +2327,7 @@ checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07"
dependencies = [
"autocfg",
"num-integer",
"num-traits 0.2.14",
]
[[package]]
name = "num-traits"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
dependencies = [
"num-traits 0.2.14",
"num-traits",
]
[[package]]
@ -2601,6 +2582,30 @@ dependencies = [
"vcpkg",
]
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]]
name = "proc-macro-hack"
version = "0.5.19"
@ -2842,7 +2847,7 @@ dependencies = [
"native-tls",
"percent-encoding",
"pin-project-lite 0.2.4",
"serde 1.0.123",
"serde",
"serde_json",
"serde_urlencoded",
"tokio 0.2.25",
@ -3012,12 +3017,6 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "serde"
version = "0.8.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8"
[[package]]
name = "serde"
version = "1.0.123"
@ -3027,19 +3026,6 @@ dependencies = [
"serde_derive",
]
[[package]]
name = "serde-hjson"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a3a4e0ea8a88553209f6cc6cfe8724ecad22e1acf372793c27d995290fe74f8"
dependencies = [
"lazy_static",
"linked-hash-map 0.3.0",
"num-traits 0.1.43",
"regex",
"serde 0.8.23",
]
[[package]]
name = "serde_derive"
version = "1.0.123"
@ -3060,16 +3046,7 @@ dependencies = [
"indexmap",
"itoa",
"ryu",
"serde 1.0.123",
]
[[package]]
name = "serde_test"
version = "0.8.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "110b3dbdf8607ec493c22d5d947753282f3bae73c0f56d322af1e8c78e4c23d5"
dependencies = [
"serde 0.8.23",
"serde",
]
[[package]]
@ -3081,7 +3058,7 @@ dependencies = [
"form_urlencoded",
"itoa",
"ryu",
"serde 1.0.123",
"serde",
]
[[package]]
@ -3173,7 +3150,7 @@ checksum = "692ca13de57ce0613a363c8c2f1de925adebc81b04c923ac60c5488bb44abe4b"
dependencies = [
"chrono",
"num-bigint",
"num-traits 0.2.14",
"num-traits",
]
[[package]]
@ -3214,12 +3191,6 @@ dependencies = [
"version_check",
]
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "stdweb"
version = "0.4.20"
@ -3242,7 +3213,7 @@ checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef"
dependencies = [
"proc-macro2",
"quote",
"serde 1.0.123",
"serde",
"serde_derive",
"syn",
]
@ -3256,7 +3227,7 @@ dependencies = [
"base-x",
"proc-macro2",
"quote",
"serde 1.0.123",
"serde",
"serde_derive",
"serde_json",
"sha1",
@ -3684,15 +3655,15 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "url"
version = "2.2.0"
version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5909f2b0817350449ed73e8bcd81c8c3c8d9a7a5d8acba4b27db277f1868976e"
checksum = "9ccd964113622c8e9322cfac19eb1004a07e636c545f325da085d5cdde6f1f8b"
dependencies = [
"form_urlencoded",
"idna",
"matches",
"percent-encoding",
"serde 1.0.123",
"serde",
]
[[package]]
@ -3702,7 +3673,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
dependencies = [
"getrandom 0.2.2",
"serde 1.0.123",
"serde",
]
[[package]]
@ -3746,7 +3717,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55c0f7123de74f0dab9b7d00fd614e7b19349cd1e2f5252bbe9b1754b59433be"
dependencies = [
"cfg-if 1.0.0",
"serde 1.0.123",
"serde",
"serde_json",
"wasm-bindgen-macro",
]

View File

@ -19,7 +19,7 @@ members = [
"crates/db_views",
"crates/db_views_actor",
"crates/db_views_actor",
"crates/structs",
"crates/api_structs",
"crates/websocket",
"crates/routes"
]
@ -33,7 +33,7 @@ lemmy_db_queries = { path = "./crates/db_queries" }
lemmy_db_views = { path = "./crates/db_views" }
lemmy_db_views_moderator = { path = "./crates/db_views_moderator" }
lemmy_db_views_actor = { path = "./crates/db_views_actor" }
lemmy_structs = { path = "./crates/structs" }
lemmy_api_structs = { path = "crates/api_structs" }
lemmy_websocket = { path = "./crates/websocket" }
lemmy_routes = { path = "./crates/routes" }
diesel = "1.4.5"
@ -45,7 +45,7 @@ actix-web = { version = "3.3.2", default-features = false, features = ["rustls"]
log = "0.4.14"
env_logger = "0.8.2"
strum = "0.20.0"
url = { version = "2.2.0", features = ["serde"] }
url = { version = "2.2.1", features = ["serde"] }
openssl = "0.10.32"
http-signature-normalization-actix = { version = "0.4.1", default-features = false, features = ["sha-2"] }
tokio = "0.3.6"

View File

@ -29,8 +29,9 @@
# https://join.lemmy.ml/docs/en/federation/administration.html#instance-allowlist-and-blocklist
#
# comma separated list of instances with which federation is allowed
# allowed_instances: ""
# Only one of these blocks should be uncommented
# allowed_instances: ["instance1.tld","instance2.tld"]
# comma separated list of instances which are blocked from federating
# blocked_instances: ""
# blocked_instances: []
}
}

View File

@ -1,4 +1,4 @@
version: '3.3'
version: '2.2'
services:
lemmy:
@ -53,6 +53,7 @@ services:
volumes:
- ./iframely.config.local.js:/iframely/config.local.js:ro
restart: always
mem_limit: 200m
postfix:
image: mwader/postfix-relay

View File

@ -1,13 +1,6 @@
#!/bin/bash
set -e
export LEMMY_JWT_SECRET=changeme
export LEMMY_FEDERATION__ENABLED=true
export LEMMY_TLS_ENABLED=false
export LEMMY_SETUP__ADMIN_PASSWORD=lemmy
export LEMMY_RATE_LIMIT__POST=99999
export LEMMY_RATE_LIMIT__REGISTER=99999
export LEMMY_CAPTCHA__ENABLED=false
export LEMMY_TEST_SEND_SYNC=1
export RUST_BACKTRACE=1
@ -35,52 +28,40 @@ fi
killall lemmy_server || true
echo "$PWD"
echo "start alpha"
LEMMY_HOSTNAME=lemmy-alpha:8541 \
LEMMY_PORT=8541 \
LEMMY_CONFIG_LOCATION=./docker/federation/lemmy_alpha.hjson \
LEMMY_DATABASE_URL="${LEMMY_DATABASE_URL}/lemmy_alpha" \
LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-beta,lemmy-gamma,lemmy-delta,lemmy-epsilon \
LEMMY_SETUP__ADMIN_USERNAME=lemmy_alpha \
LEMMY_SETUP__SITE_NAME=lemmy-alpha \
target/lemmy_server >/dev/null 2>&1 &
LEMMY_HOSTNAME="lemmy-alpha:8541" \
target/lemmy_server >/tmp/lemmy_alpha.out 2>&1 &
echo "start beta"
LEMMY_HOSTNAME=lemmy-beta:8551 \
LEMMY_PORT=8551 \
LEMMY_CONFIG_LOCATION=./docker/federation/lemmy_beta.hjson \
LEMMY_DATABASE_URL="${LEMMY_DATABASE_URL}/lemmy_beta" \
LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-alpha,lemmy-gamma,lemmy-delta,lemmy-epsilon \
LEMMY_SETUP__ADMIN_USERNAME=lemmy_beta \
LEMMY_SETUP__SITE_NAME=lemmy-beta \
target/lemmy_server >/dev/null 2>&1 &
target/lemmy_server >/tmp/lemmy_beta.out 2>&1 &
echo "start gamma"
LEMMY_HOSTNAME=lemmy-gamma:8561 \
LEMMY_PORT=8561 \
LEMMY_CONFIG_LOCATION=./docker/federation/lemmy_gamma.hjson \
LEMMY_DATABASE_URL="${LEMMY_DATABASE_URL}/lemmy_gamma" \
LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-alpha,lemmy-beta,lemmy-delta,lemmy-epsilon \
LEMMY_SETUP__ADMIN_USERNAME=lemmy_gamma \
LEMMY_SETUP__SITE_NAME=lemmy-gamma \
target/lemmy_server >/dev/null 2>&1 &
target/lemmy_server >/tmp/lemmy_gamma.out 2>&1 &
echo "start delta"
# An instance with only an allowlist for beta
LEMMY_HOSTNAME=lemmy-delta:8571 \
LEMMY_PORT=8571 \
LEMMY_CONFIG_LOCATION=./docker/federation/lemmy_delta.hjson \
LEMMY_DATABASE_URL="${LEMMY_DATABASE_URL}/lemmy_delta" \
LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-beta \
LEMMY_SETUP__ADMIN_USERNAME=lemmy_delta \
LEMMY_SETUP__SITE_NAME=lemmy-delta \
target/lemmy_server >/dev/null 2>&1 &
target/lemmy_server >/tmp/lemmy_delta.out 2>&1 &
echo "start epsilon"
# An instance who has a blocklist, with lemmy-alpha blocked
LEMMY_HOSTNAME=lemmy-epsilon:8581 \
LEMMY_PORT=8581 \
LEMMY_CONFIG_LOCATION=./docker/federation/lemmy_epsilon.hjson \
LEMMY_DATABASE_URL="${LEMMY_DATABASE_URL}/lemmy_epsilon" \
LEMMY_FEDERATION__BLOCKED_INSTANCES=lemmy-alpha \
LEMMY_SETUP__ADMIN_USERNAME=lemmy_epsilon \
LEMMY_SETUP__SITE_NAME=lemmy-epsilon \
target/lemmy_server >/dev/null 2>&1 &
target/lemmy_server >/tmp/lemmy_epsilon.out 2>&1 &
echo "wait for all instances to start"
while [[ "$(curl -s -o /dev/null -w '%{http_code}' 'localhost:8541/api/v2/site')" != "200" ]]; do sleep 1; done

View File

@ -4,7 +4,7 @@ set -e
export LEMMY_DATABASE_URL=postgres://lemmy:password@localhost:5432
pushd ..
cargo +1.47.0 build
cargo build
rm target/lemmy_server || true
cp target/debug/lemmy_server target/lemmy_server
./api_tests/prepare-drone-federation-test.sh

View File

@ -66,9 +66,10 @@
# https://join.lemmy.ml/docs/en/federation/administration.html#instance-allowlist-and-blocklist
#
# comma separated list of instances with which federation is allowed
allowed_instances: ""
# Only one of these blocks should be uncommented
# allowed_instances: ["instance1.tld","instance2.tld"]
# comma separated list of instances which are blocked from federating
blocked_instances: ""
# blocked_instances: []
}
captcha: {
enabled: true

View File

@ -1,7 +1,6 @@
[package]
name = "lemmy_api"
version = "0.1.0"
authors = ["Felix Ableitner <me@nutomic.com>"]
edition = "2018"
[lib]
@ -17,7 +16,7 @@ lemmy_db_schema = { path = "../db_schema" }
lemmy_db_views = { path = "../db_views" }
lemmy_db_views_moderator = { path = "../db_views_moderator" }
lemmy_db_views_actor = { path = "../db_views_actor" }
lemmy_structs = { path = "../structs" }
lemmy_api_structs = { path = "../api_structs" }
lemmy_websocket = { path = "../websocket" }
diesel = "1.4.5"
bcrypt = "0.9.0"
@ -33,7 +32,7 @@ rand = "0.8.3"
strum = "0.20.0"
strum_macros = "0.20.1"
lazy_static = "1.4.0"
url = { version = "2.2.0", features = ["serde"] }
url = { version = "2.2.1", features = ["serde"] }
openssl = "0.10.32"
http = "0.2.3"
http-signature-normalization-actix = { version = "0.4.1", default-features = false, features = ["sha-2"] }

View File

@ -9,6 +9,7 @@ use crate::{
Perform,
};
use actix_web::web::Data;
use lemmy_api_structs::{blocking, comment::*, send_local_notifs};
use lemmy_apub::{generate_apub_endpoint, ApubLikeableType, ApubObjectType, EndpointType};
use lemmy_db_queries::{
source::comment::Comment_,
@ -24,7 +25,6 @@ use lemmy_db_views::{
comment_report_view::{CommentReportQueryBuilder, CommentReportView},
comment_view::{CommentQueryBuilder, CommentView},
};
use lemmy_structs::{blocking, comment::*, send_local_notifs};
use lemmy_utils::{
utils::{remove_slurs, scrape_text_for_mentions},
ApiError,

View File

@ -1,6 +1,5 @@
use crate::{
check_community_ban,
check_optional_url,
get_user_from_jwt,
get_user_from_jwt_opt,
is_admin,
@ -9,6 +8,7 @@ use crate::{
};
use actix_web::web::Data;
use anyhow::Context;
use lemmy_api_structs::{blocking, community::*};
use lemmy_apub::{
generate_apub_endpoint,
generate_followers_url,
@ -18,7 +18,7 @@ use lemmy_apub::{
EndpointType,
};
use lemmy_db_queries::{
diesel_option_overwrite,
diesel_option_overwrite_to_url,
source::{
comment::Comment_,
community::{CommunityModerator_, Community_},
@ -43,7 +43,6 @@ use lemmy_db_views_actor::{
community_view::{CommunityQueryBuilder, CommunityView},
user_view::UserViewSafe,
};
use lemmy_structs::{blocking, community::*};
use lemmy_utils::{
apub::generate_actor_keypair,
location_info,
@ -155,11 +154,8 @@ impl Perform for CreateCommunity {
}
// Check to make sure the icon and banners are urls
let icon = diesel_option_overwrite(&data.icon);
let banner = diesel_option_overwrite(&data.banner);
check_optional_url(&icon)?;
check_optional_url(&banner)?;
let icon = diesel_option_overwrite_to_url(&data.icon)?;
let banner = diesel_option_overwrite_to_url(&data.banner)?;
// When you create a community, make sure the user becomes a moderator and a follower
let keypair = generate_actor_keypair()?;
@ -260,11 +256,8 @@ impl Perform for EditCommunity {
})
.await??;
let icon = diesel_option_overwrite(&data.icon);
let banner = diesel_option_overwrite(&data.banner);
check_optional_url(&icon)?;
check_optional_url(&banner)?;
let icon = diesel_option_overwrite_to_url(&data.icon)?;
let banner = diesel_option_overwrite_to_url(&data.banner)?;
let community_form = CommunityForm {
name: read_community.name,

View File

@ -1,4 +1,13 @@
use actix_web::{web, web::Data};
use lemmy_api_structs::{
blocking,
comment::*,
community::*,
post::*,
site::*,
user::*,
websocket::*,
};
use lemmy_db_queries::{
source::{
community::{CommunityModerator_, Community_},
@ -18,8 +27,13 @@ use lemmy_db_views_actor::{
community_user_ban_view::CommunityUserBanView,
community_view::CommunityView,
};
use lemmy_structs::{blocking, comment::*, community::*, post::*, site::*, user::*, websocket::*};
use lemmy_utils::{claims::Claims, settings::Settings, ApiError, ConnectionId, LemmyError};
use lemmy_utils::{
claims::Claims,
settings::structs::Settings,
ApiError,
ConnectionId,
LemmyError,
};
use lemmy_websocket::{serialize_websocket_message, LemmyContext, UserOperation};
use serde::Deserialize;
use std::{env, process::Command};
@ -182,19 +196,10 @@ pub(crate) async fn collect_moderated_communities(
}
}
pub(crate) fn check_optional_url(item: &Option<Option<String>>) -> Result<(), LemmyError> {
if let Some(Some(item)) = &item {
if Url::parse(item).is_err() {
return Err(ApiError::err("invalid_url").into());
}
}
Ok(())
}
pub(crate) async fn build_federated_instances(
pool: &DbPool,
) -> Result<Option<FederatedInstances>, LemmyError> {
if Settings::get().federation.enabled {
if Settings::get().federation().enabled {
let distinct_communities = blocking(pool, move |conn| {
Community::distinct_federated_communities(conn)
})
@ -208,8 +213,13 @@ pub(crate) async fn build_federated_instances(
.map(|actor_id| Ok(Url::parse(actor_id)?.host_str().unwrap_or("").to_string()))
.collect::<Result<Vec<String>, LemmyError>>()?;
linked.extend_from_slice(&allowed);
linked.retain(|a| !blocked.contains(a) && !a.eq("") && !a.eq(&Settings::get().hostname));
if let Some(allowed) = allowed.as_ref() {
linked.extend_from_slice(allowed);
}
if let Some(blocked) = blocked.as_ref() {
linked.retain(|a| !blocked.contains(a) && !a.eq(&Settings::get().hostname()));
}
// Sort and remove dupes
linked.sort_unstable();
@ -469,6 +479,15 @@ pub(crate) fn espeak_wav_base64(text: &str) -> Result<String, LemmyError> {
Ok(base64)
}
/// Checks the password length
pub(crate) fn password_length_check(pass: &str) -> Result<(), LemmyError> {
if pass.len() > 60 {
Err(ApiError::err("invalid_password").into())
} else {
Ok(())
}
}
#[cfg(test)]
mod tests {
use crate::{captcha_espeak_wav_base64, get_user_from_jwt};

View File

@ -1,7 +1,6 @@
use crate::{
check_community_ban,
check_downvotes_enabled,
check_optional_url,
collect_moderated_communities,
get_user_from_jwt,
get_user_from_jwt_opt,
@ -9,6 +8,7 @@ use crate::{
Perform,
};
use actix_web::web::Data;
use lemmy_api_structs::{blocking, post::*};
use lemmy_apub::{generate_apub_endpoint, ApubLikeableType, ApubObjectType, EndpointType};
use lemmy_db_queries::{
source::post::Post_,
@ -36,7 +36,6 @@ use lemmy_db_views_actor::{
community_moderator_view::CommunityModeratorView,
community_view::CommunityView,
};
use lemmy_structs::{blocking, post::*};
use lemmy_utils::{
request::fetch_iframely_and_pictrs_data,
utils::{check_slurs, check_slurs_opt, is_valid_post_title},
@ -72,15 +71,14 @@ impl Perform for CreatePost {
check_community_ban(user.id, data.community_id, context.pool()).await?;
check_optional_url(&Some(data.url.to_owned()))?;
// Fetch Iframely and pictrs cached image
let data_url = data.url.as_ref();
let (iframely_title, iframely_description, iframely_html, pictrs_thumbnail) =
fetch_iframely_and_pictrs_data(context.client(), data.url.to_owned()).await;
fetch_iframely_and_pictrs_data(context.client(), data_url).await;
let post_form = PostForm {
name: data.name.trim().to_owned(),
url: data.url.to_owned(),
url: data_url.map(|u| u.to_owned().into()),
body: data.body.to_owned(),
community_id: data.community_id,
creator_id: user.id,
@ -93,7 +91,7 @@ impl Perform for CreatePost {
embed_title: iframely_title,
embed_description: iframely_description,
embed_html: iframely_html,
thumbnail_url: pictrs_thumbnail,
thumbnail_url: pictrs_thumbnail.map(|u| u.into()),
ap_id: None,
local: true,
published: None,
@ -385,12 +383,13 @@ impl Perform for EditPost {
}
// Fetch Iframely and Pictrs cached image
let data_url = data.url.as_ref();
let (iframely_title, iframely_description, iframely_html, pictrs_thumbnail) =
fetch_iframely_and_pictrs_data(context.client(), data.url.to_owned()).await;
fetch_iframely_and_pictrs_data(context.client(), data_url).await;
let post_form = PostForm {
name: data.name.trim().to_owned(),
url: data.url.to_owned(),
url: data_url.map(|u| u.to_owned().into()),
body: data.body.to_owned(),
nsfw: data.nsfw,
creator_id: orig_post.creator_id.to_owned(),
@ -403,7 +402,7 @@ impl Perform for EditPost {
embed_title: iframely_title,
embed_description: iframely_description,
embed_html: iframely_html,
thumbnail_url: pictrs_thumbnail,
thumbnail_url: pictrs_thumbnail.map(|u| u.into()),
ap_id: Some(orig_post.ap_id),
local: orig_post.local,
published: None,

View File

@ -1,6 +1,6 @@
use crate::Perform;
use actix_web::{error::ErrorBadRequest, *};
use lemmy_structs::{comment::*, community::*, post::*, site::*, user::*, websocket::*};
use lemmy_api_structs::{comment::*, community::*, post::*, site::*, user::*, websocket::*};
use lemmy_utils::rate_limit::RateLimit;
use lemmy_websocket::{routes::chat_route, LemmyContext};
use serde::Deserialize;

View File

@ -9,8 +9,15 @@ use crate::{
};
use actix_web::web::Data;
use anyhow::Context;
use lemmy_api_structs::{blocking, site::*, user::Register};
use lemmy_apub::fetcher::search::search_by_apub_id;
use lemmy_db_queries::{diesel_option_overwrite, source::site::Site_, Crud, SearchType, SortType};
use lemmy_db_queries::{
diesel_option_overwrite_to_url,
source::site::Site_,
Crud,
SearchType,
SortType,
};
use lemmy_db_schema::{
naive_now,
source::{
@ -38,10 +45,9 @@ use lemmy_db_views_moderator::{
mod_remove_post_view::ModRemovePostView,
mod_sticky_post_view::ModStickyPostView,
};
use lemmy_structs::{blocking, site::*, user::Register};
use lemmy_utils::{
location_info,
settings::Settings,
settings::structs::Settings,
utils::{check_slurs, check_slurs_opt},
version,
ApiError,
@ -157,8 +163,8 @@ impl Perform for CreateSite {
let site_form = SiteForm {
name: data.name.to_owned(),
description: data.description.to_owned(),
icon: Some(data.icon.to_owned()),
banner: Some(data.banner.to_owned()),
icon: Some(data.icon.to_owned().map(|url| url.into())),
banner: Some(data.banner.to_owned().map(|url| url.into())),
creator_id: user.id,
enable_downvotes: data.enable_downvotes,
open_registration: data.open_registration,
@ -196,8 +202,8 @@ impl Perform for EditSite {
let found_site = blocking(context.pool(), move |conn| Site::read_simple(conn)).await??;
let icon = diesel_option_overwrite(&data.icon);
let banner = diesel_option_overwrite(&data.banner);
let icon = diesel_option_overwrite_to_url(&data.icon)?;
let banner = diesel_option_overwrite_to_url(&data.banner)?;
let site_form = SiteForm {
name: data.name.to_owned(),
@ -245,7 +251,7 @@ impl Perform for GetSite {
Ok(site_view) => Some(site_view),
// If the site isn't created yet, check the setup
Err(_) => {
if let Some(setup) = Settings::get().setup.as_ref() {
if let Some(setup) = Settings::get().setup().as_ref() {
let register = Register {
username: setup.admin_username.to_owned(),
email: setup.admin_email.to_owned(),

View File

@ -1,10 +1,10 @@
use crate::{
captcha_espeak_wav_base64,
check_optional_url,
collect_moderated_communities,
get_user_from_jwt,
get_user_from_jwt_opt,
is_admin,
password_length_check,
Perform,
};
use actix_web::web::Data;
@ -12,6 +12,7 @@ use anyhow::Context;
use bcrypt::verify;
use captcha::{gen, Difficulty};
use chrono::Duration;
use lemmy_api_structs::{blocking, send_email_to_user, user::*};
use lemmy_apub::{
generate_apub_endpoint,
generate_followers_url,
@ -22,6 +23,7 @@ use lemmy_apub::{
};
use lemmy_db_queries::{
diesel_option_overwrite,
diesel_option_overwrite_to_url,
source::{
comment::Comment_,
community::Community_,
@ -65,13 +67,12 @@ use lemmy_db_views_actor::{
user_mention_view::{UserMentionQueryBuilder, UserMentionView},
user_view::UserViewSafe,
};
use lemmy_structs::{blocking, send_email_to_user, user::*};
use lemmy_utils::{
apub::generate_actor_keypair,
claims::Claims,
email::send_email,
location_info,
settings::Settings,
settings::structs::Settings,
utils::{
check_slurs,
generate_random_string,
@ -121,7 +122,7 @@ impl Perform for Login {
// Return the jwt
Ok(LoginResponse {
jwt: Claims::jwt(user.id, Settings::get().hostname)?,
jwt: Claims::jwt(user.id, Settings::get().hostname())?,
})
}
}
@ -144,10 +145,7 @@ impl Perform for Register {
}
}
// Password length check
if data.password.len() > 60 {
return Err(ApiError::err("invalid_password").into());
}
password_length_check(&data.password)?;
// Make sure passwords match
if data.password != data.password_verify {
@ -161,7 +159,7 @@ impl Perform for Register {
.await??;
// If its not the admin, check the captcha
if !no_admins && Settings::get().captcha.enabled {
if !no_admins && Settings::get().captcha().enabled {
let check = context
.chat_server()
.send(CheckCaptcha {
@ -302,7 +300,7 @@ impl Perform for Register {
// Return the jwt
Ok(LoginResponse {
jwt: Claims::jwt(inserted_user.id, Settings::get().hostname)?,
jwt: Claims::jwt(inserted_user.id, Settings::get().hostname())?,
})
}
}
@ -316,7 +314,7 @@ impl Perform for GetCaptcha {
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<Self::Response, LemmyError> {
let captcha_settings = Settings::get().captcha;
let captcha_settings = Settings::get().captcha();
if !captcha_settings.enabled {
return Ok(GetCaptchaResponse { ok: None });
@ -366,17 +364,13 @@ impl Perform for SaveUserSettings {
let data: &SaveUserSettings = &self;
let user = get_user_from_jwt(&data.auth, context.pool()).await?;
let avatar = diesel_option_overwrite(&data.avatar);
let banner = diesel_option_overwrite(&data.banner);
let avatar = diesel_option_overwrite_to_url(&data.avatar)?;
let banner = diesel_option_overwrite_to_url(&data.banner)?;
let email = diesel_option_overwrite(&data.email);
let bio = diesel_option_overwrite(&data.bio);
let preferred_username = diesel_option_overwrite(&data.preferred_username);
let matrix_user_id = diesel_option_overwrite(&data.matrix_user_id);
// Check to make sure the avatar and banners are urls
check_optional_url(&avatar)?;
check_optional_url(&banner)?;
if let Some(Some(bio)) = &bio {
if bio.chars().count() > 300 {
return Err(ApiError::err("bio_length_overflow").into());
@ -394,6 +388,8 @@ impl Perform for SaveUserSettings {
Some(new_password) => {
match &data.new_password_verify {
Some(new_password_verify) => {
password_length_check(&new_password)?;
// Make sure passwords match
if new_password != new_password_verify {
return Err(ApiError::err("passwords_dont_match").into());
@ -475,7 +471,7 @@ impl Perform for SaveUserSettings {
// Return the jwt
Ok(LoginResponse {
jwt: Claims::jwt(updated_user.id, Settings::get().hostname)?,
jwt: Claims::jwt(updated_user.id, Settings::get().hostname())?,
})
}
}
@ -993,6 +989,8 @@ impl Perform for PasswordChange {
})
.await??;
password_length_check(&data.password)?;
// Make sure passwords match
if data.password != data.password_verify {
return Err(ApiError::err("passwords_dont_match").into());
@ -1011,7 +1009,7 @@ impl Perform for PasswordChange {
// Return the jwt
Ok(LoginResponse {
jwt: Claims::jwt(updated_user.id, Settings::get().hostname)?,
jwt: Claims::jwt(updated_user.id, Settings::get().hostname())?,
})
}
}

View File

@ -1,6 +1,6 @@
use crate::{get_user_from_jwt, Perform};
use actix_web::web::Data;
use lemmy_structs::websocket::*;
use lemmy_api_structs::websocket::*;
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::{
messages::{JoinCommunityRoom, JoinModRoom, JoinPostRoom, JoinUserRoom},

View File

@ -1,11 +1,10 @@
[package]
name = "lemmy_structs"
name = "lemmy_api_structs"
version = "0.1.0"
authors = ["Felix Ableitner <me@nutomic.com>"]
edition = "2018"
[lib]
name = "lemmy_structs"
name = "lemmy_api_structs"
path = "src/lib.rs"
doctest = false
@ -22,4 +21,4 @@ diesel = "1.4.5"
actix-web = "3.3.2"
chrono = { version = "0.4.19", features = ["serde"] }
serde_json = { version = "1.0.61", features = ["preserve_order"] }
url = "2.2.0"
url = "2.2.1"

View File

@ -27,7 +27,6 @@ pub struct CreateCommunity {
pub description: Option<String>,
pub icon: Option<String>,
pub banner: Option<String>,
pub category_id: i32,
pub nsfw: bool,
pub auth: String,
}
@ -88,7 +87,6 @@ pub struct EditCommunity {
pub description: Option<String>,
pub icon: Option<String>,
pub banner: Option<String>,
pub category_id: i32,
pub nsfw: bool,
pub auth: String,
}

View File

@ -13,7 +13,7 @@ use lemmy_db_schema::source::{
user::User_,
user_mention::{UserMention, UserMentionForm},
};
use lemmy_utils::{email::send_email, settings::Settings, utils::MentionData, LemmyError};
use lemmy_utils::{email::send_email, settings::structs::Settings, utils::MentionData, LemmyError};
use log::error;
use serde::{Deserialize, Serialize};
use url::Url;
@ -152,7 +152,7 @@ pub fn send_email_to_user(user: User_, subject_text: &str, body_text: &str, comm
let subject = &format!(
"{} - {} {}",
subject_text,
Settings::get().hostname,
Settings::get().hostname(),
user.name,
);
let html = &format!(

View File

@ -8,11 +8,12 @@ use lemmy_db_views_actor::{
community_view::CommunityView,
};
use serde::{Deserialize, Serialize};
use url::Url;
#[derive(Deserialize, Debug)]
pub struct CreatePost {
pub name: String,
pub url: Option<String>,
pub url: Option<Url>,
pub body: Option<String>,
pub nsfw: bool,
pub community_id: i32,
@ -66,7 +67,7 @@ pub struct CreatePostLike {
pub struct EditPost {
pub post_id: i32,
pub name: String,
pub url: Option<String>,
pub url: Option<Url>,
pub body: Option<String>,
pub nsfw: bool,
pub auth: String,

View File

@ -13,6 +13,7 @@ use lemmy_db_views_moderator::{
mod_sticky_post_view::ModStickyPostView,
};
use serde::{Deserialize, Serialize};
use url::Url;
#[derive(Deserialize, Debug)]
pub struct Search {
@ -60,8 +61,8 @@ pub struct GetModlogResponse {
pub struct CreateSite {
pub name: String,
pub description: Option<String>,
pub icon: Option<String>,
pub banner: Option<String>,
pub icon: Option<Url>,
pub banner: Option<Url>,
pub enable_downvotes: bool,
pub open_registration: bool,
pub enable_nsfw: bool,
@ -126,6 +127,6 @@ pub struct SaveSiteConfig {
#[derive(Serialize)]
pub struct FederatedInstances {
pub linked: Vec<String>,
pub allowed: Vec<String>,
pub blocked: Vec<String>,
pub allowed: Option<Vec<String>>,
pub blocked: Option<Vec<String>>,
}

View File

@ -1,7 +1,6 @@
[package]
name = "lemmy_apub"
version = "0.1.0"
authors = ["Felix Ableitner <me@nutomic.com>"]
edition = "2018"
[lib]
@ -15,7 +14,7 @@ lemmy_db_queries = { path = "../db_queries" }
lemmy_db_schema = { path = "../db_schema" }
lemmy_db_views = { path = "../db_views" }
lemmy_db_views_actor = { path = "../db_views_actor" }
lemmy_structs = { path = "../structs" }
lemmy_api_structs = { path = "../api_structs" }
lemmy_websocket = { path = "../websocket" }
diesel = "1.4.5"
activitystreams = "0.7.0-alpha.10"
@ -33,7 +32,7 @@ rand = "0.8.3"
strum = "0.20.0"
strum_macros = "0.20.1"
lazy_static = "1.4.0"
url = { version = "2.2.0", features = ["serde"] }
url = { version = "2.2.1", features = ["serde"] }
percent-encoding = "2.1.0"
openssl = "0.10.32"
http = "0.2.3"

View File

@ -4,13 +4,13 @@ use activitystreams::{
base::ExtendsExt,
};
use anyhow::Context;
use lemmy_api_structs::{blocking, comment::CommentResponse, send_local_notifs};
use lemmy_db_queries::{source::comment::Comment_, Crud, Likeable};
use lemmy_db_schema::source::{
comment::{Comment, CommentLike, CommentLikeForm},
post::Post,
};
use lemmy_db_views::comment_view::CommentView;
use lemmy_structs::{blocking, comment::CommentResponse, send_local_notifs};
use lemmy_utils::{location_info, utils::scrape_text_for_mentions, LemmyError};
use lemmy_websocket::{messages::SendComment, LemmyContext, UserOperation};

View File

@ -1,9 +1,9 @@
use crate::activities::receive::get_actor_as_user;
use activitystreams::activity::{Dislike, Like};
use lemmy_api_structs::{blocking, comment::CommentResponse};
use lemmy_db_queries::{source::comment::Comment_, Likeable};
use lemmy_db_schema::source::comment::{Comment, CommentLike};
use lemmy_db_views::comment_view::CommentView;
use lemmy_structs::{blocking, comment::CommentResponse};
use lemmy_utils::LemmyError;
use lemmy_websocket::{messages::SendComment, LemmyContext, UserOperation};

View File

@ -4,10 +4,10 @@ use activitystreams::{
base::{AnyBase, ExtendsExt},
};
use anyhow::Context;
use lemmy_api_structs::{blocking, community::CommunityResponse};
use lemmy_db_queries::{source::community::Community_, ApubObject};
use lemmy_db_schema::source::community::Community;
use lemmy_db_views_actor::community_view::CommunityView;
use lemmy_structs::{blocking, community::CommunityResponse};
use lemmy_utils::{location_info, LemmyError};
use lemmy_websocket::{messages::SendCommunityRoomMessage, LemmyContext, UserOperation};
use url::Url;

View File

@ -4,10 +4,10 @@ use activitystreams::{
prelude::*,
};
use anyhow::Context;
use lemmy_api_structs::{blocking, post::PostResponse};
use lemmy_db_queries::{source::post::Post_, Likeable};
use lemmy_db_schema::source::post::{Post, PostLike, PostLikeForm};
use lemmy_db_views::post_view::PostView;
use lemmy_structs::{blocking, post::PostResponse};
use lemmy_utils::{location_info, LemmyError};
use lemmy_websocket::{messages::SendPost, LemmyContext, UserOperation};

View File

@ -1,9 +1,9 @@
use crate::activities::receive::get_actor_as_user;
use activitystreams::activity::{Dislike, Like};
use lemmy_api_structs::{blocking, post::PostResponse};
use lemmy_db_queries::{source::post::Post_, Likeable};
use lemmy_db_schema::source::post::{Post, PostLike};
use lemmy_db_views::post_view::PostView;
use lemmy_structs::{blocking, post::PostResponse};
use lemmy_utils::LemmyError;
use lemmy_websocket::{messages::SendPost, LemmyContext, UserOperation};

View File

@ -13,10 +13,10 @@ use activitystreams::{
public,
};
use anyhow::{anyhow, Context};
use lemmy_api_structs::{blocking, user::PrivateMessageResponse};
use lemmy_db_queries::source::private_message::PrivateMessage_;
use lemmy_db_schema::source::private_message::PrivateMessage;
use lemmy_db_views::private_message_view::PrivateMessageView;
use lemmy_structs::{blocking, user::PrivateMessageResponse};
use lemmy_utils::{location_info, LemmyError};
use lemmy_websocket::{messages::SendUserRoomMessage, LemmyContext, UserOperation};
use url::Url;

View File

@ -26,12 +26,12 @@ use activitystreams::{
};
use anyhow::anyhow;
use itertools::Itertools;
use lemmy_api_structs::{blocking, WebFingerResponse};
use lemmy_db_queries::{Crud, DbPool};
use lemmy_db_schema::source::{comment::Comment, community::Community, post::Post, user::User_};
use lemmy_structs::{blocking, WebFingerResponse};
use lemmy_utils::{
request::{retry, RecvError},
settings::Settings,
settings::structs::Settings,
utils::{scrape_text_for_mentions, MentionData},
LemmyError,
};

View File

@ -23,10 +23,10 @@ use activitystreams::{
};
use anyhow::Context;
use itertools::Itertools;
use lemmy_api_structs::blocking;
use lemmy_db_queries::DbPool;
use lemmy_db_schema::source::community::Community;
use lemmy_db_views_actor::community_follower_view::CommunityFollowerView;
use lemmy_structs::blocking;
use lemmy_utils::{location_info, LemmyError};
use lemmy_websocket::LemmyContext;
use url::Url;

View File

@ -1,4 +1,4 @@
use lemmy_utils::settings::Settings;
use lemmy_utils::settings::structs::Settings;
use url::{ParseError, Url};
use uuid::Uuid;

View File

@ -21,9 +21,9 @@ use activitystreams::{
prelude::*,
public,
};
use lemmy_api_structs::blocking;
use lemmy_db_queries::Crud;
use lemmy_db_schema::source::{community::Community, post::Post, user::User_};
use lemmy_structs::blocking;
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;

View File

@ -16,9 +16,9 @@ use activitystreams::{
},
prelude::*,
};
use lemmy_api_structs::blocking;
use lemmy_db_queries::Crud;
use lemmy_db_schema::source::{private_message::PrivateMessage, user::User_};
use lemmy_structs::blocking;
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;

View File

@ -13,12 +13,12 @@ use activitystreams::{
base::{AnyBase, BaseExt, ExtendsExt},
object::ObjectExt,
};
use lemmy_api_structs::blocking;
use lemmy_db_queries::{ApubObject, DbPool, Followable};
use lemmy_db_schema::source::{
community::{Community, CommunityFollower, CommunityFollowerForm},
user::User_,
};
use lemmy_structs::blocking;
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
use url::Url;

View File

@ -22,7 +22,7 @@ use background_jobs::{
use itertools::Itertools;
use lemmy_db_queries::DbPool;
use lemmy_db_schema::source::{community::Community, user::User_};
use lemmy_utils::{location_info, settings::Settings, LemmyError};
use lemmy_utils::{location_info, settings::structs::Settings, LemmyError};
use lemmy_websocket::LemmyContext;
use log::{debug, warn};
use reqwest::Client;
@ -88,7 +88,7 @@ where
.await?
.iter()
.unique()
.filter(|inbox| inbox.host_str() != Some(&Settings::get().hostname))
.filter(|inbox| inbox.host_str() != Some(&Settings::get().hostname()))
.filter(|inbox| check_is_apub_id_valid(inbox).is_ok())
.map(|inbox| inbox.to_owned())
.collect();
@ -215,7 +215,7 @@ where
Kind: Serialize,
<T as Extends<Kind>>::Error: From<serde_json::Error> + Send + Sync + 'static,
{
if !Settings::get().federation.enabled || inboxes.is_empty() {
if !Settings::get().federation().enabled || inboxes.is_empty() {
return Ok(());
}
@ -223,7 +223,7 @@ where
let hostname = Settings::get().get_hostname_without_port()?;
let inboxes: Vec<&Url> = inboxes
.iter()
.filter(|i| i.domain().unwrap() != hostname)
.filter(|i| i.domain().expect("valid inbox url") != hostname)
.collect();
let activity = activity.into_any_base()?;

View File

@ -6,7 +6,6 @@ pub(crate) fn lemmy_context() -> Result<Vec<AnyBase>, LemmyError> {
let context_ext = AnyBase::from_arbitrary_json(json!(
{
"sc": "http://schema.org#",
"category": "sc:category",
"sensitive": "as:sensitive",
"stickied": "as:stickied",
"comments_enabled": {

View File

@ -16,9 +16,9 @@ use activitystreams::{
};
use anyhow::Context;
use diesel::result::Error::NotFound;
use lemmy_api_structs::blocking;
use lemmy_db_queries::{source::community::Community_, ApubObject, Joinable};
use lemmy_db_schema::source::community::{Community, CommunityModerator, CommunityModeratorForm};
use lemmy_structs::blocking;
use lemmy_utils::{location_info, LemmyError};
use lemmy_websocket::LemmyContext;
use log::debug;

View File

@ -1,9 +1,9 @@
use crate::{fetcher::fetch::fetch_remote_object, objects::FromApub, NoteExt, PageExt};
use anyhow::anyhow;
use diesel::result::Error::NotFound;
use lemmy_api_structs::blocking;
use lemmy_db_queries::{ApubObject, Crud};
use lemmy_db_schema::source::{comment::Comment, post::Post};
use lemmy_structs::blocking;
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
use log::debug;

View File

@ -15,6 +15,7 @@ use crate::{
};
use activitystreams::base::BaseExt;
use anyhow::{anyhow, Context};
use lemmy_api_structs::{blocking, site::SearchResponse};
use lemmy_db_queries::{
source::{
comment::Comment_,
@ -34,8 +35,7 @@ use lemmy_db_schema::source::{
};
use lemmy_db_views::{comment_view::CommentView, post_view::PostView};
use lemmy_db_views_actor::{community_view::CommunityView, user_view::UserViewSafe};
use lemmy_structs::{blocking, site::SearchResponse};
use lemmy_utils::{settings::Settings, LemmyError};
use lemmy_utils::{settings::structs::Settings, LemmyError};
use lemmy_websocket::LemmyContext;
use log::debug;
use url::Url;

View File

@ -5,9 +5,9 @@ use crate::{
};
use anyhow::anyhow;
use diesel::result::Error::NotFound;
use lemmy_api_structs::blocking;
use lemmy_db_queries::{source::user::User, ApubObject};
use lemmy_db_schema::source::user::User_;
use lemmy_structs::blocking;
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
use log::debug;

View File

@ -4,9 +4,9 @@ use crate::{
};
use actix_web::{body::Body, web, web::Path, HttpResponse};
use diesel::result::Error::NotFound;
use lemmy_api_structs::blocking;
use lemmy_db_queries::Crud;
use lemmy_db_schema::source::comment::Comment;
use lemmy_structs::blocking;
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
use serde::Deserialize;

View File

@ -9,10 +9,10 @@ use activitystreams::{
collection::{CollectionExt, OrderedCollection, UnorderedCollection},
};
use actix_web::{body::Body, web, HttpResponse};
use lemmy_api_structs::blocking;
use lemmy_db_queries::source::{activity::Activity_, community::Community_};
use lemmy_db_schema::source::{activity::Activity, community::Community};
use lemmy_db_views_actor::community_follower_view::CommunityFollowerView;
use lemmy_structs::blocking;
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
use serde::Deserialize;

View File

@ -1,12 +1,13 @@
use crate::APUB_JSON_CONTENT_TYPE;
use actix_web::{body::Body, web, HttpResponse};
use http::StatusCode;
use lemmy_api_structs::blocking;
use lemmy_db_queries::source::activity::Activity_;
use lemmy_db_schema::source::activity::Activity;
use lemmy_structs::blocking;
use lemmy_utils::{settings::Settings, LemmyError};
use lemmy_utils::{settings::structs::Settings, LemmyError};
use lemmy_websocket::LemmyContext;
use serde::{Deserialize, Serialize};
use url::Url;
pub mod comment;
pub mod community;
@ -46,12 +47,13 @@ pub async fn get_activity(
context: web::Data<LemmyContext>,
) -> Result<HttpResponse<Body>, LemmyError> {
let settings = Settings::get();
let activity_id = format!(
let activity_id = Url::parse(&format!(
"{}/activities/{}/{}",
settings.get_protocol_and_hostname(),
info.type_,
info.id
);
))?
.into();
let activity = blocking(context.pool(), move |conn| {
Activity::read_from_apub_id(&conn, &activity_id)
})

View File

@ -4,9 +4,9 @@ use crate::{
};
use actix_web::{body::Body, web, HttpResponse};
use diesel::result::Error::NotFound;
use lemmy_api_structs::blocking;
use lemmy_db_queries::Crud;
use lemmy_db_schema::source::post::Post;
use lemmy_structs::blocking;
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
use serde::Deserialize;

View File

@ -9,9 +9,9 @@ use activitystreams::{
collection::{CollectionExt, OrderedCollection},
};
use actix_web::{body::Body, web, HttpResponse};
use lemmy_api_structs::blocking;
use lemmy_db_queries::source::user::User;
use lemmy_db_schema::source::user::User_;
use lemmy_structs::blocking;
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
use serde::Deserialize;

View File

@ -26,13 +26,13 @@ use activitystreams::{
};
use actix_web::{web, HttpRequest, HttpResponse};
use anyhow::{anyhow, Context};
use lemmy_api_structs::blocking;
use lemmy_db_queries::{source::community::Community_, ApubObject, DbPool, Followable};
use lemmy_db_schema::source::{
community::{Community, CommunityFollower, CommunityFollowerForm},
user::User_,
};
use lemmy_db_views_actor::community_user_ban_view::CommunityUserBanView;
use lemmy_structs::blocking;
use lemmy_utils::{location_info, LemmyError};
use lemmy_websocket::LemmyContext;
use log::info;

View File

@ -12,14 +12,14 @@ use activitystreams::{
};
use actix_web::HttpRequest;
use anyhow::{anyhow, Context};
use lemmy_api_structs::blocking;
use lemmy_db_queries::{
source::{activity::Activity_, community::Community_},
ApubObject,
DbPool,
};
use lemmy_db_schema::source::{activity::Activity, community::Community, user::User_};
use lemmy_structs::blocking;
use lemmy_utils::{location_info, settings::Settings, LemmyError};
use lemmy_utils::{location_info, settings::structs::Settings, LemmyError};
use lemmy_websocket::LemmyContext;
use serde::Serialize;
use std::fmt::Debug;
@ -45,7 +45,7 @@ pub(crate) async fn is_activity_already_known(
pool: &DbPool,
activity_id: &Url,
) -> Result<bool, LemmyError> {
let activity_id = activity_id.to_string();
let activity_id = activity_id.to_owned().into();
let existing = blocking(pool, move |conn| {
Activity::read_from_apub_id(&conn, &activity_id)
})
@ -167,7 +167,7 @@ where
let id = activity.id_unchecked().context(location_info!())?;
let activity_domain = id.domain().context(location_info!())?;
if activity_domain == Settings::get().hostname {
if activity_domain == Settings::get().hostname() {
return Err(
anyhow!(
"Error: received activity which was sent by local instance: {:?}",

View File

@ -43,9 +43,9 @@ use activitystreams::{
};
use anyhow::Context;
use diesel::result::Error::NotFound;
use lemmy_api_structs::blocking;
use lemmy_db_queries::Crud;
use lemmy_db_schema::source::site::Site;
use lemmy_structs::blocking;
use lemmy_utils::{location_info, LemmyError};
use lemmy_websocket::LemmyContext;
use strum_macros::EnumString;
@ -120,9 +120,9 @@ pub(in crate::inbox) async fn receive_like_for_community(
.as_single_xsd_any_uri()
.context(location_info!())?;
match fetch_post_or_comment_by_id(&object_id, context, request_counter).await? {
PostOrComment::Post(post) => receive_like_post(like, post, context, request_counter).await,
PostOrComment::Post(post) => receive_like_post(like, *post, context, request_counter).await,
PostOrComment::Comment(comment) => {
receive_like_comment(like, comment, context, request_counter).await
receive_like_comment(like, *comment, context, request_counter).await
}
}
}
@ -152,10 +152,10 @@ pub(in crate::inbox) async fn receive_dislike_for_community(
.context(location_info!())?;
match fetch_post_or_comment_by_id(&object_id, context, request_counter).await? {
PostOrComment::Post(post) => {
receive_dislike_post(dislike, post, context, request_counter).await
receive_dislike_post(dislike, *post, context, request_counter).await
}
PostOrComment::Comment(comment) => {
receive_dislike_comment(dislike, comment, context, request_counter).await
receive_dislike_comment(dislike, *comment, context, request_counter).await
}
}
}
@ -177,8 +177,8 @@ pub(in crate::inbox) async fn receive_delete_for_community(
.context(location_info!())?;
match find_post_or_comment_by_id(context, object).await {
Ok(PostOrComment::Post(p)) => receive_delete_post(context, p).await,
Ok(PostOrComment::Comment(c)) => receive_delete_comment(context, c).await,
Ok(PostOrComment::Post(p)) => receive_delete_post(context, *p).await,
Ok(PostOrComment::Comment(c)) => receive_delete_comment(context, *c).await,
// if we dont have the object, no need to do anything
Err(_) => Ok(()),
}
@ -215,8 +215,8 @@ pub(in crate::inbox) async fn receive_remove_for_community(
remove.id(community_id.domain().context(location_info!())?)?;
match find_post_or_comment_by_id(context, object).await {
Ok(PostOrComment::Post(p)) => receive_remove_post(context, remove, p).await,
Ok(PostOrComment::Comment(c)) => receive_remove_comment(context, remove, c).await,
Ok(PostOrComment::Post(p)) => receive_remove_post(context, remove, *p).await,
Ok(PostOrComment::Comment(c)) => receive_remove_comment(context, remove, *c).await,
// if we dont have the object, no need to do anything
Err(_) => Ok(()),
}
@ -276,8 +276,8 @@ pub(in crate::inbox) async fn receive_undo_delete_for_community(
.single_xsd_any_uri()
.context(location_info!())?;
match find_post_or_comment_by_id(context, object).await {
Ok(PostOrComment::Post(p)) => receive_undo_delete_post(context, p).await,
Ok(PostOrComment::Comment(c)) => receive_undo_delete_comment(context, c).await,
Ok(PostOrComment::Post(p)) => receive_undo_delete_post(context, *p).await,
Ok(PostOrComment::Comment(c)) => receive_undo_delete_comment(context, *c).await,
// if we dont have the object, no need to do anything
Err(_) => Ok(()),
}
@ -300,8 +300,8 @@ pub(in crate::inbox) async fn receive_undo_remove_for_community(
.single_xsd_any_uri()
.context(location_info!())?;
match find_post_or_comment_by_id(context, object).await {
Ok(PostOrComment::Post(p)) => receive_undo_remove_post(context, p).await,
Ok(PostOrComment::Comment(c)) => receive_undo_remove_comment(context, c).await,
Ok(PostOrComment::Post(p)) => receive_undo_remove_post(context, *p).await,
Ok(PostOrComment::Comment(c)) => receive_undo_remove_comment(context, *c).await,
// if we dont have the object, no need to do anything
Err(_) => Ok(()),
}
@ -325,10 +325,10 @@ pub(in crate::inbox) async fn receive_undo_like_for_community(
.context(location_info!())?;
match fetch_post_or_comment_by_id(&object_id, context, request_counter).await? {
PostOrComment::Post(post) => {
receive_undo_like_post(&like, post, context, request_counter).await
receive_undo_like_post(&like, *post, context, request_counter).await
}
PostOrComment::Comment(comment) => {
receive_undo_like_comment(&like, comment, context, request_counter).await
receive_undo_like_comment(&like, *comment, context, request_counter).await
}
}
}
@ -351,10 +351,10 @@ pub(in crate::inbox) async fn receive_undo_dislike_for_community(
.context(location_info!())?;
match fetch_post_or_comment_by_id(&object_id, context, request_counter).await? {
PostOrComment::Post(post) => {
receive_undo_dislike_post(&dislike, post, context, request_counter).await
receive_undo_dislike_post(&dislike, *post, context, request_counter).await
}
PostOrComment::Comment(comment) => {
receive_undo_dislike_comment(&dislike, comment, context, request_counter).await
receive_undo_dislike_comment(&dislike, *comment, context, request_counter).await
}
}
}
@ -365,11 +365,11 @@ async fn fetch_post_or_comment_by_id(
request_counter: &mut i32,
) -> Result<PostOrComment, LemmyError> {
if let Ok(post) = get_or_fetch_and_insert_post(apub_id, context, request_counter).await {
return Ok(PostOrComment::Post(post));
return Ok(PostOrComment::Post(Box::new(post)));
}
if let Ok(comment) = get_or_fetch_and_insert_comment(apub_id, context, request_counter).await {
return Ok(PostOrComment::Comment(comment));
return Ok(PostOrComment::Comment(Box::new(comment)));
}
Err(NotFound.into())

View File

@ -15,9 +15,9 @@ use crate::{
use activitystreams::{activity::ActorAndObject, prelude::*};
use actix_web::{web, HttpRequest, HttpResponse};
use anyhow::Context;
use lemmy_api_structs::blocking;
use lemmy_db_queries::{ApubObject, DbPool};
use lemmy_db_schema::source::community::Community;
use lemmy_structs::blocking;
use lemmy_utils::{location_info, LemmyError};
use lemmy_websocket::LemmyContext;
use serde::{Deserialize, Serialize};

View File

@ -48,13 +48,13 @@ use activitystreams::{
use actix_web::{web, HttpRequest, HttpResponse};
use anyhow::{anyhow, Context};
use diesel::NotFound;
use lemmy_api_structs::blocking;
use lemmy_db_queries::{source::user::User, ApubObject, Followable};
use lemmy_db_schema::source::{
community::{Community, CommunityFollower},
private_message::PrivateMessage,
user::User_,
};
use lemmy_structs::blocking;
use lemmy_utils::{location_info, LemmyError};
use lemmy_websocket::LemmyContext;
use log::debug;
@ -143,7 +143,14 @@ pub(crate) async fn user_receive_message(
let actor_url = actor.actor_id();
match kind {
UserValidTypes::Accept => {
receive_accept(&context, any_base, actor, to_user.unwrap(), request_counter).await?;
receive_accept(
&context,
any_base,
actor,
to_user.expect("user provided"),
request_counter,
)
.await?;
}
UserValidTypes::Announce => {
receive_announce(&context, any_base, actor, request_counter).await?

View File

@ -24,17 +24,20 @@ use activitystreams::{
use activitystreams_ext::{Ext1, Ext2};
use anyhow::{anyhow, Context};
use diesel::NotFound;
use lemmy_api_structs::blocking;
use lemmy_db_queries::{source::activity::Activity_, ApubObject, DbPool};
use lemmy_db_schema::source::{
use lemmy_db_schema::{
source::{
activity::Activity,
comment::Comment,
community::Community,
post::Post,
private_message::PrivateMessage,
user::User_,
},
DbUrl,
};
use lemmy_structs::blocking;
use lemmy_utils::{location_info, settings::Settings, LemmyError};
use lemmy_utils::{location_info, settings::structs::Settings, LemmyError};
use lemmy_websocket::LemmyContext;
use serde::Serialize;
use std::net::IpAddr;
@ -64,7 +67,7 @@ fn check_is_apub_id_valid(apub_id: &Url) -> Result<(), LemmyError> {
let domain = apub_id.domain().context(location_info!())?.to_string();
let local_instance = settings.get_hostname_without_port()?;
if !settings.federation.enabled {
if !settings.federation().enabled {
return if domain == local_instance {
Ok(())
} else {
@ -88,22 +91,23 @@ fn check_is_apub_id_valid(apub_id: &Url) -> Result<(), LemmyError> {
return Err(anyhow!("invalid apub id scheme {}: {}", apub_id.scheme(), apub_id).into());
}
let mut allowed_instances = Settings::get().get_allowed_instances();
let allowed_instances = Settings::get().get_allowed_instances();
let blocked_instances = Settings::get().get_blocked_instances();
if allowed_instances.is_empty() && blocked_instances.is_empty() {
if allowed_instances.is_none() && blocked_instances.is_none() {
Ok(())
} else if !allowed_instances.is_empty() {
} else if let Some(mut allowed) = allowed_instances {
// need to allow this explicitly because apub receive might contain objects from our local
// instance. split is needed to remove the port in our federation test setup.
allowed_instances.push(local_instance);
allowed.push(local_instance);
if allowed_instances.contains(&domain) {
if allowed.contains(&domain) {
Ok(())
} else {
Err(anyhow!("{} not in federation allowlist", domain).into())
}
} else if !blocked_instances.is_empty() {
if blocked_instances.contains(&domain) {
} else if let Some(blocked) = blocked_instances {
if blocked.contains(&domain) {
Err(anyhow!("{} is in federation blocklist", domain).into())
} else {
Ok(())
@ -215,7 +219,7 @@ pub enum EndpointType {
pub fn generate_apub_endpoint(
endpoint_type: EndpointType,
name: &str,
) -> Result<lemmy_db_schema::Url, ParseError> {
) -> Result<DbUrl, ParseError> {
let point = match endpoint_type {
EndpointType::Community => "c",
EndpointType::User => "u",
@ -235,21 +239,15 @@ pub fn generate_apub_endpoint(
)
}
pub fn generate_followers_url(
actor_id: &lemmy_db_schema::Url,
) -> Result<lemmy_db_schema::Url, ParseError> {
pub fn generate_followers_url(actor_id: &DbUrl) -> Result<DbUrl, ParseError> {
Ok(Url::parse(&format!("{}/followers", actor_id))?.into())
}
pub fn generate_inbox_url(
actor_id: &lemmy_db_schema::Url,
) -> Result<lemmy_db_schema::Url, ParseError> {
pub fn generate_inbox_url(actor_id: &DbUrl) -> Result<DbUrl, ParseError> {
Ok(Url::parse(&format!("{}/inbox", actor_id))?.into())
}
pub fn generate_shared_inbox_url(
actor_id: &lemmy_db_schema::Url,
) -> Result<lemmy_db_schema::Url, LemmyError> {
pub fn generate_shared_inbox_url(actor_id: &DbUrl) -> Result<DbUrl, LemmyError> {
let actor_id = actor_id.clone().into_inner();
let url = format!(
"{}://{}{}/inbox",
@ -276,7 +274,7 @@ pub(crate) async fn insert_activity<T>(
where
T: Serialize + std::fmt::Debug + Send + 'static,
{
let ap_id = ap_id.to_string();
let ap_id = ap_id.to_owned().into();
blocking(pool, move |conn| {
Activity::insert(conn, ap_id, &activity, local, sensitive)
})
@ -285,8 +283,8 @@ where
}
pub(crate) enum PostOrComment {
Comment(Comment),
Post(Post),
Comment(Box<Comment>),
Post(Box<Post>),
}
/// Tries to find a post or comment in the local database, without any network requests.
@ -302,7 +300,7 @@ pub(crate) async fn find_post_or_comment_by_id(
})
.await?;
if let Ok(p) = post {
return Ok(PostOrComment::Post(p));
return Ok(PostOrComment::Post(Box::new(p)));
}
let ap_id = apub_id.clone();
@ -311,7 +309,7 @@ pub(crate) async fn find_post_or_comment_by_id(
})
.await?;
if let Ok(c) = comment {
return Ok(PostOrComment::Comment(c));
return Ok(PostOrComment::Comment(Box::new(c)));
}
Err(NotFound.into())
@ -332,8 +330,8 @@ pub(crate) async fn find_object_by_id(
let ap_id = apub_id.clone();
if let Ok(pc) = find_post_or_comment_by_id(context, ap_id.to_owned()).await {
return Ok(match pc {
PostOrComment::Post(p) => Object::Post(p),
PostOrComment::Comment(c) => Object::Comment(c),
PostOrComment::Post(p) => Object::Post(*p),
PostOrComment::Comment(c) => Object::Comment(*c),
});
}

View File

@ -21,13 +21,13 @@ use activitystreams::{
public,
};
use anyhow::{anyhow, Context};
use lemmy_api_structs::blocking;
use lemmy_db_queries::{Crud, DbPool};
use lemmy_db_schema::source::{
comment::{Comment, CommentForm},
post::Post,
user::User_,
};
use lemmy_structs::blocking;
use lemmy_utils::{
location_info,
utils::{convert_datetime, remove_slurs},

View File

@ -22,13 +22,13 @@ use activitystreams::{
};
use activitystreams_ext::Ext2;
use anyhow::Context;
use lemmy_api_structs::blocking;
use lemmy_db_queries::DbPool;
use lemmy_db_schema::{
naive_now,
source::community::{Community, CommunityForm},
};
use lemmy_db_views_actor::community_moderator_view::CommunityModeratorView;
use lemmy_structs::blocking;
use lemmy_utils::{
location_info,
utils::{check_slurs, check_slurs_opt, convert_datetime},
@ -73,13 +73,13 @@ impl ToApub for Community {
if let Some(icon_url) = &self.icon {
let mut image = Image::new();
image.set_url(Url::parse(icon_url)?);
image.set_url::<Url>(icon_url.to_owned().into());
group.set_icon(image.into_any_base()?);
}
if let Some(banner_url) = &self.banner {
let mut image = Image::new();
image.set_url(Url::parse(banner_url)?);
image.set_url::<Url>(banner_url.to_owned().into());
group.set_image(image.into_any_base()?);
}
@ -173,7 +173,7 @@ impl FromApubToForm<GroupExt> for CommunityForm {
.url()
.context(location_info!())?
.as_single_xsd_any_uri()
.map(|u| u.to_string()),
.map(|u| u.to_owned().into()),
),
None => None,
};
@ -185,7 +185,7 @@ impl FromApubToForm<GroupExt> for CommunityForm {
.url()
.context(location_info!())?
.as_single_xsd_any_uri()
.map(|u| u.to_string()),
.map(|u| u.to_owned().into()),
),
None => None,
};

View File

@ -12,12 +12,12 @@ use activitystreams::{
use anyhow::{anyhow, Context};
use chrono::NaiveDateTime;
use diesel::result::Error::NotFound;
use lemmy_api_structs::blocking;
use lemmy_db_queries::{ApubObject, Crud, DbPool};
use lemmy_db_schema::source::community::Community;
use lemmy_structs::blocking;
use lemmy_db_schema::{source::community::Community, DbUrl};
use lemmy_utils::{
location_info,
settings::Settings,
settings::structs::Settings,
utils::{convert_datetime, markdown_to_html},
LemmyError,
};
@ -96,7 +96,7 @@ where
pub(in crate::objects) fn check_object_domain<T, Kind>(
apub: &T,
expected_domain: Url,
) -> Result<lemmy_db_schema::Url, LemmyError>
) -> Result<DbUrl, LemmyError>
where
T: Base + AsBase<Kind>,
{
@ -187,7 +187,7 @@ where
let domain = object_id.domain().context(location_info!())?;
// if its a local object, return it directly from the database
if Settings::get().hostname == domain {
if Settings::get().hostname() == domain {
let object = blocking(context.pool(), move |conn| {
To::read_from_apub_id(conn, &object_id.into())
})

View File

@ -22,13 +22,16 @@ use activitystreams::{
};
use activitystreams_ext::Ext1;
use anyhow::Context;
use lemmy_api_structs::blocking;
use lemmy_db_queries::{Crud, DbPool};
use lemmy_db_schema::source::{
use lemmy_db_schema::{
self,
source::{
community::Community,
post::{Post, PostForm},
user::User_,
},
};
use lemmy_structs::blocking;
use lemmy_utils::{
location_info,
request::fetch_iframely_and_pictrs_data,
@ -70,16 +73,13 @@ impl ToApub for Post {
set_content_and_source(&mut page, &body)?;
}
// TODO: hacky code because we get self.url == Some("")
// https://github.com/LemmyNet/lemmy/issues/602
let url = self.url.as_ref().filter(|u| !u.is_empty());
if let Some(u) = url {
page.set_url(Url::parse(u)?);
if let Some(url) = &self.url {
page.set_url::<Url>(url.to_owned().into());
}
if let Some(thumbnail_url) = &self.thumbnail_url {
let mut image = Image::new();
image.set_url(Url::parse(thumbnail_url)?);
image.set_url::<Url>(thumbnail_url.to_owned().into());
page.set_image(image.into_any_base()?);
}
@ -146,7 +146,7 @@ impl FromApubToForm<PageExt> for PostForm {
let community = get_to_community(page, context, request_counter).await?;
let thumbnail_url = match &page.inner.image() {
let thumbnail_url: Option<Url> = match &page.inner.image() {
Some(any_image) => Image::from_any_base(
any_image
.to_owned()
@ -158,7 +158,7 @@ impl FromApubToForm<PageExt> for PostForm {
.url()
.context(location_info!())?
.as_single_xsd_any_uri()
.map(|u| u.to_string()),
.map(|url| url.to_owned()),
None => None,
};
let url = page
@ -166,11 +166,11 @@ impl FromApubToForm<PageExt> for PostForm {
.url()
.map(|u| u.as_single_xsd_any_uri())
.flatten()
.map(|s| s.to_string());
.map(|u| u.to_owned());
let (iframely_title, iframely_description, iframely_html, pictrs_thumbnail) =
if let Some(url) = &url {
fetch_iframely_and_pictrs_data(context.client(), Some(url.to_owned())).await
fetch_iframely_and_pictrs_data(context.client(), Some(url)).await
} else {
(None, None, None, thumbnail_url)
};
@ -192,7 +192,7 @@ impl FromApubToForm<PageExt> for PostForm {
let body_slurs_removed = body.map(|b| remove_slurs(&b));
Ok(PostForm {
name,
url,
url: url.map(|u| u.into()),
body: body_slurs_removed,
creator_id: creator.id,
community_id: community.id,
@ -214,7 +214,7 @@ impl FromApubToForm<PageExt> for PostForm {
embed_title: iframely_title,
embed_description: iframely_description,
embed_html: iframely_html,
thumbnail_url: pictrs_thumbnail,
thumbnail_url: pictrs_thumbnail.map(|u| u.into()),
ap_id: Some(check_object_domain(page, expected_domain)?),
local: false,
})

View File

@ -19,12 +19,12 @@ use activitystreams::{
prelude::*,
};
use anyhow::Context;
use lemmy_api_structs::blocking;
use lemmy_db_queries::{Crud, DbPool};
use lemmy_db_schema::source::{
private_message::{PrivateMessage, PrivateMessageForm},
user::User_,
};
use lemmy_structs::blocking;
use lemmy_utils::{location_info, utils::convert_datetime, LemmyError};
use lemmy_websocket::LemmyContext;
use url::Url;

View File

@ -18,15 +18,15 @@ use activitystreams::{
};
use activitystreams_ext::Ext1;
use anyhow::Context;
use lemmy_api_structs::blocking;
use lemmy_db_queries::{ApubObject, DbPool};
use lemmy_db_schema::{
naive_now,
source::user::{UserForm, User_},
};
use lemmy_structs::blocking;
use lemmy_utils::{
location_info,
settings::Settings,
settings::structs::Settings,
utils::{check_slurs, check_slurs_opt, convert_datetime},
LemmyError,
};
@ -50,13 +50,13 @@ impl ToApub for User_ {
if let Some(avatar_url) = &self.avatar {
let mut image = Image::new();
image.set_url(Url::parse(avatar_url)?);
image.set_url::<Url>(avatar_url.to_owned().into());
person.set_icon(image.into_any_base()?);
}
if let Some(banner_url) = &self.banner {
let mut image = Image::new();
image.set_url(Url::parse(banner_url)?);
image.set_url::<Url>(banner_url.to_owned().into());
person.set_image(image.into_any_base()?);
}
@ -96,7 +96,7 @@ impl FromApub for User_ {
) -> Result<User_, LemmyError> {
let user_id = person.id_unchecked().context(location_info!())?.to_owned();
let domain = user_id.domain().context(location_info!())?;
if domain == Settings::get().hostname {
if domain == Settings::get().hostname() {
let user = blocking(context.pool(), move |conn| {
User_::read_from_apub_id(conn, &user_id.into())
})
@ -126,7 +126,7 @@ impl FromApubToForm<PersonExt> for UserForm {
.url()
.context(location_info!())?
.as_single_xsd_any_uri()
.map(|u| u.to_string()),
.map(|url| url.to_owned()),
),
None => None,
};
@ -139,7 +139,7 @@ impl FromApubToForm<PersonExt> for UserForm {
.url()
.context(location_info!())?
.as_single_xsd_any_uri()
.map(|u| u.to_string()),
.map(|url| url.to_owned()),
),
None => None,
};
@ -174,8 +174,8 @@ impl FromApubToForm<PersonExt> for UserForm {
admin: false,
banned: None,
email: None,
avatar,
banner,
avatar: avatar.map(|o| o.map(|i| i.into())),
banner: banner.map(|o| o.map(|i| i.into())),
published: person.inner.published().map(|u| u.to_owned().naive_local()),
updated: person.updated().map(|u| u.to_owned().naive_local()),
show_nsfw: false,

View File

@ -16,15 +16,15 @@ use crate::{
};
use actix_web::*;
use http_signature_normalization_actix::digest::middleware::VerifyDigest;
use lemmy_utils::settings::Settings;
use lemmy_utils::settings::structs::Settings;
use sha2::{Digest, Sha256};
static APUB_JSON_CONTENT_TYPE_LONG: &str =
"application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"";
pub fn config(cfg: &mut web::ServiceConfig) {
if Settings::get().federation.enabled {
println!("federation enabled, host is {}", Settings::get().hostname);
if Settings::get().federation().enabled {
println!("federation enabled, host is {}", Settings::get().hostname());
let digest_verifier = VerifyDigest::new(Sha256::new());
let header_guard_accept = guard::Any(guard::Header("Accept", APUB_JSON_CONTENT_TYPE))

View File

@ -20,7 +20,7 @@ strum = "0.20.0"
strum_macros = "0.20.1"
log = "0.4.14"
sha2 = "0.9.3"
url = { version = "2.2.0", features = ["serde"] }
url = { version = "2.2.1", features = ["serde"] }
lazy_static = "1.4.0"
regex = "1.4.3"
bcrypt = "0.9.0"

View File

@ -13,10 +13,12 @@ extern crate diesel_migrations;
extern crate serial_test;
use diesel::{result::Error, *};
use lemmy_db_schema::Url;
use lemmy_db_schema::DbUrl;
use lemmy_utils::ApiError;
use regex::Regex;
use serde::{Deserialize, Serialize};
use std::{env, env::VarError};
use url::Url;
pub mod aggregates;
pub mod source;
@ -112,7 +114,7 @@ pub trait Reportable<T> {
}
pub trait ApubObject<T> {
fn read_from_apub_id(conn: &PgConnection, object_id: &Url) -> Result<Self, Error>
fn read_from_apub_id(conn: &PgConnection, object_id: &DbUrl) -> Result<Self, Error>
where
Self: Sized;
fn upsert(conn: &PgConnection, user_form: &T) -> Result<Self, Error>
@ -219,6 +221,20 @@ pub fn diesel_option_overwrite(opt: &Option<String>) -> Option<Option<String>> {
}
}
pub fn diesel_option_overwrite_to_url(
opt: &Option<String>,
) -> Result<Option<Option<DbUrl>>, ApiError> {
match opt.as_ref().map(|s| s.as_str()) {
// An empty string is an erase
Some("") => Ok(Some(None)),
Some(str_url) => match Url::parse(str_url) {
Ok(url) => Ok(Some(Some(url.into()))),
Err(_) => Err(ApiError::err("invalid_url")),
},
None => Ok(None),
}
}
embed_migrations!();
pub fn establish_unpooled_connection() -> PgConnection {
@ -231,7 +247,7 @@ pub fn establish_unpooled_connection() -> PgConnection {
};
let conn =
PgConnection::establish(&db_url).unwrap_or_else(|_| panic!("Error connecting to {}", db_url));
embedded_migrations::run(&conn).unwrap();
embedded_migrations::run(&conn).expect("load migrations");
conn
}
@ -264,7 +280,8 @@ pub fn establish_pooled_connection(
lazy_static! {
static ref EMAIL_REGEX: Regex =
Regex::new(r"^[a-zA-Z0-9.!#$%&*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$").unwrap();
Regex::new(r"^[a-zA-Z0-9.!#$%&*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$")
.expect("compile email regex");
}
pub mod functions {
@ -277,7 +294,7 @@ pub mod functions {
#[cfg(test)]
mod tests {
use super::fuzzy_search;
use super::{fuzzy_search, *};
use crate::is_email_regex;
#[test]
@ -291,4 +308,32 @@ mod tests {
assert!(is_email_regex("gush@gmail.com"));
assert!(!is_email_regex("nada_neutho"));
}
#[test]
fn test_diesel_option_overwrite() {
assert_eq!(diesel_option_overwrite(&None), None);
assert_eq!(diesel_option_overwrite(&Some("".to_string())), Some(None));
assert_eq!(
diesel_option_overwrite(&Some("test".to_string())),
Some(Some("test".to_string()))
);
}
#[test]
fn test_diesel_option_overwrite_to_url() {
assert!(matches!(diesel_option_overwrite_to_url(&None), Ok(None)));
assert!(matches!(
diesel_option_overwrite_to_url(&Some("".to_string())),
Ok(Some(None))
));
assert!(matches!(
diesel_option_overwrite_to_url(&Some("invalid_url".to_string())),
Err(_)
));
let example_url = "https://example.com";
assert!(matches!(
diesel_option_overwrite_to_url(&Some(example_url.to_string())),
Ok(Some(Some(url))) if url == Url::parse(&example_url).unwrap().into()
));
}
}

View File

@ -1,6 +1,6 @@
use crate::Crud;
use diesel::{dsl::*, result::Error, sql_types::Text, *};
use lemmy_db_schema::{source::activity::*, Url};
use lemmy_db_schema::{source::activity::*, DbUrl};
use log::debug;
use serde::Serialize;
use serde_json::Value;
@ -41,7 +41,7 @@ impl Crud<ActivityForm> for Activity {
pub trait Activity_ {
fn insert<T>(
conn: &PgConnection,
ap_id: String,
ap_id: DbUrl,
data: &T,
local: bool,
sensitive: bool,
@ -49,20 +49,20 @@ pub trait Activity_ {
where
T: Serialize + Debug;
fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result<Activity, Error>;
fn read_from_apub_id(conn: &PgConnection, object_id: &DbUrl) -> Result<Activity, Error>;
fn delete_olds(conn: &PgConnection) -> Result<usize, Error>;
/// Returns up to 20 activities of type `Announce/Create/Page` from the community
fn read_community_outbox(
conn: &PgConnection,
community_actor_id: &Url,
community_actor_id: &DbUrl,
) -> Result<Vec<Value>, Error>;
}
impl Activity_ for Activity {
fn insert<T>(
conn: &PgConnection,
ap_id: String,
ap_id: DbUrl,
data: &T,
local: bool,
sensitive: bool,
@ -88,7 +88,7 @@ impl Activity_ for Activity {
}
}
fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result<Activity, Error> {
fn read_from_apub_id(conn: &PgConnection, object_id: &DbUrl) -> Result<Activity, Error> {
use lemmy_db_schema::schema::activity::dsl::*;
activity.filter(ap_id.eq(object_id)).first::<Self>(conn)
}
@ -100,7 +100,7 @@ impl Activity_ for Activity {
fn read_community_outbox(
conn: &PgConnection,
community_actor_id: &Url,
community_actor_id: &DbUrl,
) -> Result<Vec<Value>, Error> {
use lemmy_db_schema::schema::activity::dsl::*;
let res: Vec<Value> = activity
@ -121,6 +121,7 @@ impl Activity_ for Activity {
#[cfg(test)]
mod tests {
use super::*;
use crate::{
establish_unpooled_connection,
source::activity::Activity_,
@ -134,6 +135,7 @@ mod tests {
};
use serde_json::Value;
use serial_test::serial;
use url::Url;
#[test]
#[serial]
@ -171,8 +173,11 @@ mod tests {
let inserted_creator = User_::create(&conn, &creator_form).unwrap();
let ap_id =
"https://enterprise.lemmy.ml/activities/delete/f1b5d57c-80f8-4e03-a615-688d552e946c";
let ap_id: DbUrl = Url::parse(
"https://enterprise.lemmy.ml/activities/delete/f1b5d57c-80f8-4e03-a615-688d552e946c",
)
.unwrap()
.into();
let test_json: Value = serde_json::from_str(
r#"{
"@context": "https://www.w3.org/ns/activitystreams",
@ -188,7 +193,7 @@ mod tests {
)
.unwrap();
let activity_form = ActivityForm {
ap_id: ap_id.to_string(),
ap_id: ap_id.clone(),
data: test_json.to_owned(),
local: true,
sensitive: false,
@ -198,7 +203,7 @@ mod tests {
let inserted_activity = Activity::create(&conn, &activity_form).unwrap();
let expected_activity = Activity {
ap_id: Some(ap_id.to_string()),
ap_id: Some(ap_id.clone()),
id: inserted_activity.id,
data: test_json,
local: true,
@ -208,7 +213,7 @@ mod tests {
};
let read_activity = Activity::read(&conn, inserted_activity.id).unwrap();
let read_activity_by_apub_id = Activity::read_from_apub_id(&conn, ap_id).unwrap();
let read_activity_by_apub_id = Activity::read_from_apub_id(&conn, &ap_id).unwrap();
User_::delete(&conn, inserted_creator.id).unwrap();
Activity::delete(&conn, inserted_activity.id).unwrap();

View File

@ -10,11 +10,11 @@ use lemmy_db_schema::{
CommentSaved,
CommentSavedForm,
},
Url,
DbUrl,
};
pub trait Comment_ {
fn update_ap_id(conn: &PgConnection, comment_id: i32, apub_id: Url) -> Result<Comment, Error>;
fn update_ap_id(conn: &PgConnection, comment_id: i32, apub_id: DbUrl) -> Result<Comment, Error>;
fn permadelete_for_creator(
conn: &PgConnection,
for_creator_id: i32,
@ -43,7 +43,7 @@ pub trait Comment_ {
}
impl Comment_ for Comment {
fn update_ap_id(conn: &PgConnection, comment_id: i32, apub_id: Url) -> Result<Self, Error> {
fn update_ap_id(conn: &PgConnection, comment_id: i32, apub_id: DbUrl) -> Result<Self, Error> {
use lemmy_db_schema::schema::comment::dsl::*;
diesel::update(comment.find(comment_id))
@ -145,7 +145,7 @@ impl Crud<CommentForm> for Comment {
}
impl ApubObject<CommentForm> for Comment {
fn read_from_apub_id(conn: &PgConnection, object_id: &Url) -> Result<Self, Error> {
fn read_from_apub_id(conn: &PgConnection, object_id: &DbUrl) -> Result<Self, Error> {
use lemmy_db_schema::schema::comment::dsl::*;
comment.filter(ap_id.eq(object_id)).first::<Self>(conn)
}

View File

@ -12,7 +12,7 @@ use lemmy_db_schema::{
CommunityUserBan,
CommunityUserBanForm,
},
Url,
DbUrl,
};
mod safe_type {
@ -90,7 +90,7 @@ impl Crud<CommunityForm> for Community {
}
impl ApubObject<CommunityForm> for Community {
fn read_from_apub_id(conn: &PgConnection, for_actor_id: &Url) -> Result<Self, Error> {
fn read_from_apub_id(conn: &PgConnection, for_actor_id: &DbUrl) -> Result<Self, Error> {
use lemmy_db_schema::schema::community::dsl::*;
community
.filter(actor_id.eq(for_actor_id))
@ -131,7 +131,10 @@ pub trait Community_ {
new_creator_id: i32,
) -> Result<Community, Error>;
fn distinct_federated_communities(conn: &PgConnection) -> Result<Vec<String>, Error>;
fn read_from_followers_url(conn: &PgConnection, followers_url: &Url) -> Result<Community, Error>;
fn read_from_followers_url(
conn: &PgConnection,
followers_url: &DbUrl,
) -> Result<Community, Error>;
}
impl Community_ for Community {
@ -194,7 +197,7 @@ impl Community_ for Community {
fn read_from_followers_url(
conn: &PgConnection,
followers_url_: &Url,
followers_url_: &DbUrl,
) -> Result<Community, Error> {
use lemmy_db_schema::schema::community::dsl::*;
community

View File

@ -12,7 +12,7 @@ use lemmy_db_schema::{
PostSaved,
PostSavedForm,
},
Url,
DbUrl,
};
impl Crud<PostForm> for Post {
@ -42,7 +42,7 @@ impl Crud<PostForm> for Post {
pub trait Post_ {
//fn read(conn: &PgConnection, post_id: i32) -> Result<Post, Error>;
fn list_for_community(conn: &PgConnection, the_community_id: i32) -> Result<Vec<Post>, Error>;
fn update_ap_id(conn: &PgConnection, post_id: i32, apub_id: Url) -> Result<Post, Error>;
fn update_ap_id(conn: &PgConnection, post_id: i32, apub_id: DbUrl) -> Result<Post, Error>;
fn permadelete_for_creator(conn: &PgConnection, for_creator_id: i32) -> Result<Vec<Post>, Error>;
fn update_deleted(conn: &PgConnection, post_id: i32, new_deleted: bool) -> Result<Post, Error>;
fn update_removed(conn: &PgConnection, post_id: i32, new_removed: bool) -> Result<Post, Error>;
@ -68,7 +68,7 @@ impl Post_ for Post {
.load::<Self>(conn)
}
fn update_ap_id(conn: &PgConnection, post_id: i32, apub_id: Url) -> Result<Self, Error> {
fn update_ap_id(conn: &PgConnection, post_id: i32, apub_id: DbUrl) -> Result<Self, Error> {
use lemmy_db_schema::schema::post::dsl::*;
diesel::update(post.find(post_id))
@ -147,7 +147,7 @@ impl Post_ for Post {
}
impl ApubObject<PostForm> for Post {
fn read_from_apub_id(conn: &PgConnection, object_id: &Url) -> Result<Self, Error> {
fn read_from_apub_id(conn: &PgConnection, object_id: &DbUrl) -> Result<Self, Error> {
use lemmy_db_schema::schema::post::dsl::*;
post.filter(ap_id.eq(object_id)).first::<Self>(conn)
}

View File

@ -1,6 +1,6 @@
use crate::{ApubObject, Crud};
use diesel::{dsl::*, result::Error, *};
use lemmy_db_schema::{naive_now, source::private_message::*, Url};
use lemmy_db_schema::{naive_now, source::private_message::*, DbUrl};
impl Crud<PrivateMessageForm> for PrivateMessage {
fn read(conn: &PgConnection, private_message_id: i32) -> Result<Self, Error> {
@ -28,7 +28,7 @@ impl Crud<PrivateMessageForm> for PrivateMessage {
}
impl ApubObject<PrivateMessageForm> for PrivateMessage {
fn read_from_apub_id(conn: &PgConnection, object_id: &Url) -> Result<Self, Error>
fn read_from_apub_id(conn: &PgConnection, object_id: &DbUrl) -> Result<Self, Error>
where
Self: Sized,
{
@ -53,7 +53,7 @@ pub trait PrivateMessage_ {
fn update_ap_id(
conn: &PgConnection,
private_message_id: i32,
apub_id: Url,
apub_id: DbUrl,
) -> Result<PrivateMessage, Error>;
fn update_content(
conn: &PgConnection,
@ -80,7 +80,7 @@ impl PrivateMessage_ for PrivateMessage {
fn update_ap_id(
conn: &PgConnection,
private_message_id: i32,
apub_id: Url,
apub_id: DbUrl,
) -> Result<PrivateMessage, Error> {
use lemmy_db_schema::schema::private_message::dsl::*;

View File

@ -5,9 +5,9 @@ use lemmy_db_schema::{
naive_now,
schema::user_::dsl::*,
source::user::{UserForm, UserSafeSettings, User_},
Url,
DbUrl,
};
use lemmy_utils::settings::Settings;
use lemmy_utils::settings::structs::Settings;
mod safe_type {
use crate::ToSafe;
@ -244,7 +244,7 @@ impl Crud<UserForm> for User_ {
}
impl ApubObject<UserForm> for User_ {
fn read_from_apub_id(conn: &PgConnection, object_id: &Url) -> Result<Self, Error> {
fn read_from_apub_id(conn: &PgConnection, object_id: &DbUrl) -> Result<Self, Error> {
use lemmy_db_schema::schema::user_::dsl::*;
user_
.filter(deleted.eq(false))

View File

@ -12,4 +12,4 @@ chrono = { version = "0.4.19", features = ["serde"] }
serde = { version = "1.0.123", features = ["derive"] }
serde_json = { version = "1.0.61", features = ["preserve_order"] }
log = "0.4.14"
url = { version = "2.2.0", features = ["serde"] }
url = { version = "2.2.1", features = ["serde"] }

View File

@ -8,21 +8,22 @@ use diesel::{
serialize::{Output, ToSql},
sql_types::Text,
};
use serde::Serialize;
use serde::{Deserialize, Serialize};
use std::{
fmt::{Display, Formatter},
io::Write,
};
use url::Url;
pub mod schema;
pub mod source;
#[repr(transparent)]
#[derive(Clone, PartialEq, Serialize, Debug, AsExpression, FromSqlRow)]
#[derive(Clone, PartialEq, Serialize, Deserialize, Debug, AsExpression, FromSqlRow)]
#[sql_type = "Text"]
pub struct Url(url::Url);
pub struct DbUrl(Url);
impl<DB: Backend> ToSql<Text, DB> for Url
impl<DB: Backend> ToSql<Text, DB> for DbUrl
where
String: ToSql<Text, DB>,
{
@ -31,37 +32,37 @@ where
}
}
impl<DB: Backend> FromSql<Text, DB> for Url
impl<DB: Backend> FromSql<Text, DB> for DbUrl
where
String: FromSql<Text, DB>,
{
fn from_sql(bytes: Option<&DB::RawValue>) -> diesel::deserialize::Result<Self> {
let str = String::from_sql(bytes)?;
Ok(Url(url::Url::parse(&str)?))
Ok(DbUrl(Url::parse(&str)?))
}
}
impl Url {
pub fn into_inner(self) -> url::Url {
impl DbUrl {
pub fn into_inner(self) -> Url {
self.0
}
}
impl Display for Url {
impl Display for DbUrl {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.to_owned().into_inner().fmt(f)
}
}
impl From<Url> for url::Url {
fn from(url: Url) -> Self {
impl From<DbUrl> for Url {
fn from(url: DbUrl) -> Self {
url.0
}
}
impl From<url::Url> for Url {
fn from(url: url::Url) -> Self {
Url(url)
impl From<Url> for DbUrl {
fn from(url: Url) -> Self {
DbUrl(url)
}
}

View File

@ -1,4 +1,4 @@
use crate::schema::activity;
use crate::{schema::activity, DbUrl};
use serde_json::Value;
use std::fmt::Debug;
@ -10,7 +10,7 @@ pub struct Activity {
pub local: bool,
pub published: chrono::NaiveDateTime,
pub updated: Option<chrono::NaiveDateTime>,
pub ap_id: Option<String>,
pub ap_id: Option<DbUrl>,
pub sensitive: Option<bool>,
}
@ -20,6 +20,6 @@ pub struct ActivityForm {
pub data: Value,
pub local: bool,
pub updated: Option<chrono::NaiveDateTime>,
pub ap_id: String,
pub ap_id: DbUrl,
pub sensitive: bool,
}

View File

@ -1,7 +1,7 @@
use crate::{
schema::{comment, comment_alias_1, comment_like, comment_saved},
source::post::Post,
Url,
DbUrl,
};
use serde::Serialize;
@ -26,7 +26,7 @@ pub struct Comment {
pub published: chrono::NaiveDateTime,
pub updated: Option<chrono::NaiveDateTime>,
pub deleted: bool,
pub ap_id: Url,
pub ap_id: DbUrl,
pub local: bool,
}
@ -44,7 +44,7 @@ pub struct CommentAlias1 {
pub published: chrono::NaiveDateTime,
pub updated: Option<chrono::NaiveDateTime>,
pub deleted: bool,
pub ap_id: Url,
pub ap_id: DbUrl,
pub local: bool,
}
@ -60,7 +60,7 @@ pub struct CommentForm {
pub published: Option<chrono::NaiveDateTime>,
pub updated: Option<chrono::NaiveDateTime>,
pub deleted: Option<bool>,
pub ap_id: Option<Url>,
pub ap_id: Option<DbUrl>,
pub local: bool,
}

View File

@ -1,6 +1,6 @@
use crate::{
schema::{community, community_follower, community_moderator, community_user_ban},
Url,
DbUrl,
};
use serde::Serialize;
@ -17,16 +17,16 @@ pub struct Community {
pub updated: Option<chrono::NaiveDateTime>,
pub deleted: bool,
pub nsfw: bool,
pub actor_id: Url,
pub actor_id: DbUrl,
pub local: bool,
pub private_key: Option<String>,
pub public_key: Option<String>,
pub last_refreshed_at: chrono::NaiveDateTime,
pub icon: Option<String>,
pub banner: Option<String>,
pub followers_url: Url,
pub inbox_url: Url,
pub shared_inbox_url: Option<Url>,
pub icon: Option<DbUrl>,
pub banner: Option<DbUrl>,
pub followers_url: DbUrl,
pub inbox_url: DbUrl,
pub shared_inbox_url: Option<DbUrl>,
}
/// A safe representation of community, without the sensitive info
@ -43,10 +43,10 @@ pub struct CommunitySafe {
pub updated: Option<chrono::NaiveDateTime>,
pub deleted: bool,
pub nsfw: bool,
pub actor_id: Url,
pub actor_id: DbUrl,
pub local: bool,
pub icon: Option<String>,
pub banner: Option<String>,
pub icon: Option<DbUrl>,
pub banner: Option<DbUrl>,
}
#[derive(Insertable, AsChangeset, Debug)]
@ -61,16 +61,16 @@ pub struct CommunityForm {
pub updated: Option<chrono::NaiveDateTime>,
pub deleted: Option<bool>,
pub nsfw: bool,
pub actor_id: Option<Url>,
pub actor_id: Option<DbUrl>,
pub local: bool,
pub private_key: Option<String>,
pub public_key: Option<String>,
pub last_refreshed_at: Option<chrono::NaiveDateTime>,
pub icon: Option<Option<String>>,
pub banner: Option<Option<String>>,
pub followers_url: Option<Url>,
pub inbox_url: Option<Url>,
pub shared_inbox_url: Option<Option<Url>>,
pub icon: Option<Option<DbUrl>>,
pub banner: Option<Option<DbUrl>>,
pub followers_url: Option<DbUrl>,
pub inbox_url: Option<DbUrl>,
pub shared_inbox_url: Option<Option<DbUrl>>,
}
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]

View File

@ -1,6 +1,6 @@
use crate::{
schema::{post, post_like, post_read, post_saved},
Url,
DbUrl,
};
use serde::Serialize;
@ -9,7 +9,7 @@ use serde::Serialize;
pub struct Post {
pub id: i32,
pub name: String,
pub url: Option<String>,
pub url: Option<DbUrl>,
pub body: Option<String>,
pub creator_id: i32,
pub community_id: i32,
@ -23,8 +23,8 @@ pub struct Post {
pub embed_title: Option<String>,
pub embed_description: Option<String>,
pub embed_html: Option<String>,
pub thumbnail_url: Option<String>,
pub ap_id: Url,
pub thumbnail_url: Option<DbUrl>,
pub ap_id: DbUrl,
pub local: bool,
}
@ -32,7 +32,7 @@ pub struct Post {
#[table_name = "post"]
pub struct PostForm {
pub name: String,
pub url: Option<String>,
pub url: Option<DbUrl>,
pub body: Option<String>,
pub creator_id: i32,
pub community_id: i32,
@ -46,8 +46,8 @@ pub struct PostForm {
pub embed_title: Option<String>,
pub embed_description: Option<String>,
pub embed_html: Option<String>,
pub thumbnail_url: Option<String>,
pub ap_id: Option<Url>,
pub thumbnail_url: Option<DbUrl>,
pub ap_id: Option<DbUrl>,
pub local: bool,
}

View File

@ -1,4 +1,4 @@
use crate::{schema::post_report, source::post::Post};
use crate::{schema::post_report, source::post::Post, DbUrl};
use serde::{Deserialize, Serialize};
#[derive(
@ -11,7 +11,7 @@ pub struct PostReport {
pub creator_id: i32,
pub post_id: i32,
pub original_post_name: String,
pub original_post_url: Option<String>,
pub original_post_url: Option<DbUrl>,
pub original_post_body: Option<String>,
pub reason: String,
pub resolved: bool,
@ -26,7 +26,7 @@ pub struct PostReportForm {
pub creator_id: i32,
pub post_id: i32,
pub original_post_name: String,
pub original_post_url: Option<String>,
pub original_post_url: Option<DbUrl>,
pub original_post_body: Option<String>,
pub reason: String,
}

View File

@ -1,4 +1,4 @@
use crate::{schema::private_message, Url};
use crate::{schema::private_message, DbUrl};
use serde::Serialize;
#[derive(Clone, Queryable, Associations, Identifiable, PartialEq, Debug, Serialize)]
@ -12,7 +12,7 @@ pub struct PrivateMessage {
pub read: bool,
pub published: chrono::NaiveDateTime,
pub updated: Option<chrono::NaiveDateTime>,
pub ap_id: Url,
pub ap_id: DbUrl,
pub local: bool,
}
@ -26,6 +26,6 @@ pub struct PrivateMessageForm {
pub read: Option<bool>,
pub published: Option<chrono::NaiveDateTime>,
pub updated: Option<chrono::NaiveDateTime>,
pub ap_id: Option<Url>,
pub ap_id: Option<DbUrl>,
pub local: bool,
}

View File

@ -1,4 +1,4 @@
use crate::schema::site;
use crate::{schema::site, DbUrl};
use serde::Serialize;
#[derive(Queryable, Identifiable, PartialEq, Debug, Clone, Serialize)]
@ -13,8 +13,8 @@ pub struct Site {
pub enable_downvotes: bool,
pub open_registration: bool,
pub enable_nsfw: bool,
pub icon: Option<String>,
pub banner: Option<String>,
pub icon: Option<DbUrl>,
pub banner: Option<DbUrl>,
}
#[derive(Insertable, AsChangeset)]
@ -28,6 +28,6 @@ pub struct SiteForm {
pub open_registration: bool,
pub enable_nsfw: bool,
// when you want to null out a column, you have to send Some(None)), since sending None means you just don't want to update that column.
pub icon: Option<Option<String>>,
pub banner: Option<Option<String>>,
pub icon: Option<Option<DbUrl>>,
pub banner: Option<Option<DbUrl>>,
}

View File

@ -1,6 +1,6 @@
use crate::{
schema::{user_, user_alias_1, user_alias_2},
Url,
DbUrl,
};
use serde::Serialize;
@ -12,7 +12,7 @@ pub struct User_ {
pub preferred_username: Option<String>,
pub password_encrypted: String,
pub email: Option<String>,
pub avatar: Option<String>,
pub avatar: Option<DbUrl>,
pub admin: bool,
pub banned: bool,
pub published: chrono::NaiveDateTime,
@ -25,16 +25,16 @@ pub struct User_ {
pub show_avatars: bool,
pub send_notifications_to_email: bool,
pub matrix_user_id: Option<String>,
pub actor_id: Url,
pub actor_id: DbUrl,
pub bio: Option<String>,
pub local: bool,
pub private_key: Option<String>,
pub public_key: Option<String>,
pub last_refreshed_at: chrono::NaiveDateTime,
pub banner: Option<String>,
pub banner: Option<DbUrl>,
pub deleted: bool,
pub inbox_url: Url,
pub shared_inbox_url: Option<Url>,
pub inbox_url: DbUrl,
pub shared_inbox_url: Option<DbUrl>,
pub validator_time: chrono::NaiveDateTime,
}
@ -45,19 +45,19 @@ pub struct UserSafe {
pub id: i32,
pub name: String,
pub preferred_username: Option<String>,
pub avatar: Option<String>,
pub avatar: Option<DbUrl>,
pub admin: bool,
pub banned: bool,
pub published: chrono::NaiveDateTime,
pub updated: Option<chrono::NaiveDateTime>,
pub matrix_user_id: Option<String>,
pub actor_id: Url,
pub actor_id: DbUrl,
pub bio: Option<String>,
pub local: bool,
pub banner: Option<String>,
pub banner: Option<DbUrl>,
pub deleted: bool,
pub inbox_url: Url,
pub shared_inbox_url: Option<Url>,
pub inbox_url: DbUrl,
pub shared_inbox_url: Option<DbUrl>,
}
/// A safe user view with only settings
@ -68,7 +68,7 @@ pub struct UserSafeSettings {
pub name: String,
pub preferred_username: Option<String>,
pub email: Option<String>,
pub avatar: Option<String>,
pub avatar: Option<DbUrl>,
pub admin: bool,
pub banned: bool,
pub published: chrono::NaiveDateTime,
@ -81,11 +81,11 @@ pub struct UserSafeSettings {
pub show_avatars: bool,
pub send_notifications_to_email: bool,
pub matrix_user_id: Option<String>,
pub actor_id: Url,
pub actor_id: DbUrl,
pub bio: Option<String>,
pub local: bool,
pub last_refreshed_at: chrono::NaiveDateTime,
pub banner: Option<String>,
pub banner: Option<DbUrl>,
pub deleted: bool,
pub validator_time: chrono::NaiveDateTime,
}
@ -98,7 +98,7 @@ pub struct UserAlias1 {
pub preferred_username: Option<String>,
pub password_encrypted: String,
pub email: Option<String>,
pub avatar: Option<String>,
pub avatar: Option<DbUrl>,
pub admin: bool,
pub banned: bool,
pub published: chrono::NaiveDateTime,
@ -111,13 +111,13 @@ pub struct UserAlias1 {
pub show_avatars: bool,
pub send_notifications_to_email: bool,
pub matrix_user_id: Option<String>,
pub actor_id: Url,
pub actor_id: DbUrl,
pub bio: Option<String>,
pub local: bool,
pub private_key: Option<String>,
pub public_key: Option<String>,
pub last_refreshed_at: chrono::NaiveDateTime,
pub banner: Option<String>,
pub banner: Option<DbUrl>,
pub deleted: bool,
}
@ -127,16 +127,16 @@ pub struct UserSafeAlias1 {
pub id: i32,
pub name: String,
pub preferred_username: Option<String>,
pub avatar: Option<String>,
pub avatar: Option<DbUrl>,
pub admin: bool,
pub banned: bool,
pub published: chrono::NaiveDateTime,
pub updated: Option<chrono::NaiveDateTime>,
pub matrix_user_id: Option<String>,
pub actor_id: Url,
pub actor_id: DbUrl,
pub bio: Option<String>,
pub local: bool,
pub banner: Option<String>,
pub banner: Option<DbUrl>,
pub deleted: bool,
}
@ -148,7 +148,7 @@ pub struct UserAlias2 {
pub preferred_username: Option<String>,
pub password_encrypted: String,
pub email: Option<String>,
pub avatar: Option<String>,
pub avatar: Option<DbUrl>,
pub admin: bool,
pub banned: bool,
pub published: chrono::NaiveDateTime,
@ -161,13 +161,13 @@ pub struct UserAlias2 {
pub show_avatars: bool,
pub send_notifications_to_email: bool,
pub matrix_user_id: Option<String>,
pub actor_id: Url,
pub actor_id: DbUrl,
pub bio: Option<String>,
pub local: bool,
pub private_key: Option<String>,
pub public_key: Option<String>,
pub last_refreshed_at: chrono::NaiveDateTime,
pub banner: Option<String>,
pub banner: Option<DbUrl>,
pub deleted: bool,
}
@ -177,16 +177,16 @@ pub struct UserSafeAlias2 {
pub id: i32,
pub name: String,
pub preferred_username: Option<String>,
pub avatar: Option<String>,
pub avatar: Option<DbUrl>,
pub admin: bool,
pub banned: bool,
pub published: chrono::NaiveDateTime,
pub updated: Option<chrono::NaiveDateTime>,
pub matrix_user_id: Option<String>,
pub actor_id: Url,
pub actor_id: DbUrl,
pub bio: Option<String>,
pub local: bool,
pub banner: Option<String>,
pub banner: Option<DbUrl>,
pub deleted: bool,
}
@ -199,7 +199,7 @@ pub struct UserForm {
pub admin: bool,
pub banned: Option<bool>,
pub email: Option<Option<String>>,
pub avatar: Option<Option<String>>,
pub avatar: Option<Option<DbUrl>>,
pub published: Option<chrono::NaiveDateTime>,
pub updated: Option<chrono::NaiveDateTime>,
pub show_nsfw: bool,
@ -210,13 +210,13 @@ pub struct UserForm {
pub show_avatars: bool,
pub send_notifications_to_email: bool,
pub matrix_user_id: Option<Option<String>>,
pub actor_id: Option<Url>,
pub actor_id: Option<DbUrl>,
pub bio: Option<Option<String>>,
pub local: bool,
pub private_key: Option<String>,
pub public_key: Option<String>,
pub last_refreshed_at: Option<chrono::NaiveDateTime>,
pub banner: Option<Option<String>>,
pub inbox_url: Option<Url>,
pub shared_inbox_url: Option<Option<Url>>,
pub banner: Option<Option<DbUrl>>,
pub inbox_url: Option<DbUrl>,
pub shared_inbox_url: Option<Option<DbUrl>>,
}

View File

@ -12,7 +12,7 @@ lemmy_db_schema = { path = "../db_schema" }
diesel = { version = "1.4.5", features = ["postgres","chrono","r2d2","serde_json"] }
serde = { version = "1.0.123", features = ["derive"] }
log = "0.4.14"
url = "2.2.0"
url = "2.2.1"
[dev-dependencies]
serial_test = "0.5.1"

View File

@ -13,7 +13,7 @@ lemmy_db_queries = { path = "../db_queries" }
lemmy_db_views = { path = "../db_views" }
lemmy_db_views_actor = { path = "../db_views_actor" }
lemmy_db_schema = { path = "../db_schema" }
lemmy_structs = { path = "../structs" }
lemmy_api_structs = { path = "../api_structs" }
diesel = "1.4.5"
actix = "0.10.0"
actix-web = { version = "3.3.2", default-features = false, features = ["rustls"] }
@ -25,6 +25,6 @@ chrono = { version = "0.4.19", features = ["serde"] }
rss = "1.10.0"
serde = { version = "1.0.123", features = ["derive"] }
awc = { version = "2.0.3", default-features = false }
url = { version = "2.2.0", features = ["serde"] }
url = { version = "2.2.1", features = ["serde"] }
strum = "0.20.0"
lazy_static = "1.4.0"

View File

@ -2,6 +2,7 @@ use actix_web::{error::ErrorBadRequest, *};
use anyhow::anyhow;
use chrono::{DateTime, NaiveDateTime, Utc};
use diesel::PgConnection;
use lemmy_api_structs::blocking;
use lemmy_db_queries::{
source::{community::Community_, user::User},
ListingType,
@ -14,8 +15,12 @@ use lemmy_db_views::{
site_view::SiteView,
};
use lemmy_db_views_actor::user_mention_view::{UserMentionQueryBuilder, UserMentionView};
use lemmy_structs::blocking;
use lemmy_utils::{claims::Claims, settings::Settings, utils::markdown_to_html, LemmyError};
use lemmy_utils::{
claims::Claims,
settings::structs::Settings,
utils::markdown_to_html,
LemmyError,
};
use lemmy_websocket::LemmyContext;
use rss::{
extension::dublincore::DublinCoreExtensionBuilder,
@ -163,7 +168,7 @@ fn get_feed_user(
) -> Result<ChannelBuilder, LemmyError> {
let site_view = SiteView::read(&conn)?;
let user = User_::find_by_username(&conn, &user_name)?;
let user_url = user.get_profile_url(&Settings::get().hostname);
let user_url = user.get_profile_url(&Settings::get().hostname());
let posts = PostQueryBuilder::create(&conn)
.listing_type(&ListingType::All)
@ -391,9 +396,6 @@ fn create_post_items(posts: Vec<PostView>) -> Result<Vec<Item>, LemmyError> {
p.community.name
);
// TODO: for category we should just put the name of the category, but then we would have
// to read each community from the db
// TODO add images
let mut description = format!("submitted by <a href=\"{}\">{}</a> to <a href=\"{}\">{}</a><br>{} points | <a href=\"{}\">{} comments</a>",
p.creator.actor_id,

View File

@ -1,7 +1,7 @@
use actix::clock::Duration;
use actix_web::{body::BodyStream, http::StatusCode, *};
use awc::Client;
use lemmy_utils::{claims::Claims, rate_limit::RateLimit, settings::Settings};
use lemmy_utils::{claims::Claims, rate_limit::RateLimit, settings::structs::Settings};
use serde::{Deserialize, Serialize};
pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) {
@ -54,8 +54,10 @@ async fn upload(
return Ok(HttpResponse::Unauthorized().finish());
};
let mut client_req =
client.request_from(format!("{}/image", Settings::get().pictrs_url), req.head());
let mut client_req = client.request_from(
format!("{}/image", Settings::get().pictrs_url()),
req.head(),
);
if let Some(addr) = req.head().peer_addr {
client_req = client_req.header("X-Forwarded-For", addr.to_string())
@ -78,14 +80,14 @@ async fn full_res(
// If there are no query params, the URL is original
let url = if params.format.is_none() && params.thumbnail.is_none() {
format!("{}/image/original/{}", Settings::get().pictrs_url, name,)
format!("{}/image/original/{}", Settings::get().pictrs_url(), name,)
} else {
// Use jpg as a default when none is given
let format = params.format.unwrap_or_else(|| "jpg".to_string());
let mut url = format!(
"{}/image/process.{}?src={}",
Settings::get().pictrs_url,
Settings::get().pictrs_url(),
format,
name,
);
@ -134,7 +136,7 @@ async fn delete(
let url = format!(
"{}/image/delete/{}/{}",
Settings::get().pictrs_url,
Settings::get().pictrs_url(),
&token,
&file
);

View File

@ -1,8 +1,8 @@
use actix_web::{body::Body, error::ErrorBadRequest, *};
use anyhow::anyhow;
use lemmy_api_structs::blocking;
use lemmy_db_views::site_view::SiteView;
use lemmy_structs::blocking;
use lemmy_utils::{settings::Settings, version, LemmyError};
use lemmy_utils::{settings::structs::Settings, version, LemmyError};
use lemmy_websocket::LemmyContext;
use serde::{Deserialize, Serialize};
use url::Url;
@ -31,7 +31,7 @@ async fn node_info(context: web::Data<LemmyContext>) -> Result<HttpResponse, Err
.await?
.map_err(|_| ErrorBadRequest(LemmyError::from(anyhow!("not_found"))))?;
let protocols = if Settings::get().federation.enabled {
let protocols = if Settings::get().federation().enabled {
vec!["activitypub".to_string()]
} else {
vec![]

View File

@ -1,10 +1,10 @@
use actix_web::{error::ErrorBadRequest, web::Query, *};
use anyhow::anyhow;
use lemmy_api_structs::{blocking, WebFingerLink, WebFingerResponse};
use lemmy_db_queries::source::{community::Community_, user::User};
use lemmy_db_schema::source::{community::Community, user::User_};
use lemmy_structs::{blocking, WebFingerLink, WebFingerResponse};
use lemmy_utils::{
settings::Settings,
settings::structs::Settings,
LemmyError,
WEBFINGER_COMMUNITY_REGEX,
WEBFINGER_USER_REGEX,
@ -18,7 +18,7 @@ struct Params {
}
pub fn config(cfg: &mut web::ServiceConfig) {
if Settings::get().federation.enabled {
if Settings::get().federation().enabled {
cfg.route(
".well-known/webfinger",
web::get().to(get_webfinger_response),

View File

@ -10,7 +10,6 @@ doctest = false
[dependencies]
regex = "1.4.3"
config = { version = "0.10.1", default-features = false, features = ["hjson"] }
chrono = { version = "0.4.19", features = ["serde"] }
lettre = "0.10.0-alpha.5"
log = "0.4.14"
@ -23,7 +22,7 @@ thiserror = "1.0.23"
comrak = { version = "0.9.0", default-features = false }
lazy_static = "1.4.0"
openssl = "0.10.32"
url = { version = "2.2.0", features = ["serde"] }
url = { version = "2.2.1", features = ["serde"] }
actix-web = { version = "3.3.2", default-features = false, features = ["rustls"] }
actix-rt = { version = "1.1.1", default-features = false }
anyhow = "1.0.38"
@ -35,3 +34,6 @@ futures = "0.3.12"
diesel = "1.4.5"
http = "0.2.3"
jsonwebtoken = "7.2.0"
deser-hjson = "0.1.12"
merge = "0.1.0"
envy = "0.4.2"

View File

@ -1,4 +1,4 @@
use crate::settings::Settings;
use crate::settings::structs::Settings;
use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, TokenData, Validation};
use serde::{Deserialize, Serialize};
@ -24,7 +24,7 @@ impl Claims {
};
decode::<Claims>(
&jwt,
&DecodingKey::from_secret(Settings::get().jwt_secret.as_ref()),
&DecodingKey::from_secret(Settings::get().jwt_secret().as_ref()),
&v,
)
}
@ -39,7 +39,7 @@ impl Claims {
encode(
&Header::default(),
&my_claims,
&EncodingKey::from_secret(Settings::get().jwt_secret.as_ref()),
&EncodingKey::from_secret(Settings::get().jwt_secret().as_ref()),
)
}
}

View File

@ -1,4 +1,4 @@
use crate::settings::Settings;
use crate::settings::structs::Settings;
use lettre::{
message::{header, Mailbox, MultiPart, SinglePart},
transport::smtp::{
@ -19,8 +19,8 @@ pub fn send_email(
to_username: &str,
html: &str,
) -> Result<(), String> {
let email_config = Settings::get().email.ok_or("no_email_setup")?;
let domain = Settings::get().hostname;
let email_config = Settings::get().email().ok_or("no_email_setup")?;
let domain = Settings::get().hostname();
let (smtp_server, smtp_port) = {
let email_and_port = email_config.smtp_server.split(':').collect::<Vec<&str>>();

View File

@ -9,12 +9,13 @@ pub mod email;
pub mod rate_limit;
pub mod request;
pub mod settings;
#[cfg(test)]
mod test;
pub mod utils;
pub mod version;
use crate::settings::Settings;
use crate::settings::structs::Settings;
use http::StatusCode;
use regex::Regex;
use thiserror::Error;
@ -83,12 +84,12 @@ impl actix_web::error::ResponseError for LemmyError {
lazy_static! {
pub static ref WEBFINGER_COMMUNITY_REGEX: Regex = Regex::new(&format!(
"^group:([a-z0-9_]{{3, 20}})@{}$",
Settings::get().hostname
Settings::get().hostname()
))
.unwrap();
.expect("compile webfinger regex");
pub static ref WEBFINGER_USER_REGEX: Regex = Regex::new(&format!(
"^acct:([a-z0-9_]{{3, 20}})@{}$",
Settings::get().hostname
Settings::get().hostname()
))
.unwrap();
.expect("compile webfinger regex");
}

View File

@ -1,5 +1,5 @@
use crate::{
settings::{RateLimitConfig, Settings},
settings::structs::{RateLimitConfig, Settings},
utils::get_ip,
LemmyError,
};
@ -70,7 +70,7 @@ impl RateLimited {
{
// Does not need to be blocking because the RwLock in settings never held across await points,
// and the operation here locks only long enough to clone
let rate_limit: RateLimitConfig = Settings::get().rate_limit;
let rate_limit: RateLimitConfig = Settings::get().rate_limit();
// before
{

View File

@ -1,4 +1,4 @@
use crate::{settings::Settings, LemmyError};
use crate::{settings::structs::Settings, LemmyError};
use anyhow::anyhow;
use log::error;
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
@ -6,6 +6,7 @@ use reqwest::Client;
use serde::Deserialize;
use std::future::Future;
use thiserror::Error;
use url::Url;
#[derive(Clone, Debug, Error)]
#[error("Error sending request, {0}")]
@ -43,22 +44,22 @@ where
}
}
response.unwrap()
response.expect("retry http request")
}
#[derive(Deserialize, Debug)]
pub(crate) struct IframelyResponse {
title: Option<String>,
description: Option<String>,
thumbnail_url: Option<String>,
thumbnail_url: Option<Url>,
html: Option<String>,
}
pub(crate) async fn fetch_iframely(
client: &Client,
url: &str,
url: &Url,
) -> Result<IframelyResponse, LemmyError> {
let fetch_url = format!("{}/oembed?url={}", Settings::get().iframely_url, url);
let fetch_url = format!("{}/oembed?url={}", Settings::get().iframely_url(), url);
let response = retry(|| client.get(&fetch_url).send()).await?;
@ -83,14 +84,14 @@ pub(crate) struct PictrsFile {
pub(crate) async fn fetch_pictrs(
client: &Client,
image_url: &str,
image_url: &Url,
) -> Result<PictrsResponse, LemmyError> {
is_image_content_type(client, image_url).await?;
let fetch_url = format!(
"{}/image/download?url={}",
Settings::get().pictrs_url,
utf8_percent_encode(image_url, NON_ALPHANUMERIC) // TODO this might not be needed
Settings::get().pictrs_url(),
utf8_percent_encode(image_url.as_str(), NON_ALPHANUMERIC) // TODO this might not be needed
);
let response = retry(|| client.get(&fetch_url).send()).await?;
@ -109,13 +110,8 @@ pub(crate) async fn fetch_pictrs(
pub async fn fetch_iframely_and_pictrs_data(
client: &Client,
url: Option<String>,
) -> (
Option<String>,
Option<String>,
Option<String>,
Option<String>,
) {
url: Option<&Url>,
) -> (Option<String>, Option<String>, Option<String>, Option<Url>) {
match &url {
Some(url) => {
// Fetch iframely data
@ -149,11 +145,19 @@ pub async fn fetch_iframely_and_pictrs_data(
// The full urls are necessary for federation
let pictrs_thumbnail = if let Some(pictrs_hash) = pictrs_hash {
Some(format!(
let url = Url::parse(&format!(
"{}/pictrs/image/{}",
Settings::get().get_protocol_and_hostname(),
pictrs_hash
))
));
match url {
Ok(parsed_url) => Some(parsed_url),
Err(e) => {
// This really shouldn't happen unless the settings or hash are malformed
error!("Unexpected error constructing pictrs thumbnail URL: {}", e);
None
}
}
} else {
None
};
@ -169,9 +173,8 @@ pub async fn fetch_iframely_and_pictrs_data(
}
}
async fn is_image_content_type(client: &Client, test: &str) -> Result<(), LemmyError> {
let response = retry(|| client.get(test).send()).await?;
async fn is_image_content_type(client: &Client, test: &Url) -> Result<(), LemmyError> {
let response = retry(|| client.get(test.to_owned()).send()).await?;
if response
.headers()
.get("Content-Type")

View File

@ -1,210 +0,0 @@
use crate::location_info;
use anyhow::Context;
use config::{Config, ConfigError, Environment, File};
use serde::Deserialize;
use std::{env, fs, io::Error, net::IpAddr, sync::RwLock};
static CONFIG_FILE_DEFAULTS: &str = "config/defaults.hjson";
static CONFIG_FILE: &str = "config/config.hjson";
#[derive(Debug, Deserialize, Clone)]
pub struct Settings {
pub setup: Option<Setup>,
pub database: DatabaseConfig,
pub hostname: String,
pub bind: IpAddr,
pub port: u16,
pub tls_enabled: bool,
pub jwt_secret: String,
pub pictrs_url: String,
pub iframely_url: String,
pub rate_limit: RateLimitConfig,
pub email: Option<EmailConfig>,
pub federation: FederationConfig,
pub captcha: CaptchaConfig,
}
#[derive(Debug, Deserialize, Clone)]
pub struct Setup {
pub admin_username: String,
pub admin_password: String,
pub admin_email: Option<String>,
pub site_name: String,
}
#[derive(Debug, Deserialize, Clone)]
pub struct RateLimitConfig {
pub message: i32,
pub message_per_second: i32,
pub post: i32,
pub post_per_second: i32,
pub register: i32,
pub register_per_second: i32,
pub image: i32,
pub image_per_second: i32,
}
#[derive(Debug, Deserialize, Clone)]
pub struct EmailConfig {
pub smtp_server: String,
pub smtp_login: Option<String>,
pub smtp_password: Option<String>,
pub smtp_from_address: String,
pub use_tls: bool,
}
#[derive(Debug, Deserialize, Clone)]
pub struct CaptchaConfig {
pub enabled: bool,
pub difficulty: String, // easy, medium, or hard
}
#[derive(Debug, Deserialize, Clone)]
pub struct DatabaseConfig {
pub user: String,
pub password: String,
pub host: String,
pub port: i32,
pub database: String,
pub pool_size: u32,
}
#[derive(Debug, Deserialize, Clone)]
pub struct FederationConfig {
pub enabled: bool,
pub allowed_instances: String,
pub blocked_instances: String,
}
lazy_static! {
static ref SETTINGS: RwLock<Settings> = RwLock::new(match Settings::init() {
Ok(c) => c,
Err(e) => panic!("{}", e),
});
}
impl Settings {
/// Reads config from the files and environment.
/// First, defaults are loaded from CONFIG_FILE_DEFAULTS, then these values can be overwritten
/// from CONFIG_FILE (optional). Finally, values from the environment (with prefix LEMMY) are
/// added to the config.
///
/// Note: The env var `LEMMY_DATABASE_URL` is parsed in
/// `lemmy_db_queries/src/lib.rs::get_database_url_from_env()`
fn init() -> Result<Self, ConfigError> {
let mut s = Config::new();
s.merge(File::with_name(&Self::get_config_defaults_location()))?;
s.merge(File::with_name(&Self::get_config_location()).required(false))?;
// Add in settings from the environment (with a prefix of LEMMY)
// Eg.. `LEMMY_DEBUG=1 ./target/app` would set the `debug` key
// Note: we need to use double underscore here, because otherwise variables containing
// underscore cant be set from environmnet.
// https://github.com/mehcode/config-rs/issues/73
s.merge(Environment::with_prefix("LEMMY").separator("__"))?;
s.try_into()
}
/// Returns the config as a struct.
pub fn get() -> Self {
SETTINGS.read().unwrap().to_owned()
}
pub fn get_database_url(&self) -> String {
format!(
"postgres://{}:{}@{}:{}/{}",
self.database.user,
self.database.password,
self.database.host,
self.database.port,
self.database.database
)
}
pub fn get_config_defaults_location() -> String {
env::var("LEMMY_CONFIG_DEFAULTS_LOCATION").unwrap_or_else(|_| CONFIG_FILE_DEFAULTS.to_string())
}
pub fn get_config_location() -> String {
env::var("LEMMY_CONFIG_LOCATION").unwrap_or_else(|_| CONFIG_FILE.to_string())
}
pub fn read_config_file() -> Result<String, Error> {
fs::read_to_string(Self::get_config_location())
}
pub fn get_allowed_instances(&self) -> Vec<String> {
let mut allowed_instances: Vec<String> = self
.federation
.allowed_instances
.split(',')
.map(|d| d.trim().to_string())
.collect();
// The defaults.hjson config always returns a [""]
allowed_instances.retain(|d| !d.eq(""));
allowed_instances
}
pub fn get_blocked_instances(&self) -> Vec<String> {
let mut blocked_instances: Vec<String> = self
.federation
.blocked_instances
.split(',')
.map(|d| d.trim().to_string())
.collect();
// The defaults.hjson config always returns a [""]
blocked_instances.retain(|d| !d.eq(""));
blocked_instances
}
/// Returns either "http" or "https", depending on tls_enabled setting
pub fn get_protocol_string(&self) -> &'static str {
if self.tls_enabled {
"https"
} else {
"http"
}
}
/// Returns something like `http://localhost` or `https://lemmy.ml`,
/// with the correct protocol and hostname.
pub fn get_protocol_and_hostname(&self) -> String {
format!("{}://{}", self.get_protocol_string(), self.hostname)
}
/// When running the federation test setup in `api_tests/` or `docker/federation`, the `hostname`
/// variable will be like `lemmy-alpha:8541`. This method removes the port and returns
/// `lemmy-alpha` instead. It has no effect in production.
pub fn get_hostname_without_port(&self) -> Result<String, anyhow::Error> {
Ok(
self
.hostname
.split(':')
.collect::<Vec<&str>>()
.first()
.context(location_info!())?
.to_string(),
)
}
pub fn save_config_file(data: &str) -> Result<String, Error> {
fs::write(CONFIG_FILE, data)?;
// Reload the new settings
// From https://stackoverflow.com/questions/29654927/how-do-i-assign-a-string-to-a-mutable-static-variable/47181804#47181804
let mut new_settings = SETTINGS.write().unwrap();
*new_settings = match Settings::init() {
Ok(c) => c,
Err(e) => panic!("{}", e),
};
Self::read_config_file()
}
}

View File

@ -0,0 +1,69 @@
use crate::settings::{CaptchaConfig, DatabaseConfig, FederationConfig, RateLimitConfig, Settings};
use std::net::{IpAddr, Ipv4Addr};
impl Default for Settings {
fn default() -> Self {
Self {
database: Some(DatabaseConfig::default()),
rate_limit: Some(RateLimitConfig::default()),
federation: Some(FederationConfig::default()),
captcha: Some(CaptchaConfig::default()),
email: None,
setup: None,
hostname: None,
bind: Some(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0))),
port: Some(8536),
tls_enabled: Some(true),
jwt_secret: Some("changeme".into()),
pictrs_url: Some("http://pictrs:8080".into()),
iframely_url: Some("http://iframely".into()),
}
}
}
impl Default for DatabaseConfig {
fn default() -> Self {
Self {
user: "lemmy".into(),
password: "password".into(),
host: "localhost".into(),
port: 5432,
database: "lemmy".into(),
pool_size: 5,
}
}
}
impl Default for CaptchaConfig {
fn default() -> Self {
Self {
enabled: true,
difficulty: "medium".into(),
}
}
}
impl Default for FederationConfig {
fn default() -> Self {
Self {
enabled: false,
allowed_instances: None,
blocked_instances: None,
}
}
}
impl Default for RateLimitConfig {
fn default() -> Self {
Self {
message: 180,
message_per_second: 60,
post: 6,
post_per_second: 600,
register: 3,
register_per_second: 3600,
image: 6,
image_per_second: 3600,
}
}
}

View File

@ -0,0 +1,172 @@
use crate::{
location_info,
settings::structs::{
CaptchaConfig,
DatabaseConfig,
EmailConfig,
FederationConfig,
RateLimitConfig,
Settings,
SetupConfig,
},
LemmyError,
};
use anyhow::{anyhow, Context};
use deser_hjson::from_str;
use merge::Merge;
use std::{env, fs, io::Error, net::IpAddr, sync::RwLock};
pub(crate) mod defaults;
pub mod structs;
static CONFIG_FILE: &str = "config/config.hjson";
lazy_static! {
static ref SETTINGS: RwLock<Settings> = RwLock::new(match Settings::init() {
Ok(c) => c,
Err(e) => panic!("{}", e),
});
}
impl Settings {
/// Reads config from the files and environment.
/// First, defaults are loaded from CONFIG_FILE_DEFAULTS, then these values can be overwritten
/// from CONFIG_FILE (optional). Finally, values from the environment (with prefix LEMMY) are
/// added to the config.
///
/// Note: The env var `LEMMY_DATABASE_URL` is parsed in
/// `lemmy_db_queries/src/lib.rs::get_database_url_from_env()`
fn init() -> Result<Self, LemmyError> {
// Read the config file
let mut custom_config = from_str::<Settings>(&Self::read_config_file()?)?;
// Merge with env vars
custom_config.merge(envy::prefixed("LEMMY_").from_env::<Settings>()?);
// Merge with default
custom_config.merge(Settings::default());
if custom_config.hostname == Settings::default().hostname {
return Err(anyhow!("Hostname variable is not set!").into());
}
Ok(custom_config)
}
/// Returns the config as a struct.
pub fn get() -> Self {
SETTINGS.read().expect("read config").to_owned()
}
pub fn get_database_url(&self) -> String {
let conf = self.database();
format!(
"postgres://{}:{}@{}:{}/{}",
conf.user, conf.password, conf.host, conf.port, conf.database,
)
}
pub fn get_config_location() -> String {
env::var("LEMMY_CONFIG_LOCATION").unwrap_or_else(|_| CONFIG_FILE.to_string())
}
pub fn read_config_file() -> Result<String, Error> {
fs::read_to_string(Self::get_config_location())
}
pub fn get_allowed_instances(&self) -> Option<Vec<String>> {
self.federation().allowed_instances
}
pub fn get_blocked_instances(&self) -> Option<Vec<String>> {
self.federation().blocked_instances
}
/// Returns either "http" or "https", depending on tls_enabled setting
pub fn get_protocol_string(&self) -> &'static str {
if let Some(tls_enabled) = self.tls_enabled {
if tls_enabled {
"https"
} else {
"http"
}
} else {
"http"
}
}
/// Returns something like `http://localhost` or `https://lemmy.ml`,
/// with the correct protocol and hostname.
pub fn get_protocol_and_hostname(&self) -> String {
format!("{}://{}", self.get_protocol_string(), self.hostname())
}
/// When running the federation test setup in `api_tests/` or `docker/federation`, the `hostname`
/// variable will be like `lemmy-alpha:8541`. This method removes the port and returns
/// `lemmy-alpha` instead. It has no effect in production.
pub fn get_hostname_without_port(&self) -> Result<String, anyhow::Error> {
Ok(
self
.hostname()
.split(':')
.collect::<Vec<&str>>()
.first()
.context(location_info!())?
.to_string(),
)
}
pub fn save_config_file(data: &str) -> Result<String, LemmyError> {
fs::write(CONFIG_FILE, data)?;
// Reload the new settings
// From https://stackoverflow.com/questions/29654927/how-do-i-assign-a-string-to-a-mutable-static-variable/47181804#47181804
let mut new_settings = SETTINGS.write().expect("write config");
*new_settings = match Settings::init() {
Ok(c) => c,
Err(e) => panic!("{}", e),
};
Ok(Self::read_config_file()?)
}
pub fn database(&self) -> DatabaseConfig {
self.database.to_owned().unwrap_or_default()
}
pub fn hostname(&self) -> String {
self.hostname.to_owned().unwrap_or_default()
}
pub fn bind(&self) -> IpAddr {
self.bind.expect("return bind address")
}
pub fn port(&self) -> u16 {
self.port.unwrap_or_default()
}
pub fn tls_enabled(&self) -> bool {
self.tls_enabled.unwrap_or_default()
}
pub fn jwt_secret(&self) -> String {
self.jwt_secret.to_owned().unwrap_or_default()
}
pub fn pictrs_url(&self) -> String {
self.pictrs_url.to_owned().unwrap_or_default()
}
pub fn iframely_url(&self) -> String {
self.iframely_url.to_owned().unwrap_or_default()
}
pub fn rate_limit(&self) -> RateLimitConfig {
self.rate_limit.to_owned().unwrap_or_default()
}
pub fn federation(&self) -> FederationConfig {
self.federation.to_owned().unwrap_or_default()
}
pub fn captcha(&self) -> CaptchaConfig {
self.captcha.to_owned().unwrap_or_default()
}
pub fn email(&self) -> Option<EmailConfig> {
self.email.to_owned()
}
pub fn setup(&self) -> Option<SetupConfig> {
self.setup.to_owned()
}
}

View File

@ -0,0 +1,72 @@
use merge::Merge;
use serde::Deserialize;
use std::net::IpAddr;
#[derive(Debug, Deserialize, Clone, Merge)]
pub struct Settings {
pub(crate) database: Option<DatabaseConfig>,
pub(crate) rate_limit: Option<RateLimitConfig>,
pub(crate) federation: Option<FederationConfig>,
pub(crate) hostname: Option<String>,
pub(crate) bind: Option<IpAddr>,
pub(crate) port: Option<u16>,
pub(crate) tls_enabled: Option<bool>,
pub(crate) jwt_secret: Option<String>,
pub(crate) pictrs_url: Option<String>,
pub(crate) iframely_url: Option<String>,
pub(crate) captcha: Option<CaptchaConfig>,
pub(crate) email: Option<EmailConfig>,
pub(crate) setup: Option<SetupConfig>,
}
#[derive(Debug, Deserialize, Clone)]
pub struct CaptchaConfig {
pub enabled: bool,
pub difficulty: String,
}
#[derive(Debug, Deserialize, Clone)]
pub struct DatabaseConfig {
pub user: String,
pub password: String,
pub host: String,
pub port: i32,
pub database: String,
pub pool_size: u32,
}
#[derive(Debug, Deserialize, Clone)]
pub struct EmailConfig {
pub smtp_server: String,
pub smtp_login: Option<String>,
pub smtp_password: Option<String>,
pub smtp_from_address: String,
pub use_tls: bool,
}
#[derive(Debug, Deserialize, Clone)]
pub struct FederationConfig {
pub enabled: bool,
pub allowed_instances: Option<Vec<String>>,
pub blocked_instances: Option<Vec<String>>,
}
#[derive(Debug, Deserialize, Clone)]
pub struct RateLimitConfig {
pub message: i32,
pub message_per_second: i32,
pub post: i32,
pub post_per_second: i32,
pub register: i32,
pub register_per_second: i32,
pub image: i32,
pub image_per_second: i32,
}
#[derive(Debug, Deserialize, Clone)]
pub struct SetupConfig {
pub admin_username: String,
pub admin_password: String,
pub admin_email: Option<String>,
pub site_name: String,
}

View File

@ -1,4 +1,4 @@
use crate::{settings::Settings, ApiError};
use crate::{settings::structs::Settings, ApiError};
use actix_web::dev::ConnectionInfo;
use chrono::{DateTime, FixedOffset, NaiveDateTime};
use itertools::Itertools;
@ -6,15 +6,15 @@ use rand::{distributions::Alphanumeric, thread_rng, Rng};
use regex::{Regex, RegexBuilder};
lazy_static! {
static ref EMAIL_REGEX: Regex = Regex::new(r"^[a-zA-Z0-9.!#$%&*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$").unwrap();
static ref SLUR_REGEX: Regex = RegexBuilder::new(r"(fag(g|got|tard)?\b|cock\s?sucker(s|ing)?|\bn(i|1)g(\b|g?(a|er)?(s|z)?)\b|mudslime?s?|kikes?|\bspi(c|k)s?\b|\bchinks?|gooks?|bitch(es|ing|y)?|whor(es?|ing)|\btr(a|@)nn?(y|ies?)|\b(b|re|r)tard(ed)?s?)").case_insensitive(true).build().unwrap();
static ref USERNAME_MATCHES_REGEX: Regex = Regex::new(r"/u/[a-zA-Z][0-9a-zA-Z_]*").unwrap();
static ref EMAIL_REGEX: Regex = Regex::new(r"^[a-zA-Z0-9.!#$%&*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$").expect("compile regex");
static ref SLUR_REGEX: Regex = RegexBuilder::new(r"(fag(g|got|tard)?\b|cock\s?sucker(s|ing)?|\bn(i|1)g(\b|g?(a|er)?(s|z)?)\b|mudslime?s?|kikes?|\bspi(c|k)s?\b|\bchinks?|gooks?|bitch(es|ing|y)?|whor(es?|ing)|\btr(a|@)nn?(y|ies?)|\b(b|re|r)tard(ed)?s?)").case_insensitive(true).build().expect("compile regex");
static ref USERNAME_MATCHES_REGEX: Regex = Regex::new(r"/u/[a-zA-Z][0-9a-zA-Z_]*").expect("compile regex");
// TODO keep this old one, it didn't work with port well tho
// static ref MENTIONS_REGEX: Regex = Regex::new(r"@(?P<name>[\w.]+)@(?P<domain>[a-zA-Z0-9._-]+\.[a-zA-Z0-9_-]+)").unwrap();
static ref MENTIONS_REGEX: Regex = Regex::new(r"@(?P<name>[\w.]+)@(?P<domain>[a-zA-Z0-9._:-]+)").unwrap();
static ref VALID_USERNAME_REGEX: Regex = Regex::new(r"^[a-zA-Z0-9_]{3,20}$").unwrap();
static ref VALID_COMMUNITY_NAME_REGEX: Regex = Regex::new(r"^[a-z0-9_]{3,20}$").unwrap();
static ref VALID_POST_TITLE_REGEX: Regex = Regex::new(r".*\S.*").unwrap();
// static ref MENTIONS_REGEX: Regex = Regex::new(r"@(?P<name>[\w.]+)@(?P<domain>[a-zA-Z0-9._-]+\.[a-zA-Z0-9_-]+)").expect("compile regex");
static ref MENTIONS_REGEX: Regex = Regex::new(r"@(?P<name>[\w.]+)@(?P<domain>[a-zA-Z0-9._:-]+)").expect("compile regex");
static ref VALID_USERNAME_REGEX: Regex = Regex::new(r"^[a-zA-Z0-9_]{3,20}$").expect("compile regex");
static ref VALID_COMMUNITY_NAME_REGEX: Regex = Regex::new(r"^[a-z0-9_]{3,20}$").expect("compile regex");
static ref VALID_POST_TITLE_REGEX: Regex = Regex::new(r".*\S.*").expect("compile regex");
}
pub fn naive_from_unix(time: i64) -> NaiveDateTime {
@ -85,7 +85,7 @@ pub struct MentionData {
impl MentionData {
pub fn is_local(&self) -> bool {
Settings::get().hostname.eq(&self.domain)
Settings::get().hostname().eq(&self.domain)
}
pub fn full_name(&self) -> String {
format!("@{}@{}", &self.name, &self.domain)

View File

@ -1,7 +1,6 @@
[package]
name = "lemmy_websocket"
version = "0.1.0"
authors = ["Felix Ableitner <me@nutomic.com>"]
edition = "2018"
[lib]
@ -11,7 +10,7 @@ doctest = false
[dependencies]
lemmy_utils = { path = "../utils" }
lemmy_structs = { path = "../structs" }
lemmy_api_structs = { path = "../api_structs" }
lemmy_db_queries = { path = "../db_queries" }
lemmy_db_schema = { path = "../db_schema" }
reqwest = { version = "0.10.10", features = ["json"] }

View File

@ -6,7 +6,7 @@ use diesel::{
r2d2::{ConnectionManager, Pool},
PgConnection,
};
use lemmy_structs::{comment::*, post::*};
use lemmy_api_structs::{comment::*, post::*};
use lemmy_utils::{
location_info,
rate_limit::RateLimit,

View File

@ -1,6 +1,6 @@
use crate::UserOperation;
use actix::{prelude::*, Recipient};
use lemmy_structs::{comment::CommentResponse, post::PostResponse};
use lemmy_api_structs::{comment::CommentResponse, post::PostResponse};
use lemmy_utils::{CommunityId, ConnectionId, IpAddr, PostId, UserId};
use serde::{Deserialize, Serialize};

Some files were not shown because too many files have changed in this diff Show More