unshortenMe

Unshorten.me is a free service to Un-Shorten the URLs created by URL shortening services. Unshorten.me can un-shorten URLs created by different services like goo.gl (Google), fb.me (Facebook), t.co (Twitter), bit.ly, TinyURL, ow.ly among others.

Utilities · UnshortenMe

Details

IDunshortenMe
ProviderOpen Source
CategoryUtilities
From Version6.10.0
Docker Imagedemisto/python3:3.12.13.10116658

README

unshorten.me Integration (Community)

Overview

This integration allows you to unshorten URLs using the unshorten.me service. It is useful for revealing the final destination of shortened links from services like bit.ly, t.co (Twitter), TinyURL, and more, which is a common requirement in threat analysis and phishing investigations.

To use this integration, you must request a free API token from unshorten.me.

Configure unshorten.me on Cortex XSOAR

  1. Navigate to Settings > Integrations > Servers & Services.
  2. Search for unshorten.me.
  3. Click Add instance to create and configure a new integration instance.
Parameter Description Required
API Token The API token for your unshorten.me account. True
Trust any certificate (not secure) When selected, the integration ignores TLS/SSL certificate validation errors. Use with caution. False
Use system proxy settings When selected, the integration uses the system’s proxy settings. False
  1. Click Test to validate the URL and token.

Commands

You can execute these commands from the Cortex XSOAR CLI, as part of an automation, or in a playbook. After you successfully execute a command, a DBot message appears in the War Room with the command details.

1. unshorten-me-unshorten-url


Unshortens a given URL.

Base Command

unshorten-me-unshorten-url

Input

Argument Name Description Required
shortUrl The shortened URL to expand. e.g., https://bit.ly/3DKWm5t True

Context Output

Path Type Description
unshortenMe.unshortened_url String The full, original destination URL.
unshortenMe.shortened_url String The shortened URL that was provided as input.
unshortenMe.success Boolean True if the operation was successful, otherwise False.

Command Example

!unshorten-me-unshorten-url shortUrl="https://bit.ly/3DKWm5t"

Human Readable Output

unshorten.me results

Unshortened URL: https://www.youtube.com/
Shortened URL: https://bit.ly/3DKWm5t
Success: True

Context Example

```json
{
“unshortenMe”: {
“success”: true,
“shortened_url”: “https://bit.ly/3DKWm5t”,
“unshortened_url”: “https://www.youtube.com/”
}
}

Configuration parameters

  • credentials — (required)

Commands (1)

  • unshorten-me-unshorten-url

    The response will contain the unshortened URL corresponding to the provided short URL and success status.

import re
import urllib3
import demistomock as demisto
from CommonServerPython import *


# Disable insecure connection warnings
urllib3.disable_warnings()


class Client(BaseClient):
    def __init__(self, base_url: str, proxy: bool, verify: bool, headers: dict):
        """
        Client to use. Overrides BaseClient.

        Args:
            base_url (str): URL to access when doing a http request. Webhook url.
        """
        super().__init__(base_url=base_url, proxy=proxy, verify=verify, headers=headers)

    def unshorten_request(self, short_url: str):
        """Sends the unshorten request to the unshorten.me API.

        This method constructs and sends a GET request to the /unshorten
        endpoint. It checks the API response for a 'success' status and
        raises an exception if the API indicates an error.

        Args:
            short_url (str): The shortened URL to be resolved.

        Returns:
            CommandResults: An object containing the API response and
            formatted markdown for the War Room.

        Raises:
            DemistoException: If the API returns a non-successful status
            or if the request fails.
        """
        outputs = []
        res = self._http_request(method="GET", raise_on_status=True, url_suffix="/unshorten", params={"url": short_url})
        demisto.info(f"Request sent. Respons{res}")

        if not res.get("success"):
            error_message = res.get("error_message", "Unknown API Error")
            raise DemistoException(f"unshorten.me API error: {error_message}")

        outputs.append(
            {
                "unshortened_url": res.get("unshortened_url"),
                "shortened_url": res.get("shortened_url"),
                "success": res.get("success"),
            }
        )

        table_headers = ["unshortened_url", "shortened_url", "success"]
        return CommandResults(
            outputs_prefix="unshortenMe",
            outputs=outputs,
            readable_output=tableToMarkdown("unshorten.me results", outputs, table_headers, removeNull=True),
            raw_response=res,
        )

    def is_valid(self, url: str):
        """
        This regex checks for the basic components of a URL
        """
        regex = re.compile(
            r"^(?:http|ftp)s?://"  # http:// or https://
            r"(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+"  # subdomain
            r"(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|"  # top-level domain
            r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})"  # ...or ip
            r"(?::\d+)?"  # optional port
            r"(?:/?|[/?]\S+)$",
            re.IGNORECASE,
        )
        return re.match(regex, url) is not None


def unshorten_url_command(client: Client, short_url):
    """Validates and processes the URL unshorten command.

    This function serves as the command handler. It first validates
    that the input string is a properly formatted URL and then passes
    it to the client to perform the unshortening request.

    Args:
        client (Client): The API client instance.
        short_url (str): The user-provided URL to unshorten.

    Returns:
        CommandResults: The result object from the client's
                        unshorten_request method.

    Raises:
        ValueError: If the input `short_url` is not in a valid
                    URL format (e.g., missing http:// or https://).
    """
    is_url = client.is_valid(short_url)
    if is_url is False:
        raise ValueError(
            f"Input is not a valid URL format. It must include http:// or https://." f"\nInput provided: {short_url}"
        )

    res = client.unshorten_request(short_url)
    return res


def test_module(client):
    """
    Test command will send a Shortened URL

    Args:
        client (Client): unshorten.me client to use

    Returns:
        str: 'ok' if test passed, anything else will raise an exception and will fail the test.
    """
    try:
        short_url = "https://bit.ly/3DKWm5t"
        client.unshorten_request(short_url=short_url)
        return "ok"
    except DemistoException as e:
        return f"Error: {e}"


def main():
    """
    Main function, pares integratio parameters, runs
    command functions, executes a test, unshortens URLs
    """

    params = demisto.params()
    args = demisto.args()
    command = demisto.command()

    token = params.get("credentials", {}).get("password")
    base_url = "https://unshorten.me/api/v2/"
    proxy = params.get("proxy", False)
    verify_certificate = not params.get("insecure", False)
    headers = {"Authorization": f"Token {token}"}

    try:
        client = Client(base_url=base_url, verify=verify_certificate, proxy=proxy, headers=headers)

        # Runs the unshorten command
        if command == "unshorten-me-unshorten-url":
            short_url = args.get("shortUrl")
            return_results(unshorten_url_command(client, short_url))
        # Runs the test module when the test button is selected
        elif command == "test-module":
            return_results(test_module(client))
        else:
            raise NotImplementedError(f"Command {command} is not implemented.")

    except Exception as e:
        demisto.error(traceback.format_exc())
        return_error(f"Failed to execute {command} encountered {e}.")


if __name__ in ("__main__", "__builtin__", "builtins"):
    main()