Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Dockerfile.ui
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ COPY cvat-core/ /tmp/cvat-core/
COPY cvat-canvas3d/ /tmp/cvat-canvas3d/
COPY cvat-canvas/ /tmp/cvat-canvas/
COPY cvat-ui/ /tmp/cvat-ui/

ARG infura_id
ARG web3_network
ENV INFURA_ID=$infura_id
ENV WEB3_NETWORK=$web3_network

RUN npm run build

FROM nginx:stable-alpine
Expand Down
8 changes: 0 additions & 8 deletions cvat-core/src/api-implementation.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,6 @@
await serverProxy.server.changePassword(oldPassword, newPassword1, newPassword2);
};

cvat.server.requestPasswordReset.implementation = async (email) => {
await serverProxy.server.requestPasswordReset(email);
};

cvat.server.resetPassword.implementation = async (newPassword1, newPassword2, uid, token) => {
await serverProxy.server.resetPassword(newPassword1, newPassword2, uid, token);
};

cvat.server.authorized.implementation = async () => {
const result = await serverProxy.server.authorized();
return result;
Expand Down
41 changes: 2 additions & 39 deletions cvat-core/src/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,18 +123,16 @@ function build() {
* @param {string} lastName A last name for the new account
* @param {string} email A email address for the new account
* @param {string} walletAddress A wallet address for the new account
* @param {string} signedEmail The signed email password for the new account
* @param {string} signedEmail The signed email for the new account
* @param {Object} userConfirmations An user confirmations of terms of use if needed
* @returns {Object} response data
* @throws {module:API.cvat.exceptions.PluginError}
* @throws {module:API.cvat.exceptions.ServerError}
*/
async register(username, firstName, lastName, email, walletAddress, signedEmail, userConfirmations) {
async register(username, email, walletAddress, signedEmail, userConfirmations) {
const result = await PluginRegistry.apiWrapper(
cvat.server.register,
username,
firstName,
lastName,
email,
walletAddress,
signedEmail,
Expand Down Expand Up @@ -189,41 +187,6 @@ function build() {
);
return result;
},
/**
* Method allows to reset user password
* @method requestPasswordReset
* @async
* @memberof module:API.cvat.server
* @param {string} email A email address for the account
* @throws {module:API.cvat.exceptions.PluginError}
* @throws {module:API.cvat.exceptions.ServerError}
*/
async requestPasswordReset(email) {
const result = await PluginRegistry.apiWrapper(cvat.server.requestPasswordReset, email);
return result;
},
/**
* Method allows to confirm reset user password
* @method resetPassword
* @async
* @memberof module:API.cvat.server
* @param {string} newPassword1 New password for the account
* @param {string} newPassword2 Confirmation password for the account
* @param {string} uid User id
* @param {string} token Request authentication token
* @throws {module:API.cvat.exceptions.PluginError}
* @throws {module:API.cvat.exceptions.ServerError}
*/
async resetPassword(newPassword1, newPassword2, uid, token) {
const result = await PluginRegistry.apiWrapper(
cvat.server.resetPassword,
newPassword1,
newPassword2,
uid,
token,
);
return result;
},
/**
* Method allows to know whether you are authorized on the server
* @method authorized
Expand Down
41 changes: 1 addition & 40 deletions cvat-core/src/server-proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,13 +195,11 @@
return response.data;
}

async function register(username, firstName, lastName, email, walletAddress, signedEmail, confirmations) {
async function register(username, email, walletAddress, signedEmail, confirmations) {
let response = null;
try {
const data = JSON.stringify({
username,
first_name: firstName,
last_name: lastName,
email,
wallet_address: walletAddress,
signed_email: signedEmail,
Expand Down Expand Up @@ -282,41 +280,6 @@
}
}

async function requestPasswordReset(email) {
try {
const data = JSON.stringify({
email,
});
await Axios.post(`${config.backendAPI}/auth/password/reset`, data, {
proxy: config.proxy,
headers: {
'Content-Type': 'application/json',
},
});
} catch (errorData) {
throw generateError(errorData);
}
}

async function resetPassword(newPassword1, newPassword2, uid, _token) {
try {
const data = JSON.stringify({
new_password1: newPassword1,
new_password2: newPassword2,
uid,
token: _token,
});
await Axios.post(`${config.backendAPI}/auth/password/reset/confirm`, data, {
proxy: config.proxy,
headers: {
'Content-Type': 'application/json',
},
});
} catch (errorData) {
throw generateError(errorData);
}
}

async function authorized() {
try {
await module.exports.users.self();
Expand Down Expand Up @@ -1182,8 +1145,6 @@
login,
logout,
changePassword,
requestPasswordReset,
resetPassword,
authorized,
register,
request: serverRequest,
Expand Down
1 change: 1 addition & 0 deletions cvat-ui/package-lock.json

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

74 changes: 10 additions & 64 deletions cvat-ui/src/actions/auth-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
// SPDX-License-Identifier: MIT

import { ActionUnion, createAction, ThunkAction } from 'utils/redux';
import { UserConfirmation } from 'components/register-page/register-form';
import getCore from 'cvat-core-wrapper';
import isReachable from 'utils/url-checker';
import connectWallet from 'utils/web3wallets';
Expand All @@ -26,12 +25,6 @@ export enum AuthActionTypes {
CHANGE_PASSWORD_SUCCESS = 'CHANGE_PASSWORD_SUCCESS',
CHANGE_PASSWORD_FAILED = 'CHANGE_PASSWORD_FAILED',
SWITCH_CHANGE_PASSWORD_DIALOG = 'SWITCH_CHANGE_PASSWORD_DIALOG',
REQUEST_PASSWORD_RESET = 'REQUEST_PASSWORD_RESET',
REQUEST_PASSWORD_RESET_SUCCESS = 'REQUEST_PASSWORD_RESET_SUCCESS',
REQUEST_PASSWORD_RESET_FAILED = 'REQUEST_PASSWORD_RESET_FAILED',
RESET_PASSWORD = 'RESET_PASSWORD_CONFIRM',
RESET_PASSWORD_SUCCESS = 'RESET_PASSWORD_CONFIRM_SUCCESS',
RESET_PASSWORD_FAILED = 'RESET_PASSWORD_CONFIRM_FAILED',
LOAD_AUTH_ACTIONS = 'LOAD_AUTH_ACTIONS',
LOAD_AUTH_ACTIONS_SUCCESS = 'LOAD_AUTH_ACTIONS_SUCCESS',
LOAD_AUTH_ACTIONS_FAILED = 'LOAD_AUTH_ACTIONS_FAILED',
Expand All @@ -54,43 +47,25 @@ export const authActions = {
changePasswordFailed: (error: any) => createAction(AuthActionTypes.CHANGE_PASSWORD_FAILED, { error }),
switchChangePasswordDialog: (showChangePasswordDialog: boolean) =>
createAction(AuthActionTypes.SWITCH_CHANGE_PASSWORD_DIALOG, { showChangePasswordDialog }),
requestPasswordReset: () => createAction(AuthActionTypes.REQUEST_PASSWORD_RESET),
requestPasswordResetSuccess: () => createAction(AuthActionTypes.REQUEST_PASSWORD_RESET_SUCCESS),
requestPasswordResetFailed: (error: any) => createAction(AuthActionTypes.REQUEST_PASSWORD_RESET_FAILED, { error }),
resetPassword: () => createAction(AuthActionTypes.RESET_PASSWORD),
resetPasswordSuccess: () => createAction(AuthActionTypes.RESET_PASSWORD_SUCCESS),
resetPasswordFailed: (error: any) => createAction(AuthActionTypes.RESET_PASSWORD_FAILED, { error }),
loadServerAuthActions: () => createAction(AuthActionTypes.LOAD_AUTH_ACTIONS),
loadServerAuthActionsSuccess: (allowChangePassword: boolean, allowResetPassword: boolean) =>
loadServerAuthActionsSuccess: (allowChangePassword: boolean) =>
createAction(AuthActionTypes.LOAD_AUTH_ACTIONS_SUCCESS, {
allowChangePassword,
allowResetPassword,
}),
loadServerAuthActionsFailed: (error: any) => createAction(AuthActionTypes.LOAD_AUTH_ACTIONS_FAILED, { error }),
};

export type AuthActions = ActionUnion<typeof authActions>;

export const registerAsync = (
username: string,
firstName: string,
lastName: string,
email: string,
confirmations: UserConfirmation[],
): ThunkAction => async (dispatch) => {
export const registerAsync = (email: string, address: string, signedEmail: string): ThunkAction => async (dispatch) => {
dispatch(authActions.register());

try {
const { address, signedEmail } = await connectWallet(email);

const user = await cvat.server.register(
username,
firstName,
lastName,
email, // temp username
email,
address,
signedEmail,
confirmations,
);

dispatch(authActions.registerSuccess(user));
Expand All @@ -101,17 +76,18 @@ export const registerAsync = (

export const loginAsync = (email: string): ThunkAction => async (dispatch) => {
dispatch(authActions.login());

let address;
let signedEmail;
try {
const { address, signedEmail } = await connectWallet(email);
({ address, signedEmail } = await connectWallet(email));

await cvat.server.login(email, address, signedEmail);

const users = await cvat.users.get({ self: true });

dispatch(authActions.loginSuccess(users[0]));
} catch (error) {
dispatch(authActions.loginFailed(error));
dispatch(registerAsync(email, address, signedEmail));
}
};

Expand Down Expand Up @@ -156,44 +132,14 @@ export const changePasswordAsync = (
}
};

export const requestPasswordResetAsync = (email: string): ThunkAction => async (dispatch) => {
dispatch(authActions.requestPasswordReset());

try {
await cvat.server.requestPasswordReset(email);
dispatch(authActions.requestPasswordResetSuccess());
} catch (error) {
dispatch(authActions.requestPasswordResetFailed(error));
}
};

export const resetPasswordAsync = (
newPassword1: string,
newPassword2: string,
uid: string,
token: string,
): ThunkAction => async (dispatch) => {
dispatch(authActions.resetPassword());

try {
await cvat.server.resetPassword(newPassword1, newPassword2, uid, token);
dispatch(authActions.resetPasswordSuccess());
} catch (error) {
dispatch(authActions.resetPasswordFailed(error));
}
};

export const loadAuthActionsAsync = (): ThunkAction => async (dispatch) => {
dispatch(authActions.loadServerAuthActions());

try {
const promises: Promise<boolean>[] = [
isReachable(`${cvat.config.backendAPI}/auth/password/change`, 'OPTIONS'),
isReachable(`${cvat.config.backendAPI}/auth/password/reset`, 'OPTIONS'),
];
const [allowChangePassword, allowResetPassword] = await Promise.all(promises);
const promises: Promise<boolean>[] = [isReachable(`${cvat.config.backendAPI}/auth/password/change`, 'OPTIONS')];
const [allowChangePassword] = await Promise.all(promises);

dispatch(authActions.loadServerAuthActionsSuccess(allowChangePassword, allowResetPassword));
dispatch(authActions.loadServerAuthActionsSuccess(allowChangePassword));
} catch (error) {
dispatch(authActions.loadServerAuthActionsFailed(error));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
// SPDX-License-Identifier: MIT

import React from 'react';
import Form from 'antd/lib/form';
import Form, { RuleRender, RuleObject } from 'antd/lib/form';
import { LockOutlined } from '@ant-design/icons';
import Button from 'antd/lib/button';
import Input from 'antd/lib/input';

import { validateConfirmation, validatePassword } from 'components/register-page/register-form';
import patterns from 'utils/validation-patterns';

export interface ChangePasswordData {
oldPassword: string;
Expand All @@ -21,6 +21,40 @@ interface Props {
onSubmit(loginData: ChangePasswordData): void;
}

export const validatePassword: RuleRender = (): RuleObject => ({
validator(_: RuleObject, value: string): Promise<void> {
if (!patterns.validatePasswordLength.pattern.test(value)) {
return Promise.reject(new Error(patterns.validatePasswordLength.message));
}

if (!patterns.passwordContainsNumericCharacters.pattern.test(value)) {
return Promise.reject(new Error(patterns.passwordContainsNumericCharacters.message));
}

if (!patterns.passwordContainsUpperCaseCharacter.pattern.test(value)) {
return Promise.reject(new Error(patterns.passwordContainsUpperCaseCharacter.message));
}

if (!patterns.passwordContainsLowerCaseCharacter.pattern.test(value)) {
return Promise.reject(new Error(patterns.passwordContainsLowerCaseCharacter.message));
}

return Promise.resolve();
},
});

export const validateConfirmation: (firstFieldName: string) => RuleRender = (firstFieldName: string): RuleRender => ({
getFieldValue,
}): RuleObject => ({
validator(_: RuleObject, value: string): Promise<void> {
if (value && value !== getFieldValue(firstFieldName)) {
return Promise.reject(new Error('Two passwords that you enter is inconsistent!'));
}

return Promise.resolve();
},
});

function ChangePasswordFormComponent({ fetching, onSubmit }: Props): JSX.Element {
return (
<Form onFinish={onSubmit} className='change-password-form'>
Expand Down
10 changes: 0 additions & 10 deletions cvat-ui/src/components/cvat-app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ import 'antd/dist/antd.css';

import GlobalErrorBoundary from 'components/global-error-boundary/global-error-boundary';
import Header from 'components/header/header';
import ResetPasswordPageConfirmComponent from 'components/reset-password-confirm-page/reset-password-confirm-page';
import ResetPasswordPageComponent from 'components/reset-password-page/reset-password-page';
import ShortcutsDialog from 'components/shortcuts-dialog/shortcuts-dialog';
import ProjectsPageComponent from 'components/projects-page/projects-page';
import CreateProjectPageComponent from 'components/create-project-page/create-project-page';
Expand All @@ -28,7 +26,6 @@ import TaskPageContainer from 'containers/task-page/task-page';
import ModelsPageContainer from 'containers/models-page/models-page';
import AnnotationPageContainer from 'containers/annotation-page/annotation-page';
import LoginPageContainer from 'containers/login-page/login-page';
import RegisterPageContainer from 'containers/register-page/register-page';
import getCore from 'cvat-core-wrapper';
import GlobalHotKeys, { KeyMap } from 'utils/mousetrap-react';
import { NotificationsState } from 'reducers/interfaces';
Expand Down Expand Up @@ -337,19 +334,12 @@ class CVATApplication extends React.PureComponent<CVATAppProps & RouteComponentP
return (
<GlobalErrorBoundary>
<Switch>
<Route exact path='/auth/register' component={RegisterPageContainer} />
<Route exact path='/auth/login' component={LoginPageContainer} />
<Route
exact
path='/auth/login-with-token/:sessionId/:token'
component={LoginWithTokenComponent}
/>
<Route exact path='/auth/password/reset' component={ResetPasswordPageComponent} />
<Route
exact
path='/auth/password/reset/confirm'
component={ResetPasswordPageConfirmComponent}
/>
<Redirect
to={location.pathname.length > 1 ? `/auth/login/?next=${location.pathname}` : '/auth/login'}
/>
Expand Down
Loading