admin-security.vue 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. <template lang='pug'>
  2. v-container(fluid, grid-list-lg)
  3. v-layout(row wrap)
  4. v-flex(xs12)
  5. .admin-header
  6. img.animated.fadeInUp(src='/svg/icon-private.svg', alt='Security', style='width: 80px;')
  7. .admin-header-title
  8. .headline.primary--text.animated.fadeInLeft {{ $t('admin:security.title') }}
  9. .subtitle-1.grey--text.animated.fadeInLeft {{ $t('admin:security.subtitle') }}
  10. v-spacer
  11. v-btn.animated.fadeInDown(color='success', depressed, @click='save', large)
  12. v-icon(left) mdi-check
  13. span {{$t('common:actions.apply')}}
  14. v-form.pt-3
  15. v-layout(row wrap)
  16. v-flex(lg6 xs12)
  17. v-card.animated.fadeInUp
  18. v-toolbar(color='red darken-2', dark, dense, flat)
  19. v-toolbar-title.subtitle-1 Security
  20. v-card-text
  21. v-alert(outlined, color='red darken-2', icon='mdi-information-outline').body-2 Make sure to understand the implications before turning on / off a security feature.
  22. v-switch.mt-3(
  23. inset
  24. label='Block IFrame Embedding'
  25. color='red darken-2'
  26. v-model='config.securityIframe'
  27. persistent-hint
  28. hint='Prevents other websites from embedding your wiki in an iframe. This provides clickjacking protection.'
  29. )
  30. v-divider.mt-3
  31. v-switch(
  32. inset
  33. label='Same Origin Referrer Policy'
  34. color='red darken-2'
  35. v-model='config.securityReferrerPolicy'
  36. persistent-hint
  37. hint='Limits the referrer header to same origin.'
  38. )
  39. v-divider.mt-3
  40. v-switch(
  41. inset
  42. label='Trust X-Forwarded-* Proxy Headers'
  43. color='red darken-2'
  44. v-model='config.securityTrustProxy'
  45. persistent-hint
  46. hint='Should be enabled when using a reverse-proxy like nginx, apache, CloudFlare, etc in front of Wiki.js. Turn off otherwise.'
  47. )
  48. //- v-divider.mt-3
  49. //- v-switch(
  50. //- inset
  51. //- label='Subresource Integrity (SRI)'
  52. //- color='red darken-2'
  53. //- v-model='config.securitySRI'
  54. //- persistent-hint
  55. //- hint='This ensure that resources such as CSS and JS files are not altered during delivery.'
  56. //- disabled
  57. //- )
  58. v-divider.mt-3
  59. v-switch(
  60. inset
  61. label='Enforce HSTS'
  62. color='red darken-2'
  63. v-model='config.securityHSTS'
  64. persistent-hint
  65. hint='This ensures the connection cannot be established through an insecure HTTP connection.'
  66. )
  67. v-select.mt-5(
  68. outlined
  69. label='HSTS Max Age'
  70. :items='hstsDurations'
  71. v-model='config.securityHSTSDuration'
  72. prepend-icon='mdi-subdirectory-arrow-right'
  73. :disabled='!config.securityHSTS'
  74. hide-details
  75. style='max-width: 450px;'
  76. )
  77. .pl-11.mt-3
  78. .caption Defines the duration for which the server should only deliver content through HTTPS.
  79. .caption It's a good idea to start with small values and make sure that nothing breaks on your wiki before moving to longer values.
  80. v-divider.mt-3
  81. v-switch(
  82. inset
  83. label='Enforce CSP'
  84. color='red darken-2'
  85. v-model='config.securityCSP'
  86. persistent-hint
  87. hint='Restricts scripts to pre-approved content sources.'
  88. disabled
  89. )
  90. v-textarea.mt-5(
  91. label='CSP Directives'
  92. outlined
  93. v-model='config.securityCSPDirectives'
  94. prepend-icon='mdi-subdirectory-arrow-right'
  95. persistent-hint
  96. hint='One directive per line.'
  97. disabled
  98. )
  99. v-flex(lg6 xs12)
  100. v-card.animated.fadeInUp.wait-p2s
  101. v-toolbar(color='primary', dark, dense, flat)
  102. v-toolbar-title.subtitle-1 {{ $t('admin:security.uploads') }}
  103. v-card-text
  104. v-text-field(
  105. outlined
  106. :label='$t(`admin:security.maxUploadSize`)'
  107. required
  108. v-model='config.uploadMaxFileSize'
  109. prepend-icon='mdi-progress-upload'
  110. :hint='$t(`admin:security.maxUploadSizeHint`)'
  111. persistent-hint
  112. :suffix='$t(`admin:security.maxUploadSizeSuffix`)'
  113. style='max-width: 450px;'
  114. )
  115. v-text-field.mt-3(
  116. outlined
  117. :label='$t(`admin:security.maxUploadBatch`)'
  118. required
  119. v-model='config.uploadMaxFiles'
  120. prepend-icon='mdi-upload-lock'
  121. :hint='$t(`admin:security.maxUploadBatchHint`)'
  122. persistent-hint
  123. :suffix='$t(`admin:security.maxUploadBatchSuffix`)'
  124. style='max-width: 450px;'
  125. )
  126. </template>
  127. <script>
  128. import _ from 'lodash'
  129. import { sync } from 'vuex-pathify'
  130. import gql from 'graphql-tag'
  131. export default {
  132. data() {
  133. return {
  134. config: {
  135. uploadMaxFileSize: 0,
  136. uploadMaxFiles: 0,
  137. securityIframe: true,
  138. securityReferrerPolicy: true,
  139. securityTrustProxy: true,
  140. securitySRI: true,
  141. securityHSTS: false,
  142. securityHSTSDuration: 0,
  143. securityCSP: false,
  144. securityCSPDirectives: ''
  145. },
  146. hstsDurations: [
  147. { value: 300, text: '5 minutes' },
  148. { value: 86400, text: '1 day' },
  149. { value: 604800, text: '1 week' },
  150. { value: 2592000, text: '1 month' },
  151. { value: 31536000, text: '1 year' },
  152. { value: 63072000, text: '2 years' }
  153. ]
  154. }
  155. },
  156. computed: {
  157. activeModal: sync('editor/activeModal')
  158. },
  159. methods: {
  160. async save () {
  161. try {
  162. await this.$apollo.mutate({
  163. mutation: gql`
  164. mutation (
  165. $uploadMaxFileSize: Int
  166. $uploadMaxFiles: Int
  167. $securityIframe: Boolean
  168. $securityReferrerPolicy: Boolean
  169. $securityTrustProxy: Boolean
  170. $securitySRI: Boolean
  171. $securityHSTS: Boolean
  172. $securityHSTSDuration: Int
  173. $securityCSP: Boolean
  174. $securityCSPDirectives: String
  175. ) {
  176. site {
  177. updateConfig(
  178. uploadMaxFileSize: $uploadMaxFileSize,
  179. uploadMaxFiles: $uploadMaxFiles,
  180. securityIframe: $securityIframe,
  181. securityReferrerPolicy: $securityReferrerPolicy,
  182. securityTrustProxy: $securityTrustProxy,
  183. securitySRI: $securitySRI,
  184. securityHSTS: $securityHSTS,
  185. securityHSTSDuration: $securityHSTSDuration,
  186. securityCSP: $securityCSP,
  187. securityCSPDirectives: $securityCSPDirectives
  188. ) {
  189. responseResult {
  190. succeeded
  191. errorCode
  192. slug
  193. message
  194. }
  195. }
  196. }
  197. }
  198. `,
  199. variables: {
  200. uploadMaxFileSize: _.toSafeInteger(_.get(this.config, 'uploadMaxFileSize', 0)),
  201. uploadMaxFiles: _.toSafeInteger(_.get(this.config, 'uploadMaxFiles', 0)),
  202. securityIframe: _.get(this.config, 'securityIframe', false),
  203. securityReferrerPolicy: _.get(this.config, 'securityReferrerPolicy', false),
  204. securityTrustProxy: _.get(this.config, 'securityTrustProxy', false),
  205. securitySRI: _.get(this.config, 'securitySRI', false),
  206. securityHSTS: _.get(this.config, 'securityHSTS', false),
  207. securityHSTSDuration: _.get(this.config, 'securityHSTSDuration', 0),
  208. securityCSP: _.get(this.config, 'securityCSP', false),
  209. securityCSPDirectives: _.get(this.config, 'securityCSPDirectives', '')
  210. },
  211. watchLoading (isLoading) {
  212. this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-site-update')
  213. }
  214. })
  215. this.$store.commit('showNotification', {
  216. style: 'success',
  217. message: 'Configuration saved successfully.',
  218. icon: 'check'
  219. })
  220. } catch (err) {
  221. this.$store.commit('pushGraphError', err)
  222. }
  223. }
  224. },
  225. apollo: {
  226. config: {
  227. query: gql`
  228. {
  229. site {
  230. config {
  231. uploadMaxFileSize
  232. uploadMaxFiles
  233. securityIframe
  234. securityReferrerPolicy
  235. securityTrustProxy
  236. securitySRI
  237. securityHSTS
  238. securityHSTSDuration
  239. securityCSP
  240. securityCSPDirectives
  241. }
  242. }
  243. }
  244. `,
  245. fetchPolicy: 'network-only',
  246. update: (data) => _.cloneDeep(data.site.config),
  247. watchLoading (isLoading) {
  248. this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-security-refresh')
  249. }
  250. }
  251. }
  252. }
  253. </script>
  254. <style lang='scss'>
  255. </style>