Looky — A UK Domain Tool

Moved away from /app/ which was a custom written php/html app, very messy. Brought everything under root now, with lots of new features. Slowly rolling out data querying. Right now you can search sales data from what we have collated so far, we'll be adding more as time goes on. Lots of focus on dropcatching, with new views of tags catching the most, which we plan to expand on later down the line to be more granular. Added a basic droplist view, for the next 7 days.
 
I only spotted and clicked the one in the middle box.

On mobile the output is 'interesting' in layout for those with a reponse ( all the status and date i fo is 1 char per line ) although trying again i get the endless no response on single and bulk now
 

Attachments

  • Screenshot_20250820_162621_Chrome.jpg
    Screenshot_20250820_162621_Chrome.jpg
    464.4 KB · Views: 2
  • Screenshot_20250820_162536_Chrome.jpg
    Screenshot_20250820_162536_Chrome.jpg
    191.2 KB · Views: 2
Thanks Rob,

It needs a lot of work.
Think it is the padding on all the divs causing the problem, each div has padding and it is just crushing your elements down, death via thousand cuts.

btw as you are using wordpress, I would use a custom rewrite of the url to hide the string - i.e spammers can't abuse the rdap={string} to extract data/waste your resources.

I got chatgpt to write this quickly:

PHP:
<?php
/**
 * Plugin Name: RDAP POST-only Intake
 * Description: Accepts RDAP lookups only via POST to /rdap/, stores server-side, then redirects back to /rdap/ with a clean URL.
 */

if (!defined('ABSPATH')) exit;

/**
 * Helpers
 */
function rdap_is_valid_domain($domain) {
    $domain = trim(strtolower(wp_unslash($domain)));
    if (function_exists('idn_to_ascii')) {
        $ascii = @idn_to_ascii($domain, IDNA_DEFAULT, INTL_IDNA_VARIANT_UTS46);
        if ($ascii !== false) $domain = $ascii;
    }
    return (bool) filter_var($domain, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME);
}

function rdap_set_cookie($name, $value, $seconds = 300) {
    $secure = is_ssl();
    setcookie($name, $value, [
        'expires'  => time() + $seconds,
        'path'     => '/',
        'secure'   => $secure,
        'httponly' => true,
        'samesite' => 'Lax',
    ]);
}

/**
 * Block leaking via query string or extra path on /rdap/
 * - Strip any query params by redirecting to /rdap/
 * - Let WP naturally 404 /rdap/<anything> (no child pages)
 */
add_action('template_redirect', function () {
    if (!is_page('rdap')) return;

    // If someone tries GET with any params, strip them.
    if ($_SERVER['REQUEST_METHOD'] === 'GET' && !empty($_GET)) {
        wp_redirect(home_url('/rdap/'), 301);
        exit;
    }

    // POST intake: accept only from our form
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        // Basic CSRF check
        if (!isset($_POST['rdap_nonce']) || !wp_verify_nonce($_POST['rdap_nonce'], 'rdap_intake')) {
            wp_die(esc_html__('Security check failed.', 'rdap'), 400);
        }

        $incoming = isset($_POST['rdap']) ? sanitize_text_field(wp_unslash($_POST['rdap'])) : '';
        if (!$incoming || !rdap_is_valid_domain($incoming)) {
            wp_die(esc_html__('Invalid domain.', 'rdap'), 400);
        }

        // Rate-limit (simple): 10 requests per 5 minutes per IP
        $ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
        $rl_key = 'rdap_rl_' . md5($ip);
        $count = (int) get_transient($rl_key);
        if ($count > 50) {
            wp_die(esc_html__('Too many requests. Please try again later.', 'rdap'), 429);
        }
        set_transient($rl_key, $count + 1, 5 * MINUTE_IN_SECONDS);

        // Store server-side only (5 minutes)
        $token = wp_generate_uuid4();
        set_transient('rdap_' . $token, $incoming, 5 * MINUTE_IN_SECONDS);
        rdap_set_cookie('rdap_token', $token, 5 * MINUTE_IN_SECONDS);

        // Redirect back to pristine /rdap/ (no data in URL/history)
        wp_redirect(home_url('/rdap/'), 303);
        exit;
    }
}, 0);

/**
 * Public helper for the /rdap/ page template to read (and optionally consume) the stored value.
 */
function rdap_get_and_forget_value() {
    if (empty($_COOKIE['rdap_token'])) return null;
    $token = sanitize_text_field(wp_unslash($_COOKIE['rdap_token']));
    if (!$token) return null;

    $key = 'rdap_' . $token;
    $val = get_transient($key);
    if ($val !== false) {
        delete_transient($key); // one-shot read to minimize exposure
        return $val;
    }
    return null;
}

You also have other custom url rewrites which could work, would shorten the url to: /rdap/url.co.uk

PHP:
// 1) Add a rewrite tag + pretty permalink like /rdap/<string>
add_action('init', function () {
    add_rewrite_tag('%rdap%', '([^/]+)');
    add_rewrite_rule('^rdap/([^/]+)/?$', 'index.php?pagename=rdap&rdap=$matches[1]', 'top');
}, 1);

// 2) Ensure 'rdap' is a public query var
add_filter('query_vars', function ($vars) {
    $vars[] = 'rdap';
    return $vars;
});
 
  • Love
Reactions: ben
Think it is the padding on all the divs causing the problem, each div has padding and it is just crushing your elements down, death via thousand cuts.

btw as you are using wordpress, I would use a custom rewrite of the url to hide the string - i.e spammers can't abuse the rdap={string} to extract data/waste your resources.

I got chatgpt to write this quickly:

PHP:
<?php
/**
 * Plugin Name: RDAP POST-only Intake
 * Description: Accepts RDAP lookups only via POST to /rdap/, stores server-side, then redirects back to /rdap/ with a clean URL.
 */

