diff options
author | Felix Ableitner <me@nutomic.com> | 2020-06-09 14:01:26 +0200 |
---|---|---|
committer | Felix Ableitner <me@nutomic.com> | 2020-06-09 14:01:26 +0200 |
commit | 0f1a8ec928a36d73490a41a778244578f39dd626 (patch) | |
tree | e55ec80acbb258197ce899cefe6e1b24e09ad2fb | |
parent | 5c6601cb2a819d20b0f0d17f3575aff006a47fd2 (diff) | |
parent | a13e9fe3959e07f901ba0647dfd7f749865a900d (diff) |
Merge branch 'master' into federation
57 files changed, 1150 insertions, 475 deletions
@@ -34,7 +34,7 @@ Front Page|Post ---|--- -![main screen](https://i.imgur.com/kZSRcRu.png)|![chat screen](https://i.imgur.com/4XghNh6.png) +![main screen](https://raw.githubusercontent.com/LemmyNet/lemmy/master/docs/img/main_screen.png)|![chat screen](https://raw.githubusercontent.com/LemmyNet/lemmy/master/docs/img/chat_screen.png) [Lemmy](https://github.com/LemmyNet/lemmy) is similar to sites like [Reddit](https://reddit.com), [Lobste.rs](https://lobste.rs), [Raddle](https://raddle.me), or [Hacker News](https://news.ycombinator.com/): you subscribe to forums you're interested in, post links and discussions, then vote, and comment on them. Behind the scenes, it is very different; anyone can easily run a server, and all these servers are federated (think email), and connected to the same universe, called the [Fediverse](https://en.wikipedia.org/wiki/Fediverse). @@ -44,7 +44,7 @@ The overall goal is to create an easily self-hostable, decentralized alternative Each lemmy server can set its own moderation policy; appointing site-wide admins, and community moderators to keep out the trolls, and foster a healthy, non-toxic environment where all can feel comfortable contributing. -*Note: Federation is still in active development* +*Note: Federation is still in active development and the WebSocket, as well as, HTTP API are currently unstable* ### Why's it called Lemmy? @@ -125,16 +125,19 @@ Lemmy is free, open-source software, meaning no advertising, monetizing, or vent - [Docker Development](https://dev.lemmy.ml/docs/contributing_docker_development.html) - [Local Development](https://dev.lemmy.ml/docs/contributing_local_development.html) -### Translations +### Translations If you want to help with translating, take a look at [Weblate](https://weblate.yerbamate.dev/projects/lemmy/). ## Contact -- [Mastodon](https://mastodon.social/@LemmyDev) - [![Mastodon Follow](https://img.shields.io/mastodon/follow/810572?domain=https%3A%2F%2Fmastodon.social&style=social)](https://mastodon.social/@LemmyDev) -- [Matrix](https://riot.im/app/#/room/#rust-reddit-fediverse:matrix.org) - [![Matrix](https://img.shields.io/matrix/rust-reddit-fediverse:matrix.org.svg?label=matrix-chat)](https://riot.im/app/#/room/#rust-reddit-fediverse:matrix.org) +- [Mastodon](https://mastodon.social/@LemmyDev) +- [Matrix](https://riot.im/app/#/room/#rust-reddit-fediverse:matrix.org) + +## Code Mirrors + - [GitHub](https://github.com/LemmyNet/lemmy) -- [Gitea](https://yerbamate.dev/dessalines/lemmy) +- [Gitea](https://yerbamate.dev/LemmyNet/lemmy) - [GitLab](https://gitlab.com/dessalines/lemmy) ## Credits diff --git a/ansible/VERSION b/ansible/VERSION index e39e33bc..e31dcbc4 100644 --- a/ansible/VERSION +++ b/ansible/VERSION @@ -1 +1 @@ -v0.6.51 +v0.6.71 diff --git a/ansible/templates/docker-compose.yml b/ansible/templates/docker-compose.yml index a4d54f6d..9ec1bfbc 100644 --- a/ansible/templates/docker-compose.yml +++ b/ansible/templates/docker-compose.yml @@ -26,7 +26,7 @@ services: restart: always pictshare: - image: shtripok/pictshare:latest + image: hascheksolutions/pictshare:latest ports: - "127.0.0.1:8537:80" volumes: diff --git a/ansible/templates/nginx.conf b/ansible/templates/nginx.conf index 04e5a643..a978c189 100644 --- a/ansible/templates/nginx.conf +++ b/ansible/templates/nginx.conf @@ -36,7 +36,7 @@ server { # It might be nice to compress JSON, but leaving that out to protect against potential # compression+encryption information leak attacks like BREACH. gzip on; - gzip_types text/css application/javascript; + gzip_types text/css application/javascript image/svg+xml; gzip_vary on; # Only connect to this site via HTTPS for the two years diff --git a/docker/dev/docker-compose.yml b/docker/dev/docker-compose.yml index 556c67bd..3fc94099 100644 --- a/docker/dev/docker-compose.yml +++ b/docker/dev/docker-compose.yml @@ -28,7 +28,7 @@ services: - iframely pictshare: - image: shtripok/pictshare:latest + image: hascheksolutions/pictshare:latest ports: - "127.0.0.1:8537:80" volumes: diff --git a/docker/lemmy.hjson b/docker/lemmy.hjson index b61ea826..271fc78d 100644 --- a/docker/lemmy.hjson +++ b/docker/lemmy.hjson @@ -23,9 +23,6 @@ jwt_secret: "changeme" # The dir for the front end front_end_dir: "/app/dist" - # whether to enable activitypub federation. this feature is in alpha, do not enable in production, as might - # cause problems like remote instances fetching and permanently storing bad data. - federation_enabled: false # rate limits for various user actions, by user ip rate_limit: { # maximum number of messages created in interval @@ -60,6 +57,7 @@ # smtp_password: "" # # address to send emails from, eg "info@your-instance.com" # smtp_from_address: "" +# use_tls: true # } } diff --git a/docker/prod/docker-compose.yml b/docker/prod/docker-compose.yml index c38bb899..db6e4004 100644 --- a/docker/prod/docker-compose.yml +++ b/docker/prod/docker-compose.yml @@ -1,4 +1,4 @@ -version: '3.3' +version: '2.2' services: postgres: @@ -12,7 +12,7 @@ services: restart: always lemmy: - image: dessalines/lemmy:v0.6.51 + image: dessalines/lemmy:v0.6.71 ports: - "127.0.0.1:8536:8536" restart: always @@ -26,12 +26,13 @@ services: - iframely pictshare: - image: shtripok/pictshare:latest + image: hascheksolutions/pictshare:latest ports: - "127.0.0.1:8537:80" volumes: - ./volumes/pictshare:/usr/share/nginx/html/data restart: always + mem_limit: 100m iframely: image: dogbin/iframely:latest @@ -40,3 +41,4 @@ services: volumes: - ./iframely.config.local.js:/iframely/config.local.js:ro restart: always + mem_limit: 100m diff --git a/docs/img/chat_screen.png b/docs/img/chat_screen.png Binary files differnew file mode 100644 index 00000000..21a452dc --- /dev/null +++ b/docs/img/chat_screen.png diff --git a/docs/img/main_screen.png b/docs/img/main_screen.png Binary files differnew file mode 100644 index 00000000..5d1f0c32 --- /dev/null +++ b/docs/img/main_screen.png diff --git a/docs/img/rank_algorithm.png b/docs/img/rank_algorithm.png Binary files differnew file mode 100644 index 00000000..c8200f91 --- /dev/null +++ b/docs/img/rank_algorithm.png diff --git a/docs/src/about.md b/docs/src/about.md index 31081f48..2c0e418b 100644 --- a/docs/src/about.md +++ b/docs/src/about.md @@ -2,7 +2,7 @@ Front Page|Post ---|--- -![main screen](https://i.imgur.com/kZSRcRu.png)|![chat screen](https://i.imgur.com/4XghNh6.png) +![main screen](https://raw.githubusercontent.com/LemmyNet/lemmy/master/docs/img/main_screen.png)|![chat screen](https://raw.githubusercontent.com/LemmyNet/lemmy/master/docs/img/chat_screen.png) [Lemmy](https://github.com/LemmyNet/lemmy) is similar to sites like [Reddit](https://reddit.com), [Lobste.rs](https://lobste.rs), [Raddle](https://raddle.me), or [Hacker News](https://news.ycombinator.com/): you subscribe to forums you're interested in, post links and discussions, then vote, and comment on them. Behind the scenes, it is very different; anyone can easily run a server, and all these servers are federated (think email), and connected to the same universe, called the [Fediverse](https://en.wikipedia.org/wiki/Fediverse). diff --git a/docs/src/about_ranking.md b/docs/src/about_ranking.md index d318ae82..fe9e82bb 100644 --- a/docs/src/about_ranking.md +++ b/docs/src/about_ranking.md @@ -26,4 +26,4 @@ Gravity = Decay gravity, 1.8 is default A plot of rank over 24 hours, of scores of 1, 5, 10, 100, 1000, with a scale factor of 10k. -![](https://i.imgur.com/w8oBLlL.png) +![](https://raw.githubusercontent.com/LemmyNet/lemmy/master/docs/img/rank_algorithm.png) diff --git a/docs/src/administration_install_docker.md b/docs/src/administration_install_docker.md index 391299b3..236faa6b 100644 --- a/docs/src/administration_install_docker.md +++ b/docs/src/administration_install_docker.md @@ -10,12 +10,13 @@ cd /lemmy wget https://raw.githubusercontent.com/dessalines/lemmy/master/docker/prod/docker-compose.yml wget https://raw.githubusercontent.com/dessalines/lemmy/master/docker/lemmy.hjson wget https://raw.githubusercontent.com/dessalines/lemmy/master/docker/iframely.config.local.js -docker-compose up -d ``` -After this, have a look at the [config file](administration_configuration.md) named `lemmy.hjson`, and adjust it, in particular the hostname. +After this, have a look at the [config file](administration_configuration.md) named `lemmy.hjson`, and adjust it, in particular the hostname, and possibly the db password. Then run: + +`docker-compose up -d` -To make Lemmy available outside the server, you need to setup a reverse proxy, like Nginx. [A sample nginx config](/ansible/templates/nginx.conf), could be setup with: +To make Lemmy available outside the server, you need to setup a reverse proxy, like Nginx. [A sample nginx config](https://raw.githubusercontent.com/dessalines/lemmy/master/ansible/templates/nginx.conf), could be setup with: ```bash wget https://raw.githubusercontent.com/dessalines/lemmy/master/ansible/templates/nginx.conf diff --git a/docs/src/contributing_federation_development.md b/docs/src/contributing_federation_development.md index bcac4caa..80567e60 100644 --- a/docs/src/contributing_federation_development.md +++ b/docs/src/contributing_federation_development.md @@ -5,12 +5,12 @@ If you don't have a local clone of the Lemmy repo yet, just run the following command: ```bash -git clone https://yerbamate.dev/LemmyNet/lemmy.git -b federation +git clone https://github.com/LemmyNet/lemmy -b federation ``` If you already have the Lemmy repo cloned, you need to add a new remote: ```bash -git remote add federation https://yerbamate.dev/LemmyNet/lemmy.git +git remote add federation https://github.com/LemmyNet/lemmy git checkout federation git pull federation federation ``` diff --git a/docs/src/contributing_websocket_http_api.md b/docs/src/contributing_websocket_http_api.md index f228f94e..567f674c 100644 --- a/docs/src/contributing_websocket_http_api.md +++ b/docs/src/contributing_websocket_http_api.md @@ -1,6 +1,6 @@ # Lemmy API -*Note: this may lag behind the actual API endpoints [here](../server/src/api).* +*Note: this may lag behind the actual API endpoints [here](../server/src/api). The API should be considered unstable and may change any time.* <!-- toc --> @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh set -e # Set the database variable to the default first. @@ -10,25 +10,55 @@ export LEMMY_DATABASE_URL=postgres://lemmy:password@localhost:5432/lemmy export JWT_SECRET=changeme export HOSTNAME=rrr +yes_no_prompt_invalid() { + echo "Invalid input. Please enter either \"y\" or \"n\"." 1>&2 +} + +ask_to_init_db() { + init_db_valid=0 + init_db_final=0 + while [ "$init_db_valid" == 0 ] + do + read -p "Initialize database (y/n)? " init_db + case "$init_db" in + [yY]* ) init_db_valid=1; init_db_final=1;; + [nN]* ) init_db_valid=1; init_db_final=0;; + * ) yes_no_prompt_invalid;; + esac + echo + done + if [ "$init_db_final" = 1 ] + then + source ./server/db-init.sh + read -n 1 -s -r -p "Press ANY KEY to continue execution of this script, press CTRL+C to quit..." + echo + fi +} + +ask_to_auto_reload() { + auto_reload_valid=0 + auto_reload_final=0 + while [ "$auto_reload_valid" == 0 ] + do + echo "Automagically reload the project when source files are changed?" + echo "ONLY ENABLE THIS FOR DEVELOPMENT!" + read -p "(y/n) " auto_reload + case "$auto_reload" in + [yY]* ) auto_reload_valid=1; auto_reload_final=1;; + [nN]* ) auto_reload_valid=1; auto_reload_final=0;; + * ) yes_no_prompt_invalid;; + esac + echo + done + if [ "$auto_reload_final" = 1 ] + then + cd ui && yarn start + cd server && cargo watch -x run + fi +} + # Optionally initialize the database -init_db_valid=0 -init_db_final=0 -while [ "$init_db_valid" == 0 ] -do - read -p "Initialize database (y/n)? " init_db - case "${init_db,,}" in - y|yes ) init_db_valid=1; init_db_final=1;; - n|no ) init_db_valid=1; init_db_final=0;; - * ) echo "Invalid input" 1>&2;; - esac - echo -done -if [ "$init_db_final" = 1 ] -then - source ./server/db-init.sh - read -n 1 -s -r -p "Press ANY KEY to continue execution of this script, press CTRL+C to quit..." - echo -fi +ask_to_init_db # Build the web client cd ui @@ -39,6 +69,5 @@ yarn build cd ../server RUST_LOG=debug cargo run -# For live coding, where both the front and back end, automagically reload on any save, do: -# cd ui && yarn start -# cd server && cargo watch -x run +# For live coding, where both the front and back end, automagically reload on any save +ask_to_auto_reload diff --git a/server/Cargo.toml b/server/Cargo.toml index ddc6e766..47be3239 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "lemmy_server" version = "0.0.1" -authors = ["Dessalines <happydooby@gmail.com>"] +authors = ["Dessalines <tyhou13@gmx.com>"] edition = "2018" [dependencies] @@ -13,8 +13,8 @@ activitystreams-new = { git = "https://git.asonix.dog/asonix/activitystreams-ske activitystreams-ext = { git = "https://git.asonix.dog/asonix/activitystreams-ext" } bcrypt = "0.8.0" chrono = { version = "0.4.7", features = ["serde"] } -failure = "0.1.8" serde_json = { version = "1.0.48", features = ["preserve_order"]} +failure = "0.1.8" serde = { version = "1.0.105", features = ["derive"] } actix = "0.9.0" actix-web = "2.0.0" @@ -29,8 +29,8 @@ strum_macros = "0.18.0" jsonwebtoken = "7.0.1" regex = "1.3.5" lazy_static = "1.3.0" -lettre = "0.9.2" -lettre_email = "0.9.2" +lettre = "0.9.3" +lettre_email = "0.9.4" sha2 = "0.8.1" rss = "1.9.0" htmlescape = "0.3.1" diff --git a/server/db-init.sh b/server/db-init.sh index c9150e9d..a2ad77b5 100755 --- a/server/db-init.sh +++ b/server/db-init.sh @@ -1,43 +1,106 @@ -#!/bin/bash +#!/bin/sh +# Default configurations username=lemmy dbname=lemmy port=5432 -password="" -password_confirm="" -password_valid=0 +yes_no_prompt_invalid() { + echo "Invalid input. Please enter either \"y\" or \"n\"." 1>&2 +} -while [ "$password_valid" == 0 ] -do - read -p "Enter database password: " -s password - echo +print_config() { + echo " database name: $dbname" + echo " username: $username" + echo " port: $port" +} - read -p "Verify database password: " -s password_confirm - echo +ask_for_db_config() { + echo "The default database configuration is:" + print_config echo - # Start the loop from the top if either check fails - if [ -z "$password" ] - then - echo "Error: Password cannot be empty." 1>&2 + default_config_final=0 + default_config_valid=0 + while [ "$default_config_valid" == 0 ] + do + read -p "Use this configuration (y/n)? " default_config + case "$default_config" in + [yY]* ) default_config_valid=1; default_config_final=1;; + [nN]* ) default_config_valid=1; default_config_final=0;; + * ) yes_no_prompt_invalid;; + esac echo - continue - fi - if [ "$password" != "$password_confirm" ] + done + + if [ "$default_config_final" == 0 ] then - echo "Error: Passwords don't match." 1>&2 - echo - continue + config_ok_final=0 + while [ "$config_ok_final" == 0 ] + do + read -p "Database name: " dbname + read -p "Username: " username + read -p "Port: " port + #echo + + #echo "The database configuration is:" + #print_config + #echo + + config_ok_valid=0 + while [ "$config_ok_valid" == 0 ] + do + read -p "Use this configuration (y/n)? " config_ok + case "$config_ok" in + [yY]* ) config_ok_valid=1; config_ok_final=1;; + [nN]* ) config_ok_valid=1; config_ok_final=0;; + * ) yes_no_prompt_invalid;; + esac + echo + done + done fi +} + +ask_for_password() { + password="" + password_confirm="" + password_valid=0 + while [ "$password_valid" == 0 ] + do + read -p "Enter database password: " -s password + echo + + read -p "Verify database password: " -s password_confirm + echo + echo - # Set the password_valid variable to break out of the loop - password_valid=1 -done + # Start the loop from the top if either check fails + if [ -z "$password" ] + then + echo "Error: Password cannot be empty." 1>&2 + echo + continue + fi + if [ "$password" != "$password_confirm" ] + then + echo "Error: Passwords don't match." 1>&2 + echo + continue + fi + # Set the password_valid variable to break out of the loop + password_valid=1 + done +} + +ask_for_db_config + +ask_for_password psql -c "CREATE USER $username WITH PASSWORD '$password' SUPERUSER;" -U postgres -psql -c 'CREATE DATABASE $dbname WITH OWNER $username;' -U postgres +psql -c "CREATE DATABASE $dbname WITH OWNER $username;" -U postgres export LEMMY_DATABASE_URL=postgres://$username:$password@localhost:$port/$dbname -echo $LEMMY_DATABASE_URL +echo "The database URL is $LEMMY_DATABASE_URL" + diff --git a/server/src/api/user.rs b/server/src/api/user.rs index 18d30985..f68a1a82 100644 --- a/server/src/api/user.rs +++ b/server/src/api/user.rs @@ -30,6 +30,7 @@ use crate::{ SortType, }, generate_random_string, + is_valid_username, naive_from_unix, naive_now, remove_slurs, @@ -314,6 +315,9 @@ impl Perform for Oper<Register> { } let user_keypair = generate_actor_keypair()?; + if !is_valid_username(&data.username) { + return Err(APIError::err("invalid_username").into()); + } // Register the new user let user_form = UserForm { diff --git a/server/src/lib.rs b/server/src/lib.rs index 055cc5f7..32c37439 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -85,6 +85,20 @@ pub fn is_email_regex(test: &str) -> bool { EMAIL_REGEX.is_match(test) } +pub fn is_image_content_type(test: &str) -> Result<(), failure::Error> { + if isahc::get(test)? + .headers() + .get("Content-Type") + .ok_or_else(|| format_err!("No Content-Type header"))? + .to_str()? + .starts_with("image/") + { + Ok(()) + } else { + Err(format_err!("Not an image type.")) + } +} + pub fn remove_slurs(test: &str) -> String { SLUR_REGEX.replace_all(test, "*removed*").to_string() } @@ -178,6 +192,8 @@ pub struct PictshareResponse { } pub fn fetch_pictshare(image_url: &str) -> Result<PictshareResponse, failure::Error> { + is_image_content_type(image_url)?; + let fetch_url = format!( "http://pictshare/api/geturl.php?url={}", utf8_percent_encode(image_url, NON_ALPHANUMERIC) @@ -195,36 +211,46 @@ fn fetch_iframely_and_pictshare_data( Option<String>, Option<String>, ) { - // Fetch iframely data - let (iframely_title, iframely_description, iframely_thumbnail_url, iframely_html) = match url { - Some(url) => match fetch_iframely(&url) { - Ok(res) => (res.title, res.description, res.thumbnail_url, res.html), - Err(e) => { - error!("iframely err: {}", e); - (None, None, None, None) - } - }, + match &url { + Some(url) => { + // Fetch iframely data + let (iframely_title, iframely_description, iframely_thumbnail_url, iframely_html) = + match fetch_iframely(url) { + Ok(res) => (res.title, res.description, res.thumbnail_url, res.html), + Err(e) => { + error!("iframely err: {}", e); + (None, None, None, None) + } + }; + + // Fetch pictshare thumbnail + let pictshare_thumbnail = match iframely_thumbnail_url { + Some(iframely_thumbnail_url) => match fetch_pictshare(&iframely_thumbnail_url) { + Ok(res) => Some(res.url), + Err(e) => { + error!("pictshare err: {}", e); + None + } + }, + // Try to generate a small thumbnail if iframely is not supported + None => match fetch_pictshare(&url) { + Ok(res) => Some(res.url), + Err(e) => { + error!("pictshare err: {}", e); + None + } + }, + }; + + ( + iframely_title, + iframely_description, + iframely_html, + pictshare_thumbnail, + ) + } None => (None, None, None, None), - }; - - // Fetch pictshare thumbnail - let pictshare_thumbnail = match iframely_thumbnail_url { - Some(iframel |