Ejemplo n.º 1
0
    def validate(self):
        """Validates this IOC structure's state.

        :raise InvalidObjectError: if the IOC structure's state is invalid
        """
        super(IOC, self).validate()

        for md5 in self.md5:
            if not validators(md5):
                raise InvalidObjectError(
                    "invalid MD5 checksum: {}".format(md5))
        for ipv4 in self.ipv4:
            if not validators(ipv4):
                raise InvalidObjectError(
                    "invalid IPv4 address: {}".format(ipv4))
        for ipv6 in self.ipv6:
            if not validators(ipv6):
                raise InvalidObjectError(
                    "invalid IPv6 address: {}".format(ipv6))
        for dns in self.dns:
            if not validators(dns):
                raise InvalidObjectError("invalid domain: {}".format(dns))
        for query in self.query:
            if not self._cb.validate(query["search_query"]):
                raise InvalidObjectError("invalid search query: {}".format(
                    query["search_query"]))
Ejemplo n.º 2
0
    def delete(self):
        """Deletes this report from the ThreatHunter server.

        >>> report.delete()

        :raises InvalidObjectError: if `id` is missing, or `feed_id` is missing
            and this report is a feed report
        """
        if not self.id:
            raise InvalidObjectError("missing Report ID")

        if self._from_watchlist:
            url = "/threathunter/watchlistmgr/v3/orgs/{}/reports/{}".format(
                self._cb.credentials.org_key,
                self.id
            )
        else:
            if not self._feed_id:
                raise InvalidObjectError("missing Feed ID")
            url = "/threathunter/feedmgr/v2/orgs/{}/feeds/{}/reports/{}".format(
                self._cb.credentials.org_key,
                self._feed_id,
                self.id
            )

        self._cb.delete_object(url)
Ejemplo n.º 3
0
    def custom_severity(self, sev_level):
        """Sets or removed the custom severity for this report

        :param int sev_level: the new severity, or None to remove the custom severity
        :return: The new custom severity, or None if removed
        :rtype: :py:class:`ReportSeverity` or None
        :raise InvalidObjectError: if `id` is missing or this report is from a watchlist
        """
        if not self.id:
            raise InvalidObjectError("missing report ID")
        if self._from_watchlist:
            raise InvalidObjectError(
                "watchlist reports don't have custom severities")

        url = "/threathunter/watchlistmgr/v3/orgs/{}/reports/{}/severity".format(
            self._cb.credentials.org_key, self.id)

        if sev_level is None:
            self._cb.delete_object(url)
            return

        args = {
            "report_id": self.id,
            "severity": sev_level,
        }

        resp = self._cb.put_object(url, args).json()
        return ReportSeverity(self._cb, initial_data=resp)
Ejemplo n.º 4
0
    def unignore(self):
        """Removes the ignore status on this IOC.

        Only watchlist IOCs have an ignore status.

        :raises InvalidObjectError: if `id` is missing or this IOC is not from a watchlist
        """
        if not self.id:
            raise InvalidObjectError("missing Report ID")
        if not self._report_id:
            raise InvalidObjectError("ignoring only applies to watchlist IOCs")

        url = "/threathunter/watchlistmgr/v1/report/{}/ioc/{}/ignore".format(self._report_id, self.id)
        self._cb.delete_object(url)
Ejemplo n.º 5
0
    def custom_severity(self):
        """Returns the custom severity for this report.

        :return: The custom severity for this report, if it exists
        :rtype: :py:class:`ReportSeverity`
        :raise InvalidObjectError: if `id` is missing or this report is from a watchlist
        """
        if not self.id:
            raise InvalidObjectError("missing report ID")
        if self._from_watchlist:
            raise InvalidObjectError("watchlist reports don't have custom severities")

        resp = self._cb.get_object("/threathunter/watchlistmgr/v1/severity/report/{}".format(self.id))
        return ReportSeverity(self._cb, initial_data=resp)
