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
|
||||
COPY nginx.conf.docker ./nginx.conf
|
||||
COPY metatags.lua .
|
||||
|
||||
WORKDIR /var/www
|
||||
COPY --from=builder /opt/app/public/ .
|
||||
|
||||
|
||||
FROM nginx:alpine as release
|
||||
FROM openresty/openresty:alpine as release
|
||||
|
||||
RUN apk --no-cache add dumb-init
|
||||
COPY --from=approot / /
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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-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'/>
|
||||
{{ generated_head_tags }}
|
||||
</head>
|
||||
<body>
|
||||
<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;
|
||||
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,15 @@ http {
|
|||
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 {
|
||||
listen 80 default_server;
|
||||
|
||||
|
@ -50,6 +61,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;
|
||||
}
|
||||
|
@ -71,7 +85,7 @@ http {
|
|||
|
||||
location / {
|
||||
root /var/www;
|
||||
try_files $uri /index.htm;
|
||||
try_files $uri /_meta_tags_html;
|
||||
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
|
@ -81,6 +95,30 @@ 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 /_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 {
|
||||
return 403 "Unauthorized";
|
||||
default_type text/plain;
|
||||
|
|
Reference in a new issue