Skip to content

Commit 9501a60

Browse files
committed
feat(new tool): IPv4/6 in IP Range
1 parent 80e46c9 commit 9501a60

File tree

5 files changed

+127
-7
lines changed

5 files changed

+127
-7
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
"highlight.js": "^11.7.0",
6363
"iarna-toml-esm": "^3.0.5",
6464
"ibantools": "^4.3.3",
65+
"ip-matching": "^2.1.2",
6566
"json5": "^2.2.3",
6667
"jwt-decode": "^3.1.2",
6768
"libphonenumber-js": "^1.10.28",

pnpm-lock.yaml

Lines changed: 13 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/tools/index.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ import { tool as urlParser } from './url-parser';
7575
import { tool as uuidGenerator } from './uuid-generator';
7676
import { tool as macAddressLookup } from './mac-address-lookup';
7777
import { tool as xmlFormatter } from './xml-formatter';
78+
import { tool as ipInRange } from './ip-in-range';
7879

7980
export const toolsByCategory: ToolCategory[] = [
8081
{
@@ -143,7 +144,15 @@ export const toolsByCategory: ToolCategory[] = [
143144
},
144145
{
145146
name: 'Network',
146-
components: [ipv4SubnetCalculator, ipv4AddressConverter, ipv4RangeExpander, macAddressLookup, macAddressGenerator, ipv6UlaGenerator],
147+
components: [
148+
ipv4SubnetCalculator,
149+
ipv4AddressConverter,
150+
ipInRange,
151+
ipv4RangeExpander,
152+
macAddressLookup,
153+
macAddressGenerator,
154+
ipv6UlaGenerator,
155+
],
147156
},
148157
{
149158
name: 'Math',

src/tools/ip-in-range/index.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { UnfoldMoreOutlined } from '@vicons/material';
2+
import { defineTool } from '../tool';
3+
4+
export const tool = defineTool({
5+
name: 'IP in Range/CIDR/Mask',
6+
path: '/ip-in-range',
7+
description: 'Given a CIDR/IP Range/Wildcard IP/IP Mask, tell if a given IP is in subnet range',
8+
keywords: ['ip', 'cidr', 'range'],
9+
component: () => import('./ip-in-range.vue'),
10+
icon: UnfoldMoreOutlined,
11+
createdAt: new Date('2024-03-09'),
12+
});

src/tools/ip-in-range/ip-in-range.vue

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<script setup lang="ts">
2+
import { useStorage } from '@vueuse/core';
3+
import { Check as CheckIcon, LetterX as CrossIcon } from '@vicons/tabler';
4+
import { getMatch } from 'ip-matching';
5+
import { withDefaultOnError } from '@/utils/defaults';
6+
import { isNotThrowing } from '@/utils/boolean';
7+
import SpanCopyable from '@/components/SpanCopyable.vue';
8+
9+
const range = useStorage('ip-in-range:range', '192.168.0.1/24'); // NOSONAR
10+
const ip = useStorage('ip-in-range:ip', '192.168.0.1'); // NOSONAR
11+
12+
const match = computed(() => withDefaultOnError(() => getMatch(range.value), undefined));
13+
const subnets = computed(() => {
14+
return (match.value?.convertToMasks() || []).map((mask) => {
15+
const subnet = mask.convertToSubnet();
16+
if (!subnet) {
17+
return { cidr: '', start: '', end: '' };
18+
}
19+
return {
20+
cidr: subnet.toString(),
21+
start: subnet.getFirst().toString(),
22+
end: subnet.getLast().toString(),
23+
};
24+
}).filter(subnet => subnet.cidr !== '');
25+
});
26+
const ipIsInMatch = computed(() => match.value?.matches(ip.value));
27+
28+
const ipValidationRules = [
29+
{
30+
message: 'We cannot parse this CIDR/IP Range/Mask/Wildcard, check the format',
31+
validator: (value: string) => isNotThrowing(() => getMatch(value)) && getMatch(range.value),
32+
},
33+
];
34+
</script>
35+
36+
<template>
37+
<div>
38+
<c-input-text
39+
v-model:value="range"
40+
label="An IPv4/6 CIDR/Range/Mask/Wildcard"
41+
placeholder="The ipv4/6 CIDR..."
42+
:validation-rules="ipValidationRules"
43+
mb-4
44+
/>
45+
46+
<c-input-text
47+
v-model:value="ip"
48+
label="An IPv4/6 address"
49+
placeholder="The ipv4/6 address..."
50+
:validation-rules="ipValidationRules"
51+
mb-4
52+
/>
53+
54+
<n-divider />
55+
56+
<div flex justify-center>
57+
<span v-if="ipIsInMatch">
58+
<n-icon color="green">
59+
<CheckIcon />
60+
</n-icon>
61+
Match
62+
</span>
63+
<span v-else>
64+
<n-icon color="red">
65+
<CrossIcon />
66+
</n-icon>
67+
Not Match
68+
</span>
69+
</div>
70+
71+
<n-divider />
72+
73+
<c-card title="Subnets">
74+
<n-table>
75+
<tbody>
76+
<tr v-for="{ cidr, start, end } in subnets" :key="cidr">
77+
<td font-bold>
78+
<SpanCopyable :value="cidr" />
79+
</td>
80+
<td>
81+
<SpanCopyable :value="start" />
82+
</td>
83+
<td>
84+
<SpanCopyable :value="end" />
85+
</td>
86+
</tr>
87+
</tbody>
88+
</n-table>
89+
</c-card>
90+
</div>
91+
</template>

0 commit comments

Comments
 (0)