import { restore } from "@excalidraw/excalidraw" ; import type { ImportedDataState } from "@excalidraw/excalidraw/types/data/types" ; const t = ( s ) => s ; const BACKEND_GET = "https://json.excalidraw.com/api/v1/" ; const BACKEND_V2_GET = "https://json.excalidraw.com/api/v2/" ; const IV_LENGTH_BYTES = 12 ; const getImportedKey = ( key , usage ) => window . crypto . subtle . importKey ( "jwk" , { alg : "A128GCM" , ext : true , k : key , key_ops : [ "encrypt" , "decrypt" ] , kty : "oct" , } , { name : "AES-GCM" , length : 128 , } , false , [ usage ] ) ; const decryptImported = async ( iv , encrypted , privateKey ) : Promise < ArrayBuffer > => { const key = await getImportedKey ( privateKey , "decrypt" ) ; return window . crypto . subtle . decrypt ( { name : "AES-GCM" , iv , } , key , encrypted ) ; } ; const importFromBackend = async ( id , privateKey ? ) : Promise < ImportedDataState > => { try { const response = await fetch ( privateKey ? `${ BACKEND_V2_GET }${ id }` : `${ BACKEND_GET }${ id }.json` ) ; if ( ! response . ok ) { window . alert ( t ( "alerts.importBackendFailed" ) ) ; return { } ; } let data ; if ( privateKey ) { const buffer = await response . arrayBuffer ( ) ; let decrypted ; try { const iv = buffer . slice ( 0 , IV_LENGTH_BYTES ) ; const encrypted = buffer . slice ( IV_LENGTH_BYTES , buffer . byteLength ) ; decrypted = await decryptImported ( iv , encrypted , privateKey ) ; } catch ( error ) { const fixedIv = new Uint8Array ( IV_LENGTH_BYTES ) ; decrypted = await decryptImported ( fixedIv , buffer , privateKey ) ; } const string = new window . TextDecoder ( "utf-8" ) . decode ( new Uint8Array ( decrypted ) ) ; data = JSON . parse ( string ) ; } else { data = await response . json ( ) ; } return { elements : data . elements || null , appState : data . appState || null , } ; } catch ( error ) { window . alert ( t ( "alerts.importBackendFailed" ) ) ; console . error ( error ) ; return { } ; } } ; export const loadScene = async ( id , privateKey , localDataState ) => { let data ; if ( id != null ) { data = restore ( await importFromBackend ( id , privateKey ) , localDataState ?. appState , localDataState ?. elements ) ; } else { data = restore ( localDataState || null , null , null ) ; } return { elements : data . elements , appState : data . appState , files : data . files , commitToHistory : false , } ; } ;