MT#66045 Fix license route guard checking wrong meta field

routes.js checked `to.meta?.license` (singular) while every route
in router/routes.js sets `meta.licenses` (array), so the license
check never fired for any route. It also called
`hasLicenses([to.meta.licenses])`, double-wrapping an already-array
value `.every()` against that nested array would never match,
silently blocking any route that did require licenses.

Align the guard on `to.meta.licenses` and pass it to `hasLicenses`
without re-wrapping it, update the doc example.

Add jest tests for licenses and capabilities.

Change-Id: I513fbf87bf11fd8db8a3a916b3debcba2a12d6d5
master
Debora Crescenzo 4 days ago
parent 3a5b0b446a
commit f5b60cb77b

@ -45,7 +45,7 @@ default: {
}
// 4. License check
if (to.meta?.license) {
if (to.meta?.licenses) {
const isSpCe = store.getters['user/isSpCe']
// CE-specific check
@ -54,7 +54,7 @@ default: {
}
// License check for non-CE users
if (!isSpCe && !store.getters['user/hasLicenses']([to.meta.license])) {
if (!isSpCe && !store.getters['user/hasLicenses'](to.meta.licenses)) {
return next('/')
}
}

@ -50,7 +50,7 @@ export default ({ app, router }) => {
}
// 4. License check
if (to.meta?.license) {
if (to.meta?.licenses) {
const isSpCe = store.getters['user/isSpCe']
// CE-specific check
@ -59,7 +59,7 @@ export default ({ app, router }) => {
}
// License check for non-CE users
if (!isSpCe && !store.getters['user/hasLicenses']([to.meta.licenses])) {
if (!isSpCe && !store.getters['user/hasLicenses'](to.meta.licenses)) {
return next('/')
}
}

@ -0,0 +1,132 @@
jest.mock('quasar', () => ({
Dark: { set: jest.fn() }
}))
jest.mock('src/auth', () => ({
hasJwt: jest.fn(() => true),
getJwt: jest.fn(() => 'jwt-token'),
getSubscriberId: jest.fn(() => 1)
}))
jest.mock('src/boot/store', () => ({
store: {
getters: {},
commit: jest.fn()
}
}))
import routesBoot from 'src/boot/routes'
import { store } from 'src/boot/store'
function createRouter () {
return {
beforeEach: jest.fn(),
afterEach: jest.fn()
}
}
function installGuard () {
const router = createRouter()
routesBoot({ app: {}, router })
return router.beforeEach.mock.calls[0][0]
}
describe('router guard (src/boot/routes.js)', () => {
let next
beforeEach(() => {
jest.clearAllMocks()
next = jest.fn()
store.getters = {
'user/isAdmin': false,
'user/hasSubscriberProfileAttribute': jest.fn(() => true),
'user/hasSomeSubscriberProfileAttributes': jest.fn(() => true),
'user/isSpCe': false,
'user/hasLicenses': jest.fn((licenses) => licenses.every((license) => ['pbx', 'phonebook'].includes(license))),
'user/hasPlatformFeature': jest.fn(() => true),
'user/hasCapability': jest.fn((capability) => capability === 'cloudPbx')
}
})
describe('license check', () => {
it('allows a route with no licenses requirement', () => {
const guard = installGuard()
guard({ path: '/dashboard', meta: {} }, {}, next)
expect(store.getters['user/hasLicenses']).not.toHaveBeenCalled()
expect(next).toHaveBeenCalledWith()
})
it('allows a route whose single required license is active', () => {
const guard = installGuard()
guard({ path: '/pbx-configuration', meta: { licenses: ['pbx'] } }, {}, next)
expect(next).toHaveBeenCalledWith()
})
it('allows a route whose multiple required licenses are all active', () => {
const guard = installGuard()
guard({ path: '/pbx-configuration/customer-phonebook', meta: { licenses: ['pbx', 'phonebook'] } }, {}, next)
expect(next).toHaveBeenCalledWith()
})
it('blocks a route when one of several required licenses is missing', () => {
const guard = installGuard()
guard({ path: '/fax-server', meta: { licenses: ['pbx', 'fax'] } }, {}, next)
expect(next).toHaveBeenCalledWith('/')
})
it('bypasses the license check for CE users on a route that allows CE', () => {
store.getters['user/isSpCe'] = true
const guard = installGuard()
guard({ path: '/subscriber-phonebook', meta: { licenses: ['phonebook'], allowCE: true } }, {}, next)
expect(store.getters['user/hasLicenses']).not.toHaveBeenCalled()
expect(next).toHaveBeenCalledWith()
})
it('blocks CE users from a licensed route that does not allow CE', () => {
store.getters['user/isSpCe'] = true
const guard = installGuard()
guard({ path: '/pbx-configuration', meta: { licenses: ['pbx'] } }, {}, next)
expect(next).toHaveBeenCalledWith('/')
})
})
describe('capability check', () => {
it('allows a route with no capability requirement', () => {
const guard = installGuard()
guard({ path: '/dashboard', meta: {} }, {}, next)
expect(store.getters['user/hasCapability']).not.toHaveBeenCalled()
expect(next).toHaveBeenCalledWith()
})
it('allows a route whose required capability is present', () => {
const guard = installGuard()
guard({ path: '/pbx-configuration', meta: { capability: 'cloudPbx' } }, {}, next)
expect(store.getters['user/hasCapability']).toHaveBeenCalledWith('cloudPbx')
expect(next).toHaveBeenCalledWith()
})
it('blocks a route when the required capability is missing', () => {
const guard = installGuard()
guard({ path: '/call-recording', meta: { capability: 'callRecording' } }, {}, next)
expect(next).toHaveBeenCalledWith('/')
})
it('still evaluates the capability check after passing the license check', () => {
const guard = installGuard()
guard({ path: '/pbx-configuration', meta: { licenses: ['pbx'], capability: 'callRecording' } }, {}, next)
expect(store.getters['user/hasLicenses']).toHaveBeenCalledWith(['pbx'])
expect(store.getters['user/hasCapability']).toHaveBeenCalledWith('callRecording')
expect(next).toHaveBeenCalledWith('/')
})
})
})
Loading…
Cancel
Save