Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions 404.template.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<!doctype html>
<html lang="en">
<title>404 ip.dog</title>
<title>404 - ip.smht.eu</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
:root {
Expand Down Expand Up @@ -33,5 +33,5 @@
color: var(--action-color);
}
</style>
<h1>404 page not found</h1>
<a href="/">home page</a>
<h1>404 - stránka nenalezena</h1>
<a href="/">zpět</a>
8 changes: 4 additions & 4 deletions assets/minimal-prototype.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<!doctype html>
<html lang="en">
<title>ip.dog</title>
<meta name="description" content="The fastest way to get your IP address.">
<title>ip.smht.eu</title>
<meta name="description" content="Nejrychlejší cesta jak získat Vaši IP adresu bezpečně">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body { font: 25px system-ui; cursor: pointer; text-align: center; }
Expand All @@ -19,13 +19,13 @@
</style>
<h1 class="v6">2001:861:5286:7a70:5caa:1ba:6f57:dfca</h1>
<h1 class="v4"hidden>233.233.233.222</h1>
<button>Click anywhere to copy</button>
<button>Klikni kamkoliv pro zkopírování</button>
<script>
document.addEventListener('click', listener)
document.addEventListener('keypress', listener)
function listener() {
navigator.clipboard.writeText(document.querySelector('h1'))
document.querySelector('button').innerHTML = 'Copied'
document.querySelector('button').innerHTML = 'Zkopírováno'
}
</script>
<script src="more.js" async></script>
Binary file added favicon.ico
Binary file not shown.
24 changes: 13 additions & 11 deletions index.template.html

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"devDependencies": {
"wrangler": "3.44.0"
"devDependencies": {
"wrangler": "^4.27.0"
},
"scripts": {
"start": "wrangler dev --assets 'assets/'",
Expand Down
9 changes: 9 additions & 0 deletions translations/cs.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Klikni kamkoliv pro zkopírování
Zkopírováno
ip.dog je nejrychlejší cesta jak získat Vaši IP adresu bezpečně. 🐶
Extra krátká doména.
Celá stránka je kopírovací tlačítko, anebo můžete zmáčknout jakoukoliv klávesu, abyste nemuseli pohnout prstem/myší.
Je to dynamická stránka s rychlostí statické, která je díky Cloudflare Workers distribuována blízko Vás kdekoli na světě.
Celá stránka se vejde do jednoho paketu TCP (≤ 1460 bajtů), aby se zabránilo obousměrnému zpoždění.
Vícejazyčnost (<a href="/translate">překlad</a> zabere dvě minuty), tmavý režim, přístupnost.
Vytvořil <a href="https://dieulot.fr/">Alexandre Dieulot</a>. <a href="https://github.com/dieulot/ip.dog">Zdrojový kód</a> je dostupný.
136 changes: 109 additions & 27 deletions worker.js
Original file line number Diff line number Diff line change
@@ -1,86 +1,149 @@
import e404Html from './404.template.html'

const translations = {
'de': (await import('./translations/de.txt')).default,
'en': (await import('./translations/en.txt')).default,
'fr': (await import('./translations/fr.txt')).default,
'hi': (await import('./translations/hi.txt')).default,
'cs': (await import('./translations/cs.txt')).default,
}
// The above cannot put in a loop because Wrangler (2.11) chokes on imports with dynamic names.

const indexHtml = (await import('./index.template.html')).default
.replaceAll('\n', '')
.replaceAll(' ', '')
.replaceAll(': ', ':')
.replaceAll(';}', '}')

const translateHtml = (await import('./translate.template.html')).default
.replace('{{TEXT}}', translations['en']
.trim()
.replaceAll('<', '&lt;')
.replaceAll('>', '&gt;')
)

export default {
fetch,
}

async function fetch(request, env) {
const {pathname} = new URL(request.url)

let ip
console.log('Country:', request.cf?.country)
console.log('Accept-Language:', request.headers.get('accept-language'))

let ipData
if (env.isDev) {
ip = generateRandomIpv4OrIpv6Address()
ipData = generateRandomIpData()
}
else {
ip = request.headers.get('cf-connecting-ip')
ipData = getIpData(request)
}

let body = ''
let status = 200

const headers = new Headers()
headers.append('Content-Type', 'text/html; charset=utf-8')
headers.append('Strict-Transport-Security', 'max-age=33333333; includeSubDomains; preload')

switch (pathname) {
case '/':
body = transform(indexHtml, ip, getLang(request.headers.get('accept-language')))
body = transform(indexHtml, ipData, getLang(request.headers.get('accept-language')))
break

case '/translate':
body = translateHtml
break

default:
status = 404
body = e404Html
}

return new Response(body, {
status,
headers,
})
}

function transform(html, ip, lang) {
function getIpData(request) {
// Získáme všechny možné IP adresy z různých headerů
const cfConnectingIp = request.headers.get('cf-connecting-ip')
const xForwardedFor = request.headers.get('x-forwarded-for')
const xRealIp = request.headers.get('x-real-ip')
const cfPseudoIpv4 = request.headers.get('cf-pseudo-ipv4')

// Sestavíme seznam všech možných IP adres
const allIps = []

if (cfPseudoIpv4) allIps.push(cfPseudoIpv4)
if (cfConnectingIp) allIps.push(cfConnectingIp)
if (xRealIp) allIps.push(xRealIp)
if (xForwardedFor) {
xForwardedFor.split(',').forEach(ip => allIps.push(ip.trim()))
}

// Odfiltrujeme prázdné hodnoty
const validIps = allIps.filter(ip => ip && ip !== '')

console.log('All available IPs:', validIps)

// Najdeme IPv4 a IPv6 adresy
let ipv4 = null
let ipv6 = null

for (const ip of validIps) {
if (isIPv4(ip) && !ipv4) {
ipv4 = ip
} else if (isIPv6(ip) && !ipv6) {
ipv6 = ip
}
}

// Vytvoříme objekt s daty
const ipData = {
primary: ipv4 || ipv6 || 'unknown', // IPv4 prioritně
ipv4: ipv4,
ipv6: ipv6,
protocol: ipv4 ? 'IPv4' : ipv6 ? 'IPv6' : 'unknown'
}

console.log('IP Data:', ipData)
return ipData
}

function isIPv4(ip) {
// Kontrola IPv4 formátu (xxx.xxx.xxx.xxx)
const ipv4Regex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
return ipv4Regex.test(ip)
}

function isIPv6(ip) {
// Kontrola IPv6 formátu
const ipv6Regex = /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/
return ipv6Regex.test(ip)
}

function transform(html, ipData, lang) {
const translationLines = translations[lang].split('\n')
html = html
.replace('{{LANG}}', lang)
.replaceAll(/\{\{LINE([0-9]+)\}\}/g, (all, p1) => {
return translationLines[p1 - 1]
})
.replaceAll('{{IP}}', ip)
.replace(' copyElement.value.length', ip.length)

.replaceAll('{{IP}}', ipData.primary)
.replace(' copyElement.value.length', ipData.primary.length)

// Přidáme podporu pro zobrazení obou IP adres
if (ipData.ipv4 && ipData.ipv6) {
html = html.replace('{{IP_INFO}}', `
<div class="ip-details">
<p><strong>Primární IP:</strong> ${ipData.primary} (${ipData.protocol})</p>
<p><strong>IPv4:</strong> ${ipData.ipv4}</p>
<p><strong>IPv6:</strong> ${ipData.ipv6}</p>
</div>
`)
} else {
html = html.replace('{{IP_INFO}}', '')
}

return html
}

function getLang(header) {
if (!header) {
return 'en'
}

header = header.toLowerCase()
const langs = header.split(/(?:,|;)/)
for (let lang of langs) {
Expand All @@ -92,15 +155,34 @@ function getLang(header) {
return base
}
}

return 'en'
}

function generateRandomIpv4OrIpv6Address() {
if (Math.random() < .5) {
return crypto.getRandomValues(new Uint8Array(4)).join('.')
function generateRandomIpData() {
const hasIpv4 = Math.random() < 0.9 // 90% šance na IPv4
const hasIpv6 = Math.random() < 0.6 // 60% šance na IPv6

let ipv4 = null
let ipv6 = null

if (hasIpv4) {
ipv4 = crypto.getRandomValues(new Uint8Array(4)).join('.')
}
else {
return Array.from(crypto.getRandomValues(new Uint16Array(8))).map((e) => e.toString(16)).join(':')

if (hasIpv6) {
ipv6 = Array.from(crypto.getRandomValues(new Uint16Array(8)))
.map((e) => e.toString(16)).join(':')
}

// Pokud nemáme ani jednu, vygenerujeme IPv4
if (!ipv4 && !ipv6) {
ipv4 = crypto.getRandomValues(new Uint8Array(4)).join('.')
}

return {
primary: ipv4 || ipv6,
ipv4: ipv4,
ipv6: ipv6,
protocol: ipv4 ? 'IPv4' : 'IPv6'
}
}
10 changes: 3 additions & 7 deletions wrangler.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,9 @@ main = "worker.js"
compatibility_date = "2024-03-26"
env = { }

[[routes]]
pattern = "ip.dog/*"
zone_id = "..."

[[routes]]
pattern = "www.ip.dog/*"
zone_id = "..."
# [[routes]]
# pattern = "ip.smht.eu/*"
# zone_id = "..."

[triggers]
crons = [ ]