Replace Iframely. Fixes #1681

This commit is contained in:
Dessalines 2021-08-16 12:23:49 -04:00
parent d8fafc1b03
commit 453298d304
21 changed files with 546 additions and 524 deletions

537
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -101,7 +101,6 @@ Each Lemmy server can set its own moderation policy; appointing site-wide admins
- Can transfer site and communities to others.
- Can fully erase your data, replacing all posts and comments.
- NSFW post / community support.
- OEmbed support via Iframely.
- High performance.
- Server is written in rust.
- Front end is `~80kB` gzipped.

View file

@ -72,16 +72,12 @@
- src: 'templates/nginx.conf'
dest: '/etc/nginx/sites-enabled/lemmy.conf'
mode: '0644'
- src: '../docker/iframely.config.local.js'
dest: '{{lemmy_base_dir}}/iframely.config.local.js'
mode: '0600'
vars:
lemmy_docker_image: "dessalines/lemmy:{{ lookup('file', 'VERSION') }}"
lemmy_docker_ui_image: "dessalines/lemmy-ui:{{ lookup('file', 'VERSION') }}"
lemmy_port: "8536"
lemmy_ui_port: "1235"
pictshare_port: "8537"
iframely_port: "8538"
- name: add config file (only during initial setup)
template:

View file

@ -61,16 +61,12 @@
- src: 'templates/nginx.conf'
dest: '/etc/nginx/sites-enabled/lemmy.conf'
mode: '0644'
- src: '../docker/iframely.config.local.js'
dest: '{{lemmy_base_dir}}/iframely.config.local.js'
mode: '0600'
vars:
lemmy_docker_image: "dessalines/lemmy:dev"
lemmy_docker_ui_image: "dessalines/lemmy-ui:{{ lookup('file', 'VERSION') }}"
lemmy_port: "8536"
lemmy_ui_port: "1235"
pictshare_port: "8537"
iframely_port: "8538"
postgres_password: "{{ lookup('password', 'passwords/{{ inventory_hostname }}/postgres chars=ascii_letters,digits') }}"
- name: add config file (only during initial setup)

View file

@ -13,7 +13,6 @@ services:
depends_on:
- postgres
- pictrs
- iframely
lemmy-ui:
image: {{ lemmy_docker_ui_image }}
@ -47,15 +46,6 @@ services:
restart: always
mem_limit: 200m
iframely:
image: dogbin/iframely:latest
ports:
- "127.0.0.1:8061:80"
volumes:
- ./iframely.config.local.js:/iframely/config.local.js:ro
restart: always
mem_limit: 200m
postfix:
image: mwader/postfix-relay
environment:

View file

