/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2026 Olaf Wintermann. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "service.h"

#include "../../util/pblock.h"
#include "../../util/util.h"
#include "cx/string.h"

#define SIMPLE_COOKIE_PAGE_TEMPLATE \
        "<!DOCTYPE html>\n" \
        "<html>\n" \
        "  <head>\n" \
        "    <title>Anti Bot Challenge</title>\n" \
        "    <script>\n" \
        "    fuckcounter=0;\n" \
        "    addEventListener(\"mousemove\", (event) => {\n" \
        "        fuckcounter++;\n" \
        "    })\n" \
        "    setTimeout(function() {\n" \
        "	const b = document.getElementById('fuckai');\n" \
        "	b.style.display = 'initial';\n" \
        "        b.addEventListener('click', function() {\n" \
        "           if (fuckcounter < 50) return;\n" \
        "           document.cookie = '%s=%s; path=/';\n" \
        "           window.location.reload();\n" \
        "        })\n" \
        "    }, 1000);\n" \
        "    </script>\n" \
        "  </head>\n" \
        "  <body>\n" \
        "    <h1>Simple Anti Bot Check</h1>\n" \
        "    <p>Please click the button below to continue.</p>\n" \
        "    <button style=\"display: none\" id=\"fuckai\" type=\"button\">I am a Human</button>\n" \
        "  </body>\n" \
        "</html>"

static cxstring gen_simple_cookie_page(pool_handle_t *pool, const char *cookie_name, const char *cookie_value) {
    size_t cname_len = strlen(cookie_name);
    size_t cvalue_len = strlen(cookie_value);
    size_t template_len = sizeof(SIMPLE_COOKIE_PAGE_TEMPLATE) - 1;
    
    size_t len = template_len + cname_len + cvalue_len;
    char *buffer = pool_malloc(pool, len + 1);
    if(!buffer) {
        return (cxstring){ NULL, 0 };
    }
    
    len = snprintf(buffer, len + 1, SIMPLE_COOKIE_PAGE_TEMPLATE, cookie_name, cookie_value);
    return (cxstring){ buffer, len };
}



// Sends a simple bot challenge page, if the request is marked with is-bot.
// The challenge page sets the specified cookie via javascript.
//
// Args:
//    cookie: cookie name
//    value: cookie value (optional)
int sab_simple_service(pblock *pb, Session *sn, Request *rq) {
    char *cookie_name = pblock_findval("cookie", pb);
    char *cookie_value = pblock_findval("value", pb);
    if(!cookie_name) {
        log_ereport(LOG_MISCONFIG, "sab-simple-service: no cookie specified");
        return REQ_ABORTED;
    }
    
    char *is_bot = pblock_findval("is-bot", rq->vars);
    if(!is_bot) {
        return REQ_NOACTION;
    }
    
    
    // send the simple challenge page, that sets the cookie with javascript
    
    if(!cookie_value) {
        cookie_value = "sab-1";
    }
    
    cxstring response = gen_simple_cookie_page(sn->pool, cookie_name, cookie_value);
    
    pblock_removekey(pb_key_content_type, rq->srvhdrs);
    pblock_kvinsert(pb_key_content_type, "text/html; charset=utf-8", 24, rq->srvhdrs);
    pblock_nninsert("content-length", (int)response.length, rq->srvhdrs);
    protocol_status(sn, rq, 200, NULL);
    http_start_response(sn, rq);

    net_write(sn->csd, response.ptr, response.length);
    
    return REQ_PROCEED;
}
