.github/000077500000000000000000000000001516077042000124205ustar00rootroot00000000000000.github/workflows/000077500000000000000000000000001516077042000144555ustar00rootroot00000000000000.github/workflows/build.yml000066400000000000000000000016761516077042000163110ustar00rootroot00000000000000# 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 .gitignore000066400000000000000000000003301516077042000130440ustar00rootroot00000000000000/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 .npmignore000066400000000000000000000002421516077042000130550ustar00rootroot00000000000000/.idea /artifacts /build /test /node_modules /*.iml /*.ipr /*.iws /.travis.yml /.scrutinizer.yml /Gruntfile.js /*.lock *.log /corifeus-boot.json /.github /.vscodeGruntfile.js000066400000000000000000000004231516077042000133540ustar00rootroot00000000000000module.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); };LICENSE000066400000000000000000000023241516077042000120660ustar00rootroot00000000000000 @license p3x-freenom v2024.4.114 🌐 Freenom API - Promise and auto renew expiring domains https://corifeus.com/freenom Copyright (c) 2024 Patrik Laszlo / P3X / Corifeus and contributors. MIT 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.md000066400000000000000000000075131516077042000123450ustar00rootroot00000000000000[//]: #@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.114 **Bugs are evident™ - MATRIX️** ### NodeJS LTS is supported ### Built on NodeJs version ```txt v20.11.1 ``` # 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 --- 🙏 This is an open-source project. Star this repository, if you like it, or even donate to maintain the servers and the development. Thank you so much! Possible, this server, rarely, is down, please, hang on for 15-30 minutes and the server will be back up. All my domains ([patrikx3.com](https://patrikx3.com) and [corifeus.com](https://corifeus.com)) could have minor errors, since I am developing in my free time. However, it is usually stable. **Note about versioning:** Versions are cut in Major.Minor.Patch schema. Major is always the current year. Minor is either 4 (January - June) or 10 (July - December). Patch is incremental by every build. If there is a breaking change, it should be noted in the readme. --- [**P3X-FREENOM**](https://corifeus.com/freenom) Build v2024.4.114 [![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.json000066400000000000000000000021031516077042000133420ustar00rootroot00000000000000{ "name": "p3x-freenom", "version": "2024.4.114", "corifeus": { "prefix": "p3x-", "publish": true, "type": "p3x", "code": "Mafia", "nodejs": "v20.11.1", "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.123" }, "dependencies": { "corifeus-utils": "^2024.4.115" }, "engines": { "node": ">=12.13.0" } }src/000077500000000000000000000000001516077042000116475ustar00rootroot00000000000000src/endpoint/000077500000000000000000000000001516077042000134675ustar00rootroot00000000000000src/endpoint/v2/000077500000000000000000000000001516077042000140165ustar00rootroot00000000000000src/endpoint/v2/domain.js000066400000000000000000000022641516077042000156270ustar00rootroot00000000000000const 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.js000066400000000000000000000013251516077042000165240ustar00rootroot00000000000000const 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.js000066400000000000000000000001451516077042000160140ustar00rootroot00000000000000module.exports.ping = (exec) => { return async () => { return await exec('ping'); } }src/index.js000066400000000000000000000056171516077042000133250ustar00rootroot00000000000000const 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.js000066400000000000000000000004561516077042000127600ustar00rootroot00000000000000module.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.js000066400000000000000000000050631516077042000136510ustar00rootroot00000000000000const 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/000077500000000000000000000000001516077042000120375ustar00rootroot00000000000000test/scripts/000077500000000000000000000000001516077042000135265ustar00rootroot00000000000000test/scripts/glue.js000077500000000000000000000030551516077042000150260ustar00rootroot00000000000000#!/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.js000066400000000000000000000013041516077042000146300ustar00rootroot00000000000000const 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.js000077500000000000000000000064531516077042000150560ustar00rootroot00000000000000#!/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();