Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Throw InsecureContextError if window.crypto.subtle is undefined #6487

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
4fb927f
implement `EventEmitter` compatible with browsers
Muhammad-Altabba Aug 31, 2023
0e9ce5d
some fixes at InBrowserEventEmitter
Muhammad-Altabba Sep 4, 2023
28ba5dc
some renaming inside event_emitter.ts
Muhammad-Altabba Sep 4, 2023
87b2b86
Merge branch '4.x' into 6371-uncaught-typeerror-class-extends-value-u…
Muhammad-Altabba Sep 7, 2023
ae40b19
Merge branch '4.x' into 6371-uncaught-typeerror-class-extends-value-u…
Muhammad-Altabba Sep 17, 2023
8913307
Merge branch '4.x' into 6371-uncaught-typeerror-class-extends-value-u…
Muhammad-Altabba Sep 19, 2023
6d0bd23
Merge branch '4.x' into 6371-uncaught-typeerror-class-extends-value-u…
Muhammad-Altabba Sep 26, 2023
cb742c7
Merge branch '4.x' into 6371-uncaught-typeerror-class-extends-value-u…
Muhammad-Altabba Oct 4, 2023
3766eec
Merge branch '4.x' into 6371-uncaught-typeerror-class-extends-value-u…
Muhammad-Altabba Oct 4, 2023
195463d
export EventEmitter as a class
Muhammad-Altabba Oct 4, 2023
1808058
add unit tests for EventEmitter
Muhammad-Altabba Oct 4, 2023
607f4b2
disable lint rule in a file and update yarn.lock
Muhammad-Altabba Oct 4, 2023
4c8bc1b
apply fixes and add tests for EventEmitter
Muhammad-Altabba Oct 4, 2023
e4d7317
configure `EventEmitter` test to run inside `jsdom`
Muhammad-Altabba Oct 4, 2023
9b0ba51
Merge branch '4.x' into 6371-uncaught-typeerror-class-extends-value-u…
Muhammad-Altabba Oct 4, 2023
1eed66d
fix issue with detecting Uint8Array
Muhammad-Altabba Oct 6, 2023
90798cf
throw `InsecureContextError` if window.crypto.subtle is `undefined`
Muhammad-Altabba Oct 6, 2023
5f195bb
prevent throwing if value is null when checking value.constructor.name
Muhammad-Altabba Oct 6, 2023
37b6617
Merge branch '6371-uncaught-typeerror-class-extends-value-undefined-i…
Muhammad-Altabba Oct 6, 2023
41fab05
Merge branch '6371-uncaught-typeerror-class-extends-value-undefined-i…
Muhammad-Altabba Oct 6, 2023
7a78cfd
check `window` is defined before accessing it
Muhammad-Altabba Oct 6, 2023
a1ae054
Merge branch '6393-web3validatorerror-error-value-at-0-must-pass-byte…
Muhammad-Altabba Oct 6, 2023
cda6420
Merge branch '4.x' into 6485-throw-insecurecontexterror-if-window.cry…
Muhammad-Altabba Oct 9, 2023
da175f6
Merge branch '4.x' into 6485-throw-insecurecontexterror-if-window.cry…
Muhammad-Altabba Oct 11, 2023
2b1591a
Merge branch '4.x' into 6485-throw-insecurecontexterror-if-window.cry…
Muhammad-Altabba Oct 16, 2023
ab5680c
Merge branch '4.x' into 6485-throw-insecurecontexterror-if-window.cry…
Muhammad-Altabba Oct 17, 2023
2bf281f
Merge branch '4.x' into 6485-throw-insecurecontexterror-if-window.cry…
Muhammad-Altabba Oct 18, 2023
970723b
Merge branch '4.x' into 6485-throw-insecurecontexterror-if-window.cry…
Muhammad-Altabba Oct 31, 2023
f59eae6
Merge branch '4.x' into 6485-throw-insecurecontexterror-if-window.cry…
Muhammad-Altabba Nov 13, 2023
b5fa731
Merge branch '4.x' into 6485-throw-insecurecontexterror-if-window.cry…
Muhammad-Altabba Nov 20, 2023
23bc4fb
Merge branch '4.x' into 6485-throw-insecurecontexterror-if-window.cry…
Muhammad-Altabba Dec 13, 2023
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
1 change: 1 addition & 0 deletions packages/web3-errors/src/error_codes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export const ERR_ABI_ENCODING = 205;
export const ERR_EXISTING_PLUGIN_NAMESPACE = 206;
export const ERR_INVALID_METHOD_PARAMS = 207;
export const ERR_MULTIPLE_ERRORS = 208;
export const ERR_INSECURE_CONTEXT = 209;

