From ac10b685af66be9ec7283b96b9d6b20a2367c353 Mon Sep 17 00:00:00 2001 From: koh Date: Mon, 22 Jan 2024 20:48:26 +0700 Subject: [PATCH] Feat: Elysia demo --- .env | 3 ++ bun.lockb | Bin 0 -> 37419 bytes package.json | 15 +++++++-- src/config/mongo.js | 7 ++++ src/index.js | 72 ++++++++++++++++++++++++++++++++++++++++++ src/index.ts | 7 ---- src/middleware/jwt.js | 40 +++++++++++++++++++++++ src/models/User.js | 21 ++++++++++++ src/modules/auth.js | 62 ++++++++++++++++++++++++++++++++++++ src/modules/user.js | 11 +++++++ src/ws/device.js | 7 ++++ 11 files changed, 235 insertions(+), 10 deletions(-) create mode 100644 .env create mode 100755 bun.lockb create mode 100644 src/config/mongo.js create mode 100644 src/index.js delete mode 100644 src/index.ts create mode 100644 src/middleware/jwt.js create mode 100644 src/models/User.js create mode 100644 src/modules/auth.js create mode 100644 src/modules/user.js create mode 100644 src/ws/device.js diff --git a/.env b/.env new file mode 100644 index 0000000..7e2d1c0 --- /dev/null +++ b/.env @@ -0,0 +1,3 @@ +PORT_SERVER=3000 +JWT_SECRET=FnESrpC4GrFFLcBcz4eFN8 +MONGODB_URI=mongodb://127.0.0.1:29000/?directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+2.1.1 \ No newline at end of file diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..7014f5af12d10edc26d646a5a4195015aad6617d GIT binary patch literal 37419 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 CV4Ldz literal 0 HcmV?d00001 diff --git a/package.json b/package.json index c427aa5..09230de 100644 --- a/package.json +++ b/package.json @@ -2,11 +2,20 @@ "name": "app", "version": "1.0.50", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "dev": "bun run --watch src/index.ts" + "dev": "bun --watch src/index.js", + "build": "bun build src/index.js", + "start": "NODE_ENV=production bun src/index.js", + "test": "bun test" }, "dependencies": { - "elysia": "latest" + "@elysiajs/cors": "^0.8.0", + "@elysiajs/jwt": "^0.8.0", + "@elysiajs/swagger": "^0.8.3", + "@grotto/logysia": "^0.1.1", + "bcrypt": "^5.1.1", + "elysia": "latest", + "elysia-helmet": "^1.0.2", + "mongoose": "^8.1.0" }, "devDependencies": { "bun-types": "latest" diff --git a/src/config/mongo.js b/src/config/mongo.js new file mode 100644 index 0000000..e2d6a0a --- /dev/null +++ b/src/config/mongo.js @@ -0,0 +1,7 @@ +import mongoose from 'mongoose'; + +// Connect to the MongoDB database +const mongoDBURI = process.env.MONGODB_URI ?? 'mongodb://localhost:27017'; + +mongoose.connect(mongoDBURI); +export default mongoose; \ No newline at end of file diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..e3815c6 --- /dev/null +++ b/src/index.js @@ -0,0 +1,72 @@ +import { Elysia, t } from "elysia"; +import { swagger } from '@elysiajs/swagger'; +import { cors } from '@elysiajs/cors'; +import { helmet } from 'elysia-helmet'; +import { jwt } from '@elysiajs/jwt'; +import { logger } from '@grotto/logysia'; +import './config/mongo'; + +import { isAuthenticatedHttp, isAuthenticatedWS } from './middleware/jwt'; +// Routers +import authRouter from './modules/auth'; +import userRouter from './modules/user'; + +// Ws +import { getDevices } from './ws/device'; + +const app = new Elysia() + .use(swagger({ + documentation: { + info: { + title: "RAT Cypher Company", + version: '1.0.0', + contact: { + name: '@kohdev', + url: 'https://t.me/kohdev' + }, + description: "RAT remote android and ios", + license: { + name: "MIT" + } + } + }, + version: '1.0.0' + })) + .use(cors(/* your options */)) + .use(helmet({ /* your options */ })) + .use(logger()) + .use( + jwt({ + name: 'jwt', + secret: process.env.JWT_SECRET, + }) + ) + .get('/', () => { + return `Elysia is running at ${app.server?.hostname}:${app.server?.port}`; + }) + // ws dùng hệ thống auth riêng nên không phải đặt trước onBeforeHandle auth của http + .ws('/ws', { + body: t.Object({ + type: t.String(), + d: t.String(), + }), + message(ws, message) { + switch(message.type) { + case 'get-device': + getDevices(ws, message.d); + } + }, + maxPayloadLength: 1024 * 1024, // 1 MB + beforeHandle: ({ headers, jwt, set, store }) => isAuthenticatedWS({ headers, jwt, set, store }), + }) + // không auth + .use(authRouter) + // auth middleware + .onBeforeHandle(isAuthenticatedHttp) + // từ router này về sau sẽ được auth + .use(userRouter) + .listen(process.env.PORT_SERVER); + +console.log( + `🦊 Elysia is running at ${app.server?.hostname}:${app.server?.port}` +); diff --git a/src/index.ts b/src/index.ts deleted file mode 100644 index 9c1f7a1..0000000 --- a/src/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Elysia } from "elysia"; - -const app = new Elysia().get("/", () => "Hello Elysia").listen(3000); - -console.log( - `🦊 Elysia is running at ${app.server?.hostname}:${app.server?.port}` -); diff --git a/src/middleware/jwt.js b/src/middleware/jwt.js new file mode 100644 index 0000000..e69ef41 --- /dev/null +++ b/src/middleware/jwt.js @@ -0,0 +1,40 @@ +import UserModel from '../models/User'; + +async function isAuthenticatedHttp({ headers, jwt, set }) { + const token = (headers.authorization || "").split(" "); + + if (!token[1]) { + set.status = 401; + return { + ok: 0, + e: "Unauthorized", + } + } + const { userId } = await jwt.verify(token[1]); + if (!userId) { + set.status = 401; + return { + ok: 0, + e: "Unauthorized", + } + } + const userByID = await UserModel.findById(userId).lean(); + set.user = userByID; + return { + user: userByID, + }; +} +async function isAuthenticatedWS({ headers, jwt, set, store }) { + const token = (headers.authorization || "").split(" "); + + if (token[1]) { + const { userId } = await jwt.verify(token[1]); + const userByID = await UserModel.findById(userId).lean(); + store.user = userByID; + return; + } + set.status = 401; + throw new Error("Unauthorized WS") +} + +export { isAuthenticatedHttp, isAuthenticatedWS } \ No newline at end of file diff --git a/src/models/User.js b/src/models/User.js new file mode 100644 index 0000000..a6a1940 --- /dev/null +++ b/src/models/User.js @@ -0,0 +1,21 @@ +import { Schema, model } from 'mongoose'; + +const schema = new Schema( + { + username: { + type: String, + required: true, + unique: true, + }, + password: { + type: String, + required: true, + select: false, // will not appear in the response + }, + }, + { + timestamps: true, + } +); + +export default model('user', schema); \ No newline at end of file diff --git a/src/modules/auth.js b/src/modules/auth.js new file mode 100644 index 0000000..6c8f2cb --- /dev/null +++ b/src/modules/auth.js @@ -0,0 +1,62 @@ +import { Elysia, t } from 'elysia'; +import bcrypt from 'bcrypt'; +import UserModel from '../models/User'; + +const SALTROUNDS = 10; + +const auth = new Elysia({ prefix: '/api/auth' }) + .guard( + { + body: t.Object({ + username: t.String(), + password: t.String(), + }) + }, + (app) => app + .post('/createAccount', async ({ body, jwt, set }) => { + const { username, password } = body; + const passwordHash = bcrypt.hashSync(password, SALTROUNDS); + const userCreated = await new UserModel({ username, password: passwordHash }).save(); + if (userCreated) { + const accessToken = await jwt.sign({ + userId: userCreated._id + }); + set.headers = { + 'X-Authorization': accessToken, + }; + set.status = 201; + return { ok: 1 }; + } + }, { + beforeHandle: async ({ body, set }) => { + const { username } = body; + const isAccountCreated = await UserModel.exists({ username }); + if (isAccountCreated) { + set.status = 400; + return { + ok: 0, + e: "Tên tài khoản đã tồn tại" + } + } + } + }) + .post("/login", async ({ body, set, jwt }) => { + const { username, password } = body; + const passwordByUsername = await UserModel.findOne({ username }).select('password').lean(); + const isValidPassword = bcrypt.compareSync(password, passwordByUsername?.password); + if (!isValidPassword) { + return { + ok: 0, + e: "Tên tài khoản hoặc mật khẩu không chính xác" + } + } + const accessToken = await jwt.sign({ + userId: passwordByUsername._id + }); + set.headers = { + 'X-Authorization': accessToken, + }; + return { ok: 1 }; + }) + ); +export default auth; \ No newline at end of file diff --git a/src/modules/user.js b/src/modules/user.js new file mode 100644 index 0000000..30c9e3f --- /dev/null +++ b/src/modules/user.js @@ -0,0 +1,11 @@ +import { Elysia, t } from 'elysia'; + +const user = new Elysia({ prefix: '/api/user' }) + .get("/me", ({ user }) => { + return { + ok: 1, + d: user, + } + }); + +export default user; \ No newline at end of file diff --git a/src/ws/device.js b/src/ws/device.js new file mode 100644 index 0000000..3ef0049 --- /dev/null +++ b/src/ws/device.js @@ -0,0 +1,7 @@ +async function getDevices(ws, d) { + const { data: { store } } = ws; + console.log(store); + ws.send({ d }); +} + +export { getDevices }; \ No newline at end of file