| |
| |
| |
| import { tr } from '../lang/i18n-lite'; |
|
|
| |
| |
| |
| |
| export class CryptoSubtleUnavailableError extends Error { |
| constructor(message: string) { |
| super(message); |
| this.name = 'CryptoSubtleUnavailableError'; |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| export function isValidHash(hash: string): boolean { |
| return /^[0-9a-fA-F]{4}$/.test(hash); |
| } |
|
|
| |
| |
| |
| |
| function isCryptoSubtleAvailable(): boolean { |
| return typeof crypto !== 'undefined' && |
| crypto.subtle !== undefined; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| export async function hashContent(data: any): Promise<string> { |
| |
| if (!isCryptoSubtleAvailable()) { |
| const isLocalhost = window.location.hostname === 'localhost' || |
| window.location.hostname === '127.0.0.1' || |
| window.location.hostname === '[::1]'; |
| const protocol = window.location.protocol; |
| |
| let message = tr('Unable to use encryption API (crypto.subtle), local cache save feature is unavailable.') + '\n\n'; |
| |
| if (protocol === 'http:' && !isLocalhost) { |
| message += tr('Reason: Currently accessing via non-HTTPS non-localhost address, browser security policy has disabled encryption API.') + '\n\n'; |
| message += tr('Solution:') + '\n'; |
| message += '1. ' + tr('Recommended: Access via http://localhost:port (recommended)') + '\n'; |
| message += '2. ' + tr('Or: Configure HTTPS access'); |
| } else if (protocol === 'file:') { |
| message += tr('Reason: Opening page via file:// protocol, browser security policy has disabled encryption API.') + '\n\n'; |
| message += tr('Solution: Please access the application via http://localhost:port'); |
| } else { |
| message += tr('Reason: Browser does not support or has disabled encryption API.') + '\n\n'; |
| message += tr('Solution:') + '\n'; |
| message += '1. ' + tr('Use http://localhost:port to access (recommended)') + '\n'; |
| message += '2. ' + tr('Or configure HTTPS access'); |
| } |
| |
| throw new CryptoSubtleUnavailableError(message); |
| } |
| |
| |
| const content = JSON.stringify(data); |
| |
| |
| const encoder = new TextEncoder(); |
| const dataBuffer = encoder.encode(content); |
| const hashBuffer = await crypto.subtle.digest('SHA-256', dataBuffer); |
| |
| |
| const hashArray = Array.from(new Uint8Array(hashBuffer)); |
| const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); |
| |
| return hashHex.slice(0, 4); |
| } |
|
|
|
|