diff --git a/apps/web/helpers/__tests__/createServerSideProps.test.ts b/apps/web/helpers/__tests__/createServerSideProps.test.ts index 200a7665b935989fd7b96479cb73c3bda390c28e..0614ee2e22e9d1153d53727e6b82dd56477aa081 100644 --- a/apps/web/helpers/__tests__/createServerSideProps.test.ts +++ b/apps/web/helpers/__tests__/createServerSideProps.test.ts @@ -88,7 +88,7 @@ describe('createServerSideProps', () => { }, } - type UserType = 'loggedIn' | 'incompleteAccount' | 'guest' | 'newUser' + type UserType = 'loggedIn' | 'incompleteAccount' | 'guest' | 'newUser' | 'bot' const setupAndCreateContextForUser = (userContextType: UserType, requestOverrides = {}): PageContext => { const userData = userContextType === 'loggedIn' @@ -102,6 +102,7 @@ describe('createServerSideProps', () => { }) } const cookies = userContextType === 'guest' ? { [GUEST_MODE_COOKIE_NAME]: 'true' } : {} + const headers = userContextType === 'bot' ? { 'user-agent': 'bot' } : {} return { ...context, @@ -109,6 +110,7 @@ describe('createServerSideProps', () => { ...context.req, ...requestOverrides, cookies, + headers, }, } as unknown as PageContext } @@ -321,6 +323,14 @@ describe('createServerSideProps', () => { expect(new HoliPageProps(props).user).toEqual(guestUserProps) }) + it('should add guest user props if user is a bot', async () => { + const botContext = setupAndCreateContextForUser('bot') + + const props = await createServerSideProps(botContext) + + expect(new HoliPageProps(props).user).toEqual(guestUserProps) + }) + it('should add logged in user props if user is logged in with complete account', async () => { const userId = 'test-user-id' const expectedUserProps = { @@ -355,6 +365,10 @@ describe('createServerSideProps', () => { userType: 'guest', expectedRedirect: false, }, + { + userType: 'bot', + expectedRedirect: false, + }, ] it.each(testData)( 'should correctly handle onboarding redirect for user of type $userType', @@ -397,6 +411,10 @@ describe('createServerSideProps', () => { userType: 'guest', expectedRedirect: false, }, + { + userType: 'bot', + expectedRedirect: false, + }, ] it.each(testData)( 'should correctly handle redirect for logged in users if user is of type $userType', @@ -443,6 +461,10 @@ describe('createServerSideProps', () => { userType: 'guest', expectedRedirect: true, }, + { + userType: 'bot', + expectedRedirect: true, + }, ] it.each(testData)( 'should correctly handle redirect for logged out users if user is of type $userType', @@ -489,6 +511,10 @@ describe('createServerSideProps', () => { userType: 'guest', expectedRedirect: false, }, + { + userType: 'bot', + expectedRedirect: false, + }, ] it.each(testData)( 'should correctly handle redirect for new users if user is of type $userType', diff --git a/apps/web/helpers/createServerSideProps.ts b/apps/web/helpers/createServerSideProps.ts index 8fbc5064e0ebd1bcc60f64e7d6172567cf4ef8a6..05559bdf7339a0f302299096ac9411ab57c950b0 100644 --- a/apps/web/helpers/createServerSideProps.ts +++ b/apps/web/helpers/createServerSideProps.ts @@ -20,9 +20,17 @@ interface SkippableQueryOptions extends QueryOptions { } type Cookies = { [key: string]: string } -export type PageContext = Omit<NextPageContext, 'req'> & { req: NextPageContext['req'] & { cookies: Cookies } } +type PageContextRequest = NextPageContext['req'] & { cookies: Cookies } +export type PageContext = Omit<NextPageContext, 'req'> & { req: PageContextRequest } -const createUserPageProps = (user: User | undefined, cookies: Cookies = {}): UserPageProps => { +// List of user agents substrings used by search engine crawlers and link preview bots (python-requests is used by Okuna) +const botUserAgents = ['bot', 'crawl', 'slurp', 'spider', 'facebookexternalhit', 'whatsapp', 'python-requests'] +const isBot = (headers: PageContextRequest['headers'] = {}) => + botUserAgents.some((userAgent) => headers['user-agent']?.toLowerCase().includes(userAgent)) + +const isGuestUser = (cookies: Cookies = {}) => !!cookies[GUEST_MODE_COOKIE_NAME] + +const createUserPageProps = (user: User | undefined, req: PageContextRequest): UserPageProps => { if (user?.id) { return { id: user.id, @@ -32,7 +40,7 @@ const createUserPageProps = (user: User | undefined, cookies: Cookies = {}): Use } return { isLoggedOut: true, - guestMode: !!cookies[GUEST_MODE_COOKIE_NAME], + guestMode: isGuestUser(req?.cookies) || isBot(req?.headers), } } @@ -90,7 +98,7 @@ export const createServerSideProps = async ( // Ignore failing user request silently const userQueryResult = await authenticatedUserPromise.catch() const userId = userQueryResult.data?.authenticatedUserV2?.id - const user = createUserPageProps(userQueryResult.data?.authenticatedUserV2, req?.cookies) + const user = createUserPageProps(userQueryResult.data?.authenticatedUserV2, req) const redirectDestination = handleLoginStateDependentRedirect(user, customProps)