码桶
发现社区成员的开源项目
search.js3.5 KB
import { getUserAllowedZones, isZoneAllowed } from './_permissions.js';
// GET: Search DNS records across all zones
export async function onRequestGet(context) {
const { request } = context;
const { cfHeaders } = context.data;
const url = new URL(request.url);
const query = url.searchParams.get('q') || '';
if (!query || query.length < 2) {
return new Response(JSON.stringify({ error: 'Search query must be at least 2 characters.' }), {
status: 400, headers: { 'Content-Type': 'application/json' }
});
}
const headers = {
...cfHeaders,
'Content-Type': 'application/json'
};
try {
// First, get all zones
const zonesRes = await fetch('https://api.cloudflare.com/client/v4/zones?per_page=50', { headers });
const zonesData = await zonesRes.json();
if (!zonesData.success) {
return new Response(JSON.stringify({ error: 'Failed to fetch zones.', results: [] }), {
status: 200, headers: { 'Content-Type': 'application/json' }
});
}
let zones = zonesData.result || [];
// Filter zones based on user permissions
const user = context.data.user;
if (user && user.role !== 'admin') {
const allowedZones = await getUserAllowedZones(context.env.CF_DNS_KV, user.username);
if (allowedZones.length > 0) {
zones = zones.filter(zone => isZoneAllowed(allowedZones, zone.name));
}
}
const results = [];
// Search DNS records in all zones in parallel
const promises = zones.map(async (zone) => {
try {
// Cloudflare API supports name and content search
const searchRes = await fetch(
`https://api.cloudflare.com/client/v4/zones/${zone.id}/dns_records?per_page=100&search=${encodeURIComponent(query)}`,
{ headers }
);
const searchData = await searchRes.json();
if (searchData.success && searchData.result) {
return searchData.result.map(r => ({
...r,
zoneName: zone.name,
zoneId: zone.id
}));
}
} catch (e) { console.error(`Failed to search DNS records for zone ${zone.name}:`, e); }
return [];
});
const allResults = await Promise.all(promises);
for (const records of allResults) results.push(...records);
// Also do client-side filtering for content, comment, and tags match (CF search may only match name)
const lowerQuery = query.toLowerCase();
const filtered = results.filter(r =>
r.name.toLowerCase().includes(lowerQuery) ||
(r.content && r.content.toLowerCase().includes(lowerQuery)) ||
r.type.toLowerCase().includes(lowerQuery) ||
(r.comment && r.comment.toLowerCase().includes(lowerQuery)) ||
(r.tags && r.tags.some(tag => tag.toLowerCase().includes(lowerQuery)))
);
return new Response(JSON.stringify({
results: filtered.slice(0, 100),
total: filtered.length,
zonesSearched: zones.length
}), {
headers: { 'Content-Type': 'application/json' }
});
} catch (e) {
return new Response(JSON.stringify({ error: 'Search failed.', results: [] }), {
status: 500, headers: { 'Content-Type': 'application/json' }
});
}
}