UNPKG

dynatrace-cordova-outsystems-plugin

Version:

This plugin gives you the ability to use the Dynatrace instrumentation in your hybrid application (Cordova, Ionic, ..). It uses the Mobile Agent, the JavaScript Agent and the Javascript Bridge. The Mobile Agent will give you all device specific values con

288 lines (251 loc) 6.77 kB
"use strict"; const punycode = require("punycode"); const regexes = require("./lib/regexes.js"); const mappingTable = require("./lib/mappingTable.json"); function containsNonASCII(str) { return /[^\x00-\x7F]/.test(str); } function findStatus(val, { useSTD3ASCIIRules }) { let start = 0; let end = mappingTable.length - 1; while (start <= end) { const mid = Math.floor((start + end) / 2); const target = mappingTable[mid]; if (target[0][0] <= val && target[0][1] >= val) { if (target[1].startsWith("disallowed_STD3_")) { const newStatus = useSTD3ASCIIRules ? "disallowed" : target[1].slice(16); return [newStatus, ...target.slice(2)]; } return target.slice(1); } else if (target[0][0] > val) { end = mid - 1; } else { start = mid + 1; } } return null; } function mapChars(domainName, { useSTD3ASCIIRules, processingOption }) { let hasError = false; let processed = ""; for (const ch of domainName) { const [status, mapping] = findStatus(ch.codePointAt(0), { useSTD3ASCIIRules }); switch (status) { case "disallowed": hasError = true; processed += ch; break; case "ignored": break; case "mapped": processed += mapping; break; case "deviation": if (processingOption === "transitional") { processed += mapping; } else { processed += ch; } break; case "valid": processed += ch; break; } } return { string: processed, error: hasError }; } function validateLabel(label, { checkHyphens, checkBidi, checkJoiners, processingOption, useSTD3ASCIIRules }) { if (label.normalize("NFC") !== label) { return false; } const codePoints = Array.from(label); if (checkHyphens) { if ((codePoints[2] === "-" && codePoints[3] === "-") || (label.startsWith("-") || label.endsWith("-"))) { return false; } } if (label.includes(".") || (codePoints.length > 0 && regexes.combiningMarks.test(codePoints[0]))) { return false; } for (const ch of codePoints) { const [status] = findStatus(ch.codePointAt(0), { useSTD3ASCIIRules }); if ((processingOption === "transitional" && status !== "valid") || (processingOption === "nontransitional" && status !== "valid" && status !== "deviation")) { return false; } } // https://tools.ietf.org/html/rfc5892#appendix-A if (checkJoiners) { let last = 0; for (const [i, ch] of codePoints.entries()) { if (ch === "\u200C" || ch === "\u200D") { if (i > 0) { if (regexes.combiningClassVirama.test(codePoints[i - 1])) { continue; } if (ch === "\u200C") { // TODO: make this more efficient const next = codePoints.indexOf("\u200C", i + 1); const test = next < 0 ? codePoints.slice(last) : codePoints.slice(last, next); if (regexes.validZWNJ.test(test.join(""))) { last = i + 1; continue; } } } return false; } } } // https://tools.ietf.org/html/rfc5893#section-2 if (checkBidi) { let rtl; // 1 if (regexes.bidiS1LTR.test(codePoints[0])) { rtl = false; } else if (regexes.bidiS1RTL.test(codePoints[0])) { rtl = true; } else { return false; } if (rtl) { // 2-4 if (!regexes.bidiS2.test(label) || !regexes.bidiS3.test(label) || (regexes.bidiS4EN.test(label) && regexes.bidiS4AN.test(label))) { return false; } } else if (!regexes.bidiS5.test(label) || !regexes.bidiS6.test(label)) { // 5-6 return false; } } return true; } function isBidiDomain(labels) { const domain = labels.map(label => { if (label.startsWith("xn--")) { try { return punycode.decode(label.substring(4)); } catch (err) { return ""; } } return label; }).join("."); return regexes.bidiDomain.test(domain); } function processing(domainName, options) { const { processingOption } = options; // 1. Map. let { string, error } = mapChars(domainName, options); // 2. Normalize. string = string.normalize("NFC"); // 3. Break. const labels = string.split("."); const isBidi = isBidiDomain(labels); // 4. Convert/Validate. for (const [i, origLabel] of labels.entries()) { let label = origLabel; let curProcessing = processingOption; if (label.startsWith("xn--")) { try { label = punycode.decode(label.substring(4)); labels[i] = label; } catch (err) { error = true; continue; } curProcessing = "nontransitional"; } // No need to validate if we already know there is an error. if (error) { continue; } const validation = validateLabel(label, Object.assign({}, options, { processingOption: curProcessing, checkBidi: options.checkBidi && isBidi })); if (!validation) { error = true; } } return { string: labels.join("."), error }; } function toASCII(domainName, { checkHyphens = false, checkBidi = false, checkJoiners = false, useSTD3ASCIIRules = false, processingOption = "nontransitional", verifyDNSLength = false } = {}) { if (processingOption !== "transitional" && processingOption !== "nontransitional") { throw new RangeError("processingOption must be either transitional or nontransitional"); } const result = processing(domainName, { processingOption, checkHyphens, checkBidi, checkJoiners, useSTD3ASCIIRules }); let labels = result.string.split("."); labels = labels.map(l => { if (containsNonASCII(l)) { try { return "xn--" + punycode.encode(l); } catch (e) { result.error = true; } } return l; }); if (verifyDNSLength) { const total = labels.join(".").length; if (total > 253 || total === 0) { result.error = true; } for (let i = 0; i < labels.length; ++i) { if (labels[i].length > 63 || labels[i].length === 0) { result.error = true; break; } } } if (result.error) { return null; } return labels.join("."); } function toUnicode(domainName, { checkHyphens = false, checkBidi = false, checkJoiners = false, useSTD3ASCIIRules = false } = {}) { const result = processing(domainName, { processingOption: "nontransitional", checkHyphens, checkBidi, checkJoiners, useSTD3ASCIIRules }); return { domain: result.string, error: result.error }; } module.exports = { toASCII, toUnicode };