*/\r
async sign (index: number, block: Block, frontier?: Block): Promise<void>\r
async sign (index: number, data: string | string[] | Block, frontier?: Block): Promise<void | string> {\r
- if (navigator.userActivation?.isActive === false) {\r
- throw new Error('Signing request was blocked due to lack of user activation.')\r
- }\r
+ const { address } = await this.account(index)\r
return data instanceof Block\r
- ? await _signBlock(this, this.#vault, index, data, frontier)\r
- : await _signData(this, this.#vault, index, data)\r
+ ? await _signBlock(this, this.#vault, index, address, data, frontier)\r
+ : await _signData(this, this.#vault, index, address, data)\r
}\r
\r
/**\r
import { Vault } from '../vault'
import { Wallet } from '../wallet'
-export async function _signData (wallet: Wallet, vault: Vault, index: number, data: string | string[]): Promise<string>
-export async function _signData (wallet: Wallet, vault: Vault, index: unknown, data: unknown): Promise<string> {
+export async function _signData (wallet: Wallet, vault: Vault, index: number, address: string, data: string | string[]): Promise<string>
+export async function _signData (wallet: Wallet, vault: Vault, index: unknown, address: unknown, data: unknown): Promise<string> {
try {
if (typeof index !== 'number') {
throw new TypeError('Index must be a number', { cause: index })
}
+ if (typeof address !== 'string') {
+ throw new TypeError('Address must be a string', { cause: address })
+ }
const message = Array.isArray(data) ? data : [data]
if (message.some(s => typeof s !== 'string')) {
throw new TypeError('Data to sign must be strings', { cause: data })
if (wallet.type === 'Ledger') {
return await Ledger.sign(index, message[0])
}
+ const reqId = crypto.randomUUID()
+ const resId = await confirm(reqId, address, message)
+ if (resId === null) {
+ throw new Error('User rejected sign request')
+ }
+ if (reqId !== resId) {
+ throw new Error('Signing confirmation responded to wrong request')
+ }
const { signature } = await vault.request<ArrayBuffer>({
action: 'sign',
index,
}
}
-
-export async function _signBlock (wallet: Wallet, vault: Vault, index: number, block: Block, frontier?: Block): Promise<void>
-export async function _signBlock (wallet: Wallet, vault: Vault, index: unknown, block: unknown, frontier?: unknown): Promise<void> {
+export async function _signBlock (wallet: Wallet, vault: Vault, index: number, address: string, block: Block, frontier?: Block): Promise<void>
+export async function _signBlock (wallet: Wallet, vault: Vault, index: unknown, address: unknown, block: unknown, frontier?: unknown): Promise<void> {
try {
if (typeof index !== 'number') {
throw new TypeError('Index must be a number', { cause: index })
}
+ if (typeof address !== 'string') {
+ throw new TypeError('Address must be a string', { cause: address })
+ }
if (!(block instanceof Block)) {
throw new TypeError('Invalid Block', { cause: block })
}
}
block.signature = await Ledger.sign(index, block)
} else {
+ const reqId = crypto.randomUUID()
+ const resId = await confirm(reqId, address, block)
+ if (resId === null) {
+ throw new Error('User rejected sign request')
+ }
+ if (reqId !== resId) {
+ throw new Error('Signing confirmation responded to wrong request')
+ }
const { signature } = await vault.request<ArrayBuffer>({
action: 'sign',
index,
throw new Error(`Failed to sign block`, { cause: err })
}
}
+
+async function confirm (id: string, address: string, message: Block | string[]): Promise<string | null> {
+ BROWSER: return new Promise((resolve, reject) => {
+ const dialog = document.createElement('dialog')
+ dialog.innerHTML = `
+ <form method="dialog">
+ <p style="font-size=1rem !important;><strong>Sign using account ${address}?</strong></p>
+ <pre style="font-size=1rem !important;>${JSON.stringify(message, null, '\t')}</pre>
+ <div style="text-align:right;">
+ <button value="no" autofocus>NO, cancel</button>
+ <button value="yes">YES, sign</button>
+ </div>
+ </form>`
+ dialog.addEventListener('close', (ev) => {
+ if (ev.isTrusted && navigator.userActivation?.isActive) {
+ resolve(dialog.returnValue === 'yes' ? id : null)
+ } else {
+ reject(new DOMException(
+ 'Signing request was blocked due to lack of user activation.',
+ 'NotAllowedError'
+ ))
+ }
+ })
+ document.body.appendChild(dialog)
+ dialog.showModal()
+ })
+ NODE: return id
+}