Ejemplo n.º 6
0
    def unignore(self):
        """Removes the ignore status on this report.

        Only watchlist reports have an ignore status.

        :raises InvalidObjectError: if `id` is missing or this report is not from a watchlist
        """
        if not self.id:
            raise InvalidObjectError("missing Report ID")

        if not self._from_watchlist:
            raise InvalidObjectError("ignoring only applies to watchlist reports")

        self._cb.delete_object("/threathunter/watchlistmgr/v1/report/{}/ignore".format(self.id))
Ejemplo n.º 7
0
    def ignore(self):
        """Sets the ignore status on this IOC.

        Only watchlist IOCs have an ignore status.

        :raises InvalidObjectError: if `id` is missing or this IOC is not from a watchlist
        """
        if not self.id:
            raise InvalidObjectError("missing Report ID")
        if not self._report_id:
            raise InvalidObjectError("ignoring only applies to watchlist IOCs")

        url = "/threathunter/watchlistmgr/v3/orgs/{}/reports/{}/iocs/{}/ignore".format(
            self._cb.credentials.org_key, self._report_id, self.id)
        self._cb.put_object(url, None)
Ejemplo n.º 8
0
    def validate(self):
        """Validates this feed's state.

        :raise InvalidObjectError: if the feed's state is invalid
        """
        super(Feed, self).validate()

        if self.access not in ["public", "private"]:
            raise InvalidObjectError("access should be public or private")

        if not validators.url(self.provider_url):
            raise InvalidObjectError("provider_url should be a valid URL")

        for report in self._reports:
            report.validate()
Ejemplo n.º 9
0
    def update(self, **kwargs):
        """Update this feed's metadata with the given arguments.

        >>> feed.update(access="private")

        :param kwargs: The fields to update
        :type kwargs: dict(str, str)
        :raise InvalidObjectError: if `id` is missing or :py:meth:`validate` fails
        :raise ApiError: if an invalid field is specified
        """
        if not self.id:
            raise InvalidObjectError("missing feed ID")

        for key, value in kwargs.items():
            if key in self._info:
                self._info[key] = value

        self.validate()

        url = "/threathunter/feedmgr/v2/orgs/{}/feeds/{}/feedinfo".format(
            self._cb.credentials.org_key,
            self.id,
        )
        new_info = self._cb.put_object(url, self._info).json()
        self._info.update(new_info)

        return self
Ejemplo n.º 10
0
    def update(self, **kwargs):
        """Updates this watchlist with the given arguments.

        >>> watchlist.update(name="New Name")

        :param kwargs: The fields to update
        :type kwargs: dict(str, str)
        :raise InvalidObjectError: if `id` is missing or :py:meth:`validate` fails
        :raise ApiError: if `report_ids` is given *and* is empty
        """
        if not self.id:
            raise InvalidObjectError("missing Watchlist ID")

        # NOTE(ww): Special case, according to the docs.
        if "report_ids" in kwargs and not kwargs["report_ids"]:
            raise ApiError(
                "can't update a watchlist to have an empty report list")

        for key, value in kwargs.items():
            if key in self._info:
                self._info[key] = value

        self.validate()

        url = "/threathunter/watchlistmgr/v3/orgs/{}/watchlists/{}".format(
            self._cb.credentials.org_key, self.id)
        new_info = self._cb.put_object(url, self._info).json()
        self._info.update(new_info)
