UNPKG

generate-ip

Version:

Randomly generate, format, and validate IPv4 + IPv6 + MAC addresses.

6 lines 9.09 kB
/** * © 2024–2026 Adam Lui & contributors under the MIT license. * Source: https://github.com/adamlui/js-utils/tree/main/generate-ip/src * Documentation: https://github.com/adamlui/js-utils/tree/main/generate-ip/docs */ Object.assign(globalThis.api??={},{name:"generate-ip",regex:{ipv4:/^ip$|v4/i,ipv6:/v6/i,mac:/^(?:mac|ethernet)$/i}});let ipv4={generate(t={}){var e="https://github.com/adamlui/js-utils/tree/main/generate-ip/docs/#ipv4generateoptions",r={verbose:!0,qty:1,sequential:!1,network:null};if(_log.prefix="ipv4.generate()",_validateOptions({options:t,defaultOptions:r,helpURL:e,exampleCall:"ipv4.generate({ verbose: false, qty: 3 })"})){(t={...r,...t}).verbose&&_log.info(`Generating IPv4 address${1<t.qty?"es":""}...`);var o=[];if(t.sequential){t.network&&this.validate(t.network)?(!t.qty||t.qty<=1)&&_log.errHelpURLandThrow({helpURL:e,errMsg:"options.qty must be > 1 when options.sequential is `true`."}):_log.errHelpURLandThrow({helpURL:e,errMsg:"options.network must be a valid IP when options.sequential is `true`."});var[i,a,s,l]=t.network.split(".").map(Number);for(let e=0;e<t.qty;e++)o.push(i+`.${a}.${s}.`+(l+e))}else if(1<t.qty)for(let e=0;e<t.qty;e++)o.push(this.generate({...t,qty:1,verbose:!1}));else{var n=[];for(let e=0;e<4;e++)n.push(_random.int(0,256));o.push(n.join("."))}r=1<t.qty?o:o[0];return t.verbose&&(_log.info(`IPv4 address${1<t.qty?"es":""} generated!`),_log.info(1==t.qty?r:r.join(", "))),r}},validate(e,t={}){var r="https://github.com/adamlui/js-utils/tree/main/generate-ip/docs/#ipv4validateaddress-options",o={verbose:!0};if(_log.prefix="ipv4.validate()","string"!=typeof e&&_log.errHelpURLandThrow({errMsg:"1st arg <address> must be a string.",helpURL:r}),_validateOptions({options:t,defaultOptions:o,helpURL:r,exampleCall:"ipv4.validate('0.0.255.255', { verbose: false })"}))return(t={...o,...t}).verbose&&_log.info(`Validating ${e}...`),o=!(4!=(r=e.split(".")).length||r.some(e=>!/^\d+$/.test(e)||parseInt(e,10)<0||255<parseInt(e,10))),t.verbose&&_log.info(`IP is ${o?"":"in"}valid IPv4 address!`),o}},ipv6={generate(a={}){var e="https://github.com/adamlui/js-utils/tree/main/generate-ip/docs/#ipv6generateoptions",t={verbose:!0,qty:1,leadingZeros:!1,doubleColon:!0,sequential:!1,network:null};if(_log.prefix="ipv6.generate()",_validateOptions({options:a,defaultOptions:t,helpURL:e,exampleCall:"ipv6.generate({ leadingZeros: true, qty: 5 })"})){(a={...t,...a}).verbose&&_log.info(`Generating IPv6 address${1<a.qty?"es":""}...`);var s=[];if(a.sequential){a.network&&this.validate(a.network)?(!a.qty||a.qty<=1)&&_log.errHelpURLandThrow({helpURL:e,errMsg:"options.qty must be > 1 when options.sequential is `true`."}):_log.errHelpURLandThrow({helpURL:e,errMsg:"options.network must be a valid IP when options.sequential is `true`."});var r=a.network.split(":").map(e=>parseInt(e,16)||0);for(let e=0;e<a.qty;e++){var o=r[7];r[7]=o+e,r[7]>o+1&&(r[7]=o+1),s.push(r.map(e=>e.toString(16).padStart(4,"0")).join(":"))}}else if(1<a.qty)for(let e=0;e<a.qty;e++)s.push(this.generate({...a,qty:1,verbose:!1}));else{let t=[],{qty:e,sequential:r,network:o,...i}=a;for(let e=0;e<8;e++)t.push(_random.hex(4));s.push(this.format(t.join(":"),{...i,verbose:!1}))}t=1<a.qty?s:s[0];return a.verbose&&(_log.info(`IPv6 address${1<a.qty?"es":""} generated!`),_log.info(1==a.qty?t:t.join(", "))),t}},format(t,r={}){var o="https://github.com/adamlui/js-utils/tree/main/generate-ip/docs/#ipv6formatipv6address-options",i={verbose:!0,leadingZeros:!1,doubleColon:!0};if(_log.prefix="ipv6.format()","string"!=typeof t&&_log.errHelpURLandThrow({errMsg:"1st arg <ipv6address> must be a string.",helpURL:o}),this.validate(t,{verbose:!1})||_log.errHelpURLandThrow({errMsg:t+" is not a valid IPv6 address.",helpURL:o}),_validateOptions({options:r,defaultOptions:i,helpURL:o,exampleCall:"ipv6.format('0d::ffff:192.1.56.10/96', { leadingZeros: true, doubleColon: false })"})){r={...i,...r};let e=t;if(e=r.doubleColon?(r.verbose&&_log.info("Replacing zero series w/ '::'..."),e.replace(/:(?:0+:)+/,"::")):(r.verbose&&_log.info("Expanding '::' into zero series..."),o=e.split(":").filter(Boolean).length,i=r.leadingZeros?"0000":"0",o=Array(8-o).fill(i).join(":"),e.replace("::",`:${o}:`)),r.leadingZeros){r.verbose&&_log.info("Adding leading zeros...");var a=e.split(":");for(let e=0;e<a.length;e++)for(;a[e].length<4;)a[e]="0"+a[e];e=a.join(":")}else r.verbose&&_log.info("Stripping leading zeros..."),e=t.replace(/(^|(?<=:))0+(?!:)/g,"$1");return r.verbose&&(e!=t?_log.info("IP formatted successfully!"):_log.info("IP already formatted to specs."),_log.info(e)),e}},validate(r,o={}){var i="https://github.com/adamlui/js-utils/tree/main/generate-ip/docs/#ipv6validateaddress-options",a={verbose:!0};if(_log.prefix="ipv6.validate()","string"!=typeof r&&_log.errHelpURLandThrow({errMsg:"1st arg <address> must be a string.",helpURL:i}),_validateOptions({options:o,defaultOptions:a,helpURL:i,exampleCall:"ipv6.validate('0:0:0:0:0:ffff:192.1.56.10/96', { verbose: false })"})){(o={...a,...o}).verbose&&_log.info(`Validating ${r}...`);let e=r.split(/::?/),t=e[e.length-1];i=!(r.includes("::")&&2<r.split("::").length||/:{3,}/.test(r)||e.length<2||8<e.length||e.some(e=>!(/^[\da-f]{1,4}$/i.test(e)||e==t&&ipv4.validate(t.replace(/\/(?:12[0-8]|[1-9]?\d)$/,""),{verbose:!1}))));return o.verbose&&_log.info(`IP is ${i?"":"in"}valid IPv6 address!`),i}}},mac={generate(t={}){var e="https://github.com/adamlui/js-utils/tree/main/generate-ip/docs/#macgenerateoptions",r={verbose:!0,qty:1,sequential:!1,network:null};if(_log.prefix="mac.generate()",_validateOptions({options:t,defaultOptions:r,helpURL:e,exampleCall:"mac.generate({ verbose: false, qty: 2 })"})){(t={...r,...t}).verbose&&_log.info(`Generating MAC address${1<t.qty?"es":""}...`);var o=[];if(t.sequential){t.network&&this.validate(t.network)?(!t.qty||t.qty<=1)&&_log.errHelpURLandThrow({helpURL:e,errMsg:"options.qty must be > 1 when options.sequential is `true`."}):_log.errHelpURLandThrow({helpURL:e,errMsg:"options.network must be a valid MAC when options.sequential is `true`."});var i=t.network.split(":").map(e=>parseInt(e,16)||0);for(let e=0;e<t.qty;e++){var a=i[5];i[5]=a+e,i[5]>a+1&&(i[5]=a+1),o.push(i.map(e=>e.toString(16).padStart(2,"0")).join(":"))}}else if(1<t.qty)for(let e=0;e<t.qty;e++)o.push(this.generate({...t,qty:1,verbose:!1}));else{var[r,e]=Array.from({length:2},()=>{var t=[];for(let e=0;e<3;e++)t.push(_random.hex(2));return t.join(":")});o.push(r+":"+e)}r=1<t.qty?o:o[0];return t.verbose&&(_log.info(`MAC address${1<t.qty?"es":""} generated!`),_log.info(1==t.qty?r:r.join(", "))),r}},validate(e,t={}){var r="https://github.com/adamlui/js-utils/tree/main/generate-ip/docs/#macvalidateaddress-options",o={verbose:!0};if(_log.prefix="mac.validate()","string"!=typeof e&&_log.errHelpURLandThrow({errMsg:"1st arg <address> must be a string.",helpURL:r}),_validateOptions({options:t,defaultOptions:o,helpURL:r,exampleCall:"mac.validate('00:1A:2B:3C:4D:5E', { verbose: false })"}))return(t={...o,...t}).verbose&&_log.info(`Validating ${e}...`),r=/^(?:[\da-f]{2}[:-]){5}[\da-f]{2}$/i.test(e),t.verbose&&_log.info(`Address is ${r?"":"in"}valid MAC address!`),r}};function _validateOptions({options:e,defaultOptions:t,helpURL:r,exampleCall:o}){var i,a,s=Object.keys(t).filter(e=>"boolean"==typeof t[e]),l=Object.keys(t).filter(e=>Number.isInteger(t[e]));if("object"!=typeof e)return i=o.split(",").findIndex(e=>e.trim().startsWith("{"))+1,i+=["st","nd","rd"][i-1]||"th",_log.error(`${"0th"==i?"[O":i+" arg [o"}ptions] can only be an object of key/vals.`),_log.info("Example valid call:",o),_log.validOptions(t),_log.helpURL(r),!1;for(a in e){if(!Object.prototype.hasOwnProperty.call(t,a))return _log.error(`\`${a}\` is an invalid option.`),_log.validOptions(t),_log.helpURL(r),!1;if(s.includes(a)&&"boolean"!=typeof e[a])return _log.error(`[${a}] option can only be \`true\` or \`false\`.`),_log.helpURL(r),!1;if(l.includes(a)&&(e[a]=parseInt(e[a],10),isNaN(e[a])||e[a]<1))return _log.error(`[${a}] option can only be an integer > 0.`),_log.helpURL(r),!1}return!0}let _random={int(e,t){var r;return"undefined"==typeof require?(r=(window.crypto||window.msCrypto)?.getRandomValues(new Uint32Array(1))[0]/4294967295||Math.random(),Math.floor(r*(t-e))+e):require("crypto").randomInt(e,t)},hex(t){let r="";for(let e=0;e<t;e++)r+=_random.int(0,16).toString(16);return r}},_log={prefix:api.name,errHelpURLandThrow({errMsg:e,helpURL:t}){throw this.error(e),this.helpURL(t),new Error(e)},error(...e){console.error(this.prefix+" » ERROR:",...e)},helpURL(e=api.urls?.docs){this.info("For more help, please visit",e)},info(...e){console.info(this.prefix+" »",...e)},validOptions(e){var t=Object.keys(e).join(", "),e=JSON.stringify(e,null,2).replace(/"([^"]+)":/g,"$1:").replace(/"/g,"'").replace(/\n\s*/g," ");this.info(`Valid options: [${t}]`),this.info("If omitted, default settings are: "+e)}};api.exports=new Proxy({ipv4:ipv4,ipv6:ipv6,mac:mac},{get(e,t){for(var[r,o]of Object.entries(api.regex))if(o.test(t))return e[r]}});try{module.exports=api.exports}catch(e){}try{Object.assign(window,api.exports)}catch(e){}