Page MenuHomePhabricator

D10338.id37093.diff
No OneTemporary

D10338.id37093.diff

diff --git a/lib/actions/link-actions.js b/lib/actions/link-actions.js
--- a/lib/actions/link-actions.js
+++ b/lib/actions/link-actions.js
@@ -50,10 +50,12 @@
};
};
-function useVerifyInviteLink(keyserverOverride?: {
- +keyserverID: string,
- +keyserverURL: string,
-}): (
+function useVerifyInviteLink(
+ keyserverOverride?: ?{
+ +keyserverID: string,
+ +keyserverURL: string,
+ },
+): (
request: InviteLinkVerificationRequest,
) => Promise<InviteLinkVerificationResponse> {
const keyserverID = keyserverOverride?.keyserverID ?? ashoatKeyserverID;
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,36 @@
return `invite_${secret}`;
}
-export { inviteLinkErrorMessages, defaultErrorMessage, inviteLinkBlobHash };
+export type KeyserverOverride = {
+ +keyserverID: string,
+ +keyserverURL: string,
+};
+
+async function getKeyserverOverrideForAnInviteLink(
+ secret: string,
+): Promise<?KeyserverOverride> {
+ const blobURL = getBlobFetchableURL(inviteLinkBlobHash(secret));
+ const result = await fetch(blobURL, {
+ method: blobService.httpEndpoints.GET_BLOB.method,
+ });
+ if (result.status !== 200) {
+ return null;
+ }
+ const resultText = await result.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,8 @@
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 { KeyserverOverride } from 'lib/shared/invite-links.js';
import type { SetState } from 'lib/types/hook-types.js';
import { useDispatchActionPromise } from 'lib/utils/redux-promise-utils.js';
@@ -79,9 +81,13 @@
}, []);
useOnFirstLaunchEffect('ANDROID_REFERRER', checkInstallReferrer);
+ const [keyserverOverride, setKeyserverOverride] =
+ React.useState<?KeyserverOverride>(undefined);
+ const inviteLinkSecret = React.useRef<?string>(null);
+
const loggedIn = useSelector(isLoggedIn);
const dispatchActionPromise = useDispatchActionPromise();
- const validateLink = useVerifyInviteLink();
+ const validateLink = useVerifyInviteLink(keyserverOverride);
const navigation = useNavigation();
React.useEffect(() => {
void (async () => {
@@ -91,6 +97,8 @@
// We're setting this to null so that we ensure that each link click
// results in at most one validation and navigation.
setCurrentLink(null);
+ setKeyserverOverride(undefined);
+ inviteLinkSecret.current = null;
const parsedData: ParsedDeepLinkData = parseDataFromDeepLink(currentLink);
if (!parsedData) {
@@ -99,28 +107,64 @@
if (parsedData.type === 'invite-link') {
const { secret } = parsedData.data;
+ inviteLinkSecret.current = secret;
+ try {
+ const newKeyserverOverride =
+ await getKeyserverOverrideForAnInviteLink(secret);
+ setKeyserverOverride(newKeyserverOverride);
+ } catch (e) {
+ console.log('Error while downloading an invite link blob', e);
+ navigation.navigate<'InviteLinkModal'>({
+ name: InviteLinkModalRouteName,
+ params: {
+ invitationDetails: {
+ status: 'invalid',
+ },
+ secret,
+ },
+ });
+ }
+ } else if (parsedData.type === 'qr-code') {
+ navigation.navigate(SecondaryDeviceQRCodeScannerRouteName);
+ }
+ })();
+ }, [currentLink, loggedIn, navigation]);
+
+ React.useEffect(() => {
+ const secret = inviteLinkSecret.current;
+ if (keyserverOverride === undefined || !secret) {
+ return;
+ }
+ setKeyserverOverride(undefined);
+
+ void (async () => {
+ let result;
+ try {
const validateLinkPromise = validateLink({ secret });
void dispatchActionPromise(
verifyInviteLinkActionTypes,
validateLinkPromise,
);
- const result = await validateLinkPromise;
+ result = await validateLinkPromise;
if (result.status === 'already_joined') {
return;
}
-
- navigation.navigate<'InviteLinkModal'>({
- name: InviteLinkModalRouteName,
- params: {
- invitationDetails: result,
- secret,
- },
- });
- } else if (parsedData.type === 'qr-code') {
- navigation.navigate(SecondaryDeviceQRCodeScannerRouteName);
+ } catch (e) {
+ console.log(e);
+ result = {
+ status: 'invalid',
+ };
}
+
+ navigation.navigate<'InviteLinkModal'>({
+ name: InviteLinkModalRouteName,
+ params: {
+ invitationDetails: result,
+ secret,
+ },
+ });
})();
- }, [currentLink, dispatchActionPromise, loggedIn, navigation, validateLink]);
+ }, [dispatchActionPromise, keyserverOverride, navigation, validateLink]);
const contextValue = React.useMemo(
() => ({
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,8 @@
} 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 type { KeyserverOverride } from 'lib/shared/invite-links.js';
import { useDispatchActionPromise } from 'lib/utils/redux-promise-utils.js';
import { useDispatch } from 'lib/utils/redux-utils.js';
@@ -17,45 +19,80 @@
function InviteLinkHandler(): null {
const inviteSecret = useSelector(state => state.navInfo.inviteSecret);
+ const inviteLinkSecret = React.useRef<?string>(null);
+ const [keyserverOverride, setKeyserverOverride] =
+ React.useState<?KeyserverOverride>(undefined);
const loggedIn = useSelector(isLoggedIn);
const dispatchActionPromise = useDispatchActionPromise();
const dispatch = useDispatch();
- const validateLink = useVerifyInviteLink();
const { pushModal } = useModalContext();
React.useEffect(() => {
- if (!inviteSecret || !loggedIn) {
+ void (async () => {
+ if (!inviteSecret || !loggedIn) {
+ return;
+ }
+ dispatch({
+ type: updateNavInfoActionType,
+ payload: { inviteSecret: null },
+ });
+ setKeyserverOverride(undefined);
+ inviteLinkSecret.current = inviteSecret;
+
+ try {
+ const newKeyserverOverride =
+ await getKeyserverOverrideForAnInviteLink(inviteSecret);
+ setKeyserverOverride(newKeyserverOverride);
+ } catch (e) {
+ console.error('Error while downloading an invite link blob', e);
+ pushModal(
+ <AcceptInviteModal
+ verificationResponse={{
+ status: 'invalid',
+ }}
+ inviteSecret={inviteSecret}
+ />,
+ );
+ }
+ })();
+ }, [dispatch, inviteSecret, loggedIn, pushModal]);
+
+ const validateLink = useVerifyInviteLink(keyserverOverride);
+ React.useEffect(() => {
+ const secret = inviteLinkSecret.current;
+ if (keyserverOverride === undefined || !secret) {
return;
}
- dispatch({
- type: updateNavInfoActionType,
- payload: { inviteSecret: null },
- });
- const validateLinkPromise = validateLink({ secret: inviteSecret });
- void dispatchActionPromise(
- verifyInviteLinkActionTypes,
- validateLinkPromise,
- );
+ setKeyserverOverride(undefined);
+
void (async () => {
- const result = await validateLinkPromise;
- if (result.status === 'already_joined') {
- return;
+ let result;
+ try {
+ const validateLinkPromise = validateLink({ secret });
+ void dispatchActionPromise(
+ verifyInviteLinkActionTypes,
+ validateLinkPromise,
+ );
+
+ result = await validateLinkPromise;
+ if (result.status === 'already_joined') {
+ return;
+ }
+ } catch (e) {
+ console.error('Error while verifying an invite link', e);
+ result = {
+ status: 'invalid',
+ };
}
+
pushModal(
<AcceptInviteModal
verificationResponse={result}
- inviteSecret={inviteSecret}
+ inviteSecret={secret}
/>,
);
})();
- }, [
- dispatch,
- dispatchActionPromise,
- inviteSecret,
- loggedIn,
- pushModal,
- validateLink,
- ]);
+ }, [dispatchActionPromise, keyserverOverride, pushModal, validateLink]);
return null;
}

File Metadata

Mime Type
text/plain
Expires
Tue, Dec 24, 5:39 AM (18 h, 45 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2698533
Default Alt Text
D10338.id37093.diff (9 KB)

Event Timeline