Skip to content

Commit

Permalink
fix: if access hidden note when loggin
Browse files Browse the repository at this point in the history
Signed-off-by: Innei <i@innei.in>
  • Loading branch information
Innei committed Apr 11, 2024
1 parent 158f30b commit 787c7e7
Show file tree
Hide file tree
Showing 17 changed files with 118 additions and 70 deletions.
11 changes: 6 additions & 5 deletions next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@ if (repoInfo) {
/** @type {import('next').NextConfig} */
// eslint-disable-next-line import/no-mutable-exports
let nextConfig = {
logging: {
fetches: {
fullUrl: true,
},
},
// logging: {
// fetches: {

// // fullUrl: true,
// },
// },
env: {
APP_VERSION: pkg.version,
COMMIT_HASH: commitHash,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { Metadata } from 'next'

import { QueryHydrate } from '~/components/common/QueryHydrate'
import { NormalContainer } from '~/components/layout/container/Normal'
import { attachUAAndRealIp } from '~/lib/attach-ua'
import { attachServerFetch } from '~/lib/attach-ua'
import { isShallowEqualArray } from '~/lib/lodash'
import { getQueryClient } from '~/lib/query-client.server'
import { definePrerenderPage } from '~/lib/request.server'
Expand All @@ -16,7 +16,7 @@ export const generateMetadata = async (
slug: string
}>,
) => {
attachUAAndRealIp()
attachServerFetch()
const queryClient = getQueryClient()

const query = getTopicQuery(props.params.slug)
Expand Down
4 changes: 2 additions & 2 deletions src/app/(app)/(page-detail)/[slug]/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
BottomToUpTransitionView,
} from '~/components/ui/transition'
import { OnlyMobile } from '~/components/ui/viewport/OnlyMobile'
import { attachUAAndRealIp } from '~/lib/attach-ua'
import { attachServerFetch } from '~/lib/attach-ua'
import { getOgUrl } from '~/lib/helper.server'
import { getSummaryFromMd } from '~/lib/markdown'
import { apiClient } from '~/lib/request'
Expand All @@ -33,7 +33,7 @@ import {

export const dynamic = 'force-dynamic'
const getData = cache(async (params: PageParams) => {
attachUAAndRealIp()
attachServerFetch()
const data = await apiClient.page
.getBySlug(params.slug)
.catch(requestErrorHandler)
Expand Down
4 changes: 2 additions & 2 deletions src/app/(app)/api.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import type { AggregateRoot } from '@mx-space/api-client'
import { simpleCamelcaseKeys } from '@mx-space/api-client'

import { appStaticConfig } from '~/app.static.config'
import { attachUAAndRealIp } from '~/lib/attach-ua'
import { attachServerFetch } from '~/lib/attach-ua'
import { getQueryClient } from '~/lib/query-client.server'
import { apiClient } from '~/lib/request'

const cacheTime = appStaticConfig.cache.enabled
? appStaticConfig.cache.ttl.aggregation
: 1
export const fetchAggregationData = cache(async () => {
attachUAAndRealIp()
attachServerFetch()
const queryClient = getQueryClient()
const fetcher = async () =>
(await $fetch<
Expand Down
4 changes: 2 additions & 2 deletions src/app/(app)/categories/[slug]/api.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { cache } from 'react'

import { attachUAAndRealIp } from '~/lib/attach-ua'
import { attachServerFetch } from '~/lib/attach-ua'
import { apiClient } from '~/lib/request'
import { requestErrorHandler } from '~/lib/request.server'

export const getData = cache(async (params: { slug: string }) => {
attachUAAndRealIp()
attachServerFetch()
return await apiClient.category
.getCategoryByIdOrSlug(params.slug)
.catch(requestErrorHandler)
Expand Down
7 changes: 5 additions & 2 deletions src/app/(app)/notes/[id]/api.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,22 @@ import { cache } from 'react'
import { headers } from 'next/dist/client/components/headers'

import { REQUEST_QUERY } from '~/constants/system'
import { attachUAAndRealIp } from '~/lib/attach-ua'
import { attachServerFetch } from '~/lib/attach-ua'
import { getQueryClient } from '~/lib/query-client.server'
import { requestErrorHandler } from '~/lib/request.server'
import { queries } from '~/queries/definition'

export const getData = cache(async (params: { id: string }) => {
attachUAAndRealIp()
attachServerFetch()

const header = headers()
const searchParams = new URLSearchParams(header.get(REQUEST_QUERY) || '')
const id = params.id
const token = searchParams.get('token')
const query = queries.note.byNid(
id,
searchParams.get('password') || undefined,
token ? `${token}` : undefined,
)
const data = await getQueryClient()
.fetchQuery(query)
Expand Down
11 changes: 10 additions & 1 deletion src/app/(app)/notes/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ import {
NoteMetaReadingCount,
NoteTopic,
} from '~/components/modules/note'
import { NoteRootBanner } from '~/components/modules/note/NoteBanner'
import {
NoteBanner,
NoteRootBanner,
} from '~/components/modules/note/NoteBanner'
import { ArticleRightAside } from '~/components/modules/shared/ArticleRightAside'
import { BanCopyWrapper } from '~/components/modules/shared/BanCopyWrapper'
import { ReadIndicatorForMobile } from '~/components/modules/shared/ReadIndicator'
Expand Down Expand Up @@ -59,6 +62,12 @@ export default async function Page(props: {
</ClientOnly>
</span>
<NoteRootBanner />
{data.hide && (
<NoteBanner
type="warning"
message="这篇文章是非公开的,仅登录可见"
/>
)}
</header>

<NoteHideIfSecret>
Expand Down
51 changes: 21 additions & 30 deletions src/app/(app)/notes/page.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,24 @@
'use client'
import { cookies } from 'next/headers'
import { redirect } from 'next/navigation'

import { useQuery } from '@tanstack/react-query'
import { useEffect } from 'react'
import { useRouter } from 'next/navigation'

import { FullPageLoading } from '~/components/ui/loading'
import { attachServerFetchAuth, detachServerFetchAuth } from '~/lib/attach-ua'
import { AuthKeyNames } from '~/lib/cookie'
import { apiClient } from '~/lib/request'
import { definePrerenderPage } from '~/lib/request.server'

export default function Page() {
const {
data: nid,
isError,
isLoading,
} = useQuery({
queryFn: async () => {
return apiClient.note.getLatest()
},
queryKey: ['note-latest'],
select(data) {
return data.data.nid
},
})

const router = useRouter()
useEffect(() => {
if (!nid) return

router.replace(`/notes/${nid}`)
}, [nid, router])

return <FullPageLoading />
}
export default definePrerenderPage()({
async fetcher() {
attachServerFetchAuth()
const { data } = await apiClient.note.getLatest()
detachServerFetchAuth()
return data
},
Component: ({ data: { nid, hide } }) => {
const jwt = cookies().get(AuthKeyNames[0])?.value
if (hide) {
return redirect(`/notes/${nid}?token=${jwt}`)
} else {
redirect(`/notes/${nid}`)
}
},
})
4 changes: 2 additions & 2 deletions src/app/(app)/posts/(post-detail)/[category]/[slug]/api.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { cache } from 'react'

import { attachUAAndRealIp } from '~/lib/attach-ua'
import { attachServerFetch } from '~/lib/attach-ua'
import { getQueryClient } from '~/lib/query-client.server'
import { requestErrorHandler } from '~/lib/request.server'
import { queries } from '~/queries/definition'
Expand All @@ -11,7 +11,7 @@ export interface PageParams {
}
export const getData = cache(async (params: PageParams) => {
const { category, slug } = params
attachUAAndRealIp()
attachServerFetch()
const data = await getQueryClient()
.fetchQuery(queries.post.bySlug(category, slug))
.catch(requestErrorHandler)
Expand Down
4 changes: 2 additions & 2 deletions src/app/(app)/timeline/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { TimelineType } from '@mx-space/api-client'
import { QueryHydrate } from '~/components/common/QueryHydrate'
import { SearchFAB } from '~/components/modules/shared/SearchFAB'
import { REQUEST_QUERY } from '~/constants/system'
import { attachUAAndRealIp } from '~/lib/attach-ua'
import { attachServerFetch } from '~/lib/attach-ua'
import { getQueryClient } from '~/lib/query-client.server'
import { apiClient } from '~/lib/request'

Expand All @@ -16,7 +16,7 @@ export const metadata = {
}
export const dynamic = 'force-dynamic'
export default async (props: PropsWithChildren) => {
attachUAAndRealIp()
attachServerFetch()
const header = headers()
const query = header.get(REQUEST_QUERY)

Expand Down
18 changes: 13 additions & 5 deletions src/components/modules/note/NoteBanner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const useNoteBanner = () => {
const meta = useCurrentNoteDataSelector((n) => n?.data.meta)

let banner = meta?.banner as {
type: string
type: keyof typeof bannerClassNames
message: string
className: string
style?: any
Expand All @@ -31,7 +31,7 @@ const useNoteBanner = () => {
type: 'info',
message: banner,
className: bannerClassNames.info,
}
} as any
}
banner = { ...banner }
banner.type ??= 'info'
Expand All @@ -47,20 +47,28 @@ export const NoteRootBanner = () => {
if (!banner) return null

return (
<div className="mx-[var(--padding-h)] mb-4 mt-8 text-sm">
<div className="mx-[var(--padding-h)] mb-4 mt-8">
<NoteBanner {...banner} />
</div>
)
}

export const NoteBanner: FC<{
style?: any
className: string
className?: string
message: string
type?: keyof typeof bannerClassNames
}> = (banner) => {
return (
<div
className={clsxm('flex justify-center p-4 leading-8', banner.className)}
className={clsxm(
'mt-4 flex justify-center p-4 text-base leading-8',
'lg:-ml-12 lg:w-[calc(100%+6rem)]',
'-ml-4 w-[calc(100%+2rem)]',

bannerClassNames[banner.type as keyof typeof bannerClassNames],
banner.className,
)}
style={banner.style}
>
{banner.message}
Expand Down
20 changes: 18 additions & 2 deletions src/lib/attach-ua.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { headers } from 'next/headers'
import { cookies, headers } from 'next/headers'

import PKG from '../../package.json'
import { AuthKeyNames } from './cookie'
import { attachFetchHeader } from './request'

export const attachUAAndRealIp = () => {
export const attachServerFetch = () => {
const { get } = headers()

const ua = get('user-agent')
Expand All @@ -22,3 +23,18 @@ export const attachUAAndRealIp = () => {
`${ua} NextJS/v${PKG.dependencies.next} ${PKG.name}/${PKG.version}`,
)
}

export const attachServerFetchAuth = () => {
const cookie = cookies()
const jwt = cookie.get(AuthKeyNames[0])

if (jwt) {
attachFetchHeader('Authorization', `Bearer ${jwt.value}`)
} else {
attachFetchHeader('Authorization', '')
}
}

export const detachServerFetchAuth = () => {
attachFetchHeader('Authorization', null)
}
7 changes: 5 additions & 2 deletions src/lib/cookie.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import dayjs from 'dayjs'
import Cookies from 'js-cookie'

export const TokenKey = 'mx-token'
const TokenKey = 'mx-token'

const ClerkCookieKey = '__session'
export const AuthKeyNames = [TokenKey, ClerkCookieKey]

export function getToken(): string | null {
// FUCK clerk constants not export, and mark it internal and can not custom
// packages/backend/src/constants.ts
const clerkJwt = Cookies.get('__session')
const clerkJwt = Cookies.get(ClerkCookieKey)

const token = Cookies.get(TokenKey) || clerkJwt

Expand Down
4 changes: 2 additions & 2 deletions src/lib/define-metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type { Metadata } from 'next'
import { getQueryClient } from '~/lib/query-client.server'
import { queries } from '~/queries/definition'

import { attachUAAndRealIp } from './attach-ua'
import { attachServerFetch } from './attach-ua'

export const defineMetadata = <T extends Record<string, string>>(
fn: (
Expand All @@ -17,7 +17,7 @@ export const defineMetadata = <T extends Record<string, string>>(
const handler = async ({ params }: { params: T }): Promise<Metadata> => {
const getData = async () => {
const queryClient = getQueryClient()
attachUAAndRealIp()
attachServerFetch()
return await queryClient.fetchQuery({
...queries.aggregation.root(),
})
Expand Down
4 changes: 2 additions & 2 deletions src/lib/request.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { RequestError } from '@mx-space/api-client'
import { BizErrorPage } from '~/components/common/BizErrorPage'
import { NormalContainer } from '~/components/layout/container/Normal'

import { attachUAAndRealIp } from './attach-ua'
import { attachServerFetch } from './attach-ua'
import { getErrorMessageFromRequestError } from './request.shared'

export const requestErrorHandler = (error: Error | RequestError) => {
Expand Down Expand Up @@ -61,7 +61,7 @@ export const definePrerenderPage =
return async (props: any) => {
const { params, searchParams } = props as NextPageParams<Params, any>
try {
attachUAAndRealIp()
attachServerFetch()
const data = await fetcher({
...params,
...searchParams,
Expand Down
9 changes: 7 additions & 2 deletions src/lib/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const $fetch = createFetch({
if (token) {
headers['Authorization'] = `bearer ${token}`
}

headers['x-session-uuid'] =
globalThis?.sessionStorage?.getItem(uuidStorageKey) ?? uuid

Expand Down Expand Up @@ -100,9 +101,13 @@ export const apiClient = createClient(fetchAdapter)(API_URL, {
},
})

export const attachFetchHeader = (key: string, value: string) => {
export const attachFetchHeader = (key: string, value: string | null) => {
const original = globalConfigureHeader[key]
globalConfigureHeader[key] = value
if (value === null) {
delete globalConfigureHeader[key]
} else {
globalConfigureHeader[key] = value
}

return () => {
if (typeof original === 'undefined') {
Expand Down
Loading

0 comments on commit 787c7e7

Please sign in to comment.