Skip to content

Commit d039d37

Browse files
guanbinruiJack-WorkszhouhansengleleneiUncleBill
authored
[Release] Hotfix 2.18.1 => 2.18.2 (patch) (#9036)
* chore: bump version to 2.18.2 * chore: add error message for unwrap (#9035) * fix(sentry): queryId cannot be of type undefined (#9038) * fix(sentry): queryId cannot be of type undefined * chore: code style * fix: cannot contain / in a part of identifier: sanyi.eth / (#9045) * fix: twitter api UserByScreenName (#9031) * fix: remove non-existed url (#9057) * fix: remove non-existed url * chore: remove relative test * fix: mf-3673 recover files deployed with unavailable arweave gateway (#9067) * fixup! fix: mf-3673 recover files deployed with unavailable arweave gateway (#9068) * fix: wordBreak css (#9059) * fix: dashboard asset token icon (#9072) * fix(RSS3): mf-3678 collectible card crash (#9069) * fix(RSS3): mf-3678 collectible card crash * fix: mf-3435 text overflow * fix: avoid guide step flickering (#9084) * fix: show glb in pets (#9070) * fix: logout dialog ui (#9080) * fix: logout dialog ui * fix: typo * fix: reply review * refactor: reply review * fix: 3D model action (#9087) * fix: mf-3699 mirgate mirror user guide from localStorage to storage (#9091) * fix: background color (#9090) * fix: mf-3699 storage user guide status persistently (#9092) * fix: mf-3699 compatible with the legacy guide storage (#9094) * fix: guidestep position of twitter (#9093) * fix: guidestep position of twitter * refactor: remove commented code --------- Co-authored-by: guanbinrui <[email protected]> * chore: update file service recovery domain (#9100) * Revert "fix: remove non-existed url (#9057)" (#9107) This reverts commit 8cd4d96. * fix: mf-3711 twitter user name node gets updated, fix tips (#9109) * fix: add currency chain pair (#9119) * chore: add solana currency match * chore: add currency chain pair --------- Co-authored-by: Jack Works <[email protected]> Co-authored-by: Hancheng Zhou <[email protected]> Co-authored-by: lelenei <[email protected]> Co-authored-by: UncleBill <[email protected]>
1 parent 6c15539 commit d039d37

File tree

59 files changed

+622
-508
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+622
-508
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"yarn": ">=999.0.0",
88
"npm": ">=999.0.0"
99
},
10-
"version": "2.18.1",
10+
"version": "2.18.2",
1111
"private": true,
1212
"license": "AGPL-3.0-or-later",
1313
"scripts": {

packages/backup-format/src/version-0/index.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,10 @@ export async function normalizeBackupVersion0(file: BackupJSONFileVersion0): Pro
4949
}
5050
backup.personas.set(persona.identifier, persona)
5151

52-
if (username && username !== '$unknown' && username !== '$local') {
52+
const identifier = ProfileIdentifier.of('facebook.com', username)
53+
if (identifier.some) {
5354
const profile: NormalizedBackup.ProfileBackup = {
54-
identifier: ProfileIdentifier.of('facebook.com', username).unwrap(),
55+
identifier: identifier.val,
5556
linkedPersona: Some(persona.identifier),
5657
createdAt: None,
5758
updatedAt: None,

packages/backup-format/src/version-1/index.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ export async function normalizeBackupVersion1(file: BackupJSONFileVersion1): Pro
3838

3939
const { whoami, people } = file
4040
for (const { network, publicKey, userId, nickname, localKey, privateKey } of [...whoami, ...(people || [])]) {
41-
const identifier = ProfileIdentifier.of(network, userId).unwrap()
41+
const identifier = ProfileIdentifier.of(network, userId).expect(
42+
`backup should not contain invalid identifier parts ${network} and ${userId}`,
43+
)
4244
const profile: NormalizedBackup.ProfileBackup = {
4345
identifier,
4446
nickname: nickname ? Some(nickname) : None,

packages/dashboard/src/components/PasswordField/index.tsx

+4-4
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import { MaskTextField, MaskTextFieldProps } from '@masknet/theme'
33
import { IconButton, InputAdornment } from '@mui/material'
44
import { Icons } from '@masknet/icons'
55

6-
export type PasswordFieldProps = Exclude<MaskTextFieldProps, 'type'>
6+
export type PasswordFieldProps = Exclude<MaskTextFieldProps, 'type'> & { show?: boolean }
77

8-
const PasswordField = forwardRef((props: PasswordFieldProps, ref: ForwardedRef<any>) => {
8+
const PasswordField = forwardRef(({ show = true, ...props }: PasswordFieldProps, ref: ForwardedRef<any>) => {
99
const [showPassword, setShowPassword] = useState(false)
1010
return (
1111
<MaskTextField
@@ -14,7 +14,7 @@ const PasswordField = forwardRef((props: PasswordFieldProps, ref: ForwardedRef<a
1414
type={showPassword ? 'text' : 'password'}
1515
InputProps={{
1616
...props.InputProps,
17-
endAdornment: (
17+
endAdornment: show ? (
1818
<InputAdornment position="end">
1919
<IconButton
2020
aria-label="toggle password visibility"
@@ -25,7 +25,7 @@ const PasswordField = forwardRef((props: PasswordFieldProps, ref: ForwardedRef<a
2525
{showPassword ? <Icons.EyeOff /> : <Icons.Eye />}
2626
</IconButton>
2727
</InputAdornment>
28-
),
28+
) : null,
2929
}}
3030
/>
3131
)

packages/dashboard/src/locales/en-US.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@
228228
"personas_disconnect": "Delete Persona Verification",
229229
"personas_disconnect_raw": "Disconnect",
230230
"personas_disconnect_warning": "Are you sure you want to delete persona verification? Your mask friends can no longer send decrypted message to you by this persona or check your Web3 products related with this persona.",
231-
"personas_logout_warning": "After logging out, your associated social accounts can no longer decrypt past encrypted messages. If you need to reuse your account, you can use your private key for recovery.",
231+
"personas_logout_warning": "After logging out, your associated social accounts can no longer decrypt past encrypted messages. If you need to reuse your account, you can recover your account with your identity, private key, local or cloud backup.",
232232
"personas_logout_manage_wallet_warning": "Please note: This Persona {{persona}} is the management account of SmartPay wallet <span>{{addresses}}</span>. You cannot use SmartPay wallet to interact with blockchain after logging out persona.",
233233
"personas_add": "Add",
234234
"personas_upload_avatar": "Upload an avatar",
@@ -310,7 +310,7 @@
310310
"settings_label_backup_password": "Backup Password",
311311
"settings_label_new_backup_password": "New Backup Password",
312312
"settings_label_backup_password_cloud": "Backup passwords for files in the cloud",
313-
"settings_label_payment_password": "Payment Password",
313+
"settings_label_payment_password": "Enter your Payment password",
314314
"settings_label_re_enter": "Re-enter",
315315
"settings_alert_password_set": "Backup password set up successfully.",
316316
"settings_alert_password_updated": "Backup password updated",

packages/dashboard/src/pages/Personas/components/LogoutPersonaDialog/index.tsx

+80-9
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { memo, useCallback, useMemo } from 'react'
1+
import { memo, useCallback, useMemo, useState } from 'react'
22
import { useNavigate } from 'react-router-dom'
33
import { Icons } from '@masknet/icons'
44
import { DashboardRoutes, PersonaIdentifier } from '@masknet/shared-base'
@@ -7,9 +7,11 @@ import { useWallets, useWeb3State } from '@masknet/web3-hooks-base'
77
import { formatEthereumAddress, ProviderType } from '@masknet/web3-shared-evm'
88
import { LoadingButton } from '@mui/lab'
99
import { Box, Button, DialogActions, DialogContent, Typography } from '@mui/material'
10-
import { Services } from '../../../../API.js'
10+
import { PluginServices, Services } from '../../../../API.js'
1111
import { DashboardTrans, useDashboardI18N } from '../../../../locales/index.js'
1212
import { PersonaContext } from '../../hooks/usePersonaContext.js'
13+
import PasswordField from '../../../../components/PasswordField/index.js'
14+
import { ManageWallet } from '@masknet/shared'
1315

1416
export interface LogoutPersonaDialogProps {
1517
open: boolean
@@ -24,13 +26,42 @@ export const LogoutPersonaDialog = memo<LogoutPersonaDialogProps>(
2426
const t = useDashboardI18N()
2527
const navigate = useNavigate()
2628
const wallets = useWallets()
27-
const { changeCurrentPersona } = PersonaContext.useContainer()
29+
const { changeCurrentPersona, currentPersona } = PersonaContext.useContainer()
2830
const { Provider } = useWeb3State()
31+
const [password, setPassword] = useState('')
32+
const [error, setError] = useState('')
33+
34+
const backupPassword = useMemo(() => {
35+
try {
36+
const password = localStorage.getItem('backupPassword')
37+
if (!password) return ''
38+
return atob(password)
39+
} catch {
40+
return ''
41+
}
42+
}, [])
2943

3044
const manageWallets = useMemo(() => {
3145
return wallets.filter((x) => x.identifier === identifier.toText())
3246
}, [wallets, identifier])
3347

48+
const onConfirm = useCallback(async () => {
49+
if (manageWallets.length && password) {
50+
const verified = await PluginServices.Wallet.verifyPassword(password)
51+
if (!verified) {
52+
setError(t.settings_dialogs_incorrect_password())
53+
return
54+
}
55+
}
56+
57+
if (backupPassword && backupPassword !== password) {
58+
setError(t.settings_dialogs_incorrect_password())
59+
return
60+
}
61+
62+
handleLogout()
63+
}, [password, backupPassword, manageWallets])
64+
3465
const handleLogout = useCallback(async () => {
3566
if (address && manageWallets.length) {
3667
const maskProvider = Provider?.getWalletProvider(ProviderType.MaskWallet)
@@ -50,34 +81,74 @@ export const LogoutPersonaDialog = memo<LogoutPersonaDialogProps>(
5081

5182
return (
5283
<MaskDialog open={open} title={t.personas_logout()} onClose={onClose} maxWidth="xs">
53-
<DialogContent>
84+
<DialogContent sx={{ paddingBottom: 0 }}>
5485
<Box>
5586
<Box textAlign="center" py={2}>
5687
<Icons.Warning size={64} color="warning" />
5788
</Box>
5889
</Box>
90+
<Box sx={{ marginBottom: 2 }}>
91+
<ManageWallet manageWallets={manageWallets} persona={currentPersona} />
92+
</Box>
5993
<Typography color="error" variant="body2" fontSize={13}>
6094
{t.personas_logout_warning()}
6195
</Typography>
6296
{manageWallets.length ? (
63-
<Typography color="error" variant="body2" fontSize={13} sx={{ wordBreak: 'break-all' }}>
97+
<Typography
98+
color="error"
99+
variant="body2"
100+
fontSize={13}
101+
sx={{ wordBreak: 'break-word', marginTop: 2 }}>
64102
<DashboardTrans.personas_logout_manage_wallet_warning
65103
values={{
66104
persona: nickname ?? '',
67105
addresses: manageWallets.map((x) => formatEthereumAddress(x.address, 4)).join(','),
68106
}}
69107
components={{
70-
span: <Typography component="span" sx={{ wordBreak: 'break-all', fontSize: 12 }} />,
108+
span: (
109+
<Typography component="span" sx={{ wordBreak: 'break-word', fontSize: 12 }} />
110+
),
71111
}}
72112
/>
73113
</Typography>
74114
) : null}
115+
116+
{backupPassword ? (
117+
<PasswordField
118+
sx={{ flex: 1, marginTop: 1.5 }}
119+
placeholder={t.settings_label_backup_password()}
120+
value={password}
121+
onChange={(e) => {
122+
setPassword(e.target.value)
123+
setError('')
124+
}}
125+
error={!!error}
126+
helperText={error}
127+
/>
128+
) : null}
129+
{manageWallets.length ? (
130+
<PasswordField
131+
sx={{ flex: 1, marginTop: 1.5 }}
132+
show={false}
133+
onChange={(e) => {
134+
setPassword(e.currentTarget.value)
135+
setError('')
136+
}}
137+
placeholder={t.settings_label_payment_password()}
138+
error={!!error}
139+
helperText={error}
140+
/>
141+
) : null}
75142
</DialogContent>
76-
<DialogActions>
77-
<Button color="secondary" onClick={onClose} sx={{ minWidth: 150 }}>
143+
<DialogActions sx={{ padding: 3 }}>
144+
<Button color="secondary" onClick={onClose} sx={{ minWidth: 150, flex: 1 }}>
78145
{t.personas_cancel()}
79146
</Button>
80-
<LoadingButton color="error" onClick={handleLogout} sx={{ minWidth: 150 }} variant="contained">
147+
<LoadingButton
148+
color="error"
149+
onClick={onConfirm}
150+
sx={{ minWidth: 150, flex: 1 }}
151+
variant="contained">
81152
{t.personas_logout()}
82153
</LoadingButton>
83154
</DialogActions>

packages/dashboard/src/pages/Personas/components/PersonaCard/Row.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ export const PersonaRowCardUI = memo<PersonaRowCardUIProps>((props) => {
163163
<MenuItem onClick={() => navigate(DashboardRoutes.Settings, { state: { open: 'setting' } })}>
164164
<MenuText>{t.settings_global_backup_title()}</MenuText>
165165
</MenuItem>,
166-
<MenuItem onClick={logoutConfirmedPasswordCallback} style={{ color: MaskColorVar.redMain }}>
166+
<MenuItem onClick={() => setLogoutDialogOpen(true)} style={{ color: MaskColorVar.redMain }}>
167167
<MenuText>{t.personas_logout()}</MenuText>
168168
</MenuItem>,
169169
)

packages/dashboard/src/pages/Wallets/hooks/useContext.ts

+21-3
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,37 @@
11
import { createContainer } from 'unstated-next'
2-
import type { NetworkPluginID } from '@masknet/shared-base'
3-
import { useFungibleAssets, useChainContext } from '@masknet/web3-hooks-base'
2+
import { type NetworkPluginID, EMPTY_LIST } from '@masknet/shared-base'
3+
import {
4+
useFungibleAssets,
5+
useChainContext,
6+
useFungibleTokensFromTokenList,
7+
useWeb3State,
8+
} from '@masknet/web3-hooks-base'
49
import type { Web3Helper } from '@masknet/web3-helpers'
10+
import { isNativeTokenAddress } from '@masknet/web3-shared-evm'
11+
import { isSameAddress } from '@masknet/web3-shared-base'
512

613
function useContext(initialState?: { account?: string; chainId?: Web3Helper.ChainIdAll; pluginID?: NetworkPluginID }) {
714
const { account, chainId } = useChainContext({ account: initialState?.account, chainId: initialState?.chainId })
15+
const { Others } = useWeb3State<'all'>(initialState?.pluginID)
816
const fungibleAssets = useFungibleAssets<'all'>(initialState?.pluginID, undefined, {
917
account,
1018
chainId,
1119
})
20+
const { value: fungibleTokens = EMPTY_LIST, loading } = useFungibleTokensFromTokenList(initialState?.pluginID, {
21+
chainId,
22+
})
1223

24+
const assets = (fungibleAssets?.value ?? EMPTY_LIST).map((x) => {
25+
if (isNativeTokenAddress(x.address))
26+
return { ...x, logoURL: Others?.chainResolver.nativeCurrency(x.chainId)?.logoURL || x.logoURL }
27+
const token = fungibleTokens.find((y) => isSameAddress(x.address, y.address) && x.chainId === y.chainId)
28+
if (!token?.logoURL) return x
29+
return { ...x, logoURL: token.logoURL }
30+
})
1331
return {
1432
account,
1533
chainId,
16-
fungibleAssets,
34+
fungibleAssets: { ...fungibleAssets, value: assets, loading: loading || fungibleAssets.loading },
1735
}
1836
}
1937

packages/mask/background/database/persona/web.ts

+15-5
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,9 @@ export async function updateProfileDB(
452452
: undefined
453453

454454
if (oldLinkedPersona && updating.linkedPersona && oldLinkedPersona !== updating.linkedPersona) {
455-
const oldIdentifier = ProfileIdentifier.from(old.identifier).unwrap()
455+
const oldIdentifier = ProfileIdentifier.from(old.identifier).expect(
456+
`old data in the profile database should be a valid ProfileIdentifier, but found ${old.identifier}`,
457+
)
456458
const oldLinkedPersona = await queryPersonaByProfileDB(oldIdentifier, t)
457459

458460
if (oldLinkedPersona) {
@@ -677,7 +679,9 @@ function profileOutDB({ network, ...x }: ProfileRecordDB): ProfileRecord {
677679
}
678680
return {
679681
...x,
680-
identifier: ProfileIdentifier.from(x.identifier).unwrap(),
682+
identifier: ProfileIdentifier.from(x.identifier).expect(
683+
`data stored in the profile database should be a valid ProfileIdentifier, but found ${x.identifier}`,
684+
),
681685
linkedPersona: x.linkedPersona
682686
? new ECKeyIdentifier(
683687
x.linkedPersona.curve,
@@ -696,7 +700,9 @@ function personaRecordToDB(x: PersonaRecord): PersonaRecordDB {
696700
}
697701
function personaRecordOutDB(x: PersonaRecordDB): PersonaRecord {
698702
Reflect.deleteProperty(x, 'hasPrivateKey' as keyof typeof x)
699-
const identifier = ECKeyIdentifier.from(x.identifier).unwrap()
703+
const identifier = ECKeyIdentifier.from(x.identifier).expect(
704+
`data stored in the profile database should be a valid ECKeyIdentifier, but found ${x.identifier}`,
705+
)
700706

701707
const obj: PersonaRecord = {
702708
...x,
@@ -722,8 +728,12 @@ function relationRecordToDB(x: Omit<RelationRecord, 'network'>): RelationRecordD
722728
function relationRecordOutDB(x: RelationRecordDB): RelationRecord {
723729
return {
724730
...x,
725-
profile: ProfileIdentifier.from(x.profile).unwrap(),
726-
linked: ECKeyIdentifier.from(x.linked).unwrap(),
731+
profile: ProfileIdentifier.from(x.profile).expect(
732+
`data stored in the profile database should be a valid ProfileIdentifier, but found ${x.profile}`,
733+
),
734+
linked: ECKeyIdentifier.from(x.linked).expect(
735+
`data stored in the profile database should be a valid ECKeyIdentifier, but found ${x.linked}`,
736+
),
727737
}
728738
}
729739

packages/mask/background/database/post/web.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,9 @@ export async function queryPostPagedDB(
266266
if (!cursor.value.postBy) continue
267267
if (!options.userIds.includes(cursor.value.postBy.userId)) continue
268268

269-
const postIdentifier = PostIVIdentifier.from(cursor.value.identifier).unwrap()
269+
const postIdentifier = PostIVIdentifier.from(cursor.value.identifier).expect(
270+
`data stored in the post database should be a valid PostIVIdentifier, but found ${cursor.value.identifier}`,
271+
)
270272
if (postIdentifier.network !== options.network) continue
271273

272274
if (firstRecord && options.after) {
@@ -301,7 +303,9 @@ function postOutDB(db: LatestPostDBRecord): PostRecord {
301303
}
302304
}
303305
return {
304-
identifier: PostIVIdentifier.from(identifier).unwrap(),
306+
identifier: PostIVIdentifier.from(identifier).expect(
307+
`data stored in the post database should be a valid PostIVIdentifier, but found ${identifier}`,
308+
),
305309
postBy: ProfileIdentifier.of(postBy?.network, postBy?.userId).unwrapOr(undefined),
306310
recipients,
307311
foundAt,

packages/mask/background/services/backup/internal_restore.ts

+7-5
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,8 @@ async function restorePlugins(backup: NormalizedBackup.Data['plugins']) {
194194
continue
195195
}
196196

197-
const f = plugin.backup?.onRestore
198-
if (!f) {
197+
const onRestore = plugin.backup?.onRestore
198+
if (!onRestore) {
199199
console.warn(
200200
`[@masknet/plugin-infra] Found a backup of plugin ${plugin} but it did not register a onRestore callback.`,
201201
item,
@@ -204,9 +204,11 @@ async function restorePlugins(backup: NormalizedBackup.Data['plugins']) {
204204
}
205205
works.add(
206206
(async () => {
207-
const x = await f(item)
208-
if (x.err) console.error(`[@masknet/plugin-infra] Plugin ${plugin} failed to restore its backup.`, item)
209-
return x.unwrap()
207+
const result = await onRestore(item)
208+
if (result.err) {
209+
const msg = `[@masknet/plugin-infra] Plugin ${plugin.ID} failed to restore its backup.`
210+
throw new Error(msg, { cause: result.err })
211+
}
210212
})(),
211213
)
212214
}

packages/mask/background/services/backup/restore.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ export async function getUnconfirmedBackup(id: string): Promise<
143143
const personaAddresses = compact(
144144
[...backup.personas.values()].map((x) => {
145145
if (x.privateKey.some) {
146-
const privateKey = x.privateKey.unwrap()
146+
const privateKey = x.privateKey.val
147147
if (!privateKey.d) return
148148
return bufferToHex(publicToAddress(privateToPublic(Buffer.from(fromBase64URL(privateKey.d)))))
149149
}

packages/mask/background/services/identity/profile/update.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,14 @@ export async function detachProfileWithNextID(
6262
})
6363
MaskMessages.events.ownProofChanged.sendToAll(undefined)
6464
}
65+
const err = 'resolveUnknownLegacyIdentity should not be called on localhost'
6566
/**
6667
* In older version of Mask, identity is marked as `ProfileIdentifier(network, '$unknown')` or `ProfileIdentifier(network, '$self')`. After upgrading to the newer version of Mask, Mask will try to find the current user in that network and call this function to replace old identifier into a "resolved" identity.
6768
* @param identifier The resolved identity
6869
*/
6970
export async function resolveUnknownLegacyIdentity(identifier: ProfileIdentifier): Promise<void> {
70-
const unknown = ProfileIdentifier.of(identifier.network, '$unknown').unwrap()
71-
const self = ProfileIdentifier.of(identifier.network, '$self').unwrap()
71+
const unknown = ProfileIdentifier.of(identifier.network, '$unknown').expect(err)
72+
const self = ProfileIdentifier.of(identifier.network, '$self').expect(err)
7273

7374
const records = await queryProfilesDB({ identifiers: [unknown, self] })
7475
if (!records.length) return

0 commit comments

Comments
 (0)