@ -101,12 +101,6 @@ server {
return 301 /pictrs/image/$1;
}
location /iframely/ {
proxy_pass http://0.0.0.0:8061/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
# Anonymize IP addresses

View file

@ -37,8 +37,6 @@
jwt_secret: "changeme"
# address where pictrs is available
pictrs_url: "http://pictrs:8080"
# address where iframely is available
iframely_url: "http://iframely"
# maximum length of local community and user names
actor_name_max_length: 20
# rate limits for various user actions, by user ip

View file

@ -20,7 +20,7 @@ use lemmy_apub::{
use lemmy_db_queries::{source::post::Post_, Crud, Likeable};
use lemmy_db_schema::source::post::*;
use lemmy_utils::{
request::fetch_iframely_and_pictrs_data,
request::fetch_post_links_and_pictrs_data,
utils::{check_slurs, check_slurs_opt, clean_url_params, is_valid_post_title},
ApiError,
ConnectionId,
@ -49,11 +49,11 @@ impl PerformCrud for CreatePost {
check_community_ban(local_user_view.person.id, data.community_id, context.pool()).await?;
// Fetch Iframely and pictrs cached image
// Fetch post links and pictrs cached image
let data_url = data.url.as_ref();
let (iframely_response, pictrs_thumbnail) =
fetch_iframely_and_pictrs_data(context.client(), data_url).await?;
let (embed_title, embed_description, embed_html) = iframely_response
let (post_links_res, pictrs_thumbnail) =
fetch_post_links_and_pictrs_data(context.client(), data_url).await?;
let (embed_title, embed_description, embed_html) = post_links_res
.map(|u| (u.title, u.description, u.html))
.unwrap_or((None, None, None));

View file

@ -5,7 +5,7 @@ use lemmy_apub::activities::{post::create_or_update::CreateOrUpdatePost, CreateO
use lemmy_db_queries::{source::post::Post_, Crud};
use lemmy_db_schema::{naive_now, source::post::*};
use lemmy_utils::{
request::fetch_iframely_and_pictrs_data,
request::fetch_post_links_and_pictrs_data,
utils::{check_slurs_opt, clean_url_params, is_valid_post_title},
ApiError,
ConnectionId,
@ -49,11 +49,11 @@ impl PerformCrud for EditPost {
return Err(ApiError::err("no_post_edit_allowed").into());
}
// Fetch Iframely and Pictrs cached image
// Fetch post links and Pictrs cached image
let data_url = data.url.as_ref();
let (iframely_response, pictrs_thumbnail) =
fetch_iframely_and_pictrs_data(context.client(), data_url).await?;
let (embed_title, embed_description, embed_html) = iframely_response
let (post_links_res, pictrs_thumbnail) =
fetch_post_links_and_pictrs_data(context.client(), data_url).await?;
let (embed_title, embed_description, embed_html) = post_links_res
.map(|u| (u.title, u.description, u.html))
.unwrap_or((None, None, None));

View file

@ -31,7 +31,7 @@ use lemmy_db_schema::{
},
};
use lemmy_utils::{
request::fetch_iframely_and_pictrs_data,
request::fetch_post_links_and_pictrs_data,
utils::{check_slurs, convert_datetime, markdown_to_html, remove_slurs},
LemmyError,
};
@ -188,12 +188,12 @@ impl FromApub for Post {
let community = extract_community(&page.to, context, request_counter).await?;
let thumbnail_url: Option<Url> = page.image.clone().map(|i| i.url);
let (iframely_response, pictrs_thumbnail) = if let Some(url) = &page.url {
fetch_iframely_and_pictrs_data(context.client(), Some(url)).await?
let (post_links_res, pictrs_thumbnail) = if let Some(url) = &page.url {
fetch_post_links_and_pictrs_data(context.client(), Some(url)).await?
} else {
(None, thumbnail_url)
};
let (embed_title, embed_description, embed_html) = iframely_response
let (embed_title, embed_description, embed_html) = post_links_res
.map(|u| (u.title, u.description, u.html))
.unwrap_or((None, None, None));

View file

@ -4,4 +4,5 @@ extern crate lazy_static;
pub mod feeds;
pub mod images;
pub mod nodeinfo;
pub mod post_link_tags;
pub mod webfinger;

View file

@ -38,3 +38,4 @@ http = "0.2.4"
jsonwebtoken = "7.2.0"
deser-hjson = "1.0.2"
smart-default = "0.6.0"
webpage = { version = "1.1", default-features = false, features = ["serde"] }

View file

@ -3,10 +3,11 @@ use anyhow::anyhow;
use log::error;
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
use reqwest::Client;
use serde::Deserialize;
use serde::{Deserialize, Serialize};
use std::future::Future;
use thiserror::Error;
use url::Url;
use webpage::HTML;
#[derive(Clone, Debug, Error)]
#[error("Error sending request, {0}")]
@ -47,31 +48,61 @@ where
response.expect("retry http request")
}
#[derive(Deserialize, Debug)]
pub struct IframelyResponse {
#[derive(Deserialize, Serialize, Debug, PartialEq)]
pub struct PostLinkTags {
pub title: Option<String>,
pub description: Option<String>,
thumbnail_url: Option<Url>,
pub html: Option<String>,
}
pub(crate) async fn fetch_iframely(
client: &Client,
url: &Url,
) -> Result<IframelyResponse, LemmyError> {
if let Some(iframely_url) = Settings::get().iframely_url {
let fetch_url = format!("{}/oembed?url={}", iframely_url, url);
/// Fetches the post link html tags (like title, description, thumbnail, etc)
pub async fn fetch_post_link_tags(client: &Client, url: &Url) -> Result<PostLinkTags, LemmyError> {
let response = retry(|| client.get(url.as_str()).send()).await?;
let response = retry(|| client.get(&fetch_url).send()).await?;
let html = response
.text()
.await
.map_err(|e| RecvError(e.to_string()))?;
let res: IframelyResponse = response
.json()
.await
.map_err(|e| RecvError(e.to_string()))?;
Ok(res)
} else {
Err(anyhow!("Missing Iframely URL in config.").into())
}
let tags = html_to_post_link_tags(&html)?;
Ok(tags)
}
fn html_to_post_link_tags(html: &str) -> Result<PostLinkTags, LemmyError> {
let page = HTML::from_string(html.to_string(), None)?;
let page_title = page.title;
let page_description = page.description;
let og_description = page
.opengraph
.properties
.get("description")
.map(|t| t.to_string());
let og_title = page
.opengraph
.properties
.get("title")
.map(|t| t.to_string());
let og_image = page
.opengraph
.images
.get(0)
.map(|ogo| Url::parse(&ogo.url).ok())
.flatten();
let title = og_title.or(page_title);
let description = og_description.or(page_description);
let thumbnail_url = og_image;
Ok(PostLinkTags {
title,
description,
thumbnail_url,
html: None,
})
}
#[derive(Deserialize, Debug, Clone)]
@ -116,22 +147,23 @@ pub(crate) async fn fetch_pictrs(
}
}
pub async fn fetch_iframely_and_pictrs_data(
/// Both are options, since the URL might be either an html page, or an image
pub async fn fetch_post_links_and_pictrs_data(
client: &Client,
url: Option<&Url>,
) -> Result<(Option<IframelyResponse>, Option<Url>), LemmyError> {
) -> Result<(Option<PostLinkTags>, Option<Url>), LemmyError> {
match &url {
Some(url) => {
// Fetch iframely data
let iframely_res_option = fetch_iframely(client, url).await.ok();
// Fetch post-links data
let post_links_res_option = fetch_post_link_tags(client, url).await.ok();
// Fetch pictrs thumbnail
let pictrs_hash = match &iframely_res_option {
Some(iframely_res) => match &iframely_res.thumbnail_url {
Some(iframely_thumbnail_url) => fetch_pictrs(client, iframely_thumbnail_url)
let pictrs_hash = match &post_links_res_option {
Some(post_link_res) => match &post_link_res.thumbnail_url {
Some(post_links_thumbnail_url) => fetch_pictrs(client, post_links_thumbnail_url)
.await?
.map(|r| r.files[0].file.to_owned()),
// Try to generate a small thumbnail if iframely is not supported
// Try to generate a small thumbnail if there's a full sized one from post-links
None => fetch_pictrs(client, url)
.await?
.map(|r| r.files[0].file.to_owned()),
@ -153,7 +185,7 @@ pub async fn fetch_iframely_and_pictrs_data(
})
.flatten();
Ok((iframely_res_option, pictrs_thumbnail))
Ok((post_links_res_option, pictrs_thumbnail))
}
None => Ok((None, None)),
}
@ -176,12 +208,35 @@ async fn is_image_content_type(client: &Client, test: &Url) -> Result<(), LemmyE
#[cfg(test)]
mod tests {
use crate::request::fetch_post_link_tags;
use url::Url;
use super::PostLinkTags;
// These helped with testing
// #[test]
// fn test_iframely() {
// let res = fetch_iframely(client, "https://www.redspark.nu/?p=15341").await;
// assert!(res.is_ok());
// }
#[actix_rt::test]
async fn test_post_links() {
let client = reqwest::Client::default();
let sample_url = Url::parse("https://www.redspark.nu/en/peoples-war/district-leader-of-chand-led-cpn-arrested-in-bhojpur/").unwrap();
let sample_res = fetch_post_link_tags(&client, &sample_url).await.unwrap();
assert_eq!(
PostLinkTags {
title: Some("District Leader Of Chand Led CPN Arrested In Bhojpur - Redspark".to_string()),
description: Some("BHOJPUR: A district leader of the outlawed Netra Bikram Chand alias Biplav-led outfit has been arrested. According to District Police".to_string()),
thumbnail_url: Some(Url::parse("https://www.redspark.nu/wp-content/uploads/2020/03/netra-bikram-chand-attends-program-1272019033653-1000x0-845x653-1.jpg").unwrap()),
html: None,
}, sample_res);
let youtube_url = Url::parse("https://www.youtube.com/watch?v=IquO_TcMZIQ").unwrap();
let youtube_res = fetch_post_link_tags(&client, &youtube_url).await.unwrap();
assert_eq!(
PostLinkTags {
title: Some("A Hard Look at Rent and Rent Seeking with Michael Hudson & Pepe Escobar".to_string()),
description: Some("An interactive discussion on wealth inequality and the “Great Game” on the control of natural resources.In this webinar organized jointly by the Henry George...".to_string()),
thumbnail_url: Some(Url::parse("https://i.ytimg.com/vi/IquO_TcMZIQ/maxresdefault.jpg").unwrap()),
html: None,
}, youtube_res);
}
// #[test]
// fn test_pictshare() {

View file

@ -29,8 +29,6 @@ pub struct Settings {
#[default(None)]
pub pictrs_url: Option<String>,
#[default(None)]
pub iframely_url: Option<String>,
#[default(None)]
pub additional_slurs: Option<String>,
#[default(20)]
pub actor_name_max_length: usize,

View file

@ -14,7 +14,6 @@ services:
depends_on:
- pictrs
- postgres
- iframely
lemmy-ui:
image: dessalines/lemmy-ui:dev
@ -49,12 +48,3 @@ services:
volumes:
- ./volumes/pictrs:/mnt
restart: always
iframely:
image: dogbin/iframely:latest
ports:
- "8061:80"
volumes:
- ../iframely.config.local.js:/iframely/config.local.js:ro
restart: always
mem_limit: 200m

View file

@ -14,7 +14,6 @@ services:
restart: on-failure
depends_on:
- pictrs
- iframely
- lemmy-alpha-ui
- lemmy-beta-ui
- lemmy-gamma-ui
@ -174,9 +173,3 @@ services:
- POSTGRES_DB=lemmy
volumes:
- ./volumes/postgres_epsilon:/var/lib/postgresql/data
iframely:
image: dogbin/iframely:latest
volumes:
- ../iframely.config.local.js:/iframely/config.local.js:ro
restart: always

View file

@ -40,12 +40,6 @@ http {
# Cuts off the trailing slash on URLs to make them valid
rewrite ^(.+)/+$ $1 permanent;
}
location /iframely/ {
proxy_pass http://iframely:80/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
upstream lemmy-beta {
@ -85,12 +79,6 @@ http {
# Cuts off the trailing slash on URLs to make them valid
rewrite ^(.+)/+$ $1 permanent;
}
location /iframely/ {
proxy_pass http://iframely:80/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
upstream lemmy-gamma {
@ -130,12 +118,6 @@ http {
# Cuts off the trailing slash on URLs to make them valid
rewrite ^(.+)/+$ $1 permanent;
}
location /iframely/ {
proxy_pass http://iframely:80/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
upstream lemmy-delta {
@ -175,12 +157,6 @@ http {
# Cuts off the trailing slash on URLs to make them valid
rewrite ^(.+)/+$ $1 permanent;
}
location /iframely/ {
proxy_pass http://iframely:80/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
upstream lemmy-epsilon {
@ -220,11 +196,5 @@ http {
# Cuts off the trailing slash on URLs to make them valid
rewrite ^(.+)/+$ $1 permanent;
}
location /iframely/ {
proxy_pass http://iframely:80/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}

View file

@ -1,283 +0,0 @@
(function() {
var config = {
// Specify a path for custom plugins. Custom plugins will override core plugins.
// CUSTOM_PLUGINS_PATH: __dirname + '/yourcustom-plugin-folder',
DEBUG: false,
RICH_LOG_ENABLED: false,
// For embeds that require render, baseAppUrl will be used as the host.
baseAppUrl: "http://yourdomain.com",
relativeStaticUrl: "/r",
// Or just skip built-in renders altogether
SKIP_IFRAMELY_RENDERS: true,
// For legacy reasons the response format of Iframely open-source is
// different by default as it does not group the links array by rel.
// In order to get the same grouped response as in Cloud API,
// add `&group=true` to your request to change response per request
// or set `GROUP_LINKS` in your config to `true` for a global change.
GROUP_LINKS: true,
// Number of maximum redirects to follow before aborting the page
// request with `redirect loop` error.
MAX_REDIRECTS: 4,
SKIP_OEMBED_RE_LIST: [
// /^https?:\/\/yourdomain\.com\//,
],
/*
// Used to pass parameters to the generate functions when creating HTML elements
// disableSizeWrapper: Don't wrap element (iframe, video, etc) in a positioned div
GENERATE_LINK_PARAMS: {
disableSizeWrapper: true
},
*/
port: 80, //can be overridden by PORT env var
host: '0.0.0.0', // Dockers beware. See https://github.com/itteco/iframely/issues/132#issuecomment-242991246
//can be overridden by HOST env var
// Optional SSL cert, if you serve under HTTPS.
/*
ssl: {
key: require('fs').readFileSync(__dirname + '/key.pem'),
cert: require('fs').readFileSync(__dirname + '/cert.pem'),
port: 443
},
*/
/*
Supported cache engines:
- no-cache - no caching will be used.
- node-cache - good for debug, node memory will be used (https://github.com/tcs-de/nodecache).
- redis - https://github.com/mranney/node_redis.
- memcached - https://github.com/3rd-Eden/node-memcached
*/
CACHE_ENGINE: 'node-cache',
CACHE_TTL: 0, // In seconds.
// 0 = 'never expire' for memcached & node-cache to let cache engine decide itself when to evict the record
// 0 = 'no cache' for redis. Use high enough (e.g. 365*24*60*60*1000) ttl for similar 'never expire' approach instead
/*
// Redis cache options.
REDIS_OPTIONS: {
host: '127.0.0.1',
port: 6379
},
*/
/*
// Memcached options. See https://github.com/3rd-Eden/node-memcached#server-locations
MEMCACHED_OPTIONS: {
locations: "127.0.0.1:11211"
}
*/
/*
// Access-Control-Allow-Origin list.
allowedOrigins: [
"*",
"http://another_domain.com"
],
*/
/*
// Uncomment to enable plugin testing framework.
tests: {
mongodb: 'mongodb://localhost:27017/iframely-tests',
single_test_timeout: 10 * 1000,
plugin_test_period: 2 * 60 * 60 * 1000,
relaunch_script_period: 5 * 60 * 1000
},
*/
// If there's no response from remote server, the timeout will occur after
RESPONSE_TIMEOUT: 5 * 1000, //ms
/* From v1.4.0, Iframely supports HTTP/2 by default. Disable it, if you'd rather not.
Alternatively, you can also disable per origin. See `proxy` option below.
*/
// DISABLE_HTTP2: true,
// Customize API calls to oembed endpoints.
ADD_OEMBED_PARAMS: [{
// Endpoint url regexp array.
re: [/^http:\/\/api\.instagram\.com\/oembed/],
// Custom get params object.
params: {
hidecaption: true
}
}, {
re: [/^https:\/\/www\.facebook\.com\/plugins\/page\/oembed\.json/i],
params: {
show_posts: 0,
show_facepile: 0,
maxwidth: 600
}
}, {
// match i=user or i=moment or i=timeline to configure these types invidually
// see params spec at https://dev.twitter.com/web/embedded-timelines/oembed
re: [/^https?:\/\/publish\.twitter\.com\/oembed\?i=user/i],
params: {
limit: 1,
maxwidth: 600
}
/*
}, {
// Facebook https://developers.facebook.com/docs/plugins/oembed-endpoints
re: [/^https:\/\/www\.facebook\.com\/plugins\/\w+\/oembed\.json/i],
params: {
// Skip script tag and fb-root div.
omitscript: true
}
*/
}],
/*
// Configure use of HTTP proxies as needed.
// You don't have to specify all options per regex - just what you need to override
PROXY: [{
re: [/^https?:\/\/www\.domain\.com/],
proxy_server: 'http://1.2.3.4:8080',
user_agent: 'CHANGE YOUR AGENT',
headers: {
// HTTP headers
// Overrides previous params if overlapped.
},
request_options: {
// Refer to: https://github.com/request/request
// Overrides previous params if overlapped.
},
disable_http2: true
}],
*/
// Customize API calls to 3rd parties. At the very least - configure required keys.
providerOptions: {
locale: "en_US", // ISO 639-1 two-letter language code, e.g. en_CA or fr_CH.
// Will be added as highest priotity in accept-language header with each request.
// Plus is used in FB, YouTube and perhaps other plugins
"twitter": {
"max-width": 550,
"min-width": 250,
hide_media: false,
hide_thread: false,
omit_script: false,
center: false,
// dnt: true,
cache_ttl: 100 * 365 * 24 * 3600 // 100 Years.
},
readability: {
enabled: false
// allowPTagDescription: true // to enable description fallback to first paragraph
},
images: {
loadSize: false, // if true, will try an load first bytes of all images to get/confirm the sizes
checkFavicon: false // if true, will verify all favicons
},
tumblr: {
consumer_key: "INSERT YOUR VALUE"
// media_only: true // disables status embeds for images and videos - will return plain media
},
google: {
// https://developers.google.com/maps/documentation/embed/guide#api_key
maps_key: "INSERT YOUR VALUE"
},
/*
// Optional Camo Proxy to wrap all images: https://github.com/atmos/camo
camoProxy: {
camo_proxy_key: "INSERT YOUR VALUE",
camo_proxy_host: "INSERT YOUR VALUE"
// ssl_only: true // will only proxy non-ssl images
},
*/
// List of query parameters to add to YouTube and Vimeo frames
// Start it with leading "?". Or omit alltogether for default values
// API key is optional, youtube will work without it too.
// It is probably the same API key you use for Google Maps.
youtube: {
// api_key: "INSERT YOUR VALUE",
get_params: "?rel=0&showinfo=1" // https://developers.google.com/youtube/player_parameters
},
vimeo: {
get_params: "?byline=0&badge=0" // https://developer.vimeo.com/player/embedding
},
/*
soundcloud: {
old_player: true // enables classic player
},
giphy: {
media_only: true // disables branded player for gifs and returns just the image
}
*/
/*
bandcamp: {
get_params: '/size=large/bgcol=333333/linkcol=ffffff/artwork=small/transparent=true/',
media: {
album: {
height: 472,
'max-width': 700
},
track: {
height: 120,
'max-width': 700
}
}
}
*/
},
// WHITELIST_WILDCARD, if present, will be added to whitelist as record for top level domain: "*"
// with it, you can define what parsers do when they run accross unknown publisher.
// If absent or empty, all generic media parsers will be disabled except for known domains
// More about format: https://iframely.com/docs/qa-format
/*
WHITELIST_WILDCARD: {
"twitter": {
"player": "allow",
"photo": "deny"
},
"oembed": {
"video": "allow",
"photo": "allow",
"rich": "deny",
"link": "deny"
},
"og": {
"video": ["allow", "ssl", "responsive"]
},
"iframely": {
"survey": "allow",
"reader": "allow",
"player": "allow",
"image": "allow"
},
"html-meta": {
"video": ["allow", "responsive"],
"promo": "allow"
}
}
*/
// Black-list any of the inappropriate domains. Iframely will return 417
// At minimum, keep your localhosts blacklisted to avoid SSRF
BLACKLIST_DOMAINS_RE: [
/^https?:\/\/127\.0\.0\.1/i,
/^https?:\/\/localhost/i,
// And this is AWS metadata service
// https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html
/^https?:\/\/169\.254\.169\.254/
]
};
module.exports = config;
})();

View file

@ -20,6 +20,8 @@
# json web token for authorization between server and client
jwt_secret: "changeme"
# settings related to the postgresql database
# address where pictrs is available
pictrs_url: "http://pictrs:8080"
database: {
# name of the postgres database for lemmy
database: "lemmy"

View file

@ -23,7 +23,6 @@ services:
depends_on:
- postgres
- pictrs
- iframely
lemmy-ui:
image: dessalines/lemmy-ui:0.11.3
@ -46,11 +45,3 @@ services:
- ./volumes/pictrs:/mnt
restart: always
iframely:
image: dogbin/iframely:latest
ports:
- "127.0.0.1:8061:80"
volumes:
- ./iframely.config.local.js:/iframely/config.local.js:ro
restart: always
mem_limit: 200m

View file

@ -12,7 +12,7 @@ use lemmy_api_common::blocking;
use lemmy_api_crud::match_websocket_operation_crud;
use lemmy_apub::activity_queue::create_activity_queue;
use lemmy_db_queries::get_database_url_from_env;
use lemmy_routes::{feeds, images, nodeinfo, webfinger};
use lemmy_routes::{feeds, images, nodeinfo, post_link_tags, webfinger};
use lemmy_server::{api_routes, code_migrations::run_advanced_migrations, scheduled_tasks};
use lemmy_utils::{
rate_limit::{rate_limiter::RateLimiter, RateLimit},
@ -20,7 +20,6 @@ use lemmy_utils::{
LemmyError,
};
use lemmy_websocket::{chat_server::ChatServer, LemmyContext};
use reqwest::Client;
use std::{sync::Arc, thread};
use tokio::sync::Mutex;
@ -66,12 +65,18 @@ async fn main() -> Result<(), LemmyError> {
);
let activity_queue = create_activity_queue();
// Required because docker installs try to use TLS, which is disabled as a reqwest feature flag
let client = reqwest::ClientBuilder::new()
.danger_accept_invalid_certs(true)
.build()?;
let chat_server = ChatServer::startup(
pool.clone(),
rate_limiter.clone(),
|c, i, o, d| Box::pin(match_websocket_operation(c, i, o, d)),
|c, i, o, d| Box::pin(match_websocket_operation_crud(c, i, o, d)),
Client::default(),
client.clone(),
activity_queue.clone(),
)
.start();
@ -81,7 +86,7 @@ async fn main() -> Result<(), LemmyError> {
let context = LemmyContext::create(
pool.clone(),
chat_server.to_owned(),
Client::default(),
client.to_owned(),
activity_queue.to_owned(),
);
let rate_limiter = rate_limiter.clone();
@ -95,6 +100,7 @@ async fn main() -> Result<(), LemmyError> {
.configure(|cfg| images::config(cfg, &rate_limiter))
.configure(nodeinfo::config)
.configure(webfinger::config)
.configure(post_link_tags::config)
})
.bind((settings.bind, settings.port))?
.run()