diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3ab87f0..491038a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,10 +1,8 @@ name: CI on: - push: - paths-ignore: - - '*.md' pull_request: + types: [opened, synchronize, reopened] env: CI: true @@ -23,7 +21,7 @@ jobs: - uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VER }} - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - run: npm install - name: Initialize MySQL run: sh sql/init-mysql.sh @@ -56,12 +54,12 @@ jobs: strategy: matrix: os: [ubuntu-latest] - node-version: ${{ fromJson(needs.get-lts.outputs.active) }} + node-version: ${{ fromJson(needs.get-lts.outputs.lts) }} fail-fast: false steps: - run: sudo /etc/init.d/mysql start - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@v6 + - uses: actions/setup-node@v6 with: node-version: ${{ matrix.node-version }} - run: sh sql/init-mysql.sh @@ -73,15 +71,15 @@ jobs: runs-on: macos-latest strategy: matrix: - node-version: ${{ fromJson(needs.get-lts.outputs.active) }} + node-version: ${{ fromJson(needs.get-lts.outputs.lts) }} fail-fast: false steps: - name: Install & Start MySQL run: | brew install mysql@8.4 brew services start mysql@8.4 - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@v6 + - uses: actions/setup-node@v6 name: Node ${{ matrix.node-version }} on ${{ matrix.os }} with: node-version: ${{ matrix.node-version }} @@ -95,15 +93,15 @@ jobs: runs-on: windows-latest strategy: matrix: - node-version: ${{ fromJson(needs.get-lts.outputs.active) }} + node-version: ${{ fromJson(needs.get-lts.outputs.lts) }} experimental: [true] fail-fast: false steps: - name: Install MySQL run: | choco install mysql - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@v6 + - uses: actions/setup-node@v6 name: Node ${{ matrix.node-version }} with: node-version: ${{ matrix.node-version }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 311399f..337ce04 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,25 +1,20 @@ name: publish on: - push: - branches: - - main - paths: - - package.json - release: - types: [published] + release: + types: [published] env: CI: true - node-version: 20 + node-version: 22 jobs: build: runs-on: ubuntu-latest steps: - run: sudo /etc/init.d/mysql start - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@v6 + - uses: actions/setup-node@v6 with: node-version: ${{ env.node-version }} - run: sh sql/init-mysql.sh @@ -30,25 +25,19 @@ jobs: needs: build runs-on: ubuntu-latest steps: - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v6 name: Node ${{ env.node-version }} with: node-version: ${{ env.node-version }} registry-url: https://registry.npmjs.org/ - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: fetch-depth: 0 # fetch-depth 0 needed by GitHub Release - name: publish to NPM run: npm publish --access=public - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} - - - name: GitHub Release - uses: justincy/github-action-npm-release@2.0.1 - id: release publish-gpr: needs: build @@ -57,8 +46,8 @@ jobs: contents: read packages: write steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@v6 + - uses: actions/setup-node@v6 with: node-version: ${{ env.node-version }} registry-url: https://npm.pkg.github.com/ diff --git a/.prettierrc.yml b/.prettierrc.yml deleted file mode 100644 index 9b110b8..0000000 --- a/.prettierrc.yml +++ /dev/null @@ -1,3 +0,0 @@ -trailingComma: 'all' -semi: false -singleQuote: true diff --git a/.release b/.release index 7307651..d106d83 160000 --- a/.release +++ b/.release @@ -1 +1 @@ -Subproject commit 73076513e83c2057a32515831b638771c15b1d83 +Subproject commit d106d83e69d5d8c99e4d6be4ba98ddde550d082b diff --git a/CHANGELOG.md b/CHANGELOG.md index c1b7847..c519682 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,15 @@ +# Changelog + +The format is based on [Keep a Changelog](https://keepachangelog.com/). + # CHANGES ### Unreleased +### [3.0.0-alpha.7] - 2026-03-13 + +- fixes + ### [3.0.0-alpha.6] - 2025-04-08 - dep(eslint): upgraded to v9 @@ -39,7 +47,11 @@ - lib/user.get: convert booleans +[3.0.0-alpha.0]: https://github.com/NicTool/api/releases/tag/3.0.0-alpha.0 +[3.0.0-alpha.1]: https://github.com/NicTool/api/releases/tag/3.0.0-alpha.1 +[3.0.0-alpha.2]: https://github.com/NicTool/api/releases/tag/3.0.0-alpha.2 [3.0.0-alpha.3]: https://github.com/NicTool/api/releases/tag/3.0.0-alpha.3 -[3.0.0-alpha.4]: https://github.com/NicTool/api/releases/tag/3.0.0-alpha.4 -[3.0.0-alpha.5]: https://github.com/NicTool/api/releases/tag/3.0.0-alpha.5 -[3.0.0-alpha.6]: https://github.com/NicTool/api/releases/tag/3.0.0-alpha.6 +[3.0.0-alpha.4]: https://github.com/NicTool/api/releases/tag/v3.0.0-alpha.4 +[3.0.0-alpha.5]: https://github.com/NicTool/api/releases/tag/v3.0.0-alpha.5 +[3.0.0-alpha.6]: https://github.com/NicTool/api/releases/tag/v3.0.0-alpha.6 +[3.0.0-alpha.7]: https://github.com/NicTool/api/releases/tag/v3.0.0-alpha.7 diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md new file mode 100644 index 0000000..a489471 --- /dev/null +++ b/CONTRIBUTORS.md @@ -0,0 +1,9 @@ +# Contributors + +This handcrafted artisanal software is brought to you by: + +|
msimerson (14)| +| :---: | + +this file is generated by [.release](https://github.com/msimerson/.release). +Contribute to this project to get your GitHub profile included here. diff --git a/lib/config.js b/lib/config.js index 08e6962..d636954 100644 --- a/lib/config.js +++ b/lib/config.js @@ -12,7 +12,7 @@ class Config { this.getEnv(opts) } - async getEnv(opts = {}) { + getEnv(opts = {}) { this.env = process.env.NODE_ENV ?? opts.env ?? '' this.debug = Boolean(process.env.NODE_DEBUG) if (this.debug) console.log(`debug: true, env: ${this.env}`) diff --git a/lib/config.test.js b/lib/config.test.js index d223605..ea7740c 100644 --- a/lib/config.test.js +++ b/lib/config.test.js @@ -39,15 +39,12 @@ describe('config', () => { it(`detects NODE_DEBUG env`, async () => { process.env.NODE_DEBUG = 1 - let cfg = await Config.get('mysql', 'test') + await Config.get('mysql', 'test') assert.equal(Config.debug, true) process.env.NODE_DEBUG = '' - cfg = await Config.get('mysql', 'test') + await Config.get('mysql', 'test') assert.equal(Config.debug, false) - - cfg = await Config.get('mysql', 'test') - assert.equal(cfg.user, 'root') }) }) }) diff --git a/lib/group.js b/lib/group.js index 332a5de..64ecc0e 100644 --- a/lib/group.js +++ b/lib/group.js @@ -15,9 +15,7 @@ class Group { if (g.length === 1) return g[0].id } - return await Mysql.execute( - ...Mysql.insert(`nt_group`, mapToDbColumn(args, groupDbMap)), - ) + return await Mysql.execute(...Mysql.insert(`nt_group`, mapToDbColumn(args, groupDbMap))) } async get(args) { @@ -48,11 +46,7 @@ class Group { const id = args.id delete args.id const r = await Mysql.execute( - ...Mysql.update( - `nt_group`, - `nt_group_id=${id}`, - mapToDbColumn(args, groupDbMap), - ), + ...Mysql.update(`nt_group`, `nt_group_id=${id}`, mapToDbColumn(args, groupDbMap)), ) return r.changedRows === 1 } @@ -67,9 +61,7 @@ class Group { } async destroy(args) { - const r = await Mysql.execute( - ...Mysql.delete(`nt_group`, { nt_group_id: args.id }), - ) + const r = await Mysql.execute(...Mysql.delete(`nt_group`, { nt_group_id: args.id })) return r.affectedRows === 1 } } diff --git a/lib/mysql.js b/lib/mysql.js index b55f35c..b72ddfc 100644 --- a/lib/mysql.js +++ b/lib/mysql.js @@ -18,8 +18,7 @@ class Mysql { if (_debug) console.log(cfg) this.dbh = await mysql.createConnection(cfg) - if (_debug) - console.log(`MySQL connection id ${this.dbh.connection.connectionId}`) + if (_debug) console.log(`MySQL connection id ${this.dbh.connection.connectionId}`) return this.dbh } @@ -54,10 +53,7 @@ class Mysql { } update(table, where, params = {}) { - return [ - `UPDATE ${table} SET ${Object.keys(params).join('=?,')}=? WHERE ${where}`, - Object.values(params), - ] + return [`UPDATE ${table} SET ${Object.keys(params).join('=?,')}=? WHERE ${where}`, Object.values(params)] } delete(table, params) { diff --git a/lib/mysql.test.js b/lib/mysql.test.js index 5bb305c..95e1047 100644 --- a/lib/mysql.test.js +++ b/lib/mysql.test.js @@ -34,10 +34,7 @@ describe('mysql', () => { first_name: 'uNite', last_name: 'Test', }) - assert.deepEqual(r, [ - `INSERT INTO nt_user (first_name,last_name) VALUES(?,?)`, - ['uNite', 'Test'], - ]) + assert.deepEqual(r, [`INSERT INTO nt_user (first_name,last_name) VALUES(?,?)`, ['uNite', 'Test']]) }) describe('update', () => { @@ -45,10 +42,7 @@ describe('mysql', () => { const r = Mysql.update(`nt_user`, `nt_user_id=4096`, { first_name: 'uNite', }) - assert.deepEqual(r, [ - `UPDATE nt_user SET first_name=? WHERE nt_user_id=4096`, - ['uNite'], - ]) + assert.deepEqual(r, [`UPDATE nt_user SET first_name=? WHERE nt_user_id=4096`, ['uNite']]) }) it('formats with two values', () => { @@ -56,10 +50,7 @@ describe('mysql', () => { last_name: 'Teste', is_admin: 1, }) - assert.deepEqual(r, [ - `UPDATE nt_user SET last_name=?,is_admin=? WHERE nt_user_id=4096`, - ['Teste', 1], - ]) + assert.deepEqual(r, [`UPDATE nt_user SET last_name=?,is_admin=? WHERE nt_user_id=4096`, ['Teste', 1]]) }) it('formats with three values', () => { diff --git a/lib/nameserver.js b/lib/nameserver.js index f349b98..84a99f3 100644 --- a/lib/nameserver.js +++ b/lib/nameserver.js @@ -26,12 +26,7 @@ class Nameserver { delete args.export.type } - return await Mysql.execute( - ...Mysql.insert( - `nt_nameserver`, - mapToDbColumn(objectToDb(args), nsDbMap), - ), - ) + return await Mysql.execute(...Mysql.insert(`nt_nameserver`, mapToDbColumn(objectToDb(args), nsDbMap))) } async get(args) { @@ -79,11 +74,7 @@ class Nameserver { delete args.id // Mysql.debug(1) const r = await Mysql.execute( - ...Mysql.update( - `nt_nameserver`, - `nt_nameserver_id=${id}`, - mapToDbColumn(args, nsDbMap), - ), + ...Mysql.update(`nt_nameserver`, `nt_nameserver_id=${id}`, mapToDbColumn(args, nsDbMap)), ) return r.changedRows === 1 } @@ -98,9 +89,7 @@ class Nameserver { } async destroy(args) { - const r = await Mysql.execute( - ...Mysql.delete(`nt_nameserver`, { nt_nameserver_id: args.id }), - ) + const r = await Mysql.execute(...Mysql.delete(`nt_nameserver`, { nt_nameserver_id: args.id })) return r.affectedRows === 1 } } @@ -109,14 +98,7 @@ export default new Nameserver() function dbToObject(rows) { for (const row of rows) { - for (const f of [ - 'description', - 'address6', - 'remote_login', - 'datadir', - 'logdir', - 'export_status', - ]) { + for (const f of ['description', 'address6', 'remote_login', 'datadir', 'logdir', 'export_status']) { if ([undefined, null].includes(row[f])) row[f] = '' } for (const f of ['export']) { diff --git a/lib/nameserver.test.js b/lib/nameserver.test.js index 619b5eb..173a19c 100644 --- a/lib/nameserver.test.js +++ b/lib/nameserver.test.js @@ -27,9 +27,7 @@ describe('nameserver', function () { }) it('changes a nameserver', async () => { - assert.ok( - await Nameserver.put({ id: testCase.id, name: 'b.ns.example.com.' }), - ) + assert.ok(await Nameserver.put({ id: testCase.id, name: 'b.ns.example.com.' })) const ns = await Nameserver.get({ id: testCase.id }) assert.deepEqual(ns[0].name, 'b.ns.example.com.') assert.ok(await Nameserver.put({ id: testCase.id, name: testCase.name })) diff --git a/lib/permission.js b/lib/permission.js index 84cc41d..c9e09c9 100644 --- a/lib/permission.js +++ b/lib/permission.js @@ -20,9 +20,7 @@ class Permission { if (p) return p.id } - return await Mysql.execute( - ...Mysql.insert(`nt_perm`, mapToDbColumn(objectToDb(args), permDbMap)), - ) + return await Mysql.execute(...Mysql.insert(`nt_perm`, mapToDbColumn(objectToDb(args), permDbMap))) } async get(args) { @@ -38,14 +36,10 @@ class Permission { , p.deleted FROM nt_perm p` - const rows = await Mysql.execute( - ...Mysql.select(query, mapToDbColumn(args, permDbMap)), - ) + const rows = await Mysql.execute(...Mysql.select(query, mapToDbColumn(args, permDbMap))) if (rows.length === 0) return if (rows.length > 1) { - throw new Error( - `permissions.get found ${rows.length} rows for uid ${args.uid}`, - ) + throw new Error(`permissions.get found ${rows.length} rows for uid ${args.uid}`) } const row = dbToObject(rows[0]) if (args.deleted === false) delete row.deleted @@ -76,11 +70,7 @@ class Permission { const id = args.id delete args.id const r = await Mysql.execute( - ...Mysql.update( - `nt_perm`, - `nt_perm_id=${id}`, - mapToDbColumn(args, permDbMap), - ), + ...Mysql.update(`nt_perm`, `nt_perm_id=${id}`, mapToDbColumn(args, permDbMap)), ) return r.changedRows === 1 } @@ -96,9 +86,7 @@ class Permission { } async destroy(args) { - const r = await Mysql.execute( - ...Mysql.delete(`nt_perm`, mapToDbColumn(args, permDbMap)), - ) + const r = await Mysql.execute(...Mysql.delete(`nt_perm`, mapToDbColumn(args, permDbMap))) return r.affectedRows === 1 } } diff --git a/lib/permission.test.js b/lib/permission.test.js index 20eb8a4..be5821f 100644 --- a/lib/permission.test.js +++ b/lib/permission.test.js @@ -24,40 +24,26 @@ describe('permission', function () { }) it('get: by id', async () => { - assert.deepEqual( - await Permission.get({ id: permTestCase.id }), - permTestCase, - ) + assert.deepEqual(await Permission.get({ id: permTestCase.id }), permTestCase) }) it('get: by user id', async () => { - assert.deepEqual( - await Permission.get({ uid: permTestCase.user.id }), - permTestCase, - ) + assert.deepEqual(await Permission.get({ uid: permTestCase.user.id }), permTestCase) }) it('get: by group id', async () => { - assert.deepEqual( - await Permission.get({ gid: permTestCase.group.id }), - permTestCase, - ) + assert.deepEqual(await Permission.get({ gid: permTestCase.group.id }), permTestCase) }) it('getGroup: gets group permissions', async () => { - assert.deepEqual( - await Permission.getGroup({ uid: permTestCase.user.id }), - permTestCase, - ) + assert.deepEqual(await Permission.getGroup({ uid: permTestCase.user.id }), permTestCase) }) it('changes a permission', async () => { assert.ok(await Permission.put({ id: permTestCase.id, name: 'Changed' })) const perm = await Permission.get({ id: permTestCase.id }) assert.deepEqual(perm.name, 'Changed') - assert.ok( - await Permission.put({ id: permTestCase.id, name: 'Test Permission' }), - ) + assert.ok(await Permission.put({ id: permTestCase.id, name: 'Test Permission' })) }) it('deletes a permission', async () => { diff --git a/lib/session.js b/lib/session.js index 31fd11e..95efcd6 100644 --- a/lib/session.js +++ b/lib/session.js @@ -16,9 +16,7 @@ class Session { const r = await this.get(args) if (r) return r.id - const id = await Mysql.execute( - ...Mysql.insert(`nt_user_session`, mapToDbColumn(args, sessionDbMap)), - ) + const id = await Mysql.execute(...Mysql.insert(`nt_user_session`, mapToDbColumn(args, sessionDbMap))) return id } @@ -67,20 +65,14 @@ class Session { const id = args.id delete args.id const r = await Mysql.execute( - ...Mysql.update( - `nt_user_session`, - `nt_user_session_id=${id}`, - mapToDbColumn(args, sessionDbMap), - ), + ...Mysql.update(`nt_user_session`, `nt_user_session_id=${id}`, mapToDbColumn(args, sessionDbMap)), ) // console.log(r) return r.changedRows === 1 } async delete(args) { - const r = await Mysql.execute( - ...Mysql.delete(`nt_user_session`, mapToDbColumn(args, sessionDbMap)), - ) + const r = await Mysql.execute(...Mysql.delete(`nt_user_session`, mapToDbColumn(args, sessionDbMap))) return r.affectedRows === 1 } } diff --git a/lib/session.test.js b/lib/session.test.js index 904fb31..288b4c4 100644 --- a/lib/session.test.js +++ b/lib/session.test.js @@ -5,11 +5,20 @@ import User from './user.js' import Session from './session.js' import userCase from './test/user.json' with { type: 'json' } +const sessionUser = { + ...userCase, + id: userCase.id + 100, + username: `${userCase.username}-session`, + email: `session-${userCase.email}`, +} + before(async () => { - await User.create(userCase) + await User.create(sessionUser) }) after(async () => { + await Session.delete({ uid: sessionUser.id }) + await User.destroy({ id: sessionUser.id }) await User.mysql.disconnect() }) @@ -20,7 +29,7 @@ describe('session', function () { describe('create', () => { it('creates a login session', async () => { sessionId = await Session.create({ - nt_user_id: userCase.id, + nt_user_id: sessionUser.id, session: '3.0.0', last_access: parseInt(Date.now() / 1000, 10), }) @@ -31,7 +40,6 @@ describe('session', function () { describe('get', () => { it('finds a session by id', async () => { const s = await Session.get({ id: sessionId }) - // console.log(s) assert.ok(s?.id) }) diff --git a/lib/test/nameserver.json b/lib/test/nameserver.json index 39e76ab..934ecbd 100644 --- a/lib/test/nameserver.json +++ b/lib/test/nameserver.json @@ -12,7 +12,7 @@ "interval": 0, "serials": true, "status": "last run:03-05 15:25
last cp :09-20 12:59", - "type": "NSD" + "type": "nsd" }, "ttl": 3600 } diff --git a/lib/user.js b/lib/user.js index 208dd7b..a5ac0ad 100644 --- a/lib/user.js +++ b/lib/user.js @@ -37,14 +37,7 @@ class User { AND g.name = ?` for (const u of await Mysql.execute(query, [username, groupName])) { - if ( - await this.validPassword( - authTry.password, - u.password, - authTry.username, - u.pass_salt, - ) - ) { + if (await this.validPassword(authTry.password, u.password, authTry.username, u.pass_salt)) { for (const f of ['password', 'pass_salt']) { delete u[f] // SECURITY: no longer needed } @@ -73,9 +66,7 @@ class User { args.password = await this.hashAuthPbkdf2(args.password, args.pass_salt) } - const userId = await Mysql.execute( - ...Mysql.insert(`nt_user`, mapToDbColumn(args, userDbMap)), - ) + const userId = await Mysql.execute(...Mysql.insert(`nt_user`, mapToDbColumn(args, userDbMap))) return userId } @@ -111,11 +102,7 @@ class User { const id = args.id delete args.id const r = await Mysql.execute( - ...Mysql.update( - `nt_user`, - `nt_user_id=${id}`, - mapToDbColumn(args, userDbMap), - ), + ...Mysql.update(`nt_user`, `nt_user_id=${id}`, mapToDbColumn(args, userDbMap)), ) return r.changedRows === 1 } @@ -130,16 +117,12 @@ class User { } async destroy(args) { - const r = await Mysql.execute( - ...Mysql.delete(`nt_user`, mapToDbColumn({ id: args.id }, userDbMap)), - ) + const r = await Mysql.execute(...Mysql.delete(`nt_user`, mapToDbColumn({ id: args.id }, userDbMap))) return r.affectedRows === 1 } generateSalt(length = 16) { - const chars = Array.from({ length: 87 }, (_, i) => - String.fromCharCode(i + 40), - ) // ASCII 40-126 + const chars = Array.from({ length: 87 }, (_, i) => String.fromCharCode(i + 40)) // ASCII 40-126 let salt = '' for (let i = 0; i < length; i++) { salt += chars[Math.floor(Math.random() * 87)] @@ -168,10 +151,7 @@ class User { // Check for HMAC SHA-1 password if (/^[0-9a-f]{40}$/.test(passDb)) { - const digest = crypto - .createHmac('sha1', username.toLowerCase()) - .update(passTry) - .digest('hex') + const digest = crypto.createHmac('sha1', username.toLowerCase()).update(passTry).digest('hex') if (this.debug) console.log(`digest: (${digest === passDb}) ${digest}`) return digest === passDb } diff --git a/lib/zone.js b/lib/zone.js index c712da3..44e065e 100644 --- a/lib/zone.js +++ b/lib/zone.js @@ -15,9 +15,7 @@ class Zone { if (g.length === 1) return g[0].id } - return await Mysql.execute( - ...Mysql.insert(`nt_zone`, mapToDbColumn(args, zoneDbMap)), - ) + return await Mysql.execute(...Mysql.insert(`nt_zone`, mapToDbColumn(args, zoneDbMap))) } async get(args) { @@ -51,6 +49,8 @@ class Zone { for (const f of ['description', 'location']) { if ([null].includes(row[f])) row[f] = '' } + if (row['last_publish'] === undefined) delete row['last_publish'] + if (/00:00:00/.test(row['last_publish'])) row['last_publish'] = null if (args.deleted === false) delete row.deleted } @@ -62,11 +62,7 @@ class Zone { const id = args.id delete args.id const r = await Mysql.execute( - ...Mysql.update( - `nt_zone`, - `nt_zone_id=${id}`, - mapToDbColumn(args, zoneDbMap), - ), + ...Mysql.update(`nt_zone`, `nt_zone_id=${id}`, mapToDbColumn(args, zoneDbMap)), ) return r.changedRows === 1 } @@ -81,9 +77,7 @@ class Zone { } async destroy(args) { - const r = await Mysql.execute( - ...Mysql.delete(`nt_zone`, { nt_zone_id: args.id }), - ) + const r = await Mysql.execute(...Mysql.delete(`nt_zone`, { nt_zone_id: args.id })) return r.affectedRows === 1 } } diff --git a/lib/zone.test.js b/lib/zone.test.js index 01185de..c4be676 100644 --- a/lib/zone.test.js +++ b/lib/zone.test.js @@ -29,9 +29,7 @@ describe('zone', function () { }) it('changes a zone', async () => { - assert.ok( - await Zone.put({ id: testCase.id, mailaddr: 'toastmaster.example.com.' }), - ) + assert.ok(await Zone.put({ id: testCase.id, mailaddr: 'toastmaster.example.com.' })) const ns = await Zone.get({ id: testCase.id }) assert.deepEqual(ns[0].mailaddr, 'toastmaster.example.com.') assert.ok(await Zone.put({ id: testCase.id, mailaddr: testCase.mailaddr })) diff --git a/lib/zone_record.js b/lib/zone_record.js index c5745bb..25ae4e1 100644 --- a/lib/zone_record.js +++ b/lib/zone_record.js @@ -5,6 +5,8 @@ import { mapToDbColumn } from './util.js' const zrDbMap = { id: 'nt_zone_record_id', zid: 'nt_zone_id', owner: 'name' } const boolFields = ['deleted'] +const keepZeroWeightFor = new Set(['SRV', 'URI']) +const keepZeroPriorityFor = new Set(['HTTPS', 'SVCB', 'URI']) class ZoneRecord { constructor() { @@ -21,14 +23,16 @@ class ZoneRecord { args = objectToDb(args) - return await Mysql.execute( - ...Mysql.insert(`nt_zone_record`, mapToDbColumn(args, zrDbMap)), - ) + return await Mysql.execute(...Mysql.insert(`nt_zone_record`, mapToDbColumn(args, zrDbMap))) } async get(args) { args = JSON.parse(JSON.stringify(args)) if (args.deleted === undefined) args.deleted = false + if (args.type !== undefined) { + args.type_id = RR.typeMap[args.type] + delete args.type + } const rows = await Mysql.execute( ...Mysql.select( @@ -66,11 +70,7 @@ class ZoneRecord { const id = args.id delete args.id const r = await Mysql.execute( - ...Mysql.update( - `nt_zone_record`, - `nt_zone_record_id=${id}`, - mapToDbColumn(args, zrDbMap), - ), + ...Mysql.update(`nt_zone_record`, `nt_zone_record_id=${id}`, mapToDbColumn(args, zrDbMap)), ) return r.changedRows === 1 } @@ -85,9 +85,7 @@ class ZoneRecord { } async destroy(args) { - const r = await Mysql.execute( - ...Mysql.delete(`nt_zone_record`, { nt_zone_record_id: args.id }), - ) + const r = await Mysql.execute(...Mysql.delete(`nt_zone_record`, { nt_zone_record_id: args.id })) return r.affectedRows === 1 } } @@ -107,15 +105,21 @@ function dbToObject(rows) { const map = getMap(row.type) if (map) unApplyMap(row, map) - for (const f of [ - 'description', - 'other', - 'location', - 'weight', - 'priority', - 'timestamp', - ]) { - if (null === row[f]) delete row[f] + if ([null, ''].includes(row.description)) delete row.description + if ([null, '', '0'].includes(row.other)) delete row.other + if ([null, ''].includes(row.location)) delete row.location + if (row.timestamp === null) delete row.timestamp + + if (row.weight === null) { + delete row.weight + } else if (row.weight === 0 && !keepZeroWeightFor.has(row.type)) { + delete row.weight + } + + if (row.priority === null) { + delete row.priority + } else if (row.priority === 0 && !keepZeroPriorityFor.has(row.type)) { + delete row.priority } } @@ -162,12 +166,10 @@ function unApplyMap(obj, map) { delete map.address } if (obj.type === 'NSEC3') { - const [algo, flags, iters, salt, bitmaps, next] = obj.address - .slice(1, -1) - .split("','") - obj['hash algorithm'] = /^\d+$/.test(algo) ? parseInt(algo) : (algo ?? '') - obj.flags = /^\d+$/.test(flags) ? parseInt(flags) : (flags ?? '') - obj.iterations = /^\d+$/.test(iters) ? parseInt(iters) : (iters ?? '') + const [algo, flags, iters, salt, bitmaps, next] = obj.address.slice(1, -1).split("','") + obj['hash algorithm'] = /^\d+$/.test(algo) ? parseInt(algo) : algo ?? '' + obj.flags = /^\d+$/.test(flags) ? parseInt(flags) : flags ?? '' + obj.iterations = /^\d+$/.test(iters) ? parseInt(iters) : iters ?? '' obj.salt = salt obj['type bit maps'] = bitmaps obj['next hashed owner name'] = next @@ -176,17 +178,15 @@ function unApplyMap(obj, map) { } if (obj.type === 'NSEC3PARAM') { const [algo, flags, iters, salt] = obj.address.slice(1, -1).split("','") - obj['hash algorithm'] = /^\d+$/.test(algo) ? parseInt(algo) : (algo ?? '') - obj.flags = /^\d+$/.test(flags) ? parseInt(flags) : (flags ?? '') - obj.iterations = /^\d+$/.test(iters) ? parseInt(iters) : (iters ?? '') + obj['hash algorithm'] = /^\d+$/.test(algo) ? parseInt(algo) : algo ?? '' + obj.flags = /^\d+$/.test(flags) ? parseInt(flags) : flags ?? '' + obj.iterations = /^\d+$/.test(iters) ? parseInt(iters) : iters ?? '' obj.salt = salt delete obj.address delete map.address } if (obj.type === 'SOA') { - const [one, two, three, four, five, six, seven] = obj.address - .slice(1, -1) - .split("','") + const [one, two, three, four, five, six, seven] = obj.address.slice(1, -1).split("','") obj.mname = one obj.rname = two obj.serial = parseInt(three) @@ -289,14 +289,7 @@ function getMap(rrType) { } case 'NSEC3': return { - address: [ - 'hash algorithm', - 'flags', - 'iterations', - 'salt', - 'type bit maps', - 'next hashed owner name', - ], + address: ['hash algorithm', 'flags', 'iterations', 'salt', 'type bit maps', 'next hashed owner name'], } case 'NSEC3PARAM': return { @@ -320,15 +313,7 @@ function getMap(rrType) { } case 'SOA': return { - address: [ - 'mname', - 'rname', - 'serial', - 'refresh', - 'retry', - 'expire', - 'minimum', - ], + address: ['mname', 'rname', 'serial', 'refresh', 'retry', 'expire', 'minimum'], } case 'SPF': return { address: 'data' } diff --git a/lib/zone_record.test.js b/lib/zone_record.test.js index 3184bf0..ee0a4ff 100644 --- a/lib/zone_record.test.js +++ b/lib/zone_record.test.js @@ -35,7 +35,11 @@ describe('zone_record', function () { }) it('GET by name', async () => { - const zrs = await ZoneRecord.get({ zone_record: testCase.zone_record }) + const zrs = await ZoneRecord.get({ + owner: testCase.owner, + type: testCase.type, + zid: testCase.zid, + }) delete zrs[0].last_modified assert.deepEqual(zrs[0], testCase) }) diff --git a/package.json b/package.json index d85acaf..a8d72c0 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,10 @@ { "name": "@nictool/api", - "version": "3.0.0-alpha.6", + "version": "3.0.0-alpha.7", "description": "NicTool API", "main": "index.js", "type": "module", + "files": [ "CHANGELOG.md", "conf.d", "html", "lib", "routes", "sql", "server.js" ], "scripts": { "format": "npm run lint:fix && npm run prettier:fix", "lint": "npx eslint *.js **/*.js", @@ -13,6 +14,7 @@ "start": "NODE_ENV=production node ./server", "develop": "NODE_ENV=development node --watch server.js ./server", "test": "./test.sh", + "test:develop": "NODE_ENV=development ./test.sh", "versions": "npx dependency-version-checker check", "versions:fix": "npx dependency-version-checker update", "watch": "./test.sh watch" @@ -51,5 +53,11 @@ "mysql2": "^3.14.0", "qs": "^6.14.0", "yaml": "^2.7.1" + }, + "prettier": { + "printWidth": 110, + "semi": false, + "singleQuote": true, + "trailingComma": "all" } } \ No newline at end of file diff --git a/routes/group.test.js b/routes/group.test.js index d3d662a..00073e7 100644 --- a/routes/group.test.js +++ b/routes/group.test.js @@ -23,7 +23,7 @@ after(async () => { }) describe('group routes', () => { - let auth = { headers: { } } + let auth = { headers: {} } it('POST /session establishes a session', async () => { const res = await server.inject({ diff --git a/routes/index.js b/routes/index.js index b33c66a..f4a1ba1 100644 --- a/routes/index.js +++ b/routes/index.js @@ -40,10 +40,7 @@ async function setup() { routes: { cors: true, files: { - relativeTo: path.join( - path.dirname(url.fileURLToPath(import.meta.url)), - 'html', - ), + relativeTo: path.join(path.dirname(url.fileURLToPath(import.meta.url)), 'html'), }, }, }) @@ -113,9 +110,7 @@ async function setup() { server.events.on('request', (request, event, tags) => { if (tags.error) { - console.error( - `Request ${event.request} error: ${event.error ? event.error.message : 'unknown'}`, - ) + console.error(`Request ${event.request} error: ${event.error ? event.error.message : 'unknown'}`) } }) diff --git a/routes/nameserver.test.js b/routes/nameserver.test.js index c93038c..33ec97e 100644 --- a/routes/nameserver.test.js +++ b/routes/nameserver.test.js @@ -27,7 +27,7 @@ after(async () => { }) describe('nameserver routes', () => { - let auth = { headers: { } } + let auth = { headers: {} } it('POST /session establishes a session', async () => { const res = await server.inject({ diff --git a/routes/permission.test.js b/routes/permission.test.js index 3c4c7bb..730fd7a 100644 --- a/routes/permission.test.js +++ b/routes/permission.test.js @@ -26,7 +26,7 @@ after(async () => { }) describe('permission routes', () => { - let auth = { headers: { } } + let auth = { headers: {} } it('POST /session establishes a session', async () => { const res = await server.inject({ diff --git a/routes/session.test.js b/routes/session.test.js index 9e3bd1f..fc5859c 100644 --- a/routes/session.test.js +++ b/routes/session.test.js @@ -42,7 +42,7 @@ describe('session routes', () => { }) describe('with session, can retrieve private URIs', () => { - let auth = { headers: { } } + let auth = { headers: {} } before(async () => { const res = await server.inject({ diff --git a/routes/test/nameserver.json b/routes/test/nameserver.json index ee6237d..a5366be 100644 --- a/routes/test/nameserver.json +++ b/routes/test/nameserver.json @@ -12,7 +12,7 @@ "interval": 0, "serials": true, "status": "last run:03-05 15:25
last cp :09-20 12:59", - "type": "NSD" + "type": "nsd" }, "ttl": 3600, "deleted": false diff --git a/routes/user.test.js b/routes/user.test.js index 2a0e6d1..5d2fdbc 100644 --- a/routes/user.test.js +++ b/routes/user.test.js @@ -8,7 +8,8 @@ import Group from '../lib/group.js' import groupCase from './test/group.json' with { type: 'json' } import userCase from './test/user.json' with { type: 'json' } -let server, auth = { headers: { } } +let server, + auth = { headers: {} } before(async () => { server = await init() diff --git a/routes/zone.test.js b/routes/zone.test.js index 6f090cd..821548e 100644 --- a/routes/zone.test.js +++ b/routes/zone.test.js @@ -14,6 +14,7 @@ let server let case2Id = 4094 before(async () => { + await Zone.destroy({ id: nsCase.id }) await Zone.destroy({ id: case2Id }) await Group.create(groupCase) await User.create(userCase) @@ -27,7 +28,7 @@ after(async () => { }) describe('zone routes', () => { - let auth = { headers: { } } + let auth = { headers: {} } it('POST /session establishes a session', async () => { const res = await server.inject({ @@ -50,7 +51,7 @@ describe('zone routes', () => { }) // console.log(res.result) assert.equal(res.statusCode, 200) - assert.equal(res.result.zone[0].name, nsCase.name) + assert.equal(res.result.zone[0].zone, nsCase.zone) }) it(`POST /zone (${case2Id})`, async () => { diff --git a/sql/04_nt_nameserver.sql b/sql/04_nt_nameserver.sql index 2e4841f..afbe6d9 100644 --- a/sql/04_nt_nameserver.sql +++ b/sql/04_nt_nameserver.sql @@ -66,7 +66,7 @@ VALUES (1,'djbdns','djbdns (tinydns & axfrdns)','cr.yp.to/djbdns.html'), (3,'maradns','MaraDNS', 'maradns.samiam.org'), (4,'powerdns','PowerDNS','www.powerdns.com'), (5,'bind-nsupdate','BIND (nsupdate protocol)',''), - (6,'NSD','Name Server Daemon (NSD)','www.nlnetlabs.nl/projects/nsd/'), + (6,'nsd','Name Server Daemon (NSD)','www.nlnetlabs.nl/projects/nsd/'), (7,'dynect','DynECT Standard DNS','dyn.com/managed-dns/'), (8,'knot','Knot DNS','www.knot-dns.cz'); diff --git a/test-fixtures.js b/test-fixtures.js index 8d599df..c852a44 100644 --- a/test-fixtures.js +++ b/test-fixtures.js @@ -26,9 +26,7 @@ switch (process.argv[2]) { teardown() break default: - console.log( - `\nusage:\tnode ${path.basename(process.argv[1])} [ setup | teardown ]\n`, - ) + console.log(`\nusage:\tnode ${path.basename(process.argv[1])} [ setup | teardown ]\n`) } async function setup() {