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
e3193550
Commit
e3193550
authored
Aug 30, 2020
by
NGPixel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: enable/disable TFA per user
parent
32d67ade
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
144 additions
and
33 deletions
+144
-33
admin-theme.vue
client/components/admin/admin-theme.vue
+26
-26
admin-users-edit.vue
client/components/admin/admin-users-edit.vue
+79
-3
auth.js
server/controllers/auth.js
+1
-1
user.js
server/graph/resolvers/user.js
+28
-2
user.graphql
server/graph/schemas/user.graphql
+9
-0
users.js
server/models/users.js
+1
-1
No files found.
client/components/admin/admin-theme.vue
View file @
e3193550
...
...
@@ -70,33 +70,33 @@
)
v-flex(lg6 xs12)
v-card.animated.fadeInUp.wait-p2s
v-toolbar(color='teal', dark, dense, flat)
v-toolbar-title.subtitle-1
{{
$t
(
'admin:theme.downloadThemes'
)
}}
v-spacer
v-chip(label, color='white', small).teal--text coming soon
v-data-table(
:headers='headers',
:items='themes',
hide-default-footer,
item-key='value',
:items-per-page='1000'
)
template(v-slot:item='thm')
td
strong
{{
thm
.
item
.
text
}}
td
span
{{
thm
.
item
.
author
}}
td.text-xs-center
v-progress-circular(v-if='thm.item.isDownloading', indeterminate, color='blue', size='20', :width='2')
v-btn(v-else-if='thm.item.isInstalled && thm.item.installDate < thm.item.updatedAt', icon)
v-icon.blue--text mdi-cached
v-btn(v-else-if='thm.item.isInstalled', icon)
v-icon.green--text mdi-check-bold
v-btn(v-else, icon)
v-icon.grey--text mdi-cloud-download
//-
v-card.animated.fadeInUp.wait-p2s
//-
v-toolbar(color='teal', dark, dense, flat)
//-
v-toolbar-title.subtitle-1
{{
$t
(
'admin:theme.downloadThemes'
)
}}
//-
v-spacer
//-
v-chip(label, color='white', small).teal--text coming soon
//-
v-data-table(
//-
:headers='headers',
//-
:items='themes',
//-
hide-default-footer,
//-
item-key='value',
//-
:items-per-page='1000'
//-
)
//-
template(v-slot:item='thm')
//-
td
//-
strong
{{
thm
.
item
.
text
}}
//-
td
//-
span
{{
thm
.
item
.
author
}}
//-
td.text-xs-center
//-
v-progress-circular(v-if='thm.item.isDownloading', indeterminate, color='blue', size='20', :width='2')
//-
v-btn(v-else-if='thm.item.isInstalled && thm.item.installDate < thm.item.updatedAt', icon)
//-
v-icon.blue--text mdi-cached
//-
v-btn(v-else-if='thm.item.isInstalled', icon)
//-
v-icon.green--text mdi-check-bold
//-
v-btn(v-else, icon)
//-
v-icon.grey--text mdi-cloud-download
v-card.
mt-3.
animated.fadeInUp.wait-p2s
v-card.animated.fadeInUp.wait-p2s
v-toolbar(color='primary', dark, dense, flat)
v-toolbar-title.subtitle-1
{{
$t
(
`admin:theme.codeInjection`
)
}}
v-card-text
...
...
client/components/admin/admin-users-edit.vue
View file @
e3193550
...
...
@@ -126,8 +126,6 @@
v-list-item-content
v-list-item-title
{{
$t
(
'admin:users.authProvider'
)
}}
v-list-item-subtitle
{{
user
.
providerName
}}
#[em.caption (
{{
user
.
providerKey
}}
)]
//- v-list-item-action
//- v-img(src='https://static.requarks.io/logo/wikijs.svg', alt='', contain, max-height='32', position='center right')
template(v-if='user.providerKey === `local`')
v-divider
v-list-item
...
...
@@ -168,6 +166,7 @@
v-btn(icon, color='grey', x-small, v-on='on', disabled)
v-icon mdi-email
span Send Password Reset Email
template(v-if='user.providerIs2FACapable')
v-divider
v-list-item
v-list-item-avatar(size='32')
...
...
@@ -179,7 +178,7 @@
v-list-item-action
v-tooltip(top)
template(v-slot:activator='{ on }')
v-btn(icon, color='grey', x-small, v-on='on',
disabled
)
v-btn(icon, color='grey', x-small, v-on='on',
@click='toggle2FA'
)
v-icon mdi-power
span
{{
$t
(
'admin:users.toggle2FA'
)
}}
template(v-if='user.providerId')
...
...
@@ -941,6 +940,82 @@ export default {
})
}
this
.
$store
.
commit
(
`loadingStop`
,
'admin-users-verify'
)
},
/**
* Toggle 2FA State
*/
async
toggle2FA
()
{
this
.
$store
.
commit
(
`loadingStart`
,
'admin-users-toggle2fa'
)
if
(
this
.
user
.
tfaIsActive
)
{
const
resp
=
await
this
.
$apollo
.
mutate
({
mutation
:
gql
`
mutation ($id: Int!) {
users {
disableTFA(id: $id) {
responseResult {
succeeded
errorCode
slug
message
}
}
}
}
`
,
variables
:
{
id
:
this
.
user
.
id
}
})
if
(
_
.
get
(
resp
,
'data.users.disableTFA.responseResult.succeeded'
,
false
))
{
this
.
$store
.
commit
(
'showNotification'
,
{
style
:
'success'
,
message
:
this
.
$t
(
'admin:users.userTFADisableSuccess'
),
icon
:
'check'
})
this
.
user
.
tfaIsActive
=
false
}
else
{
this
.
$store
.
commit
(
'showNotification'
,
{
style
:
'red'
,
message
:
_
.
get
(
resp
,
'data.users.disableTFA.responseResult.message'
,
'An unexpected error occurred.'
),
icon
:
'warning'
})
}
}
else
{
const
resp
=
await
this
.
$apollo
.
mutate
({
mutation
:
gql
`
mutation ($id: Int!) {
users {
enableTFA(id: $id) {
responseResult {
succeeded
errorCode
slug
message
}
}
}
}
`
,
variables
:
{
id
:
this
.
user
.
id
}
})
if
(
_
.
get
(
resp
,
'data.users.enableTFA.responseResult.succeeded'
,
false
))
{
this
.
$store
.
commit
(
'showNotification'
,
{
style
:
'success'
,
message
:
this
.
$t
(
'admin:users.userTFAEnableSuccess'
),
icon
:
'check'
})
this
.
user
.
tfaIsActive
=
true
}
else
{
this
.
$store
.
commit
(
'showNotification'
,
{
style
:
'red'
,
message
:
_
.
get
(
resp
,
'data.users.enableTFA.responseResult.message'
,
'An unexpected error occurred.'
),
icon
:
'warning'
})
}
}
this
.
$store
.
commit
(
`loadingStop`
,
'admin-users-toggle2fa'
)
}
},
apollo
:
{
...
...
@@ -955,6 +1030,7 @@ export default {
providerKey
providerName
providerId
providerIs2FACapable
location
jobTitle
timezone
...
...
server/controllers/auth.js
View file @
e3193550
...
...
@@ -71,7 +71,7 @@ router.all('/login/:strategy/callback', async (req, res, next) => {
strategy
:
req
.
params
.
strategy
},
{
req
,
res
})
res
.
cookie
(
'jwt'
,
authResult
.
jwt
,
{
expires
:
moment
().
add
(
1
,
'y'
).
toDate
()
})
res
.
redirect
(
'/'
)
res
.
redirect
(
authResult
.
redirect
)
}
catch
(
err
)
{
next
(
err
)
}
...
...
server/graph/resolvers/user.js
View file @
e3193550
...
...
@@ -23,11 +23,15 @@ module.exports = {
.
select
(
'id'
,
'email'
,
'name'
,
'providerKey'
,
'createdAt'
)
},
async
single
(
obj
,
args
,
context
,
info
)
{
console
.
info
(
WIKI
.
auth
.
strategies
)
let
usr
=
await
WIKI
.
models
.
users
.
query
().
findById
(
args
.
id
)
usr
.
password
=
''
usr
.
tfaSecret
=
''
usr
.
providerName
=
_
.
get
(
WIKI
.
auth
.
strategies
,
usr
.
providerKey
).
displayName
const
str
=
_
.
get
(
WIKI
.
auth
.
strategies
,
usr
.
providerKey
)
str
.
strategy
=
_
.
find
(
WIKI
.
data
.
authentication
,
[
'key'
,
str
.
strategyKey
])
usr
.
providerName
=
str
.
displayName
usr
.
providerIs2FACapable
=
_
.
get
(
str
,
'strategy.useForm'
,
false
)
return
usr
},
async
profile
(
obj
,
args
,
context
,
info
)
{
...
...
@@ -140,6 +144,28 @@ module.exports = {
return
graphHelper
.
generateError
(
err
)
}
},
async
enableTFA
(
obj
,
args
)
{
try
{
await
WIKI
.
models
.
users
.
query
().
patch
({
tfaIsActive
:
true
,
tfaSecret
:
null
}).
findById
(
args
.
id
)
return
{
responseResult
:
graphHelper
.
generateSuccess
(
'User 2FA enabled successfully'
)
}
}
catch
(
err
)
{
return
graphHelper
.
generateError
(
err
)
}
},
async
disableTFA
(
obj
,
args
)
{
try
{
await
WIKI
.
models
.
users
.
query
().
patch
({
tfaIsActive
:
false
,
tfaSecret
:
null
}).
findById
(
args
.
id
)
return
{
responseResult
:
graphHelper
.
generateSuccess
(
'User 2FA disabled successfully'
)
}
}
catch
(
err
)
{
return
graphHelper
.
generateError
(
err
)
}
},
resetPassword
(
obj
,
args
)
{
return
false
},
...
...
server/graph/schemas/user.graphql
View file @
e3193550
...
...
@@ -78,6 +78,14 @@ type UserMutation {
id
:
Int
!
):
DefaultResponse
@
auth
(
requires
:
[
"
manage
:
users
"
,
"
manage
:
system
"
])
enableTFA
(
id
:
Int
!
):
DefaultResponse
@
auth
(
requires
:
[
"
manage
:
users
"
,
"
manage
:
system
"
])
disableTFA
(
id
:
Int
!
):
DefaultResponse
@
auth
(
requires
:
[
"
manage
:
users
"
,
"
manage
:
system
"
])
resetPassword
(
id
:
Int
!
):
DefaultResponse
...
...
@@ -130,6 +138,7 @@ type User {
providerKey
:
String
!
providerName
:
String
providerId
:
String
providerIs2FACapable
:
Boolean
isSystem
:
Boolean
!
isActive
:
Boolean
!
isVerified
:
Boolean
!
...
...
server/models/users.js
View file @
e3193550
...
...
@@ -28,7 +28,7 @@ module.exports = class User extends Model {
providerId
:
{
type
:
'string'
},
password
:
{
type
:
'string'
},
tfaIsActive
:
{
type
:
'boolean'
,
default
:
false
},
tfaSecret
:
{
type
:
'string'
},
tfaSecret
:
{
type
:
[
'string'
,
null
]
},
jobTitle
:
{
type
:
'string'
},
location
:
{
type
:
'string'
},
pictureUrl
:
{
type
:
'string'
},
...
...
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