Skip to content

Commit

Permalink
yusss
Browse files Browse the repository at this point in the history
  • Loading branch information
sysop committed Nov 20, 2023
0 parents commit 6d22d74
Show file tree
Hide file tree
Showing 11 changed files with 822 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
9 changes: 9 additions & 0 deletions ReadMe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
## MX and SPF Record Updater

A script to loop through our million domains to change the MX and SPF records for each domain.

## Instructions

- Edit the config file.
- `npm i`
- `npm run dev` **OR** `npm run build && npm start`
20 changes: 20 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"dependencies": {
"@types/node": "^20.9.2",
"axios": "^1.6.2",
"nodemon": "^3.0.1",
"ts-node": "^10.9.1",
"typescript": "^5.2.2"
},
"scripts": {
"dev": "cd src && nodemon --exec ts-node main.ts",
"build": "tsc --build",
"start": "cd dist && node main.js"
},
"name": "cf-record-updater",
"description": "A script to loop through our million domains to change the MX and SPF records.",
"version": "0.0.69",
"main": "main.js",
"author": "Dylan James <github/team-tritan>",
"license": "MIT"
}
5 changes: 5 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const API_ENDPOINT = "https://api.cloudflare.com/client/v4";
export const API_KEY = "";
export const EMAIL = "";
export const NEW_MX = "";
export const NEW_SPF = "";
40 changes: 40 additions & 0 deletions src/lib/getDomains.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"use strict";

import axios, { AxiosResponse } from "axios";
import { EMAIL, API_KEY, API_ENDPOINT } from "../config";

interface Zone {
id: string;
name: string;
}

export interface ZoneResponse {
result: Zone[];
}

async function getDomains(): Promise<string[]> {
try {
const response: AxiosResponse<ZoneResponse> = await axios.get(
`${API_ENDPOINT}/zones`,
{
headers: getRequestHeaders(),
}
);

const domains = response.data.result.map(({ name }) => name);

return domains;
} catch (error: any) {
throw new Error(`Error getting domains: ${error.message}`);
}
}

function getRequestHeaders() {
return {
"X-Auth-Email": EMAIL,
"X-Auth-Key": API_KEY,
"Content-Type": "application/json",
};
}

export default getDomains;
44 changes: 44 additions & 0 deletions src/lib/getRecords.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"use strict";

import axios, { AxiosResponse } from "axios";
import { EMAIL, API_KEY, API_ENDPOINT } from "../config";

export interface DnsRecord {
id: string;
type: string;
name: string;
content: string;
}

interface DnsRecordResponse {
result: DnsRecord[];
}

async function getDnsRecords(
zoneId: string,
type: string,
name: string
): Promise<DnsRecord[]> {
try {
const response = await axios.get<DnsRecordResponse>(
`${API_ENDPOINT}/zones/${zoneId}/dns_records?type=${type}&name=${name}`,
{
headers: getRequestHeaders(),
}
);

return response.data.result;
} catch (error: any) {
throw new Error(`Error getting DNS records: ${error.message}`);
}
}

function getRequestHeaders() {
return {
"X-Auth-Email": EMAIL,
"X-Auth-Key": API_KEY,
"Content-Type": "application/json",
};
}

export default getDnsRecords;
39 changes: 39 additions & 0 deletions src/lib/getUserId.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"use strict";

import axios, { AxiosResponse } from "axios";
import { EMAIL, API_KEY, API_ENDPOINT } from "../config";

interface UserResponse {
result: { id: string };
}

async function getUserId(): Promise<string> {
try {
const response: AxiosResponse<UserResponse> = await axios.get(
`${API_ENDPOINT}/user`,
{
headers: getRequestHeaders(),
}
);

const userId = response.data.result.id;

if (userId === "null") {
throw new Error("Failed API auth.");
}

return userId;
} catch (error: any) {
throw new Error(`Error getting user ID: ${error.message}`);
}
}

function getRequestHeaders() {
return {
"X-Auth-Email": EMAIL,
"X-Auth-Key": API_KEY,
"Content-Type": "application/json",
};
}

