From 1cdf65d97411818572a0ea77d522ccc9dbafffe1 Mon Sep 17 00:00:00 2001 From: Matt Simerson Date: Fri, 23 Feb 2024 20:43:43 -0800 Subject: [PATCH] Sessions (#3) * routes: return only JSON responses * route documentation for sessions --- README.md | 15 ++-- lib/config.js | 6 +- test/config.js => lib/config.test.js | 2 +- lib/group.js | 40 +++++---- test/mysql.js => lib/mysql.test.js | 2 +- lib/session.test.js | 49 +++++++++++ lib/user.js | 79 ++++++++++++------ test/user.js => lib/user.test.js | 65 +++------------ lib/util.js | 10 +++ test/util.js => lib/util.test.js | 10 ++- package.json | 11 +-- routes/index.js | 30 +++++-- routes/session.js | 102 +++++++++++++++++++++++ test/routes.js => routes/session.test.js | 38 +++++---- routes/user.js | 65 +++++---------- routes/user.test.js | 51 ++++++++++++ test/{fixtures => }/.setup.js | 8 +- test/{fixtures => }/.teardown.js | 10 +-- test/fixtures/run.sh | 5 -- test/{fixtures => }/group.json | 0 test/run.sh | 5 ++ test/{fixtures => }/user.json | 2 +- 22 files changed, 410 insertions(+), 195 deletions(-) rename test/config.js => lib/config.test.js (97%) rename test/mysql.js => lib/mysql.test.js (95%) create mode 100644 lib/session.test.js rename test/user.js => lib/user.test.js (71%) rename test/util.js => lib/util.test.js (62%) create mode 100644 routes/session.js rename test/routes.js => routes/session.test.js (73%) create mode 100644 routes/user.test.js rename test/{fixtures => }/.setup.js (84%) rename test/{fixtures => }/.teardown.js (72%) delete mode 100755 test/fixtures/run.sh rename test/{fixtures => }/group.json (100%) create mode 100755 test/run.sh rename test/{fixtures => }/user.json (100%) diff --git a/README.md b/README.md index 27d02ff..78c63e6 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,27 @@ [![Build Status](https://github.com/NicTool/api/actions/workflows/ci.yml/badge.svg)](https://github.com/NicTool/api/actions/workflows/ci.yml) [![Coverage Status](https://coveralls.io/repos/github/NicTool/api/badge.svg)](https://coveralls.io/github/NicTool/api) -# nt-api - -nictool api v3 +# NicTool API v3 ## Install -1. Install [Node.js](https://nodejs.org/en/download/) on your system +1. Install [Node.js](https://nodejs.org/en/download/) 2. Download the NicTool v3 API ``` -git clone https://github.com/NicTool/api.git nictool-api -cd nictool-api +mkdir nictool && cd nictool +git clone https://github.com/NicTool/api.git +cd api npm install ``` ## Configure -Edit the files in conf.d to reflect your local settings. Each config file has a default section which lists all available config settings. Below the `default` section are optional deployment environments such as `production`, `development`, and `test`. When a config file is loaded, the environment variable `NODE_ENV` is checked and if defined, any overrides in the matching deployment section are applied. +Edit the files in conf.d to reflect your local settings. + +Each config file has a default section which lists all available config settings. Below the `default` section are optional deployment environments such as `production`, `development`, and `test`. When a config file is loaded, the environment variable `NODE_ENV` is checked and if defined, any overrides in the matching deployment section are applied. ## Start the service diff --git a/lib/config.js b/lib/config.js index b63b369..4ed446e 100644 --- a/lib/config.js +++ b/lib/config.js @@ -2,7 +2,7 @@ const fs = require('fs/promises') const YAML = require('yaml') -class config { +class Config { constructor(opts = {}) { this.cfg = {} this.debug = process.env.NODE_DEBUG ? true : false @@ -16,7 +16,7 @@ class config { const str = await fs.readFile(`./conf.d/${name}.yml`, 'utf8') const cfg = YAML.parse(str) - // if (this.debug) console.log(cfg) + if (this.debug) console.debug(cfg) this.cfg[cacheKey] = applyDefaults(cfg[env ?? this.env], cfg.default) return this.cfg[cacheKey] @@ -45,4 +45,4 @@ function applyDefaults(cfg = {}, defaults = {}) { return cfg } -module.exports = new config() +module.exports = new Config() diff --git a/test/config.js b/lib/config.test.js similarity index 97% rename from test/config.js rename to lib/config.test.js index bf1ac0c..c10f777 100644 --- a/test/config.js +++ b/lib/config.test.js @@ -1,7 +1,7 @@ const assert = require('node:assert/strict') const { describe, it } = require('node:test') -const config = require('../lib/config') +const config = require('./config') describe('config', function () { describe('get', function () { diff --git a/lib/group.js b/lib/group.js index a6be753..3431546 100644 --- a/lib/group.js +++ b/lib/group.js @@ -1,38 +1,48 @@ -const mysql = require('./mysql') +const Mysql = require('./mysql') +const Util = require('./util') -const validate = require('@nictool/nt-validate') +const validate = require('@nictool/validate') class Group { constructor() {} async create(args) { - const { error } = validate.group.validate(args) + const { error } = validate.group.v2.validate(args) if (error) console.error(error) const g = await this.get({ nt_group_id: args.nt_group_id }) - if (g.length) { - // console.log(g) - return g[0].nt_group_id - } + if (g.length) return g[0].id - const groupId = await mysql.insert(`INSERT INTO nt_group`, args) + const groupId = await Mysql.insert(`INSERT INTO nt_group`, args) return groupId } async get(args) { - return await mysql.select(`SELECT * FROM nt_group WHERE`, args) + args = Util.mapToDbColumn(args, { id: 'nt_group_id' }) + return await Mysql.select( + `SELECT nt_group_id AS id, name FROM nt_group WHERE`, + args, + ) + } + + async getAdmin(args) { + return await Mysql.select( + `SELECT nt_group_id AS id + , name + , parent_group_id AS parent_gid + , deleted + FROM nt_group WHERE`, + Util.mapToDbColumn(args, { id: 'nt_group_id' }), + ) } async destroy(args) { - const g = await this.get({ nt_group_id: args.nt_group_id }) - // console.log(g) + const g = await this.getAdmin({ nt_group_id: args.nt_group_id }) if (g.length === 1) { - await mysql.execute(`DELETE FROM nt_group WHERE nt_group_id=?`, [ - g[0].nt_group_id, - ]) + await Mysql.execute(`DELETE FROM nt_group WHERE nt_group_id=?`, [g[0].id]) } } } module.exports = new Group() -module.exports._mysql = mysql +module.exports._mysql = Mysql diff --git a/test/mysql.js b/lib/mysql.test.js similarity index 95% rename from test/mysql.js rename to lib/mysql.test.js index 168366b..3edebe2 100644 --- a/test/mysql.js +++ b/lib/mysql.test.js @@ -1,7 +1,7 @@ const assert = require('node:assert/strict') const { describe, it } = require('node:test') -const mysql = require('../lib/mysql') +const mysql = require('./mysql') describe('mysql', () => { it('connects', async () => { diff --git a/lib/session.test.js b/lib/session.test.js new file mode 100644 index 0000000..c27062d --- /dev/null +++ b/lib/session.test.js @@ -0,0 +1,49 @@ +const assert = require('node:assert/strict') +const { describe, it, after } = require('node:test') + +const session = require('./session') +const userCase = require('../test/user.json') + +after(async () => { + session._mysql.disconnect() +}) + +describe('session', function () { + // session._mysql.debug(true) + let sessionId + + describe('create', () => { + it('creates a login session', async () => { + sessionId = await session.create({ + nt_user_id: userCase.nt_user_id, + nt_user_session: '3.0.0', + }) + assert.ok(sessionId) + }) + }) + + describe('get', () => { + it('finds a session by ID', async () => { + const s = await session.get({ nt_user_session_id: sessionId }) + assert.ok(s.nt_user_session_id) + }) + + it('finds a session by session', async () => { + const s = await session.get({ nt_user_session: '3.0.0' }) + assert.ok(s.nt_user_session_id) + }) + }) + + describe('delete', () => { + it('deletes a session by ID', async () => { + assert.ok(await session.delete({ nt_user_session_id: sessionId })) + }) + + it('does not find a deleted session', async () => { + assert.equal( + await session.get({ nt_user_session_id: sessionId }), + undefined, + ) + }) + }) +}) diff --git a/lib/user.js b/lib/user.js index bcc7666..df73150 100644 --- a/lib/user.js +++ b/lib/user.js @@ -1,23 +1,23 @@ const crypto = require('node:crypto') -const validate = require('@nictool/nt-validate') +const validate = require('@nictool/validate') -const Config = require('./config') const Mysql = require('./mysql') +const Util = require('./util') +Util.setEnv() +const Config = require('./config') class User { constructor(args) { this.debug = args?.debug ?? false + this.cfg = Config.getSync('session') } async authenticate(authTry) { if (this.debug) console.log(authTry) - let [username, group] = authTry.username.split('@') - if (!group) { - this.cfg = await Config.get('session') - group = this.cfg.group ?? 'NicTool' - } + let [username, groupName] = authTry.username.split('@') + if (!groupName) groupName = this.cfg.group ?? 'NicTool' - const query = `SELECT u.nt_user_id + const query = `SELECT u.nt_user_id AS id , u.nt_group_id , u.first_name , u.last_name @@ -25,8 +25,8 @@ class User { , u.password , u.pass_salt , u.email - , u.is_admin - , g.name AS groupname + /*, u.is_admin */ + , g.name AS group_name FROM nt_user u, nt_group g WHERE u.nt_group_id = g.nt_group_id AND g.deleted=0 @@ -34,7 +34,7 @@ class User { AND u.username = ? AND g.name = ?` - for (const u of await Mysql.execute(query, [username, group])) { + for (const u of await Mysql.execute(query, [username, groupName])) { if ( await this.validPassword( authTry.password, @@ -46,13 +46,22 @@ class User { for (const f of ['password', 'pass_salt']) { delete u[f] // SECURITY: no longer needed } - return u + for (const b of ['is_admin']) { + if (u[b] !== undefined) u[b] = u[b] === 1 // int to boolean + } + const g = { + id: u.nt_group_id, + name: groupName, + } + delete u.nt_group_id + delete u.group_name + return { user: u, group: g } } } } async create(args) { - const { error } = validate.user.validate(args) + const { error } = validate.user.v2.validate(args) if (error) console.error(error) const u = await this.get({ @@ -75,37 +84,57 @@ class User { async get(args) { return await Mysql.select( - `SELECT email, first_name, last_name, nt_group_id, nt_user_id, username, email, deleted + `SELECT email + , first_name + , last_name + , nt_group_id AS gid + , nt_user_id AS id + , username + , email FROM nt_user WHERE`, - args, + Util.mapToDbColumn(args, { id: 'nt_user_id', gid: 'nt_group_id' }), + ) + } + + async getAdmin(args) { + return await Mysql.select( + `SELECT email + , first_name + , last_name + , nt_group_id AS gid + , nt_user_id AS id + , username + , password + , email + , deleted + FROM nt_user WHERE`, + Util.mapToDbColumn(args, { id: 'nt_user_id', gid: 'nt_group_id' }), ) } async delete(args, val) { - const u = await this.get({ nt_user_id: args.nt_user_id }) + const u = await this.getAdmin({ nt_user_id: args.nt_user_id }) if (u.length === 1) { await Mysql.execute(`UPDATE nt_user SET deleted=? WHERE nt_user_id=?`, [ val ?? 1, - u[0].nt_user_id, + u[0].id, ]) } } async destroy(args) { - const u = await this.get({ nt_user_id: args.nt_user_id }) + const u = await this.getAdmin({ nt_user_id: args.nt_user_id }) if (u.length === 1) { - await Mysql.execute(`DELETE FROM nt_user WHERE nt_user_id=?`, [ - u[0].nt_user_id, - ]) + await Mysql.execute(`DELETE FROM nt_user WHERE nt_user_id=?`, [u[0].id]) } } // async get_perms(user_id) { // return await Mysql.execute( // ` - // SELECT ${getPermFields()} FROM nt_perm - // WHERE deleted=0 - // AND nt_user_id = ?`, + // SELECT ${getPermFields()} FROM nt_perm + // WHERE deleted=0 + // AND nt_user_id = ?`, // [user_id], // ) // } @@ -189,4 +218,4 @@ function getPermFields() { ].join(`, nt_perm.`) ) } -*/ \ No newline at end of file +*/ diff --git a/test/user.js b/lib/user.test.js similarity index 71% rename from test/user.js rename to lib/user.test.js index 119e7dc..ec645d9 100644 --- a/test/user.js +++ b/lib/user.test.js @@ -1,14 +1,10 @@ const assert = require('node:assert/strict') const { describe, it, after } = require('node:test') -const session = require('../lib/session') -const user = require('../lib/user') - -const userCase = require('./fixtures/user.json') +const user = require('./user') after(async () => { - // user._mysql.disconnect() - session._mysql.disconnect() + user._mysql.disconnect() }) describe('user', function () { @@ -17,13 +13,13 @@ describe('user', function () { const u = await user.get({ nt_user_id: 4096 }) // console.log(u) assert.deepEqual(u[0], { - nt_group_id: 4096, - nt_user_id: 4096, + gid: 4096, + id: 4096, username: 'unit-test', email: 'unit-test@example.com', first_name: 'Unit', last_name: 'Test', - deleted: 0, + // deleted: 0, }) }) @@ -31,22 +27,22 @@ describe('user', function () { const u = await user.get({ username: 'unit-test' }) // console.log(u) assert.deepEqual(u[0], { - nt_group_id: 4096, - nt_user_id: 4096, + gid: 4096, + id: 4096, username: 'unit-test', email: 'unit-test@example.com', first_name: 'Unit', last_name: 'Test', - deleted: 0, + // deleted: 0, }) }) it('deletes a user', async () => { await user.delete({ nt_user_id: 4096 }) - let u = await user.get({ nt_user_id: 4096 }) + let u = await user.getAdmin({ nt_user_id: 4096 }) assert.equal(u[0].deleted, 1) await user.delete({ nt_user_id: 4096 }, 0) // restore - u = await user.get({ nt_user_id: 4096 }) + u = await user.getAdmin({ nt_user_id: 4096 }) assert.equal(u[0].deleted, 0) }) }) @@ -149,44 +145,3 @@ describe('user', function () { }) }) }) - -describe('session', function () { - // session._mysql.debug(true) - let sessionId - - describe('create', () => { - it('creates a login session', async () => { - sessionId = await session.create({ - nt_user_id: userCase.nt_user_id, - nt_user_session: 12345, - }) - assert.ok(sessionId) - }) - }) - - describe('get', () => { - it('finds a session by ID', async () => { - const s = await session.get({ nt_user_session_id: sessionId }) - // console.log(s) - assert.ok(s.nt_user_session_id) - }) - - it('finds a session by session', async () => { - const s = await session.get({ nt_user_session: 12345 }) - assert.ok(s.nt_user_session_id) - }) - }) - - describe('delete', () => { - it('deletes a session by ID', async () => { - assert.ok(await session.delete({ nt_user_session_id: sessionId })) - }) - - it('does not find a deleted session', async () => { - assert.equal( - await session.get({ nt_user_session_id: sessionId }), - undefined, - ) - }) - }) -}) diff --git a/lib/util.js b/lib/util.js index 9a29cd7..851d6da 100644 --- a/lib/util.js +++ b/lib/util.js @@ -18,3 +18,13 @@ exports.meta = { version: require('../package.json').version, }, } + +exports.mapToDbColumn = function (args, maps) { + for (const [key, val] of Object.entries(maps)) { + if (args[key] !== undefined) { + args[val] = args[key] + delete args[key] + } + } + return args +} diff --git a/test/util.js b/lib/util.test.js similarity index 62% rename from test/util.js rename to lib/util.test.js index 92db289..b853988 100644 --- a/test/util.js +++ b/lib/util.test.js @@ -1,7 +1,7 @@ const assert = require('node:assert/strict') const { describe, it } = require('node:test') -const util = require('../lib/util') +const util = require('./util') describe('util', function () { if (process.env.NODE_ENV === undefined) { @@ -18,4 +18,12 @@ describe('util', function () { assert.deepEqual(util.meta, { api: { version: '3.0.0' } }) }) }) + + describe('mapToDbColumn', function () { + it('maps short names to DB fields', async () => { + const before = { id: 5 } + const mappings = { id: 'nt_user_id' } + assert.deepEqual(util.mapToDbColumn(before, mappings), { nt_user_id: 5 }) + }) + }) }) diff --git a/package.json b/package.json index 786a8c8..9446f37 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "nt-api", + "name": "@nictool/api", "version": "3.0.0", "description": "NicTool API", "main": "index.js", @@ -11,9 +11,9 @@ "prettier:fix": "npm run prettier -- --write", "start": "NODE_ENV=production node ./server", "develop": "NODE_ENV=development node ./server", - "test": "test/fixtures/run.sh", + "test": "test/run.sh", "versions": "npx dependency-version-checker check", - "watch": "npm run test -- --watch" + "watch": "node test/.setup.js && node --test --watch; node test/.teardown.js" }, "repository": { "type": "git", @@ -35,12 +35,13 @@ "eslint": "^8.56.0" }, "dependencies": { - "@hapi/basic": "^7.0.2", "@hapi/cookie": "^12.0.1", "@hapi/hapi": "^21.3.3", "@hapi/hoek": "^11.0.4", "@hapi/inert": "^7.1.0", - "@nictool/nt-validate": "^0.6.1", + "@hapi/vision": "^7.0.3", + "@nictool/validate": "^0.6.3", + "hapi-swagger": "^17.2.1", "mysql2": "^3.9.1", "qs": "^6.11.2", "yaml": "^2.3.4" diff --git a/routes/index.js b/routes/index.js index 5c651a3..236e121 100644 --- a/routes/index.js +++ b/routes/index.js @@ -2,16 +2,22 @@ const path = require('node:path') -const hapi = require('@hapi/hapi') +const Hapi = require('@hapi/hapi') +const Inert = require('@hapi/inert') +const Vision = require('@hapi/vision') +const HapiSwagger = require('hapi-swagger') + const qs = require('qs') // const hoek = require('@hapi/hoek') -// const validate = require('@nictool/nt-validate') +// const validate = require('@nictool/validate') const util = require('../lib/util') util.setEnv() const Config = require('../lib/config') const Session = require('../lib/session') const User = require('../lib/user') + +const SessionRoutes = require('./session') const UserRoutes = require('./user') let server @@ -19,7 +25,7 @@ let server const setup = async () => { const httpCfg = await Config.get('http') - server = hapi.server({ + server = Hapi.server({ port: httpCfg.port, host: httpCfg.host, query: { @@ -32,9 +38,22 @@ const setup = async () => { }, }) - await server.register(require('@hapi/basic')) await server.register(require('@hapi/cookie')) await server.register(require('@hapi/inert')) + await server.register([ + Inert, + Vision, + { + plugin: HapiSwagger, + options: { + info: { + title: 'NicTool API Documentation', + version: require('../package.json').version, + }, + }, + }, + ]) + const sessionCfg = await Config.get('session') server.auth.strategy('session', 'cookie', { @@ -59,13 +78,14 @@ const setup = async () => { }, }) + SessionRoutes(server) UserRoutes(server) server.route({ method: '*', path: '/{any*}', handler: function (request, h) { - return h.response('404 Error! Page Not Found!').code(404) + return h.response({ msg: '404 Error! Page Not Found!' }).code(404) }, }) diff --git a/routes/session.js b/routes/session.js new file mode 100644 index 0000000..80924a7 --- /dev/null +++ b/routes/session.js @@ -0,0 +1,102 @@ +const validate = require('@nictool/validate') + +const Group = require('../lib/group') +const User = require('../lib/user') +const Session = require('../lib/session') +const Util = require('../lib/util') + +module.exports = (server) => { + server.route([ + { + method: 'GET', + path: '/session', + options: { + response: { + schema: validate.user.sessionOut, + }, + tags: ['api'], + }, + handler: async (request, h) => { + const { nt_user_id, nt_user_session_id } = request.state['sid-nictool'] + const users = await User.get({ id: nt_user_id }) + const groups = await Group.get({ nt_group_id: users[0].gid }) + delete users[0].gid + return h + .response({ + user: users[0], + group: groups[0], + session: { id: nt_user_session_id }, + meta: { + api: Util.meta.api, + msg: `working on it`, + }, + }) + .code(200) + }, + }, + { + method: 'POST', + path: '/session', + options: { + auth: { mode: 'try' }, + validate: { + payload: validate.user.sessionPost, + }, + response: { + schema: validate.user.sessionOut, + }, + tags: ['api'], + }, + handler: async (request, h) => { + const account = await User.authenticate(request.payload) + if (!account) { + return h.response({ err: 'Invalid authentication' }).code(401) + } + + const sessId = await Session.create({ + nt_user_id: account.user.id, + nt_user_session: '3.0.0', + }) + + request.cookieAuth.set({ + nt_user_id: account.user.id, + nt_user_session_id: sessId, + }) + + return h + .response({ + user: account.user, + group: account.group, + session: { id: sessId }, + meta: { + api: Util.meta.api, + msg: `you are logged in`, + }, + }) + .code(200) + }, + }, + { + method: 'DELETE', + path: '/session', + handler: (request, h) => { + request.cookieAuth.clear() + + return h + .response({ + meta: { + api: Util.meta.api, + msg: 'You are logged out', + }, + }) + .code(200) + }, + options: { + response: { + schema: validate.user.sessionOut, + }, + tags: ['api'], + }, + }, + ]) +} diff --git a/test/routes.js b/routes/session.test.js similarity index 73% rename from test/routes.js rename to routes/session.test.js index 4f12811..358fdc0 100644 --- a/test/routes.js +++ b/routes/session.test.js @@ -1,8 +1,8 @@ const assert = require('node:assert/strict') const { describe, it, before, after } = require('node:test') -const { init } = require('../routes') -const userCase = require('./fixtures/user.json') +const { init } = require('./index') +const userCase = require('../test/user.json') before(async () => { this.server = await init() @@ -19,22 +19,23 @@ const parseCookie = (c) => { describe('routes', () => { const routes = [{ GET: '/' }, { GET: '/user' }, { DELETE: '/session' }] - for (const r of routes) { - const key = Object.keys(r)[0] - const val = Object.values(r)[0] - describe(`${key} ${val}`, () => { - it('no session responds with 401', async () => { + describe('no session responds with 401', () => { + for (const r of routes) { + const key = Object.keys(r)[0] + const val = Object.values(r)[0] + it(`${key} ${val}`, async () => { const res = await this.server.inject({ method: key, url: val, }) assert.deepEqual(res.statusCode, 401) + // console.log(res.result) }) - }) - } + } + }) - describe('POST /session', () => { - it('valid auth sets a cookie', async () => { + describe('valid auth sets a cookie', () => { + it('POST /session', async () => { const res = await this.server.inject({ method: 'POST', url: '/session', @@ -44,13 +45,12 @@ describe('routes', () => { }, }) assert.ok(res.headers['set-cookie'][0]) - // console.log(res.headers['set-cookie'][0]) this.sessionCookie = parseCookie(res.headers['set-cookie'][0]) - // console.log(this.sessionCookie) + // console.log(res.result) }) }) - describe('with valid session, can retrieve URIs that require auth', () => { + describe('with session, can retrieve private URIs', () => { before(async () => { const res = await this.server.inject({ method: 'POST', @@ -72,10 +72,16 @@ describe('routes', () => { Cookie: this.sessionCookie, }, }) - console.log(res.result) + // console.log(res.result) + assert.equal(res.statusCode, 200) }) - const routes = [{ GET: '/' }, { GET: '/user' }, { DELETE: '/session' }] + const routes = [ + { GET: '/' }, + { GET: '/user' }, + { GET: '/session' }, + { DELETE: '/session' }, + ] for (const r of routes) { const key = Object.keys(r)[0] diff --git a/routes/user.js b/routes/user.js index 3776ab5..962964f 100644 --- a/routes/user.js +++ b/routes/user.js @@ -1,7 +1,7 @@ -const validate = require('@nictool/nt-validate') +const validate = require('@nictool/validate') const User = require('../lib/user') -const Session = require('../lib/session') +const Util = require('../lib/util') module.exports = (server) => { server.route([ @@ -9,51 +9,24 @@ module.exports = (server) => { method: 'GET', path: '/user', options: { - // auth: { mode: 'try' }, + response: { + schema: validate.user.userGET, + }, + tags: ['api'], }, handler: async (request, h) => { - // console.log(request.auth) - if (request.auth.isAuthenticated) { - return h.response('You ARE logged in!').code(200) - } - - return h.response('You are NOT logged in!').code(401) - }, - }, - { - method: 'POST', - path: '/session', - options: { - auth: { mode: 'try' }, - validate: { payload: validate.login }, - }, - handler: async (request, h) => { - const account = await User.authenticate(request.payload) - if (!account) { - return h.response('Invalid authentication').code(401) - } - - const sessId = await Session.create({ - nt_user_id: account.nt_user_id, - nt_user_session: '12345', - }) - - request.cookieAuth.set({ - nt_user_id: account.nt_user_id, - nt_session_id: sessId.nt_user_session_id, - }) - return h.response(`SUCCESS: you are logged in`).code(200) - }, - }, - { - method: 'DELETE', - path: '/session', - handler: (request, h) => { - if (request.auth.isAuthenticated) { - request.cookieAuth.clear() - return h.response('You are logged out').code(200) - } - return h.response('You are NOT logged in!').code(401) + const { nt_user_id } = request.state['sid-nictool'] + const users = await User.get({ id: nt_user_id }) + delete users[0].gid + return h + .response({ + user: users[0], + meta: { + api: Util.meta.api, + msg: `here's your user`, + }, + }) + .code(200) }, }, ]) @@ -62,7 +35,7 @@ module.exports = (server) => { /* server.route({ method: 'POST', // GET PUT POST DELETE - path: '/login', + path: '/', handler: (request, h) => { // request.query // request.params diff --git a/routes/user.test.js b/routes/user.test.js new file mode 100644 index 0000000..a509fa1 --- /dev/null +++ b/routes/user.test.js @@ -0,0 +1,51 @@ +const assert = require('node:assert/strict') +const { describe, it, before, after } = require('node:test') + +const { init } = require('./index') +const userCase = require('../test/user.json') + +before(async () => { + this.server = await init() + const res = await this.server.inject({ + method: 'POST', + url: '/session', + payload: { + username: `${userCase.username}@example.com`, + password: 'Wh@tA-Decent#P6ssw0rd', + }, + }) + assert.ok(res.headers['set-cookie'][0]) + this.sessionCookie = parseCookie(res.headers['set-cookie'][0]) +}) + +after(async () => { + const res = await this.server.inject({ + method: 'DELETE', + url: '/session', + headers: { + Cookie: this.sessionCookie, + }, + }) + // console.log(res.result) + assert.equal(res.statusCode, 200) + + await this.server.stop() +}) + +const parseCookie = (c) => { + return c.split(';')[0] +} + +describe('user', () => { + it('GET /user', async () => { + const res = await this.server.inject({ + method: 'GET', + url: '/user', + headers: { + Cookie: this.sessionCookie, + }, + }) + // console.log(res.result) + assert.equal(res.statusCode, 200) + }) +}) diff --git a/test/fixtures/.setup.js b/test/.setup.js similarity index 84% rename from test/fixtures/.setup.js rename to test/.setup.js index 6fc4d6e..e36ed74 100644 --- a/test/fixtures/.setup.js +++ b/test/.setup.js @@ -1,6 +1,6 @@ -const group = require('../../lib/group') -const user = require('../../lib/user') -// const session = require('../../lib/session') +const group = require('../lib/group') +const user = require('../lib/user') +// const session = require('../lib/session') const userCase = require('./user.json') const groupCase = require('./group.json') @@ -36,6 +36,6 @@ async function createTestUser() { async function createTestSession() { this.sessionId = await session.create({ nt_user_id: userCase.nt_user_id, - nt_user_session: 12345, + nt_user_session: '3.0.0', }) } diff --git a/test/fixtures/.teardown.js b/test/.teardown.js similarity index 72% rename from test/fixtures/.teardown.js rename to test/.teardown.js index 23129d3..fea981b 100644 --- a/test/fixtures/.teardown.js +++ b/test/.teardown.js @@ -1,6 +1,6 @@ -const group = require('../../lib/group') -const user = require('../../lib/user') -// const session = require('../../lib/session') +const group = require('../lib/group') +const user = require('../lib/user') +// const session = require('../lib/session') const userCase = require('./user.json') const groupCase = require('./group.json') @@ -8,8 +8,8 @@ const teardown = async () => { // await destroyTestSession() await destroyTestUser() await destroyTestGroup() - await user._mysql.disconnect() - await group._mysql.disconnect() + // await user._mysql.disconnect() + // await group._mysql.disconnect() process.exit() } diff --git a/test/fixtures/run.sh b/test/fixtures/run.sh deleted file mode 100755 index 3b1906a..0000000 --- a/test/fixtures/run.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -node test/fixtures/.setup.js -node --test test/*.js -node test/fixtures/.teardown.js \ No newline at end of file diff --git a/test/fixtures/group.json b/test/group.json similarity index 100% rename from test/fixtures/group.json rename to test/group.json diff --git a/test/run.sh b/test/run.sh new file mode 100755 index 0000000..5b81082 --- /dev/null +++ b/test/run.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +node test/.setup.js +node --test +node test/.teardown.js \ No newline at end of file diff --git a/test/fixtures/user.json b/test/user.json similarity index 100% rename from test/fixtures/user.json rename to test/user.json index af849fe..13a6f92 100644 --- a/test/fixtures/user.json +++ b/test/user.json @@ -1,6 +1,6 @@ { - "nt_group_id": 4096, "nt_user_id": 4096, + "nt_group_id": 4096, "username": "unit-test", "email": "unit-test@example.com", "first_name": "Unit",