/**
* Mozilla Observatory HTTP Security Headers Validator
* API: https://observatory-api.mdn.mozilla.net/api/v2/scan
*/
export interface MozillaObservatoryOptions {
/** Force a rescan (default: false, uses cached results if < 1 minute old) */
forceRescan?: boolean;
}
export interface MozillaObservatoryResponse {
id: number;
details_url: string;
algorithm_version: number;
scanned_at: string;
error: string | null;
grade: string;
score: number;
status_code: number;
tests_failed: number;
tests_passed: number;
tests_quantity: number;
}
export interface MozillaObservatoryResult {
tool: 'mozilla_observatory';
success: boolean;
grade: string;
score: number;
tests_passed: number;
tests_failed: number;
scanned_at: string;
details_url: string;
error?: string;
raw?: MozillaObservatoryResponse;
}
/**
* Analyze a website's HTTP security headers using Mozilla Observatory
* Rate limit: 1 scan per host per minute (returns cached results if exceeded)
*/
export async function analyzeMozillaObservatory(
url: string,
options: MozillaObservatoryOptions = {}
): Promise<MozillaObservatoryResult> {
try {
// Extract hostname from URL
const hostname = new URL(url).hostname;
// Build API URL
const apiUrl = `https://observatory-api.mdn.mozilla.net/api/v2/scan?host=${encodeURIComponent(hostname)}`;
// Make POST request to trigger/retrieve scan
const response = await fetch(apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
});
if (!response.ok) {
throw new Error(`Mozilla Observatory API error: ${response.status} ${response.statusText}`);
}
const data: MozillaObservatoryResponse = await response.json();
// Check for API errors
if (data.error) {
return {
tool: 'mozilla_observatory',
success: false,
grade: 'F',
score: 0,
tests_passed: 0,
tests_failed: 0,
scanned_at: data.scanned_at || new Date().toISOString(),
details_url: data.details_url || '',
error: data.error,
raw: data,
};
}
// Return formatted result
return {
tool: 'mozilla_observatory',
success: true,
grade: data.grade,
score: data.score,
tests_passed: data.tests_passed,
tests_failed: data.tests_failed,
scanned_at: data.scanned_at,
details_url: data.details_url,
raw: data,
};
} catch (error) {
return {
tool: 'mozilla_observatory',
success: false,
grade: 'F',
score: 0,
tests_passed: 0,
tests_failed: 0,
scanned_at: new Date().toISOString(),
details_url: '',
error: error instanceof Error ? error.message : String(error),
};
}
}