-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathqueries.ts
More file actions
97 lines (88 loc) · 3.66 KB
/
queries.ts
File metadata and controls
97 lines (88 loc) · 3.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
const sanitizer = (sanitization: (text: string) => string) =>
(substrings: TemplateStringsArray, ...values: string[]) =>
substrings.reduce((previous, current, index) => previous + current + sanitization(values[index] || ''), '');
const url = sanitizer(encodeURIComponent);
const delay = (millis: number) => new Promise<void>(resolve => setTimeout(resolve, millis));
import fetch from 'node-fetch';
import * as tls from 'tls';
export async function sslTest(query: { host: string }) {
// see:
// https://github.com/ssllabs/ssllabs-scan/blob/master/ssllabs-api-docs-v3.md#invoke-assessment-and-check-progress
interface SslLabsResponse {
status: 'IN_PROGRESS' | 'READY',
endpoints: {
ipAddress: string;
grade: 'A+' | 'A' | 'F' | 'T';
details: {
supportsAlpn: true,
protocols: {
name: string;
version: string;
}[]
}
}[]
};
let startNew = 'on';
do {
const response = await fetch(url`https://api.ssllabs.com/api/v3/analyze?host=${query.host}&startNew=${startNew}&all=done`);
const json = await response.json() as SslLabsResponse;
if (json.status === 'READY') {
return {
endpoints: json.endpoints
};
}
await delay(10000);
startNew = 'off';
} while (true);
}
export async function dnssec(query: { host: string }) {
const response = await fetch(url`https://dns.google.com/resolve?name=${query.host}`);
// see: https://developers.google.com/speed/public-dns/docs/dns-over-https#dns_response_in_json
const json: { AD: boolean } = await response.json();
return {
secure: json.AD
};
}
export async function headers(query: { url: string }) {
const response = await fetch(query.url);
return {
get(header: string) {
const value = response.headers.get(header) as string;
return value.split(/;\s*/g).reduce((previous, current) => {
if (current.includes('=')) {
const parts = current.split('=');
previous[parts[0]] = parts[1];
} else {
previous[current] = null;
}
return previous;
}, Object.create(null) as { [key: string]: string | null });
}
};
}
export async function caaRecordTags(query: { hostname: string }) {
const response = await fetch(url`https://dns.google.com/resolve?name=${query.hostname}&type=CAA`);
const json: { Answer: { data: string }[] } = await response.json();
// records have structure: "flag tag value"
// this function retrieves all configured tags
return json.Answer.map(answer => answer.data.split(' ')[1]);
}
export async function dmarcSpf(query: { hostname: string }) {
const response = await fetch(url`https://app.valimail.com/domain_checker/v1/status/${query.hostname}.json`);
const json: { status: { [metric: string]: 'ok' | 'warning' | 'error' } } = await response.json();
return Object.values(json.status).every(value => value === 'ok');
}
export function certificateValidityDays(query: { hostname: string, port: number }): Promise<number> {
return new Promise((resolve, reject) => {
const socket = tls.connect({
host: query.hostname,
port: query.port
}, () => {
const peerCertificate = socket.getPeerCertificate();
const validTo = Date.parse(peerCertificate.valid_to);
socket.end();
resolve((validTo - Date.now()) / (24 * 3600 * 1000));
});
socket.on('error', reject);
});
}