UNPKG

tencentcloud-edgeone-migration-nodejs-v2

Version:

tencentcloud cdn config copy to edgeone

444 lines (401 loc) 11.2 kB
// 工具方法,包含对配置进行组装,判断优先级,条件去重,参数合法性校验等功能 const _ = require("lodash"); const { t } = require("../i18n/trans"); function testIp(value) { let $reg_is_ip = /^((([0-9]?[0-9])|(1[0-9]{2})|(2[0-4][0-9])|(25[0-5]))\.){3}(([0-9]?[0-9])|(1[0-9]{2})|(2[0-4][0-9])|(25[0-5]))$/; return $reg_is_ip.test(value); } function testIpv6(value) { let $reg_is_ipv6 = /^((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?$/; return $reg_is_ipv6.test(value); } function testDomain(value) { var $reg_is_domain = /^(\*\.)?([a-zA-Z0-9_]([a-zA-Z0-9-_]{0,61}[a-zA-Z0-9_])?\.){1,}[a-zA-Z]{2,}$/; return $reg_is_domain.test(value); } function testIpAndPort(value) { if (!value) { return false; } var ref = value.split(":"); if (ref.length > 2) { return false; } var host = ref[0]; var port = ref[1]; if (!testIp(host)) { return false; } if (port === undefined) { return false; } if (port === "" || !/^\d+$/.test(port) || +port > 65535 || +port == 0) { return false; } return true; } function testIpAndWeight(value) { var ref = value.split("::"); var host = ref[0]; var weight = ref[1]; if (!testIp(host)) { return false; } if (weight === undefined) { return false; } if (weight === "" || !/^\d+$/.test(weight)) { return false; } return true; } function testIpAndPortAndWeight(value) { var ref = value.split(":"); if (ref.length > 3) return false; var host = ref[0]; var port = ref[1]; var weight = ref[2]; if (!testIp(host)) { return false; } if (port === undefined) { return false; } if (port === "" || !/^\d+$/.test(port) || +port > 65535 || +port == 0) { return false; } if (weight === undefined) { return false; } if (weight === "" || !/^\d+$/.test(weight)) { return false; } return true; } function testDomainAndPort(value) { if (!value) { return false; } var ref = value.split(":"); var host = ref[0]; var port = ref[1]; if (!testDomain(host)) { return false; } if (port === undefined) { return false; } if (port === "" || !/^\d+$/.test(port) || +port > 65535 || +port == 0) { return false; } return true; } function testDomainAndWeight(value) { var ref = value.split("::"); var host = ref[0]; var weight = ref[1]; if (!testDomain(host)) { return false; } if (weight === undefined) { return false; } if (weight === "" || !/^\d+$/.test(weight)) { return false; } return true; } function testDomainAndPortAndWeight(value) { var ref = value.split(":"); var host = ref[0]; var port = ref[1]; var weight = ref[2]; if (!testDomain(host)) { return false; } if (port === undefined) { return false; } if (port === "" || !/^\d+$/.test(port) || +port > 65535 || +port == 0) { return false; } if (weight === undefined) { return false; } if (weight === "" || !/^\d+$/.test(weight)) { return false; } return true; } function formatWildcardOriginHandler(illegalConfig) { return illegalConfig.map((item) => { const curOrigin = item.Values[0].split(',')[0] const formatOrigin = curOrigin.replace(/https?:\/\//g, ""); return { Rules: [ { Conditions: [ { Conditions: [ { Operator: "equal", Target: "request_header", IgnoreCase: false, Name: "origin", Values: [formatOrigin], }, ], }, ], Actions: [ { RewriteAction: { Action: "ResponseHeader", Parameters: [ { Action: "set", Name: "Access-Control-Allow-Origin", Values: ['${http.request.headers["origin"]}'], }, ], }, }, ], }, ], Tags: [], } }) } function copyConditionToOtherRule(rule) { const result = []; rule.forEach(item => { if (item.SubRules.length > 0) { for (let i = 0; i < item.SubRules.length; i += 20) { const newSubRules = item.SubRules.slice(i, i + 20); const newItem = { Conditions: item.Conditions, Actions: item?.Actions, SubRules: newSubRules }; result.push(newItem); } } }); return result } function rulesGenerator(domain, eoRuleConfigs) { let baseRule = { Conditions: [ { Conditions: [ { Operator: "equal", Target: "host", IgnoreCase: false, Values: [domain], }, ], }, ], Actions: [], SubRules: [], }; Object.keys(eoRuleConfigs).map((key) => { if (!eoRuleConfigs[key]) { return; } // 优衣库节点缓存适配 if (["Cache", "CacheKey", "MaxAge", "UrlRedirect"].includes(key)) { baseRule.SubRules.push( ...eoRuleConfigs[key].Rules.map((item) => { return { Rules: [item], Tags: [] }; }) ); }else if (eoRuleConfigs[key].Rules) { baseRule.SubRules.push(eoRuleConfigs[key]); } else if (eoRuleConfigs[key].length > 0) { baseRule.SubRules = [].concat(baseRule.SubRules, eoRuleConfigs[key]); } else { if(key === 'ResponseHeader') { const { RewriteAction } = eoRuleConfigs[key]; const legalValue = [] const illegalValue = [] RewriteAction.Parameters.forEach(item => { if([item.Name === 'Access-Control-Allow-Origin', item.Values[0]?.length > 1, item.Values[0]?.includes('*')].every((v) => !!v)) { illegalValue.push(item) } else { legalValue.push(item) } }) const defaultTemplate = { RewriteAction: { Action: 'ResponseHeader', Parameters: legalValue } } baseRule.Actions.push(defaultTemplate) if(illegalValue.length) { const formatWildcardOrigin = formatWildcardOriginHandler(illegalValue) baseRule.SubRules.push(...formatWildcardOrigin) } } else { baseRule.Actions.push(eoRuleConfigs[key]); } } }); if (baseRule.SubRules.length === 0) { delete baseRule.SubRules; } if (_.flatten(baseRule.Actions).length === 0) { delete baseRule.Actions; } return [baseRule]; } function getTarget(type) { switch (type) { case "file": return "extension"; case "directory": return "url"; case "path": return "full_url"; case "all": return "host"; case "index": return "url"; case "regex": return "full_url"; } } // 校验源站可否迁移,并返回端口号 function validateOriginsPort(origins) { const portList = []; origins.forEach((origin) => { const [ipDomain, port, weight] = origin.split(":"); if (port) { portList.push(port); } }); if (portList.length === 0) { return [true, null]; } else if (portList.length > 0 && portList.length !== origins.length) { return [ false, t( "部分源站有端口配置,部分没有端口配置,无法迁移,必须全有(且端口一致)或全无" ), ]; } const uniqPortList = _.uniq(portList); if (uniqPortList.length > 1) { return [false, t("源站端口配置不一致,无法迁移")]; } return [true, uniqPortList[0]]; } // --------------------- 相同 CIDR 网段校验 --------------------- function cidrToSubnetMask(prefixLength) { const mask = []; for (let i = 0; i < 4; i++) { const n = Math.min(prefixLength, 8); mask.push(256 - 2 ** (8 - n)); prefixLength -= n; } return mask.join("."); } function ipToInt(ip) { return ip .split(".") .reduce((int, octet) => (int << 8) + parseInt(octet, 10), 0); } function isSameCIDR(cidr1, cidr2) { const [ip1, prefixLength1] = cidr1.split("/"); const [ip2, prefixLength2] = cidr2.split("/"); if (prefixLength1 !== prefixLength2) { return false; } const subnetMask = cidrToSubnetMask(parseInt(prefixLength1, 10)); const ip1Int = ipToInt(ip1); const ip2Int = ipToInt(ip2); const subnetMaskInt = ipToInt(subnetMask); return (ip1Int & subnetMaskInt) === (ip2Int & subnetMaskInt); } function checkIsCIDR(ips) { const CIDRArr = ips.filter((item) => item.split("/").length > 1); const uniqueCIDRs = CIDRArr.filter((cidr, index, arr) => { for (let i = 0; i < index; i++) { if (isSameCIDR(cidr, arr[i])) { return false; } } return true; }); const uniqIps = ips.filter((item) => item.split("/").length === 1); return [...uniqIps, ...uniqueCIDRs]; } // --------------------- 相同 CIDR 网段校验 --------------------- function exitTerminal() { setTimeout(() => { process.exit(); }, 3e3); } const genWildString = (str) => { if (!str.endsWith('/*')) { if (str.endsWith('/')) { return str + '*'; } else { return str + '/*'; } } else { return str; } } const deepSplit = (arr) => { return arr.flatMap(item => { if (Array.isArray(item)) { return deepSplit(item); } return typeof item === 'string' ? item.split(',') : []; }); }; const genOriginValue = (rule, needSplit = false) => { if (rule.RuleType === 'directory') { return rule.RulePaths.map((path) => { return genWildString(path); }); } if(rule.RuleType === 'index') { return ['/*'] } return needSplit ? deepSplit(rule.RulePaths || []) : rule.RulePaths; } const TEO = 'eoClient' const CDN = 'cdnClient' const SSL = 'sslClient' const utils = { testIp, testDomain, testIpAndPort, testIpAndWeight, testIpAndPortAndWeight, testDomainAndPort, testDomainAndWeight, testDomainAndPortAndWeight, rulesGenerator, getTarget, validateOriginsPort, checkIsCIDR, exitTerminal, TEO, CDN, SSL, genOriginValue, copyConditionToOtherRule }; module.exports = utils;