1 | 'use strict';
|
2 |
|
3 | Object.defineProperty(exports, "__esModule", {
|
4 | value: true
|
5 | });
|
6 |
|
7 | var _es6Promisify = require('es6-promisify');
|
8 |
|
9 | var _es6Promisify2 = _interopRequireDefault(_es6Promisify);
|
10 |
|
11 | var _Any = require('./Any');
|
12 |
|
13 | var _Any2 = _interopRequireDefault(_Any);
|
14 |
|
15 | var _Error = require('../Error');
|
16 |
|
17 | var _Error2 = _interopRequireDefault(_Error);
|
18 |
|
19 | var _Reference = require('../Reference');
|
20 |
|
21 | var _Reference2 = _interopRequireDefault(_Reference);
|
22 |
|
23 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
24 |
|
25 | const specialRanges = {
|
26 | unspecified: ['0.0.0.0/8', '0::/128'],
|
27 | broadcast: ['255.255.255.255/32'],
|
28 | multicast: ['224.0.0.0/4', 'ff00::/8'],
|
29 | linklocal: ['169.254.0.0/16', 'fe80::/10'],
|
30 | loopback: ['127.0.0.0/8', '::1/128'],
|
31 | private: ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16'],
|
32 |
|
33 | reserved: ['192.0.0.0/24', '192.88.99.0/24', '198.51.100.0/24', '203.0.113.0/24', '240.0.0.0/4', '2001:db8::/32'],
|
34 | uniquelocal: ['fc00::/7'],
|
35 | ipv4mapped: ['::ffff:0:0/96'],
|
36 | rfc6145: ['::ffff:0:0:0/96'],
|
37 | rfc6052: ['64:ff9b::/96'],
|
38 | '6to4': ['2002::/16'],
|
39 | teredo: ['2001::/32'],
|
40 | special: [] };
|
41 | var _iteratorNormalCompletion = true;
|
42 | var _didIteratorError = false;
|
43 | var _iteratorError = undefined;
|
44 |
|
45 | try {
|
46 | for (var _iterator = Object.keys(specialRanges)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
47 | const key = _step.value;
|
48 |
|
49 | if (key !== 'special') specialRanges.special.push(specialRanges[key]);
|
50 | }
|
51 | } catch (err) {
|
52 | _didIteratorError = true;
|
53 | _iteratorError = err;
|
54 | } finally {
|
55 | try {
|
56 | if (!_iteratorNormalCompletion && _iterator.return) {
|
57 | _iterator.return();
|
58 | }
|
59 | } finally {
|
60 | if (_didIteratorError) {
|
61 | throw _iteratorError;
|
62 | }
|
63 | }
|
64 | }
|
65 |
|
66 | class IPSchema extends _Any2.default {
|
67 | constructor(base) {
|
68 | super(base);
|
69 | this._setting.format = 'short';
|
70 |
|
71 | let raw = this._rules.descriptor.pop();
|
72 | let allow = this._rules.descriptor.pop();
|
73 | this._rules.descriptor.push(this._typeDescriptor, allow, this._versionDescriptor, this._formatDescriptor, raw);
|
74 | raw = this._rules.validator.pop();
|
75 | allow = this._rules.validator.pop();
|
76 | this._rules.validator.push(this._typeValidator, allow, this._versionValidator, this._formatValidator, raw);
|
77 | }
|
78 |
|
79 | lookup(flag) {
|
80 | return this._setFlag('lookup', flag);
|
81 | }
|
82 |
|
83 | _typeDescriptor() {
|
84 | return 'An IP address as string or byte array is needed here.\n';
|
85 | }
|
86 |
|
87 | _typeValidator(data) {
|
88 | const check = this._check;
|
89 |
|
90 | return Promise.resolve().then(() => require('ipaddr.js')).then(ipaddr => {
|
91 | if (Array.isArray(data.value) && (data.value.length === 4 || data.value.length === 16)) {
|
92 | const ip = ipaddr.fromByteArray(data.value);
|
93 | data.value = ip;
|
94 | return Promise.resolve();
|
95 | }
|
96 | if (typeof data.value === 'string') {
|
97 | let ip = null;
|
98 | try {
|
99 | ip = ipaddr.parse(data.value);
|
100 | } catch (err) {
|
101 | if (check.lookup) {
|
102 | return Promise.resolve().then(() => require('dns')).then(dns => (0, _es6Promisify2.default)(dns.lookup)(data.value, { family: check.version }).then(resolved => {
|
103 | data.value = ipaddr.parse(resolved);
|
104 | return true;
|
105 | }));
|
106 | }
|
107 | }
|
108 | if (!ip) return Promise.reject(new Error('The given value could not be parsed as any valid IP address'));
|
109 | data.value = ip;
|
110 | return Promise.resolve();
|
111 | }
|
112 | return Promise.reject(new _Error2.default(this, data, `An ${typeof data.value} could not be transformed to an IP address`));
|
113 | });
|
114 | }
|
115 |
|
116 | _allowValidator(data) {
|
117 | const check = this._check;
|
118 | this._checkArray('allow');
|
119 | this._checkArray('deny');
|
120 |
|
121 | const deny = [];
|
122 | if (check.deny) {
|
123 | var _iteratorNormalCompletion2 = true;
|
124 | var _didIteratorError2 = false;
|
125 | var _iteratorError2 = undefined;
|
126 |
|
127 | try {
|
128 | for (var _iterator2 = check.deny[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
|
129 | const e = _step2.value;
|
130 |
|
131 | if (specialRanges[e]) {
|
132 | var _iteratorNormalCompletion3 = true;
|
133 | var _didIteratorError3 = false;
|
134 | var _iteratorError3 = undefined;
|
135 |
|
136 | try {
|
137 | for (var _iterator3 = specialRanges[e][Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
|
138 | const n = _step3.value;
|
139 | deny.push(`${n}#`);
|
140 | }
|
141 | } catch (err) {
|
142 | _didIteratorError3 = true;
|
143 | _iteratorError3 = err;
|
144 | } finally {
|
145 | try {
|
146 | if (!_iteratorNormalCompletion3 && _iterator3.return) {
|
147 | _iterator3.return();
|
148 | }
|
149 | } finally {
|
150 | if (_didIteratorError3) {
|
151 | throw _iteratorError3;
|
152 | }
|
153 | }
|
154 | }
|
155 | } else deny.push(e);
|
156 | }
|
157 | } catch (err) {
|
158 | _didIteratorError2 = true;
|
159 | _iteratorError2 = err;
|
160 | } finally {
|
161 | try {
|
162 | if (!_iteratorNormalCompletion2 && _iterator2.return) {
|
163 | _iterator2.return();
|
164 | }
|
165 | } finally {
|
166 | if (_didIteratorError2) {
|
167 | throw _iteratorError2;
|
168 | }
|
169 | }
|
170 | }
|
171 | }
|
172 | const allow = [];
|
173 | if (check.allow) {
|
174 | var _iteratorNormalCompletion4 = true;
|
175 | var _didIteratorError4 = false;
|
176 | var _iteratorError4 = undefined;
|
177 |
|
178 | try {
|
179 | for (var _iterator4 = check.allow[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
|
180 | const e = _step4.value;
|
181 |
|
182 | if (specialRanges[e]) {
|
183 | var _iteratorNormalCompletion5 = true;
|
184 | var _didIteratorError5 = false;
|
185 | var _iteratorError5 = undefined;
|
186 |
|
187 | try {
|
188 | for (var _iterator5 = specialRanges[e][Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
|
189 | const n = _step5.value;
|
190 | allow.push(`${n}#`);
|
191 | }
|
192 | } catch (err) {
|
193 | _didIteratorError5 = true;
|
194 | _iteratorError5 = err;
|
195 | } finally {
|
196 | try {
|
197 | if (!_iteratorNormalCompletion5 && _iterator5.return) {
|
198 | _iterator5.return();
|
199 | }
|
200 | } finally {
|
201 | if (_didIteratorError5) {
|
202 | throw _iteratorError5;
|
203 | }
|
204 | }
|
205 | }
|
206 | } else allow.push(e);
|
207 | }
|
208 | } catch (err) {
|
209 | _didIteratorError4 = true;
|
210 | _iteratorError4 = err;
|
211 | } finally {
|
212 | try {
|
213 | if (!_iteratorNormalCompletion4 && _iterator4.return) {
|
214 | _iterator4.return();
|
215 | }
|
216 | } finally {
|
217 | if (_didIteratorError4) {
|
218 | throw _iteratorError4;
|
219 | }
|
220 | }
|
221 | }
|
222 | }
|
223 | if (allow && deny && allow.length && deny.length) {
|
224 | check.deny = check.deny.filter(e => !check.allow.includes(e));
|
225 | }
|
226 |
|
227 | return Promise.resolve().then(() => require('ipaddr.js')).then(ipaddr => {
|
228 | let denyBits = 0;
|
229 | if (deny.length) {
|
230 | var _iteratorNormalCompletion6 = true;
|
231 | var _didIteratorError6 = false;
|
232 | var _iteratorError6 = undefined;
|
233 |
|
234 | try {
|
235 | for (var _iterator6 = deny[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
|
236 | const e = _step6.value;
|
237 |
|
238 | const n = e.replace(/#$/, '');
|
239 | let range;
|
240 | if (n.match(/\//)) range = ipaddr.parseCIDR(n);else {
|
241 | const ip = ipaddr.parse(n);
|
242 | range = ip.kind === 4 ? [ip, 32] : [ip, 128];
|
243 | }
|
244 | if (data.value.match(range)) {
|
245 | let bits = n.length < e.length ? 1 : range[1];
|
246 | if (Number.isNaN(bits)) bits = 0;
|
247 | if (bits > denyBits) denyBits = bits;
|
248 | }
|
249 | }
|
250 | } catch (err) {
|
251 | _didIteratorError6 = true;
|
252 | _iteratorError6 = err;
|
253 | } finally {
|
254 | try {
|
255 | if (!_iteratorNormalCompletion6 && _iterator6.return) {
|
256 | _iterator6.return();
|
257 | }
|
258 | } finally {
|
259 | if (_didIteratorError6) {
|
260 | throw _iteratorError6;
|
261 | }
|
262 | }
|
263 | }
|
264 | }
|
265 | let allowBits = 0;
|
266 | if (allow.length) {
|
267 | allowBits = -1;
|
268 | var _iteratorNormalCompletion7 = true;
|
269 | var _didIteratorError7 = false;
|
270 | var _iteratorError7 = undefined;
|
271 |
|
272 | try {
|
273 | for (var _iterator7 = allow[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) {
|
274 | const e = _step7.value;
|
275 |
|
276 | const n = e.replace(/#$/, '');
|
277 | let range;
|
278 | if (n.match(/\//)) range = ipaddr.parseCIDR(n);else {
|
279 | const ip = ipaddr.parse(n);
|
280 | range = ip.kind === 4 ? [ip, 32] : [ip, 128];
|
281 | }
|
282 | if (data.value.match(range)) {
|
283 | let bits = n.length < e.length ? 1 : range[1];
|
284 | if (Number.isNaN(bits)) bits = 0;
|
285 | if (bits > allowBits) allowBits = bits;
|
286 | }
|
287 | }
|
288 | } catch (err) {
|
289 | _didIteratorError7 = true;
|
290 | _iteratorError7 = err;
|
291 | } finally {
|
292 | try {
|
293 | if (!_iteratorNormalCompletion7 && _iterator7.return) {
|
294 | _iterator7.return();
|
295 | }
|
296 | } finally {
|
297 | if (_didIteratorError7) {
|
298 | throw _iteratorError7;
|
299 | }
|
300 | }
|
301 | }
|
302 | }
|
303 |
|
304 | if (denyBits > allowBits) {
|
305 | return Promise.reject(new _Error2.default(this, data, 'Element found in blacklist (denied item).'));
|
306 | }
|
307 | return Promise.resolve();
|
308 | });
|
309 | }
|
310 |
|
311 | version(value) {
|
312 | return this._setAny('version', value);
|
313 | }
|
314 | mapping(flag) {
|
315 | return this._setFlag('mapping', flag);
|
316 | }
|
317 |
|
318 | _versionDescriptor() {
|
319 | const set = this._setting;
|
320 | let msg = '';
|
321 | if (set.version) {
|
322 | if (this._isReference('version')) {
|
323 | msg += `Valid addresses has to be of IP version defined at ${set.version.description}. `;
|
324 | } else msg += `Only IPv${set.version} addresses are valid. `;
|
325 | }
|
326 | if (set.mapping) {
|
327 | if (this._isReference('mapping')) {
|
328 | msg += `IPv4 adresses may be automatically converted if set under ${set.mapping.description}. `;
|
329 | } else msg += 'IPv4 addresses may be automatically converted. ';
|
330 | }
|
331 | return msg.length ? `${msg.trim()}\n` : msg;
|
332 | }
|
333 |
|
334 | _versionValidator(data) {
|
335 | const check = this._check;
|
336 | try {
|
337 | this._checkNumber('version');
|
338 | this._checkBoolean('mapping');
|
339 | if (check.version && ![4, 6].includes(check.version)) {
|
340 | throw new Error(`Only IP version 4 or 6 are valid, ${check.version} is unknown`);
|
341 | }
|
342 | } catch (err) {
|
343 | return Promise.reject(new _Error2.default(this, data, err.message));
|
344 | }
|
345 |
|
346 | if (check.version) {
|
347 | if (check.version === 4) {
|
348 | if (data.value.kind() === 'ipv6') {
|
349 | if (check.mapping && data.value.isIPv4MappedAddress()) data.value = data.value.toIPv4Address();else {
|
350 | return Promise.reject(new _Error2.default(this, data, `The given value is no valid IPv${check.version} address`));
|
351 | }
|
352 | }
|
353 | } else if (data.value.kind() === 'ipv4') {
|
354 | if (check.mapping) data.value = data.value.toIPv4MappedAddress();else {
|
355 | return Promise.reject(new _Error2.default(this, data, `The given value is no valid IPv${check.version} address`));
|
356 | }
|
357 | }
|
358 | }
|
359 | return Promise.resolve();
|
360 | }
|
361 |
|
362 | format(value = 'short') {
|
363 | return this._setAny('format', value);
|
364 | }
|
365 |
|
366 | _formatDescriptor() {
|
367 | const set = this._setting;
|
368 | let msg = '';
|
369 | if (set.format) {
|
370 | if (this._isReference('format')) {
|
371 | msg += `The ip address will be formatted like defined under ${set.format.description}. `;
|
372 | } else msg += `The ip address will be formatted in ${set.format} form. `;
|
373 | }
|
374 | return msg.length ? `${msg.trim()}\n` : msg;
|
375 | }
|
376 |
|
377 | _formatValidator(data) {
|
378 | const check = this._check;
|
379 | try {
|
380 | this._checkString('format');
|
381 | if (!['short', 'long', 'array'].includes(check.format)) {
|
382 | throw new Error(`One of 'short', 'long' or 'array' is needed for format but ${check.format} \
|
383 | was given`);
|
384 | }
|
385 | } catch (err) {
|
386 | return Promise.reject(new _Error2.default(this, data, err.message));
|
387 | }
|
388 |
|
389 | if (check.format === 'array') {
|
390 | data.value = data.value.octets || data.value.parts;
|
391 | } else if (data.value.kind() === 'ipv6' && check.format === 'long') {
|
392 | data.value = data.value.toNormalizedString();
|
393 | } else data.value = data.value.toString();
|
394 | return Promise.resolve();
|
395 | }
|
396 | }
|
397 |
|
398 | exports.default = IPSchema; |
\ | No newline at end of file |