export default getUserId;
130 changes: 130 additions & 0 deletions src/lib/updateRecords.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
"use strict";

import axios, { AxiosResponse } from "axios";
import { API_KEY, API_ENDPOINT, EMAIL, NEW_MX, NEW_SPF } from "../config";
import getDnsRecords, { DnsRecord } from "./getRecords";
import { ZoneResponse } from "./getDomains";

async function updateMxRecord(
zoneId: string,
domain: string,
currentMx: DnsRecord | null
): Promise<void> {
try {
if (currentMx) {
if (currentMx.content !== NEW_MX) {
await axios.put(
`${API_ENDPOINT}/zones/${zoneId}/dns_records/${currentMx.id}`,
{
type: "MX",
name: domain,
content: NEW_MX,
priority: 10,
ttl: 1,
proxied: false,
},
getRequestHeaders()
);
console.log(`Updated MX record for ${domain}`);
} else {
console.log(`MX record for ${domain} is already ${NEW_MX}`);
}
} else {
await axios.post(
`${API_ENDPOINT}/zones/${zoneId}/dns_records`,
{
type: "MX",
name: domain,
content: NEW_MX,
priority: 10,
ttl: 1,
proxied: false,
},
getRequestHeaders()
);
console.log(`Added MX record for ${domain}`);
}
} catch (error: any) {
throw new Error(`Error updating MX record for ${domain}: ${error.message}`);
}
}

async function updateSpfRecord(
zoneId: string,
domain: string,
currentSpf: DnsRecord | null
): Promise<void> {
try {
if (!currentSpf) {
await axios.post(
`${API_ENDPOINT}/zones/${zoneId}/dns_records`,
{
type: "TXT",
name: "@",
content: NEW_SPF,
ttl: 1,
proxied: false,
},
getRequestHeaders()
);
console.log(`Added SPF record for ${domain}`);
} else if (currentSpf.content.startsWith("v=spf1")) {
await axios.put(
`${API_ENDPOINT}/zones/${zoneId}/dns_records/${currentSpf.id}`,
{
type: "TXT",
name: "@",
content: NEW_SPF,
ttl: 1,
proxied: false,
},
getRequestHeaders()
);
console.log(`Updated SPF record for ${domain}`);
}
} catch (error: any) {
throw new Error(
`Error updating SPF record for ${domain}: ${error.message}`
);
}
}

async function updateDnsRecords(domain: string): Promise<void> {
try {
const zoneResponse: AxiosResponse<ZoneResponse> = await axios.get(
`${API_ENDPOINT}/zones?name=${domain}`,
getRequestHeaders()
);

const zoneId = zoneResponse.data.result[0]?.id;

if (!zoneId) {
console.error(`Error: Unable to fetch Zone ID for ${domain}. Skipping.`);
return;
}

const [currentMx, currentSpf] = await Promise.all([
getDnsRecords(zoneId, "MX", domain).then((records) => records[0] || null),
getDnsRecords(zoneId, "TXT", domain).then(
(records) => records[0] || null
),
]);

await updateMxRecord(zoneId, domain, currentMx);
await updateSpfRecord(zoneId, domain, currentSpf);
} catch (error: any) {
console.error(`Error updating records for ${domain}: ${error.message}`);
}
}

function getRequestHeaders() {
return {
headers: {
"X-Auth-Email": EMAIL,
"X-Auth-Key": API_KEY,
"Content-Type": "application/json",
},
};
}

export { updateDnsRecords, updateMxRecord, updateSpfRecord };
17 changes: 17 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"use strict";

import getUserId from "./lib/getUserId";
import getDomains from "./lib/getDomains";
import { updateDnsRecords } from "./lib/updateRecords";

(async () => {
try {
const userId = await getUserId();
const domains = await getDomains();

for (const domain of domains)
if (domain !== "as393577.net") await updateDnsRecords(domain);
} catch (error: any) {
console.error(`Error: ${error.message}`);
}
})();
Loading

0 comments on commit 6d22d74

Please sign in to comment.