Skip to content

Commit 7ea1233

Browse files
committed
feat: auto-submit iframe challenge answers via postMessage
When a url/iframe challenge (e.g. OAuth, CAPTCHA) completes inside an iframe, the iframe can now signal completion via postMessage and the client auto-submits the challenge answers without manual user action.
1 parent 0bfd516 commit 7ea1233

1 file changed

Lines changed: 28 additions & 1 deletion

File tree

src/hooks/actions/actions.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {useMemo, useState} from 'react'
1+
import {useEffect, useMemo, useState} from 'react'
22
import useAccountsStore from '../../stores/accounts'
33
import Logger from '@plebbit/plebbit-logger'
44
const log = Logger('plebbit-react-hooks:actions:hooks')
@@ -36,6 +36,28 @@ const publishChallengeAnswersNotReady: PublishChallengeAnswers = async (challeng
3636
throw Error(`can't call publishChallengeAnswers() before result.challenge is defined (before the challenge message is received)`)
3737
}
3838

39+
function useIframeChallengeAutoAnswer(challenge: Challenge | undefined, publishChallengeAnswers: PublishChallengeAnswers | undefined) {
40+
const iframeChallengeUrl = challenge?.challenges?.find((c) => c.type === 'url/iframe')?.challenge
41+
42+
useEffect(() => {
43+
if (!iframeChallengeUrl || !publishChallengeAnswers) return
44+
45+
let iframeOrigin: string | undefined
46+
try {
47+
iframeOrigin = new URL(iframeChallengeUrl).origin
48+
} catch (e) {}
49+
50+
const handleMessage = (event: MessageEvent) => {
51+
if (iframeOrigin && event.origin !== iframeOrigin) return
52+
if (event.data?.type === 'challengeAnswer' && Array.isArray(event.data.challengeAnswers)) {
53+
publishChallengeAnswers(event.data.challengeAnswers)
54+
}
55+
}
56+
window.addEventListener('message', handleMessage)
57+
return () => window.removeEventListener('message', handleMessage)
58+
}, [iframeChallengeUrl, publishChallengeAnswers])
59+
}
60+
3961
export function useSubscribe(options?: UseSubscribeOptions): UseSubscribeResult {
4062
assert(!options || typeof options === 'object', `useSubscribe options argument '${options}' not an object`)
4163
const {subplebbitAddress, accountName, onError} = options || {}
@@ -155,6 +177,7 @@ export function usePublishComment(options?: UsePublishCommentOptions): UsePublis
155177
const [challenge, setChallenge] = useState<Challenge>()
156178
const [challengeVerification, setChallengeVerification] = useState<ChallengeVerification>()
157179
const [publishChallengeAnswers, setPublishChallengeAnswers] = useState<PublishChallengeAnswers>()
180+
useIframeChallengeAutoAnswer(challenge, publishChallengeAnswers)
158181

159182
let initialState = 'initializing'
160183
// before the accountId and options is defined, nothing can happen
@@ -228,6 +251,7 @@ export function usePublishVote(options?: UsePublishVoteOptions): UsePublishVoteR
228251
const [challenge, setChallenge] = useState<Challenge>()
229252
const [challengeVerification, setChallengeVerification] = useState<ChallengeVerification>()
230253
const [publishChallengeAnswers, setPublishChallengeAnswers] = useState<PublishChallengeAnswers>()
254+
useIframeChallengeAutoAnswer(challenge, publishChallengeAnswers)
231255

232256
let initialState = 'initializing'
233257
// before the accountId and options is defined, nothing can happen
@@ -299,6 +323,7 @@ export function usePublishCommentEdit(options?: UsePublishCommentEditOptions): U
299323
const [challenge, setChallenge] = useState<Challenge>()
300324
const [challengeVerification, setChallengeVerification] = useState<ChallengeVerification>()
301325
const [publishChallengeAnswers, setPublishChallengeAnswers] = useState<PublishChallengeAnswers>()
326+
useIframeChallengeAutoAnswer(challenge, publishChallengeAnswers)
302327

303328
let initialState = 'initializing'
304329
// before the accountId and options is defined, nothing can happen
@@ -370,6 +395,7 @@ export function usePublishCommentModeration(options?: UsePublishCommentModeratio
370395
const [challenge, setChallenge] = useState<Challenge>()
371396
const [challengeVerification, setChallengeVerification] = useState<ChallengeVerification>()
372397
const [publishChallengeAnswers, setPublishChallengeAnswers] = useState<PublishChallengeAnswers>()
398+
useIframeChallengeAutoAnswer(challenge, publishChallengeAnswers)
373399

374400
let initialState = 'initializing'
375401
// before the accountId and options is defined, nothing can happen
@@ -441,6 +467,7 @@ export function usePublishSubplebbitEdit(options?: UsePublishSubplebbitEditOptio
441467
const [challenge, setChallenge] = useState<Challenge>()
442468
const [challengeVerification, setChallengeVerification] = useState<ChallengeVerification>()
443469
const [publishChallengeAnswers, setPublishChallengeAnswers] = useState<PublishChallengeAnswers>()
470+
useIframeChallengeAutoAnswer(challenge, publishChallengeAnswers)
444471

445472
let initialState = 'initializing'
446473
// before the accountId and options is defined, nothing can happen

0 commit comments

Comments
 (0)