Webatrice: support hashed passwords in register and resetPassword (#4549)
* support hashed passwords in register and resetPassword * lint * support hashedPasswords for accountActivation * use salt in post-register login step Co-authored-by: Jeremy Letto <jeremy.letto@datasite.com>
This commit is contained in:
parent
92f941a54c
commit
992e28797f
3 changed files with 64 additions and 15 deletions
|
@ -139,7 +139,29 @@ export class SessionCommands {
|
||||||
switch (raw.responseCode) {
|
switch (raw.responseCode) {
|
||||||
case webClient.protobuf.controller.Response.ResponseCode.RespOk: {
|
case webClient.protobuf.controller.Response.ResponseCode.RespOk: {
|
||||||
const passwordSalt = raw['.Response_PasswordSalt.ext']?.passwordSalt;
|
const passwordSalt = raw['.Response_PasswordSalt.ext']?.passwordSalt;
|
||||||
|
|
||||||
|
switch (webClient.options.reason) {
|
||||||
|
case WebSocketConnectReason.REGISTER: {
|
||||||
|
SessionCommands.register(passwordSalt);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case WebSocketConnectReason.ACTIVATE_ACCOUNT: {
|
||||||
|
SessionCommands.activateAccount(passwordSalt);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case WebSocketConnectReason.PASSWORD_RESET: {
|
||||||
|
SessionCommands.resetPassword(passwordSalt);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case WebSocketConnectReason.LOGIN:
|
||||||
|
default: {
|
||||||
SessionCommands.login(passwordSalt);
|
SessionCommands.login(passwordSalt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case webClient.protobuf.controller.Response.ResponseCode.RespRegistrationRequired: {
|
case webClient.protobuf.controller.Response.ResponseCode.RespRegistrationRequired: {
|
||||||
|
@ -155,19 +177,24 @@ export class SessionCommands {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static register(): void {
|
static register(passwordSalt?: string): void {
|
||||||
const { userName, password, email, country, realName } = webClient.options as unknown as ServerRegisterParams;
|
const { userName, password, email, country, realName } = webClient.options as unknown as ServerRegisterParams;
|
||||||
|
|
||||||
const registerConfig = {
|
const registerConfig: any = {
|
||||||
...webClient.clientConfig,
|
...webClient.clientConfig,
|
||||||
clientid: 'webatrice',
|
clientid: 'webatrice',
|
||||||
userName,
|
userName,
|
||||||
password,
|
|
||||||
email,
|
email,
|
||||||
country,
|
country,
|
||||||
realName,
|
realName,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (passwordSalt) {
|
||||||
|
registerConfig.hashedPassword = hashPassword(passwordSalt, password);
|
||||||
|
} else {
|
||||||
|
registerConfig.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
const CmdRegister = webClient.protobuf.controller.Command_Register.create(registerConfig);
|
const CmdRegister = webClient.protobuf.controller.Command_Register.create(registerConfig);
|
||||||
|
|
||||||
const sc = webClient.protobuf.controller.SessionCommand.create({
|
const sc = webClient.protobuf.controller.SessionCommand.create({
|
||||||
|
@ -176,7 +203,7 @@ export class SessionCommands {
|
||||||
|
|
||||||
webClient.protobuf.sendSessionCommand(sc, raw => {
|
webClient.protobuf.sendSessionCommand(sc, raw => {
|
||||||
if (raw.responseCode === webClient.protobuf.controller.Response.ResponseCode.RespRegistrationAccepted) {
|
if (raw.responseCode === webClient.protobuf.controller.Response.ResponseCode.RespRegistrationAccepted) {
|
||||||
SessionCommands.login();
|
SessionCommands.login(passwordSalt);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,7 +246,7 @@ export class SessionCommands {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
static activateAccount(): void {
|
static activateAccount(passwordSalt?: string): void {
|
||||||
const { userName, token } = webClient.options as unknown as AccountActivationParams;
|
const { userName, token } = webClient.options as unknown as AccountActivationParams;
|
||||||
|
|
||||||
const accountActivationConfig = {
|
const accountActivationConfig = {
|
||||||
|
@ -238,7 +265,7 @@ export class SessionCommands {
|
||||||
webClient.protobuf.sendSessionCommand(sc, raw => {
|
webClient.protobuf.sendSessionCommand(sc, raw => {
|
||||||
if (raw.responseCode === webClient.protobuf.controller.Response.ResponseCode.RespActivationAccepted) {
|
if (raw.responseCode === webClient.protobuf.controller.Response.ResponseCode.RespActivationAccepted) {
|
||||||
SessionPersistence.accountActivationSuccess();
|
SessionPersistence.accountActivationSuccess();
|
||||||
SessionCommands.login();
|
SessionCommands.login(passwordSalt);
|
||||||
} else {
|
} else {
|
||||||
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, 'Account Activation Failed');
|
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, 'Account Activation Failed');
|
||||||
SessionCommands.disconnect();
|
SessionCommands.disconnect();
|
||||||
|
@ -311,17 +338,22 @@ export class SessionCommands {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static resetPassword(): void {
|
static resetPassword(passwordSalt?: string): void {
|
||||||
const { userName, token, newPassword } = webClient.options as unknown as ForgotPasswordResetParams;
|
const { userName, token, newPassword } = webClient.options as unknown as ForgotPasswordResetParams;
|
||||||
|
|
||||||
const forgotPasswordResetConfig = {
|
const forgotPasswordResetConfig: any = {
|
||||||
...webClient.clientConfig,
|
...webClient.clientConfig,
|
||||||
clientid: 'webatrice',
|
clientid: 'webatrice',
|
||||||
userName,
|
userName,
|
||||||
token,
|
token,
|
||||||
newPassword,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (passwordSalt) {
|
||||||
|
forgotPasswordResetConfig.hashedNewPassword = hashPassword(passwordSalt, newPassword);
|
||||||
|
} else {
|
||||||
|
forgotPasswordResetConfig.newPassword = newPassword;
|
||||||
|
}
|
||||||
|
|
||||||
const CmdForgotPasswordReset = webClient.protobuf.controller.Command_ForgotPasswordReset.create(forgotPasswordResetConfig);
|
const CmdForgotPasswordReset = webClient.protobuf.controller.Command_ForgotPasswordReset.create(forgotPasswordResetConfig);
|
||||||
|
|
||||||
const sc = webClient.protobuf.controller.SessionCommand.create({
|
const sc = webClient.protobuf.controller.SessionCommand.create({
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { Room, StatusEnum, User, WebSocketConnectReason } from 'types';
|
||||||
import { SessionCommands } from '../commands';
|
import { SessionCommands } from '../commands';
|
||||||
import { RoomPersistence, SessionPersistence } from '../persistence';
|
import { RoomPersistence, SessionPersistence } from '../persistence';
|
||||||
import { ProtobufEvents } from '../services/ProtobufService';
|
import { ProtobufEvents } from '../services/ProtobufService';
|
||||||
|
import { passwordSaltSupported } from '../utils';
|
||||||
import webClient from '../WebClient';
|
import webClient from '../WebClient';
|
||||||
|
|
||||||
export const SessionEvents: ProtobufEvents = {
|
export const SessionEvents: ProtobufEvents = {
|
||||||
|
@ -122,18 +123,25 @@ function serverIdentification(info: ServerIdentificationData) {
|
||||||
switch (webClient.options.reason) {
|
switch (webClient.options.reason) {
|
||||||
case WebSocketConnectReason.LOGIN:
|
case WebSocketConnectReason.LOGIN:
|
||||||
SessionCommands.updateStatus(StatusEnum.LOGGING_IN, 'Logging In...');
|
SessionCommands.updateStatus(StatusEnum.LOGGING_IN, 'Logging In...');
|
||||||
// Intentional use of Bitwise operator b/c of how Servatrice Enums work
|
if (passwordSaltSupported(serverOptions, webClient)) {
|
||||||
if (serverOptions & webClient.protobuf.controller.Event_ServerIdentification.ServerOptions.SupportsPasswordHash) {
|
|
||||||
SessionCommands.requestPasswordSalt();
|
SessionCommands.requestPasswordSalt();
|
||||||
} else {
|
} else {
|
||||||
SessionCommands.login();
|
SessionCommands.login();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WebSocketConnectReason.REGISTER:
|
case WebSocketConnectReason.REGISTER:
|
||||||
|
if (passwordSaltSupported(serverOptions, webClient)) {
|
||||||
|
SessionCommands.requestPasswordSalt();
|
||||||
|
} else {
|
||||||
SessionCommands.register();
|
SessionCommands.register();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case WebSocketConnectReason.ACTIVATE_ACCOUNT:
|
case WebSocketConnectReason.ACTIVATE_ACCOUNT:
|
||||||
|
if (passwordSaltSupported(serverOptions, webClient)) {
|
||||||
|
SessionCommands.requestPasswordSalt();
|
||||||
|
} else {
|
||||||
SessionCommands.activateAccount();
|
SessionCommands.activateAccount();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case WebSocketConnectReason.PASSWORD_RESET_REQUEST:
|
case WebSocketConnectReason.PASSWORD_RESET_REQUEST:
|
||||||
SessionCommands.resetPasswordRequest();
|
SessionCommands.resetPasswordRequest();
|
||||||
|
@ -142,7 +150,11 @@ function serverIdentification(info: ServerIdentificationData) {
|
||||||
SessionCommands.resetPasswordChallenge();
|
SessionCommands.resetPasswordChallenge();
|
||||||
break;
|
break;
|
||||||
case WebSocketConnectReason.PASSWORD_RESET:
|
case WebSocketConnectReason.PASSWORD_RESET:
|
||||||
|
if (passwordSaltSupported(serverOptions, webClient)) {
|
||||||
|
SessionCommands.requestPasswordSalt();
|
||||||
|
} else {
|
||||||
SessionCommands.resetPassword();
|
SessionCommands.resetPassword();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, 'Unknown Connection Reason: ' + webClient.options.reason);
|
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, 'Unknown Connection Reason: ' + webClient.options.reason);
|
||||||
|
|
|
@ -24,3 +24,8 @@ export const generateSalt = (): string => {
|
||||||
|
|
||||||
return salt;
|
return salt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const passwordSaltSupported = (serverOptions, webClient): number => {
|
||||||
|
// Intentional use of Bitwise operator b/c of how Servatrice Enums work
|
||||||
|
return serverOptions & webClient.protobuf.controller.Event_ServerIdentification.ServerOptions.SupportsPasswordHash;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue