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;
rewrite ^/docs(?:/(.*))?$ https://sdk.skynetlabs.com/$1 permanent;

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

    proxy_pass http://website:9000;
}

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

    add_header X-Proxy-Cache $upstream_cache_status;

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

    add_header X-Proxy-Cache $upstream_cache_status;

    proxy_cache skynet;
    proxy_cache_valid 200 204 15m; # cache portal blocklist for 15 minutes

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

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

    add_header X-Proxy-Cache $upstream_cache_status;

    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;

    add_header X-Proxy-Cache $upstream_cache_status;

    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;

    add_header X-Proxy-Cache $upstream_cache_status;

    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 {
        local skynet_account = require("skynet.account")

        if skynet_account.accounts_enabled() then
            -- check if portal is in authenticated only mode
            if skynet_account.is_access_unauthorized() then
                return skynet_account.exit_access_unauthorized()
            end

            -- check if portal is in subscription only mode
            if skynet_account.is_access_forbidden() then
                return skynet_account.exit_access_forbidden()
            end

            -- get account limits of currently authenticated user
            local limits = skynet_account.get_account_limits()

            -- apply bandwidth limit and notification delay
            ngx.var.bandwidthlimit = limits.download
            ngx.var.notificationdelay = limits.registry
        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/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;

    log_by_lua_block {
        local skynet_account = require("skynet.account")
        local skynet_modules = require("skynet.modules")
        local skynet_scanner = require("skynet.scanner")
        local skynet_tracker = require("skynet.tracker")

        if skynet_modules.is_enabled("a") then
            skynet_tracker.track_upload(
                ngx.header["Skynet-Skylink"],
                ngx.status,
                skynet_account.get_auth_headers(),
                ngx.var.remote_addr
            )
        end

        if skynet_modules.is_enabled("s") then
            skynet_scanner.scan_skylink(ngx.header["Skynet-Skylink"])
        end
    }
}

# 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

    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;

    # Do not limit body size in nginx, skyd will reject early on too large upload
    client_max_body_size 0;

    # 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)
    proxy_redirect $scheme://$host $scheme://$skynet_server_domain;

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

    access_by_lua_block {
        local skynet_account = require("skynet.account")

        if skynet_account.accounts_enabled() then
            -- check if portal is in authenticated only mode
            if skynet_account.is_access_unauthorized() then
                return skynet_account.exit_access_unauthorized()
            end

            -- check if portal is in subscription only mode
            if skynet_account.is_access_forbidden() then
                return skynet_account.exit_access_forbidden()
            end

            -- get account limits of currently authenticated user
            local limits = 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"] = ngx.var.scheme .. "://" .. ngx.var.skynet_portal_domain
        ngx.header["Skynet-Server-Api"] = ngx.var.scheme .. "://" .. ngx.var.skynet_server_domain

        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
    }

    log_by_lua_block {
        local skynet_account = require("skynet.account")
        local skynet_modules = require("skynet.modules")
        local skynet_scanner = require("skynet.scanner")
        local skynet_tracker = require("skynet.tracker")

        if skynet_modules.is_enabled("a") then
            skynet_tracker.track_upload(
                ngx.header["Skynet-Skylink"],
                ngx.status,
                skynet_account.get_auth_headers(),
                ngx.var.remote_addr
            )
        end

        if skynet_modules.is_enabled("s") then
            skynet_scanner.scan_skylink(ngx.header["Skynet-Skylink"])
        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/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;

    log_by_lua_block {
        local skynet_account = require("skynet.account")
        local skynet_modules = require("skynet.modules")
        local skynet_scanner = require("skynet.scanner")
        local skynet_tracker = require("skynet.tracker")

        if skynet_modules.is_enabled("a") then
            skynet_tracker.track_upload(
                ngx.header["Skynet-Skylink"],
                ngx.status,
                skynet_account.get_auth_headers(),
                ngx.var.remote_addr
            )
        end

        if skynet_modules.is_enabled("s") then
            skynet_scanner.scan_skylink(ngx.header["Skynet-Skylink"])
        end
    }
}

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"] = ngx.var.scheme .. "://" .. ngx.var.skynet_portal_domain
        ngx.header["Skynet-Server-Api"] = ngx.var.scheme .. "://" .. ngx.var.skynet_server_domain
    }

    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"] = ngx.var.scheme .. "://" .. ngx.var.skynet_portal_domain
        ngx.header["Skynet-Server-Api"] = ngx.var.scheme .. "://" .. ngx.var.skynet_server_domain
    }

    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 /skynet/trustless/basesector {
    include /etc/nginx/conf.d/include/cors;

    limit_conn downloads_by_ip 100; # ddos protection: max 100 downloads at a time

    # default download rate to unlimited
    set $limit_rate 0;

    access_by_lua_block {
        local skynet_account = require("skynet.account")

        if skynet_account.accounts_enabled() then
            -- check if portal is in authenticated only mode
            if skynet_account.is_access_unauthorized() then
                return skynet_account.exit_access_unauthorized()
            end

            -- check if portal is in subscription only mode
            if skynet_account.is_access_forbidden() then
                return skynet_account.exit_access_forbidden()
            end

            -- get account limits of currently authenticated user
            local limits = skynet_account.get_account_limits()

            -- apply download speed limit
            ngx.var.limit_rate = limits.download
        end
    }

    limit_rate_after 512k;
    limit_rate $limit_rate;

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

    log_by_lua_block {
        local skynet_account = require("skynet.account")
        local skynet_modules = require("skynet.modules")
        local skynet_scanner = require("skynet.scanner")
        local skynet_tracker = require("skynet.tracker")

        if skynet_modules.is_enabled("a") then
            skynet_tracker.track_download(ngx.header["Skynet-Skylink"], ngx.status, skynet_account.get_auth_headers(), ngx.var.body_bytes_sent)
        end

        if skynet_modules.is_enabled("s") then
            skynet_scanner.scan_skylink(ngx.header["Skynet-Skylink"])
        end
    }
}

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 skynet_account = require("skynet.account")

        local accounts_enabled = skynet_account.accounts_enabled()
        local is_auth_required = skynet_account.is_auth_required()
        local is_subscription_required = skynet_account.is_subscription_required()
        local is_authenticated = skynet_account.is_authenticated()
        local has_subscription = skynet_account.has_subscription()

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

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