Merge 22835fa5c7
into 61b9f81e39
This commit is contained in:
commit
e7bdf4f273
5 changed files with 181 additions and 5 deletions
|
@ -17,12 +17,13 @@ COPY docker-start.sh /
|
||||||
|
|
||||||
WORKDIR /etc/nginx
|
WORKDIR /etc/nginx
|
||||||
COPY nginx.conf.docker ./nginx.conf
|
COPY nginx.conf.docker ./nginx.conf
|
||||||
|
COPY metatags.lua .
|
||||||
|
|
||||||
WORKDIR /var/www
|
WORKDIR /var/www
|
||||||
COPY --from=builder /opt/app/public/ .
|
COPY --from=builder /opt/app/public/ .
|
||||||
|
|
||||||
|
|
||||||
FROM nginx:alpine as release
|
FROM openresty/openresty:alpine as release
|
||||||
|
|
||||||
RUN apk --no-cache add dumb-init
|
RUN apk --no-cache add dumb-init
|
||||||
COPY --from=approot / /
|
COPY --from=approot / /
|
||||||
|
|
|
@ -8,4 +8,5 @@ sed -i "s|__BASEURL__|${BASE_URL:-/}|g" \
|
||||||
/var/www/manifest.json
|
/var/www/manifest.json
|
||||||
|
|
||||||
# Start server
|
# Start server
|
||||||
exec nginx
|
echo "$0 starting server..."
|
||||||
|
exec openresty -c /etc/nginx/nginx.conf
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
<link rel='apple-touch-startup-image' href='img/apple-touch-startup-image-1668x2224.png' media='(min-device-width: 834px) and (max-device-width: 834px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: portrait)'/>
|
<link rel='apple-touch-startup-image' href='img/apple-touch-startup-image-1668x2224.png' media='(min-device-width: 834px) and (max-device-width: 834px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: portrait)'/>
|
||||||
<link rel='apple-touch-startup-image' href='img/apple-touch-startup-image-2048x2732.png' media='(min-device-width: 1024px) and (max-device-width: 1024px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: portrait)'/>
|
<link rel='apple-touch-startup-image' href='img/apple-touch-startup-image-2048x2732.png' media='(min-device-width: 1024px) and (max-device-width: 1024px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: portrait)'/>
|
||||||
<link rel='manifest' href='manifest.json'/>
|
<link rel='manifest' href='manifest.json'/>
|
||||||
|
{{ generated_head_tags }}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id='top-navigation-holder'></div>
|
<div id='top-navigation-holder'></div>
|
||||||
|
|
135
client/metatags.lua
Normal file
135
client/metatags.lua
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
-- 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").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)
|
||||||
|
-- send partial content to the client to allow preloading the app
|
||||||
|
ngx.flush()
|
||||||
|
end
|
||||||
|
|
||||||
|
ngx.req.set_header("Accept", "application/json")
|
||||||
|
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)
|
||||||
|
-- NOTE do not allow user-provided data in the property name, only the content has quotes escaped
|
||||||
|
additional_tags = additional_tags .. "<meta property=\"" .. property .. "\" content=\"" .. tostring(content):gsub('"', '\\"') .. "\"/>"
|
||||||
|
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_path)
|
||||||
|
|
||||||
|
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
|
||||||
|
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/(?<post_id>[0-9]+)")
|
||||||
|
local post_id = match["post_id"]
|
||||||
|
add_meta_tag("og:type", "article")
|
||||||
|
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)
|
||||||
|
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
|
||||||
|
-- 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/([^/]+)/?$')
|
||||||
|
-- check for permission to access user profiles
|
||||||
|
if server_info.config.privileges["users:view"] == "anonymous" then
|
||||||
|
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
|
||||||
|
-- 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
|
||||||
|
end
|
||||||
|
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)
|
|
@ -1,5 +1,7 @@
|
||||||
worker_processes 1;
|
worker_processes 1;
|
||||||
user nginx;
|
user nobody;
|
||||||
|
|
||||||
|
pcre_jit on;
|
||||||
|
|
||||||
error_log /dev/stderr warn;
|
error_log /dev/stderr warn;
|
||||||
pid /var/run/nginx.pid;
|
pid /var/run/nginx.pid;
|
||||||
|
@ -9,7 +11,7 @@ events {
|
||||||
}
|
}
|
||||||
|
|
||||||
http {
|
http {
|
||||||
include /etc/nginx/mime.types;
|
include /usr/local/openresty/nginx/conf/mime.types;
|
||||||
default_type application/octet-stream;
|
default_type application/octet-stream;
|
||||||
|
|
||||||
log_format main '$remote_addr -> $request [$status] - '
|
log_format main '$remote_addr -> $request [$status] - '
|
||||||
|
@ -23,6 +25,15 @@ http {
|
||||||
server __BACKEND__:6666;
|
server __BACKEND__:6666;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
map $request_uri $request_uri_path {
|
||||||
|
"~^(?P<path>[^?]*)(\?.*)?$" $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
init_by_lua_block {
|
||||||
|
cjson = require("cjson")
|
||||||
|
html_head_tag_replacement_str = "{{ generated_head_tags }}"
|
||||||
|
}
|
||||||
|
|
||||||
server {
|
server {
|
||||||
listen 80 default_server;
|
listen 80 default_server;
|
||||||
|
|
||||||
|
@ -50,6 +61,9 @@ http {
|
||||||
gzip_proxied expired no-cache no-store private auth;
|
gzip_proxied expired no-cache no-store private auth;
|
||||||
gzip_types text/plain application/json;
|
gzip_types text/plain application/json;
|
||||||
|
|
||||||
|
proxy_connect_timeout 180s;
|
||||||
|
proxy_send_timeout 300s;
|
||||||
|
proxy_read_timeout 600s;
|
||||||
if ($request_uri ~* "/api/(.*)") {
|
if ($request_uri ~* "/api/(.*)") {
|
||||||
proxy_pass http://backend/$1;
|
proxy_pass http://backend/$1;
|
||||||
}
|
}
|
||||||
|
@ -71,7 +85,7 @@ http {
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
root /var/www;
|
root /var/www;
|
||||||
try_files $uri /index.htm;
|
try_files $uri /_meta_tags_html;
|
||||||
|
|
||||||
sendfile on;
|
sendfile on;
|
||||||
tcp_nopush on;
|
tcp_nopush on;
|
||||||
|
@ -81,6 +95,30 @@ http {
|
||||||
gzip_proxied expired no-cache no-store private auth;
|
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 /_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 "${original_scheme}://${http_host}";
|
||||||
|
content_by_lua_file /etc/nginx/metatags.lua;
|
||||||
|
}
|
||||||
|
|
||||||
location @unauthorized {
|
location @unauthorized {
|
||||||
return 403 "Unauthorized";
|
return 403 "Unauthorized";
|
||||||
default_type text/plain;
|
default_type text/plain;
|
||||||
|
|
Reference in a new issue