Merge branch 'feature/virtual-rooms-1.2' of github.com:ONLYOFFICE/AppServer into feature/virtual-rooms-1.2

This commit is contained in:
Nikita Gopienko 2022-04-14 15:11:16 +03:00
commit 332df8a5cd
14 changed files with 262 additions and 123 deletions

View File

@ -42,10 +42,8 @@ class TfaStore {
this.backupCodes = codes;
};
getTfaConfirmLink = async (res) => {
if (res) {
return await api.settings.getTfaConfirmLink();
}
getTfaConfirmLink = async () => {
return await api.settings.getTfaConfirmLink();
};
getSecretKeyAndQR = async (confirmKey) => {

View File

@ -47,6 +47,7 @@ class SaveCancelButtons extends React.Component {
isFirstWelcomePageSettings,
className,
id,
isSaving,
} = this.props;
const cancelButtonDisabled =
@ -69,11 +70,12 @@ class SaveCancelButtons extends React.Component {
onClick={onSaveClick}
label={saveButtonLabel}
minwidth={displaySettings && "auto"}
isLoading={isSaving}
/>
<Button
className="cancel-button"
size="normal"
isDisabled={cancelButtonDisabled}
isDisabled={cancelButtonDisabled || isSaving}
onClick={onCancelClick}
label={cancelButtonLabel}
minwidth={displaySettings && "auto"}
@ -109,6 +111,7 @@ SaveCancelButtons.propTypes = {
hasScroll: PropTypes.bool,
minwidth: PropTypes.string,
isFirstWelcomePageSettings: PropTypes.string,
isSaving: PropTypes.bool,
};
SaveCancelButtons.defaultProps = {

View File

@ -34,7 +34,8 @@
"test:sequential": "run-s -c test:chromium:sequential test:firefox:sequential test:webkit:sequential && yarn test:parse-xml",
"test:model": "run-s -c test:chromium:model test:firefox:model test:webkit:model && yarn test:parse-xml",
"test:parse-xml": "node tests/helpers/parserXML.js",
"test:ui": "npx codecept-ui"
"test:ui": "npx codecept-ui",
"test:ui:mobile": "cross-env DEVICE_TYPE=mobile npx codecept-ui"
},
"dependencies": {
"firebase": "^8.10.0",

View File

@ -35,7 +35,15 @@ const MainContainer = styled.div`
`;
const PasswordStrength = (props) => {
const { t, history, setPortalPasswordSettings, passwordSettings } = props;
const {
t,
history,
setPortalPasswordSettings,
passwordSettings,
initSettings,
isInit,
} = props;
const [passwordLen, setPasswordLen] = useState(8);
const [useUpperCase, setUseUpperCase] = useState(false);
const [useDigits, setUseDigits] = useState(false);
@ -43,22 +51,18 @@ const PasswordStrength = (props) => {
const [showReminder, setShowReminder] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [isSaving, setIsSaving] = useState(false);
const getSettings = () => {
const currentSettings = getFromSessionStorage("currentPasswordSettings");
const defaultSettings = getFromSessionStorage("defaultPasswordSettings");
if (defaultSettings) {
saveToSessionStorage("defaultPasswordSettings", defaultSettings);
} else {
const defaultData = {
minLength: passwordSettings.minLength,
upperCase: passwordSettings.upperCase,
digits: passwordSettings.digits,
specSymbols: passwordSettings.specSymbols,
};
saveToSessionStorage("defaultPasswordSettings", defaultData);
}
const defaultData = {
minLength: passwordSettings.minLength,
upperCase: passwordSettings.upperCase,
digits: passwordSettings.digits,
specSymbols: passwordSettings.specSymbols,
};
saveToSessionStorage("defaultPasswordSettings", defaultData);
if (currentSettings) {
setPasswordLen(currentSettings.minLength);
@ -71,15 +75,21 @@ const PasswordStrength = (props) => {
setUseDigits(passwordSettings.digits);
setUseSpecialSymbols(passwordSettings.specSymbols);
}
setIsLoading(true);
};
useEffect(() => {
checkWidth();
getSettings();
window.addEventListener("resize", checkWidth);
if (!isInit) initSettings().then(() => setIsLoading(true));
else setIsLoading(true);
return () => window.removeEventListener("resize", checkWidth);
}, []);
useEffect(() => {
if (!isInit) return;
getSettings();
}, [isLoading]);
useEffect(() => {
@ -93,10 +103,11 @@ const PasswordStrength = (props) => {
specSymbols: useSpecialSymbols,
};
saveToSessionStorage("currentPasswordSettings", newSettings);
if (isEqual(defaultSettings, newSettings)) {
setShowReminder(false);
} else {
saveToSessionStorage("currentPasswordSettings", newSettings);
setShowReminder(true);
}
}, [passwordLen, useUpperCase, useDigits, useSpecialSymbols]);
@ -125,26 +136,31 @@ const PasswordStrength = (props) => {
}
};
const onSaveClick = () => {
setPortalPasswordSettings(
passwordLen,
useUpperCase,
useDigits,
useSpecialSymbols
)
.then(() => {
setShowReminder(false);
const data = {
minLength: passwordLen,
upperCase: useUpperCase,
digits: useDigits,
specSymbols: useSpecialSymbols,
};
saveToSessionStorage("currentPasswordSettings", data);
saveToSessionStorage("defaultPasswordSettings", data);
toastr.success(t("SuccessfullySaveSettingsMessage"));
})
.catch((e) => toastr.error(e));
const onSaveClick = async () => {
setIsSaving(true);
try {
const data = {
minLength: passwordLen,
upperCase: useUpperCase,
digits: useDigits,
specSymbols: useSpecialSymbols,
};
await setPortalPasswordSettings(
passwordLen,
useUpperCase,
useDigits,
useSpecialSymbols
);
setShowReminder(false);
saveToSessionStorage("currentPasswordSettings", data);
saveToSessionStorage("defaultPasswordSettings", data);
toastr.success(t("SuccessfullySaveSettingsMessage"));
} catch (error) {
toastr.error(e);
}
setIsSaving(false);
};
const onCancelClick = () => {
@ -227,17 +243,21 @@ const PasswordStrength = (props) => {
cancelButtonLabel={t("Common:CancelButton")}
displaySettings={true}
hasScroll={false}
isSaving={isSaving}
/>
</MainContainer>
);
};
export default inject(({ auth }) => {
export default inject(({ auth, setup }) => {
const { setPortalPasswordSettings, passwordSettings } = auth.settingsStore;
const { initSettings, isInit } = setup;
return {
setPortalPasswordSettings,
passwordSettings,
initSettings,
isInit,
};
})(
withTranslation(["Settings", "Common"])(

View File

@ -22,24 +22,20 @@ const MainContainer = styled.div`
`;
const TwoFactorAuth = (props) => {
const { t, history } = props;
const { t, history, initSettings, isInit, setIsInit } = props;
const [type, setType] = useState("none");
const [smsDisabled, setSmsDisabled] = useState(false);
const [appDisabled, setAppDisabled] = useState(false);
const [showReminder, setShowReminder] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [isSaving, setIsSaving] = useState(false);
const getSettings = () => {
const { tfaSettings, smsAvailable, appAvailable } = props;
const currentSettings = getFromSessionStorage("currentTfaSettings");
const defaultSettings = getFromSessionStorage("defaultTfaSettings");
if (defaultSettings) {
saveToSessionStorage("defaultTfaSettings", defaultSettings);
} else {
saveToSessionStorage("defaultTfaSettings", tfaSettings);
}
saveToSessionStorage("defaultTfaSettings", tfaSettings);
if (currentSettings) {
setType(currentSettings);
@ -49,14 +45,21 @@ const TwoFactorAuth = (props) => {
setSmsDisabled(smsAvailable);
setAppDisabled(appAvailable);
setIsLoading(true);
};
useEffect(() => {
checkWidth();
getSettings();
window.addEventListener("resize", checkWidth);
if (!isInit) initSettings().then(() => setIsLoading(true));
else setIsLoading(true);
return () => window.removeEventListener("resize", checkWidth);
}, []);
useEffect(() => {
if (!isInit) return;
getSettings();
}, [isLoading]);
useEffect(() => {
@ -84,21 +87,27 @@ const TwoFactorAuth = (props) => {
}
};
const onSaveClick = () => {
const onSaveClick = async () => {
const { t, setTfaSettings, getTfaConfirmLink, history } = props;
setTfaSettings(type).then((res) => {
toastr.success(t("SuccessfullySaveSettingsMessage"));
if (type !== "none") {
getTfaConfirmLink(res).then((link) =>
history.push(link.replace(window.location.origin, ""))
);
}
setType(type);
saveToSessionStorage("defaultTfaSettings", type);
setIsSaving(true);
try {
await setTfaSettings(type);
toastr.success(t("SuccessfullySaveSettingsMessage"));
saveToSessionStorage("defaultTfaSettings", type);
setIsSaving(false);
setShowReminder(false);
});
if (type !== "none") {
setIsInit(false);
const link = await getTfaConfirmLink();
history.push(link.replace(window.location.origin, ""));
}
} catch (error) {
toastr.error(error);
}
};
const onCancelClick = () => {
@ -159,12 +168,13 @@ const TwoFactorAuth = (props) => {
cancelButtonLabel={t("Common:CancelButton")}
displaySettings={true}
hasScroll={false}
isSaving={isSaving}
/>
</MainContainer>
);
};
export default inject(({ auth }) => {
export default inject(({ auth, setup }) => {
const {
setTfaSettings,
getTfaConfirmLink,
@ -173,12 +183,17 @@ export default inject(({ auth }) => {
appAvailable,
} = auth.tfaStore;
const { isInit, initSettings, setIsInit } = setup;
return {
setTfaSettings,
getTfaConfirmLink,
tfaSettings,
smsAvailable,
appAvailable,
isInit,
initSettings,
setIsInit,
};
})(
withTranslation(["Settings", "Common"])(withRouter(observer(TwoFactorAuth)))

View File

@ -46,17 +46,12 @@ const TrustedMail = (props) => {
const getSettings = () => {
const currentSettings = getFromSessionStorage("currentTrustedMailSettings");
const defaultSettings = getFromSessionStorage("defaultTrustedMailSettings");
if (defaultSettings) {
saveToSessionStorage("defaultTrustedMailSettings", defaultSettings);
} else {
const defaultData = {
type: String(trustedDomainsType),
domains: trustedDomains,
};
saveToSessionStorage("defaultTrustedMailSettings", defaultData);
}
const defaultData = {
type: String(trustedDomainsType),
domains: trustedDomains,
};
saveToSessionStorage("defaultTrustedMailSettings", defaultData);
if (currentSettings) {
setType(currentSettings.type);
@ -216,6 +211,7 @@ const TrustedMail = (props) => {
cancelButtonLabel={t("Common:CancelButton")}
displaySettings={true}
hasScroll={false}
isSaving={isSaving}
/>
</MainContainer>
);

View File

@ -65,6 +65,10 @@ class SettingsSetupStore {
}
};
setIsInit = (isInit) => {
this.isInit = isInit;
};
setIsLoading = (isLoading) => {
this.security.accessRight.isLoading = isLoading;
};

View File

@ -76,32 +76,6 @@ Scenario("Tfa activation success", async ({ I }) => {
I.see("Documents");
});
Scenario("Tfa on from settings", async ({ I }) => {
I.mockEndpoint(Endpoints.common, "common");
I.mockEndpoint(Endpoints.settings, "settings");
I.mockEndpoint(Endpoints.build, "build");
I.mockEndpoint(Endpoints.info, "infoSettings");
I.mockEndpoint(Endpoints.self, "selfSettings");
I.mockEndpoint(Endpoints.tfaapp, "tfaapp");
I.mockEndpoint(Endpoints.tfaconfirm, "tfaconfirm");
I.mockEndpoint(Endpoints.confirm, "confirm");
I.mockEndpoint(Endpoints.setup, "setup");
I.amOnPage("/settings/security/access-portal/tfa");
I.see("Two-factor authentication");
I.click({
react: "RadioButton",
props: {
value: "app",
},
});
I.click("Save");
I.see("Configure your authenticator application");
});
Scenario("Profile remove success", async ({ I }) => {
I.mockEndpoint(Endpoints.confirm, "confirm");
@ -741,12 +715,16 @@ Scenario(
}
);
// SECURITY SETTINGS TESTS
Scenario("Setting password strength change test success", async ({ I }) => {
I.mockEndpoint(Endpoints.settings, "settings");
I.mockEndpoint(Endpoints.password, "password");
I.mockEndpoint(Endpoints.build, "build");
I.mockEndpoint(Endpoints.info, "infoSettings");
I.mockEndpoint(Endpoints.self, "selfSettings");
I.mockEndpoint(Endpoints.info, "infoSettings");
I.mockEndpoint(Endpoints.build, "build");
I.mockEndpoint(Endpoints.settings, "settingsCustomization");
I.mockEndpoint(Endpoints.common, "common");
I.mockEndpoint(Endpoints.password, "password");
I.mockEndpoint(Endpoints.tfaapp, "tfaapp");
if (deviceType === "mobile") {
I.amOnPage("/settings/security/access-portal/password");
@ -768,11 +746,13 @@ Scenario("Setting password strength change test success", async ({ I }) => {
});
Scenario("Setting password strength change test error", async ({ I }) => {
I.mockEndpoint(Endpoints.settings, "settings");
I.mockEndpoint(Endpoints.password, "password");
I.mockEndpoint(Endpoints.build, "build");
I.mockEndpoint(Endpoints.info, "infoSettings");
I.mockEndpoint(Endpoints.self, "selfSettings");
I.mockEndpoint(Endpoints.info, "infoSettings");
I.mockEndpoint(Endpoints.build, "build");
I.mockEndpoint(Endpoints.settings, "settingsCustomization");
I.mockEndpoint(Endpoints.common, "common");
I.mockEndpoint(Endpoints.password, "password");
I.mockEndpoint(Endpoints.tfaapp, "tfaapp");
if (deviceType === "mobile") {
I.amOnPage("/settings/security/access-portal/password");
@ -796,12 +776,102 @@ Scenario("Setting password strength change test error", async ({ I }) => {
}
});
Scenario("Tfa on from settings", async ({ I }) => {
I.mockEndpoint(Endpoints.self, "selfSettings");
I.mockEndpoint(Endpoints.info, "infoSettings");
I.mockEndpoint(Endpoints.build, "build");
I.mockEndpoint(Endpoints.settings, "settingsCustomization");
I.mockEndpoint(Endpoints.common, "common");
I.mockEndpoint(Endpoints.password, "password");
I.mockEndpoint(Endpoints.tfaapp, "tfaapp");
I.mockEndpoint(Endpoints.tfaconfirm, "tfaconfirm");
I.mockEndpoint(Endpoints.confirm, "confirm");
I.mockEndpoint(Endpoints.setup, "setup");
if (deviceType === "mobile") {
I.amOnPage("/settings/security/access-portal/tfa");
I.see("Two-factor authentication");
I.click({
react: "RadioButton",
props: {
value: "app",
},
});
I.click("Save");
I.see("Configure your authenticator application");
}
});
Scenario("Tfa on from settings custom scenario", async ({ I }) => {
I.mockEndpoint(Endpoints.self, "selfSettings");
I.mockEndpoint(Endpoints.info, "infoSettings");
I.mockEndpoint(Endpoints.build, "build");
I.mockEndpoint(Endpoints.settings, "settingsCustomization");
I.mockEndpoint(Endpoints.common, "common");
I.mockEndpoint(Endpoints.password, "password");
I.mockEndpoint(Endpoints.tfaapp, "tfaapp");
I.mockEndpoint(Endpoints.tfaconfirm, "tfaconfirm");
I.mockEndpoint(Endpoints.confirm, "confirm");
I.mockEndpoint(Endpoints.setup, "setup");
I.mockEndpoint(Endpoints.providers, "providers");
I.mockEndpoint(Endpoints.capabilities, "capabilities");
I.mockEndpoint(Endpoints.auth, "auth");
if (deviceType === "mobile") {
I.amOnPage("/settings/security/access-portal/tfa");
I.see("Two-factor authentication");
I.click({
react: "RadioButton",
props: {
value: "app",
},
});
I.click("Save");
I.see("Configure your authenticator application");
I.click({
react: "Avatar",
});
I.see("Settings");
I.click("Settings");
I.see("Common");
I.click({
react: "Avatar",
});
I.click("Sign Out");
I.see("Cloud Office Applications");
I.fillField("login", "test@example.com");
I.fillField("password", "12345678");
I.click({
react: "Button",
props: {
className: "login-button",
type: "page",
},
});
I.wait(2);
I.see("Configure your authenticator application");
}
});
Scenario("Trusted mail settings change test success", async ({ I }) => {
I.mockEndpoint(Endpoints.settings, "settings");
I.mockEndpoint(Endpoints.build, "build");
I.mockEndpoint(Endpoints.info, "infoSettings");
I.mockEndpoint(Endpoints.self, "selfSettings");
I.mockEndpoint(Endpoints.common, "common");
I.mockEndpoint(Endpoints.password, "password");
I.mockEndpoint(Endpoints.tfaapp, "tfaapp");
I.mockEndpoint(Endpoints.maildomainsettings, "maildomainsettings");
if (deviceType === "mobile") {
@ -810,16 +880,18 @@ Scenario("Trusted mail settings change test success", async ({ I }) => {
I.see("Trusted mail domain settings");
I.click({
react: "Checkbox",
react: "RadioButton",
props: {
value: "1",
},
});
I.see("You have unsaved changes");
I.see("Add trusted domain");
I.click("Add trusted domain");
I.see({ react: "TextInput" });
I.seeElement("#domain-input-0");
I.fillField("#domain-input-0", "test.com");
I.click("Save");
@ -835,6 +907,8 @@ Scenario("Trusted mail settings change test error", async ({ I }) => {
I.mockEndpoint(Endpoints.info, "infoSettings");
I.mockEndpoint(Endpoints.self, "selfSettings");
I.mockEndpoint(Endpoints.common, "common");
I.mockEndpoint(Endpoints.password, "password");
I.mockEndpoint(Endpoints.tfaapp, "tfaapp");
I.mockEndpoint(Endpoints.maildomainsettings, "maildomainsettings");
if (deviceType === "mobile") {
@ -843,16 +917,18 @@ Scenario("Trusted mail settings change test error", async ({ I }) => {
I.see("Trusted mail domain settings");
I.click({
react: "Checkbox",
react: "RadioButton",
props: {
value: "1",
},
});
I.see("You have unsaved changes");
I.see("Add trusted domain");
I.click("Add trusted domain");
I.see({ react: "TextInput" });
I.seeElement("#domain-input-0");
I.fillField("#domain-input-0", "test");
I.click("Save");
@ -865,9 +941,11 @@ Scenario("Trusted mail settings change test error", async ({ I }) => {
Scenario("Trusted mail settings change test server error", async ({ I }) => {
I.mockEndpoint(Endpoints.settings, "settings");
I.mockEndpoint(Endpoints.build, "build");
I.mockEndpoint(Endpoints.info, "info");
I.mockEndpoint(Endpoints.self, "self");
I.mockEndpoint(Endpoints.info, "infoSettings");
I.mockEndpoint(Endpoints.self, "selfSettings");
I.mockEndpoint(Endpoints.common, "common");
I.mockEndpoint(Endpoints.password, "password");
I.mockEndpoint(Endpoints.tfaapp, "tfaapp");
I.mockEndpoint(Endpoints.maildomainsettings, "maildomainsettingsError");
if (deviceType === "mobile") {
@ -876,17 +954,19 @@ Scenario("Trusted mail settings change test server error", async ({ I }) => {
I.see("Trusted mail domain settings");
I.click({
react: "Checkbox",
react: "RadioButton",
props: {
value: "1",
},
});
I.see("You have unsaved changes");
I.see("Add trusted domain");
I.click("Add trusted domain");
I.see({ react: "TextInput" });
I.fillField("#domain-input-0", "test");
I.seeElement("#domain-input-0");
I.fillField("#domain-input-0", "test.com");
I.click("Save");

View File

@ -141,4 +141,10 @@ module.exports = class Endpoints {
method: "POST",
baseDir: "settings",
};
static auth = {
url: ["http://localhost:8092/api/2.0/authentication.json"],
method: "POST",
baseDir: "auth",
};
};

View File

@ -0,0 +1,11 @@
{
"count": 1,
"response": {
"expires": "0001-01-01T00:00:00",
"sms": false,
"tfa": true,
"confirmUrl": "http://localhost:8092/confirm/TfaActivation"
},
"status": 0,
"statusCode": 200
}

View File

@ -1,6 +1,5 @@
{
"count": 1,
"response": "Error",
"status": 0,
"error": { "message": "Request failed with status code 400", "hresult": 0 },
"status": 1,
"statusCode": 400
}

View File

@ -1,8 +1,8 @@
{
"count": 1,
"response": {
"id": "EXAMPLEID",
"minLength": 8,
"id": "6dde41a5-4c75-11ec-98de-089798855014",
"minLength": 10,
"upperCase": false,
"digits": false,
"specSymbols": false

View File

@ -20,6 +20,7 @@
"utcHoursOffset": 0,
"greetingSettings": "Web Office",
"ownerId": "00000000-0000-0000-0000-000000000000",
"nameSchemaId": "Common",
"enabledJoin": true,
"enableAdmMess": true,
"thirdpartyEnable": true,

View File

@ -11,6 +11,11 @@
"ownerId": "6dde41a5-4c75-11ec-98de-089798855014",
"nameSchemaId": "Common",
"personal": false,
"passwordHash": {
"size": 256,
"iterations": 100000,
"salt": "0a783fef249b0cfa2b1ddc3825bf9a5c9c869bf65a4a45cbd5a0c93b16b5a47e"
},
"firebase": {
"apiKey": "",
"authDomain": "",