listen 443 ssl http2;
listen [::]:443 ssl http2;

include /etc/nginx/conf.d/include/ssl-settings;
include /etc/nginx/conf.d/include/init-optional-variables;

# ddos protection: closing slow connections
client_body_timeout 1h;
client_header_timeout 1h;
send_timeout 1h;

proxy_connect_timeout 1h;
proxy_read_timeout 1h;
proxy_send_timeout 1h;

# Increase the body buffer size, to ensure the internal POSTs can always
# parse the full POST contents into memory.
client_body_buffer_size 128k;
client_max_body_size 128k;

# legacy endpoint rewrite
rewrite ^/portals /skynet/portals permanent;
rewrite ^/stats /skynet/stats permanent;
rewrite ^/skynet/blacklist /skynet/blocklist permanent;

location / {
    include /etc/nginx/conf.d/include/cors;

    set $skylink "0404dsjvti046fsua4ktor9grrpe76erq9jot9cvopbhsvsu76r4r30";
    set $path $uri;

    include /etc/nginx/conf.d/include/location-skylink;

    proxy_intercept_errors on;
    error_page 400 404 490 500 502 503 504 =200 @fallback;
}

location @fallback {
    proxy_pass http://website:9000;
}

location /docs {
    proxy_pass https://skynetlabs.github.io/skynet-docs;
}

location /skynet/blocklist {
    include /etc/nginx/conf.d/include/cors;

    proxy_cache skynet;
    proxy_cache_valid any 1m; # cache blocklist for 1 minute
    proxy_set_header User-Agent: Sia-Agent;
    proxy_pass http://sia:9980/skynet/blocklist;
}

location /skynet/portals {
    include /etc/nginx/conf.d/include/cors;

    proxy_cache skynet;
    proxy_cache_valid any 1m; # cache portals for 1 minute
    proxy_set_header User-Agent: Sia-Agent;
    proxy_pass http://sia:9980/skynet/portals;
}

location /skynet/stats {
    include /etc/nginx/conf.d/include/cors;

    proxy_cache skynet;
    proxy_cache_valid any 1m; # cache stats for 1 minute
    proxy_set_header User-Agent: Sia-Agent;
    proxy_read_timeout 5m; # extend the read timeout
    proxy_pass http://sia:9980/skynet/stats;
}

# Define path for server load endpoint
location /serverload {
    # Define root directory in the nginx container to load file from
    root /usr/local/share;

    # including this because of peer pressure from the other routes 
    include /etc/nginx/conf.d/include/cors;

    # tell nginx to expect json
    default_type 'application/json';

    # Allow for /serverload to load /serverload.json file
    try_files $uri $uri.json =404;
}

location /skynet/health {
    include /etc/nginx/conf.d/include/cors;

    proxy_cache skynet;
    proxy_cache_key $request_uri; # use whole request uri (uri + args) as cache key
    proxy_cache_valid any 1m; # cache responses for 1 minute
    proxy_set_header User-Agent: Sia-Agent;
    proxy_read_timeout 5m; # extend the read timeout
    proxy_pass http://sia:9980;
}

location /health-check {
    include /etc/nginx/conf.d/include/cors;

    access_log off; # do not log traffic to health-check endpoint

    proxy_pass http://10.10.10.60:3100; # hardcoded ip because health-check waits for nginx
}

location /abuse/ {
    if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Allow-Origin' 'https://0404guluqu38oaqapku91ed11kbhkge55smh9lhjukmlrj37lfpm8no.siasky.net';

        add_header 'Access-Control-Allow-Credentials' 'true';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';

        # pre-flight info is valid for 20 days
        add_header 'Access-Control-Max-Age' 1728000;
        add_header 'Content-Type' 'text/plain charset=UTF-8';
        add_header 'Content-Length' 0;
        return 204;
    }

    proxy_pass http://10.10.10.102:4000/;
}

location /report-abuse {
    # TODO: do a proxy_pass
    return https://0404guluqu38oaqapku91ed11kbhkge55smh9lhjukmlrj37lfpm8no.siasky.net;
}

location /hns {
    # match the request_uri and extract the hns domain and anything that is passed in the uri after it
    # example: /hns/something/foo/bar matches:
    # > hns_domain: something
    # > path: /foo/bar/
    set_by_lua_block $hns_domain { return string.match(ngx.var.uri, "/hns/([^/?]+)") }
    set_by_lua_block $path { return string.match(ngx.var.uri, "/hns/[^/?]+(.*)") }

    proxy_set_header Host $host;
    include /etc/nginx/conf.d/include/location-hns;
}

