Skip to content

Commit e12eedf

Browse files
authored
feat: fw-6741 update firefly login flow (#12296)
1 parent e70795e commit e12eedf

File tree

26 files changed

+394
-56
lines changed

26 files changed

+394
-56
lines changed

packages/icons/brands/TwitterX.dark.svg

Lines changed: 0 additions & 3 deletions
This file was deleted.

packages/icons/brands/TwitterX.light.svg

Lines changed: 0 additions & 3 deletions
This file was deleted.

packages/icons/brands/TwitterX.svg

Lines changed: 3 additions & 0 deletions
Loading

packages/icons/icon-generated-as-jsx.js

Lines changed: 11 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/icons/icon-generated-as-url.js

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/mask/background/services/helper/oauth-x.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { timeout } from '@masknet/kit'
22
import { requestExtensionPermissionFromContentScript } from './request-permission.js'
3+
import { XOAuthRequestOrigins } from '../../../shared/definitions/extension.js'
34

45
/** Modified from https://github.com/ddo/oauth-1.0a/blob/master/oauth-1.0a.js */
56
class OAuth {
@@ -184,15 +185,7 @@ const client = new OAuth(process.env.FIREFLY_X_CLIENT_ID, process.env.FIREFLY_X_
184185
let pendingOAuth: PromiseWithResolvers<{ oauth_verifier: string; oauth_token: string }> | undefined
185186
export async function requestXOAuthToken() {
186187
await requestExtensionPermissionFromContentScript({
187-
origins: [
188-
// In order to send API request without CORS limit
189-
'https://api.twitter.com/*',
190-
// In order to run content script on it
191-
'https://firefly.social/api/mask/delegate-x-token',
192-
'https://firefly.social/api/auth/callback/twitter',
193-
'https://canary.firefly.social/api/mask/delegate-x-token',
194-
'https://canary.firefly.social/api/auth/callback/twitter',
195-
],
188+
origins: XOAuthRequestOrigins,
196189
})
197190
await Promise.all([
198191
fetch('https://firefly.social/api/mask/delegate-x-token'),
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
import Services from '#services'
2+
import { Trans } from '@lingui/react/macro'
3+
import { Icons } from '@masknet/icons'
4+
import { PopupRoutes } from '@masknet/shared-base'
5+
import { makeStyles } from '@masknet/theme'
6+
import { Button, Dialog, DialogActions, DialogContent, DialogTitle, Typography } from '@mui/material'
7+
import { memo, useState } from 'react'
8+
import { useAsyncFn, useAsyncRetry } from 'react-use'
9+
import { PrimaryButton } from '../../../components/PrimaryButton/index.js'
10+
import { SetupFrameController } from '../../../components/SetupFrame/index.js'
11+
import { XOAuthRequestOrigins } from '../../../../shared/definitions/extension.js'
12+
13+
const useStyles = makeStyles()((theme) => ({
14+
container: {
15+
width: '100%',
16+
display: 'flex',
17+
justifyContent: 'center',
18+
flexDirection: 'column',
19+
flex: 1,
20+
},
21+
title: {
22+
fontSize: 30,
23+
margin: '12px 0',
24+
lineHeight: '120%',
25+
color: theme.palette.maskColor.main,
26+
},
27+
tips: {
28+
fontSize: 14,
29+
lineHeight: '18px',
30+
color: theme.palette.maskColor.second,
31+
},
32+
bold: {
33+
fontWeight: 700,
34+
},
35+
notes: {
36+
display: 'flex',
37+
padding: theme.spacing(3, 2),
38+
alignItems: 'center',
39+
alignContent: 'stretch',
40+
borderRadius: 12,
41+
marginTop: theme.spacing(3),
42+
background:
43+
theme.palette.mode === 'dark' ?
44+
'linear-gradient(180deg, rgba(255, 255, 255, 0.10) 0%, rgba(255, 255, 255, 0.00) 100%)'
45+
: 'linear-gradient(180deg, rgba(255, 255, 255, 0.00) 0%, #FFF 100%), linear-gradient(90deg, rgba(98, 126, 234, 0.20) 0%, rgba(59, 153, 252, 0.20) 100%)',
46+
},
47+
fireflyLogo: {
48+
width: 120,
49+
height: 120,
50+
display: 'flex',
51+
justifyContent: 'center',
52+
alignItems: 'center',
53+
},
54+
list: {
55+
listStyle: 'none',
56+
color: theme.palette.maskColor.main,
57+
fontSize: '13px',
58+
lineHeight: '18px',
59+
fontWeight: 400,
60+
paddingLeft: 16,
61+
margin: 0,
62+
'& li': {
63+
marginBottom: 12,
64+
listStyle: 'disc',
65+
},
66+
},
67+
dialog: {
68+
width: 600,
69+
boxSizing: 'border-box',
70+
padding: 24,
71+
borderRadius: 12,
72+
display: 'flex',
73+
flexDirection: 'column',
74+
gap: 24,
75+
},
76+
dialogTitle: {
77+
color: theme.palette.maskColor.main,
78+
fontSize: 18,
79+
fontWeight: 700,
80+
lineHeight: '22px',
81+
padding: 0,
82+
},
83+
dialogContent: {
84+
display: 'flex',
85+
flexDirection: 'column',
86+
gap: 12,
87+
padding: 0,
88+
},
89+
permissions: {
90+
backgroundColor: theme.palette.maskColor.bg,
91+
padding: 12,
92+
borderRadius: 8,
93+
height: 212,
94+
boxSizing: 'border-box',
95+
minHeight: 0,
96+
flexGrow: 1,
97+
overflow: 'auto',
98+
},
99+
dialogActions: {
100+
display: 'flex',
101+
justifyContent: 'center',
102+
gap: 12,
103+
padding: 0,
104+
},
105+
actionButton: {
106+
minWidth: 110,
107+
'&&': {
108+
marginLeft: 0,
109+
},
110+
},
111+
}))
112+
113+
export const Component = memo(function CreateWalletForm() {
114+
const { classes, cx } = useStyles()
115+
const [open, setOpen] = useState(false)
116+
117+
const { retry, value: hasPermission } = useAsyncRetry(() => {
118+
const hasPermission = browser.permissions.contains({
119+
origins: XOAuthRequestOrigins,
120+
})
121+
setOpen(!hasPermission)
122+
return hasPermission
123+
}, [])
124+
125+
const [{ loading }, request] = useAsyncFn(async () => {
126+
if (!hasPermission) {
127+
setOpen(true)
128+
return
129+
}
130+
try {
131+
const data = await Services.Helper.loginFireflyViaTwitter()
132+
if (!data) return
133+
await Services.Helper.openPopupWindow(PopupRoutes.CreateWallet, {
134+
creatingFireflyWallet: true,
135+
})
136+
} catch (err) {
137+
console.error('Failed to login firefly', err)
138+
}
139+
}, [hasPermission])
140+
141+
return (
142+
<div className={classes.container}>
143+
<Typography className={cx(classes.title, classes.bold)}>
144+
<Trans>Create a Firefly.social wallet</Trans>
145+
</Typography>
146+
<Typography className={classes.tips}>
147+
<Trans>Create a Firefly.social wallet using an X account</Trans>
148+
</Typography>
149+
<div className={classes.notes}>
150+
<div className={classes.fireflyLogo}>
151+
<Icons.Firefly size={60} />
152+
</div>
153+
<ul className={classes.list}>
154+
<li>
155+
Firefly.social wallet connects your Web3 identity to the entire Mask Network and firefly.social
156+
ecosystem.
157+
</li>
158+
<li>
159+
With a single wallet, you can like, post, collect, and transfer across multiple Web3 social
160+
platforms — all in one seamless flow.
161+
</li>
162+
<li>
163+
Log in securely in seconds with your X account and unify your EVM, Solana, and other chain
164+
identities effortlessly.
165+
</li>
166+
<li>
167+
Firefly.social wallet isn’t just a wallet — it’s your gateway to social, identity, and ownership
168+
in Web3.
169+
</li>
170+
</ul>
171+
</div>
172+
<SetupFrameController>
173+
<PrimaryButton
174+
width="125px"
175+
size="large"
176+
color="primary"
177+
className={classes.bold}
178+
startIcon={<Icons.TwitterX size={20} />}
179+
loading={loading}
180+
onClick={request}>
181+
<Trans>Continue</Trans>
182+
</PrimaryButton>
183+
</SetupFrameController>
184+
<Dialog
185+
open={open}
186+
PaperProps={{
187+
elevation: 0,
188+
className: classes.dialog,
189+
}}>
190+
<DialogTitle className={classes.dialogTitle}>
191+
<Trans>Mask needs the following permissions</Trans>
192+
</DialogTitle>
193+
<DialogContent className={classes.dialogContent}>
194+
<Typography>
195+
<Trans>Sites</Trans>
196+
</Typography>
197+
<div className={classes.permissions} data-hide-scrollbar>
198+
{XOAuthRequestOrigins.map((origin) => (
199+
<Typography key={origin} lineHeight="18px">
200+
{origin}
201+
</Typography>
202+
))}
203+
</div>
204+
</DialogContent>
205+
<DialogActions className={classes.dialogActions}>
206+
<Button onClick={() => setOpen(false)} variant="outlined" className={classes.actionButton}>
207+
<Trans>Cancel</Trans>
208+
</Button>
209+
<Button
210+
onClick={() => {
211+
browser.permissions.request({ origins: XOAuthRequestOrigins }).finally(retry)
212+
}}
213+
variant="contained"
214+
className={classes.actionButton}>
215+
<Trans>Approve</Trans>
216+
</Button>
217+
</DialogActions>
218+
</Dialog>
219+
</div>
220+
)
221+
})

packages/mask/dashboard/pages/CreateMaskWallet/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export const walletRoutes: RouteObject[] = [
1111
{ path: r(DashboardRoutes.SignUpMaskWalletOnboarding), lazy: () => import('./Onboarding/index.js') },
1212
{ path: r(DashboardRoutes.RecoveryMaskWallet), lazy: () => import('./Recovery/index.js') },
1313
{ path: r(DashboardRoutes.AddDeriveWallet), lazy: () => import('./AddDeriveWallet/index.js') },
14+
{ path: r(DashboardRoutes.CreateFireflyWallet), lazy: () => import('./FireflyWallet/index.js') },
1415
]
1516

1617
export function WalletFrame() {

packages/mask/dashboard/pages/SetupPersona/Onboarding/index.tsx

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -169,13 +169,7 @@ export const Component = memo(function Onboarding() {
169169
<PrimaryButton
170170
onClick={onSetupTwitter}
171171
size="large"
172-
startIcon={
173-
<Icons.TwitterX
174-
variant={theme.palette.mode === 'dark' ? 'light' : 'dark'}
175-
className={classes.twitter}
176-
size={20}
177-
/>
178-
}>
172+
startIcon={<Icons.TwitterX className={classes.twitter} size={20} />}>
179173
<Trans>Experience in X</Trans>
180174
</PrimaryButton>
181175
{!isCreate && count && !isZero(count) ?

packages/mask/dashboard/pages/SetupPersona/PermissionOnboarding/index.tsx

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -139,13 +139,7 @@ export const Component = memo(function Onboarding() {
139139
<PrimaryButton
140140
onClick={onSetupTwitter}
141141
size="large"
142-
startIcon={
143-
<Icons.TwitterX
144-
variant={theme.palette.mode === 'dark' ? 'light' : 'dark'}
145-
className={classes.twitter}
146-
size={20}
147-
/>
148-
}>
142+
startIcon={<Icons.TwitterX className={classes.twitter} size={20} />}>
149143
<Trans>Experience in X</Trans>
150144
</PrimaryButton>
151145
</SetupFrameController>

0 commit comments

Comments
 (0)