Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 44 additions & 3 deletions wallets/client/components/passphrase.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react'
import React, { useCallback } from 'react'
import Button from 'react-bootstrap/Button'
import { CopyButton } from '@/components/form'
import styles from '@/styles/wallet.module.css'

Expand All @@ -7,7 +8,7 @@ export function Passphrase ({ passphrase }) {
return (
<>
<p className='fw-bold line-height-md'>
Make sure to copy your passphrase now.
Make sure to save your passphrase now.
</p>
<p className='fw-bold line-height-md'>
This is the only time we will show it to you.
Expand All @@ -23,9 +24,49 @@ export function Passphrase ({ passphrase }) {
</div>
))}
</div>
<div className='d-flex justify-content-end mt-3'>
<div className='d-flex justify-content-center mt-3 gap-2 align-items-center'>
<CopyButton className='rounded' value={passphrase} variant='primary' />
<span className='text-muted'>or</span>
<DownloadButton passphrase={passphrase} />
</div>
</>
)
}

export default function DownloadButton ({ passphrase }) {
const onClick = useCallback(() => {
const filename = 'stacker-news-passphrase.txt'
const value = `STACKER NEWS PASSPHRASE
-----------------------

Your passphrase to unlock your wallets on any device is:

${passphrase}

Please keep this passphrase safe and do not share it with anyone.
`
download(filename, value)
}, [passphrase])

return (
<Button
className='rounded'
variant='primary'
onClick={onClick}
>
download
</Button>
)
}

function download (filename, value) {
const blob = new Blob([value], { type: 'text/plain' })
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = filename
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
URL.revokeObjectURL(url)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Race Condition in Immediate Resource Cleanup

The download function has a race condition. The object URL is revoked and the anchor element removed immediately after a.click(). Since a.click() is asynchronous, the browser may not initiate the download before these resources are cleaned up, which can cause the download to fail.

Fix in Cursor Fix in Web

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mhhh