修复朋友圈封面信息被错误解析的问题;解决了一些安全问题

This commit is contained in:
cc
2026-02-25 12:12:08 +08:00
parent b3741a5cf4
commit 411f8a8d61
11 changed files with 263 additions and 18 deletions

View File

@@ -105,9 +105,19 @@ export default function LockScreen({ onUnlock, avatar, useHello = false }: LockS
try {
const storedHash = await configService.getAuthPassword()
// 兜底:如果没有设置过密码,直接放行并关闭应用锁
if (!storedHash) {
await configService.setAuthEnabled(false)
handleUnlock()
return
}
const inputHash = await sha256(password)
if (inputHash === storedHash) {
// 解锁成功,重新写入 authEnabled 以修复可能被篡改的签名
await configService.setAuthEnabled(true)
handleUnlock()
} else {
setError('密码错误')

View File

@@ -2,7 +2,7 @@ import { useState, useEffect } from 'react'
import { NavLink, useLocation } from 'react-router-dom'
import { Home, MessageSquare, BarChart3, Users, FileText, Database, Settings, ChevronLeft, ChevronRight, Download, Aperture, UserCircle, Lock } from 'lucide-react'
import { useAppStore } from '../stores/appStore'
import * as configService from '../services/config'
import './Sidebar.scss'
function Sidebar() {
@@ -12,7 +12,7 @@ function Sidebar() {
const setLocked = useAppStore(state => state.setLocked)
useEffect(() => {
configService.getAuthEnabled().then(setAuthEnabled)
window.electronAPI.auth.verifyEnabled().then(setAuthEnabled)
}, [])
const isActive = (path: string) => {

View File

@@ -21,6 +21,7 @@ interface SnsMedia {
interface SnsMediaGridProps {
mediaList: SnsMedia[]
postType?: number
onPreview: (src: string, isVideo?: boolean, liveVideoPath?: string) => void
onMediaDeleted?: () => void
}
@@ -80,7 +81,7 @@ const extractVideoFrame = async (videoPath: string): Promise<string> => {
})
}
const MediaItem = ({ media, onPreview, onMediaDeleted }: { media: SnsMedia; onPreview: (src: string, isVideo?: boolean, liveVideoPath?: string) => void; onMediaDeleted?: () => void }) => {
const MediaItem = ({ media, postType, onPreview, onMediaDeleted }: { media: SnsMedia; postType?: number; onPreview: (src: string, isVideo?: boolean, liveVideoPath?: string) => void; onMediaDeleted?: () => void }) => {
const [error, setError] = useState(false)
const [deleted, setDeleted] = useState(false)
const [loading, setLoading] = useState(true)
@@ -96,6 +97,8 @@ const MediaItem = ({ media, onPreview, onMediaDeleted }: { media: SnsMedia; onPr
const isVideo = isSnsVideoUrl(media.url)
const isLive = !!media.livePhoto
const targetUrl = media.thumb || media.url
// type 7 的朋友圈媒体不需要解密,直接使用原始 URL
const skipDecrypt = postType === 7
// 视频重试失败时重试最多2次耗尽才标记删除
const videoRetryOrDelete = () => {
@@ -119,7 +122,7 @@ const MediaItem = ({ media, onPreview, onMediaDeleted }: { media: SnsMedia; onPr
// For images, we proxy to get the local path/base64
const result = await window.electronAPI.sns.proxyImage({
url: targetUrl,
key: media.key
key: skipDecrypt ? undefined : media.key
})
if (cancelled) return
@@ -134,7 +137,7 @@ const MediaItem = ({ media, onPreview, onMediaDeleted }: { media: SnsMedia; onPr
if (isLive && media.livePhoto?.url) {
window.electronAPI.sns.proxyImage({
url: media.livePhoto.url,
key: media.livePhoto.key || media.key
key: skipDecrypt ? undefined : (media.livePhoto.key || media.key)
}).then((res: any) => {
if (!cancelled && res.success && res.videoPath) {
setLiveVideoPath(`file://${res.videoPath.replace(/\\/g, '/')}`)
@@ -150,7 +153,7 @@ const MediaItem = ({ media, onPreview, onMediaDeleted }: { media: SnsMedia; onPr
// Usually we need to call proxyImage with the video URL to decrypt it to cache
const result = await window.electronAPI.sns.proxyImage({
url: media.url,
key: media.key
key: skipDecrypt ? undefined : media.key
})
if (cancelled) return
@@ -201,7 +204,7 @@ const MediaItem = ({ media, onPreview, onMediaDeleted }: { media: SnsMedia; onPr
try {
const res = await window.electronAPI.sns.proxyImage({
url: media.url,
key: media.key
key: skipDecrypt ? undefined : media.key
})
if (res.success && res.videoPath) {
const local = `file://${res.videoPath.replace(/\\/g, '/')}`
@@ -229,7 +232,7 @@ const MediaItem = ({ media, onPreview, onMediaDeleted }: { media: SnsMedia; onPr
try {
const result = await window.electronAPI.sns.proxyImage({
url: media.url,
key: media.key
key: skipDecrypt ? undefined : media.key
})
if (result.success) {
@@ -334,7 +337,7 @@ const MediaItem = ({ media, onPreview, onMediaDeleted }: { media: SnsMedia; onPr
)
}
export const SnsMediaGrid: React.FC<SnsMediaGridProps> = ({ mediaList, onPreview, onMediaDeleted }) => {
export const SnsMediaGrid: React.FC<SnsMediaGridProps> = ({ mediaList, postType, onPreview, onMediaDeleted }) => {
if (!mediaList || mediaList.length === 0) return null
const count = mediaList.length
@@ -350,7 +353,7 @@ export const SnsMediaGrid: React.FC<SnsMediaGridProps> = ({ mediaList, onPreview
return (
<div className={`sns-media-grid ${gridClass}`}>
{mediaList.map((media, idx) => (
<MediaItem key={idx} media={media} onPreview={onPreview} onMediaDeleted={onMediaDeleted} />
<MediaItem key={idx} media={media} postType={postType} onPreview={onPreview} onMediaDeleted={onMediaDeleted} />
))}
</div>
)

View File

@@ -264,7 +264,7 @@ export const SnsPostItem: React.FC<SnsPostItemProps> = ({ post, onPreview, onDeb
{showMediaGrid && (
<div className="post-media-container">
<SnsMediaGrid mediaList={post.media} onPreview={onPreview} onMediaDeleted={[1, 54].includes(post.type ?? 0) ? () => setMediaDeleted(true) : undefined} />
<SnsMediaGrid mediaList={post.media} postType={post.type} onPreview={onPreview} onMediaDeleted={[1, 54].includes(post.type ?? 0) ? () => setMediaDeleted(true) : undefined} />
</div>
)}