fix(hooks): 🐛 修复一些xss的问题

This commit is contained in:
Dawn
2025-04-15 18:43:13 +08:00
parent 0b97e09ccc
commit bcce4a01d4
7 changed files with 48 additions and 15 deletions

View File

@@ -2,6 +2,10 @@ name: Greetings
on: [pull_request_target, issues]
# 顶层设置最小权限,推荐 contents: read
permissions:
contents: read
jobs:
greeting:
# 跳过 Renovate PR

View File

@@ -5,6 +5,10 @@ on:
tags:
- 'v*'
# 确保默认情况下所有 job 都只有只读权限,只有需要写权限的 job比如发布 release 的 job才会单独提升权限其他 job 依然保持最小权限,最大程度保护仓库安全
permissions:
contents: read
concurrency:
group: release-${{ github.ref }}
cancel-in-progress: true # 如果有新的发布任务,取消正在进行的任务

View File

@@ -213,13 +213,17 @@ const addFriend = async () => {
globalStore.addFriendModalInfo.uid = uid
}
// 注入 enableAllScroll 方法
const { enableScroll } = inject('popoverControls', { enableScroll: () => {} })
let enableScroll = () => {}
const handleOpenMsgSession = async (uid: string) => {
enableScroll() // 在打开新会话前恢复所有滚动
await openMsgSession(uid)
}
onMounted(() => {
// 注入 enableAllScroll 方法
enableScroll.bind(inject('popoverControls', { enableScroll }))
})
</script>
<style scoped lang="scss">

View File

@@ -171,7 +171,7 @@ const { themes } = storeToRefs(settingStore)
const arrow = ref(false)
/** 输入框dom元素 */
const messageInputDom = ref<HTMLElement>()
const activeItem = ref(inject('activeItem') as SessionItem)
const activeItem = ref()
/** ait 虚拟列表 */
const virtualListInstAit = useTemplateRef<VirtualListInst>('virtualListInst-ait')
/** AI 虚拟列表 */
@@ -257,6 +257,7 @@ const closeMenu = (event: any) => {
}
onMounted(async () => {
activeItem.value = inject('activeItem') as SessionItem
onKeyStroke('Enter', () => {
if (ait.value && Number(selectedAIKey.value) > -1) {
const item = personList.value.find((item) => item.uid === selectedAitKey.value) as CacheUserItem

View File

@@ -70,7 +70,7 @@
<n-flex
align="center"
justify="center"
class="emoji-item"
class="emoji-item py-4px"
v-for="(item, index) in emojiStore.emojiList"
:key="index"
@click.stop="chooseEmoji(item.expressionUrl, 'url')">

View File

@@ -96,6 +96,16 @@ export const useCommon = () => {
imgCount: 0
})
/**
* 判断 URL 是否安全
* @param url URL 字符串
* @returns 是否安全
*/
const isSafeUrl = (url: string) => {
// 只允许 http/https 协议,且不能包含 javascript: 或 data:
return /^(https?:\/\/|\/)/.test(url) && !/^javascript:/i.test(url) && !/^data:/i.test(url)
}
/**
* 获取当前光标选取的信息(需要判断是否为空)
*/
@@ -308,7 +318,12 @@ export const useCommon = () => {
const author = dom.name
// 创建一个img标签节点作为头像
const imgNode = document.createElement('img')
imgNode.src = dom.avatar
if (isSafeUrl(dom.avatar)) {
imgNode.src = dom.avatar
} else {
// 设置为默认头像或空
imgNode.src = 'avatar/001.png'
}
imgNode.style.cssText = `
width: 20px;
height: 20px;
@@ -424,7 +439,13 @@ export const useCommon = () => {
let content = dom.content
// 创建一个img标签节点作为头像
const imgNode = document.createElement('img')
imgNode.src = AvatarUtils.getAvatarUrl(dom.avatar)
const avatarUrl = AvatarUtils.getAvatarUrl(dom.avatar)
if (isSafeUrl(avatarUrl)) {
imgNode.src = avatarUrl
} else {
// 设置为默认头像或空
imgNode.src = 'avatar/001.png'
}
imgNode.style.cssText = `
width: 20px;
height: 20px;
@@ -461,7 +482,6 @@ export const useCommon = () => {
content = content.find((item: string) => item.startsWith('data:image/'))
reply.value.imgCount = imageCount
}
console.log(content)
// todo: 暂时用http开头的图片判断后续需要优化
if (content.startsWith('http')) {

View File

@@ -9,7 +9,7 @@
<!-- 主体内容区域 -->
<div ref="contentRef" class="flex-1 overflow-auto">
<!-- 图片展示区域 -->
<div class="min-h-[calc(100vh-124px)] flex-center">
<div ref="imgContainerRef" class="min-h-[calc(100vh-124px)] flex-center">
<img
ref="imageRef"
:src="currentImage"
@@ -18,8 +18,9 @@
cursor: isDragging ? 'grabbing' : 'grab'
}"
class="max-w-90% max-h-90% select-none"
:class="[{ 'transition-transform duration-200': !isDragging }, { 'mt-62px': !isScrollbar }]"
:class="[{ 'transition-transform duration-200': !isDragging }]"
@mousedown="startDrag"
@load="checkScrollbar"
alt="preview" />
<!-- 提示文本 -->
@@ -132,7 +133,8 @@ const imagePosition = reactive({ x: 0, y: 0 })
const imageRef = ref<HTMLImageElement>()
// 添加响应式变量来跟踪是否有滚动条
const contentScrollbar = useTemplateRef<HTMLElement>('contentRef')
const isScrollbar = ref(false)
// 图片容器
const imgContainer = useTemplateRef<HTMLElement>('imgContainerRef')
//提示相关的响应式变量
const showTip = ref(false)
const tipText = ref('')
@@ -360,8 +362,9 @@ const handleKeydown = (e: KeyboardEvent) => {
// 检查是否有滚动条的函数
const checkScrollbar = () => {
setTimeout(() => {
if (contentScrollbar.value) {
isScrollbar.value = contentScrollbar.value.scrollHeight > contentScrollbar.value.clientHeight
if (imgContainer.value && contentScrollbar.value) {
imgContainer.value.style.height =
contentScrollbar.value.scrollHeight > contentScrollbar.value.clientHeight ? 'auto' : '100%'
}
}, 16)
}
@@ -369,9 +372,6 @@ const checkScrollbar = () => {
onMounted(async () => {
// 显示窗口
await getCurrentWebviewWindow().show()
setTimeout(() => {
checkScrollbar()
}, 16)
await addListener(
appWindow.listen('update-image', (event: any) => {