Skip to content

Commit f377dd9

Browse files
Merge branch 'dev' into 'main'
Update 2 files See merge request locker/web-selfhosted!127
2 parents 7cf4d4c + e81ddec commit f377dd9

38 files changed

Lines changed: 1217 additions & 236 deletions

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"version": "1.0.0",
44
"private": true,
55
"dependencies": {
6-
"@lockerpm/client-service": "^2.0.0",
6+
"@lockerpm/client-service": "^2.1.0",
77
"@lockerpm/design": "^1.0.17",
88
"apexcharts": "^3.44.2",
99
"axios": "^1.15.0",

src/components/common/NoticeCards.jsx

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import React, { useEffect, useMemo } from 'react';
1+
import React, { useEffect, useMemo, useState } from 'react';
22
import { useSelector } from 'react-redux';
33

44
import noticeCardComponents from '../notice-card';
5+
import modalsComponents from '../modals';
56

67
import global from '../../config/global';
78
import storeActions from '../../store/actions';
@@ -12,21 +13,38 @@ function NoticeCards(props) {
1213
EmergencyAccessInvitations
1314
} = noticeCardComponents;
1415

16+
const {
17+
EncryptionUpdateModal
18+
} = modalsComponents
19+
1520
const { className } = props;
1621

1722
const myShares = useSelector((state) => state.share.myShares);
1823
const confirmMyShareVisible = useSelector((state) => state.notice.confirmMyShareVisible);
24+
const userInfo = useSelector((state) => state.auth.userInfo);
25+
26+
const [encryptionUpdateVisible, setEncryptionUpdateVisible] = useState(false);
1927

2028
const isConfirmMyShare = useMemo(() => {
2129
return !!myShares.find((s) => {
2230
return s.members.filter((m) => m.status === global.constants.STATUS.ACCEPTED).length > 0
2331
})
2432
}, [myShares])
2533

34+
const isEncryptionUpdate = useMemo(() => {
35+
return userInfo.kdf === global.constants.CORE_JS_INFO.KDF && userInfo.kdf_iterations < global.constants.CORE_JS_INFO.KDF_ITERATIONS
36+
}, [userInfo])
37+
2638
useEffect(() => {
2739
initNoticeCards();
2840
}, [isConfirmMyShare]);
2941

42+
useEffect(() => {
43+
if (isEncryptionUpdate) {
44+
setEncryptionUpdateVisible(true)
45+
}
46+
}, [isEncryptionUpdate])
47+
3048
const initNoticeCards = async () => {
3149
global.store.dispatch(storeActions.updateConfirmMyShareVisible(isConfirmMyShare))
3250
}
@@ -39,6 +57,12 @@ function NoticeCards(props) {
3957
{
4058
!confirmMyShareVisible && <EmergencyAccessInvitations />
4159
}
60+
{
61+
isEncryptionUpdate && <EncryptionUpdateModal
62+
visible={encryptionUpdateVisible}
63+
onClose={() => setEncryptionUpdateVisible(false)}
64+
/>
65+
}
4266
</div>
4367
);
4468
}

src/components/forms/Passkey.jsx

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const PasskeyForm = (props) => {
1616
changing = false,
1717
userInfo = {},
1818
isAddKey = false,
19+
isNewKey = false,
1920
accessToken = null,
2021
onConfirm = () => { },
2122
} = props;
@@ -55,23 +56,40 @@ const PasskeyForm = (props) => {
5556
setCallingAPI(false);
5657
}
5758

