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

[full-ci] ADD VUE history mode #6363

Merged
merged 8 commits into from
Feb 22, 2022
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
2 changes: 1 addition & 1 deletion .drone.star
Original file line number Diff line number Diff line change
Expand Up @@ -2019,7 +2019,7 @@ def setUpOauth2(forIntegrationApp, disableFileLocking):
"make vendor",
"cd %s || exit" % dir["server"],
"php occ a:e oauth2",
"php occ oauth2:add-client Web Cxfj9F9ZZWQbQZps1E1M0BszMz6OOFq3lxjSuc8Uh4HLEYb9KIfyRMmgY5ibXXrU 930C6aA0U1VhM03IfNiheR2EwSzRi4hRSpcNqIhhbpeSGU6h38xssVfNcGP0sSwQ %s" % oidcURL,
"php occ oauth2:add-client Web Cxfj9F9ZZWQbQZps1E1M0BszMz6OOFq3lxjSuc8Uh4HLEYb9KIfyRMmgY5ibXXrU 930C6aA0U1VhM03IfNiheR2EwSzRi4hRSpcNqIhhbpeSGU6h38xssVfNcGP0sSwQ %s false true" % oidcURL,
]

if (disableFileLocking):
Expand Down
8 changes: 8 additions & 0 deletions changelog/unreleased/enhancement-history-mode
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Enhancement: Option to enable Vue history mode

We've added the option to use vue's history mode. All configuration is done automatically by the system.
To enable it, add a `<base src="PATH">` header tag to `index.html`, `oidc-callback.html` and `oidc-silent-redirect.html`.
Adding `<base>` is not needed for ocis.

https://github.com/owncloud/web/issues/6363
https://github.com/owncloud/web/issues/6277
6 changes: 6 additions & 0 deletions changelog/unreleased/enhancement-sidecar-mode
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Enhancement: Run web as oc10 sidecar

We've added the option to run web in oc10 sidecar mode.
Copy `config/config.json.sample-oc10` to `config/config.json`, run `yarn server` and then `docker compose up oc10`.

https://github.com/owncloud/web/issues/6363
2 changes: 1 addition & 1 deletion config/config.json.sample-oc10
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"theme": "https://localhost:9100/themes/owncloud/theme.json",
"version": "0.1.0",
"auth": {
"clientId": "",
"clientId": "UmCVsEIxdWmssxa6uVRRPC3txYBVN4qqxooJbsPhuuoPmHk9Pt9Oy68N4ZaKXUYy",
"url": "http://localhost:8080/index.php/apps/oauth2/api/v1/token",
"authUrl": "http://localhost:8080/index.php/apps/oauth2/authorize"
},
Expand Down
8 changes: 8 additions & 0 deletions dev/docker/oc10.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
ARG OC10_IMAGE
FROM ${OC10_IMAGE}

