diff --git a/client/src/actions/app.js b/client/src/actions/app.js
index 3aac089..8a5ca15 100644
--- a/client/src/actions/app.js
+++ b/client/src/actions/app.js
@@ -31,10 +31,6 @@ export const toggleSocketConnected = payload => async dispatch => {
dispatch({ type: 'TOGGLE_SOCKET_CONNECTED', payload });
};
-export const createUser = payload => async dispatch => {
- dispatch({ type: 'CREATE_USER', payload });
-};
-
export const clearActivities = () => async dispatch => {
dispatch({ type: 'CLEAR_ACTIVITIES' });
};
diff --git a/client/src/actions/app.test.js b/client/src/actions/app.test.js
index 9ba2a35..30c9ad2 100644
--- a/client/src/actions/app.test.js
+++ b/client/src/actions/app.test.js
@@ -40,7 +40,6 @@ describe('App actions', () => {
[actions.showNotice('test'), 'SHOW_NOTICE'],
[actions.toggleSoundEnabled('test'), 'TOGGLE_SOUND_ENABLED'],
[actions.toggleSocketConnected('test'), 'TOGGLE_SOCKET_CONNECTED'],
- [actions.createUser('test'), 'CREATE_USER'],
[actions.setLanguage('test'), 'CHANGE_LANGUAGE'],
];
diff --git a/client/src/actions/encrypted_messages.js b/client/src/actions/encrypted_messages.js
index 9500042..50f50ae 100644
--- a/client/src/actions/encrypted_messages.js
+++ b/client/src/actions/encrypted_messages.js
@@ -1,10 +1,18 @@
import { getSocket } from '@/utils/socket';
import { prepare as prepareMessage, process as processMessage } from '@/utils/message';
+import { changeUsername } from '@/reducers/user';
export const sendEncryptedMessage = payload => async (dispatch, getState) => {
const state = getState();
const msg = await prepareMessage(payload, state);
- dispatch({ type: `SEND_ENCRYPTED_MESSAGE_${msg.original.type}`, payload: msg.original.payload });
+ switch(msg.original.type){
+ case "CHANGE_USERNAME":
+ dispatch(changeUsername(msg.original.payload));
+ dispatch({ type: `SEND_ENCRYPTED_MESSAGE_${msg.original.type}`, payload: msg.original.payload });
+ break;
+ default:
+ dispatch({ type: `SEND_ENCRYPTED_MESSAGE_${msg.original.type}`, payload: msg.original.payload });
+ }
getSocket().emit('ENCRYPTED_MESSAGE', msg.toSend);
};
diff --git a/client/src/components/Home/Home.jsx b/client/src/components/Home/Home.jsx
index b3f7970..6a24f2c 100644
--- a/client/src/components/Home/Home.jsx
+++ b/client/src/components/Home/Home.jsx
@@ -4,6 +4,8 @@ import PropTypes from 'prop-types';
import { nanoid } from 'nanoid';
import { X, AlertCircle } from 'react-feather';
import classNames from 'classnames';
+import { useSelector, useDispatch } from 'react-redux';
+import { createUser } from '@/reducers/user';
import Crypto from '@/utils/crypto';
import { connect as connectSocket } from '@/utils/socket';
@@ -290,15 +292,18 @@ const Home = ({
);
};
-export const WithUser = ({ createUser, username, ...rest }) => {
+export const WithUser = ({ ...rest }) => {
const [loaded, setLoaded] = React.useState(false);
const loading = React.useRef(false);
+ const user = useSelector(state => state.user);
+ const dispatch = useDispatch();
+
React.useEffect(() => {
let mounted = true;
const createUserLocal = async () => {
- const localUsername = username || nanoid();
+ const localUsername = user.username || nanoid();
const encryptDecryptKeys = await crypto.createEncryptDecryptKeys();
const exportedEncryptDecryptPrivateKey = await crypto.exportKey(encryptDecryptKeys.privateKey);
@@ -309,11 +314,14 @@ export const WithUser = ({ createUser, username, ...rest }) => {
return;
}
- createUser({
+ const payload = {
username: localUsername,
publicKey: exportedEncryptDecryptPublicKey,
privateKey: exportedEncryptDecryptPrivateKey,
- });
+ };
+ dispatch(createUser(payload));
+
+ dispatch({ type: 'CREATE_USER', payload });
loading.current = false;
setLoaded(true);
@@ -328,12 +336,13 @@ export const WithUser = ({ createUser, username, ...rest }) => {
loading.current = false;
mounted = false;
};
- }, [createUser, loaded, username]);
+ }, [dispatch, loaded, user.username]);
if (!loaded) {
return null;
}
- return ;
+
+ return ;
};
WithUser.defaultProps = {
@@ -343,10 +352,7 @@ WithUser.defaultProps = {
WithUser.propTypes = {
receiveEncryptedMessage: PropTypes.func.isRequired,
receiveUnencryptedMessage: PropTypes.func.isRequired,
- createUser: PropTypes.func.isRequired,
activities: PropTypes.array.isRequired,
- username: PropTypes.string.isRequired,
- publicKey: PropTypes.object.isRequired,
members: PropTypes.array.isRequired,
socketId: PropTypes.string.isRequired,
roomId: PropTypes.string.isRequired,
@@ -355,7 +361,6 @@ WithUser.propTypes = {
openModal: PropTypes.func.isRequired,
closeModal: PropTypes.func.isRequired,
iAmOwner: PropTypes.bool.isRequired,
- userId: PropTypes.string.isRequired,
toggleWindowFocus: PropTypes.func.isRequired,
soundIsEnabled: PropTypes.bool.isRequired,
persistenceIsEnabled: PropTypes.bool.isRequired,
diff --git a/client/src/components/Home/WithNewMessageNotification.jsx b/client/src/components/Home/WithNewMessageNotification.jsx
index 1e3fbc4..3661928 100644
--- a/client/src/components/Home/WithNewMessageNotification.jsx
+++ b/client/src/components/Home/WithNewMessageNotification.jsx
@@ -43,7 +43,6 @@ const WithNewMessageNotification = ({
const { username, type, text, fileName, locked, newUsername, currentUsername, action } = currentLastMessage;
if (currentLastMessage !== lastMessage && !windowIsFocused) {
- setLastMessage(currentLastMessage);
if (notificationIsAllowed && notificationIsEnabled) {
// Generate the proper notification according to the message type
switch (type) {
@@ -79,6 +78,8 @@ const WithNewMessageNotification = ({
if (soundIsEnabled) beep.play();
}
+ setLastMessage(currentLastMessage);
+
if (unreadMessageCount !== lastUnreadMessageCount) {
setLastUnreadMessageCount(unreadMessageCount);
Tinycon.setBubble(unreadMessageCount);
diff --git a/client/src/components/Home/index.jsx b/client/src/components/Home/index.jsx
index c78ff94..74341cb 100644
--- a/client/src/components/Home/index.jsx
+++ b/client/src/components/Home/index.jsx
@@ -3,7 +3,6 @@ import { useLoaderData } from 'react-router-dom';
import {
receiveEncryptedMessage,
- createUser,
openModal,
closeModal,
toggleWindowFocus,
@@ -26,8 +25,6 @@ const mapStateToProps = state => {
return {
activities: state.activities.items,
- userId: state.user.id,
- username: state.user.username,
publicKey: state.user.publicKey,
privateKey: state.user.privateKey,
members: state.room.members.filter(m => m.username && m.publicKey),
@@ -48,7 +45,6 @@ const mapStateToProps = state => {
const mapDispatchToProps = {
receiveEncryptedMessage,
- createUser,
openModal,
closeModal,
toggleWindowFocus,
diff --git a/client/src/components/Home/index.test.jsx b/client/src/components/Home/index.test.jsx
index a548ce3..0100106 100644
--- a/client/src/components/Home/index.test.jsx
+++ b/client/src/components/Home/index.test.jsx
@@ -206,10 +206,15 @@ describe('Connected Home component', () => {
,
);
expect(store.getState().app.unreadMessageCount).toBe(1);
+ expect(notify).toHaveBeenCalledTimes(1);
expect(notify).toHaveBeenLastCalledWith('sender said:', 'new message');
+ expect(beep.play).toHaveBeenCalledTimes(1);
expect(beep.play).toHaveBeenLastCalledWith();
expect(Tinycon.setBubble).toHaveBeenLastCalledWith(1);
+ notify.mockClear();
+ beep.play.mockClear();
+
// Test with sound and notification disabled
await act(() => toggleNotificationEnabled(false)(store.dispatch));
await act(() => toggleSoundEnabled(false)(store.dispatch));
@@ -227,8 +232,8 @@ describe('Connected Home component', () => {
);
expect(store.getState().app.unreadMessageCount).toBe(2);
- expect(notify).toHaveBeenCalledTimes(2);
- expect(beep.play).toHaveBeenCalledTimes(2);
+ expect(notify).toHaveBeenCalledTimes(0);
+ expect(beep.play).toHaveBeenCalledTimes(0);
expect(Tinycon.setBubble).toHaveBeenLastCalledWith(2);
});
});
diff --git a/client/src/reducers/user.js b/client/src/reducers/user.js
index 0c20766..a9f47e4 100644
--- a/client/src/reducers/user.js
+++ b/client/src/reducers/user.js
@@ -1,27 +1,28 @@
-const initialState = {
- privateKey: {},
- publicKey: {},
- username: '',
- id: '',
-};
+import { createSlice } from '@reduxjs/toolkit'
-const user = (receivedState, action) => {
- const state = { ...initialState, ...receivedState };
+export const userSlice = createSlice({
+ name: 'user',
+ initialState: {
+ privateKey: {},
+ publicKey: {},
+ username: '',
+ id: '',
+ },
+ reducers: {
+ createUser: (state, action) => {
+ const { privateKey, publicKey, username } = action.payload;
+ state.privateKey = privateKey;
+ state.publicKey = publicKey;
+ state.username = username;
+ state.id = publicKey.n;
+ },
+ changeUsername: (state, action) => {
+ const { newUsername } = action.payload;
+ state.username = newUsername;
+ }
+ },
+})
- switch (action.type) {
- case 'CREATE_USER':
- return {
- ...action.payload,
- id: action.payload.publicKey.n,
- };
- case 'SEND_ENCRYPTED_MESSAGE_CHANGE_USERNAME':
- return {
- ...state,
- username: action.payload.newUsername,
- };
- default:
- return state;
- }
-};
+export const { createUser,changeUsername } = userSlice.actions
-export default user;
+export default userSlice.reducer
\ No newline at end of file
diff --git a/client/src/reducers/user.test.js b/client/src/reducers/user.test.js
index 5cb07a8..057b78d 100644
--- a/client/src/reducers/user.test.js
+++ b/client/src/reducers/user.test.js
@@ -1,6 +1,6 @@
import { describe, it, expect, vi } from 'vitest';
-import reducer from './user';
+import reducer, { createUser, changeUsername} from './user';
vi.mock('@/i18n', () => {
return {
@@ -15,7 +15,8 @@ describe('User reducer', () => {
it('should handle CREATE_USER', () => {
const payload = { publicKey: { n: 'alicekey' }, username: 'alice' };
- expect(reducer({}, { type: 'CREATE_USER', payload })).toEqual({
+
+ expect(reducer({},createUser(payload) )).toEqual({
id: 'alicekey',
publicKey: { n: 'alicekey' },
username: 'alice',
@@ -24,10 +25,8 @@ describe('User reducer', () => {
it('should handle SEND_ENCRYPTED_MESSAGE_CHANGE_USERNAME', () => {
const payload = { newUsername: 'alice' };
- expect(reducer({ username: 'polux' }, { type: 'SEND_ENCRYPTED_MESSAGE_CHANGE_USERNAME', payload })).toEqual({
- id: '',
- privateKey: {},
- publicKey: {},
+
+ expect(reducer({ username: 'polux' }, changeUsername(payload))).toEqual({
username: 'alice',
});
});
diff --git a/readme.md b/readme.md
index c170df0..5d27c82 100644
--- a/readme.md
+++ b/readme.md
@@ -86,7 +86,7 @@ Then run it. Example:
$ docker run --init --name darkwire.io --rm -p 3001:3001 darkwire.io
```
-You are able to use any of the enviroment variables available in `server/.env.dist` and `client/.env.dist`. The defaults are available in [Dockerfile](Dockerfile)
+You are able to use any of the environment variables available in `server/.env.dist` and `client/.env.dist`. The defaults are available in [Dockerfile](Dockerfile)
### Security