Skip to content

Commit

Permalink
Protect private pages
Browse files Browse the repository at this point in the history
  • Loading branch information
backjonas authored and backkjon committed Aug 21, 2023
1 parent 342b1af commit a18eb66
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 61 deletions.
19 changes: 17 additions & 2 deletions .env.local.example
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,20 @@ NEXT_PUBLIC_BASE_URL=https://cms.tf.fi
# Google calendar id for events to be displayed
NEXT_PUBLIC_GOOGLE_CALENDAR_ID=''

# Google account credentials in JSON form for authenticating to google calendar API
GOOGLE_CREDS=''
# Google account credentials in JSON form for authenticating to google calendar & drive API
GOOGLE_CREDS=''

# Google account credentials for private drive API
GOOGLE_PRIVATE_CREDS=''

# Origin of the next app
NEXTAUTH_URL=http://localhost:3000
# Random secret, generate with openssl rand -base64 32
NEXTAUTH_SECRET=

# Client secret, defined in keycloak
KEYCLOAK_CLIENT_SECRET=
# Client id, defined in keycloak
KEYCLOAK_CLIENT_ID=strapi
# Full path to the keycloak issuer, including realm
KEYCLOAK_ISSUER=https://keycloak-provider/realms/some-realm
8 changes: 2 additions & 6 deletions components/Page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,7 @@ type PageProps = {
navbarLinks: NavbarLink[]
}

