Support Registration on Webatrice with a baseline of handling. (#4436)
* Support Registration on Webatrice with a baseline of handling. Still needs to support activation tokens & unit testing. * Add support for account activation with token * Activate Account refactor * Fix typo * Add Unit Testing for Commands/Events * Changes based on review feedback
This commit is contained in:
parent
ebebb9c4bb
commit
b1ef8220ee
14 changed files with 483 additions and 68 deletions
|
@ -1,10 +1,18 @@
|
|||
import { ServerConnectParams } from "store";
|
||||
import { StatusEnum, User} from "types";
|
||||
import { webClient, SessionCommands } from "websocket";
|
||||
import {StatusEnum, User} from "types";
|
||||
import {SessionCommands, webClient} from "websocket";
|
||||
import {WebSocketConnectReason, WebSocketOptions} from "../websocket/services/WebSocketService";
|
||||
|
||||
export default class AuthenticationService {
|
||||
static connect(options: ServerConnectParams): void {
|
||||
SessionCommands.connect(options);
|
||||
static connect(options: WebSocketOptions): void {
|
||||
SessionCommands.connect(options, WebSocketConnectReason.LOGIN);
|
||||
}
|
||||
|
||||
static register(options: WebSocketOptions): void {
|
||||
SessionCommands.connect(options, WebSocketConnectReason.REGISTER);
|
||||
}
|
||||
|
||||
static activateAccount(options: WebSocketOptions): void {
|
||||
SessionCommands.connect(options, WebSocketConnectReason.ACTIVATE_ACCOUNT);
|
||||
}
|
||||
|
||||
static disconnect(): void {
|
||||
|
|
|
@ -76,7 +76,7 @@ class Account extends Component<AccountProps> {
|
|||
<Paper className="account-details" style={{margin: "0 0 5px 0"}}>
|
||||
<img src={url} alt={name} />
|
||||
<p><strong>{name}</strong></p>
|
||||
<p>Location: ({country.toUpperCase()})</p>
|
||||
<p>Location: ({country?.toUpperCase()})</p>
|
||||
<p>User Level: {userLevel}</p>
|
||||
<p>Account Age: {accountageSecs}</p>
|
||||
<p>Real Name: {realName}</p>
|
||||
|
|
|
@ -25,7 +25,6 @@ class Server extends Component<ServerProps, ServerState> {
|
|||
this.showDescription = this.showDescription.bind(this);
|
||||
this.showRegisterForm = this.showRegisterForm.bind(this);
|
||||
this.hideRegisterForm = this.hideRegisterForm.bind(this);
|
||||
this.onRegister = this.onRegister.bind(this);
|
||||
|
||||
this.state = {
|
||||
register: false
|
||||
|
@ -47,10 +46,6 @@ class Server extends Component<ServerProps, ServerState> {
|
|||
this.setState({register: false});
|
||||
}
|
||||
|
||||
onRegister(fields) {
|
||||
console.log("register", fields);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { message, rooms, joinedRooms, history, state, description, users } = this.props;
|
||||
const { register } = this.state;
|
||||
|
@ -66,7 +61,7 @@ class Server extends Component<ServerProps, ServerState> {
|
|||
<Paper className="server-connect__form">
|
||||
{
|
||||
register
|
||||
? ( <Register connect={this.hideRegisterForm} onRegister={this.onRegister} /> )
|
||||
? ( <Register connect={this.hideRegisterForm} /> )
|
||||
: ( <Connect register={this.showRegisterForm} /> )
|
||||
}
|
||||
</Paper>
|
||||
|
@ -106,7 +101,7 @@ const ServerRooms = ({ rooms, joinedRooms, history, message, users}) => (
|
|||
Users connected to server: {users.length}
|
||||
</div>
|
||||
<VirtualList
|
||||
itemKey={(index, data) => users[index].name }
|
||||
itemKey={(index) => users[index].name }
|
||||
items={ users.map(user => (
|
||||
<ListItem button dense>
|
||||
<UserDisplay user={user} />
|
||||
|
@ -122,13 +117,13 @@ const ServerRooms = ({ rooms, joinedRooms, history, message, users}) => (
|
|||
const Connect = ({register}) => (
|
||||
<div className="form-wrapper">
|
||||
<ConnectForm onSubmit={AuthenticationService.connect} />
|
||||
{/*{<Button variant="outlined" onClick={register}>Register</Button>}*/}
|
||||
<Button variant="outlined" onClick={register}>Register</Button>
|
||||
</div>
|
||||
);
|
||||
|
||||
const Register = ({ onRegister, connect }) => (
|
||||
const Register = ({ connect }) => (
|
||||
<div className="form-wrapper">
|
||||
<RegisterForm onSubmit={event => onRegister(event)} />
|
||||
<RegisterForm onSubmit={AuthenticationService.register} />
|
||||
<Button variant="outlined" onClick={connect}>Connect</Button>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -19,10 +19,10 @@ const RegisterForm = ({ handleSubmit }) => (
|
|||
<Field label="Port" name="port" component={InputField} />
|
||||
</div>
|
||||
<div className="registerForm-item">
|
||||
<Field label="Player Name" name="userName" component={InputField} />
|
||||
<Field label="Player Name" name="user" component={InputField} />
|
||||
</div>
|
||||
<div className="registerForm-item">
|
||||
<Field label="Password" name="password" type="password" component={InputField} />
|
||||
<Field label="Password" name="pass" type="password" component={InputField} />
|
||||
</div>
|
||||
<div className="registerForm-item">
|
||||
<Field label="Password (again)" name="passwordConfirm" type="password" component={InputField} />
|
||||
|
|
|
@ -7,6 +7,22 @@ export interface ServerConnectParams {
|
|||
pass: string;
|
||||
}
|
||||
|
||||
export interface ServerRegisterParams {
|
||||
host: string;
|
||||
port: string;
|
||||
user: string;
|
||||
pass: string;
|
||||
passAgain: string;
|
||||
email: string;
|
||||
country: string;
|
||||
realName: string;
|
||||
}
|
||||
|
||||
export interface AccountActivationParams extends ServerRegisterParams {
|
||||
activationCode: string;
|
||||
clientid: string;
|
||||
}
|
||||
|
||||
export interface ServerState {
|
||||
buddyList: User[];
|
||||
ignoreList: User[];
|
||||
|
|
|
@ -4,20 +4,30 @@ export interface ServerStatus {
|
|||
}
|
||||
|
||||
export enum StatusEnum {
|
||||
DISCONNECTED = 0,
|
||||
CONNECTING = 1,
|
||||
CONNECTED = 2,
|
||||
LOGGINGIN = 3,
|
||||
LOGGEDIN = 4,
|
||||
DISCONNECTED,
|
||||
CONNECTING,
|
||||
CONNECTED,
|
||||
LOGGINGIN,
|
||||
LOGGEDIN,
|
||||
REGISTERING,
|
||||
REGISTERED,
|
||||
ACTIVATING_ACCOUNT,
|
||||
ACCOUNT_ACTIVATED,
|
||||
RECOVERING_PASSWORD,
|
||||
DISCONNECTING = 99
|
||||
}
|
||||
|
||||
export enum StatusEnumLabel {
|
||||
"Disconnected" = 0,
|
||||
"Connecting" = 1,
|
||||
"Connected" = 2,
|
||||
"Loggingin" = 3,
|
||||
"Loggedin" = 4,
|
||||
"Disconnected",
|
||||
"Connecting" ,
|
||||
"Connected" ,
|
||||
"Loggingin",
|
||||
"Loggedin",
|
||||
"Registering",
|
||||
"Registered",
|
||||
"ActivatingAccount",
|
||||
"AccountActivated",
|
||||
"RecoveringPassword",
|
||||
"Disconnecting" = 99
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import { ServerConnectParams } from "store";
|
||||
import { ServerStatus, StatusEnum } from "types";
|
||||
import {ServerStatus, StatusEnum} from "types";
|
||||
|
||||
import { ProtobufService } from './services/ProtobufService';
|
||||
import { WebSocketService, WebSocketOptions } from "./services/WebSocketService";
|
||||
import {ProtobufService} from './services/ProtobufService';
|
||||
import {WebSocketOptions, WebSocketService} from "./services/WebSocketService";
|
||||
|
||||
import { RoomPersistence, SessionPersistence } from './persistence';
|
||||
import {RoomPersistence, SessionPersistence} from './persistence';
|
||||
|
||||
export class WebClient {
|
||||
public socket = new WebSocketService(this);
|
||||
|
@ -36,6 +35,8 @@ export class WebClient {
|
|||
port: "",
|
||||
user: "",
|
||||
pass: "",
|
||||
clientid: null,
|
||||
reason: null,
|
||||
autojoinrooms: true,
|
||||
keepalive: 5000
|
||||
};
|
||||
|
@ -52,8 +53,8 @@ export class WebClient {
|
|||
console.log(this);
|
||||
}
|
||||
|
||||
public connect(options: ServerConnectParams) {
|
||||
this.options = { ...this.options, ...options };
|
||||
public connect(options: WebSocketOptions) {
|
||||
this.options = {...this.options, ...options};
|
||||
this.socket.connect(this.options);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import { StatusEnum } from 'types';
|
||||
import {StatusEnum} from 'types';
|
||||
|
||||
import { SessionCommands } from './SessionCommands';
|
||||
import {SessionCommands} from './SessionCommands';
|
||||
|
||||
import { RoomPersistence, SessionPersistence } from '../persistence';
|
||||
import {RoomPersistence, SessionPersistence} from '../persistence';
|
||||
import webClient from '../WebClient';
|
||||
import {WebSocketConnectReason} from "../services/WebSocketService";
|
||||
import {AccountActivationParams, ServerRegisterParams} from "../../store";
|
||||
|
||||
describe('SessionCommands', () => {
|
||||
const roomId = 1;
|
||||
|
@ -21,23 +23,49 @@ describe('SessionCommands', () => {
|
|||
webClient.protobuf.controller.SessionCommand = { create: args => args };
|
||||
});
|
||||
|
||||
|
||||
describe('connect', () => {
|
||||
it('should call SessionCommands.updateStatus and webClient.connect', () => {
|
||||
let options;
|
||||
|
||||
beforeEach(() => {
|
||||
spyOn(webClient, 'connect');
|
||||
const options = {
|
||||
options = {
|
||||
host: 'host',
|
||||
port: 'port',
|
||||
user: 'user',
|
||||
pass: 'pass',
|
||||
};
|
||||
});
|
||||
|
||||
SessionCommands.connect(options);
|
||||
it('should call SessionCommands.updateStatus and webClient.connect when logging in', () => {
|
||||
SessionCommands.connect(options, WebSocketConnectReason.LOGIN);
|
||||
|
||||
expect(SessionCommands.updateStatus).toHaveBeenCalled();
|
||||
expect(SessionCommands.updateStatus).toHaveBeenCalledWith(StatusEnum.CONNECTING, 'Connecting...');
|
||||
expect(SessionCommands.updateStatus).toHaveBeenCalledWith(StatusEnum.CONNECTING, expect.any(String));
|
||||
|
||||
expect(webClient.connect).toHaveBeenCalled();
|
||||
expect(webClient.connect).toHaveBeenCalledWith(options);
|
||||
expect(webClient.connect).toHaveBeenCalledWith({ ...options, reason: WebSocketConnectReason.LOGIN });
|
||||
});
|
||||
|
||||
it('should call SessionCommands.updateStatus and webClient.connect when registering', () => {
|
||||
SessionCommands.connect(options, WebSocketConnectReason.REGISTER);
|
||||
|
||||
expect(SessionCommands.updateStatus).toHaveBeenCalled();
|
||||
expect(SessionCommands.updateStatus).toHaveBeenCalledWith(StatusEnum.REGISTERING, expect.any(String));
|
||||
|
||||
expect(webClient.connect).toHaveBeenCalled();
|
||||
expect(webClient.connect).toHaveBeenCalledWith({ ...options, reason: WebSocketConnectReason.REGISTER });
|
||||
});
|
||||
|
||||
|
||||
it('should call SessionCommands.updateStatus and webClient.connect when activating account', () => {
|
||||
SessionCommands.connect(options, WebSocketConnectReason.ACTIVATE_ACCOUNT);
|
||||
|
||||
expect(SessionCommands.updateStatus).toHaveBeenCalled();
|
||||
expect(SessionCommands.updateStatus).toHaveBeenCalledWith(StatusEnum.ACTIVATING_ACCOUNT, expect.any(String));
|
||||
|
||||
expect(webClient.connect).toHaveBeenCalled();
|
||||
expect(webClient.connect).toHaveBeenCalledWith({ ...options, reason: WebSocketConnectReason.ACTIVATE_ACCOUNT });
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -215,6 +243,160 @@ describe('SessionCommands', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('register', () => {
|
||||
beforeEach(() => {
|
||||
webClient.protobuf.controller.Command_Register = { create: args => args };
|
||||
webClient.options = {
|
||||
...webClient.options,
|
||||
user: 'user',
|
||||
pass: 'pass',
|
||||
email: 'email@example.com',
|
||||
country: 'us',
|
||||
realName: 'realName',
|
||||
clientid: 'abcdefg'
|
||||
} as any;
|
||||
});
|
||||
|
||||
it('should call protobuf controller methods and sendCommand', () => {
|
||||
SessionCommands.register();
|
||||
|
||||
const options = webClient.options as unknown as ServerRegisterParams;
|
||||
|
||||
expect(webClient.protobuf.sendSessionCommand).toHaveBeenCalled();
|
||||
expect(webClient.protobuf.sendSessionCommand).toHaveBeenCalledWith({
|
||||
'.Command_Register.ext': {
|
||||
...webClient.clientConfig,
|
||||
userName: options.user,
|
||||
password: options.pass,
|
||||
email: options.email,
|
||||
country: options.country,
|
||||
realName: options.realName,
|
||||
clientid: jasmine.any(String)
|
||||
}
|
||||
}, jasmine.any(Function));
|
||||
});
|
||||
|
||||
describe('response', () => {
|
||||
const RespRegistrationAccepted = 'RespRegistrationAccepted';
|
||||
const respKey = '.Response_Register.ext';
|
||||
let response;
|
||||
|
||||
beforeEach(() => {
|
||||
response = {
|
||||
responseCode: RespRegistrationAccepted,
|
||||
[respKey]: {
|
||||
reasonStr: "",
|
||||
endTime: 10000000
|
||||
}
|
||||
};
|
||||
|
||||
webClient.protobuf.controller.Response = { ResponseCode: { RespRegistrationAccepted }};
|
||||
|
||||
sendSessionCommandSpy.and.callFake((_, callback) => callback(response));
|
||||
})
|
||||
|
||||
it("should login user if registration accepted without email verification", () => {
|
||||
spyOn(SessionCommands, 'login');
|
||||
spyOn(SessionPersistence, 'accountAwaitingActivation');
|
||||
|
||||
SessionCommands.register();
|
||||
|
||||
expect(SessionCommands.login).toHaveBeenCalled();
|
||||
expect(SessionPersistence.accountAwaitingActivation).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should prompt user if registration accepted with email verification", () => {
|
||||
const RespRegistrationAcceptedNeedsActivation = 'RespRegistrationAcceptedNeedsActivation';
|
||||
response.responseCode = RespRegistrationAcceptedNeedsActivation;
|
||||
webClient.protobuf.controller.Response.ResponseCode.RespRegistrationAcceptedNeedsActivation = RespRegistrationAcceptedNeedsActivation;
|
||||
|
||||
spyOn(SessionCommands, 'login');
|
||||
spyOn(SessionPersistence, 'accountAwaitingActivation');
|
||||
|
||||
SessionCommands.register();
|
||||
|
||||
expect(SessionCommands.login).not.toHaveBeenCalled();
|
||||
expect(SessionPersistence.accountAwaitingActivation).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should disconnect user if registration fails due to registration being disabled", () => {
|
||||
const RespRegistrationDisabled = 'RespRegistrationDisabled';
|
||||
response.responseCode = RespRegistrationDisabled;
|
||||
webClient.protobuf.controller.Response.ResponseCode.RespRegistrationDisabled = RespRegistrationDisabled;
|
||||
|
||||
SessionCommands.register();
|
||||
|
||||
expect(SessionCommands.updateStatus).toHaveBeenCalledWith(StatusEnum.DISCONNECTED, expect.any(String));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('activateAccount', () => {
|
||||
beforeEach(() => {
|
||||
webClient.protobuf.controller.Command_Activate = { create: args => args };
|
||||
webClient.options = {
|
||||
...webClient.options,
|
||||
user: 'user',
|
||||
activationCode: 'token',
|
||||
clientid: 'abcdefg'
|
||||
} as any;
|
||||
});
|
||||
|
||||
it('should call protobuf controller methods and sendCommand', () => {
|
||||
SessionCommands.activateAccount();
|
||||
|
||||
const options = webClient.options as unknown as AccountActivationParams;
|
||||
|
||||
expect(webClient.protobuf.sendSessionCommand).toHaveBeenCalledWith({
|
||||
'.Command_Activate.ext': {
|
||||
...webClient.clientConfig,
|
||||
userName: options.user,
|
||||
token: options.activationCode,
|
||||
clientid: jasmine.any(String)
|
||||
}
|
||||
}, jasmine.any(Function));
|
||||
});
|
||||
|
||||
describe('response', () => {
|
||||
const RespActivationAccepted = 'RespActivationAccepted';
|
||||
const respKey = '.Response_Activate.ext';
|
||||
let response;
|
||||
|
||||
beforeEach(() => {
|
||||
response = {
|
||||
responseCode: RespActivationAccepted,
|
||||
[respKey]: {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
webClient.protobuf.controller.Response = { ResponseCode: { RespActivationAccepted }};
|
||||
|
||||
sendSessionCommandSpy.and.callFake((_, callback) => callback(response));
|
||||
spyOn(SessionCommands, 'login');
|
||||
spyOn(SessionPersistence, 'accountActivationFailed');
|
||||
});
|
||||
|
||||
it('should activate user and login if correct activation token used', () => {
|
||||
SessionCommands.activateAccount();
|
||||
|
||||
expect(SessionCommands.login).toHaveBeenCalled();
|
||||
expect(SessionPersistence.accountActivationFailed).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should disconnect user if activation failed for any reason', () => {
|
||||
const RespActivationFailed = 'RespActivationFailed';
|
||||
response.responseCode = RespActivationFailed;
|
||||
webClient.protobuf.controller.Response.ResponseCode.RespActivationFailed = RespActivationFailed;
|
||||
|
||||
SessionCommands.activateAccount();
|
||||
|
||||
expect(SessionCommands.login).not.toHaveBeenCalled();
|
||||
expect(SessionPersistence.accountActivationFailed).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('listUsers', () => {
|
||||
beforeEach(() => {
|
||||
webClient.protobuf.controller.Command_ListUsers = { create: () => ({}) };
|
||||
|
|
|
@ -1,14 +1,33 @@
|
|||
import { ServerConnectParams } from 'store';
|
||||
import { StatusEnum } from 'types';
|
||||
import {StatusEnum} from 'types';
|
||||
|
||||
import { RoomPersistence, SessionPersistence } from '../persistence';
|
||||
import {RoomPersistence, SessionPersistence} from '../persistence';
|
||||
import webClient from '../WebClient';
|
||||
import { guid } from '../utils';
|
||||
import {guid} from '../utils';
|
||||
import {WebSocketConnectReason, WebSocketOptions} from "../services/WebSocketService";
|
||||
import {ServerRegisterParams, AccountActivationParams} from "../../store";
|
||||
import NormalizeService from "../utils/NormalizeService";
|
||||
|
||||
export class SessionCommands {
|
||||
static connect(options: ServerConnectParams): void {
|
||||
SessionCommands.updateStatus(StatusEnum.CONNECTING, 'Connecting...');
|
||||
webClient.connect(options);
|
||||
static connect(options: WebSocketOptions, reason: WebSocketConnectReason): void {
|
||||
switch (reason) {
|
||||
case WebSocketConnectReason.LOGIN:
|
||||
SessionCommands.updateStatus(StatusEnum.CONNECTING, 'Connecting...');
|
||||
break;
|
||||
case WebSocketConnectReason.REGISTER:
|
||||
SessionCommands.updateStatus(StatusEnum.REGISTERING, 'Registering...');
|
||||
break;
|
||||
case WebSocketConnectReason.ACTIVATE_ACCOUNT:
|
||||
SessionCommands.updateStatus(StatusEnum.ACTIVATING_ACCOUNT, 'Activating Account...');
|
||||
break;
|
||||
case WebSocketConnectReason.RECOVER_PASSWORD:
|
||||
SessionCommands.updateStatus(StatusEnum.RECOVERING_PASSWORD, 'Recovering Password...');
|
||||
break;
|
||||
default:
|
||||
console.error('Connection Failed', reason);
|
||||
break;
|
||||
}
|
||||
|
||||
webClient.connect({ ...options, reason });
|
||||
}
|
||||
|
||||
static disconnect(): void {
|
||||
|
@ -78,6 +97,7 @@ export class SessionCommands {
|
|||
|
||||
case webClient.protobuf.controller.Response.ResponseCode.RespAccountNotActivated:
|
||||
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, 'Login failed: account not activated');
|
||||
SessionPersistence.accountAwaitingActivation();
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -86,6 +106,102 @@ export class SessionCommands {
|
|||
});
|
||||
}
|
||||
|
||||
static register(): void {
|
||||
const options = webClient.options as unknown as ServerRegisterParams;
|
||||
|
||||
const registerConfig = {
|
||||
...webClient.clientConfig,
|
||||
userName: options.user,
|
||||
password: options.pass,
|
||||
email: options.email,
|
||||
country: options.country,
|
||||
realName: options.realName,
|
||||
clientid: 'webatrice'
|
||||
};
|
||||
|
||||
const CmdRegister = webClient.protobuf.controller.Command_Register.create(registerConfig);
|
||||
|
||||
const sc = webClient.protobuf.controller.SessionCommand.create({
|
||||
'.Command_Register.ext' : CmdRegister
|
||||
});
|
||||
|
||||
webClient.protobuf.sendSessionCommand(sc, raw => {
|
||||
let error;
|
||||
|
||||
switch (raw.responseCode) {
|
||||
case webClient.protobuf.controller.Response.ResponseCode.RespRegistrationAccepted:
|
||||
SessionCommands.login();
|
||||
break;
|
||||
case webClient.protobuf.controller.Response.ResponseCode.RespRegistrationAcceptedNeedsActivation:
|
||||
SessionCommands.updateStatus(StatusEnum.REGISTERED, "Registration Successful");
|
||||
SessionPersistence.accountAwaitingActivation();
|
||||
break;
|
||||
case webClient.protobuf.controller.Response.ResponseCode.RespRegistrationDisabled:
|
||||
error = 'Registration is currently disabled';
|
||||
break;
|
||||
case webClient.protobuf.controller.Response.ResponseCode.RespUserAlreadyExists:
|
||||
error = 'There is already an existing user with this username';
|
||||
break;
|
||||
case webClient.protobuf.controller.Response.ResponseCode.RespEmailRequiredToRegister:
|
||||
error = 'A valid email address is required to register';
|
||||
break;
|
||||
case webClient.protobuf.controller.Response.ResponseCode.RespEmailBlackListed:
|
||||
error = 'The email address provider used has been blocked from use';
|
||||
break;
|
||||
case webClient.protobuf.controller.Response.ResponseCode.RespTooManyRequests:
|
||||
error = 'This email address already has the maximum number of accounts you can register';
|
||||
break;
|
||||
case webClient.protobuf.controller.Response.ResponseCode.RespPasswordTooShort:
|
||||
error = 'Your password was too short';
|
||||
break;
|
||||
case webClient.protobuf.controller.Response.ResponseCode.RespUserIsBanned:
|
||||
error = NormalizeService.normalizeBannedUserError(raw.reasonStr, raw.endTime);
|
||||
break;
|
||||
case webClient.protobuf.controller.Response.ResponseCode.RespUsernameInvalid:
|
||||
console.error("ResponseCode.RespUsernameInvalid", raw.reasonStr);
|
||||
error = 'Invalid username';
|
||||
break;
|
||||
case webClient.protobuf.controller.Response.ResponseCode.RespRegistrationFailed:
|
||||
default:
|
||||
console.error("ResponseCode Type", raw.responseCode);
|
||||
error = 'Registration failed due to a server issue';
|
||||
break;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, `Registration Failed: ${error}`);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
static activateAccount(): void {
|
||||
const options = webClient.options as unknown as AccountActivationParams;
|
||||
|
||||
const accountActivationConfig = {
|
||||
...webClient.clientConfig,
|
||||
userName: options.user,
|
||||
clientid: options.clientid,
|
||||
token: options.activationCode
|
||||
};
|
||||
|
||||
const CmdActivate = webClient.protobuf.controller.Command_Activate.create(accountActivationConfig);
|
||||
|
||||
const sc = webClient.protobuf.controller.SessionCommand.create({
|
||||
'.Command_Activate.ext': CmdActivate
|
||||
});
|
||||
|
||||
webClient.protobuf.sendSessionCommand(sc, raw => {
|
||||
if (raw.responseCode === webClient.protobuf.controller.Response.ResponseCode.RespActivationAccepted) {
|
||||
SessionCommands.updateStatus(StatusEnum.ACCOUNT_ACTIVATED, 'Account Activation Successful');
|
||||
SessionCommands.login();
|
||||
} else {
|
||||
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, 'Account Activation Failed');
|
||||
SessionPersistence.accountActivationFailed();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
static listUsers(): void {
|
||||
const CmdListUsers = webClient.protobuf.controller.Command_ListUsers.create();
|
||||
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
import { StatusEnum } from "types";
|
||||
import {StatusEnum} from "types";
|
||||
|
||||
import {
|
||||
SessionEvents,
|
||||
SessionEvent,
|
||||
AddToListData,
|
||||
ConnectionClosedData,
|
||||
ListRoomsData,
|
||||
RemoveFromListData,
|
||||
ServerIdentificationData,
|
||||
ServerMessageData,
|
||||
SessionEvents,
|
||||
UserJoinedData,
|
||||
UserLeftData,
|
||||
} from './SessionEvents';
|
||||
|
||||
import { SessionCommands } from "../commands";
|
||||
import { RoomPersistence, SessionPersistence } from '../persistence';
|
||||
import {SessionCommands} from "../commands";
|
||||
import {RoomPersistence, SessionPersistence} from '../persistence';
|
||||
import webClient from '../WebClient';
|
||||
import {WebSocketConnectReason} from "../services/WebSocketService";
|
||||
|
||||
describe('SessionEvents', () => {
|
||||
const roomId = 1;
|
||||
|
@ -277,24 +277,57 @@ describe('SessionEvents', () => {
|
|||
});
|
||||
|
||||
describe('.Event_ServerIdentification.ext', () => {
|
||||
it('update status/info and login', () => {
|
||||
spyOn(SessionPersistence, 'updateInfo');
|
||||
spyOn(SessionCommands, 'login');
|
||||
let data: ServerIdentificationData;
|
||||
let event;
|
||||
|
||||
beforeEach(() => {
|
||||
webClient.protocolVersion = 0;
|
||||
const data: ServerIdentificationData = {
|
||||
event = SessionEvents['.Event_ServerIdentification.ext'];
|
||||
data = {
|
||||
serverName: 'serverName',
|
||||
serverVersion: 'serverVersion',
|
||||
protocolVersion: 0,
|
||||
};
|
||||
|
||||
SessionEvents['.Event_ServerIdentification.ext'](data);
|
||||
spyOn(SessionPersistence, 'updateInfo');
|
||||
});
|
||||
|
||||
it('update status/info and login', () => {
|
||||
spyOn(SessionCommands, 'login');
|
||||
|
||||
webClient.options.reason = WebSocketConnectReason.LOGIN;
|
||||
|
||||
event(data);
|
||||
|
||||
expect(SessionPersistence.updateInfo).toHaveBeenCalledWith(data.serverName, data.serverVersion);
|
||||
expect(SessionCommands.updateStatus).toHaveBeenCalledWith(StatusEnum.LOGGINGIN, 'Logging in...');
|
||||
expect(SessionCommands.updateStatus).toHaveBeenCalledWith(StatusEnum.LOGGINGIN, expect.any(String));
|
||||
expect(SessionCommands.login).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should update stat/info and register', () => {
|
||||
spyOn(SessionCommands, 'register');
|
||||
|
||||
webClient.options.reason = WebSocketConnectReason.REGISTER;
|
||||
|
||||
event(data);
|
||||
|
||||
expect(SessionPersistence.updateInfo).toHaveBeenCalledWith(data.serverName, data.serverVersion);
|
||||
expect(SessionCommands.updateStatus).toHaveBeenCalledWith(StatusEnum.REGISTERING, expect.any(String));
|
||||
expect(SessionCommands.register).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should update stat/info and activate account', () => {
|
||||
spyOn(SessionCommands, 'activateAccount');
|
||||
|
||||
webClient.options.reason = WebSocketConnectReason.ACTIVATE_ACCOUNT;
|
||||
|
||||
event(data);
|
||||
|
||||
expect(SessionPersistence.updateInfo).toHaveBeenCalledWith(data.serverName, data.serverVersion);
|
||||
expect(SessionCommands.updateStatus).toHaveBeenCalledWith(StatusEnum.ACTIVATING_ACCOUNT, expect.any(String));
|
||||
expect(SessionCommands.activateAccount).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should disconnect if protocolVersion mismatched', () => {
|
||||
spyOn(SessionCommands, 'login');
|
||||
spyOn(SessionCommands, 'disconnect');
|
||||
|
@ -306,7 +339,7 @@ describe('SessionEvents', () => {
|
|||
protocolVersion: 1,
|
||||
};
|
||||
|
||||
SessionEvents['.Event_ServerIdentification.ext'](data);
|
||||
event(data);
|
||||
|
||||
expect(SessionCommands.disconnect).toHaveBeenCalled();
|
||||
expect(SessionCommands.updateStatus).toHaveBeenCalledWith(StatusEnum.DISCONNECTED, `Protocol version mismatch: ${data.protocolVersion}`);
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { Room, StatusEnum, User } from 'types';
|
||||
import {Room, StatusEnum, User} from 'types';
|
||||
|
||||
import { SessionCommands } from '../commands';
|
||||
import { RoomPersistence, SessionPersistence } from '../persistence';
|
||||
import { ProtobufEvents } from '../services/ProtobufService';
|
||||
import {SessionCommands} from '../commands';
|
||||
import {RoomPersistence, SessionPersistence} from '../persistence';
|
||||
import {ProtobufEvents} from '../services/ProtobufService';
|
||||
import webClient from '../WebClient';
|
||||
import {WebSocketConnectReason} from "../services/WebSocketService";
|
||||
|
||||
export const SessionEvents: ProtobufEvents = {
|
||||
'.Event_AddToList.ext': addToList,
|
||||
|
@ -120,9 +121,28 @@ function serverIdentification(info: ServerIdentificationData) {
|
|||
return;
|
||||
}
|
||||
|
||||
switch (webClient.options.reason) {
|
||||
case WebSocketConnectReason.LOGIN:
|
||||
SessionCommands.updateStatus(StatusEnum.LOGGINGIN, 'Logging in...');
|
||||
SessionCommands.login();
|
||||
break;
|
||||
case WebSocketConnectReason.REGISTER:
|
||||
SessionCommands.updateStatus(StatusEnum.REGISTERING, 'Registering...');
|
||||
SessionCommands.register();
|
||||
break;
|
||||
case WebSocketConnectReason.ACTIVATE_ACCOUNT:
|
||||
SessionCommands.updateStatus(StatusEnum.ACTIVATING_ACCOUNT, 'Activating account...');
|
||||
SessionCommands.activateAccount();
|
||||
break;
|
||||
case WebSocketConnectReason.RECOVER_PASSWORD:
|
||||
console.log('ServerIdentificationData.recoverPassword');
|
||||
break;
|
||||
default:
|
||||
console.error("Undefined type", webClient.options.reason);
|
||||
break;
|
||||
}
|
||||
|
||||
SessionPersistence.updateInfo(serverName, serverVersion);
|
||||
SessionCommands.updateStatus(StatusEnum.LOGGINGIN, 'Logging in...');
|
||||
SessionCommands.login();
|
||||
}
|
||||
|
||||
function serverMessage({ message }: ServerMessageData) {
|
||||
|
|
|
@ -72,4 +72,12 @@ export class SessionPersistence {
|
|||
static serverMessage(message: string) {
|
||||
ServerDispatch.serverMessage(sanitizeHtml(message));
|
||||
}
|
||||
|
||||
static accountAwaitingActivation() {
|
||||
console.log("Open Modal for Activation Code input");
|
||||
}
|
||||
|
||||
static accountActivationFailed() {
|
||||
console.log("Account activation failed, show an action here");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,15 @@ export interface WebSocketOptions {
|
|||
pass: string;
|
||||
autojoinrooms: boolean;
|
||||
keepalive: number;
|
||||
clientid: string;
|
||||
reason: WebSocketConnectReason;
|
||||
}
|
||||
|
||||
export enum WebSocketConnectReason {
|
||||
LOGIN,
|
||||
REGISTER,
|
||||
ACTIVATE_ACCOUNT,
|
||||
RECOVER_PASSWORD,
|
||||
}
|
||||
|
||||
export class WebSocketService {
|
||||
|
|
|
@ -43,4 +43,21 @@ export default class NormalizeService {
|
|||
message.message = `${name}: ${message.message}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Banned reason string is not being exposed by the server
|
||||
static normalizeBannedUserError(reasonStr: string, endTime: number): string {
|
||||
let error;
|
||||
|
||||
if (endTime) {
|
||||
error = 'You are banned until ' + new Date(endTime).toString();
|
||||
} else {
|
||||
error = 'You are permanently banned';
|
||||
}
|
||||
|
||||
if (reasonStr) {
|
||||
error += '\n\n' + reasonStr;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue