Merge 19efa59aa9 into 07eea0f484
				
					
				
			This commit is contained in:
		
						commit
						36a470b4e3
					
				
							
								
								
									
										5
									
								
								components.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								components.d.ts
									
									
									
									
										vendored
									
									
								
							| @ -37,6 +37,7 @@ declare module '@vue/runtime-core' { | |||||||
|     'CFileUpload.demo': typeof import('./src/ui/c-file-upload/c-file-upload.demo.vue')['default'] |     'CFileUpload.demo': typeof import('./src/ui/c-file-upload/c-file-upload.demo.vue')['default'] | ||||||
|     ChmodCalculator: typeof import('./src/tools/chmod-calculator/chmod-calculator.vue')['default'] |     ChmodCalculator: typeof import('./src/tools/chmod-calculator/chmod-calculator.vue')['default'] | ||||||
|     Chronometer: typeof import('./src/tools/chronometer/chronometer.vue')['default'] |     Chronometer: typeof import('./src/tools/chronometer/chronometer.vue')['default'] | ||||||
|  |     CidrInCidr: typeof import('./src/tools/cidr-in-cidr/cidr-in-cidr.vue')['default'] | ||||||
|     CInputText: typeof import('./src/ui/c-input-text/c-input-text.vue')['default'] |     CInputText: typeof import('./src/ui/c-input-text/c-input-text.vue')['default'] | ||||||
|     'CInputText.demo': typeof import('./src/ui/c-input-text/c-input-text.demo.vue')['default'] |     'CInputText.demo': typeof import('./src/ui/c-input-text/c-input-text.demo.vue')['default'] | ||||||
|     CKeyValueList: typeof import('./src/ui/c-key-value-list/c-key-value-list.vue')['default'] |     CKeyValueList: typeof import('./src/ui/c-key-value-list/c-key-value-list.vue')['default'] | ||||||
| @ -103,6 +104,7 @@ declare module '@vue/runtime-core' { | |||||||
|     IconMdiTriangleDown: typeof import('~icons/mdi/triangle-down')['default'] |     IconMdiTriangleDown: typeof import('~icons/mdi/triangle-down')['default'] | ||||||
|     InputCopyable: typeof import('./src/components/InputCopyable.vue')['default'] |     InputCopyable: typeof import('./src/components/InputCopyable.vue')['default'] | ||||||
|     IntegerBaseConverter: typeof import('./src/tools/integer-base-converter/integer-base-converter.vue')['default'] |     IntegerBaseConverter: typeof import('./src/tools/integer-base-converter/integer-base-converter.vue')['default'] | ||||||
|  |     IpInRange: typeof import('./src/tools/cidr-in-cidr/cidr-in-cidr.vue')['default'] | ||||||
|     Ipv4AddressConverter: typeof import('./src/tools/ipv4-address-converter/ipv4-address-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'] |     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'] |     Ipv4SubnetCalculator: typeof import('./src/tools/ipv4-subnet-calculator/ipv4-subnet-calculator.vue')['default'] | ||||||
| @ -130,7 +132,6 @@ declare module '@vue/runtime-core' { | |||||||
|     MetaTagGenerator: typeof import('./src/tools/meta-tag-generator/meta-tag-generator.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'] |     MimeTypes: typeof import('./src/tools/mime-types/mime-types.vue')['default'] | ||||||
|     NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default'] |     NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default'] | ||||||
|     NCheckbox: typeof import('naive-ui')['NCheckbox'] |  | ||||||
|     NCollapseTransition: typeof import('naive-ui')['NCollapseTransition'] |     NCollapseTransition: typeof import('naive-ui')['NCollapseTransition'] | ||||||
|     NConfigProvider: typeof import('naive-ui')['NConfigProvider'] |     NConfigProvider: typeof import('naive-ui')['NConfigProvider'] | ||||||
|     NDivider: typeof import('naive-ui')['NDivider'] |     NDivider: typeof import('naive-ui')['NDivider'] | ||||||
| @ -141,7 +142,6 @@ declare module '@vue/runtime-core' { | |||||||
|     NLayout: typeof import('naive-ui')['NLayout'] |     NLayout: typeof import('naive-ui')['NLayout'] | ||||||
|     NLayoutSider: typeof import('naive-ui')['NLayoutSider'] |     NLayoutSider: typeof import('naive-ui')['NLayoutSider'] | ||||||
|     NMenu: typeof import('naive-ui')['NMenu'] |     NMenu: typeof import('naive-ui')['NMenu'] | ||||||
|     NSpace: typeof import('naive-ui')['NSpace'] |  | ||||||
|     NTable: typeof import('naive-ui')['NTable'] |     NTable: typeof import('naive-ui')['NTable'] | ||||||
|     NumeronymGenerator: typeof import('./src/tools/numeronym-generator/numeronym-generator.vue')['default'] |     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'] |     OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default'] | ||||||
| @ -161,6 +161,7 @@ declare module '@vue/runtime-core' { | |||||||
|     RouterView: typeof import('vue-router')['RouterView'] |     RouterView: typeof import('vue-router')['RouterView'] | ||||||
|     RsaKeyPairGenerator: typeof import('./src/tools/rsa-key-pair-generator/rsa-key-pair-generator.vue')['default'] |     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'] |     SafelinkDecoder: typeof import('./src/tools/safelink-decoder/safelink-decoder.vue')['default'] | ||||||
|  |     SafelinkDecoder: typeof import('./src/tools/safelink-decoder/safelink-decoder.vue')['default'] | ||||||
|     SlugifyString: typeof import('./src/tools/slugify-string/slugify-string.vue')['default'] |     SlugifyString: typeof import('./src/tools/slugify-string/slugify-string.vue')['default'] | ||||||
|     SpanCopyable: typeof import('./src/components/SpanCopyable.vue')['default'] |     SpanCopyable: typeof import('./src/components/SpanCopyable.vue')['default'] | ||||||
|     SqlPrettify: typeof import('./src/tools/sql-prettify/sql-prettify.vue')['default'] |     SqlPrettify: typeof import('./src/tools/sql-prettify/sql-prettify.vue')['default'] | ||||||
|  | |||||||
| @ -70,6 +70,7 @@ | |||||||
|     "highlight.js": "^11.7.0", |     "highlight.js": "^11.7.0", | ||||||
|     "iarna-toml-esm": "^3.0.5", |     "iarna-toml-esm": "^3.0.5", | ||||||
|     "ibantools": "^4.3.3", |     "ibantools": "^4.3.3", | ||||||
|  |     "ip-matching": "^2.1.2", | ||||||
|     "js-base64": "^3.7.6", |     "js-base64": "^3.7.6", | ||||||
|     "json5": "^2.2.3", |     "json5": "^2.2.3", | ||||||
|     "jwt-decode": "^3.1.2", |     "jwt-decode": "^3.1.2", | ||||||
|  | |||||||
							
								
								
									
										14254
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										14254
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										48
									
								
								src/tools/cidr-in-cidr/cidr-in-cidr.service.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/tools/cidr-in-cidr/cidr-in-cidr.service.test.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,48 @@ | |||||||
|  | import { describe, expect, it } from 'vitest'; | ||||||
|  | import { cidrInCidr } from './cidr-in-cidr.service'; | ||||||
|  | 
 | ||||||
|  | describe('cidr-in-cidr', () => { | ||||||
|  |   describe('cidrInCidr', () => { | ||||||
|  |     it('should return correct inclusion', () => { | ||||||
|  |       expect(cidrInCidr({ baseRange: '192.168.0.0/16', ipOrRangeToTest: '192.168.0.1' }).isIncluded).toBe(true); // NOSONAR
 | ||||||
|  |       expect(cidrInCidr({ baseRange: '192.168.1.0/24', ipOrRangeToTest: '192.168.0.10' }).isIncluded).toBe(false); // NOSONAR
 | ||||||
|  |       expect(cidrInCidr({ baseRange: '192.168.1.*', ipOrRangeToTest: '192.168.0.10' }).isIncluded).toBe(false); // NOSONAR
 | ||||||
|  | 
 | ||||||
|  |       expect(cidrInCidr({ baseRange: '192.168.0.0/24', ipOrRangeToTest: '192.168.0.0/28' }).isIncluded).toBe(true); // NOSONAR
 | ||||||
|  |       expect(cidrInCidr({ baseRange: '192.168.20.0/24', ipOrRangeToTest: '192.168.1.0/28' }).isIncluded).toBe(false); // NOSONAR
 | ||||||
|  |       expect(cidrInCidr({ baseRange: '192.168.20.*', ipOrRangeToTest: '192.168.1.0/28' }).isIncluded).toBe(false); // NOSONAR
 | ||||||
|  |       expect(cidrInCidr({ baseRange: '192.168.0.*', ipOrRangeToTest: '192.168.0.0/28' }).isIncluded).toBe(true); // NOSONAR
 | ||||||
|  | 
 | ||||||
|  |       expect(cidrInCidr({ baseRange: '192.168.20.1-192.168.20.15', ipOrRangeToTest: '192.168.20.12' }).isIncluded).toBe(true); // NOSONAR
 | ||||||
|  |       expect(cidrInCidr({ baseRange: '192.168.20.1-192.168.20.15', ipOrRangeToTest: '192.168.20.20' }).isIncluded).toBe(false); // NOSONAR
 | ||||||
|  | 
 | ||||||
|  |       expect(cidrInCidr({ baseRange: '192.168.20.1-192.168.20.15', ipOrRangeToTest: '192.168.20.9-192.168.20.12' }).isIncluded).toBe(true); // NOSONAR
 | ||||||
|  |       expect(cidrInCidr({ baseRange: '192.168.20.1-192.168.20.15', ipOrRangeToTest: '192.168.20.9-192.168.20.20' }).isIncluded).toBe(false); // NOSONAR
 | ||||||
|  | 
 | ||||||
|  |       expect(cidrInCidr({ baseRange: '192.168.20.0-192.168.20.255', ipOrRangeToTest: '192.168.20.0/28' }).isIncluded).toBe(true); // NOSONAR
 | ||||||
|  |       expect(cidrInCidr({ baseRange: '192.168.20.0-192.168.20.255', ipOrRangeToTest: '192.168.1.0/28' }).isIncluded).toBe(false); // NOSONAR
 | ||||||
|  |       expect(cidrInCidr({ baseRange: '192.168.0.0-192.168.1.255', ipOrRangeToTest: '192.168.1.0/28' }).isIncluded).toBe(true); // NOSONAR
 | ||||||
|  |     }); | ||||||
|  |     it('should return correct subnet', () => { | ||||||
|  |       expect(cidrInCidr({ baseRange: '192.168.0.0/16', ipOrRangeToTest: '192.168.0.1' }).baseSubnets).to.deep.eq([ // NOSONAR
 | ||||||
|  |         { | ||||||
|  |           cidr: '192.168.0.0/16', // NOSONAR
 | ||||||
|  |           end: '192.168.255.255', // NOSONAR
 | ||||||
|  |           start: '192.168.0.0', // NOSONAR
 | ||||||
|  |         }, | ||||||
|  |       ]); | ||||||
|  |       expect(cidrInCidr({ baseRange: '192.168.20.1-192.168.20.3', ipOrRangeToTest: '192.168.1.0/28' }).baseSubnets).to.deep.eq([ // NOSONAR
 | ||||||
|  |         { | ||||||
|  |           cidr: '192.168.20.1/32', // NOSONAR
 | ||||||
|  |           end: '192.168.20.1', // NOSONAR
 | ||||||
|  |           start: '192.168.20.1', // NOSONAR
 | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           cidr: '192.168.20.2/31', // NOSONAR
 | ||||||
|  |           end: '192.168.20.3', // NOSONAR
 | ||||||
|  |           start: '192.168.20.2', // NOSONAR
 | ||||||
|  |         }, | ||||||
|  |       ]); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | }); | ||||||
							
								
								
									
										28
									
								
								src/tools/cidr-in-cidr/cidr-in-cidr.service.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/tools/cidr-in-cidr/cidr-in-cidr.service.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | |||||||
|  | import { getMatch } from 'ip-matching'; | ||||||
|  | 
 | ||||||
|  | export function cidrInCidr( | ||||||
|  |   { baseRange, ipOrRangeToTest }: | ||||||
|  |   { | ||||||
|  |     baseRange: string | ||||||
|  |     ipOrRangeToTest: string | ||||||
|  |   }) { | ||||||
|  |   const baseMatchMasks = getMatch(baseRange)?.convertToMasks() || []; | ||||||
|  |   const ipOrRangeToTestMatchMasks = getMatch(ipOrRangeToTest)?.convertToMasks() || []; | ||||||
|  | 
 | ||||||
|  |   const baseSubnets = baseMatchMasks.map((mask) => { | ||||||
|  |     const subnet = mask.convertToSubnet(); | ||||||
|  |     if (!subnet) { | ||||||
|  |       return { cidr: '', start: '', end: '' }; | ||||||
|  |     } | ||||||
|  |     return { | ||||||
|  |       cidr: subnet.toString(), | ||||||
|  |       start: subnet.getFirst().toString(), | ||||||
|  |       end: subnet.getLast().toString(), | ||||||
|  |     }; | ||||||
|  |   }).filter(subnet => subnet.cidr !== ''); | ||||||
|  | 
 | ||||||
|  |   return { | ||||||
|  |     baseSubnets, | ||||||
|  |     isIncluded: baseMatchMasks.some(baseMask => ipOrRangeToTestMatchMasks.every(ipOrRangeMask => ipOrRangeMask.isSubsetOf(baseMask))), | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										80
									
								
								src/tools/cidr-in-cidr/cidr-in-cidr.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								src/tools/cidr-in-cidr/cidr-in-cidr.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,80 @@ | |||||||
|  | <script setup lang="ts"> | ||||||
|  | import { useStorage } from '@vueuse/core'; | ||||||
|  | import { Check as CheckIcon, LetterX as CrossIcon } from '@vicons/tabler'; | ||||||
|  | import { getMatch } from 'ip-matching'; | ||||||
|  | import { cidrInCidr } from './cidr-in-cidr.service'; | ||||||
|  | import { withDefaultOnError } from '@/utils/defaults'; | ||||||
|  | import { isNotThrowing } from '@/utils/boolean'; | ||||||
|  | import SpanCopyable from '@/components/SpanCopyable.vue'; | ||||||
|  | 
 | ||||||
|  | const baseRange = useStorage('cidr-in-cidr:range', '192.168.0.1/24'); // NOSONAR | ||||||
|  | const ipOrRangeToTest = useStorage('cidr-in-cidr:ip', '192.168.0.1'); // NOSONAR | ||||||
|  | 
 | ||||||
|  | const matchResult = computed(() => withDefaultOnError( | ||||||
|  |   () => cidrInCidr({ baseRange: baseRange.value, ipOrRangeToTest: ipOrRangeToTest.value }), | ||||||
|  |   { baseSubnets: [], isIncluded: false })); | ||||||
|  | 
 | ||||||
|  | const rangeValidationRules = [ | ||||||
|  |   { | ||||||
|  |     message: 'We cannot parse this CIDR/IP Range/Mask/Wildcard, check the format', | ||||||
|  |     validator: (value: string) => isNotThrowing(() => getMatch(value)) && getMatch(value), | ||||||
|  |   }, | ||||||
|  | ]; | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <template> | ||||||
|  |   <div> | ||||||
|  |     <c-input-text | ||||||
|  |       v-model:value="baseRange" | ||||||
|  |       label="An IPv4/6 CIDR/Range/Mask/Wildcard (base network)" | ||||||
|  |       placeholder="The ipv4/6 CIDR..." | ||||||
|  |       :validation-rules="rangeValidationRules" | ||||||
|  |       mb-4 | ||||||
|  |     /> | ||||||
|  | 
 | ||||||
|  |     <c-input-text | ||||||
|  |       v-model:value="ipOrRangeToTest" | ||||||
|  |       label="An IPv4/6 CIDR/Range/Mask/Wildcard (to test for inclusion)" | ||||||
|  |       placeholder="The An IPv4/6 CIDR/Range/Mask/Wildcard..." | ||||||
|  |       :validation-rules="rangeValidationRules" | ||||||
|  |       mb-4 | ||||||
|  |     /> | ||||||
|  | 
 | ||||||
|  |     <n-divider /> | ||||||
|  | 
 | ||||||
|  |     <div flex justify-center> | ||||||
|  |       <span v-if="matchResult.isIncluded"> | ||||||
|  |         <n-icon color="green"> | ||||||
|  |           <CheckIcon /> | ||||||
|  |         </n-icon> | ||||||
|  |         Included | ||||||
|  |       </span> | ||||||
|  |       <span v-else> | ||||||
|  |         <n-icon color="red"> | ||||||
|  |           <CrossIcon /> | ||||||
|  |         </n-icon> | ||||||
|  |         Not included | ||||||
|  |       </span> | ||||||
|  |     </div> | ||||||
|  | 
 | ||||||
|  |     <n-divider /> | ||||||
|  | 
 | ||||||
|  |     <c-card title="Subnets"> | ||||||
|  |       <n-table> | ||||||
|  |         <tbody> | ||||||
|  |           <tr v-for="{ cidr, start, end } in matchResult.baseSubnets" :key="cidr"> | ||||||
|  |             <td font-bold> | ||||||
|  |               <SpanCopyable :value="cidr" /> | ||||||
|  |             </td> | ||||||
|  |             <td> | ||||||
|  |               <SpanCopyable :value="start" /> | ||||||
|  |             </td> | ||||||
|  |             <td> | ||||||
|  |               <SpanCopyable :value="end" /> | ||||||
|  |             </td> | ||||||
|  |           </tr> | ||||||
|  |         </tbody> | ||||||
|  |       </n-table> | ||||||
|  |     </c-card> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
							
								
								
									
										13
									
								
								src/tools/cidr-in-cidr/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/tools/cidr-in-cidr/index.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | |||||||
|  | import { UnfoldMoreOutlined } from '@vicons/material'; | ||||||
|  | import { defineTool } from '../tool'; | ||||||
|  | 
 | ||||||
|  | export const tool = defineTool({ | ||||||
|  |   name: 'IPv4-6/IPRange/CIDR in IPRange/CIDR/IPMask', | ||||||
|  |   path: '/cidr-in-cidr', | ||||||
|  |   description: 'Given a CIDR/IP Range/Wildcard IP/IP Mask, tell if a given IPv4-6/Range/CIDR/Wildcard IP/IP Mask is in subnet range', | ||||||
|  |   keywords: ['ip', 'cidr', 'range', 'mask', 'wildcard', 'ipv4', 'ipv6', 'subnet', 'include', 'inclusion'], | ||||||
|  |   component: () => import('./cidr-in-cidr.vue'), | ||||||
|  |   redirectFrom: ['/ip-in-range'], | ||||||
|  |   icon: UnfoldMoreOutlined, | ||||||
|  |   createdAt: new Date('2025-01-12'), | ||||||
|  | }); | ||||||
| @ -86,6 +86,7 @@ import { tool as urlParser } from './url-parser'; | |||||||
| import { tool as uuidGenerator } from './uuid-generator'; | import { tool as uuidGenerator } from './uuid-generator'; | ||||||
| import { tool as macAddressLookup } from './mac-address-lookup'; | import { tool as macAddressLookup } from './mac-address-lookup'; | ||||||
| import { tool as xmlFormatter } from './xml-formatter'; | import { tool as xmlFormatter } from './xml-formatter'; | ||||||
|  | import { tool as cidrInCidr } from './cidr-in-cidr'; | ||||||
| import { tool as yamlViewer } from './yaml-viewer'; | import { tool as yamlViewer } from './yaml-viewer'; | ||||||
| 
 | 
 | ||||||
| export const toolsByCategory: ToolCategory[] = [ | export const toolsByCategory: ToolCategory[] = [ | ||||||
| @ -164,7 +165,15 @@ export const toolsByCategory: ToolCategory[] = [ | |||||||
|   }, |   }, | ||||||
|   { |   { | ||||||
|     name: 'Network', |     name: 'Network', | ||||||
|     components: [ipv4SubnetCalculator, ipv4AddressConverter, ipv4RangeExpander, macAddressLookup, macAddressGenerator, ipv6UlaGenerator], |     components: [ | ||||||
|  |       ipv4SubnetCalculator, | ||||||
|  |       ipv4AddressConverter, | ||||||
|  |       cidrInCidr, | ||||||
|  |       ipv4RangeExpander, | ||||||
|  |       macAddressLookup, | ||||||
|  |       macAddressGenerator, | ||||||
|  |       ipv6UlaGenerator, | ||||||
|  |     ], | ||||||
|   }, |   }, | ||||||
|   { |   { | ||||||
|     name: 'Math', |     name: 'Math', | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user