location /hnsres {
    include /etc/nginx/conf.d/include/cors;

    proxy_pass http://handshake-api:3100;
}

location /skynet/registry {
    include /etc/nginx/conf.d/include/location-skynet-registry;
}

location /skynet/restore {
    include /etc/nginx/conf.d/include/cors;
    include /etc/nginx/conf.d/include/sia-auth;

    client_max_body_size 5M;

    # increase request timeouts
    proxy_read_timeout 600;
    proxy_send_timeout 600;

    proxy_request_buffering off; # stream uploaded files through the proxy as it comes in
    proxy_set_header Expect $http_expect;
    proxy_set_header User-Agent: Sia-Agent;

    # proxy this call to siad endpoint (make sure the ip is correct)
    proxy_pass http://sia:9980;
}

location /skynet/skyfile {
    include /etc/nginx/conf.d/include/cors;
    include /etc/nginx/conf.d/include/sia-auth;
    include /etc/nginx/conf.d/include/track-upload;
    include /etc/nginx/conf.d/include/generate-siapath;

    limit_req zone=uploads_by_ip burst=10 nodelay;
    limit_req zone=uploads_by_ip_throttled;

    limit_conn upload_conn 5;
    limit_conn upload_conn_rl 1;

    client_max_body_size 1000M; # make sure to limit the size of upload to a sane value

    # increase request timeouts
    proxy_read_timeout 600;
    proxy_send_timeout 600;

    proxy_request_buffering off; # stream uploaded files through the proxy as it comes in
    proxy_set_header Expect $http_expect;
    proxy_set_header User-Agent: Sia-Agent;

    # access_by_lua_block {
    # 	-- this block runs only when accounts are enabled
    # 	if os.getenv("ACCOUNTS_ENABLED") ~= "true" then return end

    # 	ngx.var.upload_limit_rate = 5 * 1024 * 1024
    # 	local res = ngx.location.capture("/accounts/user", { copy_all_vars = true })
    # 	if res.status == ngx.HTTP_OK then
    # 		local json = require('cjson')
    # 		local user = json.decode(res.body)
    # 		ngx.var.upload_limit_rate = ngx.var.upload_limit_rate * (user.tier + 1)
    # 	end
    # }

    # proxy this call to siad endpoint (make sure the ip is correct)
    proxy_pass http://sia:9980/skynet/skyfile/$dir1/$dir2/$dir3$is_args$args;
}

# endpoint implementing resumable file uploads open protocol https://tus.io
location /skynet/tus {
    include /etc/nginx/conf.d/include/cors-headers; # include cors headers but do not overwrite OPTIONS response
    include /etc/nginx/conf.d/include/track-upload;

    limit_req zone=uploads_by_ip burst=10 nodelay;
    limit_req zone=uploads_by_ip_throttled;

    limit_conn upload_conn 5;
    limit_conn upload_conn_rl 1;

    # TUS chunks size is 40M + leaving 10M of breathing room
    client_max_body_size 50M;

    # Those timeouts need to be elevated since skyd can stall reading
    # data for a while when overloaded which would terminate connection
    client_body_timeout 1h;
    proxy_send_timeout  1h;

    # Add X-Forwarded-* headers
    proxy_set_header X-Forwarded-Host  $host;
    proxy_set_header X-Forwarded-Proto $scheme;

    # rewrite proxy request to use correct host uri from env variable (required to return correct location header)
    set_by_lua $SKYNET_SERVER_API 'return os.getenv("SKYNET_SERVER_API")';
    proxy_redirect $scheme://$host $SKYNET_SERVER_API;

    # proxy /skynet/tus requests to siad endpoint with all arguments
    proxy_pass http://sia:9980;

    # set max upload size dynamically based on account limits
    rewrite_by_lua_block {
        -- set default limit value to 1 GB
        ngx.req.set_header("SkynetMaxUploadSize", 1073741824)

        -- this block runs only when accounts are enabled
        if os.getenv("ACCOUNTS_ENABLED") ~= "true" then return end

        local httpc = require("resty.http").new()

        -- fetch account limits and set max upload size accordingly
        local res, err = httpc:request_uri("http://10.10.10.70:3000/user/limits", {
            headers = { ["Cookie"] = "skynet-jwt=" .. ngx.var.skynet_jwt }
        })

        -- fail gracefully in case /user/limits failed
        if err or (res and res.status ~= ngx.HTTP_OK) then
            ngx.log(ngx.ERR, "Failed accounts service request /user/limits: ", err or ("[HTTP " .. res.status .. "] " .. res.body))
        elseif res and res.status == ngx.HTTP_OK then
            local json = require('cjson')
            local limits = json.decode(res.body)
            ngx.req.set_header("SkynetMaxUploadSize", limits.maxUploadSize)
        end
    }

    # extract skylink from base64 encoded upload metadata and assign to a proper header
    header_filter_by_lua_block {
        ngx.header["Skynet-Portal-Api"] = os.getenv("SKYNET_PORTAL_API")
        ngx.header["Skynet-Server-Api"] = os.getenv("SKYNET_SERVER_API")

        if ngx.header["Upload-Metadata"] then
            local encodedSkylink = string.match(ngx.header["Upload-Metadata"], "Skylink ([^,?]+)")

            if encodedSkylink then
                ngx.header["Skynet-Skylink"] = ngx.decode_base64(encodedSkylink)
            end
        end
    }
}

