Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@profullstack/nichedb",
"version": "0.47.1",
"version": "0.48.0",
"description": "CLI and MCP bridge for NicheDB: browse collections, manage sources and feeds, search items, from any deployment",
"type": "module",
"main": "src/index.js",
Expand Down
2 changes: 1 addition & 1 deletion apps/web/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@nichedb/web",
"version": "0.47.1",
"version": "0.48.0",
"private": true,
"type": "module",
"scripts": {
Expand Down
43 changes: 0 additions & 43 deletions apps/web/src/lib/pit-footer.js

This file was deleted.

62 changes: 51 additions & 11 deletions apps/web/src/routes/traffic.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,14 @@ import {
rpzForDomains,
rpzForIps,
} from '@nichedb/core/traffic';
import { OWNERS_FETCHED_AT, ownerOf, ownersList } from '@nichedb/core/traffic/owners';
import {
OWNERS_FETCHED_AT,
ownerBySlug,
ownerOf,
ownersList,
PROVIDERS_CHECKED,
PROVIDERS_FETCHED_AT,
} from '@nichedb/core/traffic/owners';
import { rdapLookup } from '@nichedb/core/traffic/rdap';
import * as q from '@nichedb/db/queries';
import * as reputation from '@nichedb/db/reputation';
Expand All @@ -16,8 +23,9 @@ import { callerAddress } from '../lib/auth-throttle.js';
import { render, wantsJson } from '../lib/http.js';
import { canReview, Denied } from '../lib/service.js';
import {
IpOwnerPage,
IpOwnersPage,
TrafficIpPage,
TrafficOwnersPage,
TrafficPage,
TrafficReviewPage,
} from '../views/traffic.jsx';
Expand Down Expand Up @@ -101,8 +109,9 @@ async function requireReviewer(c) {
/** Who owns an address: a known owner from the registry, else RDAP. */
export async function ownerFor(ip, { rdap = rdapLookup } = {}) {
const known = ownerOf(ip);
if (known) return { known, rdap: null };
return { known: null, rdap: await rdap(ip) };
if (known?.shared) return { known, rdap: null };
// A hosting provider still gets its registry record: the abuse contact.
return { known, rdap: await rdap(ip) };
}

/**
Expand All @@ -124,24 +133,55 @@ async function ownersWithCounts() {
}

export function registerTraffic(app) {
/** Networks we know by name and never list, and why. */
app.get('/traffic/owners', async (c) => {
/** Who owns an IP: shared networks we never list, and hosting providers. */
const ownersPage = async (c) => {
const owners = await ownersWithCounts();
return c.html(
await render(
<TrafficOwnersPage user={c.get('user')} owners={owners} fetchedAt={OWNERS_FETCHED_AT} />,
<IpOwnersPage
user={c.get('user')}
owners={owners}
fetchedAt={OWNERS_FETCHED_AT}
providersFetchedAt={PROVIDERS_FETCHED_AT}
providersChecked={PROVIDERS_CHECKED}
/>,
),
);
});
};
app.get('/ips/owners', ownersPage);
app.get('/traffic/owners', (c) => c.redirect('/ips/owners', 301));

app.get('/api/v1/traffic/owners', async (c) => {
const ownersJson = async (c) => {
c.header('cache-control', 'public, max-age=600');
return c.json({
about:
'Networks we know by name (search crawlers, CDNs, public resolvers, company blocks). None is ever listed on /traffic. `banned` counts addresses in each that ThreatCrush banned on our servers.',
'Who owns an IP. `shared: true` owners (search crawlers, CDNs, public resolvers, company blocks) are never listed on /traffic. `shared: false` owners are hosting and seedbox providers from r4ck.dev and ch4nnels.com that run their own network; bans there are listed. `banned` counts addresses in each that ThreatCrush banned on our servers. Hosting providers omit `ranges` here; get them from /api/v1/ips/owners/<slug>.',
ranges_fetched_at: OWNERS_FETCHED_AT,
owners: await ownersWithCounts(),
providers_fetched_at: PROVIDERS_FETCHED_AT,
owners: (await ownersWithCounts()).map((o) =>
o.shared ? o : { ...o, ranges: undefined, range_count: o.ranges.length },
),
});
};
app.get('/api/v1/ips/owners', ownersJson);
app.get('/api/v1/traffic/owners', ownersJson);

const ownerWithCount = async (slug) => {
const owner = ownerBySlug(slug);
if (!owner) return null;
const counts = (await ownersWithCounts()).find((o) => o.slug === slug);
return { ...owner, banned: counts?.banned ?? 0 };
};
app.get('/ips/owners/:slug', async (c) => {
const owner = await ownerWithCount(c.req.param('slug'));
if (!owner) return c.notFound();
return c.html(await render(<IpOwnerPage user={c.get('user')} owner={owner} />));
});
app.get('/api/v1/ips/owners/:slug', async (c) => {
const owner = await ownerWithCount(c.req.param('slug'));
if (!owner) return c.json({ error: 'not found' }, 404);
c.header('cache-control', 'public, max-age=600');
return c.json(owner);
});

app.get('/traffic', async (c) => {
Expand Down
3 changes: 0 additions & 3 deletions apps/web/src/views/Layout.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { bundledTemplate, latestTemplate, renderFooter } from '@profullstack/foo
import { raw } from 'hono/html';
import { assetUrl } from '../lib/asset-version.js';
import { currentModules } from '../lib/modules.js';
import { pitFooterHtml } from '../lib/pit-footer.js';

const faviconFor = (user) => {
const icon = appIconFor({ plan: currentModules().plan, icon: user?.premium_icon });
Expand Down Expand Up @@ -228,8 +227,6 @@ export const Layout = (props) => (
{config.ads.enabled && currentModules().ads ? (
<script src="https://crawlproof.com/ad.js" async />
) : null}
{/* The pit.world global footer, last in <body>. */}
{raw(pitFooterHtml())}
</body>
</html>
);
Loading
Loading