Ejemplo n.º 11
0
    def update(self, **kwargs):
        """Update this report with the given arguments.

        .. NOTE::
            The report's timestamp is always updated, regardless of whether
            passed explicitly.

        >>> report.update(title="My new report title")

        :param kwargs: The fields to update
        :type kwargs: dict(str, str)
        :return: The updated report
        :rtype: :py:class:`Report`
        :raises InvalidObjectError: if `id` is missing, or `feed_id` is missing
            and this report is a feed report, or :py:meth:`validate` fails
        """

        if not self.id:
            raise InvalidObjectError("missing Report ID")

        if self._from_watchlist:
            url = "/threathunter/watchlistmgr/v3/orgs/{}/reports/{}".format(
                self._cb.credentials.org_key,
                self.id
            )
        else:
            if not self._feed_id:
                raise InvalidObjectError("missing Feed ID")
            url = "/threathunter/feedmgr/v2/orgs/{}/feeds/{}/reports/{}".format(
                self._cb.credentials.org_key,
                self._feed_id,
                self.id
            )

        for key, value in kwargs.items():
            if key in self._info:
                self._info[key] = value

        # NOTE(ww): Updating reports on the watchlist API appears to require
        # updated timestamps.
        self.timestamp = int(time.time())
        self.validate()

        new_info = self._cb.put_object(url, self._info).json()
        self._info.update(new_info)
        return self
Ejemplo n.º 12
0
    def enable_alerts(self):
        """Enable alerts for this watchlist. Alerts are not retroactive.

        :raise InvalidObjectError: if `id` is missing
        """
        if not self.id:
            raise InvalidObjectError("missing Watchlist ID")

        self._cb.put_object("/threathunter/watchlistmgr/v1/watchlist/{}/alert".format(self.id), None)
Ejemplo n.º 13
0
    def delete(self):
        """Deletes this watchlist from the ThreatHunter server.

        :raise InvalidObjectError: if `id` is missing
        """
        if not self.id:
            raise InvalidObjectError("missing Watchlist ID")

        self._cb.delete_object("/threathunter/watchlistmgr/v1/watchlist/{}".format(self.id))
Ejemplo n.º 14
0
    def delete(self):
        """Deletes this feed from the ThreatHunter server.

        :raise InvalidObjectError: if `id` is missing
        """
        if not self.id:
            raise InvalidObjectError("missing feed ID")

        self._cb.delete_object("/threathunter/feedmgr/v1/feed/{}".format(self.id))
Ejemplo n.º 15
0
    def ignored(self):
        """Returns whether or not this IOC is ignored

        >>> if ioc.ignored:
        ...     ioc.unignore()

        :return: the ignore status
        :rtype: bool
        :raise InvalidObjectError: if this IOC is missing an `id` or is not a watchlist IOC
        """
        if not self.id:
            raise InvalidObjectError("missing IOC ID")
        if not self._report_id:
            raise InvalidObjectError("ignore status only applies to watchlist IOCs")

        url = "/threathunter/watchlistmgr/v1/report/{}/ioc/{}/ignore".format(self._report_id, self.id)
        resp = self._cb.get_object(url)
        return resp["ignored"]
Ejemplo n.º 16
0
    def disable_tags(self):
        """Disable tagging for this watchlist.

        :raise InvalidObjectError: if `id` is missing
        """
        if not self.id:
            raise InvalidObjectError("missing Watchlist ID")

        self._cb.delete_object("/threathunter/watchlistmgr/v1/watchlist/{}/tag".format(self.id))
Ejemplo n.º 17
0
    def validate(self):
        """Validates this IOC_V2's state.

        :raise InvalidObjectError: if the IOC_V2's state is invalid
        """
        super(IOC_V2, self).validate()

        if self.link and not validators.url(self.link):
            raise InvalidObjectError("link should be a valid URL")
Ejemplo n.º 18
0
    def ignored(self):
        """Returns the ignore status for this report.

        Only watchlist reports have an ignore status.

        >>> if report.ignored:
        ...     report.unignore()

        :return: whether or not this report is ignored
        :rtype: bool
        :raises InvalidObjectError: if `id` is missing or this report is not from a watchlist
        """
        if not self.id:
            raise InvalidObjectError("missing Report ID")
        if not self._from_watchlist:
            raise InvalidObjectError("ignore status only applies to watchlist reports")

        resp = self._cb.get_object("/threathunter/watchlistmgr/v1/report/{}/ignore".format(self.id))
        return resp["ignored"]
