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
75eb2774
You need to sign in or sign up before continuing.
Commit
75eb2774
authored
Jan 06, 2019
by
Nicolas Giard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: guest + user permissions
parent
aa57ea92
Hide whitespace changes
Inline
Side-by-side
Showing
33 changed files
with
463 additions
and
191 deletions
+463
-191
admin-api.vue
client/components/admin/admin-api.vue
+5
-5
admin-auth.vue
client/components/admin/admin-auth.vue
+5
-0
admin-dev.vue
client/components/admin/admin-dev.vue
+36
-5
admin-general.vue
client/components/admin/admin-general.vue
+7
-1
admin-groups-edit-permissions.vue
client/components/admin/admin-groups-edit-permissions.vue
+4
-4
admin-locale.vue
client/components/admin/admin-locale.vue
+2
-0
admin-logging.vue
client/components/admin/admin-logging.vue
+3
-2
admin-search.vue
client/components/admin/admin-search.vue
+1
-1
admin-storage.vue
client/components/admin/admin-storage.vue
+1
-1
editor.vue
client/components/editor.vue
+7
-3
editor-markdown.vue
client/components/editor/editor-markdown.vue
+1
-1
auth-mutation-save-strategies.gql
client/graph/admin/auth/auth-mutation-save-strategies.gql
+2
-2
app.scss
client/scss/app.scss
+1
-0
_unauthorized.scss
client/scss/pages/_unauthorized.scss
+81
-0
icon-delete-shield.svg
client/static/svg/icon-delete-shield.svg
+14
-0
icon-safety-float.svg
client/static/svg/icon-safety-float.svg
+33
-0
motif-diagonals.svg
client/static/svg/motif-diagonals.svg
+3
-0
page.vue
client/themes/default/components/page.vue
+2
-4
Dockerfile
dev/examples/Dockerfile
+0
-12
docker-compose.yml
dev/examples/docker-compose.yml
+50
-16
data.yml
server/app/data.yml
+0
-9
common.js
server/controllers/common.js
+41
-0
auth.js
server/core/auth.js
+84
-4
config.js
server/core/config.js
+0
-2
2.0.0-beta.1.js
server/db/migrations/2.0.0-beta.1.js
+25
-22
settings.js
server/db/seeds/settings.js
+0
-11
authentication.js
server/graph/resolvers/authentication.js
+7
-0
authentication.graphql
server/graph/schemas/authentication.graphql
+8
-1
master.js
server/master.js
+2
-3
auth.js
server/middlewares/auth.js
+0
-72
users.js
server/models/users.js
+13
-2
setup.js
server/setup.js
+12
-8
unauthorized.pug
server/views/unauthorized.pug
+13
-0
No files found.
client/components/admin/admin-api.vue
View file @
75eb2774
...
@@ -6,14 +6,14 @@
...
@@ -6,14 +6,14 @@
img(src='/svg/icon-rest-api.svg', alt='API', style='width: 80px;')
img(src='/svg/icon-rest-api.svg', alt='API', style='width: 80px;')
.admin-header-title
.admin-header-title
.headline.blue--text.text--darken-2 API
.headline.blue--text.text--darken-2 API
.subheading.grey--text Manage keys to access the API
.subheading.grey--text Manage keys to access the API
#[v-chip(label, color='primary', small).white--text coming soon]
v-spacer
v-spacer
v-btn(outline, color='grey', large, @click='refresh')
v-btn(outline, color='grey', large, @click='refresh'
, disabled
)
v-icon refresh
v-icon refresh
v-btn(color='green', d
ark
, depressed, large, @click='globalSwitch')
v-btn(color='green', d
isabled
, depressed, large, @click='globalSwitch')
v-icon(left) power_settings_new
v-icon(left) power_settings_new
| Enable API
| Enable API
v-btn(color='primary', depressed, large, @click='newKey')
v-btn(color='primary', depressed, large, @click='newKey'
, disabled
)
v-icon(left) add
v-icon(left) add
| New API Key
| New API Key
v-card.mt-3
v-card.mt-3
...
@@ -58,7 +58,7 @@
...
@@ -58,7 +58,7 @@
td
{{
props
.
item
.
updatedOn
}}
td
{{
props
.
item
.
updatedOn
}}
td: v-btn(icon): v-icon.grey--text.text--darken-1 more_horiz
td: v-btn(icon): v-icon.grey--text.text--darken-1 more_horiz
template(slot='no-data')
template(slot='no-data')
v-alert.mt-3(icon='
warning', :value='true', outline
) No API have been generated yet.
v-alert.mt-3(icon='
info', :value='true', outline, color='info'
) No API have been generated yet.
.text-xs-center.py-2
.text-xs-center.py-2
v-pagination(v-model='pagination.page', :length='pages')
v-pagination(v-model='pagination.page', :length='pages')
</
template
>
</
template
>
...
...
client/components/admin/admin-auth.vue
View file @
75eb2774
...
@@ -207,6 +207,11 @@ export default {
...
@@ -207,6 +207,11 @@ export default {
await
this
.
$apollo
.
mutate
({
await
this
.
$apollo
.
mutate
({
mutation
:
strategiesSaveMutation
,
mutation
:
strategiesSaveMutation
,
variables
:
{
variables
:
{
config
:
{
audience
:
this
.
jwtAudience
,
tokenExpiration
:
this
.
jwtExpiration
,
tokenRenewal
:
this
.
jwtRenewablePeriod
},
strategies
:
this
.
strategies
.
map
(
str
=>
_
.
pick
(
str
,
[
strategies
:
this
.
strategies
.
map
(
str
=>
_
.
pick
(
str
,
[
'isEnabled'
,
'isEnabled'
,
'key'
,
'key'
,
...
...
client/components/admin/admin-dev.vue
View file @
75eb2774
...
@@ -7,8 +7,18 @@
...
@@ -7,8 +7,18 @@
.admin-header-title
.admin-header-title
.headline.primary--text Developer Tools
.headline.primary--text Developer Tools
.subheading.grey--text ¯\_(ツ)_/¯
.subheading.grey--text ¯\_(ツ)_/¯
v-spacer
v-card.radius-7
v-card-text
.caption Enables extra dev options and removes many safeguards.
.caption.red--text Do not enable unless you know what you're doing!
v-switch.mt-1(
color='primary'
hide-details
label='Dev Mode'
)
v-card.mt-3
v-card.mt-3
.white.grey--text.text--darken-3
v-tabs(
v-tabs(
v-model='selectedTab'
v-model='selectedTab'
color='grey darken-2'
color='grey darken-2'
...
@@ -92,9 +102,8 @@ export default {
...
@@ -92,9 +102,8 @@ export default {
},
500
)
},
500
)
return
resp
return
resp
},
},
query
:
''
,
response
:
null
,
response
:
null
,
variables
:
null
,
variables
:
'{}'
,
operationName
:
null
,
operationName
:
null
,
websocketConnectionParams
:
null
websocketConnectionParams
:
null
}),
}),
...
@@ -103,6 +112,7 @@ export default {
...
@@ -103,6 +112,7 @@ export default {
graphiQLInstance
.
queryEditorComponent
.
editor
.
refresh
()
graphiQLInstance
.
queryEditorComponent
.
editor
.
refresh
()
graphiQLInstance
.
variableEditorComponent
.
editor
.
refresh
()
graphiQLInstance
.
variableEditorComponent
.
editor
.
refresh
()
graphiQLInstance
.
state
.
variableEditorOpen
=
true
graphiQLInstance
.
state
.
variableEditorOpen
=
true
graphiQLInstance
.
state
.
docExplorerOpen
=
true
},
},
renderVoyager
()
{
renderVoyager
()
{
ReactDOM
.
render
(
ReactDOM
.
render
(
...
@@ -120,7 +130,7 @@ export default {
...
@@ -120,7 +130,7 @@ export default {
<
style
lang=
'scss'
>
<
style
lang=
'scss'
>
#graphiql
{
#graphiql
{
height
:
calc
(
100vh
-
2
3
0px
);
height
:
calc
(
100vh
-
2
7
0px
);
.topBar
{
.topBar
{
background-color
:
mc
(
'grey'
,
'200'
);
background-color
:
mc
(
'grey'
,
'200'
);
...
@@ -136,10 +146,14 @@ export default {
...
@@ -136,10 +146,14 @@ export default {
background-color
:
initial
;
background-color
:
initial
;
box-shadow
:
initial
;
box-shadow
:
initial
;
}
}
.doc-explorer-title-bar
,
.history-title-bar
{
height
:
auto
;
}
}
}
#voyager
{
#voyager
{
height
:
calc
(
100vh
-
2
5
0px
);
height
:
calc
(
100vh
-
2
7
0px
);
.title-area
{
.title-area
{
display
:
none
;
display
:
none
;
...
@@ -147,5 +161,22 @@ export default {
...
@@ -147,5 +161,22 @@ export default {
.type-doc
{
.type-doc
{
margin-top
:
5px
;
margin-top
:
5px
;
}
}
.doc-navigation
{
>
span
{
overflow-y
:
hidden
;
display
:
block
;
}
min-height
:
40px
;
}
.contents
{
padding-bottom
:
0
;
color
:
#666
;
}
.type-info-popover
{
display
:
none
;
}
}
}
</
style
>
</
style
>
client/components/admin/admin-general.vue
View file @
75eb2774
...
@@ -38,6 +38,8 @@
...
@@ -38,6 +38,8 @@
:counter='50'
:counter='50'
v-model='config.title'
v-model='config.title'
prepend-icon='public'
prepend-icon='public'
hint='Displayed in the top bar and appended to all pages meta title.'
persistent-hint
)
)
v-divider
v-divider
v-subheader SEO
v-subheader SEO
...
@@ -48,6 +50,8 @@
...
@@ -48,6 +50,8 @@
:counter='255'
:counter='255'
v-model='config.description'
v-model='config.description'
prepend-icon='explore'
prepend-icon='explore'
hint='Default description when none is provided for a page.'
persistent-hint
)
)
v-select.mt-2(
v-select.mt-2(
outline
outline
...
@@ -57,7 +61,7 @@
...
@@ -57,7 +61,7 @@
v-model='config.robots'
v-model='config.robots'
prepend-icon='explore'
prepend-icon='explore'
:return-object='false'
:return-object='false'
hint='Default: Index, Follow'
hint='Default: Index, Follow
. Can also be set on a per-page basis.
'
persistent-hint
persistent-hint
)
)
v-divider
v-divider
...
@@ -69,6 +73,8 @@
...
@@ -69,6 +73,8 @@
:items='analyticsServices'
:items='analyticsServices'
v-model='config.analyticsService'
v-model='config.analyticsService'
prepend-icon='timeline'
prepend-icon='timeline'
persistent-hint
hint='Automatically add tracking code for services like Google Analytics.'
)
)
v-text-field.mt-2(
v-text-field.mt-2(
v-if='config.analyticsService !== ``'
v-if='config.analyticsService !== ``'
...
...
client/components/admin/admin-groups-edit-permissions.vue
View file @
75eb2774
...
@@ -60,14 +60,14 @@ export default {
...
@@ -60,14 +60,14 @@ export default {
},
},
{
{
permission
:
'write:pages'
,
permission
:
'write:pages'
,
hint
:
'Can
view and
create new pages, as specified in the Page Rules'
,
hint
:
'Can create new pages, as specified in the Page Rules'
,
warning
:
false
,
warning
:
false
,
restrictedForSystem
:
false
,
restrictedForSystem
:
false
,
disabled
:
false
disabled
:
false
},
},
{
{
permission
:
'manage:pages'
,
permission
:
'manage:pages'
,
hint
:
'Can
view, create,
edit and move existing pages as specified in the Page Rules'
,
hint
:
'Can edit and move existing pages as specified in the Page Rules'
,
warning
:
false
,
warning
:
false
,
restrictedForSystem
:
false
,
restrictedForSystem
:
false
,
disabled
:
false
disabled
:
false
...
@@ -95,7 +95,7 @@ export default {
...
@@ -95,7 +95,7 @@ export default {
},
},
{
{
permission
:
'manage:assets'
,
permission
:
'manage:assets'
,
hint
:
'Can edit and delete assets (such as images and files), as specified in the Page Rules'
,
hint
:
'Can edit and delete
existing
assets (such as images and files), as specified in the Page Rules'
,
warning
:
false
,
warning
:
false
,
restrictedForSystem
:
false
,
restrictedForSystem
:
false
,
disabled
:
false
disabled
:
false
...
@@ -116,7 +116,7 @@ export default {
...
@@ -116,7 +116,7 @@ export default {
},
},
{
{
permission
:
'manage:comments'
,
permission
:
'manage:comments'
,
hint
:
'Can edit and delete comments, as specified in the Page Rules'
,
hint
:
'Can edit and delete
existing
comments, as specified in the Page Rules'
,
warning
:
false
,
warning
:
false
,
restrictedForSystem
:
false
,
restrictedForSystem
:
false
,
disabled
:
false
disabled
:
false
...
...
client/components/admin/admin-locale.vue
View file @
75eb2774
...
@@ -52,6 +52,8 @@
...
@@ -52,6 +52,8 @@
v-toolbar(color='primary', dark, dense, flat)
v-toolbar(color='primary', dark, dense, flat)
v-toolbar-title
v-toolbar-title
.subheading
{{
$t
(
'admin:locale.namespacing'
)
}}
.subheading
{{
$t
(
'admin:locale.namespacing'
)
}}
v-spacer
v-chip(label, color='white', small).primary--text coming soon
v-card-text
v-card-text
v-switch(
v-switch(
v-model='namespacing'
v-model='namespacing'
...
...
client/components/admin/admin-logging.vue
View file @
75eb2774
...
@@ -6,11 +6,11 @@
...
@@ -6,11 +6,11 @@
img(src='/svg/icon-registry-editor.svg', alt='Logging', style='width: 80px;')
img(src='/svg/icon-registry-editor.svg', alt='Logging', style='width: 80px;')
.admin-header-title
.admin-header-title
.headline.primary--text Logging
.headline.primary--text Logging
.subheading.grey--text Configure the system logger(s)
.subheading.grey--text Configure the system logger(s)
#[v-chip(label, color='primary', small).white--text coming soon]
v-spacer
v-spacer
v-btn(outline, color='grey', @click='refresh', large)
v-btn(outline, color='grey', @click='refresh', large)
v-icon refresh
v-icon refresh
v-btn(color='black', d
ark
, depressed, @click='toggleConsole', large)
v-btn(color='black', d
isabled
, depressed, @click='toggleConsole', large)
ConsoleLineIcon.mr-3
ConsoleLineIcon.mr-3
span Live Trail
span Live Trail
v-btn(color='success', @click='save', depressed, large)
v-btn(color='success', @click='save', depressed, large)
...
@@ -34,6 +34,7 @@
...
@@ -34,6 +34,7 @@
:label='logger.title'
:label='logger.title'
color='primary'
color='primary'
hide-details
hide-details
disabled
)
)
v-tab-item(v-for='(logger, n) in activeLoggers', :key='logger.key', :transition='false', :reverse-transition='false')
v-tab-item(v-for='(logger, n) in activeLoggers', :key='logger.key', :transition='false', :reverse-transition='false')
...
...
client/components/admin/admin-search.vue
View file @
75eb2774
...
@@ -6,7 +6,7 @@
...
@@ -6,7 +6,7 @@
img(src='/svg/icon-search.svg', alt='Search Engine', style='width: 80px;')
img(src='/svg/icon-search.svg', alt='Search Engine', style='width: 80px;')
.admin-header-title
.admin-header-title
.headline.primary--text Search Engine
.headline.primary--text Search Engine
.subheading.grey--text Configure the search capabilities of your wiki
.subheading.grey--text Configure the search capabilities of your wiki
#[v-chip(label, color='primary', small).white--text coming soon]
v-spacer
v-spacer
v-btn(outline, color='grey', @click='refresh', large)
v-btn(outline, color='grey', @click='refresh', large)
v-icon refresh
v-icon refresh
...
...
client/components/admin/admin-storage.vue
View file @
75eb2774
...
@@ -6,7 +6,7 @@
...
@@ -6,7 +6,7 @@
img(src='/svg/icon-cloud-storage.svg', alt='Storage', style='width: 80px;')
img(src='/svg/icon-cloud-storage.svg', alt='Storage', style='width: 80px;')
.admin-header-title
.admin-header-title
.headline.primary--text Storage
.headline.primary--text Storage
.subheading.grey--text Set backup and sync targets for your content
.subheading.grey--text Set backup and sync targets for your content
#[v-chip(label, color='primary', small).white--text coming soon]
v-spacer
v-spacer
v-btn(outline, color='grey', @click='refresh', large)
v-btn(outline, color='grey', @click='refresh', large)
v-icon refresh
v-icon refresh
...
...
client/components/editor.vue
View file @
75eb2774
...
@@ -14,12 +14,12 @@
...
@@ -14,12 +14,12 @@
outline
outline
color='blue'
color='blue'
@click.native.stop='openPropsModal'
@click.native.stop='openPropsModal'
:class='{ "is-icon": $vuetify.breakpoint.mdAndDown, "mx-0":
mode === `create`, "ml-0": mode !== `create`
}'
:class='{ "is-icon": $vuetify.breakpoint.mdAndDown, "mx-0":
!welcomeMode, "ml-0": !welcomeMode
}'
)
)
v-icon(color='blue', :left='$vuetify.breakpoint.lgAndUp') sort_by_alpha
v-icon(color='blue', :left='$vuetify.breakpoint.lgAndUp') sort_by_alpha
span.white--text(v-if='$vuetify.breakpoint.lgAndUp')
{{
$t
(
'editor:page'
)
}}
span.white--text(v-if='$vuetify.breakpoint.lgAndUp')
{{
$t
(
'editor:page'
)
}}
v-btn(
v-btn(
v-if='
path !== `home`
'
v-if='
!welcomeMode
'
outline
outline
color='red'
color='red'
:class='{ "is-icon": $vuetify.breakpoint.mdAndDown }'
:class='{ "is-icon": $vuetify.breakpoint.mdAndDown }'
...
@@ -62,6 +62,7 @@ import editorStore from '@/store/editor'
...
@@ -62,6 +62,7 @@ import editorStore from '@/store/editor'
WIKI
.
$store
.
registerModule
(
'editor'
,
editorStore
)
WIKI
.
$store
.
registerModule
(
'editor'
,
editorStore
)
export
default
{
export
default
{
i18nOptions
:
{
namespaces
:
'editor'
},
components
:
{
components
:
{
AtomSpinner
,
AtomSpinner
,
editorCode
:
()
=>
import
(
/* webpackChunkName: "editor-code", webpackMode: "lazy" */
'./editor/editor-code.vue'
),
editorCode
:
()
=>
import
(
/* webpackChunkName: "editor-code", webpackMode: "lazy" */
'./editor/editor-code.vue'
),
...
@@ -127,7 +128,8 @@ export default {
...
@@ -127,7 +128,8 @@ export default {
darkMode
:
get
(
'site/dark'
),
darkMode
:
get
(
'site/dark'
),
mode
:
get
(
'editor/mode'
),
mode
:
get
(
'editor/mode'
),
notification
:
get
(
'notification'
),
notification
:
get
(
'notification'
),
notificationState
:
sync
(
'notification@isActive'
)
notificationState
:
sync
(
'notification@isActive'
),
welcomeMode
()
{
return
this
.
mode
===
`create`
&&
this
.
path
===
`home`
}
},
},
watch
:
{
watch
:
{
currentEditor
(
newValue
,
oldValue
)
{
currentEditor
(
newValue
,
oldValue
)
{
...
@@ -242,6 +244,8 @@ export default {
...
@@ -242,6 +244,8 @@ export default {
throw
new
Error
(
_
.
get
(
resp
,
'responseResult.message'
))
throw
new
Error
(
_
.
get
(
resp
,
'responseResult.message'
))
}
}
}
}
this
.
initContentParsed
=
this
.
$store
.
get
(
'editor/content'
)
}
catch
(
err
)
{
}
catch
(
err
)
{
this
.
$store
.
commit
(
'showNotification'
,
{
this
.
$store
.
commit
(
'showNotification'
,
{
message
:
err
.
message
,
message
:
err
.
message
,
...
...
client/components/editor/editor-markdown.vue
View file @
75eb2774
...
@@ -234,7 +234,7 @@ export default {
...
@@ -234,7 +234,7 @@ export default {
if
(
!
token
.
type
)
{
return
}
if
(
!
token
.
type
)
{
return
}
console
.
info
(
token
)
//
console.info(token)
},
},
/**
/**
* Update scroll sync
* Update scroll sync
...
...
client/graph/admin/auth/auth-mutation-save-strategies.gql
View file @
75eb2774
mutation
(
$strategies
:
[
AuthenticationStrategyInput
])
{
mutation
(
$strategies
:
[
AuthenticationStrategyInput
]
!,
$config
:
AuthenticationConfigInput
)
{
authentication
{
authentication
{
updateStrategies
(
strategies
:
$strategies
)
{
updateStrategies
(
strategies
:
$strategies
,
config
:
$config
)
{
responseResult
{
responseResult
{
succeeded
succeeded
errorCode
errorCode
...
...
client/scss/app.scss
View file @
75eb2774
...
@@ -23,6 +23,7 @@
...
@@ -23,6 +23,7 @@
// @import 'node_modules/diff2html/dist/diff2html.min';
// @import 'node_modules/diff2html/dist/diff2html.min';
@import
'pages/new'
;
@import
'pages/new'
;
@import
'pages/unauthorized'
;
@import
'pages/welcome'
;
@import
'pages/welcome'
;
@import
'pages/error'
;
@import
'pages/error'
;
...
...
client/scss/pages/_unauthorized.scss
0 → 100644
View file @
75eb2774
.unauthorized
{
background
:
linear-gradient
(
to
bottom
,
darken
(
mc
(
'blue'
,
'900'
)
,
10%
)
0%
,
mc
(
'red'
,
'500'
)
100%
);
height
:
100%
;
display
:
flex
;
flex-direction
:
column
;
justify-content
:
center
;
align-items
:
center
;
color
:
mc
(
'grey'
,
'50'
);
&
:
:
before
{
content
:
''
;
display
:block
;
width
:
100%
;
height
:
100%
;
position
:
absolute
;
top
:
0
;
left
:
0
;
background-image
:
url('../static/svg/motif-diagonals.svg')
;
background-position
:
center
center
;
background-repeat
:
repeat
;
background-size
:
50px
;
z-index
:
0
;
opacity
:
.75
;
animation
:
onboardingBgReveal
50s
linear
infinite
;
@include
keyframes
(
onboardingBgReveal
)
{
0
%
{
background-position-y
:
0
;
}
100
%
{
background-position-y
:
-2000px
;
}
}
}
&
:
:
after
{
content
:
''
;
position
:
absolute
;
background-color
:
transparent
;
background-image
:
url('../static/svg/motif-overlay.svg')
;
background-attachment
:
fixed
;
background-size
:
cover
;
opacity
:
.5
;
top
:
0
;
left
:
0
;
width
:
100vw
;
height
:
100vh
;
}
&
-content
{
display
:
flex
;
flex-direction
:
column
;
justify-content
:
center
;
align-items
:
center
;
z-index
:
2
;
}
img
{
height
:
250px
;
margin-bottom
:
3rem
;
z-index
:
2
;
animation-duration
:
2s
;
@include
until
(
$tablet
)
{
height
:
200px
;
}
}
h1
{
font-size
:
1
.5rem
;
margin-bottom
:
1rem
;
z-index
:
2
;
}
h2
{
margin-bottom
:
3rem
;
z-index
:
2
;
}
.v-btn
{
z-index
:
2
;
}
}
client/static/svg/icon-delete-shield.svg
0 → 100644
View file @
75eb2774
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg
width=
"100%"
height=
"100%"
viewBox=
"0 0 128 128"
version=
"1.1"
xmlns=
"http://www.w3.org/2000/svg"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
xml:space=
"preserve"
xmlns:serif=
"http://www.serif.com/"
style=
"fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;"
>
<g>
<g>
<path
d=
"M64,116c-0.5,0 -1,-0.1 -1.5,-0.4c-26,-15.4 -41.5,-42.6 -41.5,-72.7l0,-15.1c0,-1.3 0.8,-2.4 2,-2.8l40,-14.8c0.7,-0.2 1.4,-0.2 2.1,0l39.9,14.8c1.2,0.4 2,1.6 2,2.8l0,15.1c0,7.8 -1.1,15.6 -3.2,23.1c-0.4,1.6 -2.1,2.5 -3.7,2.1c-1.6,-0.4 -2.5,-2.1 -2.1,-3.7c2,-6.9 2.9,-14.1 2.9,-21.4l0,-13l-36.9,-13.8l-37,13.7l0,13c0,28 14.4,53.2 38.5,67.5c1.4,0.8 1.9,2.7 1.1,4.1c-0.6,1 -1.6,1.5 -2.6,1.5Z"
style=
"fill:#fff;fill-rule:nonzero;"
/>
<path
d=
"M64,116c-1,0 -2,-0.5 -2.6,-1.5c-0.8,-1.4 -0.4,-3.3 1.1,-4.1c3.2,-1.9 6.3,-4 9.2,-6.3c1.3,-1 3.2,-0.8 4.2,0.5c1,1.3 0.8,3.2 -0.5,4.2c-3.1,2.5 -6.4,4.8 -9.9,6.8c-0.5,0.3 -1,0.4 -1.5,0.4Z"
style=
"fill:#fff;fill-rule:nonzero;"
/>
<path
d=
"M64,101.6c-0.6,0 -1.3,-0.2 -1.8,-0.6c-15.9,-11.7 -26,-29 -28.6,-48.5c-0.2,-1.6 0.9,-3.1 2.6,-3.4c1.6,-0.2 3.1,0.9 3.4,2.6c2.3,17.1 10.9,32.3 24.4,43c15.9,-12.6 25,-31.4 25,-51.9l0,-4.6l-25,-9.2l-27,10c-1.6,0.6 -3.3,-0.2 -3.9,-1.8c-0.6,-1.6 0.2,-3.3 1.8,-3.9l28.1,-10.3c0.7,-0.2 1.4,-0.2 2.1,0l28,10.4c1.2,0.4 2,1.6 2,2.8l0,6.7c0,23.2 -10.6,44.4 -29.2,58.1c-0.6,0.4 -1.3,0.6 -1.9,0.6Z"
style=
"fill:#d0d4d8;fill-rule:nonzero;"
/>
</g>
<path
d=
"M64,25.8l0,72.8c17.7,-13.1 28,-33.4 28,-55.7l0,-6.7l-28,-10.4Z"
style=
"fill:#d0d4d8;fill-rule:nonzero;"
/>
<path
d=
"M89.857,82.858c7.805,-7.805 20.478,-7.805 28.284,0c7.805,7.805 7.805,20.479 0,28.284c-7.806,7.805 -20.479,7.805 -28.284,0c-7.806,-7.805 -7.806,-20.479 0,-28.284Z"
style=
"fill:#ff5576;"
/>
<path
d=
"M110.9,100l-14,0c-1.7,0 -3,-1.3 -3,-3c0,-1.7 1.3,-3 3,-3l14,0c1.7,0 3,1.3 3,3c0,1.7 -1.3,3 -3,3Z"
style=
"fill:#fff;fill-rule:nonzero;"
/>
</g>
</svg>
client/static/svg/icon-safety-float.svg
0 → 100644
View file @
75eb2774
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
xmlns=
"http://www.w3.org/2000/svg"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
version=
"1.1"
id=
"Layer_1"
x=
"0px"
y=
"0px"
viewBox=
"0 0 128 128"
style=
"enable-background:new 0 0 128 128;"
xml:space=
"preserve"
width=
"128px"
height=
"128px"
>
<path
style=
"fill:#FFFFFF;"
d=
"M64,14c-27.6,0-50,22.4-50,50s22.4,50,50,50s50-22.4,50-50S91.6,14,64,14z M64,89 c-13.8,0-25-11.2-25-25s11.2-25,25-25s25,11.2,25,25S77.8,89,64,89z"
/>
<g>
<path
style=
"fill:#FF5576;"
d=
"M14,64c0,6.5,1.2,12.7,3.5,18.4l22.7-10.6C39.4,69.3,39,66.7,39,64c0-9,4.7-16.8,11.8-21.2L40.2,20 C24.6,28.5,14,45,14,64z"
/>
</g>
<g>
<path
style=
"fill:#FF5576;"
d=
"M64,14c-6.5,0-12.7,1.2-18.4,3.5l10.6,22.7c2.4-0.8,5.1-1.2,7.8-1.2c9,0,16.8,4.7,21.2,11.8 L108,40.2C99.5,24.6,83,14,64,14z"
/>
</g>
<path
style=
"fill:#C3DBEA;"
d=
"M55,37.5L52.4,32c-1.9,0.7-3.7,1.6-5.4,2.6l2.5,5.5C51.2,39,53,38.2,55,37.5z"
/>
<g>
<path
style=
"fill:#FF5576;"
d=
"M64,89c-9,0-16.8-4.7-21.2-11.8L20,87.8c8.5,15.6,25,26.2,44,26.2c6.5,0,12.7-1.2,18.4-3.5 L71.8,87.8C69.3,88.6,66.7,89,64,89z"
/>
</g>
<g>
<path
style=
"fill:#FF5576;"
d=
"M114,64c0-6.5-1.2-12.7-3.5-18.4L87.8,56.2c0.8,2.4,1.2,5.1,1.2,7.8c0,9-4.7,16.8-11.8,21.2 L87.8,108C103.4,99.5,114,83,114,64z"
/>
</g>
<path
style=
"fill:#C3DBEA;"
d=
"M81.1,107.8c1.9-0.7,3.7-1.6,5.4-2.5L84,99.8c-1.7,1-3.6,1.8-5.4,2.5L81.1,107.8z"
/>
<path
style=
"fill:#FFFFFF;"
d=
"M21.5,55.7c-0.3,0-0.5,0-0.8-0.1c-1.6-0.4-2.6-2.1-2.1-3.7c2.5-9.5,7.9-17.9,15.6-24.2 c1.3-1.1,3.2-0.9,4.2,0.4c1.1,1.3,0.9,3.2-0.4,4.2c-6.7,5.5-11.4,12.8-13.6,21.1C24,54.8,22.8,55.7,21.5,55.7z"
/>
<path
style=
"fill:#FFFFFF;"
d=
"M20,67c-0.8,0-1.6-0.3-2.1-0.9c-0.1-0.1-0.3-0.3-0.4-0.4c-0.1-0.2-0.2-0.3-0.3-0.5 c-0.1-0.2-0.1-0.4-0.2-0.6c0-0.2-0.1-0.4-0.1-0.6c0-0.8,0.3-1.6,0.9-2.1c1.1-1.1,3.1-1.1,4.2,0c0.6,0.6,0.9,1.3,0.9,2.1 c0,0.8-0.3,1.6-0.9,2.1C21.6,66.7,20.8,67,20,67z"
/>
<path
style=
"fill:#DB3E64;"
d=
"M33,67c-1.7,0-3-1.3-3-3c0-18.7,15.3-34,34-34c1.7,0,3,1.3,3,3s-1.3,3-3,3c-2.7,0-5.3,2.6-7.8,4.2 c0,0-1.4-1.4-2.9-0.7c-0.9,0.4-1.9,2.9-2.5,3.2l-2.9,1.5C39.8,49.1,36,53.9,36,64C36,65.7,34.7,67,33,67z"
/>
<path
style=
"fill:#FF5576;"
d=
"M56.2,40.2L52.4,32c-1.9,0.7-3.7,1.5-5.4,2.6l3.8,8.2C52.5,41.7,54.3,40.9,56.2,40.2z"
/>
<path
style=
"fill:#DB3E64;"
d=
"M64,111c-1.7,0-3-1.3-3-3s1.3-3,3-3c22.6,0,41-18.4,41-41c0-1.7,1.3-3,3-3s3,1.3,3,3 c0,16.2-8.2,30.5-20.7,39c-1.2,0.8-1.2,4.3-2.4,5c-0.7,0.4-2.7-1.1-3.5-0.8c-1.1,0.5-0.9,2.9-2,3.3c-1.3,0.5-3.8-1.8-5.2-1.4 C73,110.3,68.6,111,64,111z"
/>
<path
style=
"fill:#FF5576;"
d=
"M82.4,110.5c1.9-0.7,3.7-1.6,5.4-2.5L84,99.8c-1.7,1-3.6,1.8-5.4,2.5L82.4,110.5z"
/>
<path
style=
"fill:#444B54;"
d=
"M111,64c0,16.8-8.9,31.6-22.2,39.9c-1.3,0.8-1.8,2.4-1.1,3.8l0,0c0.8,1.6,2.8,2.2,4.3,1.3 c15-9.4,25-26,25-45c0-5.7-0.9-11.3-2.6-16.4c-0.6-1.7-2.5-2.6-4.1-1.8l0,0c-1.4,0.6-2,2.2-1.6,3.7C110.2,54,111,58.9,111,64z"
/>
<path
style=
"fill:#444B54;"
d=
"M64,111c-16.8,0-31.6-8.9-39.9-22.2c-0.8-1.3-2.4-1.8-3.8-1.1l0,0c-1.6,0.8-2.2,2.8-1.3,4.3 c9.4,15,26,25,45,25c5.7,0,11.3-0.9,16.4-2.6c1.7-0.6,2.6-2.5,1.8-4.1l0,0c-0.6-1.4-2.2-2-3.7-1.6C74,110.2,69.1,111,64,111z"
/>
<path
style=
"fill:#444B54;"
d=
"M42,64c0-6.9,3.2-13,8.1-17.1c1.1-0.9,1.5-2.4,0.9-3.6l0,0c-0.8-1.8-3.1-2.3-4.6-1.1 C40.1,47.3,36,55.2,36,64c0,1.9,0.2,3.7,0.5,5.5c0.4,1.9,2.5,2.9,4.2,2.1l0,0c1.2-0.6,1.9-1.9,1.7-3.2C42.1,66.9,42,65.5,42,64z"
/>
<path
style=
"fill:#444B54;"
d=
"M64,42c6.9,0,13,3.2,17.1,8.1c0.9,1.1,2.4,1.5,3.6,0.9l0,0c1.8-0.8,2.3-3.1,1.1-4.6 C80.7,40.1,72.8,36,64,36c-1.9,0-3.7,0.2-5.5,0.5c-1.9,0.4-2.9,2.5-2.1,4.2l0,0c0.6,1.2,1.9,1.9,3.2,1.7C61.1,42.1,62.5,42,64,42z"
/>
<path
style=
"fill:#444B54;"
d=
"M64,86c-6.9,0-13-3.2-17.1-8.1c-0.9-1.1-2.4-1.5-3.6-0.9l0,0c-1.8,0.8-2.3,3.1-1.1,4.6 C47.3,87.9,55.2,92,64,92c1.9,0,3.7-0.2,5.5-0.5c1.9-0.4,2.9-2.5,2.1-4.2l0,0c-0.6-1.2-1.9-1.9-3.2-1.7C66.9,85.9,65.5,86,64,86z"
/>
<path
style=
"fill:#444B54;"
d=
"M86,64c0,6.9-3.2,13-8.1,17.1c-1.1,0.9-1.5,2.4-0.9,3.6l0,0c0.8,1.8,3.1,2.3,4.6,1.1 C87.9,80.7,92,72.8,92,64c0-1.9-0.2-3.7-0.5-5.5c-0.4-1.9-2.5-2.9-4.2-2.1l0,0c-1.2,0.6-1.9,1.9-1.7,3.2C85.9,61.1,86,62.5,86,64z"
/>
<path
style=
"fill:#444B54;"
d=
"M17,64c0-16.8,8.9-31.6,22.2-39.9c1.3-0.8,1.8-2.4,1.1-3.8l0,0c-0.8-1.6-2.8-2.2-4.3-1.3 c-15,9.4-25,26-25,45c0,5.7,0.9,11.3,2.6,16.4c0.6,1.7,2.5,2.6,4.1,1.8l0,0c1.4-0.6,2-2.2,1.6-3.7C17.8,74,17,69.1,17,64z"
/>
<path
style=
"fill:#444B54;"
d=
"M64,17c16.8,0,31.6,8.9,39.9,22.2c0.8,1.3,2.4,1.8,3.8,1.1l0,0c1.6-0.8,2.2-2.8,1.3-4.3 c-9.4-15-26-25-45-25c-5.7,0-11.3,0.9-16.4,2.6c-1.7,0.6-2.6,2.5-1.8,4.1l0,0c0.6,1.4,2.2,2,3.7,1.6C54,17.8,58.9,17,64,17z"
/>
</svg>
client/static/svg/motif-diagonals.svg
0 → 100644
View file @
75eb2774
<svg
width=
"100%"
height=
"100%"
viewBox=
"0 0 40 40"
xmlns=
"http://www.w3.org/2000/svg"
>
<path
d=
"M40,0l-40,40l0,-20l20,-20l20,0Zm0,40l0,-20l-20,20l20,0Z"
fill=
'#FFFFFF'
fill-opacity=
'0.03'
fill-rule=
'evenodd'
/>
</svg>
client/themes/default/components/page.vue
View file @
75eb2774
...
@@ -189,10 +189,8 @@ export default {
...
@@ -189,10 +189,8 @@ export default {
},
},
breadcrumbs
:
[
breadcrumbs
:
[
{
path
:
'/'
,
name
:
'Home'
},
{
path
:
'/'
,
name
:
'Home'
},
{
path
:
'/universe'
,
name
:
'Universe'
},
{
path
:
'/'
+
this
.
path
,
name
:
'Breadcrumb'
},
{
path
:
'/universe/galaxy'
,
name
:
'Galaxy'
},
{
path
:
'/'
+
this
.
path
,
name
:
'Coming soon'
}
{
path
:
'/universe/galaxy/solar-system'
,
name
:
'Solar System'
},
{
path
:
'/universe/galaxy/solar-system/planet-earth'
,
name
:
'Planet Earth'
}
],
],
scrollStyle
:
{
scrollStyle
:
{
vuescroll
:
{},
vuescroll
:
{},
...
...
dev/examples/Dockerfile
deleted
100644 → 0
View file @
aa57ea92
FROM
requarks/wiki:latest
# Replace with your email address:
ENV
WIKI_ADMIN_EMAIL admin@example.com
WORKDIR
/var/wiki
# Replace your-config.yml with the path to your config file:
ADD
your-config.yml config.yml
EXPOSE
3000
ENTRYPOINT
[ "node", "server" ]
dev/examples/docker-compose.yml
View file @
75eb2774
version
:
'
3'
# -- DEV DOCKER-COMPOSE --
# -- DO NOT USE IN PRODUCTION! --
version
:
"
3"
services
:
services
:
wikidb
:
image
:
mongo
redis
:
expose
:
image
:
redis:4-alpine
-
'
27017'
logging
:
command
:
'
--smallfiles
--logpath=/dev/null'
driver
:
"
none"
volumes
:
networks
:
-
./data/mongo:/data/db
-
wikinet
wikijs
:
image
:
'
requarks/wiki:latest'
db
:
links
:
image
:
postgres:9-alpine
-
wikidb
ports
:
-
'
80:3000'
environment
:
environment
:
WIKI_ADMIN_EMAIL
:
admin@example.com
POSTGRES_DB
:
wiki
POSTGRES_PASSWORD
:
wikijsrocks
POSTGRES_USER
:
wikijs
logging
:
driver
:
"
none"
volumes
:
volumes
:
-
./config.yml:/var/wiki/config.yml
-
db-data:/var/lib/postgresql/data
networks
:
-
wikinet
wiki
:
image
:
requarks/wiki:beta
depends_on
:
-
db
-
redis
environment
:
PORT
:
3000
# DO NOT CHANGE! Use ports below to specify listening port.
DB_TYPE
:
postgres
DB_HOST
:
db
DB_PORT
:
5432
DB_USER
:
wikijs
DB_PASS
:
wikijsrocks
DB_NAME
:
wiki
REDIS_HOST
:
redis
REDIS_PORT
:
6379
REDIS_DB
:
0
REDIS_PASS
:
'
'
networks
:
-
wikinet
ports
:
-
"
3000:3000"
# <-- replace with "80:3000" to listen on port 80 instead
networks
:
wikinet
:
volumes
:
db-data
:
server/app/data.yml
View file @
75eb2774
...
@@ -22,14 +22,12 @@ defaults:
...
@@ -22,14 +22,12 @@ defaults:
db
:
0
db
:
0
password
:
null
password
:
null
# DB defaults
# DB defaults
defaultEditor
:
'
markdown'
graphEndpoint
:
'
https://graph.requarks.io'
graphEndpoint
:
'
https://graph.requarks.io'
lang
:
lang
:
code
:
en
code
:
en
autoUpdate
:
true
autoUpdate
:
true
namespaces
:
[]
namespaces
:
[]
namespacing
:
false
namespacing
:
false
public
:
false
telemetry
:
telemetry
:
clientId
:
'
'
clientId
:
'
'
isEnabled
:
false
isEnabled
:
false
...
@@ -47,13 +45,6 @@ defaults:
...
@@ -47,13 +45,6 @@ defaults:
maxAge
:
600
maxAge
:
600
methods
:
'
GET,POST'
methods
:
'
GET,POST'
origin
:
true
origin
:
true
configNamespaces
:
-
auth
-
features
-
logging
-
site
-
theme
-
uploads
localeNamespaces
:
localeNamespaces
:
-
admin
-
admin
-
auth
-
auth
...
...
server/controllers/common.js
View file @
75eb2774
...
@@ -6,6 +6,18 @@ const _ = require('lodash')
...
@@ -6,6 +6,18 @@ const _ = require('lodash')
/* global WIKI */
/* global WIKI */
/**
/**
* Robots.txt
*/
router
.
get
(
'/robots.txt'
,
(
req
,
res
,
next
)
=>
{
res
.
type
(
'text/plain'
)
if
(
_
.
includes
(
WIKI
.
config
.
seo
.
robots
,
'noindex'
))
{
res
.
send
(
"User-agent: *
\
nDisallow: /"
)
}
else
{
res
.
status
(
200
).
end
()
}
})
/**
* Create/Edit document
* Create/Edit document
*/
*/
router
.
get
([
'/e'
,
'/e/*'
],
async
(
req
,
res
,
next
)
=>
{
router
.
get
([
'/e'
,
'/e/*'
],
async
(
req
,
res
,
next
)
=>
{
...
@@ -17,12 +29,20 @@ router.get(['/e', '/e/*'], async (req, res, next) => {
...
@@ -17,12 +29,20 @@ router.get(['/e', '/e/*'], async (req, res, next) => {
isPrivate
:
false
isPrivate
:
false
})
})
if
(
page
)
{
if
(
page
)
{
if
(
!
WIKI
.
auth
.
checkAccess
(
req
.
user
,
[
'manage:pages'
],
pageArgs
))
{
return
res
.
render
(
'unauthorized'
,
{
action
:
'edit'
})
}
_
.
set
(
res
.
locals
,
'pageMeta.title'
,
`Edit
${
page
.
title
}
`
)
_
.
set
(
res
.
locals
,
'pageMeta.title'
,
`Edit
${
page
.
title
}
`
)
_
.
set
(
res
.
locals
,
'pageMeta.description'
,
page
.
description
)
_
.
set
(
res
.
locals
,
'pageMeta.description'
,
page
.
description
)
page
.
mode
=
'update'
page
.
mode
=
'update'
page
.
isPublished
=
(
page
.
isPublished
===
true
||
page
.
isPublished
===
1
)
?
'true'
:
'false'
page
.
isPublished
=
(
page
.
isPublished
===
true
||
page
.
isPublished
===
1
)
?
'true'
:
'false'
page
.
content
=
Buffer
.
from
(
page
.
content
).
toString
(
'base64'
)
page
.
content
=
Buffer
.
from
(
page
.
content
).
toString
(
'base64'
)
}
else
{
}
else
{
if
(
!
WIKI
.
auth
.
checkAccess
(
req
.
user
,
[
'write:pages'
],
pageArgs
))
{
return
res
.
render
(
'unauthorized'
,
{
action
:
'create'
})
}
_
.
set
(
res
.
locals
,
'pageMeta.title'
,
`New Page`
)
_
.
set
(
res
.
locals
,
'pageMeta.title'
,
`New Page`
)
page
=
{
page
=
{
path
:
pageArgs
.
path
,
path
:
pageArgs
.
path
,
...
@@ -56,6 +76,11 @@ router.get(['/p', '/p/*'], (req, res, next) => {
...
@@ -56,6 +76,11 @@ router.get(['/p', '/p/*'], (req, res, next) => {
*/
*/
router
.
get
([
'/h'
,
'/h/*'
],
async
(
req
,
res
,
next
)
=>
{
router
.
get
([
'/h'
,
'/h/*'
],
async
(
req
,
res
,
next
)
=>
{
const
pageArgs
=
pageHelper
.
parsePath
(
req
.
path
)
const
pageArgs
=
pageHelper
.
parsePath
(
req
.
path
)
if
(
!
WIKI
.
auth
.
checkAccess
(
req
.
user
,
[
'read:pages'
],
pageArgs
))
{
return
res
.
render
(
'unauthorized'
,
{
action
:
'history'
})
}
const
page
=
await
WIKI
.
models
.
pages
.
getPageFromDb
({
const
page
=
await
WIKI
.
models
.
pages
.
getPageFromDb
({
path
:
pageArgs
.
path
,
path
:
pageArgs
.
path
,
locale
:
pageArgs
.
locale
,
locale
:
pageArgs
.
locale
,
...
@@ -76,6 +101,11 @@ router.get(['/h', '/h/*'], async (req, res, next) => {
...
@@ -76,6 +101,11 @@ router.get(['/h', '/h/*'], async (req, res, next) => {
*/
*/
router
.
get
([
'/s'
,
'/s/*'
],
async
(
req
,
res
,
next
)
=>
{
router
.
get
([
'/s'
,
'/s/*'
],
async
(
req
,
res
,
next
)
=>
{
const
pageArgs
=
pageHelper
.
parsePath
(
req
.
path
)
const
pageArgs
=
pageHelper
.
parsePath
(
req
.
path
)
if
(
!
WIKI
.
auth
.
checkAccess
(
req
.
user
,
[
'read:pages'
],
pageArgs
))
{
return
res
.
render
(
'unauthorized'
,
{
action
:
'source'
})
}
const
page
=
await
WIKI
.
models
.
pages
.
getPageFromDb
({
const
page
=
await
WIKI
.
models
.
pages
.
getPageFromDb
({
path
:
pageArgs
.
path
,
path
:
pageArgs
.
path
,
locale
:
pageArgs
.
locale
,
locale
:
pageArgs
.
locale
,
...
@@ -96,6 +126,15 @@ router.get(['/s', '/s/*'], async (req, res, next) => {
...
@@ -96,6 +126,15 @@ router.get(['/s', '/s/*'], async (req, res, next) => {
*/
*/
router
.
get
(
'/*'
,
async
(
req
,
res
,
next
)
=>
{
router
.
get
(
'/*'
,
async
(
req
,
res
,
next
)
=>
{
const
pageArgs
=
pageHelper
.
parsePath
(
req
.
path
)
const
pageArgs
=
pageHelper
.
parsePath
(
req
.
path
)
if
(
!
WIKI
.
auth
.
checkAccess
(
req
.
user
,
[
'read:pages'
],
pageArgs
))
{
if
(
pageArgs
.
path
===
'home'
)
{
return
res
.
redirect
(
'/login'
)
}
else
{
return
res
.
render
(
'unauthorized'
,
{
action
:
'view'
})
}
}
const
page
=
await
WIKI
.
models
.
pages
.
getPage
({
const
page
=
await
WIKI
.
models
.
pages
.
getPage
({
path
:
pageArgs
.
path
,
path
:
pageArgs
.
path
,
locale
:
pageArgs
.
locale
,
locale
:
pageArgs
.
locale
,
...
@@ -108,8 +147,10 @@ router.get('/*', async (req, res, next) => {
...
@@ -108,8 +147,10 @@ router.get('/*', async (req, res, next) => {
const
sidebar
=
await
WIKI
.
models
.
navigation
.
getTree
({
cache
:
true
})
const
sidebar
=
await
WIKI
.
models
.
navigation
.
getTree
({
cache
:
true
})
res
.
render
(
'page'
,
{
page
,
sidebar
})
res
.
render
(
'page'
,
{
page
,
sidebar
})
}
else
if
(
pageArgs
.
path
===
'home'
)
{
}
else
if
(
pageArgs
.
path
===
'home'
)
{
_
.
set
(
res
.
locals
,
'pageMeta.title'
,
'Welcome'
)
res
.
render
(
'welcome'
)
res
.
render
(
'welcome'
)
}
else
{
}
else
{
_
.
set
(
res
.
locals
,
'pageMeta.title'
,
'Page Not Found'
)
res
.
status
(
404
).
render
(
'new'
,
{
pagePath
:
req
.
path
})
res
.
status
(
404
).
render
(
'new'
,
{
pagePath
:
req
.
path
})
}
}
})
})
...
...
server/core/auth.js
View file @
75eb2774
...
@@ -3,6 +3,8 @@ const passportJWT = require('passport-jwt')
...
@@ -3,6 +3,8 @@ const passportJWT = require('passport-jwt')
const
fs
=
require
(
'fs-extra'
)
const
fs
=
require
(
'fs-extra'
)
const
_
=
require
(
'lodash'
)
const
_
=
require
(
'lodash'
)
const
path
=
require
(
'path'
)
const
path
=
require
(
'path'
)
const
jwt
=
require
(
'jsonwebtoken'
)
const
moment
=
require
(
'moment'
)
const
securityHelper
=
require
(
'../helpers/security'
)
const
securityHelper
=
require
(
'../helpers/security'
)
...
@@ -10,11 +12,16 @@ const securityHelper = require('../helpers/security')
...
@@ -10,11 +12,16 @@ const securityHelper = require('../helpers/security')
module
.
exports
=
{
module
.
exports
=
{
strategies
:
{},
strategies
:
{},
guest
:
{
cacheExpiration
:
moment
.
utc
().
subtract
(
1
,
'd'
)
},
/**
* Initialize the authentication module
*/
init
()
{
init
()
{
this
.
passport
=
passport
this
.
passport
=
passport
// Serialization user methods
passport
.
serializeUser
(
function
(
user
,
done
)
{
passport
.
serializeUser
(
function
(
user
,
done
)
{
done
(
null
,
user
.
id
)
done
(
null
,
user
.
id
)
})
})
...
@@ -34,6 +41,10 @@ module.exports = {
...
@@ -34,6 +41,10 @@ module.exports = {
return
this
return
this
},
},
/**
* Load authentication strategies
*/
async
activateStrategies
()
{
async
activateStrategies
()
{
try
{
try
{
// Unload any active strategies
// Unload any active strategies
...
@@ -46,7 +57,7 @@ module.exports = {
...
@@ -46,7 +57,7 @@ module.exports = {
passport
.
use
(
'jwt'
,
new
passportJWT
.
Strategy
({
passport
.
use
(
'jwt'
,
new
passportJWT
.
Strategy
({
jwtFromRequest
:
securityHelper
.
extractJWT
,
jwtFromRequest
:
securityHelper
.
extractJWT
,
secretOrKey
:
WIKI
.
config
.
certs
.
public
,
secretOrKey
:
WIKI
.
config
.
certs
.
public
,
audience
:
'urn:wiki.js'
,
// TODO: use value from admin
audience
:
WIKI
.
config
.
auth
.
audience
,
issuer
:
'urn:wiki.js'
issuer
:
'urn:wiki.js'
},
(
jwtPayload
,
cb
)
=>
{
},
(
jwtPayload
,
cb
)
=>
{
cb
(
null
,
jwtPayload
)
cb
(
null
,
jwtPayload
)
...
@@ -60,7 +71,7 @@ module.exports = {
...
@@ -60,7 +71,7 @@ module.exports = {
const
strategy
=
require
(
`../modules/authentication/
${
stg
.
key
}
/authentication.js`
)
const
strategy
=
require
(
`../modules/authentication/
${
stg
.
key
}
/authentication.js`
)
stg
.
config
.
callbackURL
=
`
${
WIKI
.
config
.
host
}
/login/
${
stg
.
key
}
/callback`
// TODO: config.host
stg
.
config
.
callbackURL
=
`
${
WIKI
.
config
.
host
}
/login/
${
stg
.
key
}
/callback`
strategy
.
init
(
passport
,
stg
.
config
)
strategy
.
init
(
passport
,
stg
.
config
)
fs
.
readFile
(
path
.
join
(
WIKI
.
ROOTPATH
,
`assets/svg/auth-icon-
${
strategy
.
key
}
.svg`
),
'utf8'
).
then
(
iconData
=>
{
fs
.
readFile
(
path
.
join
(
WIKI
.
ROOTPATH
,
`assets/svg/auth-icon-
${
strategy
.
key
}
.svg`
),
'utf8'
).
then
(
iconData
=>
{
...
@@ -79,5 +90,74 @@ module.exports = {
...
@@ -79,5 +90,74 @@ module.exports = {
WIKI
.
logger
.
error
(
`Authentication Strategy: [ FAILED ]`
)
WIKI
.
logger
.
error
(
`Authentication Strategy: [ FAILED ]`
)
WIKI
.
logger
.
error
(
err
)
WIKI
.
logger
.
error
(
err
)
}
}
},
/**
* Authenticate current request
*
* @param {Express Request} req
* @param {Express Response} res
* @param {Express Next Callback} next
*/
authenticate
(
req
,
res
,
next
)
{
WIKI
.
auth
.
passport
.
authenticate
(
'jwt'
,
{
session
:
false
},
async
(
err
,
user
,
info
)
=>
{
if
(
err
)
{
return
next
()
}
// Expired but still valid within N days, just renew
if
(
info
instanceof
Error
&&
info
.
name
===
'TokenExpiredError'
&&
moment
().
subtract
(
14
,
'days'
).
isBefore
(
info
.
expiredAt
))
{
const
jwtPayload
=
jwt
.
decode
(
securityHelper
.
extractJWT
(
req
))
try
{
const
newToken
=
await
WIKI
.
models
.
users
.
refreshToken
(
jwtPayload
.
id
)
user
=
newToken
.
user
// Try headers, otherwise cookies for response
if
(
req
.
get
(
'content-type'
)
===
'application/json'
)
{
res
.
set
(
'new-jwt'
,
newToken
.
token
)
}
else
{
res
.
cookie
(
'jwt'
,
newToken
.
token
,
{
expires
:
moment
().
add
(
365
,
'days'
).
toDate
()
})
}
}
catch
(
err
)
{
return
next
()
}
}
// JWT is NOT valid, set as guest
if
(
!
user
)
{
if
(
WIKI
.
auth
.
guest
.
cacheExpiration
)
{
WIKI
.
auth
.
guest
=
await
WIKI
.
models
.
users
.
getGuestUser
()
WIKI
.
auth
.
guest
.
cacheExpiration
=
moment
.
utc
().
add
(
1
,
'm'
)
}
req
.
user
=
WIKI
.
auth
.
guest
return
next
()
}
// JWT is valid
req
.
logIn
(
user
,
{
session
:
false
},
(
err
)
=>
{
if
(
err
)
{
return
next
(
err
)
}
next
()
})
})(
req
,
res
,
next
)
},
/**
* Check if user has access to resource
*
* @param {User} user
* @param {Array<String>} permissions
* @param {String|Boolean} path
*/
checkAccess
(
user
,
permissions
=
[],
path
=
false
)
{
// System Admin
if
(
_
.
includes
(
user
.
permissions
,
'manage:system'
))
{
return
true
}
// Check Global Permissions
if
(
_
.
intersection
(
user
.
permissions
,
permissions
).
length
<
1
)
{
return
false
}
// Check Page Rules
return
false
}
}
}
}
server/core/config.js
View file @
75eb2774
...
@@ -52,8 +52,6 @@ module.exports = {
...
@@ -52,8 +52,6 @@ module.exports = {
appconfig
.
port
=
process
.
env
.
PORT
||
80
appconfig
.
port
=
process
.
env
.
PORT
||
80
}
}
appconfig
.
public
=
(
appconfig
.
public
===
true
||
_
.
toLower
(
appconfig
.
public
)
===
'true'
)
WIKI
.
config
=
appconfig
WIKI
.
config
=
appconfig
WIKI
.
data
=
appdata
WIKI
.
data
=
appdata
WIKI
.
version
=
require
(
path
.
join
(
WIKI
.
ROOTPATH
,
'package.json'
)).
version
WIKI
.
version
=
require
(
path
.
join
(
WIKI
.
ROOTPATH
,
'package.json'
)).
version
...
...
server/db/migrations/2.0.0.js
→
server/db/migrations/2.0.0
-beta.1
.js
View file @
75eb2774
exports
.
up
=
knex
=>
{
exports
.
up
=
knex
=>
{
const
dbCompat
=
{
charset
:
(
WIKI
.
config
.
db
.
type
===
`mysql`
||
WIKI
.
config
.
db
.
type
===
`mariadb`
)
}
return
knex
.
schema
return
knex
.
schema
// =====================================
// =====================================
// MODEL TABLES
// MODEL TABLES
// =====================================
// =====================================
// ASSETS ------------------------------
// ASSETS ------------------------------
.
createTable
(
'assets'
,
table
=>
{
.
createTable
(
'assets'
,
table
=>
{
table
.
charset
(
'utf8mb4'
)
if
(
dbCompat
.
charset
)
{
table
.
charset
(
'utf8mb4'
)
}
table
.
increments
(
'id'
).
primary
()
table
.
increments
(
'id'
).
primary
()
table
.
string
(
'filename'
).
notNullable
()
table
.
string
(
'filename'
).
notNullable
()
table
.
string
(
'basename'
).
notNullable
()
table
.
string
(
'basename'
).
notNullable
()
...
@@ -19,7 +22,7 @@ exports.up = knex => {
...
@@ -19,7 +22,7 @@ exports.up = knex => {
})
})
// ASSET FOLDERS -----------------------
// ASSET FOLDERS -----------------------
.
createTable
(
'assetFolders'
,
table
=>
{
.
createTable
(
'assetFolders'
,
table
=>
{
table
.
charset
(
'utf8mb4'
)
if
(
dbCompat
.
charset
)
{
table
.
charset
(
'utf8mb4'
)
}
table
.
increments
(
'id'
).
primary
()
table
.
increments
(
'id'
).
primary
()
table
.
string
(
'name'
).
notNullable
()
table
.
string
(
'name'
).
notNullable
()
table
.
string
(
'slug'
).
notNullable
()
table
.
string
(
'slug'
).
notNullable
()
...
@@ -27,7 +30,7 @@ exports.up = knex => {
...
@@ -27,7 +30,7 @@ exports.up = knex => {
})
})
// AUTHENTICATION ----------------------
// AUTHENTICATION ----------------------
.
createTable
(
'authentication'
,
table
=>
{
.
createTable
(
'authentication'
,
table
=>
{
table
.
charset
(
'utf8mb4'
)
if
(
dbCompat
.
charset
)
{
table
.
charset
(
'utf8mb4'
)
}
table
.
string
(
'key'
).
notNullable
().
primary
()
table
.
string
(
'key'
).
notNullable
().
primary
()
table
.
boolean
(
'isEnabled'
).
notNullable
().
defaultTo
(
false
)
table
.
boolean
(
'isEnabled'
).
notNullable
().
defaultTo
(
false
)
table
.
json
(
'config'
).
notNullable
()
table
.
json
(
'config'
).
notNullable
()
...
@@ -37,7 +40,7 @@ exports.up = knex => {
...
@@ -37,7 +40,7 @@ exports.up = knex => {
})
})
// COMMENTS ----------------------------
// COMMENTS ----------------------------
.
createTable
(
'comments'
,
table
=>
{
.
createTable
(
'comments'
,
table
=>
{
table
.
charset
(
'utf8mb4'
)
if
(
dbCompat
.
charset
)
{
table
.
charset
(
'utf8mb4'
)
}
table
.
increments
(
'id'
).
primary
()
table
.
increments
(
'id'
).
primary
()
table
.
text
(
'content'
).
notNullable
()
table
.
text
(
'content'
).
notNullable
()
table
.
string
(
'createdAt'
).
notNullable
()
table
.
string
(
'createdAt'
).
notNullable
()
...
@@ -45,14 +48,14 @@ exports.up = knex => {
...
@@ -45,14 +48,14 @@ exports.up = knex => {
})
})
// EDITORS -----------------------------
// EDITORS -----------------------------
.
createTable
(
'editors'
,
table
=>
{
.
createTable
(
'editors'
,
table
=>
{
table
.
charset
(
'utf8mb4'
)
if
(
dbCompat
.
charset
)
{
table
.
charset
(
'utf8mb4'
)
}
table
.
string
(
'key'
).
notNullable
().
primary
()
table
.
string
(
'key'
).
notNullable
().
primary
()
table
.
boolean
(
'isEnabled'
).
notNullable
().
defaultTo
(
false
)
table
.
boolean
(
'isEnabled'
).
notNullable
().
defaultTo
(
false
)
table
.
json
(
'config'
).
notNullable
()
table
.
json
(
'config'
).
notNullable
()
})
})
// GROUPS ------------------------------
// GROUPS ------------------------------
.
createTable
(
'groups'
,
table
=>
{
.
createTable
(
'groups'
,
table
=>
{
table
.
charset
(
'utf8mb4'
)
if
(
dbCompat
.
charset
)
{
table
.
charset
(
'utf8mb4'
)
}
table
.
increments
(
'id'
).
primary
()
table
.
increments
(
'id'
).
primary
()
table
.
string
(
'name'
).
notNullable
()
table
.
string
(
'name'
).
notNullable
()
table
.
json
(
'permissions'
).
notNullable
()
table
.
json
(
'permissions'
).
notNullable
()
...
@@ -63,7 +66,7 @@ exports.up = knex => {
...
@@ -63,7 +66,7 @@ exports.up = knex => {
})
})
// LOCALES -----------------------------
// LOCALES -----------------------------
.
createTable
(
'locales'
,
table
=>
{
.
createTable
(
'locales'
,
table
=>
{
table
.
charset
(
'utf8mb4'
)
if
(
dbCompat
.
charset
)
{
table
.
charset
(
'utf8mb4'
)
}
table
.
string
(
'code'
,
2
).
notNullable
().
primary
()
table
.
string
(
'code'
,
2
).
notNullable
().
primary
()
table
.
json
(
'strings'
)
table
.
json
(
'strings'
)
table
.
boolean
(
'isRTL'
).
notNullable
().
defaultTo
(
false
)
table
.
boolean
(
'isRTL'
).
notNullable
().
defaultTo
(
false
)
...
@@ -74,7 +77,7 @@ exports.up = knex => {
...
@@ -74,7 +77,7 @@ exports.up = knex => {
})
})
// LOGGING ----------------------------
// LOGGING ----------------------------
.
createTable
(
'loggers'
,
table
=>
{
.
createTable
(
'loggers'
,
table
=>
{
table
.
charset
(
'utf8mb4'
)
if
(
dbCompat
.
charset
)
{
table
.
charset
(
'utf8mb4'
)
}
table
.
string
(
'key'
).
notNullable
().
primary
()
table
.
string
(
'key'
).
notNullable
().
primary
()
table
.
boolean
(
'isEnabled'
).
notNullable
().
defaultTo
(
false
)
table
.
boolean
(
'isEnabled'
).
notNullable
().
defaultTo
(
false
)
table
.
string
(
'level'
).
notNullable
().
defaultTo
(
'warn'
)
table
.
string
(
'level'
).
notNullable
().
defaultTo
(
'warn'
)
...
@@ -82,13 +85,13 @@ exports.up = knex => {
...
@@ -82,13 +85,13 @@ exports.up = knex => {
})
})
// NAVIGATION ----------------------------
// NAVIGATION ----------------------------
.
createTable
(
'navigation'
,
table
=>
{
.
createTable
(
'navigation'
,
table
=>
{
table
.
charset
(
'utf8mb4'
)
if
(
dbCompat
.
charset
)
{
table
.
charset
(
'utf8mb4'
)
}
table
.
string
(
'key'
).
notNullable
().
primary
()
table
.
string
(
'key'
).
notNullable
().
primary
()
table
.
json
(
'config'
)
table
.
json
(
'config'
)
})
})
// PAGE HISTORY ------------------------
// PAGE HISTORY ------------------------
.
createTable
(
'pageHistory'
,
table
=>
{
.
createTable
(
'pageHistory'
,
table
=>
{
table
.
charset
(
'utf8mb4'
)
if
(
dbCompat
.
charset
)
{
table
.
charset
(
'utf8mb4'
)
}
table
.
increments
(
'id'
).
primary
()
table
.
increments
(
'id'
).
primary
()
table
.
string
(
'path'
).
notNullable
()
table
.
string
(
'path'
).
notNullable
()
table
.
string
(
'hash'
).
notNullable
()
table
.
string
(
'hash'
).
notNullable
()
...
@@ -104,7 +107,7 @@ exports.up = knex => {
...
@@ -104,7 +107,7 @@ exports.up = knex => {
})
})
// PAGES -------------------------------
// PAGES -------------------------------
.
createTable
(
'pages'
,
table
=>
{
.
createTable
(
'pages'
,
table
=>
{
table
.
charset
(
'utf8mb4'
)
if
(
dbCompat
.
charset
)
{
table
.
charset
(
'utf8mb4'
)
}
table
.
increments
(
'id'
).
primary
()
table
.
increments
(
'id'
).
primary
()
table
.
string
(
'path'
).
notNullable
()
table
.
string
(
'path'
).
notNullable
()
table
.
string
(
'hash'
).
notNullable
()
table
.
string
(
'hash'
).
notNullable
()
...
@@ -124,7 +127,7 @@ exports.up = knex => {
...
@@ -124,7 +127,7 @@ exports.up = knex => {
})
})
// PAGE TREE ---------------------------
// PAGE TREE ---------------------------
.
createTable
(
'pageTree'
,
table
=>
{
.
createTable
(
'pageTree'
,
table
=>
{
table
.
charset
(
'utf8mb4'
)
if
(
dbCompat
.
charset
)
{
table
.
charset
(
'utf8mb4'
)
}
table
.
increments
(
'id'
).
primary
()
table
.
increments
(
'id'
).
primary
()
table
.
string
(
'path'
).
notNullable
()
table
.
string
(
'path'
).
notNullable
()
table
.
integer
(
'depth'
).
unsigned
().
notNullable
()
table
.
integer
(
'depth'
).
unsigned
().
notNullable
()
...
@@ -135,28 +138,28 @@ exports.up = knex => {
...
@@ -135,28 +138,28 @@ exports.up = knex => {
})
})
// RENDERERS ---------------------------
// RENDERERS ---------------------------
.
createTable
(
'renderers'
,
table
=>
{
.
createTable
(
'renderers'
,
table
=>
{
table
.
charset
(
'utf8mb4'
)
if
(
dbCompat
.
charset
)
{
table
.
charset
(
'utf8mb4'
)
}
table
.
string
(
'key'
).
notNullable
().
primary
()
table
.
string
(
'key'
).
notNullable
().
primary
()
table
.
boolean
(
'isEnabled'
).
notNullable
().
defaultTo
(
false
)
table
.
boolean
(
'isEnabled'
).
notNullable
().
defaultTo
(
false
)
table
.
json
(
'config'
)
table
.
json
(
'config'
)
})
})
// SEARCH ------------------------------
// SEARCH ------------------------------
.
createTable
(
'searchEngines'
,
table
=>
{
.
createTable
(
'searchEngines'
,
table
=>
{
table
.
charset
(
'utf8mb4'
)
if
(
dbCompat
.
charset
)
{
table
.
charset
(
'utf8mb4'
)
}
table
.
string
(
'key'
).
notNullable
().
primary
()
table
.
string
(
'key'
).
notNullable
().
primary
()
table
.
boolean
(
'isEnabled'
).
notNullable
().
defaultTo
(
false
)
table
.
boolean
(
'isEnabled'
).
notNullable
().
defaultTo
(
false
)
table
.
json
(
'config'
)
table
.
json
(
'config'
)
})
})
// SETTINGS ----------------------------
// SETTINGS ----------------------------
.
createTable
(
'settings'
,
table
=>
{
.
createTable
(
'settings'
,
table
=>
{
table
.
charset
(
'utf8mb4'
)
if
(
dbCompat
.
charset
)
{
table
.
charset
(
'utf8mb4'
)
}
table
.
string
(
'key'
).
notNullable
().
primary
()
table
.
string
(
'key'
).
notNullable
().
primary
()
table
.
json
(
'value'
)
table
.
json
(
'value'
)
table
.
string
(
'updatedAt'
).
notNullable
()
table
.
string
(
'updatedAt'
).
notNullable
()
})
})
// STORAGE -----------------------------
// STORAGE -----------------------------
.
createTable
(
'storage'
,
table
=>
{
.
createTable
(
'storage'
,
table
=>
{
table
.
charset
(
'utf8mb4'
)
if
(
dbCompat
.
charset
)
{
table
.
charset
(
'utf8mb4'
)
}
table
.
string
(
'key'
).
notNullable
().
primary
()
table
.
string
(
'key'
).
notNullable
().
primary
()
table
.
boolean
(
'isEnabled'
).
notNullable
().
defaultTo
(
false
)
table
.
boolean
(
'isEnabled'
).
notNullable
().
defaultTo
(
false
)
table
.
string
(
'mode'
,
[
'sync'
,
'push'
,
'pull'
]).
notNullable
().
defaultTo
(
'push'
)
table
.
string
(
'mode'
,
[
'sync'
,
'push'
,
'pull'
]).
notNullable
().
defaultTo
(
'push'
)
...
@@ -164,7 +167,7 @@ exports.up = knex => {
...
@@ -164,7 +167,7 @@ exports.up = knex => {
})
})
// TAGS --------------------------------
// TAGS --------------------------------
.
createTable
(
'tags'
,
table
=>
{
.
createTable
(
'tags'
,
table
=>
{
table
.
charset
(
'utf8mb4'
)
if
(
dbCompat
.
charset
)
{
table
.
charset
(
'utf8mb4'
)
}
table
.
increments
(
'id'
).
primary
()
table
.
increments
(
'id'
).
primary
()
table
.
string
(
'tag'
).
notNullable
().
unique
()
table
.
string
(
'tag'
).
notNullable
().
unique
()
table
.
string
(
'title'
)
table
.
string
(
'title'
)
...
@@ -173,7 +176,7 @@ exports.up = knex => {
...
@@ -173,7 +176,7 @@ exports.up = knex => {
})
})
// USER KEYS ---------------------------
// USER KEYS ---------------------------
.
createTable
(
'userKeys'
,
table
=>
{
.
createTable
(
'userKeys'
,
table
=>
{
table
.
charset
(
'utf8mb4'
)
if
(
dbCompat
.
charset
)
{
table
.
charset
(
'utf8mb4'
)
}
table
.
increments
(
'id'
).
primary
()
table
.
increments
(
'id'
).
primary
()
table
.
string
(
'kind'
).
notNullable
()
table
.
string
(
'kind'
).
notNullable
()
table
.
string
(
'token'
).
notNullable
()
table
.
string
(
'token'
).
notNullable
()
...
@@ -182,7 +185,7 @@ exports.up = knex => {
...
@@ -182,7 +185,7 @@ exports.up = knex => {
})
})
// USERS -------------------------------
// USERS -------------------------------
.
createTable
(
'users'
,
table
=>
{
.
createTable
(
'users'
,
table
=>
{
table
.
charset
(
'utf8mb4'
)
if
(
dbCompat
.
charset
)
{
table
.
charset
(
'utf8mb4'
)
}
table
.
increments
(
'id'
).
primary
()
table
.
increments
(
'id'
).
primary
()
table
.
string
(
'email'
).
notNullable
()
table
.
string
(
'email'
).
notNullable
()
table
.
string
(
'name'
).
notNullable
()
table
.
string
(
'name'
).
notNullable
()
...
@@ -205,21 +208,21 @@ exports.up = knex => {
...
@@ -205,21 +208,21 @@ exports.up = knex => {
// =====================================
// =====================================
// PAGE HISTORY TAGS ---------------------------
// PAGE HISTORY TAGS ---------------------------
.
createTable
(
'pageHistoryTags'
,
table
=>
{
.
createTable
(
'pageHistoryTags'
,
table
=>
{
table
.
charset
(
'utf8mb4'
)
if
(
dbCompat
.
charset
)
{
table
.
charset
(
'utf8mb4'
)
}
table
.
increments
(
'id'
).
primary
()
table
.
increments
(
'id'
).
primary
()
table
.
integer
(
'pageId'
).
unsigned
().
references
(
'id'
).
inTable
(
'pageHistory'
).
onDelete
(
'CASCADE'
)
table
.
integer
(
'pageId'
).
unsigned
().
references
(
'id'
).
inTable
(
'pageHistory'
).
onDelete
(
'CASCADE'
)
table
.
integer
(
'tagId'
).
unsigned
().
references
(
'id'
).
inTable
(
'tags'
).
onDelete
(
'CASCADE'
)
table
.
integer
(
'tagId'
).
unsigned
().
references
(
'id'
).
inTable
(
'tags'
).
onDelete
(
'CASCADE'
)
})
})
// PAGE TAGS ---------------------------
// PAGE TAGS ---------------------------
.
createTable
(
'pageTags'
,
table
=>
{
.
createTable
(
'pageTags'
,
table
=>
{
table
.
charset
(
'utf8mb4'
)
if
(
dbCompat
.
charset
)
{
table
.
charset
(
'utf8mb4'
)
}
table
.
increments
(
'id'
).
primary
()
table
.
increments
(
'id'
).
primary
()
table
.
integer
(
'pageId'
).
unsigned
().
references
(
'id'
).
inTable
(
'pages'
).
onDelete
(
'CASCADE'
)
table
.
integer
(
'pageId'
).
unsigned
().
references
(
'id'
).
inTable
(
'pages'
).
onDelete
(
'CASCADE'
)
table
.
integer
(
'tagId'
).
unsigned
().
references
(
'id'
).
inTable
(
'tags'
).
onDelete
(
'CASCADE'
)
table
.
integer
(
'tagId'
).
unsigned
().
references
(
'id'
).
inTable
(
'tags'
).
onDelete
(
'CASCADE'
)
})
})
// USER GROUPS -------------------------
// USER GROUPS -------------------------
.
createTable
(
'userGroups'
,
table
=>
{
.
createTable
(
'userGroups'
,
table
=>
{
table
.
charset
(
'utf8mb4'
)
if
(
dbCompat
.
charset
)
{
table
.
charset
(
'utf8mb4'
)
}
table
.
increments
(
'id'
).
primary
()
table
.
increments
(
'id'
).
primary
()
table
.
integer
(
'userId'
).
unsigned
().
references
(
'id'
).
inTable
(
'users'
).
onDelete
(
'CASCADE'
)
table
.
integer
(
'userId'
).
unsigned
().
references
(
'id'
).
inTable
(
'users'
).
onDelete
(
'CASCADE'
)
table
.
integer
(
'groupId'
).
unsigned
().
references
(
'id'
).
inTable
(
'groups'
).
onDelete
(
'CASCADE'
)
table
.
integer
(
'groupId'
).
unsigned
().
references
(
'id'
).
inTable
(
'groups'
).
onDelete
(
'CASCADE'
)
...
...
server/db/seeds/settings.js
deleted
100644 → 0
View file @
aa57ea92
exports
.
seed
=
(
knex
,
Promise
)
=>
{
return
knex
(
'settings'
)
.
insert
([
{
key
:
'auth'
,
value
:
{}
},
{
key
:
'features'
,
value
:
{}
},
{
key
:
'logging'
,
value
:
{}
},
{
key
:
'site'
,
value
:
{}
},
{
key
:
'theme'
,
value
:
{}
},
{
key
:
'uploads'
,
value
:
{}
}
])
}
server/graph/resolvers/authentication.js
View file @
75eb2774
...
@@ -70,6 +70,13 @@ module.exports = {
...
@@ -70,6 +70,13 @@ module.exports = {
},
},
async
updateStrategies
(
obj
,
args
,
context
)
{
async
updateStrategies
(
obj
,
args
,
context
)
{
try
{
try
{
WIKI
.
config
.
auth
=
{
audience
:
_
.
get
(
args
,
'config.audience'
,
WIKI
.
config
.
auth
.
audience
),
tokenExpiration
:
_
.
get
(
args
,
'config.tokenExpiration'
,
WIKI
.
config
.
auth
.
tokenExpiration
),
tokenRenewal
:
_
.
get
(
args
,
'config.tokenRenewal'
,
WIKI
.
config
.
auth
.
tokenRenewal
)
}
await
WIKI
.
configSvc
.
saveToDb
([
'auth'
])
for
(
let
str
of
args
.
strategies
)
{
for
(
let
str
of
args
.
strategies
)
{
await
WIKI
.
models
.
authentication
.
query
().
patch
({
await
WIKI
.
models
.
authentication
.
query
().
patch
({
isEnabled
:
str
.
isEnabled
,
isEnabled
:
str
.
isEnabled
,
...
...
server/graph/schemas/authentication.graphql
View file @
75eb2774
...
@@ -43,7 +43,8 @@ type AuthenticationMutation {
...
@@ -43,7 +43,8 @@ type AuthenticationMutation {
):
AuthenticationRegisterResponse
):
AuthenticationRegisterResponse
updateStrategies
(
updateStrategies
(
strategies
:
[
AuthenticationStrategyInput
]
strategies
:
[
AuthenticationStrategyInput
]!
config
:
AuthenticationConfigInput
):
DefaultResponse
@
auth
(
requires
:
[
"
manage
:
system
"
])
):
DefaultResponse
@
auth
(
requires
:
[
"
manage
:
system
"
])
}
}
...
@@ -88,3 +89,9 @@ input AuthenticationStrategyInput {
...
@@ -88,3 +89,9 @@ input AuthenticationStrategyInput {
domainWhitelist
:
[
String
]!
domainWhitelist
:
[
String
]!
autoEnrollGroups
:
[
Int
]!
autoEnrollGroups
:
[
Int
]!
}
}
input
AuthenticationConfigInput
{
audience
:
String
!
tokenExpiration
:
String
!
tokenRenewal
:
String
!
}
server/master.js
View file @
75eb2774
...
@@ -67,7 +67,7 @@ module.exports = async () => {
...
@@ -67,7 +67,7 @@ module.exports = async () => {
app
.
use
(
cookieParser
())
app
.
use
(
cookieParser
())
app
.
use
(
WIKI
.
auth
.
passport
.
initialize
())
app
.
use
(
WIKI
.
auth
.
passport
.
initialize
())
app
.
use
(
mw
.
auth
.
jwt
)
app
.
use
(
WIKI
.
auth
.
authenticate
)
// ----------------------------------------
// ----------------------------------------
// SEO
// SEO
...
@@ -138,8 +138,7 @@ module.exports = async () => {
...
@@ -138,8 +138,7 @@ module.exports = async () => {
// ----------------------------------------
// ----------------------------------------
app
.
use
(
'/'
,
ctrl
.
auth
)
app
.
use
(
'/'
,
ctrl
.
auth
)
app
.
use
(
'/'
,
ctrl
.
common
)
app
.
use
(
'/'
,
mw
.
auth
.
checkPath
,
ctrl
.
common
)
// ----------------------------------------
// ----------------------------------------
// Error handling
// Error handling
...
...
server/middlewares/auth.js
deleted
100644 → 0
View file @
aa57ea92
const
jwt
=
require
(
'jsonwebtoken'
)
const
moment
=
require
(
'moment'
)
const
securityHelper
=
require
(
'../helpers/security'
)
/* global WIKI */
/**
* Authentication middleware
*/
module
.
exports
=
{
jwt
(
req
,
res
,
next
)
{
WIKI
.
auth
.
passport
.
authenticate
(
'jwt'
,
{
session
:
false
},
async
(
err
,
user
,
info
)
=>
{
if
(
err
)
{
return
next
()
}
// Expired but still valid within 7 days, just renew
if
(
info
instanceof
Error
&&
info
.
name
===
'TokenExpiredError'
&&
moment
().
subtract
(
14
,
'days'
).
isBefore
(
info
.
expiredAt
))
{
const
jwtPayload
=
jwt
.
decode
(
securityHelper
.
extractJWT
(
req
))
try
{
const
newToken
=
await
WIKI
.
models
.
users
.
refreshToken
(
jwtPayload
.
id
)
user
=
newToken
.
user
// Try headers, otherwise cookies for response
if
(
req
.
get
(
'content-type'
)
===
'application/json'
)
{
res
.
set
(
'new-jwt'
,
newToken
.
token
)
}
else
{
res
.
cookie
(
'jwt'
,
newToken
.
token
,
{
expires
:
moment
().
add
(
365
,
'days'
).
toDate
()
})
}
}
catch
(
err
)
{
return
next
()
}
}
// JWT is NOT valid
if
(
!
user
)
{
return
next
()
}
// JWT is valid
req
.
logIn
(
user
,
{
session
:
false
},
(
err
)
=>
{
if
(
err
)
{
return
next
(
err
)
}
next
()
})
})(
req
,
res
,
next
)
},
checkPath
(
req
,
res
,
next
)
{
// Is user authenticated ?
if
(
!
req
.
isAuthenticated
())
{
if
(
WIKI
.
config
.
public
!==
true
)
{
return
res
.
redirect
(
'/login'
)
}
else
{
// req.user = rights.guest
res
.
locals
.
isGuest
=
true
}
}
else
{
res
.
locals
.
isGuest
=
false
}
// Check permissions
// res.locals.rights = rights.check(req)
// if (!res.locals.rights.read) {
// return res.render('error-forbidden')
// }
// Expose user data
res
.
locals
.
user
=
req
.
user
return
next
()
}
}
server/models/users.js
View file @
75eb2774
...
@@ -138,6 +138,11 @@ module.exports = class User extends Model {
...
@@ -138,6 +138,11 @@ module.exports = class User extends Model {
return
(
result
&&
_
.
has
(
result
,
'delta'
)
&&
result
.
delta
===
0
)
return
(
result
&&
_
.
has
(
result
,
'delta'
)
&&
result
.
delta
===
0
)
}
}
async
getPermissions
()
{
const
permissions
=
await
this
.
$relatedQuery
(
'groups'
).
select
(
'permissions'
).
pluck
(
'permissions'
)
this
.
permissions
=
_
.
uniq
(
_
.
flatten
(
permissions
))
}
static
async
processProfile
(
profile
)
{
static
async
processProfile
(
profile
)
{
let
primaryEmail
=
''
let
primaryEmail
=
''
if
(
_
.
isArray
(
profile
.
emails
))
{
if
(
_
.
isArray
(
profile
.
emails
))
{
...
@@ -262,8 +267,8 @@ module.exports = class User extends Model {
...
@@ -262,8 +267,8 @@ module.exports = class User extends Model {
passphrase
:
WIKI
.
config
.
sessionSecret
passphrase
:
WIKI
.
config
.
sessionSecret
},
{
},
{
algorithm
:
'RS256'
,
algorithm
:
'RS256'
,
expiresIn
:
'30m'
,
expiresIn
:
WIKI
.
config
.
auth
.
tokenExpiration
,
audience
:
'urn:wiki.js'
,
// TODO: use value from admin
audience
:
WIKI
.
config
.
auth
.
audience
,
issuer
:
'urn:wiki.js'
issuer
:
'urn:wiki.js'
}),
}),
user
user
...
@@ -391,4 +396,10 @@ module.exports = class User extends Model {
...
@@ -391,4 +396,10 @@ module.exports = class User extends Model {
throw
new
WIKI
.
Error
.
AuthRegistrationDisabled
()
throw
new
WIKI
.
Error
.
AuthRegistrationDisabled
()
}
}
}
}
static
async
getGuestUser
()
{
let
user
=
await
WIKI
.
models
.
users
.
query
().
findById
(
2
)
user
.
getPermissions
()
return
user
}
}
}
server/setup.js
View file @
75eb2774
...
@@ -104,8 +104,12 @@ module.exports = () => {
...
@@ -104,8 +104,12 @@ module.exports = () => {
await
fs
.
ensureDir
(
path
.
join
(
dataPath
,
'uploads'
))
await
fs
.
ensureDir
(
path
.
join
(
dataPath
,
'uploads'
))
// Set config
// Set config
_
.
set
(
WIKI
.
config
,
'auth'
,
{
audience
:
'urn:wiki.js'
,
tokenExpiration
:
'30m'
,
tokenRenewal
:
'14d'
})
_
.
set
(
WIKI
.
config
,
'company'
,
''
)
_
.
set
(
WIKI
.
config
,
'company'
,
''
)
_
.
set
(
WIKI
.
config
,
'defaultEditor'
,
'markdown'
)
_
.
set
(
WIKI
.
config
,
'features'
,
{
_
.
set
(
WIKI
.
config
,
'features'
,
{
featurePageRatings
:
true
,
featurePageRatings
:
true
,
featurePageComments
:
true
,
featurePageComments
:
true
,
...
@@ -136,7 +140,6 @@ module.exports = () => {
...
@@ -136,7 +140,6 @@ module.exports = () => {
dkimKeySelector
:
''
,
dkimKeySelector
:
''
,
dkimPrivateKey
:
''
dkimPrivateKey
:
''
})
})
_
.
set
(
WIKI
.
config
,
'public'
,
false
)
_
.
set
(
WIKI
.
config
,
'seo'
,
{
_
.
set
(
WIKI
.
config
,
'seo'
,
{
description
:
''
,
description
:
''
,
robots
:
[
'index'
,
'follow'
],
robots
:
[
'index'
,
'follow'
],
...
@@ -145,7 +148,7 @@ module.exports = () => {
...
@@ -145,7 +148,7 @@ module.exports = () => {
})
})
_
.
set
(
WIKI
.
config
,
'sessionSecret'
,
(
await
crypto
.
randomBytesAsync
(
32
)).
toString
(
'hex'
))
_
.
set
(
WIKI
.
config
,
'sessionSecret'
,
(
await
crypto
.
randomBytesAsync
(
32
)).
toString
(
'hex'
))
_
.
set
(
WIKI
.
config
,
'telemetry'
,
{
_
.
set
(
WIKI
.
config
,
'telemetry'
,
{
isEnabled
:
req
.
body
.
telemetry
===
'true'
,
isEnabled
:
req
.
body
.
telemetry
===
true
,
clientId
:
WIKI
.
telemetry
.
cid
clientId
:
WIKI
.
telemetry
.
cid
})
})
_
.
set
(
WIKI
.
config
,
'theming'
,
{
_
.
set
(
WIKI
.
config
,
'theming'
,
{
...
@@ -179,16 +182,15 @@ module.exports = () => {
...
@@ -179,16 +182,15 @@ module.exports = () => {
// Save config to DB
// Save config to DB
WIKI
.
logger
.
info
(
'Persisting config to DB...'
)
WIKI
.
logger
.
info
(
'Persisting config to DB...'
)
await
WIKI
.
configSvc
.
saveToDb
([
await
WIKI
.
configSvc
.
saveToDb
([
'auth'
,
'certs'
,
'certs'
,
'company'
,
'company'
,
'defaultEditor'
,
'features'
,
'features'
,
'graphEndpoint'
,
'graphEndpoint'
,
'host'
,
'host'
,
'lang'
,
'lang'
,
'logo'
,
'logo'
,
'mail'
,
'mail'
,
'public'
,
'seo'
,
'seo'
,
'sessionSecret'
,
'sessionSecret'
,
'telemetry'
,
'telemetry'
,
...
@@ -389,8 +391,10 @@ module.exports = () => {
...
@@ -389,8 +391,10 @@ module.exports = () => {
WIKI
.
server
.
on
(
'listening'
,
()
=>
{
WIKI
.
server
.
on
(
'listening'
,
()
=>
{
WIKI
.
logger
.
info
(
'HTTP Server: [ RUNNING ]'
)
WIKI
.
logger
.
info
(
'HTTP Server: [ RUNNING ]'
)
WIKI
.
logger
.
info
(
'========================================'
)
WIKI
.
logger
.
info
(
'🔻🔻🔻🔻🔻🔻🔻🔻🔻🔻🔻🔻🔻🔻🔻🔻🔻🔻🔻🔻🔻🔻🔻🔻🔻🔻🔻🔻🔻'
)
WIKI
.
logger
.
info
(
`Browse to http://localhost:
${
WIKI
.
config
.
port
}
/`
)
WIKI
.
logger
.
info
(
''
)
WIKI
.
logger
.
info
(
'========================================'
)
WIKI
.
logger
.
info
(
`Browse to http://localhost:
${
WIKI
.
config
.
port
}
/ to complete setup!`
)
WIKI
.
logger
.
info
(
''
)
WIKI
.
logger
.
info
(
'🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺'
)
})
})
}
}
server/views/unauthorized.pug
0 → 100644
View file @
75eb2774
extends master.pug
block body
#root.is-fullscreen
v-app
.unauthorized
.unauthorized-content
img.animated.fadeIn(src='/svg/icon-delete-shield.svg', alt='Unauthorized')
.headline= t('unauthorized.title')
.subheading.mt-3= t('unauthorized.action.' + action)
v-btn.mt-5(color='red lighten-4', href='javascript:window.history.go(-1);', large, outline)
v-icon(left) arrow_back
span= t('unauthorized.goback')
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