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

fix: query param handling in AuthService.signInCallback #8782

Merged
merged 1 commit into from
Apr 6, 2023
Merged
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
6 changes: 4 additions & 2 deletions changelog/unreleased/bugfix-open-external-apps
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
Bugfix: Open files in external app

We've fixed a bug that caused office documents not to be opened in app provider editors anymore.
We've fixed bugs that caused office documents not to be opened in app provider editors anymore.

https://github.com/owncloud/web/pull/8705
https://github.com/owncloud/web/issues/8695
https://github.com/owncloud/web/pull/8705
https://github.com/owncloud/web/issues/8773
https://github.com/owncloud/web/pull/8782
13 changes: 1 addition & 12 deletions packages/web-runtime/src/router/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { base, router } from './index'
import { RouteLocation, RouteParams, Router, RouteRecordNormalized } from 'vue-router'
import pick from 'lodash-es/pick'
import {
AuthContext,
authContextValues,
Expand All @@ -11,17 +10,7 @@ import {
export const buildUrl = (pathname) => {
const isHistoryMode = !!base
const baseUrl = new URL(window.location.href.split('#')[0])

// searchParams defines a set of search parameters which should be part of new url.
// The resulting querystring only contains the properties listed here.
const searchParams = new URLSearchParams(
pick(Object.fromEntries(new URLSearchParams(window.location.search).entries()), [
// needed for private links
'details'
])
).toString()

baseUrl.search = searchParams
baseUrl.search = ''

if (isHistoryMode) {
// in history mode we can't determine the base path, it must be provided by the document
Expand Down
18 changes: 3 additions & 15 deletions packages/web-runtime/src/services/auth/authService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
import { unref } from 'vue'
import { Ability } from 'web-pkg/src/utils'
import { Language } from 'vue3-gettext'
import pick from 'lodash-es/pick'

export class AuthService {
private clientService: ClientService
Expand Down Expand Up @@ -176,23 +175,12 @@ export class AuthService {
* Sign in callback gets called from the IDP after initial login.
*/
public async signInCallback() {
const currentQuery = unref(this.router.currentRoute).query

try {
await this.userManager.signinRedirectCallback(this.buildSignInCallbackUrl())

const redirectUrl = this.userManager.getAndClearPostLoginRedirectUrl()

// transportQuery defines a set of query parameters which should be part of router route replace.
// The resulting object only contains the properties listed here.
const transportQuery = pick(currentQuery, [
// needed for private links
'details'
])

const redirectRoute = this.router.resolve(this.userManager.getAndClearPostLoginRedirectUrl())
return this.router.replace({
path: redirectUrl,
query: transportQuery
path: redirectRoute.path,
...(redirectRoute.query && { query: redirectRoute.query })
})
} catch (e) {
console.warn('error during authentication:', e)
Expand Down
3 changes: 0 additions & 3 deletions packages/web-runtime/tests/unit/router/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ describe('buildUrl', () => {
${'https://localhost:9200/files/list/all'} | ${'/foo'} | ${'/login/foo'} | ${'https://localhost:9200/foo/login/foo'}
${'https://localhost:9200/files/list/all'} | ${'/'} | ${'/bar.html'} | ${'https://localhost:9200/bar.html'}
${'https://localhost:9200/files/list/all'} | ${'/foo'} | ${'/bar.html'} | ${'https://localhost:9200/foo/bar.html'}
${'https://localhost:9200/files/list/all?details=91953740'} | ${'/foo'} | ${'/bar.html'} | ${'https://localhost:9200/foo/bar.html?details=91953740'}
${'https://localhost:9200/files/list/all?details=91953740&unknown=87987987'} | ${'/foo'} | ${'/bar.html'} | ${'https://localhost:9200/foo/bar.html?details=91953740'}
${'https://localhost:9200/files/list/all?unknown=87987987'} | ${'/foo'} | ${'/bar.html'} | ${'https://localhost:9200/foo/bar.html'}
`('$path -> $expected', async ({ location, base, path, expected }) => {
delete window.location
window.location = new URL(location) as any
Expand Down
48 changes: 31 additions & 17 deletions packages/web-runtime/tests/unit/services/auth/authService.spec.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,41 @@
import { AuthService } from 'web-runtime/src/services/auth/authService'
import { createRouter } from 'web-test-helpers/src'

describe('AuthService', () => {
describe('signInCallback', () => {
it.each([
[{ details: 'details' }, { details: 'details' }],
[{ details: 'details', unknown: 'unknown' }, { details: 'details' }],
[{ unknown: 'unknown' }, {}]
])('forwards only whitelisted query parameters: %s = %s', async (query, expected: any) => {
const authService = new AuthService()
const replace = jest.fn()
['/', '/', {}],
['/?details=sharing', '/', { details: 'sharing' }],
[
'/external?contextRouteName=files-spaces-personal&fileId=0f897576',
'/external',
{
contextRouteName: 'files-spaces-personal',
fileId: '0f897576'
}
]
])(
'parses query params and passes them explicitly to router.replace: %s => %s %s',
async (url, path, query: any) => {
const authService = new AuthService()

jest.replaceProperty(authService as any, 'userManager', {
signinRedirectCallback: jest.fn(),
getAndClearPostLoginRedirectUrl: jest.fn()
})
jest.replaceProperty(authService as any, 'userManager', {
signinRedirectCallback: jest.fn(),
getAndClearPostLoginRedirectUrl: () => url
})

jest.replaceProperty(authService as any, 'router', {
currentRoute: { query },
replace
})
await authService.signInCallback()
const router = createRouter()
const replaceSpy = jest.spyOn(router, 'replace')

expect(replace.mock.calls[0][0].query).toEqual(expected)
})
authService.initialize(null, null, null, router, null, null)

await authService.signInCallback()

expect(replaceSpy).toHaveBeenCalledWith({
path,
query
})
}
)
})
})