Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 29 additions & 16 deletions src/Lighthouse/uploadEncrypted/encryptionBrowser.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { EncryptionError, DecryptionError, InvalidPasswordError, CorruptedDataError } from '../../errors/EncryptionErrors';

/* istanbul ignore file */
declare const window: any
const importKeyFromBytes = async (keyBytes: any) =>
Expand Down Expand Up @@ -50,14 +52,17 @@ export const encryptFile = async (fileArrayBuffer: any, password: any) => {

return resultBytes
} catch (error) {
console.error('Error encrypting file')
console.error(error)
throw error
console.error('Error encrypting file:', error);
throw new EncryptionError('Failed to encrypt file', error as Error);
}
}

export const decryptFile = async (cipher: any, password: any) => {
try {
if (!cipher || cipher.byteLength < 28) {
throw new CorruptedDataError('Invalid or corrupted encrypted data');
}

const cipherBytes = new Uint8Array(cipher)
const passwordBytes = new TextEncoder().encode(password)

Expand All @@ -72,19 +77,27 @@ export const decryptFile = async (cipher: any, password: any) => {
hash: 'SHA-256',
})

const decryptedContent = await window.crypto.subtle.decrypt(
{
name: 'AES-GCM',
iv: iv,
},
aesKey,
data
)

return decryptedContent
try {
const decryptedContent = await window.crypto.subtle.decrypt(
{
name: 'AES-GCM',
iv: iv,
},
aesKey,
data
)
return decryptedContent
} catch (error: any) {
if (error.name === 'OperationError') {
throw new InvalidPasswordError();
}
throw error;
}
} catch (error) {
console.error('Error decrypting file')
console.error(error)
return
console.error('Error decrypting file:', error);
if (error instanceof DecryptionError) {
throw error;
}
throw new DecryptionError('Failed to decrypt file', error as Error);
}
}
45 changes: 29 additions & 16 deletions src/Lighthouse/uploadEncrypted/encryptionNode.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { EncryptionError, DecryptionError, InvalidPasswordError, CorruptedDataError } from '../../errors/EncryptionErrors';

const importKeyFromBytes = async (keyBytes: any, crypto: any) =>
crypto.subtle.importKey('raw', keyBytes, 'PBKDF2', false, ['deriveKey'])

Expand Down Expand Up @@ -55,9 +57,8 @@ const encryptFile = async (fileArrayBuffer: any, password: any) => {

return resultBytes
} catch (error) {
console.error('Error encrypting file')
console.error(error)
throw error
console.error('Error encrypting file:', error);
throw new EncryptionError('Failed to encrypt file', error as Error);
}
}

Expand All @@ -66,6 +67,10 @@ const decryptFile = async (cipher: any, password: any) => {
const { Crypto } = eval('require')('@peculiar/webcrypto')
const crypto = new Crypto()

if (!cipher || cipher.byteLength < 28) {
throw new CorruptedDataError('Invalid or corrupted encrypted data');
}

const cipherBytes = new Uint8Array(cipher)
const passwordBytes = new TextEncoder().encode(password)

Expand All @@ -85,20 +90,28 @@ const decryptFile = async (cipher: any, password: any) => {
crypto
)

const decryptedContent = await crypto.subtle.decrypt(
{
name: 'AES-GCM',
iv: iv,
},
aesKey,
data
)

return decryptedContent
try {
const decryptedContent = await crypto.subtle.decrypt(
{
name: 'AES-GCM',
iv: iv,
},
aesKey,
data
)
return decryptedContent
} catch (error: any) {
if (error.name === 'OperationError') {
throw new InvalidPasswordError();
}
throw error;
}
} catch (error) {
console.error('Error decrypting file')
console.error(error)
return
console.error('Error decrypting file:', error);
if (error instanceof DecryptionError) {
throw error;
}
throw new DecryptionError('Failed to decrypt file', error as Error);
}
}

Expand Down
43 changes: 43 additions & 0 deletions src/errors/EncryptionErrors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
export class DecryptionError extends Error {
readonly cause?: Error;

constructor(message: string, cause?: Error | unknown) {
super(message);
this.name = 'DecryptionError';

if (cause instanceof Error) {
this.cause = cause;
} else if (cause !== undefined) {
this.cause = new Error(String(cause));
}
}
}

export class InvalidPasswordError extends DecryptionError {
constructor(message: string = 'Invalid password provided', cause?: Error | unknown) {
super(message, cause);
this.name = 'InvalidPasswordError';
}
}

export class CorruptedDataError extends DecryptionError {
constructor(message: string = 'Data appears to be corrupted', cause?: Error | unknown) {
super(message, cause);
this.name = 'CorruptedDataError';
}
}

export class EncryptionError extends Error {
readonly cause?: Error;

constructor(message: string, cause?: Error | unknown) {
super(message);
this.name = 'EncryptionError';

if (cause instanceof Error) {
this.cause = cause;
} else if (cause !== undefined) {
this.cause = new Error(String(cause));
}
}
}