Skip to content

Commit

Permalink
Sessions (#3)
Browse files Browse the repository at this point in the history
* routes: return only JSON responses
* route documentation for sessions
  • Loading branch information
msimerson authored Feb 24, 2024
1 parent 99908d7 commit 1cdf65d
Show file tree
Hide file tree
Showing 22 changed files with 410 additions and 195 deletions.
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -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

Expand Down
6 changes: 3 additions & 3 deletions lib/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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]
Expand Down Expand Up @@ -45,4 +45,4 @@ function applyDefaults(cfg = {}, defaults = {}) {
return cfg
}

module.exports = new config()
module.exports = new Config()
2 changes: 1 addition & 1 deletion test/config.js → lib/config.test.js
Original file line number Diff line number Diff line change
@@ -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 () {
Expand Down
40 changes: 25 additions & 15 deletions lib/group.js
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion test/mysql.js → lib/mysql.test.js
Original file line number Diff line number Diff line change
@@ -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 () => {
Expand Down
49 changes: 49 additions & 0 deletions lib/session.test.js
Original file line number Diff line number Diff line change
@@ -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,
)
})
})
})
79 changes: 54 additions & 25 deletions lib/user.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,40 @@
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
, u.username
, 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
AND u.deleted=0
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,
Expand All @@ -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({
Expand All @@ -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],
// )
// }
Expand Down Expand Up @@ -189,4 +218,4 @@ function getPermFields() {
].join(`, nt_perm.`)
)
}
*/
*/
Loading

0 comments on commit 1cdf65d

Please sign in to comment.