Skip to content

Commit

Permalink
Merge pull request #110 from nicolelim02/feat/communication
Browse files Browse the repository at this point in the history
Verify user auth status
  • Loading branch information
feliciagan authored Nov 7, 2024
2 parents 8580bea + 70c3c6d commit 640e575
Show file tree
Hide file tree
Showing 33 changed files with 303 additions and 53 deletions.
3 changes: 3 additions & 0 deletions backend/collab-service/.env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ SERVICE_PORT=3003
# Origins for cors
ORIGINS=http://localhost:5173,http://127.0.0.1:5173

# Other service APIs
USER_SERVICE_URL=http://user-service:3001/api

# Redis configuration
REDIS_URI=redis://collab-service-redis:6379

Expand Down
15 changes: 15 additions & 0 deletions backend/collab-service/src/api/userService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import axios from "axios";

const USER_SERVICE_URL =
process.env.USER_SERVICE_URL || "http://localhost:3001/api";

const userClient = axios.create({
baseURL: USER_SERVICE_URL,
withCredentials: true,
});

export const verifyToken = (token: string | undefined) => {
return userClient.get("/auth/verify-token", {
headers: { authorization: token },
});
};
19 changes: 19 additions & 0 deletions backend/collab-service/src/middlewares/basicAccessControl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { ExtendedError, Socket } from "socket.io";
import { verifyToken } from "../api/userService.ts";

export const verifyUserToken = (
socket: Socket,
next: (err?: ExtendedError) => void
) => {
const token =
socket.handshake.headers.authorization || socket.handshake.auth.token;
verifyToken(token)
.then(() => {
console.log("Valid credentials");
next();
})
.catch((err) => {
console.error(err);
next(new Error("Unauthorized"));
});
};
4 changes: 4 additions & 0 deletions backend/collab-service/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import app, { allowedOrigins } from "./app.ts";
import { handleWebsocketCollabEvents } from "./handlers/websocketHandler.ts";
import { Server, Socket } from "socket.io";
import { connectRedis } from "./config/redis.ts";
import { verifyUserToken } from "./middlewares/basicAccessControl.ts";

const server = http.createServer(app);

