mirror of
https://github.com/CorentinTh/it-tools.git
synced 2025-05-05 05:47:10 -04:00
feat: Implement IPv6 subnet calculator for issue #924
This commit is contained in:
parent
d3b32cc14e
commit
8ab7b3f650
8 changed files with 167 additions and 8 deletions
30
components.d.ts
vendored
30
components.d.ts
vendored
|
@ -89,22 +89,34 @@ declare module '@vue/runtime-core' {
|
|||
HttpStatusCodes: typeof import('./src/tools/http-status-codes/http-status-codes.vue')['default']
|
||||
IbanValidatorAndParser: typeof import('./src/tools/iban-validator-and-parser/iban-validator-and-parser.vue')['default']
|
||||
'IconMdi:brushVariant': typeof import('~icons/mdi/brush-variant')['default']
|
||||
'IconMdi:contentCopy': typeof import('~icons/mdi/content-copy')['default']
|
||||
'IconMdi:kettleSteamOutline': typeof import('~icons/mdi/kettle-steam-outline')['default']
|
||||
IconMdiArrowDown: typeof import('~icons/mdi/arrow-down')['default']
|
||||
IconMdiArrowRightBottom: typeof import('~icons/mdi/arrow-right-bottom')['default']
|
||||
IconMdiCamera: typeof import('~icons/mdi/camera')['default']
|
||||
IconMdiChevronDown: typeof import('~icons/mdi/chevron-down')['default']
|
||||
IconMdiChevronRight: typeof import('~icons/mdi/chevron-right')['default']
|
||||
IconMdiClose: typeof import('~icons/mdi/close')['default']
|
||||
IconMdiContentCopy: typeof import('~icons/mdi/content-copy')['default']
|
||||
IconMdiDeleteOutline: typeof import('~icons/mdi/delete-outline')['default']
|
||||
IconMdiDownload: typeof import('~icons/mdi/download')['default']
|
||||
IconMdiEye: typeof import('~icons/mdi/eye')['default']
|
||||
IconMdiEyeOff: typeof import('~icons/mdi/eye-off')['default']
|
||||
IconMdiHeart: typeof import('~icons/mdi/heart')['default']
|
||||
IconMdiPause: typeof import('~icons/mdi/pause')['default']
|
||||
IconMdiPlay: typeof import('~icons/mdi/play')['default']
|
||||
IconMdiRecord: typeof import('~icons/mdi/record')['default']
|
||||
IconMdiRefresh: typeof import('~icons/mdi/refresh')['default']
|
||||
IconMdiSearch: typeof import('~icons/mdi/search')['default']
|
||||
IconMdiTranslate: typeof import('~icons/mdi/translate')['default']
|
||||
IconMdiTriangleDown: typeof import('~icons/mdi/triangle-down')['default']
|
||||
IconMdiVideo: typeof import('~icons/mdi/video')['default']
|
||||
InputCopyable: typeof import('./src/components/InputCopyable.vue')['default']
|
||||
IntegerBaseConverter: typeof import('./src/tools/integer-base-converter/integer-base-converter.vue')['default']
|
||||
Ipv4AddressConverter: typeof import('./src/tools/ipv4-address-converter/ipv4-address-converter.vue')['default']
|
||||
Ipv4RangeExpander: typeof import('./src/tools/ipv4-range-expander/ipv4-range-expander.vue')['default']
|
||||
Ipv4SubnetCalculator: typeof import('./src/tools/ipv4-subnet-calculator/ipv4-subnet-calculator.vue')['default']
|
||||
Ipv6SubnetCalculator: typeof import('./src/tools/ipv6-subnet-calculator/ipv6-subnet-calculator.vue')['default']
|
||||
Ipv6UlaGenerator: typeof import('./src/tools/ipv6-ula-generator/ipv6-ula-generator.vue')['default']
|
||||
JsonDiff: typeof import('./src/tools/json-diff/json-diff.vue')['default']
|
||||
JsonMinify: typeof import('./src/tools/json-minify/json-minify.vue')['default']
|
||||
|
@ -126,25 +138,40 @@ declare module '@vue/runtime-core' {
|
|||
MenuLayout: typeof import('./src/components/MenuLayout.vue')['default']
|
||||
MetaTagGenerator: typeof import('./src/tools/meta-tag-generator/meta-tag-generator.vue')['default']
|
||||
MimeTypes: typeof import('./src/tools/mime-types/mime-types.vue')['default']
|
||||
NAlert: typeof import('naive-ui')['NAlert']
|
||||
NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default']
|
||||
NCheckbox: typeof import('naive-ui')['NCheckbox']
|
||||
NCode: typeof import('naive-ui')['NCode']
|
||||
NCollapseTransition: typeof import('naive-ui')['NCollapseTransition']
|
||||
NColorPicker: typeof import('naive-ui')['NColorPicker']
|
||||
NConfigProvider: typeof import('naive-ui')['NConfigProvider']
|
||||
NDatePicker: typeof import('naive-ui')['NDatePicker']
|
||||
NDivider: typeof import('naive-ui')['NDivider']
|
||||
NDynamicInput: typeof import('naive-ui')['NDynamicInput']
|
||||
NEllipsis: typeof import('naive-ui')['NEllipsis']
|
||||
NForm: typeof import('naive-ui')['NForm']
|
||||
NFormItem: typeof import('naive-ui')['NFormItem']
|
||||
NGi: typeof import('naive-ui')['NGi']
|
||||
NGrid: typeof import('naive-ui')['NGrid']
|
||||
NH1: typeof import('naive-ui')['NH1']
|
||||
NH2: typeof import('naive-ui')['NH2']
|
||||
NH3: typeof import('naive-ui')['NH3']
|
||||
NIcon: typeof import('naive-ui')['NIcon']
|
||||
NImage: typeof import('naive-ui')['NImage']
|
||||
NInputGroup: typeof import('naive-ui')['NInputGroup']
|
||||
NInputGroupLabel: typeof import('naive-ui')['NInputGroupLabel']
|
||||
NInputNumber: typeof import('naive-ui')['NInputNumber']
|
||||
NLabel: typeof import('naive-ui')['NLabel']
|
||||
NLayout: typeof import('naive-ui')['NLayout']
|
||||
NLayoutSider: typeof import('naive-ui')['NLayoutSider']
|
||||
NMenu: typeof import('naive-ui')['NMenu']
|
||||
NProgress: typeof import('naive-ui')['NProgress']
|
||||
NScrollbar: typeof import('naive-ui')['NScrollbar']
|
||||
NSlider: typeof import('naive-ui')['NSlider']
|
||||
NSpin: typeof import('naive-ui')['NSpin']
|
||||
NStatistic: typeof import('naive-ui')['NStatistic']
|
||||
NSwitch: typeof import('naive-ui')['NSwitch']
|
||||
NTable: typeof import('naive-ui')['NTable']
|
||||
NTag: typeof import('naive-ui')['NTag']
|
||||
NumeronymGenerator: typeof import('./src/tools/numeronym-generator/numeronym-generator.vue')['default']
|
||||
OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default']
|
||||
PasswordStrengthAnalyser: typeof import('./src/tools/password-strength-analyser/password-strength-analyser.vue')['default']
|
||||
|
@ -159,6 +186,7 @@ declare module '@vue/runtime-core' {
|
|||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
RsaKeyPairGenerator: typeof import('./src/tools/rsa-key-pair-generator/rsa-key-pair-generator.vue')['default']
|
||||
SafelinkDecoder: typeof import('./src/tools/safelink-decoder/safelink-decoder.vue')['default']
|
||||
SlugifyString: typeof import('./src/tools/slugify-string/slugify-string.vue')['default']
|
||||
SpanCopyable: typeof import('./src/components/SpanCopyable.vue')['default']
|
||||
SqlPrettify: typeof import('./src/tools/sql-prettify/sql-prettify.vue')['default']
|
||||
|
|
|
@ -304,6 +304,10 @@ tools:
|
|||
title: IPv4 subnet calculator
|
||||
description: Parse your IPv4 CIDR blocks and get all the info you need about your sub network.
|
||||
|
||||
ipv6-subnet-calculator:
|
||||
title: IPv6 subnet calculator
|
||||
description: Parse your IPv6 CIDR blocks and get all the info you need about your sub network.
|
||||
|
||||
og-meta-generator:
|
||||
title: Open graph meta generator
|
||||
description: Generate open-graph and socials html meta tags for your website.
|
||||
|
|
|
@ -300,6 +300,10 @@ tools:
|
|||
title: IPv4子网计算器
|
||||
description: 解析IPv4 CIDR块,并获取有关子网络的所有所需信息。
|
||||
|
||||
ipv6-subnet-calculator:
|
||||
title: IPv6子网计算器
|
||||
description: 解析IPv6 CIDR块,并获取有关子网络的所有所需信息。
|
||||
|
||||
og-meta-generator:
|
||||
title: 开放式图形元生成器
|
||||
description: 为您的网站生成开放式图形和社交html元标记。
|
||||
|
|
|
@ -64,6 +64,7 @@
|
|||
"highlight.js": "^11.7.0",
|
||||
"iarna-toml-esm": "^3.0.5",
|
||||
"ibantools": "^4.3.3",
|
||||
"ip-address": "^9.0.5",
|
||||
"json5": "^2.2.3",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"libphonenumber-js": "^1.10.28",
|
||||
|
|
28
pnpm-lock.yaml
generated
28
pnpm-lock.yaml
generated
|
@ -92,6 +92,9 @@ dependencies:
|
|||
ibantools:
|
||||
specifier: ^4.3.3
|
||||
version: 4.3.3
|
||||
ip-address:
|
||||
specifier: ^9.0.5
|
||||
version: 9.0.5
|
||||
json5:
|
||||
specifier: ^2.2.3
|
||||
version: 2.2.3
|
||||
|
@ -3351,7 +3354,7 @@ packages:
|
|||
dependencies:
|
||||
'@unhead/dom': 0.5.1
|
||||
'@unhead/schema': 0.5.1
|
||||
'@vueuse/shared': 10.7.2(vue@3.3.4)
|
||||
'@vueuse/shared': 10.9.0(vue@3.3.4)
|
||||
unhead: 0.5.1
|
||||
vue: 3.3.4
|
||||
transitivePeerDependencies:
|
||||
|
@ -3993,10 +3996,10 @@ packages:
|
|||
- vue
|
||||
dev: false
|
||||
|
||||
/@vueuse/shared@10.7.2(vue@3.3.4):
|
||||
resolution: {integrity: sha512-qFbXoxS44pi2FkgFjPvF4h7c9oMDutpyBdcJdMYIMg9XyXli2meFMuaKn+UMgsClo//Th6+beeCgqweT/79BVA==}
|
||||
/@vueuse/shared@10.9.0(vue@3.3.4):
|
||||
resolution: {integrity: sha512-Uud2IWncmAfJvRaFYzv5OHDli+FbOzxiVEQdLCKQKLyhz94PIyFC3CHcH7EDMwIn8NPtD06+PNbC/PiO0LGLtw==}
|
||||
dependencies:
|
||||
vue-demi: 0.14.6(vue@3.3.4)
|
||||
vue-demi: 0.14.7(vue@3.3.4)
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
- vue
|
||||
|
@ -6177,6 +6180,14 @@ packages:
|
|||
sprintf-js: 1.1.2
|
||||
dev: false
|
||||
|
||||
/ip-address@9.0.5:
|
||||
resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==}
|
||||
engines: {node: '>= 12'}
|
||||
dependencies:
|
||||
jsbn: 1.1.0
|
||||
sprintf-js: 1.1.3
|
||||
dev: false
|
||||
|
||||
/ip-cidr@3.1.0:
|
||||
resolution: {integrity: sha512-HUCn4snshEX1P8cja/IyU3qk8FVDW8T5zZcegDFbu4w7NojmAhk5NcOgj3M8+0fmumo1afJTPDtJlzsxLdOjtg==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
|
@ -8183,6 +8194,10 @@ packages:
|
|||
resolution: {integrity: sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==}
|
||||
dev: false
|
||||
|
||||
/sprintf-js@1.1.3:
|
||||
resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==}
|
||||
dev: false
|
||||
|
||||
/sql-formatter@13.0.0:
|
||||
resolution: {integrity: sha512-V21cVvge4rhn9Fa7K/fTKcmPM+x1yee6Vhq8ZwgaWh3VPBqApgsaoFB5kLAhiqRo5AmSaRyLU7LIdgnNwH01/w==}
|
||||
hasBin: true
|
||||
|
@ -9151,8 +9166,8 @@ packages:
|
|||
vue: 3.3.4
|
||||
dev: false
|
||||
|
||||
/vue-demi@0.14.6(vue@3.3.4):
|
||||
resolution: {integrity: sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==}
|
||||
/vue-demi@0.14.7(vue@3.3.4):
|
||||
resolution: {integrity: sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==}
|
||||
engines: {node: '>=12'}
|
||||
hasBin: true
|
||||
requiresBuild: true
|
||||
|
@ -9442,6 +9457,7 @@ packages:
|
|||
|
||||
/workbox-google-analytics@7.0.0:
|
||||
resolution: {integrity: sha512-MEYM1JTn/qiC3DbpvP2BVhyIH+dV/5BjHk756u9VbwuAhu0QHyKscTnisQuz21lfRpOwiS9z4XdqeVAKol0bzg==}
|
||||
deprecated: It is not compatible with newer versions of GA starting with v4, as long as you are using GAv3 it should be ok, but the package is not longer being maintained
|
||||
dependencies:
|
||||
workbox-background-sync: 7.0.0
|
||||
workbox-core: 7.0.0
|
||||
|
|
|
@ -34,6 +34,7 @@ import { tool as ipv4AddressConverter } from './ipv4-address-converter';
|
|||
import { tool as benchmarkBuilder } from './benchmark-builder';
|
||||
import { tool as userAgentParser } from './user-agent-parser';
|
||||
import { tool as ipv4SubnetCalculator } from './ipv4-subnet-calculator';
|
||||
import { tool as ipv6SubnetCalculator } from './ipv6-subnet-calculator';
|
||||
import { tool as dockerRunToDockerComposeConverter } from './docker-run-to-docker-compose-converter';
|
||||
import { tool as htmlWysiwygEditor } from './html-wysiwyg-editor';
|
||||
import { tool as rsaKeyPairGenerator } from './rsa-key-pair-generator';
|
||||
|
@ -152,7 +153,7 @@ export const toolsByCategory: ToolCategory[] = [
|
|||
},
|
||||
{
|
||||
name: 'Network',
|
||||
components: [ipv4SubnetCalculator, ipv4AddressConverter, ipv4RangeExpander, macAddressLookup, macAddressGenerator, ipv6UlaGenerator],
|
||||
components: [ipv4SubnetCalculator, ipv6SubnetCalculator, ipv4AddressConverter, ipv4RangeExpander, macAddressLookup, macAddressGenerator, ipv6UlaGenerator],
|
||||
},
|
||||
{
|
||||
name: 'Math',
|
||||
|
|
12
src/tools/ipv6-subnet-calculator/index.ts
Normal file
12
src/tools/ipv6-subnet-calculator/index.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { RouterOutlined } from '@vicons/material';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: translate('tools.ipv6-subnet-calculator.title'),
|
||||
path: '/ipv6-subnet-calculator',
|
||||
description: translate('tools.ipv6-subnet-calculator.description'),
|
||||
keywords: ['ipv6', 'subnet', 'calculator', 'mask', 'network', 'cidr', 'netmask', 'bitmask', 'broadcast', 'address'],
|
||||
component: () => import('./ipv6-subnet-calculator.vue'),
|
||||
icon: RouterOutlined,
|
||||
});
|
93
src/tools/ipv6-subnet-calculator/ipv6-subnet-calculator.vue
Normal file
93
src/tools/ipv6-subnet-calculator/ipv6-subnet-calculator.vue
Normal file
|
@ -0,0 +1,93 @@
|
|||
<script setup lang="ts">
|
||||
import { Address6 } from 'ip-address';
|
||||
import { useStorage } from '@vueuse/core';
|
||||
import { withDefaultOnError } from '@/utils/defaults';
|
||||
import { isNotThrowing } from '@/utils/boolean';
|
||||
import SpanCopyable from '@/components/SpanCopyable.vue';
|
||||
|
||||
const ip = useStorage('ipv6-subnet-calculator:ip', 'fd00::1/64');
|
||||
|
||||
const getNetworkInfo = (address: string) => new Address6(address.trim());
|
||||
|
||||
const networkInfo = computed(() => withDefaultOnError(() => getNetworkInfo(ip.value), undefined));
|
||||
|
||||
const ipValidationRules = [
|
||||
{
|
||||
message: 'We cannot parse this address, check the format',
|
||||
validator: (value: string) => isNotThrowing(() => getNetworkInfo(value.trim())),
|
||||
},
|
||||
];
|
||||
|
||||
const sections: {
|
||||
label: string
|
||||
getValue: (blocks: Address6) => string | undefined
|
||||
undefinedFallback?: string
|
||||
}[] = [
|
||||
{
|
||||
label: 'IP address',
|
||||
getValue: (block: Address6) => block.correctForm(),
|
||||
},
|
||||
{
|
||||
label: 'Full IP address',
|
||||
getValue: (block: Address6) => block.canonicalForm(),
|
||||
},
|
||||
{
|
||||
label: 'Total IP addresses',
|
||||
getValue: (block: Address6) => {
|
||||
const totalAddresses = BigInt(2) ** BigInt(128 - block.subnetMask);
|
||||
return totalAddresses.toString();
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Total networks',
|
||||
getValue: ({ subnetMask }) => subnetMask <= 64 ? (BigInt(2) ** BigInt(64 - subnetMask)).toString() : '',
|
||||
},
|
||||
{
|
||||
label: 'Netmask',
|
||||
getValue: ({ subnetMask }) => subnetMask.toString(),
|
||||
},
|
||||
{
|
||||
label: 'Network size',
|
||||
getValue: (block: Address6) => block.possibleSubnets().toString(),
|
||||
},
|
||||
{
|
||||
label: 'First address',
|
||||
getValue: (block: Address6) => block.startAddress().correctForm(),
|
||||
},
|
||||
{
|
||||
label: 'Last address',
|
||||
getValue: (block: Address6) => block.endAddress().correctForm(),
|
||||
},
|
||||
{
|
||||
label: 'IP range',
|
||||
getValue: (block: Address6) => `${block.startAddress().correctForm()} - ${block.endAddress().correctForm()}`,
|
||||
},
|
||||
];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<c-input-text
|
||||
v-model:value="ip" label="An IPv6 address with or without mask" placeholder="The ipv6 address..."
|
||||
:validation-rules="ipValidationRules" mb-4
|
||||
/>
|
||||
|
||||
<div v-if="networkInfo">
|
||||
<n-table>
|
||||
<tbody>
|
||||
<tr v-for="{ getValue, label, undefinedFallback } in sections" :key="label">
|
||||
<td font-bold>
|
||||
{{ label }}
|
||||
</td>
|
||||
<td>
|
||||
<SpanCopyable v-if="getValue(networkInfo)" :value="getValue(networkInfo)" />
|
||||
<span v-else op-70>
|
||||
{{ undefinedFallback }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</n-table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
Loading…
Add table
Add a link
Reference in a new issue