Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Review _user API mod #1264

Merged
merged 38 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
b9d30e3
Review _user API mod
dbauszus-glx May 20, 2024
5df0ef7
Merge branch 'main' into user-api-evaluation
dbauszus-glx Jun 4, 2024
7c24cdf
user api mod docs
dbauszus-glx Jun 4, 2024
ca6efed
mod/user docs
dbauszus-glx Jun 4, 2024
5ea6eca
reqHost docs
dbauszus-glx Jun 5, 2024
5b63758
user acl and add docs
dbauszus-glx Jun 5, 2024
9239087
session and token check for auth.
dbauszus-glx Jun 5, 2024
a95271e
enable check session
dbauszus-glx Jun 5, 2024
d5139db
res object for auth method
dbauszus-glx Jun 5, 2024
336ff7b
checkToken docs
dbauszus-glx Jun 5, 2024
3aebbfd
use asyncJWT for auth module.
dbauszus-glx Jun 6, 2024
77a6211
update async verify method
dbauszus-glx Jun 6, 2024
4deed07
reduce cognitive load on auth function
dbauszus-glx Jun 6, 2024
aa0ae16
name api method
dbauszus-glx Jun 6, 2024
868ab68
Update checkToken condition; access log
dbauszus-glx Jun 7, 2024
4eefb5d
user list docs
dbauszus-glx Jun 7, 2024
b7d870b
update user/api description
dbauszus-glx Jun 7, 2024
c0cc1be
update token description
dbauszus-glx Jun 7, 2024
af78376
optional chaining for rows.length
dbauszus-glx Jun 7, 2024
fed3f4d
user/update description
dbauszus-glx Jun 7, 2024
b1dd37f
register module review
dbauszus-glx Jun 7, 2024
1daa6dc
describe register module
dbauszus-glx Jun 7, 2024
23ff9f1
make rows in user registry const
dbauszus-glx Jun 7, 2024
78503c6
update fromACL docs
dbauszus-glx Jun 12, 2024
f7e798b
saml docs
dbauszus-glx Jun 12, 2024
1a94ec0
replace match with regex exec
dbauszus-glx Jun 12, 2024
6b838e4
login user api docs
dbauszus-glx Jun 12, 2024
8be8949
redirect documentation
dbauszus-glx Jun 12, 2024
1e3d2ea
Merge branch 'main' into user-api-evaluation
dbauszus-glx Jun 19, 2024
40cb8ee
Update Signer and Provider Authentication
RobAndrewHurst Jun 19, 2024
b172712
Revert "Update Signer and Provider Authentication"
RobAndrewHurst Jun 19, 2024
4f85a33
Merge branch 'main' into user-api-evaluation
dbauszus-glx Jun 20, 2024
0efa0b2
verification by admin
dbauszus-glx Jun 20, 2024
328f681
Add re-verification
dbauszus-glx Jun 20, 2024
28f1726
Update Session Message
RobAndrewHurst Jun 20, 2024
15e1349
reqHost requirement in register module
dbauszus-glx Jun 21, 2024
6857946
register new user insert values
dbauszus-glx Jun 24, 2024
6048efe
update values array for password reset
dbauszus-glx Jun 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 51 additions & 64 deletions mod/user/_user.js
Original file line number Diff line number Diff line change
@@ -1,84 +1,71 @@
/**
## /user/_user

The _user module exports the user method to route User API requests.

- admin
- register
- verify
- add
- delete
- update
- list
- log
- key
- token
- cookie
- login

@module /user
*/

const reqHost = require('../utils/reqHost')

const view = require('../view')

const methods = {
admin: {
handler: (req, res) => {
req.params.template = 'user_admin_view'
req.params.language = req.params.user.language
req.params.user = req.params.user.email
view(req, res)
},
admin: true
},
register: {
handler: require('./register')
},
verify: {
handler: require('./verify')
},
add: {
handler: require('./add'),
admin: true
},
delete: {
handler: require('./delete'),
admin: true
},
update: {
handler: require('./update'),
admin: true
},
list: {
handler: require('./list'),
admin: true
},
log: {
handler: require('./log'),
admin: true
},
key: {
handler: require('./key'),
login: true
},
token: {
handler: require('./token'),
login: true
},
cookie: {
handler: require('./cookie')
},
login: {
handler: require('./login')
}
admin: require('./admin'),
register: require('./register'),
verify: require('./verify'),
add: require('./add'),
delete: require('./delete'),
update: require('./update'),
list: require('./list'),
log: require('./log'),
key: require('./key'),
token: require('./token'),
cookie: require('./cookie'),
login: require('./login')
}