Ejemplo n.º 19
0
    def delete(self):
        """Deletes this feed from the ThreatHunter server.

        :raise InvalidObjectError: if `id` is missing
        """
        if not self.id:
            raise InvalidObjectError("missing feed ID")

        url = "/threathunter/feedmgr/v2/orgs/{}/feeds/{}".format(
            self._cb.credentials.org_key, self.id)
        self._cb.delete_object(url)
Ejemplo n.º 20
0
    def disable_tags(self):
        """Disable tagging for this watchlist.

        :raise InvalidObjectError: if `id` is missing
        """
        if not self.id:
            raise InvalidObjectError("missing Watchlist ID")

        url = "/threathunter/watchlistmgr/v3/orgs/{}/watchlists/{}/tag".format(
            self._cb.credentials.org_key, self.id)
        self._cb.delete_object(url)
Ejemplo n.º 21
0
    def enable_alerts(self):
        """Enable alerts for this watchlist. Alerts are not retroactive.

        :raise InvalidObjectError: if `id` is missing
        """
        if not self.id:
            raise InvalidObjectError("missing Watchlist ID")

        url = "/threathunter/watchlistmgr/v3/orgs/{}/watchlists/{}/alert".format(
            self._cb.credentials.org_key, self.id)
        self._cb.put_object(url, None)
Ejemplo n.º 22
0
    def delete(self):
        """Deletes this watchlist from the ThreatHunter server.

        :raise InvalidObjectError: if `id` is missing
        """
        if not self.id:
            raise InvalidObjectError("missing Watchlist ID")

        url = "/threathunter/watchlistmgr/v3/orgs/{}/watchlists/{}".format(
            self._cb.credentials.org_key, self.id)
        self._cb.delete_object(url)
Ejemplo n.º 23
0
    def validate(self):
        """Validates this report's state.

        :raise InvalidObjectError: if the report's state is invalid
        """
        super(Report, self).validate()

        if self.link and not validators.url(self.link):
            raise InvalidObjectError("link should be a valid URL")

        if self.iocs_v2:
            [ioc.validate() for ioc in self._iocs_v2]
Ejemplo n.º 24
0
    def replace_reports(self, reports):
        """Replace this feed's reports with the given reports.

        :param reports: the reports to replace with
        :type reports: list(:py:class:`Report`)
        :raise InvalidObjectError: if `id` is missing
        """
        if not self.id:
            raise InvalidObjectError("missing feed ID")

        rep_dicts = [report._info for report in reports]
        body = {"reports": rep_dicts}

        self._cb.post_object("/threathunter/feedmgr/v1/{}/report".format(self.id), body)
Ejemplo n.º 25
0
    def append_reports(self, reports):
        """Append the given reports to this feed's current reports.

        :param reports: the reports to append
        :type reports: list(:py:class:`Report`)
        :raise InvalidObjectError: if `id` is missing
        """
        if not self.id:
            raise InvalidObjectError("missing feed ID")

        rep_dicts = [report._info for report in reports]
        rep_dicts += [report._info for report in self._reports]
        body = {"reports": rep_dicts}

        self._cb.post_object("/threathunter/feedmgr/v1/{}/report".format(self.id), body)
Ejemplo n.º 26
0
    def download_url(self, expiration_seconds=3600):
        """Returns a URL that can be used to download the file
        for this binary. Returns None if no download can be found.

        :param expiration_seconds: How long the download should be valid for
        :raise InvalidObjectError: if URL retrieval should be retried
        :return: A pre-signed AWS download URL
        :rtype: str
        """
        downloads = self._cb.select(Downloads, [self.sha256],
                                    expiration_seconds=expiration_seconds)

        if self.sha256 in downloads.not_found:
            return None
        elif self.sha256 in downloads.error:
            raise InvalidObjectError("{} should be retried".format(self.sha256))
        else:
            return next((item.url
                        for item in downloads.found()
                        if self.sha256 == item.sha256), None)