Skip to content

Commit 03f99d6

Browse files
committed
feat(new tool): IP Geolocation
IP Geolocation information using ip-api.com FIx CorentinTh#454
1 parent 7f5fa00 commit 03f99d6

File tree

4 files changed

+135
-1
lines changed

4 files changed

+135
-1
lines changed

components.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ declare module '@vue/runtime-core' {
112112
IconMdiVideo: typeof import('~icons/mdi/video')['default']
113113
InputCopyable: typeof import('./src/components/InputCopyable.vue')['default']
114114
IntegerBaseConverter: typeof import('./src/tools/integer-base-converter/integer-base-converter.vue')['default']
115+
IpGeoLocation: typeof import('./src/tools/ip-geo-location/ip-geo-location.vue')['default']
115116
Ipv4AddressConverter: typeof import('./src/tools/ipv4-address-converter/ipv4-address-converter.vue')['default']
116117
Ipv4RangeExpander: typeof import('./src/tools/ipv4-range-expander/ipv4-range-expander.vue')['default']
117118
Ipv4SubnetCalculator: typeof import('./src/tools/ipv4-subnet-calculator/ipv4-subnet-calculator.vue')['default']

src/tools/index.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { tool as base64FileConverter } from './base64-file-converter';
22
import { tool as base64StringConverter } from './base64-string-converter';
33
import { tool as basicAuthGenerator } from './basic-auth-generator';
44
import { tool as textToUnicode } from './text-to-unicode';
5+
import { tool as ipGeoLocation } from './ip-geo-location';
56
import { tool as pdfSignatureChecker } from './pdf-signature-checker';
67
import { tool as numeronymGenerator } from './numeronym-generator';
78
import { tool as macAddressGenerator } from './mac-address-generator';
@@ -147,7 +148,15 @@ export const toolsByCategory: ToolCategory[] = [
147148
},
148149
{
149150
name: 'Network',
150-
components: [ipv4SubnetCalculator, ipv4AddressConverter, ipv4RangeExpander, macAddressLookup, macAddressGenerator, ipv6UlaGenerator],
151+
components: [
152+
ipv4SubnetCalculator,
153+
ipv4AddressConverter,
154+
ipv4RangeExpander,
155+
macAddressLookup,
156+
macAddressGenerator,
157+
ipv6UlaGenerator,
158+
ipGeoLocation,
159+
],
151160
},
152161
{
153162
name: 'Math',

src/tools/ip-geo-location/index.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { World } from '@vicons/tabler';
2+
import { defineTool } from '../tool';
3+
4+
export const tool = defineTool({
5+
name: 'IP Geo Location',
6+
path: '/ip-geo-location',
7+
description: 'Retrieve information about an IPv4/6 address or domain location',
8+
keywords: ['ip', 'domain', 'geo', 'location'],
9+
component: () => import('./ip-geo-location.vue'),
10+
icon: World,
11+
createdAt: new Date('2024-01-17'),
12+
});
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<script setup lang="ts">
2+
import type { CKeyValueListItems } from '@/ui/c-key-value-list/c-key-value-list.types';
3+
4+
const ipOrDomain = ref('8.8.8.8');
5+
const errorMessage = ref('');
6+
7+
const fields: Array<{ field: string; name: string }> = [
8+
{ field: 'message', name: 'Message' },
9+
{ field: 'continent', name: 'Continent Name' },
10+
{ field: 'continentCode', name: 'Continent code' },
11+
{ field: 'country', name: 'Country Name' },
12+
{ field: 'countryCode', name: 'Country Code' },
13+
{ field: 'region', name: 'Region/state Code' },
14+
{ field: 'regionName', name: 'Region/state Name' },
15+
{ field: 'city', name: 'City' },
16+
{ field: 'district', name: 'District' },
17+
{ field: 'zip', name: 'Zip Code' },
18+
{ field: 'lat', name: 'Latitude' },
19+
{ field: 'lon', name: 'Longitude' },
20+
{ field: 'timezone', name: 'Timezone' },
21+
{ field: 'offset', name: 'Timezone UTC DST offset (in seconds)' },
22+
{ field: 'currency', name: 'National Currency' },
23+
{ field: 'isp', name: 'ISP Name' },
24+
{ field: 'org', name: 'Organization Name' },
25+
{ field: 'as', name: 'AS Number and Organization' },
26+
{ field: 'asname', name: 'AS name (RIR)' },
27+
{ field: 'reverse', name: 'Reverse DNS of the IP' },
28+
{ field: 'mobile', name: 'Mobile (cellular) connection' },
29+
{ field: 'proxy', name: 'Proxy, VPN or Tor exit address' },
30+
{ field: 'hosting', name: 'Hosting, colocated or data center' },
31+
{ field: 'query', name: 'IP used for the query' },
32+
];
33+
34+
const geoInfos = ref<CKeyValueListItems>([]);
35+
const geoInfosData = ref<any>({});
36+
const status = ref<'pending' | 'error' | 'success'>('pending');
37+
38+
const openStreetMapUrl = computed(
39+
() => {
40+
const gpsLatitude = geoInfosData.value.lat;
41+
const gpsLongitude = geoInfosData.value.lon;
42+
return gpsLatitude && gpsLongitude ? `https://www.openstreetmap.org/?mlat=${gpsLatitude}&mlon=${gpsLongitude}#map=18/${gpsLatitude}/${gpsLongitude}` : undefined;
43+
},
44+
);
45+
46+
async function onGetInfos() {
47+
try {
48+
status.value = 'pending';
49+
50+
const geoInfoQueryResponse = await fetch(`http://ip-api.com/json/${ipOrDomain.value}`);
51+
if (!geoInfoQueryResponse.ok) {
52+
throw geoInfoQueryResponse.statusText;
53+
}
54+
55+
const data = await geoInfoQueryResponse.json();
56+
57+
const allGeoInfos = [];
58+
for (const field of fields) {
59+
if (data[field.field]) {
60+
allGeoInfos.push({
61+
label: field.name,
62+
value: data[field.field],
63+
});
64+
}
65+
}
66+
67+
status.value = 'success';
68+
geoInfos.value = allGeoInfos;
69+
geoInfosData.value = data;
70+
}
71+
catch (e: any) {
72+
errorMessage.value = e.toString();
73+
status.value = 'error';
74+
return [];
75+
}
76+
}
77+
</script>
78+
79+
<template>
80+
<div>
81+
<div flex items-center gap-2>
82+
<c-input-text
83+
v-model:value="ipOrDomain"
84+
placeholder="Enter an IPv4/6 or a domain name"
85+
@update:value="() => { status = 'pending' }"
86+
/>
87+
<c-button align-center @click="onGetInfos">
88+
Get GEO Location Infos
89+
</c-button>
90+
</div>
91+
92+
<n-divider />
93+
94+
<c-card v-if="status === 'pending'" mt-5>
95+
Click on button above to get latest infos
96+
</c-card>
97+
98+
<c-card v-if="status === 'success' && openStreetMapUrl" mt-4>
99+
<c-button :href="openStreetMapUrl" target="_blank">
100+
Localize on Open Street Map
101+
</c-button>
102+
</c-card>
103+
104+
<c-card v-if="status === 'success'" mt-5>
105+
<c-key-value-list :items="geoInfos" />
106+
</c-card>
107+
108+
<n-alert v-if="status === 'error'" title="Errors occured" type="error" mt-5>
109+
{{ errorMessage }}
110+
</n-alert>
111+
</div>
112+
</template>

0 commit comments

Comments
 (0)