'use strict'; const axios = require('axios'); const {DnsApi} = require('./common'); //like the options obj will always use domain data and type // change content to data // change name to domain class CloudFlare extends DnsApi{ static _keyMap = { token: {isRequired: true, type: 'string', isPrivate: true, displayName: 'API Token'}, } static displayName = 'CloudFlare' static displayIconHtml = ` ` // Cloud icon for cloudflare static displayIconUni = '' constructor(token){ super() this.token = token.token || token; } __typeCheck(type){ if(!type) return; if(!['A', 'MX', 'CNAME', 'ALIAS', 'TXT', 'NS', 'AAAA', 'SRV', 'TLSA', 'CAA', 'HTTPS', 'SVCB'].includes(type)) throw new Error(`${this.constructor.name} API: Invalid 'type' passed`) } async axios(method, ...args){ try{ let a = axios.create({ baseURL: 'https://api.cloudflare.com/client/v4/zones', headers: {Authorization: `Bearer ${this.token}`} }); return await a[method](...args); }catch(error){ if(!error.response) throw error; if(error.response.data && error.response.data.errors[0].code == 10000){ throw this.errors.unauthorized(); } throw this.errors.other(error.response.status, error.response.data.errors[0].message, error.response.data.errors[0].code, error); } } async listDomains(){ let res = await this.axios('get'); for(let domain of res.data.result){ domain.domain = domain.name domain.zoneId = domain.id } return res.data.result; } /* The API and the generic class interface have different opinions of what keys hold what data, the __parseOptions and __pastseRes normal the keys to what the class expects What the the API calls it : What the class wants it as. */ __apiKeyMap = { 'content': 'data', } //get records async getRecords(domain, options){ let res = await this.axios('get', `${domain.zoneId}/dns_records`, ); let records = this.__parseRes(res.data.result); if(!options) return records; return records.filter((record)=>{ let matchCount = 0 for(let key in options){ if(record[key] === options[key] && ++matchCount === Object.keys(options).length){ return true; } } }); } // CloudFlare names an apex record with the full domain (e.g. example.com). apexName(domainName){ return domainName; } async createRecord(domain, options){ try{ if(options.name === '@') options.name = this.apexName(domain.domain); let res = await this.axios('post', `${domain.zoneId}/dns_records`, this.__parseOptions(options, ['type', 'name', 'data']) ); return this.__parseRes([res.data.result])[0]; }catch(error){ if(error.APIcode == 81058){ return (await this.getRecords(domain, options))[0]; } throw error; } } async deleteRecordById(domain, id){ let res = await this.axios('delete', `${domain.zoneId}/dns_records/${id}`); } async deleteRecords(domain, options){ let records = await this.getRecords(domain, options) for(let record of records){ } return true; } } module.exports = CloudFlare; if(require.main === module){(async function(){try{ // let cf = new CloudFlare(""); // let domain = { // domain: "example.uk", // zoneId: "5eb25c12cd7d22f11252330a29a0dd77" // } // console.log(await cf.listDomains()) //content = ip //name = domain // console.log('get', await cf.getRecords(domain, {content: '172.206.221.130'})) // console.log('post', await cf.createRecord(domain, {name:'test', content: '10.0.0.1', type: "TXT"})) // console.log('delete', await cf.deleteRecordById(domain , "5c0e958c3406a34d011459933d538b78")) // console.log('delete', await cf.deleteRecords(domain, {type: 'A'})) }catch(error){ console.log('IIFE Error:', error) }})()}