Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wiki-js
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
1
Issues
1
List
Board
Labels
Milestones
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
wiki-js
Commits
d5fa587c
Unverified
Commit
d5fa587c
authored
May 24, 2022
by
Nicolas Giard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat(admin): migrate extensions + security to vue 3 composable
parent
3d2e5c9d
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
229 additions
and
184 deletions
+229
-184
settings.json
.vscode/settings.json
+2
-1
AdminExtensions.vue
ux/src/pages/AdminExtensions.vue
+72
-49
AdminSecurity.vue
ux/src/pages/AdminSecurity.vue
+153
-132
routes.js
ux/src/router/routes.js
+2
-2
No files found.
.vscode/settings.json
View file @
d5fa587c
...
...
@@ -12,5 +12,6 @@
},
"i18n-ally.localesPaths"
:
[
"ux/src/i18n/locales"
]
],
"i18n-ally.keystyle"
:
"nested"
}
ux/src/pages/AdminExtensions.vue
View file @
d5fa587c
...
...
@@ -4,8 +4,8 @@ q-page.admin-extensions
.col-auto
img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-module.svg')
.col.q-pl-md
.text-h5.text-primary.animated.fadeInLeft
{{
$
t
(
'admin.extensions.title'
)
}}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s
{{
$
t
(
'admin.extensions.subtitle'
)
}}
.text-h5.text-primary.animated.fadeInLeft
{{
t
(
'admin.extensions.title'
)
}}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s
{{
t
(
'admin.extensions.subtitle'
)
}}
.col-auto
q-btn.acrylic-btn.q-mr-sm(
icon='las la-question-circle'
...
...
@@ -19,7 +19,7 @@ q-page.admin-extensions
icon='las la-redo-alt'
flat
color='secondary'
:loading='loading > 0'
:loading='
state.
loading > 0'
@click='load'
)
q-separator(inset)
...
...
@@ -28,7 +28,7 @@ q-page.admin-extensions
q-card.shadow-1
q-list(separator)
q-item(
v-for='(ext, idx) of extensions'
v-for='(ext, idx) of
state.
extensions'
:key='`ext-` + ext.key'
)
blueprint-icon(icon='module')
...
...
@@ -49,9 +49,9 @@ q-page.admin-extensions
q-tooltip(
anchor='center left'
self='center right'
)
{{
$
t
(
'admin.extensions.installed'
)
}}
)
{{
t
(
'admin.extensions.installed'
)
}}
q-btn(
:label='
$
t(`admin.extensions.install`)'
:label='t(`admin.extensions.install`)'
color='blue-7'
v-if='ext.isCompatible && !ext.isInstalled && ext.isInstallable'
@click='install(ext)'
...
...
@@ -59,21 +59,21 @@ q-page.admin-extensions
)
q-btn(
v-else-if='ext.isCompatible && ext.isInstalled && ext.isInstallable'
:label='
$
t(`admin.extensions.reinstall`)'
:label='t(`admin.extensions.reinstall`)'
color='blue-7'
@click='install(ext)'
no-caps
)
q-btn(
v-else-if='ext.isCompatible && ext.isInstalled && !ext.isInstallable'
:label='
$
t(`admin.extensions.installed`)'
:label='t(`admin.extensions.installed`)'
color='positive'
no-caps
:ripple='false'
)
q-btn(
v-else-if='ext.isCompatible'
:label='
$
t(`admin.extensions.instructions`)'
:label='t(`admin.extensions.instructions`)'
icon='las la-info-circle'
color='indigo'
outline
...
...
@@ -85,45 +85,62 @@ q-page.admin-extensions
q-tooltip(
anchor='center left'
self='center right'
)
{{
$
t
(
'admin.extensions.instructionsHint'
)
}}
)
{{
t
(
'admin.extensions.instructionsHint'
)
}}
q-btn(
v-else
color='negative'
outline
:label='
$
t(`admin.extensions.incompatible`)'
:label='t(`admin.extensions.incompatible`)'
no-caps
:ripple='false'
)
</
template
>
<
script
>
<
script
setup
>
import
gql
from
'graphql-tag'
import
cloneDeep
from
'lodash/cloneDeep'
import
{
createMetaMixin
}
from
'quasar'
import
{
useI18n
}
from
'vue-i18n'
import
{
useMeta
,
useQuasar
}
from
'quasar'
import
{
computed
,
onMounted
,
reactive
,
watch
}
from
'vue'
export
default
{
mixins
:
[
createMetaMixin
(
function
()
{
return
{
title
:
this
.
$t
(
'admin.extensions.title'
)
}
})
],
data
()
{
return
{
import
{
useAdminStore
}
from
'src/stores/admin'
import
{
useSiteStore
}
from
'src/stores/site'
import
{
useDataStore
}
from
'src/stores/data'
// QUASAR
const
$q
=
useQuasar
()
// STORES
const
adminStore
=
useAdminStore
()
const
siteStore
=
useSiteStore
()
const
dataStore
=
useDataStore
()
// I18N
const
{
t
}
=
useI18n
()
// META
useMeta
({
title
:
t
(
'admin.extensions.title'
)
})
// DATA
const
state
=
reactive
({
loading
:
false
,
extensions
:
[]
}
},
mounted
()
{
this
.
load
()
},
methods
:
{
async
load
()
{
this
.
loading
++
this
.
$q
.
loading
.
show
()
const
resp
=
await
this
.
$apollo
.
query
({
})
// METHODS
async
function
load
()
{
state
.
loading
++
$q
.
loading
.
show
()
const
resp
=
await
APOLLO_CLIENT
.
query
({
query
:
gql
`
query fetchExtensions {
systemExtensions {
...
...
@@ -138,17 +155,18 @@ export default {
`
,
fetchPolicy
:
'network-only'
})
this
.
extensions
=
cloneDeep
(
resp
?.
data
?.
systemExtensions
)
this
.
$q
.
loading
.
hide
()
this
.
loading
--
},
async
install
(
ext
)
{
this
.
$q
.
loading
.
show
({
message
:
this
.
$t
(
'admin.extensions.installing'
)
+
'<br>'
+
this
.
$t
(
'admin.extensions.installingHint'
),
state
.
extensions
=
cloneDeep
(
resp
?.
data
?.
systemExtensions
)
$q
.
loading
.
hide
()
state
.
loading
--
}
async
function
install
(
ext
)
{
$q
.
loading
.
show
({
message
:
t
(
'admin.extensions.installing'
)
+
'<br>'
+
t
(
'admin.extensions.installingHint'
),
html
:
true
})
try
{
const
respRaw
=
await
this
.
$apollo
.
mutate
({
const
respRaw
=
await
APOLLO_CLIENT
.
mutate
({
mutation
:
gql
`
mutation installExtension (
$key: String!
...
...
@@ -168,26 +186,31 @@ export default {
}
})
if
(
respRaw
.
data
?.
installExtension
?.
status
?.
succeeded
)
{
this
.
$q
.
notify
({
$q
.
notify
({
type
:
'positive'
,
message
:
this
.
$
t
(
'admin.extensions.installSuccess'
)
message
:
t
(
'admin.extensions.installSuccess'
)
})
ext
.
isInstalled
=
true
this
.
$forceUpdate
()
//
this.$forceUpdate()
}
else
{
throw
new
Error
(
respRaw
.
data
?.
installExtension
?.
status
?.
message
||
'An unexpected error occured'
)
}
}
catch
(
err
)
{
this
.
$q
.
notify
({
$q
.
notify
({
type
:
'negative'
,
message
:
this
.
$
t
(
'admin.extensions.installFailed'
),
message
:
t
(
'admin.extensions.installFailed'
),
caption
:
err
.
message
})
}
this
.
$q
.
loading
.
hide
()
}
}
$q
.
loading
.
hide
()
}
// MOUNTED
onMounted
(()
=>
{
load
()
})
</
script
>
<
style
lang=
'scss'
>
...
...
ux/src/pages/AdminSecurity.vue
View file @
d5fa587c
...
...
@@ -4,8 +4,8 @@ q-page.admin-mail
.col-auto
img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-protect.svg')
.col.q-pl-md
.text-h5.text-primary.animated.fadeInLeft
{{
$
t
(
'admin.security.title'
)
}}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s
{{
$
t
(
'admin.security.subtitle'
)
}}
.text-h5.text-primary.animated.fadeInLeft
{{
t
(
'admin.security.title'
)
}}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s
{{
t
(
'admin.security.subtitle'
)
}}
.col-auto
q-btn.q-mr-sm.acrylic-btn(
icon='las la-question-circle'
...
...
@@ -19,16 +19,16 @@ q-page.admin-mail
icon='las la-redo-alt'
flat
color='secondary'
:loading='loading > 0'
:loading='
state.
loading > 0'
@click='load'
)
q-btn(
unelevated
icon='
mdi
-check'
:label='
$
t(`common.actions.apply`)'
icon='
fa-solid fa
-check'
:label='t(`common.actions.apply`)'
color='secondary'
@click='save'
:loading='loading > 0'
:loading='
state.
loading > 0'
)
q-separator(inset)
.row.q-pa-md.q-col-gutter-md
...
...
@@ -38,134 +38,134 @@ q-page.admin-mail
//- -----------------------
q-card.shadow-1.q-pb-sm
q-card-section
.text-subtitle1
{{
$
t
(
'admin.security.title'
)
}}
.text-subtitle1
{{
t
(
'admin.security.title'
)
}}
q-item.q-pt-none
q-item-section
q-card.bg-negative.text-white.rounded-borders(flat)
q-card-section.items-center(horizontal)
q-card-section.col-auto.q-pr-none
q-icon(name='las la-exclamation-triangle', size='sm')
q-card-section.text-caption
{{
$
t
(
'admin.security.warn'
)
}}
q-card-section.text-caption
{{
t
(
'admin.security.warn'
)
}}
q-item(tag='label', v-ripple)
blueprint-icon(icon='rfid-signal')
q-item-section
q-item-label
{{
$
t
(
`admin.security.disallowFloc`
)
}}
q-item-label(caption)
{{
$
t
(
`admin.security.disallowFlocHint`
)
}}
q-item-label
{{
t
(
`admin.security.disallowFloc`
)
}}
q-item-label(caption)
{{
t
(
`admin.security.disallowFlocHint`
)
}}
q-item-section(avatar)
q-toggle(
v-model='config.disallowFloc'
v-model='
state.
config.disallowFloc'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='
$
t(`admin.security.disallowFloc`)'
:aria-label='t(`admin.security.disallowFloc`)'
)
q-separator.q-my-sm(inset)
q-item(tag='label', v-ripple)
blueprint-icon(icon='maximize-window')
q-item-section
q-item-label
{{
$
t
(
`admin.security.disallowIframe`
)
}}
q-item-label(caption)
{{
$
t
(
`admin.security.disallowIframeHint`
)
}}
q-item-label
{{
t
(
`admin.security.disallowIframe`
)
}}
q-item-label(caption)
{{
t
(
`admin.security.disallowIframeHint`
)
}}
q-item-section(avatar)
q-toggle(
v-model='config.disallowIframe'
v-model='
state.
config.disallowIframe'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='
$
t(`admin.security.disallowIframe`)'
:aria-label='t(`admin.security.disallowIframe`)'
)
q-separator.q-my-sm(inset)
q-item(tag='label', v-ripple)
blueprint-icon(icon='do-not-touch')
q-item-section
q-item-label
{{
$
t
(
`admin.security.enforceSameOriginReferrerPolicy`
)
}}
q-item-label(caption)
{{
$
t
(
`admin.security.enforceSameOriginReferrerPolicyHint`
)
}}
q-item-label
{{
t
(
`admin.security.enforceSameOriginReferrerPolicy`
)
}}
q-item-label(caption)
{{
t
(
`admin.security.enforceSameOriginReferrerPolicyHint`
)
}}
q-item-section(avatar)
q-toggle(
v-model='config.enforceSameOriginReferrerPolicy'
v-model='
state.
config.enforceSameOriginReferrerPolicy'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='
$
t(`admin.security.enforceSameOriginReferrerPolicy`)'
:aria-label='t(`admin.security.enforceSameOriginReferrerPolicy`)'
)
q-separator.q-my-sm(inset)
q-item(tag='label', v-ripple)
blueprint-icon(icon='curly-arrow')
q-item-section
q-item-label
{{
$
t
(
`admin.security.disallowOpenRedirect`
)
}}
q-item-label(caption)
{{
$
t
(
`admin.security.disallowOpenRedirectHint`
)
}}
q-item-label
{{
t
(
`admin.security.disallowOpenRedirect`
)
}}
q-item-label(caption)
{{
t
(
`admin.security.disallowOpenRedirectHint`
)
}}
q-item-section(avatar)
q-toggle(
v-model='config.disallowOpenRedirect'
v-model='
state.
config.disallowOpenRedirect'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='
$
t(`admin.security.disallowOpenRedirect`)'
:aria-label='t(`admin.security.disallowOpenRedirect`)'
)
q-separator.q-my-sm(inset)
q-item(tag='label', v-ripple)
blueprint-icon(icon='download-from-cloud')
q-item-section
q-item-label
{{
$
t
(
`admin.security.forceAssetDownload`
)
}}
q-item-label(caption)
{{
$
t
(
`admin.security.forceAssetDownloadHint`
)
}}
q-item-label
{{
t
(
`admin.security.forceAssetDownload`
)
}}
q-item-label(caption)
{{
t
(
`admin.security.forceAssetDownloadHint`
)
}}
q-item-section(avatar)
q-toggle(
v-model='config.forceAssetDownload'
v-model='
state.
config.forceAssetDownload'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='
$
t(`admin.security.forceAssetDownload`)'
:aria-label='t(`admin.security.forceAssetDownload`)'
)
q-separator.q-my-sm(inset)
q-item(tag='label', v-ripple)
blueprint-icon(icon='door-sensor-alarmed')
q-item-section
q-item-label
{{
$
t
(
`admin.security.trustProxy`
)
}}
q-item-label(caption)
{{
$
t
(
`admin.security.trustProxyHint`
)
}}
q-item-label
{{
t
(
`admin.security.trustProxy`
)
}}
q-item-label(caption)
{{
t
(
`admin.security.trustProxyHint`
)
}}
q-item-section(avatar)
q-toggle(
v-model='config.trustProxy'
v-model='
state.
config.trustProxy'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='
$
t(`admin.security.trustProxy`)'
:aria-label='t(`admin.security.trustProxy`)'
)
//- -----------------------
//- HSTS
//- -----------------------
q-card.shadow-1.q-pb-sm.q-mt-md
q-card-section
.text-subtitle1
{{
$
t
(
'admin.security.hsts'
)
}}
.text-subtitle1
{{
t
(
'admin.security.hsts'
)
}}
q-item(tag='label', v-ripple)
blueprint-icon(icon='hips')
q-item-section
q-item-label
{{
$
t
(
`admin.security.enforceHsts`
)
}}
q-item-label(caption)
{{
$
t
(
`admin.security.enforceHstsHint`
)
}}
q-item-label
{{
t
(
`admin.security.enforceHsts`
)
}}
q-item-label(caption)
{{
t
(
`admin.security.enforceHstsHint`
)
}}
q-item-section(avatar)
q-toggle(
v-model='config.enforceHsts'
v-model='
state.
config.enforceHsts'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='
$
t(`admin.security.enforceHsts`)'
:aria-label='t(`admin.security.enforceHsts`)'
)
template(v-if='config.enforceHsts')
template(v-if='
state.
config.enforceHsts')
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='timer')
q-item-section
q-item-label
{{
$
t
(
`admin.security.hstsDuration`
)
}}
q-item-label(caption)
{{
$
t
(
`admin.security.hstsDurationHint`
)
}}
q-item-label
{{
t
(
`admin.security.hstsDuration`
)
}}
q-item-label(caption)
{{
t
(
`admin.security.hstsDurationHint`
)
}}
q-item-section(style='flex: 0 0 200px;')
q-select(
outlined
v-model='config.hstsDuration'
v-model='
state.
config.hstsDuration'
:options='hstsDurations'
option-value='value'
option-label='text'
emit-value
map-options
dense
:aria-label='
$
t(`admin.security.hstsDuration`)'
:aria-label='t(`admin.security.hstsDuration`)'
)
.col-12.col-lg-6
...
...
@@ -174,53 +174,53 @@ q-page.admin-mail
//- -----------------------
q-card.shadow-1.q-pb-sm
q-card-section
.text-subtitle1
{{
$
t
(
'admin.security.uploads'
)
}}
.text-subtitle1
{{
t
(
'admin.security.uploads'
)
}}
q-item.q-pt-none
q-item-section
q-card.bg-info.text-white.rounded-borders(flat)
q-card-section.items-center(horizontal)
q-card-section.col-auto.q-pr-none
q-icon(name='las la-info-circle', size='sm')
q-card-section.text-caption
{{
$
t
(
'admin.security.uploadsInfo'
)
}}
q-card-section.text-caption
{{
t
(
'admin.security.uploadsInfo'
)
}}
q-item
blueprint-icon(icon='upload-to-the-cloud')
q-item-section
q-item-label
{{
$
t
(
`admin.security.maxUploadSize`
)
}}
q-item-label(caption)
{{
$
t
(
`admin.security.maxUploadSizeHint`
)
}}
q-item-label
{{
t
(
`admin.security.maxUploadSize`
)
}}
q-item-label(caption)
{{
t
(
`admin.security.maxUploadSizeHint`
)
}}
q-item-section(style='flex: 0 0 200px;')
q-input(
outlined
v-model.number='humanUploadMaxFileSize'
v-model.number='
state.
humanUploadMaxFileSize'
dense
:aria-label='
$
t(`admin.security.maxUploadSize`)'
:aria-label='t(`admin.security.maxUploadSize`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='upload-to-ftp')
q-item-section
q-item-label
{{
$
t
(
`admin.security.maxUploadBatch`
)
}}
q-item-label(caption)
{{
$
t
(
`admin.security.maxUploadBatchHint`
)
}}
q-item-label
{{
t
(
`admin.security.maxUploadBatch`
)
}}
q-item-label(caption)
{{
t
(
`admin.security.maxUploadBatchHint`
)
}}
q-item-section(style='flex: 0 0 200px;')
q-input(
outlined
v-model.number='config.uploadMaxFiles'
v-model.number='
state.
config.uploadMaxFiles'
dense
:suffix='
$
t(`admin.security.maxUploadBatchSuffix`)'
:aria-label='
$
t(`admin.security.maxUploadBatch`)'
:suffix='t(`admin.security.maxUploadBatchSuffix`)'
:aria-label='t(`admin.security.maxUploadBatch`)'
)
q-separator.q-my-sm(inset)
q-item(tag='label', v-ripple)
blueprint-icon(icon='scan-stock')
q-item-section
q-item-label
{{
$
t
(
`admin.security.scanSVG`
)
}}
q-item-label(caption)
{{
$
t
(
`admin.security.scanSVGHint`
)
}}
q-item-label
{{
t
(
`admin.security.scanSVG`
)
}}
q-item-label(caption)
{{
t
(
`admin.security.scanSVGHint`
)
}}
q-item-section(avatar)
q-toggle(
v-model='config.uploadScanSVG'
v-model='
state.
config.uploadScanSVG'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='
$
t(`admin.security.scanSVG`)'
:aria-label='t(`admin.security.scanSVG`)'
)
//- -----------------------
...
...
@@ -228,52 +228,52 @@ q-page.admin-mail
//- -----------------------
q-card.shadow-1.q-pb-sm.q-mt-md
q-card-section
.text-subtitle1
{{
$
t
(
'admin.security.cors'
)
}}
.text-subtitle1
{{
t
(
'admin.security.cors'
)
}}
q-item
blueprint-icon(icon='firewall')
q-item-section
q-item-label
{{
$
t
(
`admin.security.corsMode`
)
}}
q-item-label(caption)
{{
$
t
(
`admin.security.corsModeHint`
)
}}
q-item-label
{{
t
(
`admin.security.corsMode`
)
}}
q-item-label(caption)
{{
t
(
`admin.security.corsModeHint`
)
}}
q-item-section
q-select(
outlined
v-model='config.corsMode'
v-model='
state.
config.corsMode'
:options='corsModes'
option-value='value'
option-label='text'
emit-value
map-options
dense
:aria-label='
$
t(`admin.security.corsMode`)'
:aria-label='t(`admin.security.corsMode`)'
)
template(v-if='config.corsMode === `HOSTNAMES`')
template(v-if='
state.
config.corsMode === `HOSTNAMES`')
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='todo-list', key='corsHostnames')
q-item-section
q-item-label
{{
$
t
(
`admin.security.corsHostnames`
)
}}
q-item-label(caption)
{{
$
t
(
`admin.security.corsHostnamesHint`
)
}}
q-item-label
{{
t
(
`admin.security.corsHostnames`
)
}}
q-item-label(caption)
{{
t
(
`admin.security.corsHostnamesHint`
)
}}
q-item-section
q-input(
outlined
v-model='config.corsConfig'
v-model='
state.
config.corsConfig'
dense
type='textarea'
:aria-label='
$
t(`admin.security.corsHostnames`)'
:aria-label='t(`admin.security.corsHostnames`)'
)
template(v-else-if='config.corsMode === `REGEX`')
template(v-else-if='
state.
config.corsMode === `REGEX`')
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='validation', key='corsRegex')
q-item-section
q-item-label
{{
$
t
(
`admin.security.corsRegex`
)
}}
q-item-label(caption)
{{
$
t
(
`admin.security.corsRegexHint`
)
}}
q-item-label
{{
t
(
`admin.security.corsRegex`
)
}}
q-item-label(caption)
{{
t
(
`admin.security.corsRegexHint`
)
}}
q-item-section
q-input(
outlined
v-model='config.corsConfig'
v-model='
state.
config.corsConfig'
dense
:aria-label='
$
t(`admin.security.corsRegex`)'
:aria-label='t(`admin.security.corsRegex`)'
)
//- -----------------------
...
...
@@ -281,65 +281,85 @@ q-page.admin-mail
//- -----------------------
q-card.shadow-1.q-pb-sm.q-mt-md
q-card-section
.text-subtitle1
{{
$
t
(
'admin.security.jwt'
)
}}
.text-subtitle1
{{
t
(
'admin.security.jwt'
)
}}
q-item
blueprint-icon(icon='ticket')
q-item-section
q-item-label
{{
$
t
(
`admin.security.jwtAudience`
)
}}
q-item-label(caption)
{{
$
t
(
`admin.security.jwtAudienceHint`
)
}}
q-item-label
{{
t
(
`admin.security.jwtAudience`
)
}}
q-item-label(caption)
{{
t
(
`admin.security.jwtAudienceHint`
)
}}
q-item-section(style='flex: 0 0 250px;')
q-input(
outlined
v-model='config.authJwtAudience'
v-model='
state.
config.authJwtAudience'
dense
:aria-label='
$
t(`admin.security.jwtAudience`)'
:aria-label='t(`admin.security.jwtAudience`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='expired')
q-item-section
q-item-label
{{
$
t
(
`admin.security.tokenExpiration`
)
}}
q-item-label(caption)
{{
$
t
(
`admin.security.tokenExpirationHint`
)
}}
q-item-label
{{
t
(
`admin.security.tokenExpiration`
)
}}
q-item-label(caption)
{{
t
(
`admin.security.tokenExpirationHint`
)
}}
q-item-section(style='flex: 0 0 140px;')
q-input(
outlined
v-model='config.authJwtExpiration'
v-model='
state.
config.authJwtExpiration'
dense
:aria-label='
$
t(`admin.security.tokenExpiration`)'
:aria-label='t(`admin.security.tokenExpiration`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='future')
q-item-section
q-item-label
{{
$
t
(
`admin.security.tokenRenewalPeriod`
)
}}
q-item-label(caption)
{{
$
t
(
`admin.security.tokenRenewalPeriodHint`
)
}}
q-item-label
{{
t
(
`admin.security.tokenRenewalPeriod`
)
}}
q-item-label(caption)
{{
t
(
`admin.security.tokenRenewalPeriodHint`
)
}}
q-item-section(style='flex: 0 0 140px;')
q-input(
outlined
v-model='config.authJwtRenewablePeriod'
v-model='
state.
config.authJwtRenewablePeriod'
dense
:aria-label='
$
t(`admin.security.tokenRenewalPeriod`)'
:aria-label='t(`admin.security.tokenRenewalPeriod`)'
)
</
template
>
<
script
>
<
script
setup
>
import
cloneDeep
from
'lodash/cloneDeep'
import
gql
from
'graphql-tag'
import
_get
from
'lodash/get'
import
filesize
from
'filesize'
import
filesizeParser
from
'filesize-parser'
import
{
createMetaMixin
}
from
'quasar'
export
default
{
mixins
:
[
createMetaMixin
(
function
()
{
return
{
title
:
this
.
$t
(
'admin.security.title'
)
}
})
],
data
()
{
return
{
import
{
useI18n
}
from
'vue-i18n'
import
{
useMeta
,
useQuasar
}
from
'quasar'
import
{
computed
,
onMounted
,
reactive
,
watch
}
from
'vue'
import
{
useAdminStore
}
from
'src/stores/admin'
import
{
useSiteStore
}
from
'src/stores/site'
import
{
useDataStore
}
from
'src/stores/data'
// QUASAR
const
$q
=
useQuasar
()
// STORES
const
adminStore
=
useAdminStore
()
const
siteStore
=
useSiteStore
()
const
dataStore
=
useDataStore
()
// I18N
const
{
t
}
=
useI18n
()
// META
useMeta
({
title
:
t
(
'admin.security.title'
)
})
// DATA
const
state
=
reactive
({
loading
:
false
,
config
:
{
corsConfig
:
''
,
...
...
@@ -361,35 +381,31 @@ export default {
uploadMaxFiles
:
0
,
uploadScanSVG
:
false
},
humanUploadMaxFileSize
:
'0'
,
hstsDurations
:
[
humanUploadMaxFileSize
:
'0'
})
const
hstsDurations
=
[
{
value
:
300
,
text
:
'5 minutes'
},
{
value
:
86400
,
text
:
'1 day'
},
{
value
:
604800
,
text
:
'1 week'
},
{
value
:
2592000
,
text
:
'1 month'
},
{
value
:
31536000
,
text
:
'1 year'
},
{
value
:
63072000
,
text
:
'2 years'
}
]
}
},
computed
:
{
corsModes
()
{
return
[
]
const
corsModes
=
[
{
value
:
'OFF'
,
text
:
'Off / Same-Origin'
},
{
value
:
'REFLECT'
,
text
:
'Reflect Request Origin'
},
{
value
:
'HOSTNAMES'
,
text
:
'Hostnames Whitelist'
},
{
value
:
'REGEX'
,
text
:
'Regex Pattern Match'
}
]
}
},
mounted
()
{
this
.
load
()
},
methods
:
{
async
load
()
{
this
.
loading
++
this
.
$q
.
loading
.
show
()
const
resp
=
await
this
.
$apollo
.
query
({
]
// METHODS
async
function
load
()
{
state
.
loading
++
$q
.
loading
.
show
()
const
resp
=
await
APOLLO_CLIENT
.
query
({
query
:
gql
`
query getSecurityConfig {
systemSecurity {
...
...
@@ -416,15 +432,16 @@ export default {
`
,
fetchPolicy
:
'network-only'
})
this
.
config
=
cloneDeep
(
resp
?.
data
?.
systemSecurity
)
this
.
humanUploadMaxFileSize
=
filesize
(
this
.
config
.
uploadMaxFileSize
??
0
,
{
base
:
2
,
standard
:
'jedec'
})
this
.
$q
.
loading
.
hide
()
this
.
loading
--
},
async
save
()
{
this
.
loading
=
true
state
.
config
=
cloneDeep
(
resp
?.
data
?.
systemSecurity
)
state
.
humanUploadMaxFileSize
=
filesize
(
state
.
config
.
uploadMaxFileSize
??
0
,
{
base
:
2
,
standard
:
'jedec'
})
$q
.
loading
.
hide
()
state
.
loading
--
}
async
function
save
()
{
state
.
loading
++
try
{
const
respRaw
=
await
this
.
$apollo
.
mutate
({
const
respRaw
=
await
APOLLO_CLIENT
.
mutate
({
mutation
:
gql
`
mutation saveSecurityConfig (
$authJwtAudience: String
...
...
@@ -471,30 +488,34 @@ export default {
}
`
,
variables
:
{
...
this
.
config
,
uploadMaxFileSize
:
filesizeParser
(
this
.
humanUploadMaxFileSize
||
'0'
)
...
state
.
config
,
uploadMaxFileSize
:
filesizeParser
(
state
.
humanUploadMaxFileSize
||
'0'
)
}
})
const
resp
=
_get
(
respRaw
,
'data.updateSystemSecurity.status'
,
{})
if
(
resp
.
succeeded
)
{
this
.
$q
.
notify
({
$q
.
notify
({
type
:
'positive'
,
message
:
this
.
$
t
(
'admin.security.saveSuccess'
)
message
:
t
(
'admin.security.saveSuccess'
)
})
}
else
{
throw
new
Error
(
resp
.
message
)
}
}
catch
(
err
)
{
this
.
$q
.
notify
({
$q
.
notify
({
type
:
'negative'
,
message
:
'Failed to save security config'
,
caption
:
err
.
message
})
}
this
.
loading
=
false
}
}
state
.
loading
--
}
// MOUNTED
onMounted
(()
=>
{
load
()
})
</
script
>
<
style
lang=
'scss'
>
...
...
ux/src/router/routes.js
View file @
d5fa587c
...
...
@@ -45,9 +45,9 @@ const routes = [
// { path: 'users/:id?/:section?', component: () => import('../pages/AdminUsers.vue') },
// -> System
// { path: 'api', component: () => import('../pages/AdminApi.vue') },
//
{ path: 'extensions', component: () => import('../pages/AdminExtensions.vue') },
{
path
:
'extensions'
,
component
:
()
=>
import
(
'../pages/AdminExtensions.vue'
)
},
{
path
:
'mail'
,
component
:
()
=>
import
(
'../pages/AdminMail.vue'
)
},
//
{ path: 'security', component: () => import('../pages/AdminSecurity.vue') },
{
path
:
'security'
,
component
:
()
=>
import
(
'../pages/AdminSecurity.vue'
)
},
{
path
:
'system'
,
component
:
()
=>
import
(
'../pages/AdminSystem.vue'
)
},
// { path: 'utilities', component: () => import('../pages/AdminUtilities.vue') },
// { path: 'webhooks', component: () => import('../pages/AdminWebhooks.vue') },
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment