types#Domain TypeScript Examples

The following examples show how to use types#Domain. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: columns.tsx    From crossfeed with Creative Commons Zero v1.0 Universal 6 votes vote down vote up
getServiceNames = (domain: Domain) => {
  const allServices: { [key: string]: string } = {};
  for (const service of domain.services) {
    for (const product of service.products) {
      if (product.name)
        allServices[product.name.toLowerCase()] =
          product.name + (product.version ? ` ${product.version}` : '');
    }
  }
  return Object.values(allServices).join(', ');
}
Example #2
Source File: columns.tsx    From crossfeed with Creative Commons Zero v1.0 Universal 6 votes vote down vote up
createColumns: CreateColumns = () => [
  {
    Header: 'Details',
    Cell: ({ row: { original } }: CellProps<Domain>) => (
      <Link to={`/inventory/domain/${original.id}`}>
        <FaSearch className="margin-x-auto display-block" />
      </Link>
    )
  },
  {
    Header: 'Organization',
    accessor: (e) => e.organization.name,
    id: 'organizationName',
    Filter: ColumnFilter
  },
  {
    Header: 'Domain',
    accessor: 'name',
    id: 'reverseName',
    Filter: ColumnFilter
  },
  {
    Header: 'IP',
    accessor: 'ip',
    Filter: ColumnFilter
  },
  {
    Header: 'Ports',
    id: 'port',
    disableSortBy: true,
    accessor: ({ services }) =>
      services.map((service) => service.port).join(', '),
    Filter: ColumnFilter
  },
  {
    Header: 'Services',
    id: 'service',
    disableSortBy: true,
    accessor: (domain) => getServiceNames(domain),
    Filter: ColumnFilter
  },
  {
    Header: 'Vulnerabilities',
    id: 'vulnerability',
    accessor: (domain) =>
      domain.vulnerabilities &&
      domain.vulnerabilities
        .map((vulnerability) => vulnerability.cve)
        .join(', '),
    Filter: ColumnFilter
  },
  {
    Header: 'Last Seen',
    id: 'updatedAt',
    accessor: ({ updatedAt }) =>
      `${formatDistanceToNow(parseISO(updatedAt))} ago`,
    disableFilters: true
  },
  {
    Header: 'First Seen',
    id: 'createdAt',
    accessor: ({ createdAt }) =>
      `${formatDistanceToNow(parseISO(createdAt))} ago`,
    disableFilters: true
  }
]
Example #3
Source File: useDomainApi.ts    From crossfeed with Creative Commons Zero v1.0 Universal 5 votes vote down vote up
useDomainApi = (showAll?: boolean) => {
  const { currentOrganization, apiPost, apiGet } = useAuthContext();
  const listDomains = useCallback(
    async (query: DomainQuery, doExport = false) => {
      const { page, sort, filters, pageSize = PAGE_SIZE } = query;

      const tableFilters: any = filters
        .filter((f) => Boolean(f.value))
        .reduce(
          (accum, next) => ({
            ...accum,
            [next.id]: next.value
          }),
          {}
        );

      if (!showAll && currentOrganization) {
        if ('rootDomains' in currentOrganization)
          tableFilters['organization'] = currentOrganization.id;
        else tableFilters['tag'] = currentOrganization.id;
      }

      const { result, count, url } = await apiPost<ApiResponse>(
        doExport ? '/domain/export' : '/domain/search',
        {
          body: {
            pageSize,
            page,
            sort: sort[0]?.id ?? 'name',
            order: sort[0]?.desc ? 'DESC' : 'ASC',
            filters: tableFilters
          }
        }
      );

      return {
        domains: result,
        count,
        url,
        pageCount: Math.ceil(count / pageSize)
      };
    },
    [apiPost, showAll, currentOrganization]
  );

  const getDomain = useCallback(
    async (domainId: string) => {
      return await apiGet<Domain>(`/domain/${domainId}`);
    },
    [apiGet]
  );

  return {
    listDomains,
    getDomain
  };
}
Example #4
Source File: Domains.tsx    From crossfeed with Creative Commons Zero v1.0 Universal 5 votes vote down vote up
Domains: React.FC = () => {
  const { showAllOrganizations } = useAuthContext();
  const tableRef = useRef<TableInstance<Domain>>(null);
  const columns = useMemo(() => createColumns(), []);
  const [domains, setDomains] = useState<Domain[]>([]);
  const [totalResults, setTotalResults] = useState(0);

  const { listDomains } = useDomainApi(showAllOrganizations);

  const fetchDomains = useCallback(
    async (q: Query<Domain>) => {
      try {
        const { domains, count } = await listDomains(q);
        setDomains(domains);
        setTotalResults(count);
      } catch (e) {
        console.error(e);
      }
    },
    [listDomains]
  );

  const fetchDomainsExport = async (): Promise<string> => {
    const { sortBy, filters } = tableRef.current?.state ?? {};
    try {
      const { url } = await listDomains(
        {
          sort: sortBy ?? [],
          page: 1,
          pageSize: -1,
          filters: filters ?? []
        },
        true
      );
      return url!;
    } catch (e) {
      console.error(e);
      return '';
    }
  };

  const renderPagination = (table: TableInstance<Domain>) => (
    <Paginator
      table={table}
      totalResults={totalResults}
      export={{
        name: 'domains',
        getDataToExport: fetchDomainsExport
      }}
    />
  );

  return (
    <div className={classes.root}>
      <Subnav
        items={[
          { title: 'Search Results', path: '/inventory', exact: true },
          { title: 'All Domains', path: '/inventory/domains' },
          { title: 'All Vulnerabilities', path: '/inventory/vulnerabilities' }
        ]}
      ></Subnav>
      <br></br>
      <Table<Domain>
        renderPagination={renderPagination}
        tableRef={tableRef}
        columns={columns}
        data={domains}
        pageCount={Math.ceil(totalResults / PAGE_SIZE)}
        fetchData={fetchDomains}
        pageSize={PAGE_SIZE}
      />
    </div>
  );
}
Example #5
Source File: DomainDetails.tsx    From crossfeed with Creative Commons Zero v1.0 Universal 4 votes vote down vote up
DomainDetails: React.FC<Props> = (props) => {
  const { domainId } = props;
  const { getDomain } = useDomainApi(false);
  const { user } = useAuthContext();
  const [domain, setDomain] = useState<Domain>();
  const classes = useStyles();
  const history = useHistory();

  const fetchDomain = useCallback(async () => {
    try {
      setDomain(undefined);
      const result = await getDomain(domainId);
      setDomain(result);
    } catch (e) {
      console.error(e);
    }
  }, [domainId, getDomain]);

  useEffect(() => {
    fetchDomain();
  }, [fetchDomain]);

  const webInfo = useMemo(() => {
    if (!domain) {
      return [];
    }
    const categoriesToProducts: Record<string, Set<string>> = {};
    for (const service of domain.services) {
      for (const product of service.products) {
        const version = product.version ? ` ${product.version}` : '';
        const value = product.name + version;
        const name =
          product.tags && product.tags.length > 0 ? product.tags[0] : 'Misc';
        if (!categoriesToProducts[name]) {
          categoriesToProducts[name] = new Set();
        }
        categoriesToProducts[name].add(value);
      }
    }
    return Object.entries(categoriesToProducts).reduce(
      (acc, [name, value]) => [
        ...acc,
        {
          label: name,
          value: Array.from(value).join(', ')
        }
      ],
      [] as any
    );
  }, [domain]);

  const overviewInfo = useMemo(() => {
    if (!domain) {
      return [];
    }
    const ret = [];
    if (domain.ip) {
      ret.push({
        label: 'IP',
        value: domain.ip
      });
    }
    ret.push({
      label: 'First Seen',
      value: `${differenceInCalendarDays(
        Date.now(),
        parseISO(domain.createdAt)
      )} days ago`
    });
    ret.push({
      label: 'Last Seen',
      value: `${differenceInCalendarDays(
        Date.now(),
        parseISO(domain.updatedAt)
      )} days ago`
    });
    if (domain.country) {
      ret.push({
        label: 'Country',
        value: domain.country
      });
    }
    if (domain.cloudHosted) {
      ret.push({
        label: 'Cloud Hosted',
        value: 'Yes'
      });
    }
    ret.push({
      label: 'Organization',
      value: domain.organization.name
    });
    return ret;
  }, [domain]);

  const [hiddenRows, setHiddenRows] = React.useState<{
    [key: string]: boolean;
  }>({});

  const formatBytes = (bytes: number, decimals = 2): string => {
    if (bytes === 0) return '0 Bytes';

    const k = 1024;
    const dm = decimals < 0 ? 0 : decimals;
    const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];

    const i = Math.floor(Math.log(bytes) / Math.log(k));

    return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
  };

  const generateWebpageList = (tree: any, prefix = '') => {
    return (
      <List
        className={`${classes.listRoot}${prefix ? ' ' + classes.nested : ''}`}
      >
        {Object.keys(tree).map((key) => {
          const isWebpage =
            'url' in tree[key] && typeof tree[key]['url'] === 'string';
          if (!isWebpage) {
            const newPrefix = prefix + '/' + key;
            return (
              <>
                <ListItem
                  button
                  onClick={() => {
                    setHiddenRows((hiddenRows: any) => {
                      hiddenRows[newPrefix] =
                        newPrefix in hiddenRows ? !hiddenRows[newPrefix] : true;
                      return { ...hiddenRows };
                    });
                  }}
                  key={newPrefix}
                >
                  <ListItemText primary={(prefix ? '' : '/') + key + '/'} />
                  {hiddenRows[newPrefix] ? <ExpandLess /> : <ExpandMore />}
                </ListItem>
                <Collapse
                  in={!hiddenRows[newPrefix]}
                  timeout="auto"
                  unmountOnExit
                >
                  {generateWebpageList(tree[key], newPrefix)}
                </Collapse>
              </>
            );
          }
          const page = tree[key] as Webpage;
          const parsed = new URL(page.url);
          const split = parsed.pathname
            .replace(/\/$/, '') // Remove trailing slash
            .split('/');
          return (
            <ListItem
              button
              divider={true}
              key={page.url}
              onClick={() => window.open(page.url, '_blank')}
            >
              <ListItemText
                primary={(prefix ? '' : '/') + split.pop()}
                secondary={
                  page.status + ' • ' + formatBytes(page.responseSize ?? 0, 1)
                }
              ></ListItemText>
            </ListItem>
          );
        })}
      </List>
    );
  };

  if (!domain) {
    return null;
  }

  const url =
    (domain.services.find((service) => service.port === 443)
      ? 'https://'
      : 'http://') + domain.name;

  const { webpages = [] } = domain;
  webpages.sort((a, b) => (a.url > b.url ? 1 : -1));
  const webpageTree = generateWebpageTree(webpages);
  const webpageList = generateWebpageList(webpageTree);

  return (
    <Paper classes={{ root: classes.root }}>
      <div className={classes.title}>
        <h4>
          <Link to={`/inventory/domain/${domain.id}`}>{domain.name}</Link>
        </h4>

        <a href={url} target="_blank" rel="noopener noreferrer">
          <LinkOffIcon />
        </a>
      </div>
      <div className={classes.inner}>
        {overviewInfo.length > 0 && (
          <div className={classes.section}>
            <h4 className={classes.subtitle}>Overview</h4>
            <DefinitionList items={overviewInfo} />
          </div>
        )}
        {webInfo.length > 0 && (
          <div className={classes.section}>
            <h4 className={classes.subtitle}>Known Products</h4>
            <DefinitionList items={webInfo} />
          </div>
        )}

        {domain.vulnerabilities.length > 0 && (
          <div className={classes.section}>
            <h4 className={classes.subtitle}>Vulnerabilities</h4>
            <Accordion className={classes.accordionHeaderRow} disabled>
              <AccordionSummary>
                <Typography className={classes.accordionHeading}>
                  Title
                </Typography>
                <Typography className={classes.vulnDescription}>
                  Serverity
                </Typography>
                <Typography className={classes.vulnDescription}>
                  State
                </Typography>
                <Typography className={classes.vulnDescription}>
                  Created
                </Typography>
              </AccordionSummary>
            </Accordion>
            {domain.vulnerabilities.map((vuln) => (
              <Accordion
                className={classes.accordion}
                key={vuln.id}
                onClick={(event) => {
                  event.stopPropagation();
                  history.push('/inventory/vulnerability/' + vuln.id);
                }}
              >
                <AccordionSummary>
                  <Typography className={classes.accordionHeading}>
                    {vuln.title}
                  </Typography>
                  <Typography className={classes.vulnDescription}>
                    {vuln.severity}
                  </Typography>
                  <Typography className={classes.vulnDescription}>
                    {vuln.state}
                  </Typography>
                  <Typography className={classes.vulnDescription}>
                    {vuln.createdAt
                      ? `${differenceInCalendarDays(
                          Date.now(),
                          parseISO(vuln.createdAt)
                        )} days ago`
                      : ''}
                  </Typography>
                </AccordionSummary>
              </Accordion>
            ))}
          </div>
        )}
        {domain.services.length > 0 && (
          <div className={classes.section}>
            <h4 className={classes.subtitle}>Ports</h4>
            <Accordion className={classes.accordionHeaderRow} disabled>
              <AccordionSummary expandIcon={<ExpandMore />}>
                <Typography className={classes.accordionHeading}>
                  Port
                </Typography>
                <Typography className={classes.accordionHeading}>
                  Products
                </Typography>
                <Typography className={classes.lastSeen}>Last Seen</Typography>
              </AccordionSummary>
            </Accordion>
            {domain.services.map((service) => {
              const products = service.products
                .map(
                  (product) =>
                    product.name +
                    (product.version ? ` ${product.version}` : '')
                )
                .join(', ');
              return (
                <Accordion className={classes.accordion} key={service.id}>
                  <AccordionSummary expandIcon={<ExpandMore />}>
                    <Typography className={classes.accordionHeading}>
                      {service.port}
                    </Typography>
                    <Typography className={classes.accordionHeading}>
                      {products}
                    </Typography>
                    <Typography className={classes.lastSeen}>
                      {service.lastSeen
                        ? `${differenceInCalendarDays(
                            Date.now(),
                            parseISO(service.lastSeen)
                          )} days ago`
                        : ''}
                    </Typography>
                  </AccordionSummary>
                  {service.products.length > 0 && (
                    <AccordionDetails>
                      <DefinitionList
                        items={[
                          {
                            label: 'Products',
                            value: products
                          },
                          {
                            label: 'Banner',
                            value:
                              (user?.userType === 'globalView' ||
                                user?.userType === 'globalAdmin') &&
                              service.banner
                                ? service.banner
                                : 'None'
                          }
                        ]}
                      />
                    </AccordionDetails>
                  )}
                </Accordion>
              );
            })}
          </div>
        )}
        {domain.webpages?.length > 0 && (
          <div className={classes.section}>
            <h4 className={classes.subtitle}>Site Map</h4>
            {webpageList}
          </div>
        )}
      </div>
    </Paper>
  );
}