location /skynet/pin {
    include /etc/nginx/conf.d/include/cors;
    include /etc/nginx/conf.d/include/sia-auth;
    include /etc/nginx/conf.d/include/track-upload;
    include /etc/nginx/conf.d/include/generate-siapath;

    limit_req zone=uploads_by_ip burst=10 nodelay;
    limit_req zone=uploads_by_ip_throttled;

    limit_conn upload_conn 5;
    limit_conn upload_conn_rl 1;

    proxy_set_header User-Agent: Sia-Agent;
    proxy_pass http://sia:9980$uri?siapath=$dir1/$dir2/$dir3&$args;
}

location /skynet/metadata {
    include /etc/nginx/conf.d/include/cors;

    header_filter_by_lua_block {
        ngx.header["Skynet-Portal-Api"] = os.getenv("SKYNET_PORTAL_API")
        ngx.header["Skynet-Server-Api"] = os.getenv("SKYNET_SERVER_API")
    }

    proxy_set_header User-Agent: Sia-Agent;
    proxy_pass http://sia:9980;
}

location /skynet/resolve {
    include /etc/nginx/conf.d/include/cors;

    header_filter_by_lua_block {
        ngx.header["Skynet-Portal-Api"] = os.getenv("SKYNET_PORTAL_API")
        ngx.header["Skynet-Server-Api"] = os.getenv("SKYNET_SERVER_API")
    }

    proxy_set_header User-Agent: Sia-Agent;
    proxy_pass http://sia:9980;
}

location ~ "^/(([a-zA-Z0-9-_]{46}|[a-z0-9]{55})(/.*)?)$" {
    set $skylink $2;
    set $path $3;

    include /etc/nginx/conf.d/include/location-skylink;
}

location ~ "^/file/(([a-zA-Z0-9-_]{46}|[a-z0-9]{55})(/.*)?)$" {
    set $skylink $2;
    set $path $3;
    set $args attachment=true&$args;
    #set $is_args ?;

    include /etc/nginx/conf.d/include/location-skylink;
}

location @purge {
    allow 10.0.0.0/8;
    allow 127.0.0.1/32;
    allow 172.16.0.0/12;
    allow 192.168.0.0/16;
    deny all;

    set $lua_purge_path "/data/nginx/cache/";
    content_by_lua_file /etc/nginx/conf.d/scripts/purge-multi.lua;
}

location /__internal/do/not/use/authenticated {
    include /etc/nginx/conf.d/include/cors;

    charset utf-8;
    charset_types application/json;
    default_type application/json;

    content_by_lua_block {
        local json = require('cjson')

        -- this block runs only when accounts are enabled
        if os.getenv("ACCOUNTS_ENABLED") ~= "true" then
            ngx.say(json.encode{authenticated = false})
            return ngx.exit(ngx.HTTP_OK)
        end

        local httpc = require("resty.http").new()

        -- 10.10.10.70 points to accounts service (alias not available when using resty-http)
        local res, err = httpc:request_uri("http://10.10.10.70:3000/user", {
            headers = { ["Cookie"] = "skynet-jwt=" .. ngx.var.skynet_jwt }
        })

        -- endpoint /user should return HTTP_OK for authenticated and HTTP_UNAUTHORIZED for not authenticated
        if res and (res.status == ngx.HTTP_OK or res.status == ngx.HTTP_UNAUTHORIZED) then
            ngx.say(json.encode{authenticated = res.status == ngx.HTTP_OK})
            return ngx.exit(ngx.HTTP_OK)
        else
            ngx.log(ngx.ERR, "Failed accounts service request /user: ", err or ("[HTTP " .. res.status .. "] " .. res.body))
            ngx.say(json.encode{authenticated = false})
            return ngx.exit(ngx.HTTP_OK)
        end
    }
}

include /etc/nginx/conf.d/server-override/*;