commit 8615e8b78b5e02f3f80c2eb585e9849e9de2581d Author: Simon Gruber Date: Mon May 11 07:59:46 2026 +0200 init diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..5d95dd4 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,17 @@ +FROM node:20-slim + +WORKDIR /usr/src/app + +COPY package*.json ./ + +RUN npm install --production + +COPY . . + +ENV PORT=8080 +ENV HOST=0.0.0.0 +ENV ACCESS_SECRET=gif + +EXPOSE 8080 + +CMD ["node", "index.js"] \ No newline at end of file diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..11b512e --- /dev/null +++ b/Readme.md @@ -0,0 +1,37 @@ +# Giphy Proxy + +Minimalistic Node.js proxy with a protected subroute. + +## Setup + +Build: + +```sh +r build -t giphy-proxy . +``` + +Run: + +```sh +docker run -d \ + -p 8080:8080 \ + -e GIPHY_API_KEY="your_api_key" \ + -e ACCESS_SECRET="mysecret" \ + giphy-proxy +``` + +## Usage + +Example (Random): + +```sh +curl http://localhost:8080/mysecret/ +``` + +Example (Specific Tag): + +```sh +curl http://localhost:8080/mysecret/cat +``` + +All subsequent routes will be ignored! \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..c508590 --- /dev/null +++ b/index.js @@ -0,0 +1,62 @@ +const http = require("http"); +const axios = require("axios"); + +// Configuration +const host = process.env.HOST || "0.0.0.0"; +const port = process.env.PORT || 8080; +const GIPHY_API_KEY = process.env.GIPHY_API_KEY; +const PROXY_SECRET = process.env.PROXY_SECRET || "gif"; + +function catchError(res, error) { + console.error("An error occurred:", error.message); + res.writeHead(500); + res.end(JSON.stringify({ error: "Internal Server Error" })); +} + +const requestListener = function (clientReq, clientRes) { + const parts = clientReq.url?.split("/").filter(Boolean) || []; + + const providedSecret = parts[0]; + const tag = parts[1] || ""; + + if (providedSecret !== PROXY_SECRET) { + console.warn(`Unauthorized access: Invalid secret`); + clientRes.writeHead(403); + clientRes.end(JSON.stringify({ error: "Forbidden: Invalid access key" })); + return; + } + + if (!GIPHY_API_KEY) { + console.error("GIPHY_API_KEY is not configured."); + clientRes.writeHead(500); + clientRes.end(JSON.stringify({ error: "Server configuration error" })); + return; + } + + const apiUrl = `https://api.giphy.com/v1/gifs/random?api_key=${GIPHY_API_KEY}&rating=pg-13${tag ? `&tag=${tag}` : ""}`; + + axios + .get(apiUrl) + .then((apiRes) => { + const gifUrl = apiRes?.data?.data?.images?.original?.url; + + if (gifUrl) { + console.log(`Success: Found GIF for '${tag}'`); + clientRes.setHeader("Content-Type", "application/json"); + clientRes.writeHead(200); + clientRes.end(JSON.stringify({ url: gifUrl })); + } else { + console.log(`Notice: No GIF found for topic '${tag}'`); + clientRes.writeHead(404); + clientRes.end(JSON.stringify({ error: "No GIF found" })); + } + }) + .catch((error) => { + catchError(clientRes, error); + }); +}; + +const server = http.createServer(requestListener); +server.listen(port, host, () => { + console.log(`Server is running on http://${host}:${port}`); +}); \ No newline at end of file