1 | "use strict";
|
2 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
3 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
4 | };
|
5 | Object.defineProperty(exports, "__esModule", { value: true });
|
6 | exports.sanitize = exports.SanitizationResultType = exports.ValidationErrorType = void 0;
|
7 | const is_ip_1 = __importDefault(require("is-ip"));
|
8 |
|
9 |
|
10 | const LABEL_SEPARATOR = ".";
|
11 | const LABEL_ROOT = "";
|
12 | const LABEL_LENGTH_MIN = 1;
|
13 | const LABEL_LENGTH_MAX = 63;
|
14 | const DOMAIN_LENGTH_MAX = 253;
|
15 | var ValidationErrorType;
|
16 | (function (ValidationErrorType) {
|
17 | ValidationErrorType["NoHostname"] = "NO_HOSTNAME";
|
18 | ValidationErrorType["DomainMaxLength"] = "DOMAIN_MAX_LENGTH";
|
19 | ValidationErrorType["LabelMinLength"] = "LABEL_MIN_LENGTH";
|
20 | ValidationErrorType["LabelMaxLength"] = "LABEL_MAX_LENGTH";
|
21 | ValidationErrorType["LabelInvalidCharacter"] = "LABEL_INVALID_CHARACTER";
|
22 | })(ValidationErrorType = exports.ValidationErrorType || (exports.ValidationErrorType = {}));
|
23 | var SanitizationResultType;
|
24 | (function (SanitizationResultType) {
|
25 | SanitizationResultType["ValidIp"] = "VALID_IP";
|
26 | SanitizationResultType["ValidDomain"] = "VALID_DOMAIN";
|
27 | SanitizationResultType["Error"] = "ERROR";
|
28 | })(SanitizationResultType = exports.SanitizationResultType || (exports.SanitizationResultType = {}));
|
29 | const createNoHostnameError = (input) => {
|
30 | return {
|
31 | type: ValidationErrorType.NoHostname,
|
32 | message: `The given input ${String(input)} does not look like a hostname.`,
|
33 | column: 1,
|
34 | };
|
35 | };
|
36 | const createDomainMaxLengthError = (domain) => {
|
37 | const length = domain.length;
|
38 | return {
|
39 | type: ValidationErrorType.DomainMaxLength,
|
40 | message: `Domain "${domain}" is too long. Domain is ${length} octets long but should not be longer than ${DOMAIN_LENGTH_MAX}.`,
|
41 | column: length,
|
42 | };
|
43 | };
|
44 | const createLabelMinLengthError = (label, column) => {
|
45 | const length = label.length;
|
46 | return {
|
47 | type: ValidationErrorType.LabelMinLength,
|
48 | message: `Label "${label}" is too short. Label is ${length} octets long but should be at least ${LABEL_LENGTH_MIN}.`,
|
49 | column,
|
50 | };
|
51 | };
|
52 | const createLabelMaxLengthError = (label, column) => {
|
53 | const length = label.length;
|
54 | return {
|
55 | type: ValidationErrorType.LabelMaxLength,
|
56 | message: `Label "${label}" is too long. Label is ${length} octets long but should not be longer than ${LABEL_LENGTH_MAX}.`,
|
57 | column,
|
58 | };
|
59 | };
|
60 | const createLabelInvalidCharacterError = (label, invalidCharacter, column) => {
|
61 | return {
|
62 | type: ValidationErrorType.LabelInvalidCharacter,
|
63 | message: `Label "${label}" contains invalid character "${invalidCharacter}" at column ${column}.`,
|
64 | column,
|
65 | };
|
66 | };
|
67 | const sanitize = (input) => {
|
68 |
|
69 | if (typeof input !== "string") {
|
70 | return {
|
71 | type: SanitizationResultType.Error,
|
72 | errors: [createNoHostnameError(input)],
|
73 | };
|
74 | }
|
75 | const inputTrimmed = input.trim();
|
76 |
|
77 |
|
78 | const inputTrimmedAsIp = inputTrimmed.replace(/^\[|]$/g, "");
|
79 | const ipVersion = is_ip_1.default.version(inputTrimmedAsIp);
|
80 | if (ipVersion !== undefined) {
|
81 | return {
|
82 | type: SanitizationResultType.ValidIp,
|
83 | ip: inputTrimmedAsIp,
|
84 | ipVersion,
|
85 | };
|
86 | }
|
87 | if (inputTrimmed.length > DOMAIN_LENGTH_MAX) {
|
88 | return {
|
89 | type: SanitizationResultType.Error,
|
90 | errors: [createDomainMaxLengthError(inputTrimmed)],
|
91 | };
|
92 | }
|
93 | const labels = inputTrimmed.split(LABEL_SEPARATOR);
|
94 | const lastLabel = labels[labels.length - 1];
|
95 |
|
96 | if (lastLabel === LABEL_ROOT) {
|
97 | labels.pop();
|
98 | }
|
99 | const labelValidationErrors = [];
|
100 | let column = 1;
|
101 | for (const label of labels) {
|
102 |
|
103 |
|
104 | const invalidCharacter = /[^\da-z-]/iu.exec(label);
|
105 | if (invalidCharacter) {
|
106 | labelValidationErrors.push(createLabelInvalidCharacterError(label, invalidCharacter[0], invalidCharacter.index + 1));
|
107 | }
|
108 | else if (
|
109 |
|
110 |
|
111 | label.length < LABEL_LENGTH_MIN) {
|
112 | labelValidationErrors.push(createLabelMinLengthError(label, column));
|
113 | }
|
114 | else if (label.length > LABEL_LENGTH_MAX) {
|
115 | labelValidationErrors.push(createLabelMaxLengthError(label, column));
|
116 | }
|
117 | column += label.length + LABEL_SEPARATOR.length;
|
118 | }
|
119 | if (labelValidationErrors.length > 0) {
|
120 | return {
|
121 | type: SanitizationResultType.Error,
|
122 | errors: labelValidationErrors,
|
123 | };
|
124 | }
|
125 | return {
|
126 | type: SanitizationResultType.ValidDomain,
|
127 | domain: inputTrimmed,
|
128 | labels,
|
129 | };
|
130 | };
|
131 | exports.sanitize = sanitize;
|
132 |
|
\ | No newline at end of file |