if (!defined('ABSPATH')) exit;

/**
 * Helpers
 */
function rdap_is_valid_domain($domain) {
    $domain = trim(strtolower(wp_unslash($domain)));
    if (function_exists('idn_to_ascii')) {
        $ascii = @idn_to_ascii($domain, IDNA_DEFAULT, INTL_IDNA_VARIANT_UTS46);
        if ($ascii !== false) $domain = $ascii;
    }
    return (bool) filter_var($domain, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME);
}

function rdap_set_cookie($name, $value, $seconds = 300) {
    $secure = is_ssl();
    setcookie($name, $value, [
        'expires'  => time() + $seconds,
        'path'     => '/',
        'secure'   => $secure,
        'httponly' => true,
        'samesite' => 'Lax',
    ]);
}

/**
 * Block leaking via query string or extra path on /rdap/
 * - Strip any query params by redirecting to /rdap/
 * - Let WP naturally 404 /rdap/<anything> (no child pages)
 */
add_action('template_redirect', function () {
    if (!is_page('rdap')) return;

    // If someone tries GET with any params, strip them.
    if ($_SERVER['REQUEST_METHOD'] === 'GET' && !empty($_GET)) {
        wp_redirect(home_url('/rdap/'), 301);
        exit;
    }

    // POST intake: accept only from our form
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        // Basic CSRF check
        if (!isset($_POST['rdap_nonce']) || !wp_verify_nonce($_POST['rdap_nonce'], 'rdap_intake')) {
            wp_die(esc_html__('Security check failed.', 'rdap'), 400);
        }

        $incoming = isset($_POST['rdap']) ? sanitize_text_field(wp_unslash($_POST['rdap'])) : '';
        if (!$incoming || !rdap_is_valid_domain($incoming)) {
            wp_die(esc_html__('Invalid domain.', 'rdap'), 400);
        }

        // Rate-limit (simple): 10 requests per 5 minutes per IP
        $ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
        $rl_key = 'rdap_rl_' . md5($ip);
        $count = (int) get_transient($rl_key);
        if ($count > 50) {
            wp_die(esc_html__('Too many requests. Please try again later.', 'rdap'), 429);
        }
        set_transient($rl_key, $count + 1, 5 * MINUTE_IN_SECONDS);

        // Store server-side only (5 minutes)
        $token = wp_generate_uuid4();
        set_transient('rdap_' . $token, $incoming, 5 * MINUTE_IN_SECONDS);
        rdap_set_cookie('rdap_token', $token, 5 * MINUTE_IN_SECONDS);

        // Redirect back to pristine /rdap/ (no data in URL/history)
        wp_redirect(home_url('/rdap/'), 303);
        exit;
    }
}, 0);

/**
 * Public helper for the /rdap/ page template to read (and optionally consume) the stored value.
 */
function rdap_get_and_forget_value() {
    if (empty($_COOKIE['rdap_token'])) return null;
    $token = sanitize_text_field(wp_unslash($_COOKIE['rdap_token']));
    if (!$token) return null;

    $key = 'rdap_' . $token;
    $val = get_transient($key);
    if ($val !== false) {
        delete_transient($key); // one-shot read to minimize exposure
        return $val;
    }
    return null;
}

You also have other custom url rewrites which could work, would shorten the url to: /rdap/url.co.uk

PHP:
// 1) Add a rewrite tag + pretty permalink like /rdap/<string>
add_action('init', function () {
    add_rewrite_tag('%rdap%', '([^/]+)');
    add_rewrite_rule('^rdap/([^/]+)/?$', 'index.php?pagename=rdap&rdap=$matches[1]', 'top');
}, 1);

// 2) Ensure 'rdap' is a public query var
add_filter('query_vars', function ($vars) {
    $vars[] = 'rdap';
    return $vars;
});
Thanks for that, yes it is definitely padding, but the whole logic is skewed atm as I am also in the middle of adding a custom domain registration process with passwordless login. Ambitious, I know lol.

The RDAP query's are in the URL because I wanted people to be able to land on it like I do, via Alfred or something (on mac) and have it load up the results right away. As the queries are client sided, there isn't an issue with it hoovering up server sided requests, and it is rate limited (or should be) to ensure they can't spam it. The data extraction is a non-issue, as the information is freely available.

The new front end domain sales form however is a little bit different, but it does use lots of server sided caching and limiting, and does not use URL query forming in order to deter bots and such like from doing as you say and extracting data, also behind Cloudflare which should help somewhat.
 
Strangely if I change my screensize to be smaller XbyY pixels, it fits a lot beter, so poss some CSS/viewport issue
 
  • Cheers
Reactions: ben
Thanks for that, yes it is definitely padding, but the whole logic is skewed atm as I am also in the middle of adding a custom domain registration process with passwordless login. Ambitious, I know lol.

The RDAP query's are in the URL because I wanted people to be able to land on it like I do, via Alfred or something (on mac) and have it load up the results right away. As the queries are client sided, there isn't an issue with it hoovering up server sided requests, and it is rate limited (or should be) to ensure they can't spam it. The data extraction is a non-issue, as the information is freely available.

The new front end domain sales form however is a little bit different, but it does use lots of server sided caching and limiting, and does not use URL query forming in order to deter bots and such like from doing as you say and extracting data, also behind Cloudflare which should help somewhat.
If that is the case, I think the custom rewrite page rules could work better, you can have it as just: /rdap/url.co.uk which looks a bit cleaner - the second part of the code I sent is related to that. I use it for a creating pages per a query on a site of mine. It effectively makes unlimited pages, the url structure is just:

/{query}-keyword

and then I just index the pages on google with a tool I have created https://brandify.co.uk or there is others like speedyindex too.
 
Back
Top