diff --git a/.release b/.release index 0d06b1c..6ad30e5 160000 --- a/.release +++ b/.release @@ -1 +1 @@ -Subproject commit 0d06b1cbb2a5ef38840cd3d2346842795dc72865 +Subproject commit 6ad30e5df5fc026b332bbae7a0a4dfd47baf5898 diff --git a/CHANGELOG.md b/CHANGELOG.md index 37c4966..736616c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/). ### Unreleased +### [0.8.9] - 2026-03-29 + +- group: GET can return one group or array +- PUT added to: group, ns, user, zone, zr + ### [0.8.8] - 2026-03-25 - zone_rec: delete request has id in param @@ -108,7 +113,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/). [0.5.0]: https://github.com/NicTool/validate/releases/tag/0.5.0 [0.6.0]: https://github.com/NicTool/validate/releases/tag/0.6.0 [0.6.1]: https://github.com/NicTool/validate/releases/tag/0.6.1 -[0.6.3]: https://github.com/NicTool/validate/releases/tag/v0.6.3 +[0.6.3]: https://github.com/NicTool/validate/releases/tag/0.6.3 [0.7.0]: https://github.com/NicTool/validate/releases/tag/0.7.0 [0.7.1]: https://github.com/NicTool/validate/releases/tag/v0.7.1 [0.7.2]: https://github.com/NicTool/validate/releases/tag/v0.7.2 @@ -122,3 +127,4 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/). [0.8.5]: https://github.com/NicTool/validate/releases/tag/v0.8.5 [0.8.7]: https://github.com/NicTool/validate/releases/tag/v0.8.7 [0.8.8]: https://github.com/NicTool/validate/releases/tag/v0.8.8 +[0.8.9]: https://github.com/NicTool/validate/releases/tag/v0.8.9 diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 158d764..6fd2b97 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -2,7 +2,7 @@ This handcrafted artisanal software is brought to you by: -|
msimerson (27) | +|
msimerson (28) | | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | this file is generated by [.release](https://github.com/msimerson/.release). diff --git a/lib/group.js b/lib/group.js index b83329e..0e2e3cd 100644 --- a/lib/group.js +++ b/lib/group.js @@ -20,6 +20,7 @@ export const v3 = Joi.object({ deleted: Joi.boolean(), has_children: Joi.boolean(), permission: permission.v3, + usable_ns: Joi.array().items(shared.uint32), }) // legacy group format @@ -36,15 +37,39 @@ export const GET_req = Joi.object({ id: pid, name: name, deleted: Joi.boolean(), + include_subgroups: Joi.boolean(), +}) + +const groupItem = Joi.object({ + id: pid, + name: name, + parent_gid: pid, + deleted: Joi.boolean(), + permissions: permission.v3, }) export const GET_res = Joi.object({ - group: Joi.object({ - id: pid, - name: name, - parent_gid: pid, - deleted: Joi.boolean(), - }), + group: Joi.alternatives().try(groupItem, Joi.array().items(groupItem)), + meta: shared.meta, +}) + +export const GET_list_req = Joi.object({ + parent_gid: pid, + name: name, + deleted: Joi.boolean(), + include_subgroups: Joi.boolean(), +}) + +export const GET_list_res = Joi.object({ + group: Joi.array().items( + Joi.object({ + id: pid, + name: name, + parent_gid: pid, + deleted: Joi.boolean(), + permissions: permission.v3, + }), + ), meta: shared.meta, }) @@ -53,6 +78,14 @@ export const POST = Joi.object({ name: name, parent_gid: pid, deleted: Joi.boolean(), + usable_ns: Joi.array().items(shared.uint32), +}) + +export const PUT = Joi.object({ + name: name, + parent_gid: pid, + deleted: Joi.boolean(), + usable_ns: Joi.array().items(shared.uint32), }) export const DELETE = Joi.object({ diff --git a/lib/nameserver.js b/lib/nameserver.js index 2514ada..dce8a4d 100644 --- a/lib/nameserver.js +++ b/lib/nameserver.js @@ -45,17 +45,41 @@ export const v3 = Joi.object({ export const GET_req = Joi.object({ id: id, name: name, + gid: shared.uint32, deleted: Joi.boolean(), }) -export const GET_res = Joi.object({ - nameserver: Joi.array().items(v3), - meta: shared.meta, -}) - export const POST = v3 +export const PUT = Joi.object({ + name: name, + ttl: shared.ttl, + description: Joi.string().empty('').max(255), + address: shared.ipv4, + address6: shared.ipv6.empty(''), + remote_login: remote_login, + export: Joi.object({ + interval: shared.uint16, + serials: Joi.boolean(), + status: Joi.string().empty('').max(255), + type: type, + }), + deleted: Joi.boolean(), +}) + export const DELETE = Joi.object({ id: id, deleted: Joi.boolean(), }) + +// GET_res uses a looser name check so records with legacy/missing trailing dots +// don't fail the entire response. +const v3_out = v3 + .fork(['name'], () => Joi.string().min(1).max(255).allow('')) + .fork(['address'], () => shared.ipv4.allow('').optional()) + .fork(['gid', 'ttl'], (s) => s.optional()) + +export const GET_res = Joi.object({ + nameserver: Joi.array().items(v3_out), + meta: shared.meta, +}) diff --git a/lib/permission.js b/lib/permission.js index e08a2e4..b321264 100644 --- a/lib/permission.js +++ b/lib/permission.js @@ -2,12 +2,12 @@ import Joi from 'joi' import * as shared from './shared.js' -export const id = Joi.number().integer().min(1).max(4294967295) +export const id = Joi.number().integer().min(0).max(4294967295) export const v3 = Joi.object({ id: id, - name: Joi.string().empty(''), - inherit: Joi.boolean(), + name: Joi.string().allow('', null), + inherit: Joi.boolean().allow(null), self_write: Joi.boolean(), deleted: Joi.boolean(), group: Joi.object({ @@ -17,13 +17,13 @@ export const v3 = Joi.object({ delete: Joi.boolean(), }), user: Joi.object({ - id: id, + id: id.allow(null), write: Joi.boolean(), create: Joi.boolean(), delete: Joi.boolean(), }), nameserver: Joi.object({ - usable: Joi.array().items(Joi.number().integer().positive()), + usable: Joi.array().items(Joi.number().integer().min(0)), write: Joi.boolean(), create: Joi.boolean(), delete: Joi.boolean(), diff --git a/lib/session.js b/lib/session.js index bc4336d..a20d93b 100644 --- a/lib/session.js +++ b/lib/session.js @@ -8,7 +8,7 @@ export const id = shared.uint32 export const POST = Joi.object({ username: user.username.required(), - password: user.password.required(), + password: Joi.string().min(1).required(), }) export const GET_res = Joi.object({ diff --git a/lib/user.js b/lib/user.js index 5f415a5..91d8cc1 100644 --- a/lib/user.js +++ b/lib/user.js @@ -4,6 +4,7 @@ const JoiPassword = Joi.extend(joiPasswordExtendCore) import * as shared from './shared.js' import * as group from './group.js' +import * as permission from './permission.js' export const id = Joi.number().integer().min(1).max(4294967295) @@ -30,11 +31,15 @@ export const v3 = Joi.object({ password: password, is_admin: Joi.boolean(), deleted: Joi.boolean(), + permissions: permission.v3, + inherit_group_permissions: Joi.boolean(), }) export const GET_req = Joi.object({ id: id, + gid: group.id, deleted: Joi.boolean(), + include_subgroups: Joi.boolean(), }) export const GET_res = Joi.object({ @@ -55,6 +60,18 @@ export const POST = Joi.object({ email: email, password: password, is_admin: Joi.boolean(), + inherit_group_permissions: Joi.boolean(), +}) + +export const PUT = Joi.object({ + first_name: Joi.string().min(1), + last_name: Joi.string().min(1), + username: username, + email: email, + password: password, + is_admin: Joi.boolean(), + deleted: Joi.boolean(), + inherit_group_permissions: Joi.boolean(), }) export const DELETE = Joi.object({ diff --git a/lib/zone.js b/lib/zone.js index 402ac3a..2873b81 100644 --- a/lib/zone.js +++ b/lib/zone.js @@ -8,7 +8,7 @@ export const zone = Joi.string().min(3).max(255) // .domain({ allowFullyQualified: true, allowUnderscore: true, tlds: false }) export const v3 = Joi.object({ - id: id, + id, gid: shared.uint32.required(), @@ -41,6 +41,7 @@ export const v3 = Joi.object({ export const GET_req = Joi.object({ id: id, + gid: shared.uint32, zone: zone, search: Joi.string().max(255).allow(''), zone_like: Joi.string().max(255).allow(''), @@ -50,16 +51,38 @@ export const GET_req = Joi.object({ sort_by: Joi.string().valid('id', 'zone', 'description', 'last_modified'), sort_dir: Joi.string().lowercase().valid('asc', 'desc'), deleted: Joi.boolean(), +}).options({ allowUnknown: true }) + +export const GET_ns_res = Joi.object({ + ns: Joi.array().items( + Joi.object({ + owner: Joi.string().required(), + ttl: shared.ttl.required(), + dname: Joi.string().required(), + }), + ), + meta: shared.meta, }) export const GET_res = Joi.object({ zone: Joi.array().items(v3), meta: shared.meta, + deleted: Joi.boolean(), }) export const POST = v3 -export const DELETE = Joi.object({ - id: id, +export const PUT = Joi.object({ + description: Joi.string().empty('').allow(null), + mailaddr: Joi.string().empty('').allow(null), + ttl: shared.ttl, + refresh: shared.int32, + retry: shared.int32, + expire: shared.int32, + minimum: shared.int32, deleted: Joi.boolean(), }) + +export const DELETE = Joi.object({ + id, +}) diff --git a/lib/zone_record.js b/lib/zone_record.js index 99516b7..d5be903 100644 --- a/lib/zone_record.js +++ b/lib/zone_record.js @@ -227,7 +227,7 @@ export const GET_req = Joi.object({ id: shared.uint32, zid: shared.uint32, deleted: Joi.boolean(), -}) +}).options({ allowUnknown: true }) export const GET_res = Joi.object({ zone_record: Joi.array().items(v3), @@ -236,6 +236,8 @@ export const GET_res = Joi.object({ export const POST = v3.fork(['id', 'ttl'], (schema) => schema.optional()) +export const PUT = v3.fork(['id', 'zid', 'owner', 'ttl', 'type'], (schema) => schema.optional()) + export const DELETE = Joi.object({ deleted: Joi.boolean(), }) diff --git a/package.json b/package.json index 1e4acb3..20ac64c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@nictool/validate", - "version": "0.8.8", + "version": "0.8.9", "description": "NicTool Object Validation", "type": "module", "files": [ @@ -19,7 +19,7 @@ }, "scripts": { "format:check": "npm run prettier; npm run lint", - "format": "npm run prettier -- --write && npm run lint --fix", + "format": "npm run prettier -- --write && npm run lint:fix", "lint": "npx eslint .", "lint:fix": "npx eslint --fix .", "prettier": "npx prettier --ignore-path .gitignore --check .",