diff --git a/lib/shared/invite-links.js b/lib/shared/invite-links.js --- a/lib/shared/invite-links.js +++ b/lib/shared/invite-links.js @@ -1,5 +1,8 @@ // @flow +import blobService from '../facts/blob-service.js'; +import { getBlobFetchableURL } from '../utils/blob-service.js'; + const inviteLinkErrorMessages: { +[string]: string } = { invalid_characters: 'Link cannot contain any spaces or special characters.', offensive_words: 'No offensive or abusive words allowed.', @@ -15,4 +18,40 @@ return `invite_${secret}`; } -export { inviteLinkErrorMessages, defaultErrorMessage, inviteLinkBlobHash }; +export type KeyserverOverride = { + +keyserverID: string, + +keyserverURL: string, +}; + +async function getKeyserverOverrideForAnInviteLink( + secret: string, +): Promise { + const blobURL = getBlobFetchableURL(inviteLinkBlobHash(secret)); + const result = await fetch(blobURL, { + method: blobService.httpEndpoints.GET_BLOB.method, + headers: { + 'content-type': 'application/json', + }, + }); + if (result.status !== 200) { + return null; + } + const resultBlob = await result.blob(); + const resultText = await resultBlob.text(); + const resultObject = JSON.parse(resultText); + if (resultObject.keyserverID && resultObject.keyserverURL) { + const keyserverURL: string = resultObject.keyserverURL; + return { + keyserverID: resultObject.keyserverID, + keyserverURL: keyserverURL.replace(/\/$/, ''), + }; + } + return null; +} + +export { + inviteLinkErrorMessages, + defaultErrorMessage, + inviteLinkBlobHash, + getKeyserverOverrideForAnInviteLink, +}; diff --git a/native/navigation/deep-links-context-provider.react.js b/native/navigation/deep-links-context-provider.react.js --- a/native/navigation/deep-links-context-provider.react.js +++ b/native/navigation/deep-links-context-provider.react.js @@ -15,6 +15,7 @@ type ParsedDeepLinkData, } from 'lib/facts/links.js'; import { isLoggedIn } from 'lib/selectors/user-selectors.js'; +import { getKeyserverOverrideForAnInviteLink } from 'lib/shared/invite-links.js'; import type { SetState } from 'lib/types/hook-types.js'; import { useDispatchActionPromise } from 'lib/utils/action-utils.js'; @@ -99,14 +100,28 @@ if (parsedData.type === 'invite-link') { const { secret } = parsedData.data; - const validateLinkPromise = validateLink({ secret }); - void dispatchActionPromise( - verifyInviteLinkActionTypes, - validateLinkPromise, - ); - const result = await validateLinkPromise; - if (result.status === 'already_joined') { - return; + let result; + try { + const keyserverOverride = await getKeyserverOverrideForAnInviteLink( + secret, + ); + const validateLinkPromise = validateLink( + { secret }, + keyserverOverride, + ); + void dispatchActionPromise( + verifyInviteLinkActionTypes, + validateLinkPromise, + ); + result = await validateLinkPromise; + if (result.status === 'already_joined') { + return; + } + } catch (e) { + console.log(e); + result = { + status: 'invalid', + }; } navigation.navigate<'InviteLinkModal'>({ diff --git a/web/invite-links/invite-link-handler.react.js b/web/invite-links/invite-link-handler.react.js --- a/web/invite-links/invite-link-handler.react.js +++ b/web/invite-links/invite-link-handler.react.js @@ -8,6 +8,7 @@ } from 'lib/actions/link-actions.js'; import { useModalContext } from 'lib/components/modal-provider.react.js'; import { isLoggedIn } from 'lib/selectors/user-selectors.js'; +import { getKeyserverOverrideForAnInviteLink } from 'lib/shared/invite-links.js'; import { useDispatchActionPromise } from 'lib/utils/action-utils.js'; import { useDispatch } from 'lib/utils/redux-utils.js'; @@ -24,23 +25,40 @@ const validateLink = useVerifyInviteLink(); const { pushModal } = useModalContext(); React.useEffect(() => { - if (!inviteSecret || !loggedIn) { - return; - } - dispatch({ - type: updateNavInfoActionType, - payload: { inviteSecret: null }, - }); - const validateLinkPromise = validateLink({ secret: inviteSecret }); - void dispatchActionPromise( - verifyInviteLinkActionTypes, - validateLinkPromise, - ); void (async () => { - const result = await validateLinkPromise; - if (result.status === 'already_joined') { + if (!inviteSecret || !loggedIn) { return; } + dispatch({ + type: updateNavInfoActionType, + payload: { inviteSecret: null }, + }); + + let result; + try { + const keyserverOverride = await getKeyserverOverrideForAnInviteLink( + inviteSecret, + ); + const validateLinkPromise = validateLink( + { secret: inviteSecret }, + keyserverOverride, + ); + void dispatchActionPromise( + verifyInviteLinkActionTypes, + validateLinkPromise, + ); + + result = await validateLinkPromise; + if (result.status === 'already_joined') { + return; + } + } catch (e) { + console.error(e); + result = { + status: 'invalid', + }; + } + pushModal(