-
Notifications
You must be signed in to change notification settings - Fork 77
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f5a9ae3
commit 4744e4d
Showing
2 changed files
with
112 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
// DoH servers list | ||
export enum DoHServer { | ||
// Google Public DNS | ||
Google = "https://dns.google/resolve", | ||
// Cloudflare DNS | ||
Cloudflare = "https://cloudflare-dns.com/dns-query", | ||
} | ||
|
||
/** | ||
* DNS over HTTPS (DoH) resolver | ||
* | ||
* @export | ||
* @class DoH | ||
*/ | ||
export class DoH { | ||
|
||
// DNS response codes | ||
static DoHStatusNoError = 0; | ||
// DNS RR types | ||
static DoHTypeTXT = 16; | ||
|
||
/** | ||
* Resolve DKIM public key from DNS | ||
* | ||
* @static | ||
* @param {string} name DKIM record name (e.g. 20230601._domainkey.gmail.com) | ||
* @param {string} DNSServer DNS over HTTPS API URL | ||
* @return {*} {(Promise<string | null>)} DKIM public key or null if not found | ||
* @memberof DoH | ||
*/ | ||
public static async resolveDKIMPublicKey(name: string, DNSServer: string): Promise<string | null> { | ||
if (!DNSServer.startsWith('https://')) { | ||
DNSServer = 'https://' + DNSServer; | ||
} | ||
if (DNSServer.endsWith('/')) { | ||
DNSServer = DNSServer.slice(0, -1); | ||
} | ||
const resp = await fetch( | ||
DNSServer + "?" + | ||
new URLSearchParams({ | ||
name: name, | ||
// DKIM public key record type is TXT | ||
type: DoH.DoHTypeTXT.toString(), | ||
}), | ||
{ | ||
headers: { | ||
"accept": "application/dns-json", | ||
} | ||
} | ||
); | ||
if (resp.status === 200) { | ||
const out = await resp.json(); | ||
if (typeof out === 'object' && out !== null && 'Status' in out && 'Answer' in out) { | ||
const resp = out as DoHResponse; | ||
if (resp.Status === DoH.DoHStatusNoError && resp.Answer.length > 0) { | ||
for (const ans of resp.Answer) { | ||
if (ans.type === DoH.DoHTypeTXT) { | ||
let DKIMRecord = ans.data; | ||
/* | ||
Remove all double quotes | ||
Some DNS providers wrap TXT records in double quotes, | ||
and others like Cloudflare may include them. According to | ||
TXT (potentially multi-line) and DKIM (Base64 data) standards, | ||
we can directly remove all double quotes from the DKIM public key. | ||
*/ | ||
DKIMRecord = DKIMRecord.replace(/"/g, ''); | ||
return DKIMRecord; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
return null; | ||
} | ||
} | ||
|
||
interface DoHResponse { | ||
Status: number; // NOERROR - Standard DNS response code (32 bit integer). | ||
TC: boolean; // Whether the response is truncated | ||
AD: boolean; // Whether all response data was validated with DNSSEC | ||
CD: boolean; // Whether the client asked to disable DNSSEC | ||
Question: Question[]; | ||
Answer: Answer[]; | ||
Comment: string; | ||
} | ||
|
||
interface Question { | ||
name: string; // FQDN with trailing dot | ||
type: number; // A - Standard DNS RR type. 5:CNAME, 16:TXT | ||
} | ||
|
||
interface Answer { | ||
name: string; // Always matches name in the Question section | ||
type: number; // A - Standard DNS RR type. 5:CNAME, 16:TXT | ||
TTL: number; // Record's time-to-live in seconds | ||
data: string; // Record data | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters