Skip to content

Instantly share code, notes, and snippets.

@Lissy93
Last active October 19, 2024 19:56
Show Gist options
  • Save Lissy93/e33a6b2218f57c51127bbbe7046f5c83 to your computer and use it in GitHub Desktop.
Save Lissy93/e33a6b2218f57c51127bbbe7046f5c83 to your computer and use it in GitHub Desktop.

Revisions

  1. Lissy93 revised this gist Oct 19, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion usage-docs.md
    Original file line number Diff line number Diff line change
    @@ -70,7 +70,7 @@ server.listen(3000, () => {


    <details>
    <summary><b>Usage Example 2: As an API</b></summary>
    <summary><b>Usage Example 3: As a CLI</b></summary>



  2. Lissy93 revised this gist Oct 19, 2024. 1 changed file with 4 additions and 0 deletions.
    4 changes: 4 additions & 0 deletions _whois-lookup.js
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,7 @@
    /**
    * A quick and simple JS WHOIS lookup to return JSON
    * Docs and usage instructions are below...
    **/
    import * as whois from 'whois';
    import * as changeCase from 'change-case';
    import { decodeEntity } from 'html-entities';
  3. Lissy93 renamed this gist Oct 19, 2024. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  4. Lissy93 renamed this gist Oct 19, 2024. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  5. Lissy93 renamed this gist Oct 19, 2024. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  6. Lissy93 revised this gist Oct 19, 2024. 2 changed files with 0 additions and 0 deletions.
    File renamed without changes.
    File renamed without changes.
  7. Lissy93 renamed this gist Oct 19, 2024. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  8. Lissy93 created this gist Oct 19, 2024.
    147 changes: 147 additions & 0 deletions readme.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,147 @@
    > A really quick script to run a whois lookup, and format the response into JSON.<br>
    > Inspired by [whois-json](https://github.com/mikemaccana/whois-json) by @mikemaccana.

    ## Usage

    **Prerequisites**
    1. Paste the above code in a file, like `whois-lookup.js`
    2. And then run `npm i html-entities change-case whois`

    ---

    <details open>
    <summary><b>Usage Example 1: In your code</b></summary>


    ```javascript
    import { getWhoisData } from './whois-lookup.js';

    getWhoisData('google.com').then(data => {
    console.log(data); // Outputs a JSON WHOIS response
    }).catch(error => {
    console.error(error);
    });
    ```

    </details>

    ---

    <details>
    <summary><b>Usage Example 2: As an API</b></summary>


    1. Create a file named `server.js`, and paste the code below into it
    2. Run `node server`
    3. Open `localhost:3000/duck.com` to return the WHOIS JSON

    ```javascript
    import { getWhoisData } from './whois-lookup.js';
    import http from 'http';

    const server = http.createServer((req, res) => {
    const urlParts = req.url.split('/');
    const domain = urlParts[1];

    if (domain) {
    getWhoisData(domain).then(data => {
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify(data, null, 2));
    }).catch(error => {
    res.writeHead(500, { 'Content-Type': 'text/plain' });
    res.end(`Error: ${error.message}`);
    });
    } else {
    res.writeHead(400, { 'Content-Type': 'text/plain' });
    res.end('Please specify a domain in the URL. For example: /example.com');
    }
    });

    server.listen(3000, () => {
    console.log('Server running at http://localhost:3000/');
    });

    ```

    </details>

    ---


    <details>
    <summary><b>Usage Example 2: As an API</b></summary>



    1. Create a file named `whois-cli.js`, and paste the code below into it
    2. In your terminal, run `node ./whois-cli.js --url='google.com'` to get WHOIS JSON


    ```javascript
    import { getWhoisData } from './whois-lookup.js';

    const args = process.argv.slice(2);
    const domainArg = args.find(arg => arg.startsWith('--url='));

    if (domainArg) {
    const domain = domainArg.split('=')[1];
    getWhoisData(domain).then(data => {
    console.log(data);
    }).catch(error => {
    console.error('Error:', error);
    });
    } else {
    console.log('Usage: node ./example.js --url="example.com"');
    }
    ```

    </details>

    ---

    <details>
    <summary><b>Example Output (JSON)</b></summary>

    ```json
    {
    "domainName": "google.com",
    "registryDomainId": "2138514_DOMAIN_COM-VRSN",
    "registrarWhoisServer": "whois.markmonitor.com",
    "registrarUrl": "http://www.markmonitor.com",
    "updatedDate": "2024-08-02T02:17:33+0000",
    "creationDate": "1997-09-15T07:00:00+0000",
    "registrarRegistrationExpirationDate": "2028-09-13T07:00:00+0000",
    "registrar": "MarkMonitor, Inc.",
    "registrarIanaId": "292",
    "registrarAbuseContactEmail": "[email protected]",
    "registrarAbuseContactPhone": "+1.2086851750",
    "domainStatus": "clientUpdateProhibited (https://www.icann.org/epp#clientUpdateProhibited) clientTransferProhibited (https://www.icann.org/epp#clientTransferProhibited) clientDeleteProhibited (https://www.icann.org/epp#clientDeleteProhibited) serverUpdateProhibited (https://www.icann.org/epp#serverUpdateProhibited) serverTransferProhibited (https://www.icann.org/epp#serverTransferProhibited) serverDeleteProhibited (https://www.icann.org/epp#serverDeleteProhibited)",
    "registrantOrganization": "Google LLC",
    "registrantStateProvince": "CA",
    "registrantCountry": "US",
    "registrantEmail": "Select Request Email Form at https://domains.markmonitor.com/whois/google.com",
    "adminOrganization": "Google LLC",
    "adminStateProvince": "CA",
    "adminCountry": "US",
    "adminEmail": "Select Request Email Form at https://domains.markmonitor.com/whois/google.com",
    "techOrganization": "Google LLC",
    "techStateProvince": "CA",
    "techCountry": "US",
    "techEmail": "Select Request Email Form at https://domains.markmonitor.com/whois/google.com",
    "nameServer": "ns4.google.com ns3.google.com ns2.google.com ns1.google.com",
    "dnssec": "unsigned",
    "urlOfTheIcannWhoisDataProblemReportingSystem": "http://wdprs.internic.net/",
    "lastUpdateOfWhoisDatabase": "2024-10-19T14:27:44+0000 <<<",
    "forMoreInformationOnWhoisStatusCodesPleaseVisit": "https://www.icann.org/resources/pages/epp-status-codes",
    "webBasedWhois": "https://domains.markmonitor.com/whois",
    "lawfulPurposesAndThatUnderNoCircumstancesWillYouUseThisDataTo": "(1) allow, enable, or otherwise support the transmission by email, telephone,"
    }
    ```

    </details>

    ---

    > [!NOTE]
    > Hate JavaScript? Me too. I've written a Go Lang version, here: [github.com/Lissy93/who-dat](https://github.com/Lissy93/who-dat). Much better 😎
    101 changes: 101 additions & 0 deletions whois-lookup.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,101 @@
    import * as whois from 'whois';
    import * as changeCase from 'change-case';
    import { decodeEntity } from 'html-entities';

    const DELIMITER = ':';

    /**
    * Promisified version of the whois lookup function for async/await usage.
    */
    const whoisLookup = async (domain, options = {}) => {
    return new Promise((resolve, reject) => {
    whois.default.lookup(domain, options, (error, data) => {
    if (error) {
    return reject(error);
    }
    resolve(data);
    });
    });
    };

    /**
    * Main function to handle the WHOIS lookup and parse raw data.
    *
    * @param {string} domain - Domain name to lookup
    * @param {object} options - Options for the lookup (optional)
    * @returns {object} Parsed WHOIS data
    */
    export const getWhoisData = async (domain, options = {}) => {
    try {
    const rawData = await whoisLookup(domain, options);
    return Array.isArray(rawData)
    ? rawData.map(data => ({ ...data, data: parseRawData(data.data) }))
    : parseRawData(rawData);
    } catch (error) {
    console.error('Error during WHOIS lookup:', error);
    throw new Error('Failed to fetch WHOIS data');
    }
    };

    /**
    * Strip HTML entities from the raw data.
    *
    * @param {string} rawData - The raw WHOIS data
    * @returns {string} Decoded string with HTML entities stripped
    */
    const stripHTMLEntities = (rawData) => decodeEntity(rawData);

    /**
    * Determines the most common delimiter form in the raw data (e.g., `: ` or `:`).
    *
    * @param {string} rawData - The raw WHOIS data
    * @param {string} delimiter - The delimiter to search for
    * @returns {string} The most common delimiter found in the data
    */
    const getCommonDelimiterForm = (rawData, delimiter) => {
    const delimiterPattern = new RegExp(`${delimiter}\\S+`, 'g');
    const delimiterWithSpacePattern = new RegExp(`${delimiter} `, 'g');

    const delimiterMatches = rawData.match(delimiterPattern) || [];
    const delimiterWithSpaceMatches = rawData.match(delimiterWithSpacePattern) || [];

    return delimiterMatches.length > delimiterWithSpaceMatches.length
    ? delimiter
    : `${delimiter} `;
    };

    /**
    * Parses raw WHOIS data and converts it into a key-value object format.
    *
    * @param {string} rawData - The raw WHOIS data
    * @returns {object} Parsed key-value data
    */
    const parseRawData = (rawData) => {
    const result = {};

    rawData = stripHTMLEntities(rawData)
    .replace(/:\s*\r?\n/g, ': '); // Normalize colon space formatting

    const lines = rawData.split('\n');
    const delimiter = getCommonDelimiterForm(rawData, DELIMITER);

    lines.forEach(line => {
    const trimmedLine = line.trim();

    if (trimmedLine && trimmedLine.includes(delimiter)) {
    const [key, ...valueParts] = trimmedLine.split(DELIMITER);
    const value = valueParts.join(DELIMITER).trim();
    const formattedKey = changeCase.camelCase(key);

    // Combine values for the same key across multiple lines
    if (formattedKey in result) {
    result[formattedKey] = `${result[formattedKey]} ${value}`;
    } else {
    result[formattedKey] = value;
    }
    }
    });

    return result;
    };