RUN apt -qqy update \
&& apt -qqy --no-install-recommends install \
bash \
&& rm -rf /var/lib/apt/lists/* \
&& apt -qyy clean
18 changes: 16 additions & 2 deletions dev/docker/oc10.entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,28 @@ done

if [ ! -d /mnt/data/apps/testing ]
then
# testing app
git clone https://github.com/owncloud/testing.git /mnt/data/apps/testing
occ app:enable oauth2
occ app:enable testing
# oauth2 app
rm -rf /var/www/owncloud/apps/oauth2
git clone https://github.com/owncloud/oauth2.git /var/www/owncloud/apps/oauth2
make -C /var/www/owncloud/apps/oauth2 vendor
occ app:enable oauth2
occ oauth2:add-client \
web \
M8W5mo3wQV3VHWYsaYpWhkr8dwa949i4GljCkedHhl7GWqmHMkxSeJgK2PcS0jt5 \
sqvPYXK94tMsEEVOYORxg8Ufesi2kC4WpJJSYb0Kj1DSAYl6u2XvJZjc3VcitjDv \
http://host.docker.internal:8080/index.php/apps/web/oidc-callback.html
http://host.docker.internal:8080/index.php/apps/web/oidc-callback.html \
false \
true
occ oauth2:add-client \
web-sidecar \
UmCVsEIxdWmssxa6uVRRPC3txYBVN4qqxooJbsPhuuoPmHk9Pt9Oy68N4ZaKXUYy \
HW1fo6lbtgEERBQufBouJ4HID2QaDfngvIdc2vjDUE46qKB4JRG1YDir41LliReC \
http://localhost:9100/oidc-callback.html
occ config:system:set trusted_domains 0 --value="localhost"
occ config:system:set cors.allowed-domains 0 --value="http://localhost:9100"
fi

if [ -d /var/www/owncloud/apps/web/ ]
Expand Down
6 changes: 5 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ services:
- host.docker.internal:${DOCKER_HOST:-host-gateway}

oc10:
image: ${OC10_IMAGE:-owncloud/server:latest}
build:
dockerfile: oc10.Dockerfile
context: ./dev/docker
args:
OC10_IMAGE: ${OC10_IMAGE:-owncloud/server:latest}
container_name: web_oc10
ports:
- 8080:8080
Expand Down
13 changes: 8 additions & 5 deletions packages/web-container/oidc-callback.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<body>
<script>
window.onload = function() {
window.location.href = window.location.origin +
window.location.pathname.substr(0, window.location.pathname.length - 18) +
"index.html#/oidc-callback" + window.location.search;
}
window.onload = function () {
const base = document.querySelector('base')
const path = base ? new URL(base.href).pathname.split('/') : [...window.location.pathname.split('/').slice(0, -1), 'index.html#']
const url = new URL([...path, 'oidc-callback'].filter(Boolean).join('/'), window.location.origin)
window.location.href = url.href + window.location.search
}
</script>
</body>
</html>
13 changes: 8 additions & 5 deletions packages/web-container/oidc-silent-redirect.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<body>
<script>
window.onload = function() {
window.location.href = window.location.origin +
window.location.pathname.substr(0, window.location.pathname.length - 25) +
"index.html#/oidc-silent-redirect" + window.location.search;
}
window.onload = function () {
const base = document.querySelector('base')
const path = base ? new URL(base.href).pathname.split('/') : [...window.location.pathname.split('/').slice(0, -1), 'index.html#']
const url = new URL([...path, 'oidc-silent-redirect'].filter(Boolean).join('/'), window.location.origin)
window.location.href = url.href + window.location.search
}
</script>
</body>
</html>
2 changes: 1 addition & 1 deletion packages/web-runtime/src/defaults/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import '@fortawesome/fontawesome-free/attribution'

export { default as Vue } from './vue'
export { default as DesignSystem } from 'owncloud-design-system'
export { default as Router } from '../router'

export const store = createStore(Vuex.Store, { ...Store })
export const pages = { success: App, failure: missingOrInvalidConfigPage }
export const translations = merge({}, coreTranslations, odsTranslations)
Expand Down
4 changes: 3 additions & 1 deletion packages/web-runtime/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import {
translations,
supportedLanguages,
store,
Router as router,
Vue
} from './defaults'

import { router } from './router'

import {
requestConfiguration,
announceApplications,
Expand Down
203 changes: 117 additions & 86 deletions packages/web-runtime/src/router/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,67 +10,131 @@ import Account from '../pages/account.vue'

Vue.use(Router)

// type: patch
// temporary patch till we have upgraded web to the latest vue router which make this obsolete
// this takes care that routes like 'foo/bar/baz' which by default would be converted to 'foo%2Fbar%2Fbaz' stay as they are
// should immediately go away and be removed after finalizing the update
// to apply the patch to a route add meta.patchCleanPath = true to it
// to patch needs to be enabled on a route level, to do so add meta.patchCleanPath = true property to the route
const patchRouter = (router) => {
const bindMatcher = router.match.bind(router)
const cleanPath = (route) =>
[
['%2F', '/'],
['//', '/']
].reduce((path, rule) => path.replaceAll(rule[0], rule[1]), route || '')

router.match = (raw, current, redirectFrom) => {
const bindMatch = bindMatcher(raw, current, redirectFrom)

if (!get(bindMatch, 'meta.patchCleanPath', false)) {
return bindMatch
}

return {
...bindMatch,
path: cleanPath(bindMatch.path),
fullPath: cleanPath(bindMatch.fullPath)
}
}

return router
}

// just a dummy function to trick gettext tools
function $gettext(msg) {
return msg
}

const router = new Router({
// mode: 'history',
parseQuery(query) {
return qs.parse(query)
},
stringifyQuery(obj) {
return qs.stringify(obj, {
allowDots: true,
addQueryPrefix: true
})
},
routes: [
{
path: '/login',
name: 'login',
component: LoginPage,
meta: { auth: false, title: $gettext('Login') }
},
{
path: '/oidc-callback',
name: 'oidcCallback',
component: OidcCallbackPage,
meta: { auth: false, title: $gettext('Oidc callback') }
},
{
path: '/oidc-silent-redirect',
name: 'oidcSilentRedirect',
component: OidcCallbackPage,
meta: { auth: false, title: $gettext('Oidc redirect') }
},
{
path: '/f/:fileId',
name: 'privateLink',
redirect: '/files/ops/resolver/private-link/:fileId',
meta: { title: $gettext('Private link') }
},
{
path: '/s/:token',
name: 'publicLink',
redirect: '/files/ops/resolver/public-link/:token',
meta: { auth: false, title: $gettext('Public link') }
const base = document.querySelector('base')
export const router = patchRouter(
new Router({
parseQuery(query) {
return qs.parse(query)
},
{
path: '/access-denied',
name: 'accessDenied',
component: AccessDeniedPage,
meta: { auth: false, title: $gettext('Access denied') }
stringifyQuery(obj) {
return qs.stringify(obj, {
allowDots: true,
addQueryPrefix: true
})
},
{
path: '/account',
name: 'account',
component: Account,
meta: { title: $gettext('Account') }
...(base && {
mode: 'history',
base: new URL(base.href).pathname
}),
routes: [
{
path: '/login',
name: 'login',
component: LoginPage,
meta: { auth: false, title: $gettext('Login') }
},
{
path: '/oidc-callback',
component: OidcCallbackPage,
meta: { auth: false, title: $gettext('Oidc callback') }
},
{
path: '/oidc-silent-redirect',
component: OidcCallbackPage,
meta: { auth: false, title: $gettext('Oidc redirect') }
},
{
path: '/f/:fileId',
name: 'privateLink',
redirect: '/files/ops/resolver/private-link/:fileId',
meta: { title: $gettext('Private link') }
},
{
path: '/s/:token',
name: 'publicLink',
redirect: '/files/ops/resolver/public-link/:token',
meta: { auth: false, title: $gettext('Public link') }
},
{
path: '/access-denied',
name: 'accessDenied',
component: AccessDeniedPage,
meta: { auth: false, title: $gettext('Access denied') }
},
{
path: '/account',
name: 'account',
component: Account,
meta: { title: $gettext('Account') }
}
]
})
)

export const buildUrl = (pathname) => {
const isHistoryMode = !!base
const baseUrl = new URL(window.location.href.split('#')[0])
if (isHistoryMode) {
// in history mode we can't determine the base path, it must be provided by the document
baseUrl.pathname = new URL(base.href).pathname
} else {
// in hash mode, auto-determine the base path by removing `/index.html`
if (baseUrl.pathname.endsWith('/index.html')) {
baseUrl.pathname = baseUrl.pathname.split('/').slice(0, -1).filter(Boolean).join('/')
}
]
})
}

/**
* build full url by either
* - concatenating baseUrl and pathname (for unknown/non-router urls, e.g. `oidc-callback.html`) or
* - resolving via router (for known routes)
*/
if (/\.(html?)$/i.test(pathname)) {
baseUrl.pathname = [...baseUrl.pathname.split('/'), ...pathname.split('/')]
.filter(Boolean)
.join('/')
} else {
baseUrl[isHistoryMode ? 'pathname' : 'hash'] = router.resolve(pathname).href
}