// Contract error codes
export const ERR_CONTRACT = 300;
Expand Down
5 changes: 5 additions & 0 deletions packages/web3-errors/src/errors/generic_errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
ERR_PARAM,
ERR_EXISTING_PLUGIN_NAMESPACE,
ERR_INVALID_METHOD_PARAMS,
ERR_INSECURE_CONTEXT,
} from '../error_codes.js';
import { BaseWeb3Error } from '../web3_error_base.js';

Expand Down Expand Up @@ -81,6 +82,10 @@ export class OperationAbortError extends BaseWeb3Error {
public code = ERR_OPERATION_ABORT;
}

export class InsecureContextError extends BaseWeb3Error {
public code = ERR_INSECURE_CONTEXT;
}

export class AbiError extends BaseWeb3Error {
public code = ERR_ABI_ENCODING;
public readonly props: Record<string, unknown> & { name?: string };
Expand Down
21 changes: 16 additions & 5 deletions packages/web3-eth-accounts/src/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import {
import { pbkdf2Sync } from 'ethereum-cryptography/pbkdf2.js';
import { scryptSync } from 'ethereum-cryptography/scrypt.js';
import {
InsecureContextError,
InvalidKdfError,
InvalidPasswordError,
InvalidPrivateKeyError,
Expand Down Expand Up @@ -126,7 +127,10 @@ export const parseAndValidatePrivateKey = (data: Bytes, ignoreLength?: boolean):
}

try {
privateKeyUint8Array = data instanceof Uint8Array ? data : bytesToUint8Array(data);
privateKeyUint8Array =
data instanceof Uint8Array || data?.constructor?.name === 'Uint8Array'
? (data as Uint8Array)
: bytesToUint8Array(data);
} catch {
throw new InvalidPrivateKeyError();
}
Expand Down Expand Up @@ -406,7 +410,7 @@ export const recover = (
const V_INDEX = 130; // r = first 32 bytes, s = second 32 bytes, v = last byte of signature
const hashedMessage = prefixedOrR ? data : hashMessage(data);

let v = parseInt(signatureOrV.substring(V_INDEX),16); // 0x + r + s + v
let v = parseInt(signatureOrV.substring(V_INDEX), 16); // 0x + r + s + v
if (v > 26) {
v -= 27;
}
Expand All @@ -421,7 +425,7 @@ export const recover = (
const address = toChecksumAddress(`0x${publicHash.slice(-40)}`);

return address;
};
};;

/**
* Get the ethereum Address from a private key
Expand Down Expand Up @@ -456,7 +460,7 @@ export const privateKeyToAddress = (privateKey: Bytes): string => {
* Get the public key from a private key
*
* @param privateKey - String or Uint8Array of 32 bytes
* @param isCompressed - if true, will generate a 33 byte compressed public key instead of a 65 byte public key
* @param isCompressed - if true, will generate a 33 byte compressed public key instead of a 65 byte public key
* @returns The public key
* @example
* ```ts
Expand All @@ -465,7 +469,7 @@ export const privateKeyToAddress = (privateKey: Bytes): string => {
* > "0x42beb65f179720abaa3ec9a70a539629cbbc5ec65bb57e7fc78977796837e537662dd17042e6449dc843c281067a4d6d8d1a1775a13c41901670d5de7ee6503a" // uncompressed public key
* ```
*/
export const privateKeyToPublicKey = (privateKey: Bytes, isCompressed: boolean): string => {
export const privateKeyToPublicKey = (privateKey: Bytes, isCompressed: boolean): string => {
const privateKeyUint8Array = parseAndValidatePrivateKey(privateKey);

// Get public key from private key in compressed format
Expand Down Expand Up @@ -618,6 +622,13 @@ export const encrypt = async (
throw new InvalidKdfError();
}

// https://stackoverflow.com/a/46468377/8303489
// > crypto.subtle is supposed to be undefined in insecure contexts
if (typeof window !== 'undefined' && !window?.crypto?.subtle) {
throw new InsecureContextError(
'crypto.subtle is supposed to be undefined in insecure contexts',
);
}
const cipher = await createCipheriv(
privateKeyUint8Array,
derivedKey.slice(0, 16),
Expand Down
4 changes: 2 additions & 2 deletions packages/web3-eth-accounts/src/tx/transactionFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,8 @@ export class TransactionFactory {
* @param txOptions - The transaction options
*/
public static fromBlockBodyData(data: Uint8Array | Uint8Array[], txOptions: TxOptions = {}) {
if (data instanceof Uint8Array) {
return this.fromSerializedData(data, txOptions);
if (data instanceof Uint8Array || data?.constructor?.name === 'Uint8Array') {
return this.fromSerializedData(data as Uint8Array, txOptions);
}
if (Array.isArray(data)) {
// It is a legacy transaction
Expand Down
42 changes: 42 additions & 0 deletions packages/web3-eth-accounts/test/unit/encrypt-jsdom.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* @jest-environment jsdom
*/

/*
This file is part of web3.js.

web3.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

web3.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
*/

// ignore the rule `header/header` to allow keeping `@jest-environment jsdom` on top:
// eslint-disable-next-line header/header
import { TextEncoder } from 'util';

/* eslint-disable import/first */
global.TextEncoder = TextEncoder; // polyfill TextEncoder for jsdom

import { InsecureContextError } from 'web3-errors';
import { encrypt } from '../../src/account';
import { validEncryptData } from '../fixtures/account';

describe('encrypt/decrypt in jsdom', () => {
describe('encrypt', () => {
describe('valid cases', () => {
it.each(validEncryptData)('%s', async input => {
const result = encrypt(input[0], input[1], input[2]);
await expect(result).rejects.toThrow(InsecureContextError);
});
});
});
});
10 changes: 7 additions & 3 deletions packages/web3-utils/src/converters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ export type EtherUnits = keyof typeof ethUnitMap;
export const bytesToUint8Array = (data: Bytes): Uint8Array | never => {
validator.validate(['bytes'], [data]);

if (data instanceof Uint8Array) {
return data;
if (data instanceof Uint8Array || data?.constructor?.name === 'Uint8Array') {
return data as Uint8Array;
}

if (Array.isArray(data)) {
Expand Down Expand Up @@ -588,7 +588,11 @@ export const toChecksumAddress = (address: Address): string => {

const lowerCaseAddress = address.toLowerCase().replace(/^0x/i, '');

const hash = utils.uint8ArrayToHexString(keccak256(utf8ToBytes(lowerCaseAddress)));
// calling `Uint8Array.from` because `noble-hashes` checks with `instanceof Uint8Array` that fails in some edge cases:
// https://github.com/paulmillr/noble-hashes/issues/25#issuecomment-1750106284
const hash = utils.uint8ArrayToHexString(
keccak256(Uint8Array.from(utf8ToBytes(lowerCaseAddress))),
);

if (
isNullish(hash) ||
Expand Down
12 changes: 9 additions & 3 deletions packages/web3-validator/src/validation/bytes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,21 @@
/**
* checks input if typeof data is valid Uint8Array input
*/
export const isUint8Array = (data: ValidInputTypes) => data instanceof Uint8Array;
export const isUint8Array = (data: ValidInputTypes) =>
data instanceof Uint8Array || data?.constructor?.name === 'Uint8Array';

Check warning on line 26 in packages/web3-validator/src/validation/bytes.ts

View check run for this annotation

Codecov / codecov/patch

packages/web3-validator/src/validation/bytes.ts#L26

Added line #L26 was not covered by tests

export const isBytes = (
value: ValidInputTypes | Uint8Array | number[],
options: { abiType: string; size?: never } | { size: number; abiType?: never } = {
abiType: 'bytes',
},
) => {
if (typeof value !== 'string' && !Array.isArray(value) && !(value instanceof Uint8Array)) {
if (
typeof value !== 'string' &&
!Array.isArray(value) &&
!(value instanceof Uint8Array) &&
value?.constructor?.name !== 'Uint8Array'
) {
return false;
}

Expand All @@ -57,7 +63,7 @@
}
valueToCheck = new Uint8Array(value);
} else {
valueToCheck = value;
valueToCheck = value as Uint8Array;
}

if (options?.abiType) {
Expand Down
Loading