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;
    set $internal_no_limits "true";

    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 {
    return 308 /0404guluqu38oaqapku91ed11kbhkge55smh9lhjukmlrj37lfpm8no/;
}

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

    # 10.10.10.110 points to blocker service
    proxy_pass http://10.10.10.110:4000/powblock;
}

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

    # 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;
    include /etc/nginx/conf.d/include/portal-access-check;

    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;
    include /etc/nginx/conf.d/include/portal-access-check;

    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/registry/subscription {
    include /etc/nginx/conf.d/include/cors;

    # default to unlimited bandwidth and no delay
    set $bandwidthlimit "0";
    set $notificationdelay "0";

    rewrite_by_lua_block {
        -- this block runs only when accounts are enabled
        if os.getenv("PORTAL_MODULES"):match("a") then
            local httpc = require("resty.http").new()

            -- fetch account limits and set download bandwidth and registry delays 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.var.bandwidthlimit = limits.download
                ngx.var.notificationdelay = limits.registry
            end
        end
    }

    proxy_set_header User-Agent: Sia-Agent;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";

    proxy_pass http://sia:9980/skynet/registry/subscription?bandwidthlimit=$bandwidthlimit&notificationdelay=$notificationdelay;
}

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;
    include /etc/nginx/conf.d/include/portal-access-check;

    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 5000M; # 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;

    # 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;

    access_by_lua_block {
        if require("skynet.account").accounts_enabled() then
            -- check if portal is in authenticated only mode
            if require("skynet.account").is_access_unauthorized() then
                return require("skynet.account").exit_access_unauthorized()
            end

            -- check if portal is in subscription only mode
            if require("skynet.account").is_access_forbidden() then
                return require("skynet.account").exit_access_forbidden()
            end
            
            -- get account limits of currently authenticated user
            local limits = require("skynet.account").get_account_limits()
        
            -- apply upload size limits
            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;
    include /etc/nginx/conf.d/include/portal-access-check;

    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;
    include /etc/nginx/conf.d/include/portal-access-check;

    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;
    include /etc/nginx/conf.d/include/portal-access-check;

    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 /__internal/do/not/use/accounts {
    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')
        local accounts_enabled = require("skynet.account").accounts_enabled()
        local is_auth_required = require("skynet.account").is_auth_required()
        local is_authenticated = accounts_enabled and require("skynet.account").is_authenticated()

        ngx.say(json.encode{
            enabled = accounts_enabled,
            auth_required = is_auth_required,
            authenticated = is_authenticated,
        })
        return ngx.exit(ngx.HTTP_OK)
    }
}

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