diff --git a/keyserver/src/services/blob.js b/keyserver/src/services/blob.js --- a/keyserver/src/services/blob.js +++ b/keyserver/src/services/blob.js @@ -107,8 +107,11 @@ const headers = await createRequestHeaders(); const blobResult = await downloadBlob(hash, headers); - if (blobResult.result !== 'success') { + if (blobResult.result === 'error') { return { found: false, status: blobResult.status }; + } else if (blobResult.result === 'invalid_csat') { + await clearIdentityInfo(); + return { found: false, status: 401 }; } const blob = await blobResult.response.blob(); return { found: true, blob }; diff --git a/lib/components/base-auto-join-community-handler.react.js b/lib/components/base-auto-join-community-handler.react.js --- a/lib/components/base-auto-join-community-handler.react.js +++ b/lib/components/base-auto-join-community-handler.react.js @@ -5,6 +5,7 @@ import * as React from 'react'; import { NeynarClientContext } from './neynar-client-provider.react.js'; +import { useInvalidCSATLogOut } from '../actions/user-actions.js'; import { useIsLoggedInToIdentityAndAuthoritativeKeyserver } from '../hooks/account-hooks.js'; import { extractKeyserverIDFromID } from '../keyserver-conn/keyserver-call-utils.js'; import { @@ -80,6 +81,8 @@ const prevCanQueryRef = React.useRef(); const canQuery = loggedIn && !!fid; + const invalidTokenLogOut = useInvalidCSATLogOut(); + React.useEffect(() => { if (canQuery === prevCanQueryRef.current) { return; @@ -127,6 +130,9 @@ const blobHash = farcasterChannelTagBlobHash(channelID); const blobResult = await downloadBlob(blobHash, headers); if (blobResult.result !== 'success') { + if (blobResult.result === 'invalid_csat') { + void invalidTokenLogOut(); + } return null; } @@ -180,6 +186,7 @@ getAuthMetadata, keyserverInfos, canQuery, + invalidTokenLogOut, ]); const potentiallyIncrementBatch: ( 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 @@ -22,8 +22,10 @@ : {}; const blobResult = await downloadBlob(inviteLinkBlobHash(secret), headers); - if (blobResult.result !== 'success') { + if (blobResult.result === 'error') { return null; + } else if (blobResult.result === 'invalid_csat') { + throw new Error('invalid_csat'); } const resultText = await blobResult.response.text(); diff --git a/lib/utils/blob-service.js b/lib/utils/blob-service.js --- a/lib/utils/blob-service.js +++ b/lib/utils/blob-service.js @@ -87,6 +87,7 @@ export type BlobDownloadResult = | { +result: 'success', response: Response } + | { +result: 'invalid_csat' } | { +result: 'error', +status: number, +statusText: string }; async function downloadBlob( @@ -100,7 +101,9 @@ headers, }); - if (response.status !== 200) { + if (httpResponseIsInvalidCSAT(response)) { + return { result: 'invalid_csat' }; + } else if (response.status !== 200) { const { status, statusText } = response; return { result: 'error', status, statusText }; } 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 @@ -10,6 +10,7 @@ useVerifyInviteLink, verifyInviteLinkActionTypes, } from 'lib/actions/link-actions.js'; +import { useInvalidCSATLogOut } from 'lib/actions/user-actions.js'; import { parseInstallReferrerFromInviteLinkURL, parseDataFromDeepLink, @@ -20,6 +21,7 @@ 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 { getMessageForException } from 'lib/utils/errors.js'; import { useDispatchActionPromise } from 'lib/utils/redux-promise-utils.js'; import { usingCommServicesAccessToken } from 'lib/utils/services-utils.js'; @@ -92,6 +94,7 @@ invariant(identityContext, 'Identity context should be set'); const { getAuthMetadata } = identityContext; + const invalidTokenLogOut = useInvalidCSATLogOut(); const loggedIn = useSelector(isLoggedIn); const dispatchActionPromise = useDispatchActionPromise(); const validateLink = useVerifyInviteLink(keyserverOverride); @@ -125,6 +128,10 @@ await getKeyserverOverrideForAnInviteLink(secret, authMetadata); setKeyserverOverride(newKeyserverOverride); } catch (e) { + if (getMessageForException(e) === 'invalid_csat') { + void invalidTokenLogOut(); + return; + } console.log('Error while downloading an invite link blob', e); navigation.navigate<'InviteLinkModal'>({ name: InviteLinkModalRouteName, @@ -140,7 +147,7 @@ navigation.navigate(SecondaryDeviceQRCodeScannerRouteName); } })(); - }, [currentLink, getAuthMetadata, loggedIn, navigation]); + }, [currentLink, getAuthMetadata, loggedIn, navigation, invalidTokenLogOut]); React.useEffect(() => { const secret = inviteLinkSecret.current; 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 @@ -7,6 +7,7 @@ useVerifyInviteLink, verifyInviteLinkActionTypes, } from 'lib/actions/link-actions.js'; +import { useInvalidCSATLogOut } from 'lib/actions/user-actions.js'; import { useModalContext } from 'lib/components/modal-provider.react.js'; import { threadInfoSelector } from 'lib/selectors/thread-selectors.js'; import { isLoggedIn } from 'lib/selectors/user-selectors.js'; @@ -15,6 +16,7 @@ getKeyserverOverrideForAnInviteLink, type KeyserverOverride, } from 'lib/shared/invite-links.js'; +import { getMessageForException } from 'lib/utils/errors.js'; import { useDispatchActionPromise } from 'lib/utils/redux-promise-utils.js'; import { useDispatch } from 'lib/utils/redux-utils.js'; import { usingCommServicesAccessToken } from 'lib/utils/services-utils.js'; @@ -34,6 +36,7 @@ invariant(identityContext, 'Identity context should be set'); const { getAuthMetadata } = identityContext; + const invalidTokenLogOut = useInvalidCSATLogOut(); const dispatchActionPromise = useDispatchActionPromise(); const dispatch = useDispatch(); const { pushModal } = useModalContext(); @@ -61,6 +64,10 @@ ); setKeyserverOverride(newKeyserverOverride); } catch (e) { + if (getMessageForException(e) === 'invalid_csat') { + void invalidTokenLogOut(); + return; + } console.error('Error while downloading an invite link blob', e); pushModal(