Skip to content

Commit

Permalink
Proxy updated
Browse files Browse the repository at this point in the history
  • Loading branch information
darsan-in committed Nov 22, 2024
1 parent 3c28596 commit 1e0252b
Show file tree
Hide file tree
Showing 12 changed files with 1,230 additions and 38 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
node_modules
dist
proxy/credential
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ rjs make -o <relativePath/subpath>
rjs init
```
Now you can configure your settings inside `richiejs.config.js` file.

---

## License ©️
Expand Down
23 changes: 23 additions & 0 deletions proxy/build.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const esbuild = require("esbuild");

const isDev = process.argv[2] === "-dev";

const baseConfig = {
bundle: true,
minify: false,
sourcemap: isDev,
tsconfig: "tsconfig.json",
treeShaking: true,
packages: "external",
};

esbuild
.build({
entryPoints: ["index.ts"],
outfile: "dist/index.js",
target: "node20",
format: "cjs",
platform: "node",
...baseConfig,
})
.catch(() => process.exit(1));
3 changes: 2 additions & 1 deletion proxy/dist-package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"license": "Apache-2.0",
"private": true,
"dependencies": {
"@google-cloud/functions-framework": "^3.4.2"
"@google-cloud/functions-framework": "^3.4.2",
"firebase-admin": "^13.0.1"
}
}
57 changes: 38 additions & 19 deletions proxy/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import * as functions from "@google-cloud/functions-framework";
import { makeRequest } from "./lib/core";
import { decrementQuota, firewall } from "./lib/firewall";

functions.http("invoke", (req: any, res: any) => {
/* CORS */
Expand Down Expand Up @@ -26,27 +28,44 @@ functions.http("invoke", (req: any, res: any) => {
}
/* input valudate ended */

makeRequest(url)
.then((htmlContent: string) => {
res.set("Content-Type", "text/html").status(200).send(htmlContent);
/* firewall */

const orginatedFrom = new URL(req.headers.origin).hostname.replaceAll(
".",
"_",
);

firewall(orginatedFrom)
.then((currentQuota: number | boolean) => {
if (currentQuota) {
makeRequest(url)
.then((htmlContent: string) => {
if (currentQuota !== true) {
/* currentQuota is true only if it is localhost,
Otherwise, it is number of quota left */

decrementQuota(orginatedFrom, currentQuota);
}

res
.set("Content-Type", "text/html")
.status(200)
.send(htmlContent);
})
.catch((err) => {
console.error(err);
res.status(500).send("Internal Server Error");
});
} else {
//denied
res
.status(429)
.send("You quota is over, Contact rjs@cresteem.com");
}
})
.catch((err) => {
.catch((err: Error) => {
console.error(err);
res.status(500).send("Internal Server Error");
});
/* firewall ended */
});

async function makeRequest(url: string): Promise<string> {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(
`Failed to get '${url}' (status code: ${response.status})`,
);
}
return await response.text();
} catch (error) {
console.error(`Error fetching page: ${error}`);
throw error;
}
}
14 changes: 14 additions & 0 deletions proxy/lib/core.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export async function makeRequest(url: string): Promise<string> {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(
`Failed to get '${url}' (status code: ${response.status})`,
);
}
return await response.text();
} catch (error) {
console.error(`Error fetching page: ${error}`);
throw error;
}
}
94 changes: 94 additions & 0 deletions proxy/lib/firewall.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import admin from "firebase-admin";
import quota from "./quota";
const serviceAccount = require("../credential/bonse-001-8a382ce36723.json");

admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL:
"https://bonse-001-default-rtdb.asia-southeast1.firebasedatabase.app",
});

const database = admin.database();

function _createQuota(orginatedFrom: string): Promise<number> {
return new Promise((resolve, reject) => {
const ref = database.ref(
`/rjs-proxy/limits/${orginatedFrom}/per-month`,
);

ref
.set(quota.perMonth)
.then(() => {
resolve(quota.perMonth);
})
.catch(reject);
});
}

function _checkQuota(orginatedFrom: string): Promise<number> {
return new Promise((resolve, reject) => {
const ref = database.ref(
`/rjs-proxy/limits/${orginatedFrom}/per-month`,
);

ref
.get()
.then((snapshot) => {
if (snapshot.exists()) {
//existing user
const currentQuota: number = snapshot.val() as number;
resolve(currentQuota);
} else {
//new user
_createQuota(orginatedFrom)
.then((quota: number) => {
resolve(quota);
})
.catch((err) => {
reject(err); //temp block user forcefully
});
}
})
.catch((err) => {
reject(err); //temp block user forcefully
});
});
}

export function decrementQuota(
orginatedFrom: string,
lastLimitCount: number,
): Promise<void> {
return new Promise((resolve, reject) => {
const ref = database.ref(
`/rjs-proxy/limits/${orginatedFrom}/per-month`,
);

ref
.set(lastLimitCount - 1)
.then(resolve)
.catch(reject);
});
}

export function firewall(
orginatedFrom: string,
): Promise<number | boolean> {
return new Promise((resolve, reject) => {
if (orginatedFrom === "localhost") {
resolve(true); // No limit for localhost
}

_checkQuota(orginatedFrom)
.then((currentLimitCount: number) => {
if (currentLimitCount > 0) {
//grant
resolve(currentLimitCount);
} else {
//deny
resolve(false);
}
})
.catch(reject);
});
}
6 changes: 6 additions & 0 deletions proxy/lib/quota.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const quota = {
perDay: 20,
perWeek: 80,
perMonth: 100,
};
export default quota;
17 changes: 10 additions & 7 deletions proxy/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,23 @@
"license": "Apache-2.0",
"private": true,
"scripts": {
"dev": "cls && rimraf dist && tsc -p tsconfig.json",
"dr": "yarn dev && yarn rp",
"rp": "pushd dist && npx @google-cloud/functions-framework --target=invoke && popd",
"build": "cls && rimraf dist && tsc -p tsconfig.json && ncp ./dist-package.json ./dist/package.json",
"clean": "cls && rimraf dist",
"rp": "pushd dist && npx @google-cloud/functions-framework --target=invoke && popd",
"dev": "yarn clean && node build -dev",
"build": "yarn clean && node build && ncp ./dist-package.json ./dist/package.json",
"dr": "yarn dev && yarn rp",
"br": "yarn build && yarn rp",
"deploy": "yarn build && deploy"
},
"dependencies": {
"@google-cloud/functions-framework": "^3.4.2"
"@google-cloud/functions-framework": "^3.4.2",
"esbuild": "^0.24.0",
"firebase-admin": "^13.0.1"
},
"devDependencies": {
"rimraf": "latest",
"ncp": "latest",
"@types/node": "^20.14.8",
"ncp": "latest",
"rimraf": "latest",
"ts-node": "10.9.2",
"typescript": "5.4.5"
}
Expand Down
Loading

0 comments on commit 1e0252b

Please sign in to comment.