mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-05 06:24:37 +00:00
fix: correct UTF-8 encoding in base64 decode for file paths fix #20
The old decodeBase64 implementation tried atob() first which returns garbled text for UTF-8 content (e.g., Chinese characters), and only fell back to correct UTF-8 decoding when atob() threw an exception (which it doesn't for valid base64). Changes: - Add encodeBase64/decodeBase64 utilities to web/src/lib/utils.ts using TextEncoder/TextDecoder for proper UTF-8 support - Update file.tsx to use shared decodeBase64 instead of buggy local impl - Update files.tsx to use shared encodeBase64 instead of deprecated escape/unescape approach
This commit is contained in:
@@ -5,3 +5,26 @@ export function cn(...inputs: ClassValue[]): string {
|
||||
return twMerge(clsx(inputs))
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode base64 string to UTF-8 text
|
||||
*/
|
||||
export function decodeBase64(value: string): { text: string; ok: boolean } {
|
||||
try {
|
||||
const binaryString = atob(value)
|
||||
const bytes = Uint8Array.from(binaryString, (char) => char.charCodeAt(0))
|
||||
const text = new TextDecoder('utf-8').decode(bytes)
|
||||
return { text, ok: true }
|
||||
} catch {
|
||||
return { text: '', ok: false }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode UTF-8 text to base64 string
|
||||
*/
|
||||
export function encodeBase64(value: string): string {
|
||||
const bytes = new TextEncoder().encode(value)
|
||||
const binaryString = Array.from(bytes, (byte) => String.fromCharCode(byte)).join('')
|
||||
return btoa(binaryString)
|
||||
}
|
||||
|
||||
|
||||
@@ -9,18 +9,7 @@ import { useAppGoBack } from '@/hooks/useAppGoBack'
|
||||
import { useCopyToClipboard } from '@/hooks/useCopyToClipboard'
|
||||
import { queryKeys } from '@/lib/query-keys'
|
||||
import { langAlias, useShikiHighlighter } from '@/lib/shiki'
|
||||
|
||||
function decodeBase64(value: string): { text: string; ok: boolean } {
|
||||
try {
|
||||
return { text: atob(value), ok: true }
|
||||
} catch {
|
||||
try {
|
||||
return { text: decodeURIComponent(escape(atob(value))), ok: true }
|
||||
} catch {
|
||||
return { text: '', ok: false }
|
||||
}
|
||||
}
|
||||
}
|
||||
import { decodeBase64 } from '@/lib/utils'
|
||||
|
||||
function decodePath(value: string): string {
|
||||
if (!value) return ''
|
||||
|
||||
@@ -7,14 +7,7 @@ import { useAppGoBack } from '@/hooks/useAppGoBack'
|
||||
import { useGitStatusFiles } from '@/hooks/queries/useGitStatusFiles'
|
||||
import { useSession } from '@/hooks/queries/useSession'
|
||||
import { useSessionFileSearch } from '@/hooks/queries/useSessionFileSearch'
|
||||
|
||||
function encodePath(value: string): string {
|
||||
try {
|
||||
return btoa(value)
|
||||
} catch {
|
||||
return btoa(unescape(encodeURIComponent(value)))
|
||||
}
|
||||
}
|
||||
import { encodeBase64 } from '@/lib/utils'
|
||||
|
||||
function BackIcon(props: { className?: string }) {
|
||||
return (
|
||||
@@ -255,8 +248,8 @@ export default function FilesPage() {
|
||||
|
||||
const handleOpenFile = useCallback((path: string, staged?: boolean) => {
|
||||
const search = staged === undefined
|
||||
? { path: encodePath(path) }
|
||||
: { path: encodePath(path), staged }
|
||||
? { path: encodeBase64(path) }
|
||||
: { path: encodeBase64(path), staged }
|
||||
navigate({
|
||||
to: '/sessions/$sessionId/file',
|
||||
params: { sessionId },
|
||||
|
||||
Reference in New Issue
Block a user