diff --git a/bun.lockb b/bun.lockb index 39a60e9..a4739f5 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 546fd60..313092e 100644 --- a/package.json +++ b/package.json @@ -4,9 +4,12 @@ "dev": "bun run --hot src/index.ts" }, "dependencies": { - "hono": "^4.6.9" + "hono": "^4.6.9", + "id": "^0.0.0", + "zod": "^3.23.8" }, "devDependencies": { - "@types/bun": "latest" + "@types/bun": "latest", + "@types/ip": "^1.1.3" } } \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 3191383..090c9ca 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,9 +1,19 @@ import { Hono } from 'hono' +import {getConnInfo} from "hono/bun" +import connectToAddress from './utils/connect-to-address' const app = new Hono() -app.get('/', (c) => { - return c.text('Hello Hono!') +app.get('/:port', async context => { + const port = Number(context.req.param("port")) + const info = getConnInfo(context) + const ipAddress = info.remote.address! + + const result = await connectToAddress(ipAddress, port) + + return context.json({ + isOpen: result.isOpen + }) }) export default app diff --git a/src/routes/port.ts b/src/routes/port.ts new file mode 100644 index 0000000..21f5536 --- /dev/null +++ b/src/routes/port.ts @@ -0,0 +1,33 @@ +import { Hono } from "hono"; +import { getConnInfo } from "hono/bun"; +import connectToAddress from "../utils/connect-to-address"; +import { z } from "zod"; +import * as IP from "ip" + +export const portRoute = new Hono(); + +const schema = z.object({ + ip: z.string().refine(ip => !IP.isPublic(ip), "This IP address is not valid"), + port: z.coerce.number().min(1).max(2**16 - 1), +}); + +portRoute.get("/:port", async context => { + const info = getConnInfo(context) + const rawData = { + ip: info.remote.address || "", + port: context.req.param("port"), + }; + const parsedData = schema.safeParse(rawData); + + if (!parsedData.success) { + return context.json({ error: parsedData.error }, 401); + } + + const { ip, port } = parsedData.data; + + const result = await connectToAddress(ip, port) + + return context.json({ + isOpen: result.isOpen + }) +}); diff --git a/src/utils/connect-to-address.ts b/src/utils/connect-to-address.ts new file mode 100644 index 0000000..078df85 --- /dev/null +++ b/src/utils/connect-to-address.ts @@ -0,0 +1,43 @@ +export interface ConnectionResult { + isOpen: boolean +} + +const TIMEOUT = 5 + +export default function connectToAddress(address: string, port: number): Promise { + return new Promise(async (resolve) => { + const socket = await Bun.connect({ + hostname: address, + port: port, + + socket: { + open(socket) { + socket.end() + resolve({ + isOpen: true + }) + }, + data() { + }, + connectError() { + resolve({ + isOpen: false + }) + }, + error(socket) { + socket.end() + resolve({ + isOpen: false + }) + }, + timeout() { + resolve({ + isOpen: false + }) + }, + } + }) + + socket.timeout(TIMEOUT) + }) +}