59+
const setNewPwl = async (values) => {
60+
setCallingAPI(true)
61+
await service.setApiToken(accessToken);
62+
await service.setNewPasswordlessUsingPasskey({
63+
email: userInfo.email,
64+
name: userInfo.name,
65+
passkeyName: values.passkeyName
66+
}).then((response) => {
67+
onConfirm(response);
68+
}).catch((error) => {
69+
global.pushError(error);
70+
});
71+
setCallingAPI(false);
72+
}
73+
5874
return (
5975
<div className="passwordless-form">
6076
{
6177
isAddKey && <div>
62-
<div className="mb-2">
63-
<Trans
64-
i18nKey={'security.passkey.add_new_key_note'}
65-
components={{
66-
b: <b className="font-semibold"></b>
67-
}}
68-
/>
69-
</div>
78+
{
79+
!isNewKey && <div className="mb-2">
80+
<Trans
81+
i18nKey={'security.passkey.add_new_key_note'}
82+
components={{
83+
b: <b className="font-semibold"></b>
84+
}}
85+
/>
86+
</div>
87+
}
7088
<Form
7189
form={form}
7290
layout="vertical"
7391
disabled={callingAPI}
74-
onFinish={setBackupPwl}
92+
onFinish={isNewKey ? setNewPwl : setBackupPwl}
7593
>
7694
<Form.Item
7795
name={'passkeyName'}

src/components/forms/SecurityKey.jsx

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ const SecurityKeyForm = (props) => {
3030
changing = false,
3131
userInfo = {},
3232
isAddKey = false,
33+
isNewKey = false,
3334
accessToken = null,
3435
onRepair = () => { },
3536
onConfirm = () => { }
@@ -80,16 +81,36 @@ const SecurityKeyForm = (props) => {
8081
setPin(pin);
8182
if (!isAddKey) {
8283
await getPwl();
84+
} else if (isNewKey) {
85+
await setNewPwl();
8386
} else {
84-
const apiToken = accessToken || await common.getAccessToken();
85-
await service.setApiToken(apiToken);
8687
await setBackupPwl();
8788
}
8889
}
8990

91+
const getPwl = async () => {
92+
setCallingAPI(true)
93+
try {
94+
const response = await service.getPasswordless({
95+
email: userInfo.email,
96+
devicePath: selectedDevice.path,
97+
pin: pin,
98+
onlyBackup: userInfo.login_method === 'password'
99+
})
100+
setStep(2);
101+
setPasswordless(response)
102+
await onConfirm(response)
103+
} catch (error) {
104+
redirectByError(error)
105+
}
106+
setCallingAPI(false)
107+
}
108+
90109
const setBackupPwl = async () => {
91110
setCallingAPI(true)
92111
try {
112+
const apiToken = accessToken || await common.getAccessToken();
113+
await service.setApiToken(apiToken);
93114
const encKey = await global.jsCore.cryptoService.getEncKey();
94115
const response = await service.setBackupPasswordless({
95116
email: userInfo.email,
@@ -108,18 +129,20 @@ const SecurityKeyForm = (props) => {
108129
setCallingAPI(false)
109130
}
110131

111-
const getPwl = async () => {
132+
const setNewPwl = async () => {
112133
setCallingAPI(true)
113134
try {
114-
const response = await service.getPasswordless({
135+
await service.setApiToken(accessToken);
136+
const response = await service.setNewPasswordless({
115137
email: userInfo.email,
138+
name: selectedDevice.name,
116139
devicePath: selectedDevice.path,
117-
pin: pin,
118-
onlyBackup: userInfo.login_method === 'password'
140+
deviceName: selectedDevice.name,
141+
pin: pin
119142
})
120143
setStep(2);
121-
setPasswordless(response)
122-
await onConfirm(response)
144+
setPasswordless(response);
145+
await onConfirm(response);
123146
} catch (error) {
124147
redirectByError(error)
125148
}

src/components/items/RouterLink.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const RouterLink = (props) => {
2828
<>
2929
{
3030
onClick ? <div
31-
className={`cursor-pointer ${className} text-${type} ${icon ? 'flex items-center' : ''}`}
31+
className={`cursor-pointer ${className} text-${type} ${icon ? 'flex items-center gap-1' : ''}`}
3232
onClick={onClick}
3333
>
3434
<span
@@ -38,7 +38,7 @@ const RouterLink = (props) => {
3838
{label}
3939
</span> {icon}
4040
</div> : <Link
41-
className={`cs-link ${className} text-${type} ${icon ? 'flex items-center' : ''}`}
41+
className={`cs-link ${className} text-${type} ${icon ? 'flex items-center gap-1' : ''}`}
4242
style={{ maxWidth: maxWidth, flex: flex }}
4343
target={blank ? '_blank' : ''}
4444
to={newPath}

src/components/layout/Breadcrumb.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useState, useMemo } from 'react';
1+
import React, { useMemo } from 'react';
22
import { useSelector } from 'react-redux';
33
import { useTranslation } from "react-i18next";
44
import { useLocation } from 'react-router-dom';
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import React from "react";
2+
import { useTranslation } from "react-i18next";
3+
4+
import {
5+
Modal,
6+
Button,
7+
} from '@lockerpm/design';
8+
9+
import {
10+
ArrowRightOutlined
11+
} from "@ant-design/icons";
12+
13+
import itemsComponents from "../items";
14+
15+
import global from "../../config/global";
16+
17+
const EncryptionUpdateModal = (props) => {
18+
const { RouterLink } = itemsComponents;
19+
const { t } = useTranslation()
20+
const {
21+
visible = false,
22+
onClose = () => { },
23+
} = props;
24+
25+
return (
26+
<Modal
27+
title={<div className="px-2 py-0.5 rounded-full bg-warning-100 text-warning-700 uppercase w-max text-xs">
28+
{t('security.encryption_key_settings.update_now.tag')}
29+
</div>}
30+
open={visible}
31+
onCancel={onClose}
32+
width={600}
33+
footer={false}
34+
>
35+
<div className="flex flex-col gap-10">
36+
<div className="flex flex-col gap-1">
37+
<h2 className="text-xl font-semibold">
38+
{t('security.encryption_key_settings.update_now.title')}
39+
</h2>
40+
<p className="text-md">
41+
{t('security.encryption_key_settings.update_now.description')}
42+
</p>
43+
<RouterLink
44+
className={'font-semibold'}
45+
label={t('security.encryption_key_settings.update_now.learn_more')}
46+
icon={<ArrowRightOutlined />}
47+
onClick={() => {}}
48+
/>
49+
</div>
50+
<Button
51+
className="w-full"
52+
type="primary"
53+
size="large"
54+
onClick={() => {
55+
global.navigate(global.keys.SETTINGS_SECURITY);
56+
onClose();
57+
}}
58+
>
59+
{t('security.encryption_key_settings.update_now.action')}
60+
</Button>
61+
</div>
62+
</Modal>
63+
);
64+
}
65+
66+
export default EncryptionUpdateModal;

src/components/modals/PasswordConfirm.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ const PasswordConfirmModal = (props) => {
155155
<SecurityKey
156156
changing={callingAPI}
157157
userInfo={userInfo}
158-
onConfirm={(p) => handleConfirm(p)}
158+
onConfirm={(p) => handleConfirm(p.secret)}
159159
onRepair={() => setIsPair(true)}
160160
/>
161161
</div>
@@ -165,7 +165,7 @@ const PasswordConfirmModal = (props) => {
165165
<Passkey
166166
changing={callingAPI}
167167
userInfo={userInfo}
168-
onConfirm={(p) => handleConfirm(p)}
168+
onConfirm={(p) => handleConfirm(p.secret)}
169169
/>
170170
</div>
171171
}

src/components/modals/index.jsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import PasswordConfirmModal from "./PasswordConfirm";
22
import PasswordViolatedModal from "./PasswordViolated";
33
import ImportDuplicateModal from "./ImportDuplicate";
4+
import EncryptionUpdateModal from "./EncryptionUpdate";
45

56
const modalsComponents = {
67
PasswordConfirmModal,
78
PasswordViolatedModal,
8-
ImportDuplicateModal
9+
ImportDuplicateModal,
10+
EncryptionUpdateModal
911
}
1012

1113
export default modalsComponents

src/config/constants.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React from 'react'
22
import { CipherType } from '../core-js/src/enums'
33
import { FieldType } from '../core-js/src/enums/fieldType'
4+
import { KdfType } from '../core-js/src/enums/kdfType';
45

56
import {
67
DesktopOutlined,
@@ -140,8 +141,8 @@ export default {
140141
MAX_TABLE_WIDTH: 748,
141142
MAX_ATTACHMENT_SIZE: 50 * 1024 * 1024,
142143
CORE_JS_INFO: {
143-
KDF: 0,
144-
KDF_ITERATIONS: 100000
144+
KDF: KdfType.PBKDF2_SHA256,
145+
KDF_ITERATIONS: 600000
145146
},
146147
LANGUAGES: [
147148
{

0 commit comments

Comments
 (0)