const Page: NextPage<PageProps> = ({
page,
navbarLinks,
logos,
}) => {
const Page: NextPage<PageProps> = ({ page, navbarLinks, logos }) => {
return (
<div className="bg-white">
<Header navbarLinks={navbarLinks} />
Expand All @@ -50,4 +46,4 @@ const Page: NextPage<PageProps> = ({
)
}

export default Page
export default Page
22 changes: 16 additions & 6 deletions lib/api/privatepage.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import qs from 'qs'
import { PageType } from '@models/page'
import { fetchCollection, fetchCollectionSingle } from '@lib/api/strapi'
import strapi from '@lib/api/strapi'

export async function fetchPrivatePage(
sessionToken: string,
slug?: string
): Promise<PageType | null> {
if (slug === undefined) return null
Expand All @@ -15,13 +16,22 @@ export async function fetchPrivatePage(
},
})

const res = await fetchCollectionSingle<PageType>('/private-pages', slug, {
query,
})
const res = await strapi.fetchCollectionSingle<PageType>(
'/private-pages',
slug,
{
query,
headers: { Authorization: `Bearer ${sessionToken}` },
}
)
return res?.data?.attributes ?? null
}

export async function fetchPrivatePages(): Promise<PageType[]> {
const res = await fetchCollection<PageType>('/private-pages')
export async function fetchPrivatePages(
sessionToken: string
): Promise<PageType[]> {
const res = await strapi.fetchCollection<PageType>('/private-pages', {
headers: { Authorization: `Bearer ${sessionToken}` },
})
return res?.data?.map((c) => c.attributes) ?? []
}
16 changes: 11 additions & 5 deletions lib/api/strapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export const API_URL = `${process.env.NEXT_PUBLIC_BASE_URL}/api`
export type StrapiFetchOptions = {
query?: string
url?: string
headers?: HeadersInit
}

export type SingleResponse<T> = {
Expand Down Expand Up @@ -69,7 +70,10 @@ async function fetchSingle<T>(
const url = options?.url ?? API_URL
const query = options?.query ?? ''

return fetchFromStrapi<T, SingleResponse<T>>(`${url}${path}?${query}`)
return fetchFromStrapi<T, SingleResponse<T>>(
`${url}${path}?${query}`,
options?.headers
)
}

async function fetchCollectionSingle<T>(
Expand All @@ -88,7 +92,8 @@ async function fetchCollectionSingle<T>(
})

const res = await fetchFromStrapi<T, CollectionResponse<T>>(
`${url}${path}?${query}&${slugQuery}`
`${url}${path}?${query}&${slugQuery}`,
options?.headers
)

if (!res?.data?.[0]) {
Expand All @@ -111,15 +116,16 @@ async function fetchCollection<T, P extends Pagination = PagePagination>(
: ''
const query = options?.query ?? ''
return fetchFromStrapi<T, CollectionResponse<T>>(
`${url}${path}?${query}&${paginationQuery}`
`${url}${path}?${query}&${paginationQuery}`,
options?.headers
)
}

async function fetchFromStrapi<
T,
S extends CollectionResponse<T> | SingleResponse<T>
>(url: string): Promise<StrapiResponse<T, S> | null> {
const res = await fetch(url)
>(url: string, headers?: HeadersInit): Promise<StrapiResponse<T, S> | null> {
const res = await fetch(url, { headers })
const json = (await res.json()) as StrapiResponse<T, S>
if (json.error !== undefined) {
console.error(`Error fetching ${url}: ${JSON.stringify(json.error)}`)
Expand Down
20 changes: 11 additions & 9 deletions pages/[category]/[contentPage].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,22 @@ type ContentPageProps = {
}

const ContentPage: NextPage<ContentPageProps> = (props) => {
return <Page {...props}/>
return <Page {...props} />
}

export const getStaticPaths: GetStaticPaths = async () => {
// Get all content pages
const contentPages = await fetchContentPages()

// Create a path for each page
const paths = contentPages.filter(category => category).map((contentpage) => ({
params: {
category: contentpage.category?.data.attributes.slug,
contentPage: contentpage.slug,
},
}))
const paths = contentPages
.filter((category) => category)
.map((contentpage) => ({
params: {
category: contentpage.category?.data.attributes.slug,
contentPage: contentpage.slug,
},
}))

return {
paths,
Expand All @@ -48,11 +50,11 @@ export const getStaticProps: GetStaticProps = async ({ params }) => {
params?.contentPage instanceof Array
? params?.contentPage[0]
: params?.contentPage
const contentPage = await fetchContentPage(slug)
const page = await fetchContentPage(slug)
const { logos, navbarLinks } = await getLayoutProps()
return {
props: {
contentPage,
page,
navbarLinks,
logos,
},
Expand Down
9 changes: 2 additions & 7 deletions pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import type { GetServerSideProps, NextPage } from 'next'
import type { GetStaticProps, NextPage } from 'next'
import Image from 'next/image'
import { getSession } from 'next-auth/react'
import { Session } from 'next-auth'
import { fetchEvents } from '@lib/api/event'
import { fetchHomepage } from '@lib/api/homepage'
import Column from '@components/Column'
Expand Down Expand Up @@ -80,9 +78,7 @@ const Home: NextPage<HomeProps> = ({
</>
)

export const getServerSideProps: GetServerSideProps<{
session: Session | null
}> = async (context) => {
export const getStaticProps: GetStaticProps = async () => {
const events = await fetchEvents(1)
const homepage = await fetchHomepage()
const navbarLinks = await fetchNavbar()
Expand All @@ -93,7 +89,6 @@ export const getServerSideProps: GetServerSideProps<{
events: events?.data ?? [],
logos: homepage?.footer?.nationlogos ?? [],
bannerImages: homepage?.banner?.bannerImages?.data ?? [],
session: await getSession(context),
},
}
}
Expand Down
56 changes: 30 additions & 26 deletions pages/medlem/[privatePage].tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { GetStaticPaths, GetStaticProps, NextPage } from 'next'
import { GetServerSideProps, NextPage } from 'next'
import { PageType } from '@models/page'
import { marked } from 'marked'
import { fetchPrivatePage, fetchPrivatePages } from '@lib/api/privatepage'
import { signIn } from 'next-auth/react'
import { useEffect } from 'react'
import { Session } from 'next-auth'
import { getSession } from 'next-auth/react'
import { fetchPrivatePage } from '@lib/api/privatepage'
import { NavbarLink } from '@lib/api/navbar'
import { NationLogo } from '@components/footer/Logos'
import { getLayoutProps } from '@utils/helpers'
Expand All @@ -19,41 +23,41 @@ type PrivatePageProps = {
page: PageType
logos: NationLogo[]
navbarLinks: NavbarLink[]
session: Session
}

const PrivatePage: NextPage<PrivatePageProps> = (props) => {
return <Page {...props}/>
}

export const getStaticPaths: GetStaticPaths = async () => {
// Get all content pages
const privatePages = await fetchPrivatePages()

// Create a path for each page
const paths = privatePages.map((page) => ({
params: {
privatePage: page.slug,
},
}))
const PrivatePage: NextPage<PrivatePageProps> = ({
session,
...props
}: PrivatePageProps) => {
// TODO: Fix login redirect flow
useEffect(() => {
if (!session) {
void signIn('keycloak')
}
}, [session])

return {
paths,
fallback: 'blocking',
}
// TODO: Return something meaningful instead.. maybe empty page contents?
return session ? <Page {...props} /> : <></>
}

export const getStaticProps: GetStaticProps = async ({ params }) => {
const slug =
params?.contentPage instanceof Array
? params?.contentPage[0]
: params?.contentPage
const page = await fetchPrivatePage(slug)
export const getServerSideProps: GetServerSideProps<{
session: Session | null
}> = async (context) => {
const query = context.query.privatePage
const slug = query instanceof Array ? query[0] : query
const session = await getSession(context)
// TODO: Fix types
const page = session?.jwt
? await fetchPrivatePage(session.jwt, slug)
: undefined
const { logos, navbarLinks } = await getLayoutProps()
return {
props: {
page,
navbarLinks,
logos,
session,
},
}
}
Expand Down

0 comments on commit a18eb66

Please sign in to comment.