return baseUrl.href
}

router.beforeEach(function (to, from, next) {
const store = Vue.$store
Expand Down Expand Up @@ -119,36 +183,3 @@ const isAuthRequired = (router, to) => {
}
return false
}

// type: patch
// temporary patch till we have upgraded web to the latest vue router which make this obsolete
// this takes care that routes like 'foo/bar/baz' which by default would be converted to 'foo%2Fbar%2Fbaz' stay as they are
// should immediately go away and be removed after finalizing the update
// to apply the patch to a route add meta.patchCleanPath = true to it
// to patch needs to be enabled on a route level, to do so add meta.patchCleanPath = true property to the route
const patchRouter = (router) => {
const bindMatcher = router.match.bind(router)
const cleanPath = (route) =>
[
['%2F', '/'],
['//', '/']
].reduce((path, rule) => path.replaceAll(rule[0], rule[1]), route || '')

router.match = (raw, current, redirectFrom) => {
const bindMatch = bindMatcher(raw, current, redirectFrom)

if (!get(bindMatch, 'meta.patchCleanPath', false)) {
return bindMatch
}

return {
...bindMatch,
path: cleanPath(bindMatch.path),
fullPath: cleanPath(bindMatch.fullPath)
}
}

return router
}

export default patchRouter(router)
11 changes: 4 additions & 7 deletions packages/web-runtime/src/services/auth.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
import { Log, User, UserManager, WebStorageStateStore } from 'oidc-client'
import { buildUrl } from '../router'

export function initVueAuthenticate(config) {
if (config) {
const store = new WebStorageStateStore({
prefix: 'oc_oAuth',
store: sessionStorage
})
let baseUrl = window.location.href.split('#')[0]
if (baseUrl.endsWith('/index.html')) {
baseUrl = baseUrl.substr(0, baseUrl.length - 10)
}
const openIdConfig = {
userStore: store,
redirect_uri: baseUrl + 'oidc-callback.html',
redirect_uri: buildUrl('/oidc-callback.html'),
response_type: 'code', // code triggers auth code grant flow
response_mode: 'query',
scope: 'openid profile offline_access',
monitorSession: false,
// set uri directly to the login route to prevent problems with query parameters.
// See https://github.com/owncloud/web/issues/3285
post_logout_redirect_uri: baseUrl + '#/login',
silent_redirect_uri: baseUrl + 'oidc-silent-redirect.html',
post_logout_redirect_uri: buildUrl('/login'),
silent_redirect_uri: buildUrl('/oidc-silent-redirect.html'),
accessTokenExpiringNotificationTime: 10,
automaticSilentRenew: true,
filterProtocolClaims: true,
Expand Down
Loading