Skip to content

Commit 161aaab

Browse files
UncleBillguanbinrui
authored andcommitted
feat: mf-5479 next id verification post
1 parent bb52750 commit 161aaab

File tree

9 files changed

+123
-6
lines changed

9 files changed

+123
-6
lines changed

packages/mask/content-script/site-adaptors/twitter.com/injection/Tips/PostTipsButton.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ export function injectTipsButtonOnPost(signal: AbortSignal) {
5252
const root = attachReactTreeWithContainer(proxy.afterShadow, {
5353
signal,
5454
tag: createRootElement,
55-
// untilVisible: true,
5655
})
5756
root.render(<PostTipsSlot userId={userId} />)
5857
remover = root.destroy

packages/plugins/NextID/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"@masknet/web3-providers": "workspace:^",
2525
"@masknet/web3-shared-base": "workspace:^",
2626
"@masknet/web3-shared-evm": "workspace:^",
27-
"react-use": "^17.4.0"
27+
"react-use": "^17.4.0",
28+
"zod": "^3.22.2"
2829
}
2930
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { EmojiAvatar } from '@masknet/shared'
2+
import { makeStyles } from '@masknet/theme'
3+
import { Button, Typography } from '@mui/material'
4+
import { memo } from 'react'
5+
import { useNextID_Trans } from '../locales/i18n_generated.js'
6+
7+
const useStyles = makeStyles()((theme) => ({
8+
container: {
9+
padding: theme.spacing(1.5),
10+
display: 'flex',
11+
alignItems: 'center',
12+
},
13+
text: {
14+
flexGrow: 1,
15+
color: theme.palette.maskColor.main,
16+
marginLeft: theme.spacing(1.5),
17+
marginRight: theme.spacing(1.5),
18+
fontSize: 14,
19+
wordBreak: 'break-all',
20+
},
21+
button: {
22+
width: 42,
23+
},
24+
}))
25+
26+
interface Props {
27+
pubkey: string
28+
}
29+
export const VerificationPayload = memo(function VerificationPayload({ pubkey }: Props) {
30+
const { classes } = useStyles()
31+
const t = useNextID_Trans()
32+
return (
33+
<div className={classes.container}>
34+
<EmojiAvatar value={pubkey} size={40} />
35+
<Typography className={classes.text}>{pubkey}</Typography>
36+
<Button
37+
className={classes.button}
38+
variant="roundedContained"
39+
href={`https://web3.bio/?s=${pubkey}`}
40+
target="_blank"
41+
rel="noopener noreferrer">
42+
{t.view()}
43+
</Button>
44+
</div>
45+
)
46+
})

packages/plugins/NextID/src/SiteAdaptor/index.tsx

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,54 @@
11
import type { Plugin } from '@masknet/plugin-infra'
2+
import { usePluginWrapper, usePostInfoDetails } from '@masknet/plugin-infra/content-script'
3+
import { NextIDPlatform } from '@masknet/shared-base'
4+
import { NextIDProof } from '@masknet/web3-providers'
5+
import { useQuery } from '@tanstack/react-query'
6+
import { useMemo } from 'react'
7+
import { z } from 'zod'
28
import { base } from '../base.js'
3-
import { PLUGIN_ID } from '../constants.js'
49
import { NextIdPage } from '../components/NextIdPage.js'
10+
import { PLUGIN_ID } from '../constants.js'
11+
import { VerificationPayload } from './VerificationPayload.js'
12+
13+
function createSchema() {
14+
return z.object({
15+
type: z.literal('tuple'),
16+
items: z.tuple([
17+
z.object({
18+
type: z.literal('text'),
19+
content: z.string(),
20+
}),
21+
z.any(),
22+
]),
23+
})
24+
}
525

