From f96274033b6a4ee789e257b41bad69ab461b9229 Mon Sep 17 00:00:00 2001 From: Ben Klein Date: Fri, 9 Jul 2021 04:42:35 +0000 Subject: [PATCH 01/16] client/nginx: increase timeouts --- client/nginx.conf.docker | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/nginx.conf.docker b/client/nginx.conf.docker index 98c18b35..2ccc24fd 100644 --- a/client/nginx.conf.docker +++ b/client/nginx.conf.docker @@ -50,6 +50,9 @@ http { gzip_proxied expired no-cache no-store private auth; gzip_types text/plain application/json; + proxy_connect_timeout 180s; + proxy_send_timeout 300s; + proxy_read_timeout 600s; if ($request_uri ~* "/api/(.*)") { proxy_pass http://backend/$1; } From b2800ad7790f005074f499313b2eca6d94a2c61f Mon Sep 17 00:00:00 2001 From: Ben Klein Date: Sat, 10 Jul 2021 02:34:23 +0000 Subject: [PATCH 02/16] client: using openresty for content rewriting --- client/Dockerfile | 3 ++- client/docker-start.sh | 3 ++- client/nginx.conf.docker | 43 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/client/Dockerfile b/client/Dockerfile index 2aeaf3b5..b71165fa 100644 --- a/client/Dockerfile +++ b/client/Dockerfile @@ -23,9 +23,10 @@ WORKDIR /var/www COPY --from=builder /opt/app/public/ . -FROM nginx:alpine as release +FROM openresty/openresty:alpine-fat as release RUN apk --no-cache add dumb-init +RUN /usr/local/openresty/luajit/bin/luarocks install gumbo COPY --from=approot / / CMD ["/docker-start.sh"] diff --git a/client/docker-start.sh b/client/docker-start.sh index 0b2bec8a..bca05fe2 100755 --- a/client/docker-start.sh +++ b/client/docker-start.sh @@ -8,4 +8,5 @@ sed -i "s|__BASEURL__|${BASE_URL:-/}|g" \ /var/www/manifest.json # Start server -exec nginx +echo "$0 starting server..." +exec openresty -c /etc/nginx/nginx.conf diff --git a/client/nginx.conf.docker b/client/nginx.conf.docker index 2ccc24fd..58545e84 100644 --- a/client/nginx.conf.docker +++ b/client/nginx.conf.docker @@ -1,5 +1,7 @@ worker_processes 1; -user nginx; +user nobody; + +pcre_jit on; error_log /dev/stderr warn; pid /var/run/nginx.pid; @@ -9,7 +11,7 @@ events { } http { - include /etc/nginx/mime.types; + include /usr/local/openresty/nginx/conf/mime.types; default_type application/octet-stream; log_format main '$remote_addr -> $request [$status] - ' @@ -23,6 +25,11 @@ http { server __BACKEND__:6666; } + init_by_lua_block { + cjson = require("cjson") + gumbo = require("gumbo") + } + server { listen 80 default_server; @@ -84,6 +91,38 @@ http { gzip_proxied expired no-cache no-store private auth; } + location ~ ^/_internal_api/(.*)$ { + internal; + tcp_nodelay on; + + add_header 'Access-Control-Allow-Origin' '*'; + + gzip off; + proxy_connect_timeout 10s; + proxy_send_timeout 10s; + proxy_read_timeout 10s; + proxy_pass http://backend/$1; + } + + location ~ ^/_internal_tag_generator/(.*)$ { + content_by_lua_block { + ngx.say("") + } + } + location /_og_tags_html { + root /var/www; + content_by_lua_block { + ngx.req.read_body() + + local page_html = ngx.location.capture("/index.htm") + ngx.say(page_html.body) + + ngx.req.set_header("Accept", "application/json") + local server_info = cjson.decode((ngx.location.capture("/_internal_api/info")).body) + ngx.say(server_info.config.name) + } + } + location @unauthorized { return 403 "Unauthorized"; default_type text/plain; From 44d28f3f63e202f9cf9abf226e8d77a9c6906d9e Mon Sep 17 00:00:00 2001 From: Ben Klein Date: Fri, 9 Jul 2021 23:54:49 -0400 Subject: [PATCH 03/16] client: og:site_name served via lua content script --- client/Dockerfile | 4 +++- client/html/index.htm | 1 + client/metatags.lua | 32 ++++++++++++++++++++++++++++++++ client/nginx.conf.docker | 20 +++----------------- 4 files changed, 39 insertions(+), 18 deletions(-) create mode 100644 client/metatags.lua diff --git a/client/Dockerfile b/client/Dockerfile index b71165fa..708b48af 100644 --- a/client/Dockerfile +++ b/client/Dockerfile @@ -18,6 +18,7 @@ COPY docker-start.sh / WORKDIR /etc/nginx COPY nginx.conf.docker ./nginx.conf +COPY metatags.lua . WORKDIR /var/www COPY --from=builder /opt/app/public/ . @@ -26,7 +27,8 @@ COPY --from=builder /opt/app/public/ . FROM openresty/openresty:alpine-fat as release RUN apk --no-cache add dumb-init -RUN /usr/local/openresty/luajit/bin/luarocks install gumbo +RUN opm get bungle/lua-resty-template +# RUN /usr/local/openresty/luajit/bin/luarocks install gumbo COPY --from=approot / / CMD ["/docker-start.sh"] diff --git a/client/html/index.htm b/client/html/index.htm index 00728903..951e6b8a 100644 --- a/client/html/index.htm +++ b/client/html/index.htm @@ -22,6 +22,7 @@ + {{ generated_head_tags }}
diff --git a/client/metatags.lua b/client/metatags.lua new file mode 100644 index 00000000..586a1fc4 --- /dev/null +++ b/client/metatags.lua @@ -0,0 +1,32 @@ +ngx.req.read_body() + +local page_html = ngx.location.capture("/index.htm") + +ngx.req.set_header("Accept", "application/json") +local server_info = cjson.decode((ngx.location.capture("/_internal_api/info")).body) + +-- local document = gumbo.parse(page_html.body) +-- +-- function add_meta_tag (property, content) +-- local new_element = document:createElement("meta") +-- document.head:appendChild(new_element) +-- new_element:setAttribute("property", property) +-- new_element:setAttribute("content", content) +-- end + +local additional_tags = "" + +local function add_meta_tag (property, content) + additional_tags = additional_tags .. "" +end + +-- Add the site name tag +add_meta_tag("og:site_name", server_info.config.name) + +local final_response = page_html.body:gsub("{{ generated_head_tags }}", additional_tags) + +-- Set the content type back to HTML +ngx.header.content_type = 'text/html'; + +-- ngx.say(page_html.body) +ngx.say(final_response) diff --git a/client/nginx.conf.docker b/client/nginx.conf.docker index 58545e84..3040dfaf 100644 --- a/client/nginx.conf.docker +++ b/client/nginx.conf.docker @@ -27,7 +27,7 @@ http { init_by_lua_block { cjson = require("cjson") - gumbo = require("gumbo") + -- gumbo = require("gumbo") } server { @@ -81,7 +81,7 @@ http { location / { root /var/www; - try_files $uri /index.htm; + try_files $uri /_og_tags_html; sendfile on; tcp_nopush on; @@ -104,23 +104,9 @@ http { proxy_pass http://backend/$1; } - location ~ ^/_internal_tag_generator/(.*)$ { - content_by_lua_block { - ngx.say("") - } - } location /_og_tags_html { root /var/www; - content_by_lua_block { - ngx.req.read_body() - - local page_html = ngx.location.capture("/index.htm") - ngx.say(page_html.body) - - ngx.req.set_header("Accept", "application/json") - local server_info = cjson.decode((ngx.location.capture("/_internal_api/info")).body) - ngx.say(server_info.config.name) - } + content_by_lua_file /etc/nginx/metatags.lua; } location @unauthorized { From b4851ce32cb477393a19856845482a777be8477b Mon Sep 17 00:00:00 2001 From: Ben Klein Date: Sat, 10 Jul 2021 00:21:13 -0400 Subject: [PATCH 04/16] client: set og:url to the request_uri --- client/metatags.lua | 3 ++- client/nginx.conf.docker | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/client/metatags.lua b/client/metatags.lua index 586a1fc4..f14aa14a 100644 --- a/client/metatags.lua +++ b/client/metatags.lua @@ -17,11 +17,12 @@ local server_info = cjson.decode((ngx.location.capture("/_internal_api/info")).b local additional_tags = "" local function add_meta_tag (property, content) - additional_tags = additional_tags .. "" + additional_tags = additional_tags .. "" end -- Add the site name tag add_meta_tag("og:site_name", server_info.config.name) +add_meta_tag("og:url", ngx.var.scheme .. "://" .. ngx.var.http_host .. ngx.var.request_uri) local final_response = page_html.body:gsub("{{ generated_head_tags }}", additional_tags) diff --git a/client/nginx.conf.docker b/client/nginx.conf.docker index 3040dfaf..e4983100 100644 --- a/client/nginx.conf.docker +++ b/client/nginx.conf.docker @@ -81,7 +81,7 @@ http { location / { root /var/www; - try_files $uri /_og_tags_html; + try_files $uri /_meta_tags_html; sendfile on; tcp_nopush on; @@ -104,7 +104,8 @@ http { proxy_pass http://backend/$1; } - location /_og_tags_html { + location /_meta_tags_html { + internal; root /var/www; content_by_lua_file /etc/nginx/metatags.lua; } From 1f3c6ca35fcdff156414431934587f2485b73429 Mon Sep 17 00:00:00 2001 From: Ben Klein Date: Sat, 10 Jul 2021 00:50:16 -0400 Subject: [PATCH 05/16] client: openresty-fat -> openresty (save 200MB+) --- client/Dockerfile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/client/Dockerfile b/client/Dockerfile index 708b48af..425ab61a 100644 --- a/client/Dockerfile +++ b/client/Dockerfile @@ -24,11 +24,9 @@ WORKDIR /var/www COPY --from=builder /opt/app/public/ . -FROM openresty/openresty:alpine-fat as release +FROM openresty/openresty:alpine as release RUN apk --no-cache add dumb-init -RUN opm get bungle/lua-resty-template -# RUN /usr/local/openresty/luajit/bin/luarocks install gumbo COPY --from=approot / / CMD ["/docker-start.sh"] From 7d90a73b111fea9a5aac867181675c46d3dfb3d1 Mon Sep 17 00:00:00 2001 From: Ben Klein Date: Sat, 10 Jul 2021 01:46:18 -0400 Subject: [PATCH 06/16] client: initial og:title and og:image for posts --- client/metatags.lua | 8 +++++++- client/nginx.conf.docker | 6 +++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/client/metatags.lua b/client/metatags.lua index f14aa14a..510dbd16 100644 --- a/client/metatags.lua +++ b/client/metatags.lua @@ -22,7 +22,13 @@ end -- Add the site name tag add_meta_tag("og:site_name", server_info.config.name) -add_meta_tag("og:url", ngx.var.scheme .. "://" .. ngx.var.http_host .. ngx.var.request_uri) +add_meta_tag("og:url", ngx.var.external_host_url .. ngx.var.request_uri) + +if ngx.var.request_uri_path:match('^/post') then + local post_info = cjson.decode((ngx.location.capture("/_internal_api"..ngx.var.request_uri_path)).body) + add_meta_tag("og:image", ngx.var.external_host_url .. '/' .. post_info.contentUrl) + add_meta_tag("og:title", server_info.config.name .. " - Post " .. post_info.id) +end local final_response = page_html.body:gsub("{{ generated_head_tags }}", additional_tags) diff --git a/client/nginx.conf.docker b/client/nginx.conf.docker index e4983100..c5b2ada4 100644 --- a/client/nginx.conf.docker +++ b/client/nginx.conf.docker @@ -25,9 +25,12 @@ http { server __BACKEND__:6666; } + map $request_uri $request_uri_path { + "~^(?P[^?]*)(\?.*)?$" $path; + } + init_by_lua_block { cjson = require("cjson") - -- gumbo = require("gumbo") } server { @@ -107,6 +110,7 @@ http { location /_meta_tags_html { internal; root /var/www; + set $external_host_url "${scheme}://${http_host}"; content_by_lua_file /etc/nginx/metatags.lua; } From 38080611d5f52637835f1a8c9990b19ccce23cf4 Mon Sep 17 00:00:00 2001 From: Ben Klein Date: Sat, 10 Jul 2021 01:56:40 -0400 Subject: [PATCH 07/16] client: og-tags fix for restricted posts --- client/metatags.lua | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/client/metatags.lua b/client/metatags.lua index 510dbd16..1882f654 100644 --- a/client/metatags.lua +++ b/client/metatags.lua @@ -26,8 +26,13 @@ add_meta_tag("og:url", ngx.var.external_host_url .. ngx.var.request_uri) if ngx.var.request_uri_path:match('^/post') then local post_info = cjson.decode((ngx.location.capture("/_internal_api"..ngx.var.request_uri_path)).body) - add_meta_tag("og:image", ngx.var.external_host_url .. '/' .. post_info.contentUrl) - add_meta_tag("og:title", server_info.config.name .. " - Post " .. post_info.id) + -- If no permission to access, fields will be nil, thus cannot be concat'd + if post_info.contentUrl then + add_meta_tag("og:image", ngx.var.external_host_url .. '/' .. post_info.contentUrl) + end + if post_info.id then + add_meta_tag("og:title", server_info.config.name .. " - Post " .. post_info.id) + end end local final_response = page_html.body:gsub("{{ generated_head_tags }}", additional_tags) From 3ec013b210963adae0489cad7adf55df9692ddfd Mon Sep 17 00:00:00 2001 From: Ben Klein Date: Sat, 10 Jul 2021 15:25:09 -0400 Subject: [PATCH 08/16] client/lua: handle the api server being offline --- client/metatags.lua | 48 ++++++++++++++++++++++++---------------- client/nginx.conf.docker | 1 + 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/client/metatags.lua b/client/metatags.lua index 1882f654..a227e247 100644 --- a/client/metatags.lua +++ b/client/metatags.lua @@ -1,21 +1,35 @@ +-- Set the response content type back to HTML +ngx.header.content_type = 'text/html'; + ngx.req.read_body() -local page_html = ngx.location.capture("/index.htm") +local page_html = ngx.location.capture("/index.htm").body + +local before_content, placeholder, after_content +before_content, placeholder, after_content = page_html:match( + string.format("^(.*)(%s)(.*)$", html_head_tag_replacement_str) +) + +-- check for placeholder to replace +if not placeholder then + ngx.log(ngx.STDERR, "WARNING: Meta tag placeholder was not found in page html.") + ngx.say(page_html) + return +else + -- start the response + ngx.print(before_content) +end ngx.req.set_header("Accept", "application/json") -local server_info = cjson.decode((ngx.location.capture("/_internal_api/info")).body) - --- local document = gumbo.parse(page_html.body) --- --- function add_meta_tag (property, content) --- local new_element = document:createElement("meta") --- document.head:appendChild(new_element) --- new_element:setAttribute("property", property) --- new_element:setAttribute("content", content) --- end +local server_info_resp = ngx.location.capture("/_internal_api/info") +if server_info_resp.status ~= 200 then + ngx.log(ngx.STDERR, "Failed to acquire server info from szurubooru API, unable to generate meta tags: HTTP status "..server_info_resp.status) + ngx.print(after_content) + return +end +local server_info = cjson.decode(server_info_resp.body) local additional_tags = "" - local function add_meta_tag (property, content) additional_tags = additional_tags .. "" end @@ -35,10 +49,6 @@ if ngx.var.request_uri_path:match('^/post') then end end -local final_response = page_html.body:gsub("{{ generated_head_tags }}", additional_tags) - --- Set the content type back to HTML -ngx.header.content_type = 'text/html'; - --- ngx.say(page_html.body) -ngx.say(final_response) +-- Once tags have been generated, write them and then finish the response +ngx.print(additional_tags) +ngx.print(after_content) diff --git a/client/nginx.conf.docker b/client/nginx.conf.docker index c5b2ada4..4f36a8b2 100644 --- a/client/nginx.conf.docker +++ b/client/nginx.conf.docker @@ -31,6 +31,7 @@ http { init_by_lua_block { cjson = require("cjson") + html_head_tag_replacement_str = "{{ generated_head_tags }}" } server { From 9fdeb293c1d059ae57411eeb246fb5b0be845c30 Mon Sep 17 00:00:00 2001 From: Ben Klein Date: Sat, 10 Jul 2021 16:07:52 -0400 Subject: [PATCH 09/16] client/lua: further development for post tags --- client/metatags.lua | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/client/metatags.lua b/client/metatags.lua index a227e247..97d68e71 100644 --- a/client/metatags.lua +++ b/client/metatags.lua @@ -18,6 +18,8 @@ if not placeholder then else -- start the response ngx.print(before_content) + -- send partial content to the client to allow preloading the app + ngx.flush() end ngx.req.set_header("Accept", "application/json") @@ -31,21 +33,40 @@ local server_info = cjson.decode(server_info_resp.body) local additional_tags = "" local function add_meta_tag (property, content) - additional_tags = additional_tags .. "" + additional_tags = additional_tags .. "" end -- Add the site name tag add_meta_tag("og:site_name", server_info.config.name) add_meta_tag("og:url", ngx.var.external_host_url .. ngx.var.request_uri) -if ngx.var.request_uri_path:match('^/post') then - local post_info = cjson.decode((ngx.location.capture("/_internal_api"..ngx.var.request_uri_path)).body) - -- If no permission to access, fields will be nil, thus cannot be concat'd - if post_info.contentUrl then - add_meta_tag("og:image", ngx.var.external_host_url .. '/' .. post_info.contentUrl) - end - if post_info.id then +if ngx.var.request_uri_path:match('^/post') then -- Post metadata + -- check if posts are accessible to anonymous users: + if server_info.config.privileges["posts:view"] == "anonymous" then + local post_info = cjson.decode((ngx.location.capture("/_internal_api"..ngx.var.request_uri_path)).body) add_meta_tag("og:title", server_info.config.name .. " - Post " .. post_info.id) + local og_media_prefix + if post_info.type == "image" then + og_media_prefix = "og:image" + elseif post_info.type == "video" then + og_media_prefix = "og:video" + end + add_meta_tag(og_media_prefix..":url", ngx.var.external_host_url .. '/' .. post_info.contentUrl) + add_meta_tag(og_media_prefix..":width", post_info.canvasWidth) + add_meta_tag(og_media_prefix..":height", post_info.canvasHeight) + else + -- no permission to retrieve post data + add_meta_tag("og:title", server_info.config.name .. " - Login required") + end +elseif ngx.var.request_uri_path:match('^/user/(.*)$') then -- User metadata + local username = ngx.var.request_uri_path:match('^/user/(.*)/?$') + add_meta_tag("og:title", server_info.config.name .. " - User " .. username) + -- check for permission to access user profiles + if server_info.config.privileges["users:view"] == "anonymous" then + local user_info = cjson.decode((ngx.location.capture("/_internal_api/"..username)).body) + -- TODO + else + -- TODO end end From 9f1bb53b4f260ba073b86b2e0c7cc7652fe540df Mon Sep 17 00:00:00 2001 From: Ben Klein Date: Sat, 10 Jul 2021 16:45:21 -0400 Subject: [PATCH 10/16] client/lua: additional post tags --- client/metatags.lua | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/client/metatags.lua b/client/metatags.lua index 97d68e71..92dcae19 100644 --- a/client/metatags.lua +++ b/client/metatags.lua @@ -33,27 +33,39 @@ local server_info = cjson.decode(server_info_resp.body) local additional_tags = "" local function add_meta_tag (property, content) + -- NOTE do not allow user-provided data in the property name, only the content has quotes escaped additional_tags = additional_tags .. "" end -- Add the site name tag add_meta_tag("og:site_name", server_info.config.name) -add_meta_tag("og:url", ngx.var.external_host_url .. ngx.var.request_uri) +add_meta_tag("og:url", ngx.var.external_host_url .. ngx.var.request_uri_path) if ngx.var.request_uri_path:match('^/post') then -- Post metadata -- check if posts are accessible to anonymous users: if server_info.config.privileges["posts:view"] == "anonymous" then + add_meta_tag("og:type", "article") local post_info = cjson.decode((ngx.location.capture("/_internal_api"..ngx.var.request_uri_path)).body) add_meta_tag("og:title", server_info.config.name .. " - Post " .. post_info.id) + add_meta_tag("twitter:title", server_info.config.name .. " - Post " .. post_info.id) + add_meta_tag("article:published_time", post_info.creationTime) local og_media_prefix if post_info.type == "image" then og_media_prefix = "og:image" + add_meta_tag("twitter:card", "summary_large_image") + add_meta_tag("twitter:image", ngx.var.external_host_url .. '/' .. post_info.contentUrl) elseif post_info.type == "video" then og_media_prefix = "og:video" + -- some sites don't preview video, so at least provide a thumbnail + add_meta_tag("og:image", ngx.var.external_host_url .. '/' .. post_info.thumbnailUrl) end add_meta_tag(og_media_prefix..":url", ngx.var.external_host_url .. '/' .. post_info.contentUrl) add_meta_tag(og_media_prefix..":width", post_info.canvasWidth) add_meta_tag(og_media_prefix..":height", post_info.canvasHeight) + -- user is not present for anonymous uploads: + if post_info.user then + add_meta_tag("article:author", post_info.user.name) + end else -- no permission to retrieve post data add_meta_tag("og:title", server_info.config.name .. " - Login required") From b302ce23bd61b28f3a456596f82cd035c158ad51 Mon Sep 17 00:00:00 2001 From: Ben Klein Date: Sat, 10 Jul 2021 17:17:08 -0400 Subject: [PATCH 11/16] client/lua: stricter matches and home tags --- client/metatags.lua | 41 +++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/client/metatags.lua b/client/metatags.lua index 92dcae19..9274bf27 100644 --- a/client/metatags.lua +++ b/client/metatags.lua @@ -41,7 +41,29 @@ end add_meta_tag("og:site_name", server_info.config.name) add_meta_tag("og:url", ngx.var.external_host_url .. ngx.var.request_uri_path) -if ngx.var.request_uri_path:match('^/post') then -- Post metadata +if ngx.var.request_uri_path:match('^/$') then -- Site root + add_meta_tag("og:title", server_info.config.name) + add_meta_tag("twitter:title", server_info.config.name) + -- if there's a featured post, let's use that as the image + if server_info.featuredPost then + local post_info = server_info.featuredPost + -- NOTE this is different from the normal Post tags, + -- notably we avoid setting the article type, author, time, etc + local og_media_prefix + if post_info.type == "image" then + og_media_prefix = "og:image" + add_meta_tag("twitter:card", "summary_large_image") + add_meta_tag("twitter:image", ngx.var.external_host_url .. '/' .. post_info.contentUrl) + elseif post_info.type == "video" then + og_media_prefix = "og:video" + -- some sites don't preview video, so at least provide a thumbnail + add_meta_tag("og:image", ngx.var.external_host_url .. '/' .. post_info.thumbnailUrl) + end + add_meta_tag(og_media_prefix..":url", ngx.var.external_host_url .. '/' .. post_info.contentUrl) + add_meta_tag(og_media_prefix..":width", post_info.canvasWidth) + add_meta_tag(og_media_prefix..":height", post_info.canvasHeight) + end +elseif ngx.var.request_uri_path:match('^/post/([0-9]+)/?$') then -- Post metadata -- check if posts are accessible to anonymous users: if server_info.config.privileges["posts:view"] == "anonymous" then add_meta_tag("og:type", "article") @@ -70,15 +92,22 @@ if ngx.var.request_uri_path:match('^/post') then -- Post metadata -- no permission to retrieve post data add_meta_tag("og:title", server_info.config.name .. " - Login required") end -elseif ngx.var.request_uri_path:match('^/user/(.*)$') then -- User metadata - local username = ngx.var.request_uri_path:match('^/user/(.*)/?$') - add_meta_tag("og:title", server_info.config.name .. " - User " .. username) +elseif ngx.var.request_uri_path:match('^/user/([^/]+)/?$') then -- User metadata + local username = ngx.var.request_uri_path:match('^/user/([^/]+)/?$') + add_meta_tag("og:title", server_info.config.name .. " - " .. username) + add_meta_tag("og:type", "profile") -- check for permission to access user profiles if server_info.config.privileges["users:view"] == "anonymous" then local user_info = cjson.decode((ngx.location.capture("/_internal_api/"..username)).body) - -- TODO + add_meta_tag("profile:username", user_info.name) + local avatar_url = user_info.avatarUrl + if avatar_url:match("^https?://") then + add_meta_tag("og:image", avatar_url) + else + add_meta_tag("og:image", ngx.var.external_host_url .. '/' .. avatar_url) + end else - -- TODO + -- no permission to view user data end end From d5fda346d206c961c04ba15a83668c299248f0a8 Mon Sep 17 00:00:00 2001 From: Ben Klein Date: Sat, 10 Jul 2021 18:17:24 -0400 Subject: [PATCH 12/16] client/lua: fix user meta tags --- client/metatags.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/client/metatags.lua b/client/metatags.lua index 9274bf27..8cf83ebd 100644 --- a/client/metatags.lua +++ b/client/metatags.lua @@ -42,6 +42,7 @@ add_meta_tag("og:site_name", server_info.config.name) add_meta_tag("og:url", ngx.var.external_host_url .. ngx.var.request_uri_path) if ngx.var.request_uri_path:match('^/$') then -- Site root + add_meta_tag("og:type", "website") add_meta_tag("og:title", server_info.config.name) add_meta_tag("twitter:title", server_info.config.name) -- if there's a featured post, let's use that as the image @@ -98,9 +99,10 @@ elseif ngx.var.request_uri_path:match('^/user/([^/]+)/?$') then -- User metadata add_meta_tag("og:type", "profile") -- check for permission to access user profiles if server_info.config.privileges["users:view"] == "anonymous" then - local user_info = cjson.decode((ngx.location.capture("/_internal_api/"..username)).body) + local user_info = cjson.decode((ngx.location.capture("/_internal_api/user/"..username)).body) add_meta_tag("profile:username", user_info.name) - local avatar_url = user_info.avatarUrl + local avatar_url + avatar_url = user_info.avatarUrl if avatar_url:match("^https?://") then add_meta_tag("og:image", avatar_url) else From 372b40a6b5139d008dc9184fb278666fb416c571 Mon Sep 17 00:00:00 2001 From: Ben Klein Date: Sat, 10 Jul 2021 22:38:39 -0400 Subject: [PATCH 13/16] client/nginx: meta tags use X-Forwarded-Proto --- client/metatags.lua | 3 +++ client/nginx.conf.docker | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/client/metatags.lua b/client/metatags.lua index 8cf83ebd..6826a13e 100644 --- a/client/metatags.lua +++ b/client/metatags.lua @@ -79,6 +79,9 @@ elseif ngx.var.request_uri_path:match('^/post/([0-9]+)/?$') then -- Post metadat add_meta_tag("twitter:image", ngx.var.external_host_url .. '/' .. post_info.contentUrl) elseif post_info.type == "video" then og_media_prefix = "og:video" + add_meta_tag("twitter:card", "player") + add_meta_tag("twitter:player:width", post_info.canvasWidth) + add_meta_tag("twitter:player:height", post_info.canvasHeight) -- some sites don't preview video, so at least provide a thumbnail add_meta_tag("og:image", ngx.var.external_host_url .. '/' .. post_info.thumbnailUrl) end diff --git a/client/nginx.conf.docker b/client/nginx.conf.docker index 4f36a8b2..b4c63e7e 100644 --- a/client/nginx.conf.docker +++ b/client/nginx.conf.docker @@ -110,8 +110,12 @@ http { location /_meta_tags_html { internal; + set $original_scheme $scheme; + if ( $http_x_forwarded_proto = 'https' ) { + set $original_scheme "https"; + } root /var/www; - set $external_host_url "${scheme}://${http_host}"; + set $external_host_url "${original_scheme}://${http_host}"; content_by_lua_file /etc/nginx/metatags.lua; } From 6e07c61d3f40b513081e6db6bc7382e4a0b15e23 Mon Sep 17 00:00:00 2001 From: Ben Klein Date: Sun, 11 Jul 2021 15:06:40 -0400 Subject: [PATCH 14/16] client/lua: wrap tags with error handler --- client/metatags.lua | 145 +++++++++++++++++++++++--------------------- 1 file changed, 76 insertions(+), 69 deletions(-) diff --git a/client/metatags.lua b/client/metatags.lua index 6826a13e..aa6839b1 100644 --- a/client/metatags.lua +++ b/client/metatags.lua @@ -41,81 +41,88 @@ end add_meta_tag("og:site_name", server_info.config.name) add_meta_tag("og:url", ngx.var.external_host_url .. ngx.var.request_uri_path) -if ngx.var.request_uri_path:match('^/$') then -- Site root - add_meta_tag("og:type", "website") - add_meta_tag("og:title", server_info.config.name) - add_meta_tag("twitter:title", server_info.config.name) - -- if there's a featured post, let's use that as the image - if server_info.featuredPost then - local post_info = server_info.featuredPost - -- NOTE this is different from the normal Post tags, - -- notably we avoid setting the article type, author, time, etc - local og_media_prefix - if post_info.type == "image" then - og_media_prefix = "og:image" - add_meta_tag("twitter:card", "summary_large_image") - add_meta_tag("twitter:image", ngx.var.external_host_url .. '/' .. post_info.contentUrl) - elseif post_info.type == "video" then - og_media_prefix = "og:video" - -- some sites don't preview video, so at least provide a thumbnail - add_meta_tag("og:image", ngx.var.external_host_url .. '/' .. post_info.thumbnailUrl) +local function generate_meta_tags () + if ngx.var.request_uri_path:match('^/$') then -- Site root + add_meta_tag("og:type", "website") + add_meta_tag("og:title", server_info.config.name) + add_meta_tag("twitter:title", server_info.config.name) + -- if there's a featured post, let's use that as the image + if server_info.featuredPost then + local post_info = server_info.featuredPost + -- NOTE this is different from the normal Post tags, + -- notably we avoid setting the article type, author, time, etc + local og_media_prefix + if post_info.type == "image" then + og_media_prefix = "og:image" + add_meta_tag("twitter:card", "summary_large_image") + add_meta_tag("twitter:image", ngx.var.external_host_url .. '/' .. post_info.contentUrl) + elseif post_info.type == "video" then + og_media_prefix = "og:video" + -- some sites don't preview video, so at least provide a thumbnail + add_meta_tag("og:image", ngx.var.external_host_url .. '/' .. post_info.thumbnailUrl) + end + add_meta_tag(og_media_prefix..":url", ngx.var.external_host_url .. '/' .. post_info.contentUrl) + add_meta_tag(og_media_prefix..":width", post_info.canvasWidth) + add_meta_tag(og_media_prefix..":height", post_info.canvasHeight) end - add_meta_tag(og_media_prefix..":url", ngx.var.external_host_url .. '/' .. post_info.contentUrl) - add_meta_tag(og_media_prefix..":width", post_info.canvasWidth) - add_meta_tag(og_media_prefix..":height", post_info.canvasHeight) - end -elseif ngx.var.request_uri_path:match('^/post/([0-9]+)/?$') then -- Post metadata - -- check if posts are accessible to anonymous users: - if server_info.config.privileges["posts:view"] == "anonymous" then - add_meta_tag("og:type", "article") - local post_info = cjson.decode((ngx.location.capture("/_internal_api"..ngx.var.request_uri_path)).body) - add_meta_tag("og:title", server_info.config.name .. " - Post " .. post_info.id) - add_meta_tag("twitter:title", server_info.config.name .. " - Post " .. post_info.id) - add_meta_tag("article:published_time", post_info.creationTime) - local og_media_prefix - if post_info.type == "image" then - og_media_prefix = "og:image" - add_meta_tag("twitter:card", "summary_large_image") - add_meta_tag("twitter:image", ngx.var.external_host_url .. '/' .. post_info.contentUrl) - elseif post_info.type == "video" then - og_media_prefix = "og:video" - add_meta_tag("twitter:card", "player") - add_meta_tag("twitter:player:width", post_info.canvasWidth) - add_meta_tag("twitter:player:height", post_info.canvasHeight) - -- some sites don't preview video, so at least provide a thumbnail - add_meta_tag("og:image", ngx.var.external_host_url .. '/' .. post_info.thumbnailUrl) - end - add_meta_tag(og_media_prefix..":url", ngx.var.external_host_url .. '/' .. post_info.contentUrl) - add_meta_tag(og_media_prefix..":width", post_info.canvasWidth) - add_meta_tag(og_media_prefix..":height", post_info.canvasHeight) - -- user is not present for anonymous uploads: - if post_info.user then - add_meta_tag("article:author", post_info.user.name) - end - else - -- no permission to retrieve post data - add_meta_tag("og:title", server_info.config.name .. " - Login required") - end -elseif ngx.var.request_uri_path:match('^/user/([^/]+)/?$') then -- User metadata - local username = ngx.var.request_uri_path:match('^/user/([^/]+)/?$') - add_meta_tag("og:title", server_info.config.name .. " - " .. username) - add_meta_tag("og:type", "profile") - -- check for permission to access user profiles - if server_info.config.privileges["users:view"] == "anonymous" then - local user_info = cjson.decode((ngx.location.capture("/_internal_api/user/"..username)).body) - add_meta_tag("profile:username", user_info.name) - local avatar_url - avatar_url = user_info.avatarUrl - if avatar_url:match("^https?://") then - add_meta_tag("og:image", avatar_url) + elseif ngx.var.request_uri_path:match('^/post/([0-9]+)/?$') then -- Post metadata + -- check if posts are accessible to anonymous users: + if server_info.config.privileges["posts:view"] == "anonymous" then + add_meta_tag("og:type", "article") + local post_info = cjson.decode((ngx.location.capture("/_internal_api"..ngx.var.request_uri_path)).body) + add_meta_tag("og:title", server_info.config.name .. " - Post " .. post_info.id) + add_meta_tag("twitter:title", server_info.config.name .. " - Post " .. post_info.id) + add_meta_tag("article:published_time", post_info.creationTime) + local og_media_prefix + if post_info.type == "video" then + og_media_prefix = "og:video" + add_meta_tag("twitter:card", "player") + add_meta_tag("twitter:player:width", post_info.canvasWidth) + add_meta_tag("twitter:player:height", post_info.canvasHeight) + -- some sites don't preview video, so at least provide a thumbnail + add_meta_tag("og:image", ngx.var.external_host_url .. '/' .. post_info.thumbnailUrl) + else + og_media_prefix = "og:image" + add_meta_tag("twitter:card", "summary_large_image") + add_meta_tag("twitter:image", ngx.var.external_host_url .. '/' .. post_info.contentUrl) + end + add_meta_tag(og_media_prefix..":url", ngx.var.external_host_url .. '/' .. post_info.contentUrl) + add_meta_tag(og_media_prefix..":width", post_info.canvasWidth) + add_meta_tag(og_media_prefix..":height", post_info.canvasHeight) + -- user is not present for anonymous uploads: + if post_info.user then + add_meta_tag("article:author", post_info.user.name) + end else - add_meta_tag("og:image", ngx.var.external_host_url .. '/' .. avatar_url) + -- no permission to retrieve post data + add_meta_tag("og:title", server_info.config.name .. " - Login required") + end + elseif ngx.var.request_uri_path:match('^/user/([^/]+)/?$') then -- User metadata + local username = ngx.var.request_uri_path:match('^/user/([^/]+)/?$') + add_meta_tag("og:title", server_info.config.name .. " - " .. username) + add_meta_tag("og:type", "profile") + -- check for permission to access user profiles + if server_info.config.privileges["users:view"] == "anonymous" then + local user_info = cjson.decode((ngx.location.capture("/_internal_api/user/"..username)).body) + add_meta_tag("profile:username", user_info.name) + local avatar_url + avatar_url = user_info.avatarUrl + if avatar_url:match("^https?://") then + add_meta_tag("og:image", avatar_url) + else + add_meta_tag("og:image", ngx.var.external_host_url .. '/' .. avatar_url) + end + else + -- no permission to view user data end - else - -- no permission to view user data end end +local status, err = pcall(generate_meta_tags) +if not status then + ngx.log(ngx.STDERR, "Failed to generate meta tags: "..tostring(err)) +end + -- Once tags have been generated, write them and then finish the response ngx.print(additional_tags) ngx.print(after_content) From d94f5e9fd6cfdd8ecd1db5b19ac0d6791221adcc Mon Sep 17 00:00:00 2001 From: Ben Klein Date: Sun, 11 Jul 2021 16:04:08 -0400 Subject: [PATCH 15/16] client/lua: /user/* "User not found" title --- client/metatags.lua | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/client/metatags.lua b/client/metatags.lua index aa6839b1..799f6f50 100644 --- a/client/metatags.lua +++ b/client/metatags.lua @@ -99,18 +99,23 @@ local function generate_meta_tags () end elseif ngx.var.request_uri_path:match('^/user/([^/]+)/?$') then -- User metadata local username = ngx.var.request_uri_path:match('^/user/([^/]+)/?$') - add_meta_tag("og:title", server_info.config.name .. " - " .. username) - add_meta_tag("og:type", "profile") -- check for permission to access user profiles if server_info.config.privileges["users:view"] == "anonymous" then - local user_info = cjson.decode((ngx.location.capture("/_internal_api/user/"..username)).body) - add_meta_tag("profile:username", user_info.name) - local avatar_url - avatar_url = user_info.avatarUrl - if avatar_url:match("^https?://") then - add_meta_tag("og:image", avatar_url) + local user_info_request = ngx.location.capture("/_internal_api/user/"..username) + add_meta_tag("og:type", "profile") + if user_info_request.status == 200 then + add_meta_tag("og:title", server_info.config.name .. " - " .. username) + local user_info = cjson.decode(user_info_request.body) + add_meta_tag("profile:username", user_info.name) + local avatar_url = user_info.avatarUrl + if avatar_url:match("^https?://") then + add_meta_tag("og:image", avatar_url) + else + add_meta_tag("og:image", ngx.var.external_host_url .. '/' .. avatar_url) + end else - add_meta_tag("og:image", ngx.var.external_host_url .. '/' .. avatar_url) + -- could not retrieve the user profile, show some defaults + add_meta_tag("og:title", server_info.config.name .. " - User not found") end else -- no permission to view user data From 43327132cba34c6d769c99e8fab4569cafc7f712 Mon Sep 17 00:00:00 2001 From: Ben Klein Date: Fri, 17 Sep 2021 23:04:39 -0400 Subject: [PATCH 16/16] client: /post/id/* allowed to match for post tags --- client/metatags.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/client/metatags.lua b/client/metatags.lua index 799f6f50..bebd51e1 100644 --- a/client/metatags.lua +++ b/client/metatags.lua @@ -65,11 +65,13 @@ local function generate_meta_tags () add_meta_tag(og_media_prefix..":width", post_info.canvasWidth) add_meta_tag(og_media_prefix..":height", post_info.canvasHeight) end - elseif ngx.var.request_uri_path:match('^/post/([0-9]+)/?$') then -- Post metadata + elseif ngx.var.request_uri_path:match('^/post/([0-9]+)') then -- Post metadata -- check if posts are accessible to anonymous users: if server_info.config.privileges["posts:view"] == "anonymous" then + local match, err = ngx.re.match(ngx.var.request_uri_path, "^/post/(?[0-9]+)") + local post_id = match["post_id"] add_meta_tag("og:type", "article") - local post_info = cjson.decode((ngx.location.capture("/_internal_api"..ngx.var.request_uri_path)).body) + local post_info = cjson.decode((ngx.location.capture("/_internal_api/post/"..post_id)).body) add_meta_tag("og:title", server_info.config.name .. " - Post " .. post_info.id) add_meta_tag("twitter:title", server_info.config.name .. " - Post " .. post_info.id) add_meta_tag("article:published_time", post_info.creationTime)