UNPKG

decentralized-internet

Version:

An NPM library of programs to create decentralized web and distributed computing projects

1 lines 3.75 kB
"use strict";const Punycode=require("punycode"),Abnf=require("./abnf"),Tlds=require("./tlds"),internals={nonAsciiRx:/[^\x00-\x7f]/,minDomainSegments:2,defaultTlds:{allow:Tlds,deny:null}};module.exports={email:{analyze:function(n,t){return internals.email(n,t)},isValid:function(n,t){return!internals.email(n,t)}},domain:{analyze:function(n,t={}){if(internals.options(n,t),!n)return internals.error("Domain must be a non-empty string");if(n.length>256)return internals.error("Domain too long");if(!!internals.nonAsciiRx.test(n)){if(!1===t.allowUnicode)return internals.error("Domain contains forbidden Unicode characters");const e=n.normalize("NFC");n=Punycode.toASCII(e)}return internals.domain(n,t)},isValid:function(n,t){return!module.exports.domain.analyze(n,t)}}},internals.email=function(n,t={}){if(internals.options(n,t),!n)return internals.error("Address must be a non-empty string");const e=!internals.nonAsciiRx.test(n);if(!e){if(!1===t.allowUnicode)return internals.error("Address contains forbidden Unicode characters");const e=n.normalize("NFC");n=Punycode.toASCII(e)}const r=n.split("@");if(2!==r.length)return internals.error(r.length>2?"Address cannot contain more than one @ character":"Address must contain one @ character");const o=r[0],i=r[1];return o?i?n.length>254?internals.error("Address too long"):Buffer.byteLength(o,"utf-8")>64?internals.error("Address local part too long"):internals.local(o,e)||internals.domain(i,t):internals.error("Domain cannot be empty"):internals.error("Address local part cannot be empty")},internals.options=function(n,t){if(t.tlds&&!0!==t.tlds){if("object"!=typeof t.tlds)throw new Error("Invalid options: tlds must be a boolean or an object");if(void 0!==t.tlds.allow&&!0!==t.tlds.allow&&t.tlds.allow instanceof Set==!1)throw new Error("Invalid options: tlds.allow must be a Set object or true");if(t.tlds.deny){if(t.tlds.deny instanceof Set==!1)throw new Error("Invalid options: tlds.deny must be a Set object");if(t.tlds.allow instanceof Set)throw new Error("Invalid options: cannot specify both tlds.allow and tlds.deny lists")}}if("string"!=typeof n)throw new Error("Invalid input: value must be a string")},internals.local=function(n,t){const e=n.split(".");for(const n of e){if(!n.length)return internals.error("Address local part contains empty dot-separated segment");if(t){if(!Abnf.atextRx.test(n))return internals.error("Address local part contains invalid character")}else for(const t of n){const n=Buffer.from(t).toString("binary");if(!Abnf.atomRx.test(n))return internals.error("Address local part contains invalid character")}}},internals.tldSegmentRx=/^[a-zA-Z](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?$/,internals.domainSegmentRx=/^[a-zA-Z0-9](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?$/,internals.domain=function(n,t){const e=t.minDomainSegments||internals.minDomainSegments,r=n.split(".");if(r.length<e)return internals.error("Domain lacks the minimum required number of segments");const o=internals.tlds(t);if(o){const n=r[r.length-1].toLowerCase();if(o.deny&&o.deny.has(n)||o.allow&&!o.allow.has(n))return internals.error("Domain uses forbidden TLD")}for(let n=0;n<r.length;++n){const t=r[n];if(!t.length)return internals.error("Domain contains empty dot-separated segment");if(t.length>63)return internals.error("Domain contains dot-separated segment that is too long");if(n<r.length-1){if(!internals.domainSegmentRx.test(t))return internals.error("Domain contains invalid character")}else if(!internals.tldSegmentRx.test(t))return internals.error("Domain contains invalid tld character")}},internals.tlds=function(n){return!1===n.tlds?null:n.tlds&&!0!==n.tlds?{allow:!0===n.tlds.allow?null:n.tlds.allow||Tlds,deny:n.tlds.deny||null}:internals.defaultTlds},internals.error=function(n){return{error:n}};