-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Ensure checkout cancel_to param is a relative url (#96514)
* Use a url origin check to confirm path is a relative url * Add tests around cancel_to
- Loading branch information
Showing
2 changed files
with
135 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
/** | ||
* @jest-environment jsdom | ||
*/ | ||
|
||
import { navigate } from 'calypso/lib/navigate'; | ||
import { leaveCheckout, isRelativeUrl } from '../lib/leave-checkout'; | ||
|
||
// Mock dependencies | ||
jest.mock( 'calypso/lib/analytics/tracks', () => ( { | ||
recordTracksEvent: jest.fn(), | ||
} ) ); | ||
|
||
jest.mock( 'calypso/lib/navigate', () => ( { | ||
navigate: jest.fn(), | ||
} ) ); | ||
|
||
describe( 'leaveCheckout', () => { | ||
beforeEach( () => { | ||
// Reset all mocks before each test | ||
jest.clearAllMocks(); | ||
// Setup window.location | ||
Object.defineProperty( window, 'location', { | ||
value: { | ||
href: 'https://wordpress.com/checkout', | ||
origin: 'https://wordpress.com', | ||
search: '', | ||
}, | ||
writable: true, | ||
} ); | ||
} ); | ||
|
||
describe( 'cancel_to parameter handling', () => { | ||
it( 'should navigate to cancel_to path when it is a relative URL', () => { | ||
window.location.search = '?cancel_to=/home'; | ||
|
||
leaveCheckout( { tracksEvent: 'checkout_cancel' } ); | ||
|
||
expect( navigate ).toHaveBeenCalledWith( '/home' ); | ||
} ); | ||
|
||
it( 'should not navigate to cancel_to path when it is an absolute URL', () => { | ||
window.location.search = '?cancel_to=https://example.com'; | ||
|
||
leaveCheckout( { tracksEvent: 'checkout_cancel' } ); | ||
|
||
expect( navigate ).not.toHaveBeenCalledWith( 'https://example.com' ); | ||
} ); | ||
|
||
it( 'should not navigate to cancel_to path when it is a protocol-relative URL', () => { | ||
window.location.search = '?cancel_to=//example.com'; | ||
|
||
leaveCheckout( { tracksEvent: 'checkout_cancel' } ); | ||
|
||
expect( navigate ).not.toHaveBeenCalledWith( '//example.com' ); | ||
} ); | ||
|
||
it( 'should not navigate to cancel_to path when it is trying to bypass relative path check', () => { | ||
window.location.search = '?cancel_to=/\\example.com'; | ||
|
||
leaveCheckout( { tracksEvent: 'checkout_cancel' } ); | ||
|
||
expect( navigate ).not.toHaveBeenCalledWith( '/\\example.com' ); | ||
} ); | ||
} ); | ||
} ); | ||
|
||
describe( 'isRelativeUrl', () => { | ||
beforeEach( () => { | ||
Object.defineProperty( window, 'location', { | ||
value: { | ||
href: 'https://wordpress.com/checkout', | ||
origin: 'https://wordpress.com', | ||
}, | ||
writable: true, | ||
} ); | ||
} ); | ||
|
||
describe( 'relative paths', () => { | ||
const testCases = [ | ||
'/home', | ||
'/path/to/page', | ||
'path', | ||
'./path', | ||
'../path', | ||
'https://wordpress.com/path', | ||
'wordpress.com/path', | ||
'//wordpress.com/path', | ||
'/\\wordpress.com/path', | ||
]; | ||
|
||
testCases.forEach( ( path ) => { | ||
it( `should return true for relative path: ${ path }`, () => { | ||
expect( isRelativeUrl( path ) ).toBe( true ); | ||
} ); | ||
} ); | ||
} ); | ||
|
||
describe( 'absolute URLs', () => { | ||
const testCases = [ | ||
'http://example.com', | ||
'//example.com', | ||
'https://example.com/path', | ||
'/\\example.com', | ||
]; | ||
|
||
testCases.forEach( ( url ) => { | ||
it( `should return false for absolute URL: ${ url }`, () => { | ||
expect( isRelativeUrl( url ) ).toBe( false ); | ||
} ); | ||
} ); | ||
} ); | ||
|
||
describe( 'invalid URLs', () => { | ||
const testCases = [ | ||
'javascript:alert(1)', | ||
'data:text/html,<script>alert(1)</script>', | ||
'mailto:[email protected]', | ||
]; | ||
|
||
testCases.forEach( ( url ) => { | ||
it( `should return false for invalid URL: ${ url }`, () => { | ||
expect( isRelativeUrl( url ) ).toBe( false ); | ||
} ); | ||
} ); | ||
} ); | ||
} ); |