diff --git a/.husky/pre-push b/.husky/pre-push index 3dc4fa4bcd0..05b3f2a4632 100755 --- a/.husky/pre-push +++ b/.husky/pre-push @@ -1,8 +1,11 @@ #!/bin/bash . "$(dirname "$0")/_/husky.sh" -# Allows us to read user input below, redirects script's input to the terminal. -exec < /dev/tty +# check if main stream (stdout and stderr) are attached to the terminal +if [ -t 1 ] && [ -t 2 ]; then + # Allows us to read user input below, redirects script's input to the terminal. + exec < /dev/tty +fi PROTECTED_BRANCH=("develop" "trunk") CURRENT_BRANCH=$(git branch --show-current) diff --git a/changelog/enhance-pre-push-hook b/changelog/enhance-pre-push-hook new file mode 100644 index 00000000000..9a3b3e2919c --- /dev/null +++ b/changelog/enhance-pre-push-hook @@ -0,0 +1,4 @@ +Significance: minor +Type: dev + +Ensure pre-push hook understands terminal & non-terminal environments diff --git a/changelog/fix-gateway-individual-settings b/changelog/fix-gateway-individual-settings new file mode 100644 index 00000000000..6eb09cd2a3a --- /dev/null +++ b/changelog/fix-gateway-individual-settings @@ -0,0 +1,4 @@ +Significance: minor +Type: fix + +Ensure every gateway has individual settings object. diff --git a/changelog/update-deposit-details-validate-user-input b/changelog/update-deposit-details-validate-user-input new file mode 100644 index 00000000000..87bf37a3036 --- /dev/null +++ b/changelog/update-deposit-details-validate-user-input @@ -0,0 +1,4 @@ +Significance: minor +Type: update + +Validate deposit id before sending a request to fetch deposit. diff --git a/client/data/deposits/resolvers.js b/client/data/deposits/resolvers.js index 65d6eda9d40..52961f25570 100644 --- a/client/data/deposits/resolvers.js +++ b/client/data/deposits/resolvers.js @@ -30,6 +30,12 @@ import { formatDateValue } from 'utils'; * @param {string} id Identifier for specified deposit to retrieve. */ export function* getDeposit( id ) { + // Validate input to avoid path traversal request. + // Avoid lookup if the id contains any unexpected characters. + if ( /\W/.test( id ) ) { + return; + } + const path = addQueryArgs( `${ NAMESPACE }/deposits/${ id }` ); try { diff --git a/client/data/deposits/test/resolvers.js b/client/data/deposits/test/resolvers.js index 71c9c4e16dd..7678aba1717 100644 --- a/client/data/deposits/test/resolvers.js +++ b/client/data/deposits/test/resolvers.js @@ -20,6 +20,8 @@ import { import { getDeposit, getDeposits, getDepositsSummary } from '../resolvers'; +jest.mock( '@wordpress/data-controls' ); + const depositsResponse = { data: [ { @@ -57,36 +59,54 @@ const filterQuery = { }; describe( 'getDeposit resolver', () => { - let generator = null; + describe( 'on', () => { + let generator = null; - beforeEach( () => { - generator = getDeposit( 'test_dep_1' ); - expect( generator.next().value ).toEqual( - apiFetch( { path: '/wc/v3/payments/deposits/test_dep_1' } ) - ); - } ); + beforeEach( () => { + generator = getDeposit( 'test_dep_1' ); + expect( generator.next().value ).toEqual( + apiFetch( { path: '/wc/v3/payments/deposits/test_dep_1' } ) + ); + } ); - afterEach( () => { - expect( generator.next().done ).toStrictEqual( true ); - } ); + afterEach( () => { + expect( generator.next().done ).toStrictEqual( true ); + } ); - describe( 'on success', () => { - test( 'should update state with deposit data', () => { - expect( - generator.next( depositsResponse.data[ 0 ] ).value - ).toEqual( updateDeposit( depositsResponse.data[ 0 ] ) ); + describe( 'success', () => { + test( 'should update state with deposit data', () => { + expect( + generator.next( depositsResponse.data[ 0 ] ).value + ).toEqual( updateDeposit( depositsResponse.data[ 0 ] ) ); + } ); + } ); + + describe( 'error', () => { + test( 'should update state with error on error', () => { + expect( generator.throw( errorResponse ).value ).toEqual( + controls.dispatch( + 'core/notices', + 'createErrorNotice', + expect.any( String ) + ) + ); + } ); } ); } ); - describe( 'on error', () => { - test( 'should update state with error on error', () => { - expect( generator.throw( errorResponse ).value ).toEqual( - controls.dispatch( - 'core/notices', - 'createErrorNotice', - expect.any( String ) - ) - ); + describe( 'validation', () => { + let generator = null; + + beforeEach( () => { + jest.clearAllMocks(); + } ); + + test( "shouldn't fetch deposit with non-word-character deposit id", () => { + generator = getDeposit( '../path?a=b&c=d' ); + const next = generator.next(); + expect( next.value ).toStrictEqual( undefined ); + expect( next.done ).toStrictEqual( true ); + expect( apiFetch ).not.toBeCalled(); } ); } ); } ); @@ -101,6 +121,9 @@ describe( 'getDeposits resolver', () => { 'page=1&pagesize=25&match=all&store_currency_is=gbp&date_before=2020-04-29%2003%3A59%3A59&date_after=2020-04-29%2004%3A00%3A00&date_between%5B0%5D=2020-04-28%2004%3A00%3A00&date_between%5B1%5D=2020-04-30%2003%3A59%3A59&status_is=paid&status_is_not=failed'; beforeEach( () => { + apiFetch.mockImplementation( () => { + return 'something'; + } ); generator = getDeposits( query ); expect( generator.next().value ).toEqual( apiFetch( { diff --git a/includes/class-wc-payment-gateway-wcpay.php b/includes/class-wc-payment-gateway-wcpay.php index 423d42ba190..98ce26aaed2 100644 --- a/includes/class-wc-payment-gateway-wcpay.php +++ b/includes/class-wc-payment-gateway-wcpay.php @@ -2399,8 +2399,7 @@ public function get_option( $key, $empty_value = null ) { * Overrides parent method so the option key is the same as the parent class. */ public function get_option_key() { - // Intentionally using self instead of static so options are loaded from main gateway settings. - return $this->plugin_id . self::GATEWAY_ID . '_settings'; + return $this->plugin_id . $this->id . '_settings'; }