module.exports = async (req, res) => {
/**
### user(req, res)

The Mapp API uses the user method to lookup and route User API requests.

The route method assigns the host param from /utils/reqHost before the request and response arguments are passed a User API method identified by the method param.

const method = methods[req.params.method]
The method request parameter must be an own member of the methods object, eg. `admin`, `register`, `verify`, `add`, `delete`, `update`, `list`, `log`, `key`, `token`, `cookie`, or `login`.

@function user
@param {Object} [req] HTTP request.
@param {Object} [res] HTTP response.
@param {Object} [req.params] Request parameter.
@param {string} [req.params.method] Method request parameter.
*/

module.exports = async function user(req, res) {

if (!Object.hasOwn(methods, req.params.method)) {

if (!method) {
return res.send(`Failed to evaluate 'method' param.`)
}

req.params.host = reqHost(req)

if (!req.params.user && (method.login || method.admin)) {
const method = await methods[req.params.method](req, res)

req.params.msg = 'login_required'
return methods.login.handler(req, res)
}

if (req.params.user && (!req.params.user.admin && method.admin)) {
if (method instanceof Error) {

req.params.msg = 'admin_required'
return methods.login.handler(req, res)
req.params.msg = method.message
methods.login(req, res)
}

method.handler(req, res)
}
10 changes: 10 additions & 0 deletions mod/user/add.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ module.exports = async (req, res) => {
return res.status(500).send('Missing email param')
}

if (!req.params.user) {

return new Error('login_required')
}

if (!req.params.user?.admin) {

return new Error('admin_required')
}

const email = req.params.email.replace(/\s+/g, '')

// Delete exsiting user account with same email in ACL.
Expand Down
19 changes: 19 additions & 0 deletions mod/user/admin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const view = require('../view')

module.exports = async (req, res) => {

if (!req.params.user) {

return new Error('login_required')
}

if (!req.params.user?.admin) {

return new Error('admin_required')
}

req.params.template = 'user_admin_view'
req.params.language = req.params.user.language
req.params.user = req.params.user.email
view(req, res)
}
2 changes: 2 additions & 0 deletions mod/user/cookie.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ const acl = require('./acl')

module.exports = async (req, res) => {

if (!acl) return res.status(500).send('ACL unavailable.')

const cookie = req.cookies && req.cookies[process.env.TITLE]

if (!cookie) {
Expand Down
23 changes: 23 additions & 0 deletions mod/user/delete.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,31 @@ const mailer = require('../utils/mailer')

module.exports = async (req, res) => {

if (!acl) return res.status(500).send('ACL unavailable.')

if (!req.params.email) {

return res.status(500).send('Missing email param')
}

if (!req.params.user) {

return new Error('login_required')
}

const email = req.params.email.replace(/\s+/g, '')

// A user may remove themselves from the ACL.
if (req.params.user?.email === email) {

// The cookie must be set to null on successful return from delete method.
res.setHeader('Set-Cookie', `${process.env.TITLE}=null;HttpOnly;Max-Age=0;Path=${process.env.DIR || '/'}`)
console.log(`${email} removed themselves`)
} else if (!req.params.user?.admin) {

return new Error('admin_required')
}

// Delete user account in ACL.
let rows = await acl(`
DELETE FROM acl_schema.acl_table
Expand Down
12 changes: 12 additions & 0 deletions mod/user/key.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,18 @@ const jwt = require('jsonwebtoken')

module.exports = async (req, res) => {

if (!acl) return res.status(500).send('ACL unavailable.')

if (!req.params.email) {

return res.status(500).send('Missing email param')
}

if (!req.params.user) {

return new Error('login_required')
}

// Get user from ACL.
let rows = await acl(`
SELECT * FROM acl_schema.acl_table
Expand Down
60 changes: 27 additions & 33 deletions mod/user/list.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,40 +17,34 @@ const acl = require('./acl')
*/
module.exports = async (req, res) => {

/**
@typedef {Object} acl
@property {string} email
@property {bool} verified
@property {bool} approved
@property {bool} admin
@property {bool} api
@property {array} roles
@property {string} language
@property {array} access_log
@property {int} failedattempts
@property {string} approved_by
@property {string} expires_on
@property {bool} blocked
@property {string} verificationtoken
*/
if (!req.params.user) {

return new Error('login_required')
}

if (!req.params.user?.admin) {

return new Error('admin_required')
}

let rows = await acl(`
SELECT
email,
verified,
approved,
admin,
length(api)::boolean AS api,
roles,
language,
access_log[array_upper(access_log, 1)],
failedattempts,
approved_by,
${process.env.APPROVAL_EXPIRY ? 'expires_on,' : ''}
blocked,
verificationtoken
FROM acl_schema.acl_table
${req.params.email ? `WHERE email='${req.params.email}'`: ''}
ORDER BY email;`)
SELECT
email,
verified,
approved,
admin,
length(api)::boolean AS api,
roles,
language,
access_log[array_upper(access_log, 1)],
failedattempts,
approved_by,
${process.env.APPROVAL_EXPIRY ? 'expires_on,' : ''}
blocked,
verificationtoken
FROM acl_schema.acl_table
${req.params.email ? `WHERE email='${req.params.email}'`: ''}
ORDER BY email;`)

if (rows instanceof Error) return res.status(500).send('Failed to query PostGIS table.')

Expand Down
17 changes: 17 additions & 0 deletions mod/user/log.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,23 @@ const acl = require('./acl')

module.exports = async (req, res) => {

if (!acl) return res.status(500).send('ACL unavailable.')

if (!req.params.email) {

return res.status(500).send('Missing email param')
}

if (!req.params.user) {

return new Error('login_required')
}

if (!req.params.user?.admin) {

return new Error('admin_required')
}

const rows = await acl(`
SELECT access_log
FROM acl_schema.acl_table
Expand Down
5 changes: 5 additions & 0 deletions mod/user/token.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ const jwt = require('jsonwebtoken')

module.exports = async (req, res) => {

if (!req.params.user) {

return new Error('login_required')
}

const user = req.params.user

if (user.from_token) return res.send('Token may not be generated from token authentication.')
Expand Down
12 changes: 12 additions & 0 deletions mod/user/update.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,18 @@ const languageTemplates = require('../utils/languageTemplates')

module.exports = async (req, res) => {

if (!acl) return res.status(500).send('ACL unavailable.')

if (!req.params.user) {

return new Error('login_required')
}

if (!req.params.user?.admin) {

return new Error('admin_required')
}

// Remove spaces from email.
const email = req.params.email.replace(/\s+/g, '')

Expand Down
Loading