Skip to content

Commit

Permalink
Add authentication for internal DoH resolver routes 🔐
Browse files Browse the repository at this point in the history
  • Loading branch information
wotschofsky committed Jan 15, 2024
1 parent ff021c0 commit 366436a
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 46 deletions.
24 changes: 23 additions & 1 deletion app/api/internal/resolve/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,29 @@ import CloudflareDoHResolver from '@/lib/resolvers/CloudflareDoHResolver';
import { RECORD_TYPES, type RecordType } from '@/lib/resolvers/DnsResolver';
import GoogleDoHResolver from '@/lib/resolvers/GoogleDoHResolver';

if (process.env.NODE_ENV === 'production' && !process.env.INTERNAL_API_SECRET) {
throw new Error('INTERNAL_API_SECRET is required in production');
}

export const handler = async (request: Request) => {
if (
process.env.INTERNAL_API_SECRET &&
process.env.INTERNAL_API_SECRET !== request.headers.get('authorization')
) {
return Response.json(
{
error: true,
message: 'Unauthorized',
},
{
status: 401,
headers: {
'Content-Type': 'application/json',
},
}
);
}

const { searchParams } = new URL(request.url);
const resolverName = searchParams.get('resolver');
const types = searchParams.getAll('type');
Expand All @@ -12,7 +34,7 @@ export const handler = async (request: Request) => {
return Response.json(
{
error: true,
message: '"type" and "domain" params are required',
message: '"resolver", "type" and "domain" params are required',
},
{
status: 400,
Expand Down
22 changes: 4 additions & 18 deletions app/lookup/[domain]/map/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { FC } from 'react';

import ResultsGlobe from '@/components/ResultsGlobe';
import { REGIONS } from '@/lib/data';
import { RawRecord } from '@/lib/resolvers/DnsResolver';
import InternalDoHResolver from '@/lib/resolvers/InternalDoHResolver';

export const runtime = 'edge';

Expand All @@ -17,23 +17,9 @@ const MapResultsPage: FC<MapResultsPageProps> = async ({
}) => {
const markers = await Promise.all(
Object.entries(REGIONS).map(async ([code, data]) => {
const url = `${
process.env.SITE_URL ||
(process.env.VERCEL_URL && `https://${process.env.VERCEL_URL}`) ||
'http://localhost:3000'
}/api/internal/resolve/${code}?resolver=cloudflare&type=A&type=AAAA&type=CNAME&domain=${encodeURIComponent(
domain
)}`;
const response = await fetch(url);
if (!response.ok)
throw new Error(
`Failed to fetch results for ${code} from ${url}: ${response.status} ${response.statusText}`
);
const results = (await response.json()) as {
A: RawRecord[];
AAAA: RawRecord[];
CNAME: RawRecord[];
};
const resolver = new InternalDoHResolver(code, 'cloudflare');
// TODO Optimize this to only required records
const results = await resolver.resolveAllRecords(domain);

return {
...data,
Expand Down
41 changes: 14 additions & 27 deletions lib/resolvers/InternalDoHResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,6 @@ import DnsResolver, {
type ResolvedRecords,
} from './DnsResolver';

type DoHResponse = {
Status: number;
TC: boolean;
RD: boolean;
RA: boolean;
AD: boolean;
CD: boolean;
Question: {
name: string;
type: number;
}[];
Answer?: {
name: string;
type: number;
TTL: number;
data: string;
}[];
Authority?: {
name: string;
type: number;
TTL: number;
data: string;
}[];
};

export default class InternalDoHResolver extends DnsResolver {
constructor(
private readonly location: string,
Expand All @@ -48,6 +23,18 @@ export default class InternalDoHResolver extends DnsResolver {
return baseUrl;
}

private get requestInit() {
if (!process.env.INTERNAL_API_SECRET) {
return {};
}

return {
headers: {
Authorization: process.env.INTERNAL_API_SECRET,
},
};
}

public async resolveRecordType(
domain: string,
type: RecordType
Expand All @@ -57,7 +44,7 @@ export default class InternalDoHResolver extends DnsResolver {
url.searchParams.set('type', type);
url.searchParams.set('domain', domain);

const response = await fetch(url);
const response = await fetch(url, this.requestInit);
if (!response.ok)
throw new Error(
`Failed to fetch results for ${this.location} from ${url}: ${response.status} ${response.statusText}`
Expand All @@ -74,7 +61,7 @@ export default class InternalDoHResolver extends DnsResolver {
RECORD_TYPES.forEach((type) => url.searchParams.append('type', type));
url.searchParams.set('domain', domain);

const response = await fetch(url);
const response = await fetch(url, this.requestInit);
if (!response.ok)
throw new Error(
`Failed to fetch results for ${this.location} from ${url}: ${response.status} ${response.statusText}`
Expand Down

1 comment on commit 366436a

@vercel
Copy link

@vercel vercel bot commented on 366436a Jan 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.