Skip to content

Commit

Permalink
feat: add encryption (#537)
Browse files Browse the repository at this point in the history
  • Loading branch information
Dun-sin authored Oct 23, 2023
1 parent 1054a4b commit dd0dc79
Show file tree
Hide file tree
Showing 12 changed files with 89 additions and 54 deletions.
6 changes: 6 additions & 0 deletions client/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 client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"@rsuite/icons": "^1.0.3",
"axios": "^1.4.0",
"bad-words-next": "^2.2.1",
"crypto-js": "^4.1.1",
"emoji-picker-react": "^4.5.2",
"lodash": "^4.17.21",
"markdown-it": "^13.0.1",
Expand Down
51 changes: 24 additions & 27 deletions client/src/components/Chat.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import MessageSeen from './Chat/MessageSeen';
import MessageInput from './Chat/MessageInput';
import DropDownOptions from './Chat/DropDownOption';
import PreviousMessages from './Chat/PreviousMessages';
import decryptMessage from 'src/lib/decryptMessage';


const inactiveTimeThreshold = 180000; // 3 mins delay
Expand All @@ -59,7 +60,7 @@ const Chat = () => {
const [openPreviousMessages, setOpenPreviousMessages] = useState(null);
const [badwordChoices, setBadwordChoices] = useState({});

const { messages: state, addMessage, updateMessage, removeMessage, editText, receiveMessage } = useChat();
const { messages: state, addMessage, updateMessage, removeMessage, receiveMessage } = useChat();
const { authState, dispatchAuth } = useAuth();
const { logout } = useKindeAuth();
const socket = useContext(SocketContext);
Expand Down Expand Up @@ -104,43 +105,38 @@ const Chat = () => {
[state, app.currentChatId]
);

const doSend = async ({ senderId, room, tmpId = uuid(), message, time, containsBadword }) => {
const doSend = async ({ senderId, room, message, time, containsBadword }) => {
try {
addMessage({
const sentMessage = await sendMessage({
senderId,
room,
id: tmpId,
message,
time,
status: 'pending',
chatId: room,
containsBadword
});
} catch {
logOut();
return false;
}

try {
const sentMessage = await sendMessage({
addMessage({
senderId,
room,
id: sentMessage.id,
message,
time,
chatId: room,
status: 'pending',
containsBadword
});

try {
updateMessage(tmpId, sentMessage);
updateMessage(sentMessage);
} catch {
logOut();
return false;
}
} catch (e) {
try {
updateMessage(tmpId, {
updateMessage({
senderId,
room,
id: tmpId,
id: uuid(),
message,
time,
status: 'failed',
Expand Down Expand Up @@ -183,18 +179,17 @@ const Chat = () => {

if (editing.isediting === true) {
try {
const oldMessage = getMessage(editing.messageID, state, app).message;
await editMessage({
const messageObject = getMessage(editing.messageID, state, app)
const oldMessage = messageObject.message;
const editedMessage = await editMessage({
id: editing.messageID,
chatId: app.currentChatId,
newMessage: message,
oldMessage,
});
editText(editing.messageID, app.currentChatId, message, oldMessage);
const messageObject = getMessage(editing.messageID, state, app);

updateMessage(editing.messageID, messageObject, true);
} catch {
updateMessage({ ...editedMessage, room: app.currentChatId }, true);
} catch (e) {
setEditing({ isediting: false, messageID: null });
return;
}
Expand Down Expand Up @@ -274,8 +269,8 @@ const Chat = () => {
removeMessage(id, chatId);
};

const editMessageHandler = ({ id, chatId, newMessage, oldMessage }) => {
editText(id, chatId, newMessage, oldMessage);
const editMessageHandler = (messageEdited) => {
updateMessage({ ...messageEdited, room: app.currentChatId }, true);
};

const limitMessageHandler = (data) => {
Expand Down Expand Up @@ -329,12 +324,14 @@ const Chat = () => {
>
{sortedMessages.map(
({ senderId: sender, id, message, time, status, isEdited, oldMessages, containsBadword, isRead }) => {
const isSender = sender.toString() === senderId.toString()
const isSender = sender.toString() === senderId.toString();
message = decryptMessage(message)

return (
<div
key={id}
id={!isSender && `message-${id}`}
className={`w-full flex text-white relative ${
className={`w-full flex text-white relative mb-2 ${
isSender ? 'justify-end' : 'justify-start'
}`}
>
Expand Down Expand Up @@ -404,8 +401,8 @@ const Chat = () => {
openPreviousMessages={openPreviousMessages}
oldMessages={oldMessages}
/>
<MessageSeen isRead={isRead} isSender={isSender} />
</div>
<MessageSeen isRead={isRead} isSender={isSender} />
</>}
</div>
</div>
Expand Down
19 changes: 15 additions & 4 deletions client/src/components/Chat/PreviousMessages.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ import PropTypes from 'prop-types'
import { AiFillCaretDown } from 'react-icons/ai';
import { BiSolidEditAlt } from 'react-icons/bi';

import BadWordsNext from 'bad-words-next';
import en from 'bad-words-next/data/en.json'

import decryptMessage from 'src/lib/decryptMessage';


const PreviousMessages = ({
id,
Expand All @@ -13,6 +18,8 @@ const PreviousMessages = ({
openPreviousEdit,
openPreviousMessages,
oldMessages }) => {

const badwords = new BadWordsNext({ data: en });
return (
<div>
{isEdited && (
Expand All @@ -36,11 +43,15 @@ const PreviousMessages = ({
<div className="flex flex-col">
{oldMessages !== undefined &&
Array.isArray(oldMessages) &&
oldMessages.map((message, index) => (
oldMessages.map((message, index) => {
message = badwords
.filter(decryptMessage(message))
return (
<span key={index} className="text-base">
{message}
</span>
))}
)
})}
</div>
</div>
)}
Expand All @@ -53,8 +64,8 @@ export default PreviousMessages
PreviousMessages.propTypes = {
id: PropTypes.string.isRequired,
isSender: PropTypes.bool.isRequired,
isEdited: PropTypes.bool.isRequired,
isEdited: PropTypes.bool,
openPreviousEdit: PropTypes.func.isRequired,
openPreviousMessages: PropTypes.string.isRequired,
openPreviousMessages: PropTypes.string,
oldMessages: PropTypes.array
}
12 changes: 2 additions & 10 deletions client/src/context/ChatContext.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,10 @@ export const ChatProvider = ({ children }) => {
* @param {string} id
* @param {Message} message
*/
function updateMessage(id, message, isEdited) {
function updateMessage(message, isEdited) {
dispatch({
type: 'UPDATE_MESSAGE',
payload: { id, message, isEdited },
payload: { message, isEdited },
});
}

Expand All @@ -90,13 +90,6 @@ export const ChatProvider = ({ children }) => {
});
}

function editText(id, chatId, newText, oldMessage) {
dispatch({
type: 'EDIT_TEXT',
payload: { id, room: chatId, newText, oldMessage },
});
}

function receiveMessage(id, chatId) {
dispatch({
type: 'RECEIVE_MESSAGE',
Expand Down Expand Up @@ -126,7 +119,6 @@ export const ChatProvider = ({ children }) => {
updateMessage,
createChat,
removeMessage,
editText,
closeChat,
closeAllChats,
receiveMessage
Expand Down
10 changes: 9 additions & 1 deletion client/src/context/reducers/chatReducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,9 @@ export default function chatReducer(state, action) {
}

case 'UPDATE_MESSAGE': {
const { id, message, isEdited } = action.payload;
const { message, isEdited } = action.payload;

const id = message.id;
if (!clonedState[message.room]) {
throw new Error('Room not found!');
}
Expand All @@ -85,6 +86,7 @@ export default function chatReducer(state, action) {
const room = message.room;
const messageId = message.id;
const updatedMessage = message;
const oldMessages = message.oldMessages;

// Assign the message to the cloned state
clonedState[room].messages[messageId] = updatedMessage;
Expand All @@ -94,6 +96,12 @@ export default function chatReducer(state, action) {
break;
}
clonedState[room].messages[messageId].isEdited = isEdited;

if (oldMessages.length === 0) {
break;
}

clonedState[room].messages[messageId].oldMessages = oldMessages
break;
}

Expand Down
5 changes: 3 additions & 2 deletions client/src/lib/browserNotification.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import BadWordsNext from 'bad-words-next';
import en from 'bad-words-next/data/en.json'
import decryptMessage from './decryptMessage';

export const requestBrowserNotificationPermissions = () => {
if (!('Notification' in window)) {
Expand All @@ -10,7 +11,7 @@ export const requestBrowserNotificationPermissions = () => {
};

export const createBrowserNotification = (title, body) => {
const badwords = new BadWordsNext({ data: en })
const badwords = new BadWordsNext({ data: en });

if (Notification.permission === 'denied') {
return;
Expand All @@ -20,7 +21,7 @@ export const createBrowserNotification = (title, body) => {
return;
}

const message = badwords.filter(body);
const message = badwords.filter(decryptMessage(body));

new Notification(title, {
body: message,
Expand Down
10 changes: 10 additions & 0 deletions client/src/lib/decryptMessage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import CryptoJS from 'crypto-js';

const secretKey = import.meta.env.VITE_SECRET_KEY;

export default (message) => {
const bytes = CryptoJS.AES.decrypt(message, secretKey);
const originalMessage = bytes.toString(CryptoJS.enc.Utf8);

return originalMessage;
};
6 changes: 6 additions & 0 deletions server/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 server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"license": "ISC",
"dependencies": {
"cors": "^2.8.5",
"crypto-js": "^4.1.1",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"express-rate-limit": "^7.1.1",
Expand Down
11 changes: 3 additions & 8 deletions server/sockets/editMessage.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,13 @@ module.exports = (socket) => {
return;
}

const messageEditted = await editMessage(chatId, {
const messageEdited = await editMessage(chatId, {
id: messageId,
message: newMessage,
oldMessage,
});
socket.broadcast.to(chatId).emit(NEW_EVENT_EDIT_MESSAGE, {
id: messageId,
chatId,
newMessage,
oldMessage,
});
messageWasEditedSuccessfully(messageEditted);
socket.broadcast.to(chatId).emit(NEW_EVENT_EDIT_MESSAGE, messageEdited);
messageWasEditedSuccessfully(messageEdited);
}
);
};
Loading

1 comment on commit dd0dc79

@vercel
Copy link

@vercel vercel bot commented on dd0dc79 Oct 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.