Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom Domains for Territories #1958

Draft
wants to merge 44 commits into
base: master
Choose a base branch
from
Draft
Changes from 1 commit
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
bd72179
Middleware for Custom Domains; Sync auth if coming from main domain; …
Soxasora Mar 8, 2025
2acbb44
Middleware tweaks; TODOs
Soxasora Mar 9, 2025
fa3b9a2
Merge branch 'master' into custom_domain
Soxasora Mar 9, 2025
cada0ee
values from customDomain in Territory Edit, domain string validation
Soxasora Mar 9, 2025
7bb6166
Fetch and cache all verified domains; allow only verified domains
Soxasora Mar 9, 2025
003ebe9
wip Custom Domain form for Territory Edit; fix endpoint typo; upsert …
Soxasora Mar 9, 2025
a39e5b0
Merge branch 'master' into custom_domain
Soxasora Mar 10, 2025
c930106
fix Sorts active key; referrer cookies workaround; structure for terr…
Soxasora Mar 10, 2025
5072aa1
don't show territory selector; don't redirect to main domain
Soxasora Mar 10, 2025
04df5d5
consider referrer cookies
Soxasora Mar 10, 2025
f4f37c3
check validity of CNAME and TXT records via worker; clean sub-select;…
Soxasora Mar 11, 2025
cf27645
DNS Resolver env setting, fixes inconsistencies with results
Soxasora Mar 11, 2025
3ac04a6
custom domain form and validation; FAILED verification only if it was…
Soxasora Mar 11, 2025
2a9297d
fix form submit; update Sub onSubmit
Soxasora Mar 13, 2025
f959c7f
wip One-click single sign on
Soxasora Mar 13, 2025
3947ff8
Merge branch 'master' into custom_domain
Soxasora Mar 14, 2025
9552bf8
issue and check SSL with worker; refactor customDomain; early ACM imp…
Soxasora Mar 14, 2025
1d04948
adjust schema and worker validation
Soxasora Mar 15, 2025
d906afa
Merge branch 'master' into custom_domain
Soxasora Mar 16, 2025
25bafc0
switch to AWS localstack; mock ACM integration; add certificate DNS v…
Soxasora Mar 17, 2025
390a15d
Merge branch 'master' into custom_domain
Soxasora Mar 18, 2025
0c79d9f
consequential domain verification flow
Soxasora Mar 18, 2025
23bba32
poll every 30 seconds SSL and DNS verification states
Soxasora Mar 18, 2025
76df54a
refactor custom domain queries, todo dynamic callback for login
Soxasora Mar 19, 2025
6db07b8
fix login flow, temporarily disable auto-auth, fix OAuth login
Soxasora Mar 21, 2025
d4d2a70
Merge branch 'master' into custom_domain
Soxasora Mar 22, 2025
4d6d659
middleware multiAuth support, referrer redirect support
Soxasora Mar 23, 2025
81f1550
refetch and start polling on domain update; domain verification tweak…
Soxasora Mar 23, 2025
d26e6c1
check for allowed domain earlier; remove domain after 5 failed verifi…
Soxasora Mar 23, 2025
9fbf794
handle isCustomDomain server-level
Soxasora Mar 24, 2025
1dd2e58
use AccountProvider for sync signIn and multiAuth
Soxasora Mar 24, 2025
1508719
Merge branch 'master' into custom_domain
Soxasora Mar 24, 2025
bd78954
compose auth sync callback with search params
Soxasora Mar 24, 2025
413387d
add comments to domainVerification worker
Soxasora Mar 24, 2025
987245d
comments: middleware, domain verification worker
Soxasora Mar 25, 2025
f0649e8
comments: auth sync, domain mapper, login page; fix: multiAuth signup
Soxasora Mar 25, 2025
260c2e6
comments: territory domains edit, auth, small comments
Soxasora Mar 25, 2025
310e766
restore nav commons
Soxasora Mar 25, 2025
934fc3f
cleanup: territory domains
Soxasora Mar 25, 2025
46db09b
Merge branch 'master' into custom_domain
Soxasora Mar 25, 2025
7256701
move auth sync out of Account Provider; remove faq todo
Soxasora Mar 25, 2025
0abf460
Merge branch 'master' into custom_domain
Soxasora Mar 25, 2025
5b314aa
update isCustomDomain also on client side navigation
Soxasora Mar 26, 2025
cc334f4
allow only www or subdomains
Soxasora Mar 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Fetch and cache all verified domains; allow only verified domains
  • Loading branch information
