diff --git a/package-lock.json b/package-lock.json
index 96825ba..aefe5e1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -408,10 +408,12 @@
"dev": true
},
"basic-auth": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz",
- "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=",
- "optional": true
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.0.tgz",
+ "integrity": "sha1-AV2z81PgLlY3d1X5YnQuiYHnu7o=",
+ "requires": {
+ "safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz"
+ }
},
"bcrypt-pbkdf": {
"version": "1.0.1",
@@ -3256,16 +3258,30 @@
}
},
"morgan": {
- "version": "1.8.2",
- "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.8.2.tgz",
- "integrity": "sha1-eErHc05KRTqcbm6GgKkyknXItoc=",
- "optional": true,
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.0.tgz",
+ "integrity": "sha1-0B+mxlhZt2/PMbPLU6OCGjEdgFE=",
"requires": {
- "basic-auth": "1.1.0",
- "debug": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
- "depd": "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz",
+ "basic-auth": "2.0.0",
+ "debug": "2.6.9",
+ "depd": "1.1.1",
"on-finished": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
"on-headers": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz"
+ }
+ },
+ "depd": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz",
+ "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k="
+ }
}
},
"ms": {
@@ -3460,7 +3476,7 @@
"body-parser": "https://registry.npmjs.org/body-parser/-/body-parser-1.17.2.tgz",
"express": "https://registry.npmjs.org/express/-/express-4.15.3.tgz",
"express-session": "https://registry.npmjs.org/express-session/-/express-session-1.15.3.tgz",
- "morgan": "1.8.2"
+ "morgan": "1.9.0"
}
},
"oauth-sign": {
@@ -4765,10 +4781,6 @@
}
}
},
- "string_decoder": {
- "version": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
- "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
- },
"string-width": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
@@ -4780,6 +4792,10 @@
"strip-ansi": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz"
}
},
+ "string_decoder": {
+ "version": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
+ },
"stringstream": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
diff --git a/package.json b/package.json
index 0d8d4a5..6aae3eb 100644
--- a/package.json
+++ b/package.json
@@ -60,6 +60,7 @@
"concurrently": "^3.5.0",
"eslint-plugin-import": "^2.7.0",
"jquery": "^3.2.1",
+ "morgan": "^1.9.0",
"mustache": "^2.3.0",
"standard": "^10.0.3",
"uglifyjs-webpack-plugin": "^0.4.6",
diff --git a/scripts/logger.js b/scripts/logger.js
index d192aa3..516d645 100644
--- a/scripts/logger.js
+++ b/scripts/logger.js
@@ -29,6 +29,8 @@ function stampAndWrite (fnc, prfx, message) {
lfs.write(message + '\n')
}
+ message = message.replace(/\\u001b/g, '\x1b')
+
fnc.call(this, message)
}
diff --git a/server/api/admin.js b/server/api/admin.js
index 47c2b00..7f56c1c 100644
--- a/server/api/admin.js
+++ b/server/api/admin.js
@@ -62,11 +62,28 @@ async function cleanBanObject (dbe) {
}
}
+function dataFilter (data, fields, optional = []) {
+ // Remove keys not listed in `fields`
+ for (let i in data) {
+ if (fields.indexOf(i) === -1) {
+ delete data[i]
+ }
+ }
+
+ // Ensure all the entries in `fields` are present as keys in `data` or are `optional`
+ for (let j in fields) {
+ if (!data[fields[j]] && optional.indexOf(fields[j]) === -1) return null
+ }
+
+ return data
+}
+
const API = {
+ // List all users (paginated)
getAllUsers: async function (page, adminId) {
let count = await Models.User.query().count('id as ids')
if (!count.length || !count[0]['ids'] || isNaN(page)) {
- return {error: 'No users found'}
+ return { error: 'No users found' }
}
count = count[0].ids
@@ -86,10 +103,11 @@ const API = {
users: users
}
},
+ // List all clients (paginated)
getAllClients: async function (page) {
let count = await Models.OAuth2Client.query().count('id as ids')
if (!count.length || !count[0]['ids'] || isNaN(page)) {
- return {error: 'No clients found'}
+ return { error: 'No clients found' }
}
count = count[0].ids
@@ -108,62 +126,54 @@ const API = {
clients: clients
}
},
+ // Get information about a client via id
getClient: async function (id) {
let raw = await Models.OAuth2Client.query().where('id', id)
if (!raw.length) return null
return cleanClientObject(raw[0])
},
+ // Update a client `id` in database with `data`
updateClient: async function (id, data) {
let fields = [
- 'title', 'description', 'url', 'redirect_url', 'scope'
+ 'title', 'description', 'url', 'redirect_url', 'scope', 'verified'
]
- for (let i in data) {
- if (fields.indexOf(i) === -1) {
- delete data[i]
- }
- }
+ data = dataFilter(data, fields, ['scope', 'verified'])
+ if (!data) return { error: 'Missing fields' }
- for (let i in fields) {
- if (!data[fields[i]] && fields[i] !== 'scope') return {error: 'Missing fields'}
- }
+ data.verified = (data.verified != null ? 1 : 0)
try {
await Models.OAuth2Client.query().patchAndFetchById(id, data)
await Models.OAuth2AuthorizedClient.query().delete().where('client_id', id)
} catch (e) {
- return {error: 'No such client'}
+ return { error: 'No such client' }
}
return {}
},
+ // Create a new secret for a client
newSecret: async function (id) {
- if (isNaN(id)) return {error: 'Invalid client ID'}
+ if (isNaN(id)) return { error: 'Invalid client ID' }
let secret = Users.Hash(16)
try {
await Models.OAuth2Client.query().patchAndFetchById(id, {secret: secret})
} catch (e) {
- return {error: 'No such client'}
+ return { error: 'No such client' }
}
return {}
},
+ // Create a new client
createClient: async function (data, user) {
let fields = [
'title', 'description', 'url', 'redirect_url', 'scope'
]
- for (let i in data) {
- if (fields.indexOf(i) === -1) {
- delete data[i]
- }
- }
-
- for (let i in fields) {
- if (!data[fields[i]] && fields[i] !== 'scope') return {error: 'Missing fields'}
- }
+ data = dataFilter(data, fields, ['scope'])
+ if (!data) return { error: 'Missing fields' }
let obj = Object.assign({
secret: Users.Hash(16),
@@ -174,6 +184,7 @@ const API = {
return Models.OAuth2Client.query().insert(obj)
},
+ // Remove a client and all associated data
removeClient: async function (id) {
if (isNaN(id)) return {error: 'Invalid ID number'}
await Models.OAuth2Client.query().delete().where('id', id)
@@ -182,6 +193,7 @@ const API = {
await Models.OAuth2RefreshToken.query().delete().where('client_id', id)
return true
},
+ // List all bans (paginated)
getAllBans: async function (page) {
let count = await Models.Ban.query().count('id as ids')
if (!count.length || !count[0]['ids'] || isNaN(page)) {
@@ -204,9 +216,11 @@ const API = {
bans: bans
}
},
+ // Remove a ban
removeBan: async function (banId) {
return Models.Ban.query().delete().where('id', banId)
},
+ // Create a ban
addBan: async function (data, adminId) {
let user = await Users.User.get(parseInt(data.user_id))
diff --git a/server/server.js b/server/server.js
index 440311b..215ffcd 100644
--- a/server/server.js
+++ b/server/server.js
@@ -67,7 +67,14 @@ module.exports = (args) => {
app.set('view engine', 'pug')
app.set('views', path.join(__dirname, '../views'))
- if (args.dev) console.log('Worker is in development mode')
+ if (args.dev) {
+ console.log('Worker is in development mode')
+
+ // Dev logger
+ const morgan = require('morgan')
+ app.use(morgan('dev'))
+ }
+
let staticAge = args.dev ? 1000 : 7 * 24 * 60 * 60 * 1000 // 1 week of cache in production
// Static content directories, cache these requests.
diff --git a/views/admin/oauth2.pug b/views/admin/oauth2.pug
index 91f30fb..738594c 100644
--- a/views/admin/oauth2.pug
+++ b/views/admin/oauth2.pug
@@ -52,6 +52,8 @@ block body
+
+
script(type="x-tmpl-mustache" id="clientNew").