feat: 커스텀 템플릿 추가 수정 중
This commit is contained in:
@@ -1,55 +1,148 @@
|
||||
import VueDOMPurifyHTML from 'vue-dompurify-html'
|
||||
import DOMPurify from 'dompurify'
|
||||
|
||||
export default defineNuxtPlugin(nuxtApp => {
|
||||
nuxtApp.vueApp.use(VueDOMPurifyHTML, {
|
||||
default: {
|
||||
ALLOWED_TAGS: [
|
||||
'br',
|
||||
'div',
|
||||
'b',
|
||||
'strong',
|
||||
'i',
|
||||
'em',
|
||||
'u',
|
||||
's',
|
||||
'a',
|
||||
'p',
|
||||
'ol',
|
||||
'ul',
|
||||
'li',
|
||||
'span',
|
||||
'img',
|
||||
'pre',
|
||||
'iframe',
|
||||
'input',
|
||||
'dl',
|
||||
'dt',
|
||||
'dd',
|
||||
'blockquote',
|
||||
'table',
|
||||
'thead',
|
||||
'tbody',
|
||||
'tfoot',
|
||||
'tr',
|
||||
'th',
|
||||
'td',
|
||||
],
|
||||
ALLOWED_ATTR: [
|
||||
'style',
|
||||
'id',
|
||||
'href',
|
||||
'src',
|
||||
'target',
|
||||
'alt',
|
||||
'class',
|
||||
'width',
|
||||
'height',
|
||||
'frameborder',
|
||||
'allowfullscreen',
|
||||
'colspan',
|
||||
'rowspan',
|
||||
'scope',
|
||||
],
|
||||
import type { DirectiveBinding } from 'vue'
|
||||
|
||||
// DOMPurify 설정 타입
|
||||
interface DOMPurifyConfig {
|
||||
ALLOWED_TAGS: string[]
|
||||
ALLOWED_ATTR: string[]
|
||||
}
|
||||
|
||||
// 공통 허용 태그
|
||||
const commonTags = [
|
||||
'br',
|
||||
'div',
|
||||
'b',
|
||||
'strong',
|
||||
'i',
|
||||
'em',
|
||||
'u',
|
||||
'a',
|
||||
'p',
|
||||
'ul',
|
||||
'li',
|
||||
's',
|
||||
'ol',
|
||||
'button',
|
||||
'span',
|
||||
'img',
|
||||
'pre',
|
||||
'input',
|
||||
'dl',
|
||||
'dt',
|
||||
'dd',
|
||||
'table',
|
||||
'thead',
|
||||
'tbody',
|
||||
'tfoot',
|
||||
'tr',
|
||||
'th',
|
||||
'td',
|
||||
] as const
|
||||
|
||||
// 공통 허용 속성
|
||||
const commonAttrs = [
|
||||
'style',
|
||||
'id',
|
||||
'href',
|
||||
'src',
|
||||
'target',
|
||||
'alt',
|
||||
'class',
|
||||
'width',
|
||||
'height',
|
||||
'frameborder',
|
||||
'colspan',
|
||||
'rowspan',
|
||||
'scope',
|
||||
] as const
|
||||
|
||||
// 기본 설정 (일반 사용자용)
|
||||
const defaultConfig: DOMPurifyConfig = {
|
||||
ALLOWED_TAGS: [
|
||||
...commonTags
|
||||
],
|
||||
ALLOWED_ATTR: [
|
||||
...commonAttrs
|
||||
],
|
||||
}
|
||||
|
||||
// 관리자용 설정 (확장된 태그 및 속성)
|
||||
const adminConfig: DOMPurifyConfig = {
|
||||
ALLOWED_TAGS: [
|
||||
...commonTags,
|
||||
'iframe',
|
||||
'link',
|
||||
'style',
|
||||
'blockquote',
|
||||
],
|
||||
ALLOWED_ATTR: [
|
||||
...commonAttrs,
|
||||
'onclick',
|
||||
'rel',
|
||||
'media',
|
||||
'integrity',
|
||||
'crossorigin',
|
||||
'referrerpolicy',
|
||||
'allowfullscreen',
|
||||
],
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML 문자열을 안전하게 정화하는 헬퍼 함수
|
||||
* @param value - 정화할 HTML 문자열
|
||||
* @param config - DOMPurify 설정
|
||||
* @returns 정화된 HTML 문자열
|
||||
*/
|
||||
function sanitizeHtml(value: unknown, config: DOMPurifyConfig): string {
|
||||
// SSR 환경에서는 빈 문자열 반환
|
||||
if (!import.meta.client) {
|
||||
return ''
|
||||
}
|
||||
|
||||
// 값이 없거나 문자열이 아닌 경우 빈 문자열 반환
|
||||
if (!value || typeof value !== 'string') {
|
||||
return ''
|
||||
}
|
||||
|
||||
try {
|
||||
return DOMPurify.sanitize(value, config)
|
||||
} catch (error) {
|
||||
// 에러 발생 시 원본 값 반환하지 않고 빈 문자열 반환 (보안상 안전)
|
||||
if (import.meta.dev) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('[DOMPurify] Sanitization error:', error)
|
||||
}
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 디렉티브 핸들러 생성 함수
|
||||
* @param config - DOMPurify 설정
|
||||
* @returns 디렉티브 핸들러 객체
|
||||
*/
|
||||
function createDirectiveHandler(config: DOMPurifyConfig) {
|
||||
return {
|
||||
mounted(el: HTMLElement, binding: DirectiveBinding) {
|
||||
el.innerHTML = sanitizeHtml(binding.value, config)
|
||||
},
|
||||
})
|
||||
updated(el: HTMLElement, binding: DirectiveBinding) {
|
||||
el.innerHTML = sanitizeHtml(binding.value, config)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export default defineNuxtPlugin((nuxtApp) => {
|
||||
// SSR 환경에서는 디렉티브 등록하지 않음
|
||||
// if (!import.meta.client) {
|
||||
// return
|
||||
// }
|
||||
|
||||
// 기본 디렉티브: v-dompurify-html
|
||||
nuxtApp.vueApp.directive('dompurify-html', createDirectiveHandler(defaultConfig))
|
||||
|
||||
// 관리자용 디렉티브: v-dompurify-admin
|
||||
nuxtApp.vueApp.directive('dompurify-admin', createDirectiveHandler(adminConfig))
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user