first-commit
This commit is contained in:
commit
054cb94c47
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
node_modules
|
||||||
|
.idea
|
||||||
|
.env
|
||||||
|
build
|
||||||
18
Dockerfile
Normal file
18
Dockerfile
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Declare build-time argument
|
||||||
|
ARG DOCKER_IMAGE_SOURCE
|
||||||
|
|
||||||
|
FROM ${DOCKER_IMAGE_SOURCE}
|
||||||
|
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
|
COPY package*.json ./
|
||||||
|
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
EXPOSE ${PORT}
|
||||||
|
|
||||||
|
# CMD npm run build;npm run start
|
||||||
|
# CMD [ "npm", "run", "start-ts" ]
|
||||||
|
CMD ./start.sh
|
||||||
22
docker-compose.yml
Normal file
22
docker-compose.yml
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
services:
|
||||||
|
svg:
|
||||||
|
build:
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
context: .
|
||||||
|
args:
|
||||||
|
DOCKER_IMAGE_SOURCE: ${DOCKER_IMAGE_SOURCE}
|
||||||
|
ports:
|
||||||
|
- ${PORT}:8000
|
||||||
|
container_name: ${CONTAINER_NAME}
|
||||||
|
tmpfs:
|
||||||
|
- /tmp:size=${TMPFS_SIZE}
|
||||||
|
- /var/log:size=50m
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpus: ${CPU_LIMIT}
|
||||||
|
memory: ${MEMORY_LIMIT}
|
||||||
|
volumes:
|
||||||
|
- .:/wrkdir
|
||||||
|
restart: unless-stopped
|
||||||
|
env_file: .env
|
||||||
34
eslint.config.cjs
Normal file
34
eslint.config.cjs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// eslint.config.cjs
|
||||||
|
const js = require("@eslint/js");
|
||||||
|
const ts = require("@typescript-eslint/eslint-plugin");
|
||||||
|
const tsParser = require("@typescript-eslint/parser");
|
||||||
|
const prettier = require("eslint-plugin-prettier");
|
||||||
|
const globals = require("globals");
|
||||||
|
|
||||||
|
module.exports = [
|
||||||
|
js.configs.recommended,
|
||||||
|
{
|
||||||
|
files: ["**/*.ts", "**/*.tsx"],
|
||||||
|
languageOptions: {
|
||||||
|
parser: tsParser,
|
||||||
|
ecmaVersion: "latest",
|
||||||
|
sourceType: "module",
|
||||||
|
globals: {
|
||||||
|
...globals.node,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
"@typescript-eslint": ts,
|
||||||
|
prettier,
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
"no-unused-vars": "off",
|
||||||
|
"@typescript-eslint/no-unused-vars": "error",
|
||||||
|
indent: "off",
|
||||||
|
"linebreak-style": "off",
|
||||||
|
quotes: "off",
|
||||||
|
semi: ["error", "always"],
|
||||||
|
"prettier/prettier": "error",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
2259
package-lock.json
generated
Normal file
2259
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
31
package.json
Normal file
31
package.json
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"name": "svg_schemes",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "ts-node src/index.ts",
|
||||||
|
"build": "tsc",
|
||||||
|
"start": "node build/index.js",
|
||||||
|
"lint": "npx eslint \"{src,apps,libs,test}/**/*.ts\" --fix"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^22.13.10",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
||||||
|
"@typescript-eslint/parser": "^8.26.1",
|
||||||
|
"eslint": "^9.22.0",
|
||||||
|
"ts-node": "^10.9.2",
|
||||||
|
"typescript": "^5.8.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@eslint/js": "^9.22.0",
|
||||||
|
"@fastify/cors": "^11.0.0",
|
||||||
|
"dotenv": "^16.4.7",
|
||||||
|
"eslint-plugin-prettier": "^5.2.3",
|
||||||
|
"fastify": "^5.2.1",
|
||||||
|
"globals": "^16.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
30
src/auth/global-access-guard.ts
Normal file
30
src/auth/global-access-guard.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import Config from "../config";
|
||||||
|
|
||||||
|
function isIpPrivate(ip: string): boolean {
|
||||||
|
if ("192.168" === ip.slice(0, 7)) {
|
||||||
|
return true;
|
||||||
|
} else if (
|
||||||
|
ip.slice(0, 3) === "172" &&
|
||||||
|
ip.slice(4, 6) >= "16" &&
|
||||||
|
ip.slice(4, 6) <= "31"
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
} else if ("10" === ip.slice(0, 2)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const GlobalAccessGuard = async (req, reply): Promise<void> => {
|
||||||
|
const ip = req.ip;
|
||||||
|
const token: string = (req.query as any).token;
|
||||||
|
|
||||||
|
if (Config.nodeEnv === "LOCAL") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!isIpPrivate(ip) || token !== Config.token) {
|
||||||
|
reply.code(401);
|
||||||
|
throw new Error("Access denied");
|
||||||
|
}
|
||||||
|
};
|
||||||
40
src/config/index.ts
Normal file
40
src/config/index.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import * as dotenv from "dotenv";
|
||||||
|
import * as process from "node:process";
|
||||||
|
|
||||||
|
dotenv.config();
|
||||||
|
|
||||||
|
class Config {
|
||||||
|
public readonly nodeEnv: "DEV" | "PROD" | "LOCAL";
|
||||||
|
public readonly port: number;
|
||||||
|
public readonly token: string;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.nodeEnv = process.env.NODE_ENV as "DEV" | "PROD" | "LOCAL";
|
||||||
|
this.port = +process.env.PORT;
|
||||||
|
this.token = process.env.TOKEN;
|
||||||
|
|
||||||
|
if (
|
||||||
|
this.nodeEnv !== "DEV" &&
|
||||||
|
this.nodeEnv !== "PROD" &&
|
||||||
|
this.nodeEnv !== "LOCAL"
|
||||||
|
) {
|
||||||
|
throw new Error("Config: nodeEnv is not defined or not valid");
|
||||||
|
}
|
||||||
|
|
||||||
|
const numberValues = ["port"];
|
||||||
|
for (const numberValue of numberValues) {
|
||||||
|
if (!this[numberValue] || typeof this[numberValue] !== "number") {
|
||||||
|
throw new Error(`Config: ${numberValue} is not defined`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const stringValues = ["token"];
|
||||||
|
for (const stringValue of stringValues) {
|
||||||
|
if (!this[stringValue] || typeof this[stringValue] !== "string") {
|
||||||
|
throw new Error(`Config: ${stringValue} is not defined`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new Config();
|
||||||
57
src/index.ts
Normal file
57
src/index.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import fastify from "fastify";
|
||||||
|
import * as cors from "@fastify/cors";
|
||||||
|
import Config from "./config";
|
||||||
|
import { GlobalAccessGuard } from "./auth/global-access-guard";
|
||||||
|
|
||||||
|
let app: fastify.FastifyInstance;
|
||||||
|
|
||||||
|
const createApp = () => {
|
||||||
|
console.log("createApp");
|
||||||
|
app = fastify({
|
||||||
|
logger: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
//accept only private ips + token OR LOCAL
|
||||||
|
app.addHook("preValidation", GlobalAccessGuard);
|
||||||
|
|
||||||
|
app.setErrorHandler((error, request, reply) => {
|
||||||
|
console.error(error.message);
|
||||||
|
// Send error response
|
||||||
|
reply.status(500).send({
|
||||||
|
status: "error",
|
||||||
|
data: {
|
||||||
|
message: error.message,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
app.register(cors);
|
||||||
|
|
||||||
|
app.get("/health-check", () => ({ statusCode: 200, status: "ok" }));
|
||||||
|
// app.register(authController, { prefix: '/auth' });
|
||||||
|
// if (Config.nodeEnv === 'LOCAL' || Config.nodeEnv === 'DEV') {
|
||||||
|
// app.register(DevController, { prefix: '/dev' });
|
||||||
|
// console.log('register dev controller');
|
||||||
|
// }
|
||||||
|
console.log("appCreated");
|
||||||
|
};
|
||||||
|
|
||||||
|
const start = async (): Promise<void> => {
|
||||||
|
try {
|
||||||
|
createApp();
|
||||||
|
|
||||||
|
await app.listen({
|
||||||
|
port: 8000,
|
||||||
|
host: "0.0.0.0",
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("Server started on port: 8000");
|
||||||
|
console.log(
|
||||||
|
`You can access it from outside the docker on port ${Config.port}`,
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
start();
|
||||||
10
start.sh
Normal file
10
start.sh
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
if [ "$NODE" = "LOCAL" ] ; then
|
||||||
|
npm run lint
|
||||||
|
npm run dev
|
||||||
|
else
|
||||||
|
npm run lint
|
||||||
|
npm run build
|
||||||
|
npm run start
|
||||||
|
fi
|
||||||
8
tmpls/.env-template
Normal file
8
tmpls/.env-template
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
PORT=8000
|
||||||
|
CONTAINER_NAME='svgdev'
|
||||||
|
TMPFS_SIZE='8192m'
|
||||||
|
CPU_LIMIT='10'
|
||||||
|
MEMORY_LIMIT='8g'
|
||||||
|
DOCKER_IMAGE_SOURCE='node:20.12.1-alpine'
|
||||||
|
NODE_ENV='LOCAL'
|
||||||
|
TOKEN='secret_token'
|
||||||
10
tsconfig.json
Normal file
10
tsconfig.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es2022",
|
||||||
|
"module": "commonjs",
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"strict": true,
|
||||||
|
"rootDir": "src",
|
||||||
|
"outDir": "build",
|
||||||
|
},
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user