import * as plugins from './cloudflare.plugins.js'; import { logger } from './cloudflare.logger.js'; import * as interfaces from './interfaces/index.js'; // interfaces import { WorkerManager } from './cloudflare.classes.workermanager.js'; import { ZoneManager } from './cloudflare.classes.zonemanager.js'; export class CloudflareAccount { private authToken: string; public preselectedAccountId: string; public workerManager = new WorkerManager(this); public zoneManager = new ZoneManager(this); public apiAccount: plugins.cloudflare.Cloudflare; /** * constructor sets auth information on the CloudflareAccountInstance * @param optionsArg */ constructor(authTokenArg: string) { this.authToken = authTokenArg; this.apiAccount = new plugins.cloudflare.Cloudflare({ apiToken: this.authToken, }); } public async preselectAccountByName(nameArg: string) { const accounts = await this.convenience.listAccounts(); const account = accounts.find((accountArg) => { return accountArg.name === nameArg; }); if (account) { this.preselectedAccountId = account.id; } else { throw new Error(`account with name ${nameArg} not found`); } } public convenience = { /** * listAccounts */ listAccounts: async () => { const accounts: plugins.ICloudflareTypes['Account'][] = []; for await (const account of this.apiAccount.accounts.list()) { accounts.push(account as interfaces.ICloudflareApiAccountObject); } return accounts; }, /** * gets a zone id of a domain from cloudflare * @param domainName */ getZoneId: async (domainName: string) => { const domain = new plugins.smartstring.Domain(domainName); const zoneArray = await this.convenience.listZones(domain.zoneName); const filteredResponse = zoneArray.filter((zoneArg) => { return zoneArg.name === domainName; }); if (filteredResponse.length >= 1) { return filteredResponse[0].id; } else { logger.log('error', `the domain ${domainName} does not appear to be in this account!`); throw new Error(`the domain ${domainName} does not appear to be in this account!`); } }, /** * gets a record * @param domainNameArg * @param typeArg */ getRecord: async ( domainNameArg: string, typeArg: plugins.tsclass.network.TDnsRecordType ): Promise => { const domain = new plugins.smartstring.Domain(domainNameArg); const recordArrayArg = await this.convenience.listRecords(domain.zoneName); const filteredResponse = recordArrayArg.filter((recordArg) => { return recordArg.type === typeArg && recordArg.name === domainNameArg; }); return filteredResponse[0]; }, /** * creates a record */ createRecord: async ( domainNameArg: string, typeArg: plugins.tsclass.network.TDnsRecordType, contentArg: string, ttlArg = 1 ): Promise => { const domain = new plugins.smartstring.Domain(domainNameArg); const zoneId = await this.convenience.getZoneId(domain.zoneName); const response = await this.apiAccount.dns.records.create({ zone_id: zoneId, type: typeArg as any, name: domain.fullName, content: contentArg, ttl: ttlArg, }) return response; }, /** * removes a record from Cloudflare * @param domainNameArg * @param typeArg */ removeRecord: async ( domainNameArg: string, typeArg: plugins.tsclass.network.TDnsRecordType ): Promise => { const domain = new plugins.smartstring.Domain(domainNameArg); const zoneId = await this.convenience.getZoneId(domain.zoneName); const records = await this.convenience.listRecords(domain.zoneName); const recordToDelete = records.find((recordArg) => { return recordArg.name === domainNameArg && recordArg.type === typeArg; }); if (recordToDelete) { await this.apiAccount.dns.records.delete(recordToDelete.id, { zone_id: zoneId, }); } else { logger.log('warn', `record ${domainNameArg} of type ${typeArg} not found`); } }, /** * cleanrecord allows the cleaning of any previous records to avoid unwanted sideeffects */ cleanRecord: async (domainNameArg: string, typeArg: plugins.tsclass.network.TDnsRecordType) => { console.log(`cleaning record for ${domainNameArg}`); const records = await this.convenience.listRecords(domainNameArg); const recordsToDelete = records.filter((recordArg) => { return recordArg.type === typeArg; }); for (const recordToDelete of recordsToDelete) { await this.apiAccount.dns.records.delete(recordToDelete.id, { zone_id: recordToDelete.zone_id, }); } }, /** * updates a record * @param domainNameArg * @param typeArg * @param valueArg */ updateRecord: async ( domainNameArg: string, typeArg: plugins.tsclass.network.TDnsRecordType, valueArg ) => { // TODO: implement const domain = new plugins.smartstring.Domain(domainNameArg); }, /** * list all records of a specified domain name * @param domainNameArg - the domain name that you want to get the records from */ listRecords: async (domainNameArg: string) => { const domain = new plugins.smartstring.Domain(domainNameArg); const zoneId = await this.convenience.getZoneId(domain.zoneName); const records: plugins.ICloudflareTypes['Record'][] = []; for await (const record of this.apiAccount.dns.records.list({ zone_id: zoneId, })) { records.push(record); } return records; }, /** * list all zones in the associated authenticated account * @param domainName */ listZones: async (domainName?: string) => { const zones: plugins.ICloudflareTypes['Zone'][] = []; for await (const zone of this.apiAccount.zones.list()) { zones.push(zone); } return zones; }, /** * purges a zone */ purgeZone: async (domainName: string): Promise => { const domain = new plugins.smartstring.Domain(domainName); const zoneId = await this.convenience.getZoneId(domain.zoneName); await this.apiAccount.cache.purge({ zone_id: zoneId, purge_everything: true, }); }, // acme convenience functions acmeSetDnsChallenge: async (dnsChallenge: plugins.tsclass.network.IDnsChallenge) => { await this.convenience.cleanRecord(dnsChallenge.hostName, 'TXT'); await this.convenience.createRecord( dnsChallenge.hostName, 'TXT', dnsChallenge.challenge, 120 ); }, acmeRemoveDnsChallenge: async (dnsChallenge: plugins.tsclass.network.IDnsChallenge) => { await this.convenience.removeRecord(dnsChallenge.hostName, 'TXT'); }, }; }