.github/000077500000000000000000000000001516644370500124315ustar00rootroot00000000000000.github/workflows/000077500000000000000000000000001516644370500144665ustar00rootroot00000000000000.github/workflows/build.yml000066400000000000000000000016761516644370500163220ustar00rootroot00000000000000# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions name: build on: schedule: - cron: '0 0 1 * *' push: branches: [ master ] pull_request: branches: [ master ] jobs: build: runs-on: ubuntu-latest strategy: matrix: node-version: ['lts/*'] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ steps: - uses: actions/checkout@v2 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v2 with: node-version: ${{ matrix.node-version }} - run: npm i -g grunt-cli - run: npm install - run: grunt .gitignore000066400000000000000000000003301516644370500130550ustar00rootroot00000000000000/build /node_modules /*.log .idea/workspace.xml .idea/tasks.xml .idea/profiles_settings.xml .idea/inspectionProfiles/Project_Default.xml .idea/inspectionProfiles/profiles_settings.xml node_modules/.yarn-integrity .npmignore000066400000000000000000000002421516644370500130660ustar00rootroot00000000000000/.idea /artifacts /build /test /node_modules /*.iml /*.ipr /*.iws /.travis.yml /.scrutinizer.yml /Gruntfile.js /*.lock *.log /corifeus-boot.json /.github /.vscodeGruntfile.js000066400000000000000000000004231516644370500133650ustar00rootroot00000000000000module.exports = (grunt) => { const builder = require(`corifeus-builder`); const loader = new builder.loader(grunt); loader.js({ replacer: { type: 'p3x', }, }); grunt.registerTask('default', builder.config.task.build.js); };LICENSE000066400000000000000000000020131516644370500120720ustar00rootroot00000000000000MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.README.md000066400000000000000000000103471516644370500123550ustar00rootroot00000000000000[//]: #@corifeus-header [![NPM](https://img.shields.io/npm/v/p3x-freenom.svg)](https://www.npmjs.com/package/p3x-freenom) [![Donate for Corifeus / P3X](https://img.shields.io/badge/Donate-Corifeus-003087.svg)](https://paypal.me/patrikx3) [![Contact Corifeus / P3X](https://img.shields.io/badge/Contact-P3X-ff9900.svg)](https://www.patrikx3.com/en/front/contact) [![Corifeus @ Facebook](https://img.shields.io/badge/Facebook-Corifeus-3b5998.svg)](https://www.facebook.com/corifeus.software) [![Uptime Robot ratio (30 days)](https://img.shields.io/uptimerobot/ratio/m780749701-41bcade28c1ea8154eda7cca.svg)](https://stats.uptimerobot.com/9ggnzcWrw) # 🌐 Freenom API - Promise and auto renew expiring domains v2024.4.122 **Bugs are evident™ - MATRIX️** ### NodeJS LTS is supported ### Built on NodeJs version ```txt v22.1.0 ``` # Description [//]: #@corifeus-header:end ## To be able to register and renew FREE DOMAINS Before, we were able to register and renew with free domains, but by now, these functions are allowed and working ONLY with PAID domains. ### Some links http://www.freenom.com/en/resellers.html http://www.freenom.com/en/termsandconditions.html ## API http://www.freenom.com/en/freenom-api.html I am using these only right now. So no other functions but very easy to add in and Promise based. ```js const Freenom = require('p3x-freenom'); const freenom = await Freenom({ email: 'p3x@corifeus', password: 'password', }); await freenom.service.ping(); await freenom.domain.search({ domainname: 'patrikx3.com', domaintype: 'FREE' }) await freenom.domain.delete({ domainname: 'random.tk')); await freenom.domain.register({ domainname: [ 'random.tk', 'random1.tk', 'random2.tk', ], domaintype: 'FREE', period: '1Y', nameserver: [ 'ns1.ns.tk', 'ns2.ns.tk', ] }) await freenom.domain.delete, { domainname: domains }) // if you have no domain in the list, instead of // giving an empty list, it shows and error!!! // so make sure you have one in the domain list // because freenom.domain.expiringRenew will of course // throw an error as well!!! await freenom.domain.list() ``` # The good extra functions It automatically renew the free domains (it checks if it is within 14 days expiry and then does it). ```js // just a helper, you don't relly need it const renewable = await freenom.domain.expiring({ expiry: '60 days', }); // the magic await freenom.domain.expiringRenew({ period: '12M', }) ``` [//]: #@corifeus-footer --- ## Support Our Open-Source Project ❤️ If you appreciate our work, consider starring this repository or making a donation to support server maintenance and ongoing development. Your support means the world to us—thank you! ### Server Availability Our server may occasionally be down, but please be patient. Typically, it will be back online within 15-30 minutes. We appreciate your understanding. ### About My Domains All my domains, including [patrikx3.com](https://patrikx3.com) and [corifeus.com](https://corifeus.com), are developed in my spare time. While you may encounter minor errors, the sites are generally stable and fully functional. ### Versioning Policy **Version Structure:** We follow a Major.Minor.Patch versioning scheme: - **Major:** Corresponds to the current year. - **Minor:** Set as 4 for releases from January to June, and 10 for July to December. - **Patch:** Incremental, updated with each build. **Important Changes:** Any breaking changes are prominently noted in the readme to keep you informed. --- [**P3X-FREENOM**](https://corifeus.com/freenom) Build v2024.4.122 [![NPM](https://img.shields.io/npm/v/p3x-freenom.svg)](https://www.npmjs.com/package/p3x-freenom) [![Donate for Corifeus / P3X](https://img.shields.io/badge/Donate-Corifeus-003087.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=QZVM4V6HVZJW6) [![Contact Corifeus / P3X](https://img.shields.io/badge/Contact-P3X-ff9900.svg)](https://www.patrikx3.com/en/front/contact) [![Like Corifeus @ Facebook](https://img.shields.io/badge/LIKE-Corifeus-3b5998.svg)](https://www.facebook.com/corifeus.software) [//]: #@corifeus-footer:end package.json000066400000000000000000000021021516644370500133520ustar00rootroot00000000000000{ "name": "p3x-freenom", "version": "2024.4.122", "corifeus": { "prefix": "p3x-", "publish": true, "type": "p3x", "code": "Mafia", "nodejs": "v22.1.0", "opencollective": false, "reponame": "freenom", "build": true }, "license": "MIT", "description": "🌐 Freenom API - Promise and auto renew expiring domains", "main": "src/index.js", "directories": { "test": "test" }, "scripts": { "test": "grunt" }, "repository": { "type": "git", "url": "git+https://github.com/patrikx3/freenom.git" }, "keywords": [ "freenom", "promise", "api" ], "author": "Patrik Laszlo ", "bugs": { "url": "https://github.com/patrikx3/freenom/issues" }, "homepage": "https://corifeus.com/freenom", "devDependencies": { "corifeus-builder": "^2024.4.140" }, "dependencies": { "corifeus-utils": "^2024.4.123" }, "engines": { "node": ">=12.13.0" } }src/000077500000000000000000000000001516644370500116605ustar00rootroot00000000000000src/endpoint/000077500000000000000000000000001516644370500135005ustar00rootroot00000000000000src/endpoint/v2/000077500000000000000000000000001516644370500140275ustar00rootroot00000000000000src/endpoint/v2/domain.js000066400000000000000000000022641516644370500156400ustar00rootroot00000000000000const search = (exec) => { return async (body) => { return await exec({ service: 'domain', func: 'search', body: body }); } } const register = (exec) => { return async (body) => { return await exec({ service: 'domain', func: 'register', method: 'POST', body: body }) } } const _delete = (exec) => { return async (body) => { return await exec({ service: 'domain', func: 'delete', method: 'DELETE', body: body }) } } const list = (exec) => { return async (body) => { return await exec({ service: 'domain', func: 'list', method: 'GET', body: body, }) } } const renew = (exec) => { return async (body) => { return await exec({ service: 'domain', func: 'renew', method: 'POST', body: body, }) } } module.exports.list = list; module.exports.search = search; module.exports.register = register; module.exports.delete = _delete module.exports.renew = renewsrc/endpoint/v2/nameserver.js000066400000000000000000000013251516644370500165350ustar00rootroot00000000000000const list = (exec) => { return async (body) => { return await exec({ service: 'nameserver', func: 'list', body: body }); } } const _delete = (exec) => { return async (body) => { return await exec({ service: 'nameserver', func: 'delete', method: 'DELETE', body: body }) } } const register = (exec) => { return async (body) => { return await exec({ service: 'nameserver', func: 'register', method: 'PUT', body: body }) } } module.exports.list = list; module.exports.delete = _delete; module.exports.register = register;src/endpoint/v2/service.js000066400000000000000000000001451516644370500160250ustar00rootroot00000000000000module.exports.ping = (exec) => { return async () => { return await exec('ping'); } }src/index.js000066400000000000000000000056171516644370500133360ustar00rootroot00000000000000const utils = require('corifeus-utils'); const querystring = require('querystring'); const mz = require('mz'); const path = require('path'); // http://www.freenom.com/en/freenom-api.html module.exports = async function (options) { let { email, password, debug, version } = options; if (!version) { version = 'v2'; } const baseUrl = 'https://api.freenom.com/v2'; const endpointDir = `${__dirname}/endpoint/${version}`; const endpoints = await mz.fs.readdir(endpointDir) const endpointServices = {}; endpoints.forEach((endpoint) => { const requireName = path.basename(endpoint, '.js'); // console.log(requireName); endpointServices[requireName] = require(`${endpointDir}/${endpoint}`); }) if (debug) { console.log('----------------------------') console.log('endpointService') console.log(endpointServices) console.log(); } return new function(options) { if (debug) { console.log('----------------------------') console.log('Settings') console.log(this) console.log(); } const exec = async (options) => { if (typeof options === 'string') { options = { func: options, } } let { service, func, method, body } = options; service = service || 'service'; method = method || "GET"; body = body || {}; body.email = email; body.password = password; if (debug && !body.hasOwnProperty('test_mode')) { body.test_mode = 1; } let url = `${baseUrl}/${service}/${func}`; Object.keys(body).forEach(key => { if (body[key] === undefined) { delete body[key]; } }) url += '?' + querystring.stringify(body); if (debug) { console.log('----------------------------'); console.log('Request') console.log(method, url, body) } const response = await utils.http.request({ url: url, method: method, }) return response; }; const service = require('./service');; Object.keys(endpointServices).forEach((endpointService) => { service[endpointService] = service[endpointService] || {}; Object.keys(endpointServices[endpointService]).forEach(endpointServiceMethod => { service[endpointService][endpointServiceMethod] = endpointServices[endpointService][endpointServiceMethod](exec); }) }) if (debug) { console.log('----------------------------'); console.log('service') console.log(service) } return service; } }src/lib.js000066400000000000000000000004561516644370500127710ustar00rootroot00000000000000module.exports.stringEightNumbersToDate = (string) => { const year = parseInt(string.substring(0, 4)); const month = parseInt(string.substr(4, 2)); const day = parseInt(string.substr(6, 2)); //console.log(string, year, month, day); return new Date(Date.UTC( year, month -1, day )) }src/service.js000066400000000000000000000050631516644370500136620ustar00rootroot00000000000000const utils = require('corifeus-utils'); const lib = require('./lib'); const service = { domain: {}, }; service.domain.active = async (options) => { const response = await service.domain.list(options); /* { status: 'ACTIVE', expirationdate: '20170729', registrationdate: '20160729', domaintype: 'PAID', domainname: 'corifeus.com' }, */ const domains = {}; const generateDate = (string) => { const year = parseInt(string.substring(0, 4)); const month = parseInt(string.substr(4, 2)); const day = parseInt(string.substr(6, 2)); //console.log(string, year, month, day); return new Date(Date.UTC( year, month -1, day )) } response.body.domain.forEach((domain) => { if (domain.status !== 'ACTIVE') { return; } domain.registration = lib.stringEightNumbersToDate(domain.registrationdate); domain.expiration = lib.stringEightNumbersToDate(domain.expirationdate); delete domain.registrationdate; delete domain.expirationdate; if (!domains.hasOwnProperty(domain.domainname)) { domains[domain.domainname] = domain; } }) return Object.values(domains); } service.domain.expiring = async(options) => { let expiry = '14 days'; if (options.hasOwnProperty('expiry')) { expiry = options.expiry; delete options.expiry; } const maxExpiry = utils.time.span(expiry); let active = await service.domain.active(options); active = active.map((domain) => { domain.expiry = utils.time.verbose( domain.expiration.getTime(), domain.registration.getTime() ) return domain; }) return active.filter((domain) => { // console.log(maxExpiry, domain.expiry.leftMs); // console.log(utils.time.msParse(maxExpiry), utils.time.msParse(domain.expiry.leftMs)); return domain.expiry.leftMs < maxExpiry; }).map((domain) => { const expiry = domain.expiry; delete domain.expiry; domain.left = expiry.left; domain.leftMs = expiry.leftMs; return domain; }); } service.domain.expiringRenew = async(options) => { const renewable = await service.domain.expiring(options); const result = {}; await renewable.forEachAsync(async (domain) => { const response = await service.domain.renew(Object.assign({ domainname: domain.domainname, }, options)); result[domain.domainname] = response.body; }) return result; } module.exports = service;test/000077500000000000000000000000001516644370500120505ustar00rootroot00000000000000test/scripts/000077500000000000000000000000001516644370500135375ustar00rootroot00000000000000test/scripts/glue.js000077500000000000000000000030551516644370500150370ustar00rootroot00000000000000#!/usr/bin/env node const Freenom = require('../../src'); const utils = require('corifeus-utils'); const lib = require('./lib'); const start = async() => { const freenom = await lib.start(); /* await lib.test(freenom.nameserver.delete, { domainname: 'namesystem.tk', hostname: 'IPV6.NAMESYSTEM.TK', }) */ const ns = await lib.test(freenom.nameserver.list, { domainname: 'namesystem.tk' }); /* const response = await utils.http.request({ url: 'https://v4.ident.me/.json', localAddress: '192.168.81.2', }) let ip = response.body.address; ip = '86.101.220.140'; const ns = await lib.test(freenom.nameserver.list, { domainname: 'namesystem.tk' }); await ns.body.nameserver.forEachAsync(async(ns) => { if (ns.ipaddress !== ip) { await lib.test(freenom.nameserver.register, { domainname: ns.domainname, hostname: ns.hostname, ipaddress: ip, test_mode: undefined, }) } }) */ /* const renewable = await lib.test(freenom.domain.expiring, { expiry: '60 days', test_mode: undefined }); const result = {}; await renewable.forEachAsync(async (domain) => { const response = await lib.test(freenom.domain.renew, { domainname: domain.domainname, test_mode: undefined, period: '1Y' }); result[domain.domainname] = response.body; }) console.log(result); */ } start();test/scripts/lib.js000066400000000000000000000013041516644370500146410ustar00rootroot00000000000000const Freenom = require('../../src'); const utils = require('corifeus-utils'); module.exports.start = async() => { const freenom = await Freenom({ email: 'alabard@gmail.com', password: process.argv[2], debug: true, }); return freenom } module.exports.test = async(func, options) => { console.log('------------------------------------------'); if (options !== undefined) { console.log('Request', options) console.log(); } const result = await func(options); if (result.hasOwnProperty('body')) { console.log('Response', result.body); console.log(); } else { console.log(result); } return result; } test/scripts/test.js000077500000000000000000000064531516644370500150670ustar00rootroot00000000000000#!/usr/bin/env node const Freenom = require('../../src'); const utils = require('corifeus-utils'); const lib = require('./lib'); const start = async() => { try { const domainTest = 'p3x-' + await utils.random.lower(6) + '.tk' const freenom = await lib.start(); /* await lib.test(freenom.service.ping) await lib.test(freenom.domain.search, { domainname: domainTest, domaintype: 'FREE' }); try { await lib.test(freenom.domain.delete, { domainname: domainTest }) } catch(e) { console.error('delete domain', e) } */ const domains = [ // prefix + await utils.random.lower(6) + '.tk', // prefix + await utils.random.lower(6) + '.tk', // prefix + await utils.random.lower(6) + '.tk', domainTest ]; const domaintype = 'FREE'; const period = '1Y'; /* await lib.test(freenom.domain.search, { domainname: domains, domaintype: domaintype, }) */ await lib.test(freenom.domain.register, { domainname: domains, domaintype: domaintype, period: '3M', owner_id: 'patrikx3', nameserver: [ 'ns1.afraid.org', 'ns2.afraid.org', 'ns3.afraid.org', 'ns4.afraid.org', ] }) await lib.test(freenom.domain.delete, { domainname: domains }) // await lib.test(freenom.domain.delete, { domainname: 'p3x-ns.tk', test_mode: undefined }) await lib.test(freenom.domain.active, { test_mode: undefined }); await lib.test(freenom.domain.expiringRenew, { expiry: '60 days', // test_mode: undefined, //period: '1Y', }) const ns = await lib.test(freenom.nameserver.list, { domainname: domainTest }); /* const response = await utils.http.request({ url: 'https://v4.ident.me/.json', localAddress: '192.168.81.2', }) let ip = response.body.address; ip = '86.101.220.140'; const ns = await lib.test(freenom.nameserver.list, { domainname: 'namesystem.tk' }); await ns.body.nameserver.forEachAsync(async(ns) => { if (ns.ipaddress !== ip) { await lib.test(freenom.nameserver.register, { domainname: ns.domainname, hostname: ns.hostname, ipaddress: ip, test_mode: undefined, }) } }) */ const renewable = await lib.test(freenom.domain.expiring, { expiry: '60 days', test_mode: undefined }); const result = {}; await renewable.forEachAsync(async (domain) => { const response = await lib.test(freenom.domain.renew, { domainname: domain.domainname, test_mode: undefined, period: '1Y' }); result[domain.domainname] = response.body; }) console.log(result); } catch(e) { console.error(e) } } start();