export const io = new Server(server, {
cors: {
origin: allowedOrigins,
Expand All @@ -13,6 +15,8 @@ export const io = new Server(server, {
connectionStateRecovery: {},
});

io.use(verifyUserToken);

io.on("connection", (socket: Socket) => {
handleWebsocketCollabEvents(socket);
});
Expand Down
3 changes: 3 additions & 0 deletions backend/communication-service/.env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@ SERVER_PORT=3005

# Origins for cors
ORIGINS=http://localhost:5173,http://127.0.0.1:5173

# Other service APIs
USER_SERVICE_URL=http://user-service:3001/api
16 changes: 10 additions & 6 deletions backend/communication-service/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,25 +30,29 @@

- Select the `Socket.IO` option and set URL to `http://localhost:3005`. Click `Connect`.

![image1.png](./docs/image1.png)
![image1.png](./docs/images/postman-setup1.png)

- Add the following events in the `Events` tab and listen to them.

![image2.png](./docs/image2.png)
![image2.png](./docs/images/postman-setup2.png)

- To send a message, go to the `Message` tab and ensure that your message is being parsed as `JSON`.
- Add a valid JWT token in the `Authorization` header.

![image3.png](./docs/image3.png)
![image3.png](./docs/images/postman-setup3.png)

- In the `Event name` input, input the correct event name. Click on `Send` to send a message.

![image4.png](./docs/image4.png)
![image4.png](./docs/images/postman-setup4.png)

- To send a message, go to the `Message` tab and ensure that your message is being parsed as `JSON`.

![image5.png](./docs/images/postman-setup5.png)

## Events Available

| Event Name | Description | Parameters | Response Event |
| --------------------- | --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| **join** | Joins a communication rooms | `roomId` (string): ID of the room. <br> `username` (string): Username of the user that joined. | **user_joined**: Notify the other user that a new user has joined the room. |
| **send_text_message** | Sends a message to the other user | `roomId` (string): ID of the room. <br> `message` (string): Message to send. <br> `username` (string): User that sent the message. <br> `createdTime` (number): Time that the user sent the message. | **text_message_received**: Notify the user that a message is sent |
| **leave** | Leaves the communication room. | `roomId` (string): ID of the room to leave. <br> `username` (string): User that wants to leave. | **user_left**: To notify the user when one user leaves. |
| **user_disconnect** | User disconnection. | None | **user_left**: To notify the user when one user leaves. |
| **disconnect** | Disconnects from the server. | None | **disconnected**: To notify the user when one user gets disconnected from the server. |
Binary file removed backend/communication-service/docs/image2.png
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
79 changes: 79 additions & 0 deletions backend/communication-service/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions backend/communication-service/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"license": "ISC",
"description": "",
"dependencies": {
"axios": "^1.7.7",
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"express": "^4.21.1",
Expand Down
15 changes: 15 additions & 0 deletions backend/communication-service/src/api/userService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import axios from "axios";

const USER_SERVICE_URL =
process.env.USER_SERVICE_URL || "http://localhost:3001/api";

const userClient = axios.create({
baseURL: USER_SERVICE_URL,
withCredentials: true,
});

export const verifyToken = (token: string | undefined) => {
return userClient.get("/auth/verify-token", {
headers: { authorization: token },
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export const handleWebsocketCommunicationEvents = (socket: Socket) => {
CommunicationEvents.JOIN,
async ({ roomId, username }: { roomId: string; username: string }) => {
connectUser(username);
console.log(username, roomId);
const room = io.sockets.adapter.rooms.get(roomId);
if (room?.has(socket.id)) {
socket.emit(CommunicationEvents.ALREADY_JOINED);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { ExtendedError, Socket } from "socket.io";
import { verifyToken } from "../api/userService";

export const verifyUserToken = (
socket: Socket,
next: (err?: ExtendedError) => void
) => {
const token =
socket.handshake.headers.authorization || socket.handshake.auth.token;
verifyToken(token)
.then(() => {
console.log("Valid credentials");
next();
})
.catch((err) => {
console.error(err);
next(new Error("Unauthorized"));
});
};
5 changes: 4 additions & 1 deletion backend/communication-service/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@ import app, { allowedOrigins } from "./app";
import { createServer } from "http";
import { Server } from "socket.io";
import { handleWebsocketCommunicationEvents } from "./handlers/websocketHandler";
import { verifyUserToken } from "./middlewares/basicAccessControl";

const PORT = process.env.SERVICE_PORT || 3005;

const server = createServer(app);

export const io = new Server(server, {
cors: { origin: allowedOrigins, methods: ["GET", "POST"] },
cors: { origin: allowedOrigins, methods: ["GET", "POST"], credentials: true },
connectionStateRecovery: {},
});

io.use(verifyUserToken);

io.on("connection", handleWebsocketCommunicationEvents);

server.listen(PORT, () => {
Expand Down
1 change: 1 addition & 0 deletions backend/matching-service/.env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ ORIGINS=http://localhost:5173,http://127.0.0.1:5173
# Other service APIs
QUESTION_SERVICE_URL=http://question-service:3000/api/questions
QN_HISTORY_SERVICE_URL=http://qn-history-service:3006/api/qnhistories
USER_SERVICE_URL=http://user-service:3001/api

# RabbitMq configuration
RABBITMQ_DEFAULT_USER=admin
Expand Down
31 changes: 31 additions & 0 deletions backend/matching-service/src/api/questionHistoryService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import axios from "axios";

const QN_HISTORY_SERVICE_URL =
process.env.QN_HISTORY_SERVICE_URL ||
"http://qn-history-service:3006/api/qnhistories";

const qnHistoryService = axios.create({
baseURL: QN_HISTORY_SERVICE_URL,
headers: {
"Content-Type": "application/json",
},
});

export const createQuestionHistory = (
questionId: string,
title: string,
submissionStatus: string,
language: string,
...userIds: string[]
) => {
const dateAttempted = new Date();
return qnHistoryService.post("/", {
userIds,
questionId,
title,
submissionStatus,
language,
dateAttempted,
timeTaken: 0,
});
};
16 changes: 16 additions & 0 deletions backend/matching-service/src/api/questionService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import axios from "axios";

const QUESTION_SERVICE_URL =
process.env.QUESTION_SERVICE_URL ||
"http://question-service:3000/api/questions";

const questionClient = axios.create({
baseURL: QUESTION_SERVICE_URL,
headers: {
"Content-Type": "application/json",
},
});

export const getRandomQuestion = (complexity: string, category: string) => {
return questionClient.get("/random", { params: { complexity, category } });
};
15 changes: 15 additions & 0 deletions backend/matching-service/src/api/userService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import axios from "axios";

const USER_SERVICE_URL =
process.env.USER_SERVICE_URL || "http://localhost:3001/api";

const userClient = axios.create({
baseURL: USER_SERVICE_URL,
withCredentials: true,
});

export const verifyToken = (token: string | undefined) => {
return userClient.get("/auth/verify-token", {
headers: { authorization: token },
});
};
2 changes: 1 addition & 1 deletion backend/matching-service/src/config/rabbitmq.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import amqplib, { Connection } from "amqplib";
import dotenv from "dotenv";
import { matchUsers } from "../utils/mq_utils";
import { matchUsers } from "../utils/messageQueue";
import { MatchRequestItem } from "../handlers/matchHandler";
import { Complexities, Categories, Languages } from "../utils/constants";

Expand Down
Loading

0 comments on commit 640e575

Please sign in to comment.