116 lines
3.2 KiB
JavaScript
116 lines
3.2 KiB
JavaScript
|
'use strict';
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Polyfill for `endsWith`
|
||
|
*
|
||
|
* @param {string} str
|
||
|
* @param {string} pattern
|
||
|
* @return {boolean}
|
||
|
*/
|
||
|
function endsWith(str, pattern) {
|
||
|
return (
|
||
|
str.lastIndexOf(pattern) === (str.length - pattern.length)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Check if `vhost` is a valid suffix of `hostname` (top-domain)
|
||
|
*
|
||
|
* It means that `vhost` needs to be a suffix of `hostname` and we then need to
|
||
|
* make sure that: either they are equal, or the character preceding `vhost` in
|
||
|
* `hostname` is a '.' (it should not be a partial label).
|
||
|
*
|
||
|
* * hostname = 'not.evil.com' and vhost = 'vil.com' => not ok
|
||
|
* * hostname = 'not.evil.com' and vhost = 'evil.com' => ok
|
||
|
* * hostname = 'not.evil.com' and vhost = 'not.evil.com' => ok
|
||
|
*
|
||
|
* @param {string} hostname
|
||
|
* @param {string} vhost
|
||
|
* @return {boolean}
|
||
|
*/
|
||
|
function shareSameDomainSuffix(hostname, vhost) {
|
||
|
if (endsWith(hostname, vhost)) {
|
||
|
return (
|
||
|
hostname.length === vhost.length ||
|
||
|
hostname[hostname.length - vhost.length - 1] === '.'
|
||
|
);
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Given a hostname and its public suffix, extract the general domain.
|
||
|
*
|
||
|
* @param {string} hostname
|
||
|
* @param {string} publicSuffix
|
||
|
* @return {string}
|
||
|
*/
|
||
|
function extractDomainWithSuffix(hostname, publicSuffix) {
|
||
|
// Locate the index of the last '.' in the part of the `hostname` preceding
|
||
|
// the public suffix.
|
||
|
//
|
||
|
// examples:
|
||
|
// 1. not.evil.co.uk => evil.co.uk
|
||
|
// ^ ^
|
||
|
// | | start of public suffix
|
||
|
// | index of the last dot
|
||
|
//
|
||
|
// 2. example.co.uk => example.co.uk
|
||
|
// ^ ^
|
||
|
// | | start of public suffix
|
||
|
// |
|
||
|
// | (-1) no dot found before the public suffix
|
||
|
var publicSuffixIndex = hostname.length - publicSuffix.length - 2;
|
||
|
var lastDotBeforeSuffixIndex = hostname.lastIndexOf('.', publicSuffixIndex);
|
||
|
|
||
|
// No '.' found, then `hostname` is the general domain (no sub-domain)
|
||
|
if (lastDotBeforeSuffixIndex === -1) {
|
||
|
return hostname;
|
||
|
}
|
||
|
|
||
|
// Extract the part between the last '.'
|
||
|
return hostname.substr(lastDotBeforeSuffixIndex + 1);
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Detects the domain based on rules and upon and a host string
|
||
|
*
|
||
|
* @api
|
||
|
* @param {string} host
|
||
|
* @return {String}
|
||
|
*/
|
||
|
module.exports = function getDomain(validHosts, suffix, hostname) {
|
||
|
// Check if `hostname` ends with a member of `validHosts`.
|
||
|
for (var i = 0; i < validHosts.length; i += 1) {
|
||
|
var vhost = validHosts[i];
|
||
|
if (shareSameDomainSuffix(hostname, vhost)) {
|
||
|
return vhost;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If there is no suffix, there is no hostname
|
||
|
if (suffix === null) {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
// If `hostname` is a valid public suffix, then there is no domain to return.
|
||
|
// Since we already know that `getPublicSuffix` returns a suffix of `hostname`
|
||
|
// there is no need to perform a string comparison and we only compare the
|
||
|
// size.
|
||
|
if (suffix.length === hostname.length) {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
// To extract the general domain, we start by identifying the public suffix
|
||
|
// (if any), then consider the domain to be the public suffix with one added
|
||
|
// level of depth. (e.g.: if hostname is `not.evil.co.uk` and public suffix:
|
||
|
// `co.uk`, then we take one more level: `evil`, giving the final result:
|
||
|
// `evil.co.uk`).
|
||
|
return extractDomainWithSuffix(hostname, suffix);
|
||
|
};
|