mirror of
				https://github.com/langgenius/dify.git
				synced 2025-11-04 12:53:38 +00:00 
			
		
		
		
	Signed-off-by: -LAN- <laipz8200@outlook.com> Co-authored-by: Hash Brown <hi@xzd.me> Co-authored-by: crazywoola <427733928@qq.com> Co-authored-by: GareArc <chen4851@purdue.edu> Co-authored-by: Byron.wang <byron@dify.ai> Co-authored-by: Joel <iamjoel007@gmail.com> Co-authored-by: -LAN- <laipz8200@outlook.com> Co-authored-by: Garfield Dai <dai.hai@foxmail.com> Co-authored-by: KVOJJJin <jzongcode@gmail.com> Co-authored-by: Alexi.F <654973939@qq.com> Co-authored-by: Xiyuan Chen <52963600+GareArc@users.noreply.github.com> Co-authored-by: kautsar_masuara <61046989+izon-masuara@users.noreply.github.com> Co-authored-by: achmad-kautsar <achmad.kautsar@insignia.co.id> Co-authored-by: Xin Zhang <sjhpzx@gmail.com> Co-authored-by: kelvintsim <83445753+kelvintsim@users.noreply.github.com> Co-authored-by: zxhlyh <jasonapring2015@outlook.com> Co-authored-by: Zixuan Cheng <61724187+Theysua@users.noreply.github.com>
		
			
				
	
	
		
			87 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			87 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import type { NextRequest } from 'next/server'
 | 
						|
import { NextResponse } from 'next/server'
 | 
						|
 | 
						|
const NECESSARY_DOMAIN = '*.sentry.io http://localhost:* http://127.0.0.1:* https://analytics.google.com googletagmanager.com *.googletagmanager.com https://www.google-analytics.com https://api.github.com'
 | 
						|
 | 
						|
const wrapResponseWithXFrameOptions = (response: NextResponse, pathname: string) => {
 | 
						|
  // prevent clickjacking: https://owasp.org/www-community/attacks/Clickjacking
 | 
						|
  // Chatbot page should be allowed to be embedded in iframe. It's a feature
 | 
						|
  if (process.env.NEXT_PUBLIC_ALLOW_EMBED !== 'true' && !pathname.startsWith('/chat') && !pathname.startsWith('/workflow') && !pathname.startsWith('/completion') && !pathname.startsWith('/webapp-signin'))
 | 
						|
    response.headers.set('X-Frame-Options', 'DENY')
 | 
						|
 | 
						|
  return response
 | 
						|
}
 | 
						|
export function middleware(request: NextRequest) {
 | 
						|
  const { pathname } = request.nextUrl
 | 
						|
  const requestHeaders = new Headers(request.headers)
 | 
						|
  const response = NextResponse.next({
 | 
						|
    request: {
 | 
						|
      headers: requestHeaders,
 | 
						|
    },
 | 
						|
  })
 | 
						|
 | 
						|
  const isWhiteListEnabled = !!process.env.NEXT_PUBLIC_CSP_WHITELIST && process.env.NODE_ENV === 'production'
 | 
						|
  if (!isWhiteListEnabled)
 | 
						|
    return wrapResponseWithXFrameOptions(response, pathname)
 | 
						|
 | 
						|
  const whiteList = `${process.env.NEXT_PUBLIC_CSP_WHITELIST} ${NECESSARY_DOMAIN}`
 | 
						|
  const nonce = Buffer.from(crypto.randomUUID()).toString('base64')
 | 
						|
  const csp = `'nonce-${nonce}'`
 | 
						|
 | 
						|
  const scheme_source = 'data: mediastream: blob: filesystem:'
 | 
						|
 | 
						|
  const cspHeader = `
 | 
						|
    default-src 'self' ${scheme_source} ${csp} ${whiteList};
 | 
						|
    connect-src 'self' ${scheme_source} ${csp} ${whiteList};
 | 
						|
    script-src 'self' ${scheme_source} ${csp} ${whiteList};
 | 
						|
    style-src 'self' 'unsafe-inline' ${scheme_source} ${whiteList};
 | 
						|
    worker-src 'self' ${scheme_source} ${csp} ${whiteList};
 | 
						|
    media-src 'self' ${scheme_source} ${csp} ${whiteList};
 | 
						|
    img-src * data: blob:;
 | 
						|
    font-src 'self';
 | 
						|
    object-src 'none';
 | 
						|
    base-uri 'self';
 | 
						|
    form-action 'self';
 | 
						|
    upgrade-insecure-requests;
 | 
						|
`
 | 
						|
  // Replace newline characters and spaces
 | 
						|
  const contentSecurityPolicyHeaderValue = cspHeader
 | 
						|
    .replace(/\s{2,}/g, ' ')
 | 
						|
    .trim()
 | 
						|
 | 
						|
  requestHeaders.set('x-nonce', nonce)
 | 
						|
 | 
						|
  requestHeaders.set(
 | 
						|
    'Content-Security-Policy',
 | 
						|
    contentSecurityPolicyHeaderValue,
 | 
						|
  )
 | 
						|
 | 
						|
  response.headers.set(
 | 
						|
    'Content-Security-Policy',
 | 
						|
    contentSecurityPolicyHeaderValue,
 | 
						|
  )
 | 
						|
 | 
						|
  return wrapResponseWithXFrameOptions(response, pathname)
 | 
						|
}
 | 
						|
 | 
						|
export const config = {
 | 
						|
  matcher: [
 | 
						|
    /*
 | 
						|
     * Match all request paths except for the ones starting with:
 | 
						|
     * - api (API routes)
 | 
						|
     * - _next/static (static files)
 | 
						|
     * - _next/image (image optimization files)
 | 
						|
     * - favicon.ico (favicon file)
 | 
						|
     */
 | 
						|
    {
 | 
						|
      // source: '/((?!api|_next/static|_next/image|favicon.ico).*)',
 | 
						|
      source: '/((?!_next/static|_next/image|favicon.ico).*)',
 | 
						|
      // source: '/(.*)',
 | 
						|
      // missing: [
 | 
						|
      //   { type: 'header', key: 'next-router-prefetch' },
 | 
						|
      //   { type: 'header', key: 'purpose', value: 'prefetch' },
 | 
						|
      // ],
 | 
						|
    },
 | 
						|
  ],
 | 
						|
}
 |