Skip to content

Commit

Permalink
feat(routes): GET /accounts
Browse files Browse the repository at this point in the history
  • Loading branch information
gr2m committed Nov 26, 2015
1 parent 89f1838 commit 8ff8a09
Show file tree
Hide file tree
Showing 16 changed files with 219 additions and 13 deletions.
3 changes: 1 addition & 2 deletions api/accounts/add.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ var createAccount = require('../../utils/account/create')

function addAccount (state, options) {
return new Promise(function (resolve, reject) {
createAccount({
couchUrl: state.url,
createAccount(state, {
username: options.username,
password: options.password,
includeProfile: options.include === 'account.profile'
Expand Down
31 changes: 31 additions & 0 deletions api/accounts/find-all.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
module.exports = findAccount

var findIdInRoles = require('../../utils/find-id-in-roles')
var getAllAccounts = require('../../utils/account/get-all')

function findAccount (state, options) {
return new Promise(function (resolve, reject) {
getAllAccounts({
couchUrl: state.url
}, function (error, response) {
if (error) {
return reject(error)
}

resolve(response.rows.map(toAccount.bind(null, options)))
})
})
}

function toAccount (options, row) {
var account = {
username: row.doc.name,
id: findIdInRoles(row.doc.roles)
}

if (options.include === 'profile') {
account.profile = row.doc.profile
}

return account
}
7 changes: 6 additions & 1 deletion api/accounts/find.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ function findAccount (state, username, options) {
getAccount({
couchUrl: state.url,
username: username,
includeProfile: options.include === 'profile'
bearerToken: options.bearerToken
}, function (error, doc) {
if (error) {
return reject(error)
Expand All @@ -18,6 +18,11 @@ function findAccount (state, username, options) {
username: doc.name,
id: findIdInRoles(doc.roles)
}

if (options.include === 'profile') {
account.profile = account.profile
}

resolve(account)
})
})
Expand Down
2 changes: 2 additions & 0 deletions api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ var removeSession = require('./sessions/remove')

var addAccount = require('./accounts/add')
var findAccount = require('./accounts/find')
var findAllAccounts = require('./accounts/find-all')
var removeAccount = require('./accounts/remove')

function accountApi (options) {
Expand All @@ -22,6 +23,7 @@ function accountApi (options) {
accounts: {
add: addAccount.bind(null, state),
find: findAccount.bind(null, state),
findAll: findAllAccounts.bind(null, state),
remove: removeAccount.bind(null, state)
}
}
Expand Down
3 changes: 2 additions & 1 deletion plugin/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ hapiAccount.attributes = {

var routePlugins = [
require('../routes/session'),
require('../routes/account')
require('../routes/account'),
require('../routes/accounts')
]

function hapiAccount (server, options, next) {
Expand Down
15 changes: 14 additions & 1 deletion routes/account.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ module.exports.attributes = {
name: 'account-routes-account'
}

var Boom = require('boom')

var getApi = require('../api')
var joiFailAction = require('../utils/joi-fail-action')
var serialiseAccount = require('../utils/account/serialise')
Expand All @@ -12,7 +14,7 @@ var validations = require('../utils/validations')
function accountRoutes (server, options, next) {
var couchUrl = options.couchdb.url
var prefix = options.prefix || ''
var api = getApi({ url: couchUrl })
var api = getApi({ url: couchUrl, admin: options.admin })
var sessions = api.sessions
var accounts = api.accounts
var serialise = serialiseAccount.bind(null, {
Expand All @@ -23,6 +25,7 @@ function accountRoutes (server, options, next) {
method: 'PUT',
path: prefix + '/session/account',
config: {
auth: false,
validate: {
headers: validations.bearerTokenHeaderForbidden,
query: validations.accountQuery,
Expand Down Expand Up @@ -53,6 +56,9 @@ function accountRoutes (server, options, next) {
var getAccountRoute = {
method: 'GET',
path: prefix + '/session/account',
config: {
auth: false
},
handler: function (request, reply) {
var sessionId = toBearerToken(request)

Expand All @@ -61,6 +67,10 @@ function accountRoutes (server, options, next) {
})

.then(function (session) {
if (session.account.isAdmin) {
throw Boom.forbidden('Admin users have no account')
}

return accounts.find(session.account.username, {
bearerToken: sessionId,
include: request.query.include
Expand All @@ -78,6 +88,9 @@ function accountRoutes (server, options, next) {
var destroyAccountRoute = {
method: 'DELETE',
path: prefix + '/session/account',
config: {
auth: false
},
handler: function (request, reply) {
var sessionId = toBearerToken(request)

Expand Down
54 changes: 54 additions & 0 deletions routes/accounts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
module.exports = accountRoutes
module.exports.attributes = {
name: 'account-routes-accounts'
}

var getApi = require('../api')
var joiFailAction = require('../utils/joi-fail-action')
var serialiseAccount = require('../utils/account/serialise')
var toBearerToken = require('../utils/to-bearer-token')
var validations = require('../utils/validations')

function accountRoutes (server, options, next) {
var couchUrl = options.couchdb.url
var prefix = options.prefix || ''
var api = getApi({ url: couchUrl })
var accounts = api.accounts
var serialise = serialiseAccount.bind(null, {
baseUrl: server.info.uri + prefix
})

var getAccountsRoute = {
method: 'GET',
path: prefix + '/accounts',
config: {
auth: false,
validate: {
headers: validations.bearerTokenHeader,
failAction: joiFailAction
}
},
handler: function (request, reply) {
var sessionId = toBearerToken(request)

return accounts.findAll({
bearerToken: sessionId,
include: request.query.include
})

.then(function (accounts) {
return accounts.map(serialise)
})

.then(reply)

.catch(reply)
}
}

server.route([
getAccountsRoute
])

next()
}
5 changes: 4 additions & 1 deletion routes/session.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ var validations = require('../utils/validations')
function sessionRoutes (server, options, next) {
var couchUrl = options.couchdb.url
var prefix = options.prefix || ''
var sessions = getApi({ url: couchUrl }).sessions
var sessions = getApi({ url: couchUrl, admin: options.admin }).sessions
var serialise = serialiseSession.bind(null, {
baseUrl: server.info.uri + prefix
})
Expand All @@ -21,6 +21,7 @@ function sessionRoutes (server, options, next) {
method: 'PUT',
path: prefix + '/session',
config: {
auth: false,
validate: {
headers: validations.bearerTokenHeaderForbidden,
query: validations.sessionQuery,
Expand Down Expand Up @@ -52,6 +53,7 @@ function sessionRoutes (server, options, next) {
method: 'GET',
path: prefix + '/session',
config: {
auth: false,
validate: {
headers: validations.bearerTokenHeader,
query: validations.sessionQuery,
Expand All @@ -77,6 +79,7 @@ function sessionRoutes (server, options, next) {
method: 'DELETE',
path: prefix + '/session',
config: {
auth: false,
validate: {
headers: validations.bearerTokenHeader,
query: validations.sessionQuery,
Expand Down
16 changes: 12 additions & 4 deletions utils/account/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ module.exports = createAccount
var Boom = require('boom')
var randomstring = require('randomstring')

function createAccount (options, callback) {
function createAccount (state, options, callback) {
var request = require('request').defaults({
json: true,
baseUrl: options.couchUrl,
baseUrl: state.url,
timeout: 10000 // 10 seconds
})

Expand All @@ -16,7 +16,7 @@ function createAccount (options, callback) {
charset: 'hex'
})

request.put({
var requestOptions = {
url: '/_users/' + accountKey,
body: {
type: 'user',
Expand All @@ -26,7 +26,15 @@ function createAccount (options, callback) {
name: options.username,
password: options.password
}
}, function (error, response, body) {
}

if (state.admin) {
requestOptions.auth = {
user: state.admin.username,
pass: state.admin.password
}
}
request.put(requestOptions, function (error, response, body) {
if (error) {
return callback(Boom.wrap(error))
}
Expand Down
35 changes: 35 additions & 0 deletions utils/account/get-all.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
module.exports = getAllAccounts

var Boom = require('boom')

function getAllAccounts (options, callback) {
var request = require('request').defaults({
json: true,
baseUrl: options.couchUrl,
timeout: 10000 // 10 seconds
})

request.get({
url: '/_users/_all_docs?startkey=%22org.couchdb.user%3A%22&enkey=%22org.couchdb.user%3A%E9%A6%99%22',
headers: {
cookie: 'AuthSession=' + options.bearerToken
}
}, function (error, response, body) {
if (error) {
return callback(Boom.wrap(error))
}

if (response.statusCode >= 400) {
return callback(Boom.create(response.statusCode, fixErrorMessage(body.reason)))
}
callback(null, body)
})
}

function fixErrorMessage (message) {
if (message === 'Only admins can access _all_docs of system databases.') {
return 'Only admins can access /users'
}

return message
}
17 changes: 17 additions & 0 deletions utils/find-custom-roles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module.exports = findCustomRoles

function findCustomRoles (roles) {
return roles.filter(isntInteralRole)
}

function isntInteralRole (role) {
if (role === '_admin') {
return false
}

if (role.substr(0, 3) === 'id:') {
return false
}

return true
}
5 changes: 5 additions & 0 deletions utils/has-admin-role.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = hasAdminRole

function hasAdminRole (roles) {
return roles.indexOf('_admin') !== -1
}
11 changes: 10 additions & 1 deletion utils/session/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ module.exports = createSession

var Boom = require('boom')

var findcustomRoles = require('../find-custom-roles')
var findIdInRoles = require('../find-id-in-roles')
var getAccount = require('../account/get')
var hasAdminRole = require('../has-admin-role')

function createSession (options, callback) {
var request = require('request').defaults({
Expand Down Expand Up @@ -36,14 +38,21 @@ function createSession (options, callback) {
bearerToken = bearerToken.pop()

var accountId = findIdInRoles(body.roles)
var isAdmin = hasAdminRole(body.roles)
var session = {
id: bearerToken,
account: {
id: accountId,
username: options.username
username: options.username,
isAdmin: isAdmin,
roles: findcustomRoles(body.roles)
}
}

if (isAdmin && options.includeProfile) {
return callback(Boom.forbidden('Admin accounts have no profile'))
}

if (!options.includeProfile) {
return callback(null, session)
}
Expand Down
Loading

0 comments on commit 8ff8a09

Please sign in to comment.