626
const site: Plugin.SiteAdaptor.Definition = {
727
...base,
28+
PostInspector: function VerificationPayloadInspector() {
29+
const raw = usePostInfoDetails.rawMessage()
30+
const author = usePostInfoDetails.author()
31+
const payload = useMemo(() => {
32+
const schema = createSchema()
33+
const result = schema.safeParse(raw)
34+
35+
if (!result.success) return null
36+
const PAYLOAD_RE = /^🎭 {2}Verify {2}@.*? {2}with {2}@NextDotID .\nSig: .*\nMisc: /
37+
return result.data.items.find((x) => x.type === 'text' && x.content.match(PAYLOAD_RE))?.content
38+
}, [raw])
39+
40+
const enabled = !!payload && !!author?.userId
41+
const { data: pubkey } = useQuery({
42+
enabled,
43+
queryKey: ['next-id', 'restore-pubkey', author?.userId, payload],
44+
queryFn: () => NextIDProof.restorePubkey(payload, NextIDPlatform.Twitter, author!.userId),
45+
})
46+
47+
const available = enabled && !!pubkey
48+
usePluginWrapper(available)
49+
50+
return available ? <VerificationPayload pubkey={pubkey} /> : null
51+
},
852
ProfileTabs: [
953
{
1054
ID: `${PLUGIN_ID}_tabContent`,

packages/plugins/NextID/src/locales/en-US.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"please_connect_persona": "Please connect persona",
4040
"unbind_persona_tip": "Choose either your Persona or the currently connected wallet to sign to disconnect.",
4141
"unbind_wallet_tip": "Choose either your Persona or the currently connected wallet to sign to disconnect.",
42+
"view": "View",
4243
"done": "Done",
4344
"confirm": "Confirm",
4445
"cancel": "Cancel",

packages/shared-base/src/constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,4 @@ export const UNIT_TEST_ERC20_ADDRESS = '0xdAC17F958D2ee523a2206206994597C13D831e
3030
export const EMPTY_LIST = Object.freeze([]) as never[]
3131
export const EMPTY_OBJECT = Object.freeze({}) as Record<string, never>
3232

33-
export const DEFAULT_PLUGIN_PUBLISHER = { name: { fallback: 'Mask Network' }, link: 'https://mask.io/' }
33+
export const DEFAULT_PLUGIN_PUBLISHER = { name: { fallback: 'Web3.io' }, link: 'https://web3.bio/' }

packages/shared/src/UI/components/EmojiAvatar/index.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ import { EMOJI_LIST } from './constants.js'
66

77
interface Props extends AvatarProps {
88
value: string
9+
size?: number
910
}
1011

11-
export function EmojiAvatar({ value, ...props }: Props) {
12+
export function EmojiAvatar({ value, size, ...props }: Props) {
1213
const theme = useTheme()
1314

1415
const { emoji, backgroundColor } = useMemo(() => {
@@ -26,6 +27,8 @@ export function EmojiAvatar({ value, ...props }: Props) {
2627
<MuiAvatar
2728
style={{
2829
backgroundColor,
30+
height: size,
31+
width: size,
2932
}}
3033
{...props}>
3134
{emoji}

packages/web3-providers/src/NextID/proof.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
fromHex,
66
toBase64,
77
type BindingProof,
8-
type NextIDAction,
8+
NextIDAction,
99
type NextIDBindings,
1010
type NextIDErrorBody,
1111
type NextIDIdentity,
@@ -206,6 +206,11 @@ interface CreatePayloadResponse {
206206
created_at: string
207207
}
208208

209+
interface RestorePubkeyResponse {
210+
/** hex public key */
211+
public_key: string
212+
}
213+
209214
type NeighborNode = {
210215
source: NextIDPlatform
211216
to: NextIDIdentity
@@ -558,6 +563,20 @@ export class NextIDProof {
558563
}
559564
: null
560565
}
566+
567+
static async restorePubkey(payload: string, platform: NextIDPlatform, identity: string) {
568+
const url = urlcat(BASE_URL, '/v1/proof/restore_pubkey')
569+
const response = await fetchJSON<RestorePubkeyResponse>(url, {
570+
method: 'POST',
571+
body: JSON.stringify({
572+
action: NextIDAction.Create,
573+
platform,
574+
identity,
575+
proof_post: payload,
576+
}),
577+
})
578+
return response.public_key
579+
}
561580
}
562581

563582
function createBindingProofNodeFromNeighbor(nextIDIdentity: NextIDIdentity, source: NextIDPlatform) {

pnpm-lock.yaml

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

0 commit comments

Comments
 (0)