expressa 1.0.5 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.circleci/config.yml +1 -1
- package/auth/index.js +5 -1
- package/auth/jwt.js +9 -13
- package/controllers/install.js +1 -1
- package/controllers/status.js +2 -1
- package/controllers/users.js +3 -3
- package/index.js +2 -2
- package/listeners_users.js +1 -2
- package/listeners_validation.js +4 -0
- package/middleware/{users_permissions.js → permissions.js} +4 -4
- package/modules/admin/dist/index.html +1 -1
- package/modules/admin/dist/static/css/chunk-1059.220d4af5.css +1 -0
- package/modules/admin/dist/static/css/{chunk-f116.2ff74e8a.css → chunk-418a.5ee55031.css} +1 -1
- package/modules/admin/dist/static/css/chunk-787e.1d849865.css +1 -0
- package/modules/admin/dist/static/css/chunk-d0cd.97323951.css +1 -0
- package/modules/admin/dist/static/css/{chunk-759b.3a895a1e.css → chunk-f075.3a895a1e.css} +0 -0
- package/modules/admin/dist/static/css/chunk-libs.327ad89e.css +14 -0
- package/modules/admin/dist/static/js/{app.5f6e0e4c.js → app.4c984719.js} +1 -1
- package/modules/admin/dist/static/js/chunk-1059.e6aa7b61.js +1 -0
- package/modules/admin/dist/static/js/chunk-418a.e0987b3c.js +1 -0
- package/modules/admin/dist/static/js/chunk-787e.3ee96fce.js +1 -0
- package/modules/admin/dist/static/js/chunk-8bab.7052832d.js +2 -0
- package/modules/admin/dist/static/js/{chunk-23bd.5fa24c85.js.LICENSE.txt → chunk-8bab.7052832d.js.LICENSE.txt} +1 -1
- package/modules/admin/dist/static/js/chunk-d0cd.1781b9dd.js +1 -0
- package/modules/admin/dist/static/js/chunk-f075.315ceec1.js +1 -0
- package/modules/admin/dist/static/js/chunk-libs.06c38828.js +2 -0
- package/modules/admin/dist/static/js/{chunk-libs.b6f27cfe.js.LICENSE.txt → chunk-libs.06c38828.js.LICENSE.txt} +1 -1
- package/modules/admin/package.json +3 -3
- package/modules/admin/src/components/JSONEditor.vue +181 -167
- package/modules/admin/src/main.js +2 -2
- package/modules/admin/src/router/index.js +185 -185
- package/modules/admin/src/views/ListDocuments2.vue +29 -7
- package/modules/permissions/permissions.js +9 -3
- package/package.json +1 -1
- package/util.js +2 -2
- package/modules/admin/dist/static/css/chunk-0884.40d0b632.css +0 -1
- package/modules/admin/dist/static/css/chunk-34ab.f9393b1e.css +0 -1
- package/modules/admin/dist/static/css/chunk-fb07.ac81d7d6.css +0 -1
- package/modules/admin/dist/static/css/chunk-libs.68e8d170.css +0 -14
- package/modules/admin/dist/static/js/chunk-0884.5ca2b4c5.js +0 -1
- package/modules/admin/dist/static/js/chunk-23bd.5fa24c85.js +0 -2
- package/modules/admin/dist/static/js/chunk-34ab.06400cb6.js +0 -1
- package/modules/admin/dist/static/js/chunk-759b.89a889b6.js +0 -1
- package/modules/admin/dist/static/js/chunk-f116.b616ebb3.js +0 -1
- package/modules/admin/dist/static/js/chunk-fb07.075ac852.js +0 -1
- package/modules/admin/dist/static/js/chunk-libs.b6f27cfe.js +0 -2
package/.circleci/config.yml
CHANGED
package/auth/index.js
CHANGED
|
@@ -14,7 +14,11 @@ exports.doLogin = handler.doLogin
|
|
|
14
14
|
|
|
15
15
|
exports.middleware = async function authMiddleware(req, res, next) {
|
|
16
16
|
try {
|
|
17
|
-
|
|
17
|
+
req.query = req.query || {}
|
|
18
|
+
const token = req.query['token'] || req.headers['x-access-token']
|
|
19
|
+
delete req.query['token']
|
|
20
|
+
delete req.headers['x-access-token']
|
|
21
|
+
const user = await handler.isLoggedIn(token, req.getSetting('jwt_secret'))
|
|
18
22
|
if (user) {
|
|
19
23
|
req.uid = user._id
|
|
20
24
|
req.ucollection = user.collection
|
package/auth/jwt.js
CHANGED
|
@@ -4,31 +4,27 @@ const util = require('../util')
|
|
|
4
4
|
|
|
5
5
|
// User document already validated, created, and saved to database
|
|
6
6
|
// The id of that document is given.
|
|
7
|
-
exports.doLogin = function (
|
|
8
|
-
if (!
|
|
9
|
-
throw new util.ApiError(500, 'missing jwt_secret
|
|
7
|
+
exports.doLogin = function (id, collection, jwt_secret, jwt_options = {}) {
|
|
8
|
+
if (!jwt_secret) {
|
|
9
|
+
throw new util.ApiError(500, 'missing jwt_secret')
|
|
10
10
|
}
|
|
11
11
|
const token = jwt.sign({
|
|
12
|
-
_id:
|
|
13
|
-
email: user.email,
|
|
12
|
+
_id: id,
|
|
14
13
|
collection
|
|
15
|
-
},
|
|
14
|
+
}, jwt_secret, jwt_options)
|
|
16
15
|
return {
|
|
17
16
|
token: token,
|
|
18
|
-
uid:
|
|
17
|
+
uid: id
|
|
19
18
|
}
|
|
20
19
|
}
|
|
21
20
|
|
|
22
21
|
// Returns the user id, or false if not logged in.
|
|
23
|
-
exports.isLoggedIn = async function (
|
|
24
|
-
if (!
|
|
22
|
+
exports.isLoggedIn = async function (token, jwt_secret) {
|
|
23
|
+
if (!jwt_secret) {
|
|
25
24
|
return false
|
|
26
25
|
}
|
|
27
|
-
req.query = req.query || {}
|
|
28
|
-
const token = req.query.token || req.headers['x-access-token']
|
|
29
|
-
delete req.query.token
|
|
30
26
|
if (token) {
|
|
31
|
-
return jwt.verify(token,
|
|
27
|
+
return jwt.verify(token, jwt_secret)
|
|
32
28
|
}
|
|
33
29
|
return false
|
|
34
30
|
}
|
package/controllers/install.js
CHANGED
|
@@ -13,7 +13,7 @@ exports.updateAdminPermissions = async function (api) {
|
|
|
13
13
|
// expected if not installed
|
|
14
14
|
}
|
|
15
15
|
const neededPermissions = permissions.reduce((obj, p) => { obj[p] = 1; return obj }, {})
|
|
16
|
-
|
|
16
|
+
adminRole.permissions = { ...neededPermissions, ...adminRole.permissions }
|
|
17
17
|
await api.db.role.update('Admin', adminRole)
|
|
18
18
|
}
|
|
19
19
|
|
package/controllers/status.js
CHANGED
|
@@ -29,6 +29,7 @@ exports.getStatus = function(router) {
|
|
|
29
29
|
})
|
|
30
30
|
listeners.sort((a, b) => a.priority - b.priority)
|
|
31
31
|
const collections = Object.keys(router.db)
|
|
32
|
+
.filter((collection) => req.hasPermission(`${collection}: view`) || req.hasPermission(`${collection}: view own`))
|
|
32
33
|
return {
|
|
33
34
|
nodeVersion: process.version,
|
|
34
35
|
uptime: util.friendlyDuration(process.uptime()),
|
|
@@ -39,4 +40,4 @@ exports.getStatus = function(router) {
|
|
|
39
40
|
collections,
|
|
40
41
|
}
|
|
41
42
|
}
|
|
42
|
-
}
|
|
43
|
+
}
|
package/controllers/users.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const auth = require('../auth')
|
|
2
2
|
const util = require('../util')
|
|
3
3
|
const collectionsApi = require('./collections')
|
|
4
|
-
const
|
|
4
|
+
const permissions = require('../middleware/permissions')
|
|
5
5
|
|
|
6
6
|
exports.login = async (req, collection) => {
|
|
7
7
|
const password = req.body.password
|
|
@@ -22,10 +22,10 @@ exports.login = async (req, collection) => {
|
|
|
22
22
|
throw new util.ApiError(401, 'Incorrect password')
|
|
23
23
|
}
|
|
24
24
|
const jwt_options = req.settings.jwt_expires_in ? { expiresIn: req.settings.jwt_expires_in } : {}
|
|
25
|
-
const payload = auth.doLogin(user,
|
|
25
|
+
const payload = auth.doLogin(user._id, collection, req.getSetting('jwt_secret'), jwt_options)
|
|
26
26
|
req.uid = user._id
|
|
27
27
|
req.ucollection = collection
|
|
28
|
-
await
|
|
28
|
+
await permissions.addRolePermissionsAsync(req)
|
|
29
29
|
payload.canUseAdmin = req.hasPermission('login to admin')
|
|
30
30
|
return payload
|
|
31
31
|
}
|
package/index.js
CHANGED
|
@@ -17,7 +17,7 @@ const collectionsApi = require('./controllers/collections')
|
|
|
17
17
|
const usersApi = require('./controllers/users')
|
|
18
18
|
const installApi = require('./controllers/install')
|
|
19
19
|
const statusApi = require('./controllers/status')
|
|
20
|
-
const
|
|
20
|
+
const permissions = require('./middleware/permissions')
|
|
21
21
|
const loggingMiddleware = require('./middleware/logging')
|
|
22
22
|
|
|
23
23
|
process.env.NODE_ENV = process.env.NODE_ENV || 'development'
|
|
@@ -249,7 +249,7 @@ module.exports.api = function (settings) {
|
|
|
249
249
|
}
|
|
250
250
|
|
|
251
251
|
router.use(auth.middleware) // Add user id to request
|
|
252
|
-
router.use(
|
|
252
|
+
router.use(permissions.middleware) // Add user and permissions to request
|
|
253
253
|
|
|
254
254
|
router.get('/status', ph(statusApi.getStatus(router)))
|
|
255
255
|
|
package/listeners_users.js
CHANGED
|
@@ -47,8 +47,7 @@ module.exports = async function(api) {
|
|
|
47
47
|
}
|
|
48
48
|
})
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
api.addCollectionListenerWithPriority('get', loginCollections, -100, function hidePasswordHashes(req, collection, data) {
|
|
50
|
+
api.addCollectionListenerWithPriority(['get', 'changed', 'deleted'], loginCollections, 100, function hidePasswordHashes(req, collection, data) {
|
|
52
51
|
if (!req.hasPermission(`${collection}: view hashed passwords`)) {
|
|
53
52
|
debug(`deleting password because "${collection}: view hashed passwords"-permission is not set`)
|
|
54
53
|
delete data.password
|
package/listeners_validation.js
CHANGED
|
@@ -16,6 +16,10 @@ ajv.addKeyword({
|
|
|
16
16
|
type: 'string',
|
|
17
17
|
schemaType: 'object',
|
|
18
18
|
})
|
|
19
|
+
ajv.addKeyword({
|
|
20
|
+
keyword: 'propertyOrder',
|
|
21
|
+
schemaType: 'number',
|
|
22
|
+
})
|
|
19
23
|
const formatKey = ajv.getKeyword('format')
|
|
20
24
|
formatKey.type = formatKey.type.concat(['array', 'boolean', 'object'])
|
|
21
25
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
const util = require('../util')
|
|
2
2
|
|
|
3
3
|
async function addRolePermissions (req, roles) {
|
|
4
|
-
req.
|
|
4
|
+
req.permissions = req.permissions || {}
|
|
5
5
|
const roleDocs = await Promise.all(roles.map((name) => req.db.role.get(name)))
|
|
6
6
|
roleDocs.forEach((roleDoc) => {
|
|
7
7
|
for (const permission in roleDoc.permissions) {
|
|
8
8
|
if (roleDoc.permissions[permission]) {
|
|
9
|
-
req.
|
|
9
|
+
req.permissions[permission] = true
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
})
|
|
@@ -27,7 +27,7 @@ module.exports.addRolePermissionsAsync = async function addRolePermissionsMiddle
|
|
|
27
27
|
req.hasPermission = () => true
|
|
28
28
|
return
|
|
29
29
|
}
|
|
30
|
-
req.hasPermission = (permission) => req.
|
|
30
|
+
req.hasPermission = (permission) => req.permissions && req.permissions[permission]
|
|
31
31
|
let roles = ['Anonymous']
|
|
32
32
|
const isAuthenticatedRole = await doesAuthenticatedRoleExist(req)
|
|
33
33
|
if (req.uid) {
|
|
@@ -39,7 +39,7 @@ module.exports.addRolePermissionsAsync = async function addRolePermissionsMiddle
|
|
|
39
39
|
throw new util.ApiError(404, 'User no longer exists')
|
|
40
40
|
}
|
|
41
41
|
} else {
|
|
42
|
-
req.user = {
|
|
42
|
+
req.user = {}
|
|
43
43
|
}
|
|
44
44
|
await addRolePermissions(req, roles)
|
|
45
45
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><script crossorigin src=https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react.min.js></script><script crossorigin src=https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react-dom.min.js></script><link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel=stylesheet><script src=settings.js></script><title>Expressa Admin</title><link rel=
|
|
1
|
+
<!DOCTYPE html><html><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><script crossorigin src=https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react.min.js></script><script crossorigin src=https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react-dom.min.js></script><link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel=stylesheet><script src=settings.js></script><title>Expressa Admin</title><link rel=icon href=/admin/favicon.ico><link href=/admin/static/css/chunk-elementUI.3d004d9f.css rel=stylesheet><link href=/admin/static/css/chunk-libs.327ad89e.css rel=stylesheet><link href=/admin/static/css/app.9dd57eea.css rel=stylesheet></head><body><div id=app></div><script>!function(e){function n(n){for(var r,c,a=n[0],i=n[1],f=n[2],h=0,d=[];h<a.length;h++)c=a[h],Object.prototype.hasOwnProperty.call(u,c)&&u[c]&&d.push(u[c][0]),u[c]=0;for(r in i)Object.prototype.hasOwnProperty.call(i,r)&&(e[r]=i[r]);for(l&&l(n);d.length;)d.shift()();return o.push.apply(o,f||[]),t()}function t(){for(var e,n=0;n<o.length;n++){for(var t=o[n],r=!0,c=1;c<t.length;c++){var i=t[c];0!==u[i]&&(r=!1)}r&&(o.splice(n--,1),e=a(a.s=t[0]))}return e}var r={},c={runtime:0},u={runtime:0},o=[];function a(n){if(r[n])return r[n].exports;var t=r[n]={i:n,l:!1,exports:{}};return e[n].call(t.exports,t,t.exports,a),t.l=!0,t.exports}a.e=function(e){var n=[];c[e]?n.push(c[e]):0!==c[e]&&{"chunk-1059":1,"chunk-3bc2":1,"chunk-418a":1,"chunk-5cee":1,"chunk-7291":1,"chunk-787e":1,"chunk-d0cd":1,"chunk-b423":1,"chunk-bd5f":1,"chunk-f075":1}[e]&&n.push(c[e]=new Promise((function(n,t){for(var r="static/css/"+({}[e]||e)+"."+{"chunk-1059":"220d4af5","chunk-3bc2":"89632b9d","chunk-418a":"5ee55031","chunk-5cee":"ce0e4bdb","chunk-7291":"13514e45","chunk-8bab":"31d6cfe0","chunk-787e":"1d849865","chunk-d0cd":"97323951","chunk-b423":"5f239333","chunk-bd5f":"aefa49d7","chunk-e7c3":"31d6cfe0","chunk-f075":"3a895a1e"}[e]+".css",c=a.p+r,u=document.getElementsByTagName("link"),o=0;o<u.length;o++){var i=(h=u[o]).getAttribute("data-href")||h.getAttribute("href");if("stylesheet"===h.rel&&(i===r||i===c))return n()}var f=document.getElementsByTagName("style");for(o=0;o<f.length;o++){var h;if((i=(h=f[o]).getAttribute("data-href"))===r||i===c)return n()}var l=document.createElement("link");l.rel="stylesheet",l.type="text/css",l.onload=n,l.onerror=function(n){var r=n&&n.target&&n.target.src||c,u=new Error("Loading CSS chunk "+e+" failed.\n("+r+")");u.request=r,t(u)},l.href=c,document.getElementsByTagName("head")[0].appendChild(l)})).then((function(){c[e]=0})));var t=u[e];if(0!==t)if(t)n.push(t[2]);else{var r=new Promise((function(n,r){t=u[e]=[n,r]}));n.push(t[2]=r);var o,i=document.createElement("script");i.charset="utf-8",i.timeout=120,a.nc&&i.setAttribute("nonce",a.nc),i.src=function(e){return a.p+"static/js/"+({}[e]||e)+"."+{"chunk-1059":"e6aa7b61","chunk-3bc2":"028748b7","chunk-418a":"e0987b3c","chunk-5cee":"a3b03f7a","chunk-7291":"590524e9","chunk-8bab":"7052832d","chunk-787e":"3ee96fce","chunk-d0cd":"1781b9dd","chunk-b423":"387c504c","chunk-bd5f":"e9509f10","chunk-e7c3":"e5df8ceb","chunk-f075":"315ceec1"}[e]+".js"}(e);var f=new Error;o=function(n){i.onerror=i.onload=null,clearTimeout(h);var t=u[e];if(0!==t){if(t){var r=n&&("load"===n.type?"missing":n.type),c=n&&n.target&&n.target.src;f.message="Loading chunk "+e+" failed.\n("+r+": "+c+")",f.name="ChunkLoadError",f.type=r,f.request=c,t[1](f)}u[e]=void 0}};var h=setTimeout((function(){o({type:"timeout",target:i})}),12e4);i.onerror=i.onload=o,document.head.appendChild(i)}return Promise.all(n)},a.m=e,a.c=r,a.d=function(e,n,t){a.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:t})},a.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,n){if(1&n&&(e=a(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(a.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var r in e)a.d(t,r,function(n){return e[n]}.bind(null,r));return t},a.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(n,"a",n),n},a.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},a.p="/admin/",a.oe=function(e){throw console.error(e),e};var i=window.webpackJsonp=window.webpackJsonp||[],f=i.push.bind(i);i.push=n,i=i.slice();for(var h=0;h<i.length;h++)n(i[h]);var l=f;t()}([]);</script><script src=/admin/static/js/chunk-elementUI.b0c99c08.js></script><script src=/admin/static/js/chunk-libs.06c38828.js></script><script src=/admin/static/js/app.4c984719.js></script></body></html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.el-table[data-v-1453a01e] th{background-color:#343a40!important;border-color:#454d55;color:#fff}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
.el-table[data-v-
|
|
1
|
+
.el-table[data-v-1453a01e] th{background-color:#343a40!important;border-color:#454d55;color:#fff}.dashboard-container[data-v-5d163182]{margin:30px}.dashboard-text[data-v-5d163182]{font-size:30px;line-height:46px}a#settings-link[data-v-5d163182]{color:#35a;padding-left:25px}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.expandable-textarea{display:block;min-height:250px;min-width:250px;resize:both!important}.jsoneditor-vue img{border:1px solid #ddd;border-radius:4px;padding:5px;width:150px}.jsoneditor-vue img:hover{-webkit-box-shadow:0 0 2px 1px rgba(0,140,186,.5);box-shadow:0 0 2px 1px rgba(0,140,186,.5)}.jsoneditor-vue button.btn{font-size:14px!important;padding:3px}.jsoneditor-vue .form-control-label,label{font-weight:700}.jsoneditor-vue input[type=checkbox]{margin-right:5px;margin-top:3px}.comment-link{margin-top:-15px}.error-message{color:red}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.expandable-textarea{display:block;min-height:250px;min-width:250px;resize:both!important}.jsoneditor-vue img{border:1px solid #ddd;border-radius:4px;padding:5px;width:150px}.jsoneditor-vue img:hover{-webkit-box-shadow:0 0 2px 1px rgba(0,140,186,.5);box-shadow:0 0 2px 1px rgba(0,140,186,.5)}.jsoneditor-vue button.btn{font-size:14px!important;padding:3px}.jsoneditor-vue .form-control-label,label{font-weight:700}.jsoneditor-vue input[type=checkbox]{margin-right:5px;margin-top:3px}.error-message[data-v-3c5b79e9]{color:red}
|
|
File without changes
|