Soxasora committed Mar 9, 2025
commit 7bb6166e27b135f17851e346eb864f19d1c062c4
37 changes: 26 additions & 11 deletions middleware.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { NextResponse, URLPattern } from 'next/server'
import { cachedFetcher } from '@/lib/fetch'
const referrerPattern = new URLPattern({ pathname: ':pathname(*)/r/:referrer([\\w_]+)' })
const itemPattern = new URLPattern({ pathname: '/items/:id(\\d+){/:other(\\w+)}?' })
const profilePattern = new URLPattern({ pathname: '/:name([\\w_]+){/:type(\\w+)}?' })
@@ -14,15 +15,29 @@ const SN_REFEREE_LANDING = 'sn_referee_landing'
const TERRITORY_PATHS = ['/~', '/recent', '/random', '/top', '/post', '/edit']
const NO_REWRITE_PATHS = ['/api', '/_next', '/_error', '/404', '/500', '/offline', '/static', '/items']

function getDomainMapping () {
// placeholder for cachedFetcher
return {
'forum.pizza.com': { subName: 'pizza' }
// placeholder for other domains
// fetch custom domain mappings from our API, caching it for 5 minutes
const getDomainMappingsCache = cachedFetcher(async function fetchDomainMappings () {
const url = `${process.env.NEXT_PUBLIC_URL}/api/domains/map`
try {
const response = await fetch(url)
if (!response.ok) {
console.error(`Cannot fetch domain mappings: ${response.status} ${response.statusText}`)
return null
}

const data = await response.json()
return Object.keys(data).length > 0 ? data : null
} catch (error) {
console.error('Cannot fetch domain mappings:', error)
return null
}
}
}, {
cacheExpiry: 300000, // 5 minutes cache
forceRefreshThreshold: 600000, // 10 minutes before force refresh
keyGenerator: () => 'domain_mappings'
})

export function customDomainMiddleware (request, referrerResp) {
export async function customDomainMiddleware (request, referrerResp) {
const host = request.headers.get('host')
const referer = request.headers.get('referer')
const url = request.nextUrl.clone()
@@ -33,8 +48,8 @@ export function customDomainMiddleware (request, referrerResp) {

console.log('referer', referer)

const domainMapping = getDomainMapping() // placeholder
const domainInfo = domainMapping[host.toLowerCase()]
const domainMapping = await getDomainMappingsCache()
const domainInfo = domainMapping?.[host.toLowerCase()]
if (!domainInfo) {
return NextResponse.redirect(new URL(pathname, mainDomain))
}
@@ -250,7 +265,7 @@ export function applySecurityHeaders (resp) {
return resp
}

export function middleware (request) {
export async function middleware (request) {
const host = request.headers.get('host')
const isCustomDomain = host !== process.env.NEXT_PUBLIC_URL.replace(/^https?:\/\//, '')

@@ -259,7 +274,7 @@ export function middleware (request) {

// If we're on a custom domain, handle that next
if (isCustomDomain) {
const customDomainResp = customDomainMiddleware(request, referrerResp)
const customDomainResp = await customDomainMiddleware(request, referrerResp)
return applySecurityHeaders(customDomainResp)
}

39 changes: 39 additions & 0 deletions pages/api/domains/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import prisma from '@/api/models'

// TODO: Authentication for this?
export default async function handler (req, res) {
res.setHeader('Access-Control-Allow-Origin', '*')
res.setHeader('Access-Control-Allow-Methods', 'GET')
res.setHeader('Access-Control-Allow-Headers', 'Content-Type')

// Only allow GET requests
if (req.method !== 'GET') {
return res.status(405).json({ error: 'Method not allowed' })
}

try {
// fetch all custom domains from the database
const domains = await prisma.customDomain.findMany({
select: {
domain: true,
subName: true
},
where: {
verificationState: 'VERIFIED'
}
})

// map domains to a key-value pair
const domainMappings = domains.reduce((acc, domain) => {
acc[domain.domain.toLowerCase()] = {
subName: domain.subName
}
return acc
}, {})

return res.status(200).json(domainMappings)
} catch (error) {
console.error('cannot fetch domains:', error)
return res.status(500).json({ error: 'Failed to fetch domains' })
}
}