@@ -40,7 +40,10 @@ const PBKDF2_ITERATIONS = 200_000
4040const SALT_LEN = 16
4141const IV_LEN = 12
4242
43- const deriveKey = async ( password : string , salt : Uint8Array ) : Promise < CryptoKey > => {
43+ const deriveKey = async (
44+ password : string ,
45+ salt : Uint8Array ,
46+ ) : Promise < CryptoKey > => {
4447 const keyMaterial = await crypto . subtle . importKey (
4548 'raw' ,
4649 new TextEncoder ( ) . encode ( password ) ,
@@ -50,18 +53,26 @@ const deriveKey = async (password: string, salt: Uint8Array): Promise<CryptoKey>
5053 )
5154
5255 return crypto . subtle . deriveKey (
53- { name : 'PBKDF2' , salt : salt . buffer as ArrayBuffer , iterations : PBKDF2_ITERATIONS , hash : 'SHA-256' } ,
56+ {
57+ name : 'PBKDF2' ,
58+ salt : salt . buffer as ArrayBuffer ,
59+ iterations : PBKDF2_ITERATIONS ,
60+ hash : 'SHA-256' ,
61+ } ,
5462 keyMaterial ,
5563 { name : 'AES-GCM' , length : 256 } ,
5664 false ,
5765 [ 'encrypt' , 'decrypt' ] ,
5866 )
5967}
6068
61- export const encryptBW = async ( data : string , password : string ) : Promise < Blob > => {
69+ export const encryptBW = async (
70+ data : string ,
71+ password : string ,
72+ ) : Promise < Blob > => {
6273 const salt = crypto . getRandomValues ( new Uint8Array ( SALT_LEN ) )
63- const iv = crypto . getRandomValues ( new Uint8Array ( IV_LEN ) )
64- const key = await deriveKey ( password , salt )
74+ const iv = crypto . getRandomValues ( new Uint8Array ( IV_LEN ) )
75+ const key = await deriveKey ( password , salt )
6576
6677 const ciphertext = new Uint8Array (
6778 await crypto . subtle . encrypt (
@@ -77,10 +88,13 @@ export const encryptBW = async (data: string, password: string): Promise<Blob> =
7788 payload . set ( iv , SALT_LEN )
7889 payload . set ( ciphertext , SALT_LEN + IV_LEN )
7990
80- const blobWriter = new BlobWriter ( )
81- const zipWriter = new ZipWriter ( blobWriter )
91+ const blobWriter = new BlobWriter ( )
92+ const zipWriter = new ZipWriter ( blobWriter )
8293
83- await zipWriter . add ( 'meta.json' , new TextReader ( JSON . stringify ( { encrypted : true , version : 1 } ) ) )
94+ await zipWriter . add (
95+ 'meta.json' ,
96+ new TextReader ( JSON . stringify ( { encrypted : true , version : 1 } ) ) ,
97+ )
8498 await zipWriter . add ( 'encrypted.bin' , new BlobReader ( new Blob ( [ payload ] ) ) )
8599 await zipWriter . add ( 'mimetype' , writeMimetype ( ) )
86100 await zipWriter . close ( )
@@ -94,27 +108,34 @@ const isEncryptedZip = async (zipReader: ZipReader<Blob>): Promise<boolean> => {
94108 return entries . some ( ( e : Entry ) => e . filename === 'meta.json' )
95109}
96110
97- export const decryptBW = async ( blob : Blob , password : string ) : Promise < ProjectObject > => {
111+ export const decryptBW = async (
112+ blob : Blob ,
113+ password : string ,
114+ ) : Promise < ProjectObject > => {
98115 const zipReader = new ZipReader ( new BlobReader ( blob ) )
99- const entries = await zipReader . getEntries ( )
116+ const entries = await zipReader . getEntries ( )
100117
101118 const encEntry = entries . find ( ( e ) => e . filename === 'encrypted.bin' )
102119
103120 if ( ! encEntry ) throw new Error ( 'encrypted.bin not found' )
104121
105122 const payloadBlob = await ( encEntry as FileEntry ) . getData ( new BlobWriter ( ) )
106- const payload = new Uint8Array ( await payloadBlob . arrayBuffer ( ) )
123+ const payload = new Uint8Array ( await payloadBlob . arrayBuffer ( ) )
107124
108- const salt = payload . slice ( 0 , SALT_LEN )
109- const iv = payload . slice ( SALT_LEN , SALT_LEN + IV_LEN )
125+ const salt = payload . slice ( 0 , SALT_LEN )
126+ const iv = payload . slice ( SALT_LEN , SALT_LEN + IV_LEN )
110127 const ciphertext = payload . slice ( SALT_LEN + IV_LEN )
111128
112129 const key = await deriveKey ( password , salt )
113130
114131 let plaintext : ArrayBuffer
115132
116133 try {
117- plaintext = await crypto . subtle . decrypt ( { name : 'AES-GCM' , iv } , key , ciphertext )
134+ plaintext = await crypto . subtle . decrypt (
135+ { name : 'AES-GCM' , iv } ,
136+ key ,
137+ ciphertext ,
138+ )
118139 } catch {
119140 throw new Error ( 'wrong-password' )
120141 }
@@ -124,14 +145,18 @@ export const decryptBW = async (blob: Blob, password: string): Promise<ProjectOb
124145 return destr ( new TextDecoder ( ) . decode ( plaintext ) )
125146}
126147
127- export const readBW = async ( blob : Blob , getPassword ?: ( ) => Promise < string | null > ) : Promise < ProjectObject > => {
148+ export const readBW = async (
149+ blob : Blob ,
150+ getPassword ?: ( ) => Promise < string | null > ,
151+ ) : Promise < ProjectObject > => {
128152 // peek at entries to decide the path
129- const peekReader = new ZipReader ( new BlobReader ( blob ) )
130- const encrypted = await isEncryptedZip ( peekReader )
153+ const peekReader = new ZipReader ( new BlobReader ( blob ) )
154+ const encrypted = await isEncryptedZip ( peekReader )
131155 await peekReader . close ( )
132156
133157 if ( encrypted ) {
134- if ( ! getPassword ) throw new Error ( 'File is encrypted but no password provider was given' )
158+ if ( ! getPassword )
159+ throw new Error ( 'File is encrypted but no password provider was given' )
135160
136161 const password = await getPassword ( )
137162
@@ -142,9 +167,9 @@ export const readBW = async (blob: Blob, getPassword?: () => Promise<string | nu
142167
143168 // original unencrypted path
144169 const zipFileReader = new BlobReader ( blob )
145- const writer = new TextWriter ( )
146- const zipReader = new ZipReader ( zipFileReader )
147- const firstEntry = ( await zipReader . getEntries ( ) ) . shift ( )
170+ const writer = new TextWriter ( )
171+ const zipReader = new ZipReader ( zipFileReader )
172+ const firstEntry = ( await zipReader . getEntries ( ) ) . shift ( )
148173
149174 // @ts -expect-error
150175 const data = await firstEntry . getData ( writer )
0 commit comments