diff --git a/cveClientlib.js b/cveClientlib.js index 0a050ff..4fcca59 100644 --- a/cveClientlib.js +++ b/cveClientlib.js @@ -5,7 +5,7 @@ class cveClient { this.key = key; this.url = url; this.user_path = "/org/" + this.org + "/user/" + this.user; - this._version = "1.0.15"; + this._version = "1.0.25"; } /* PUT /cve/{id}/adp — the only ADP endpoint per CVE Services API spec See https://cveawg.mitre.org/api-docs/ */ @@ -22,6 +22,8 @@ class cveClient { let path = "/cve/" + cve + "/cna"; if(rejected) path = "/cve/" + cve + "/reject"; + if(!cnajson["x_generator"]) + cnajson["x_generator"] = {engine: "cveClient/" + this._version}; return this.putjson(path,opts,null,{cnaContainer:cnajson}); } reservecve(amount,cve_year,batch_type) { diff --git a/cveInterface.js b/cveInterface.js index 2e9fd66..f5cddc7 100644 --- a/cveInterface.js +++ b/cveInterface.js @@ -639,10 +639,7 @@ async function download_json() { orgId: "00000000-0000-0000-0000-000000000000", shortName: "none", }; - if (get_deep(client, "constructor.name") && client._version) - returnJSON["x_generator"] = { - engine: client.constructor.name + "/" + client._version, - }; + returnJSON["x_generator"] = { engine: "cveClient/" + _version }; $("#cveUpdateModal .cveupdate").attr("download", cve + ".json"); let cson = encodeURIComponent(JSON.stringify(returnJSON)); $("#cveUpdateModal .cveupdate").attr( @@ -1817,10 +1814,7 @@ async function publish_cve() { orgId: client.userobj.org_UUID, shortName: client.org, }; - if (get_deep(client, "constructor.name") && client._version) - pubcve["x_generator"] = { - engine: client.constructor.name + "/" + client._version, - }; + pubcve["x_generator"] = { engine: "cveClient/" + _version }; let cve = mr.cve_id; let ispublic = mr.state != "RESERVED"; let rejected = false; @@ -2079,10 +2073,7 @@ async function reject_cve(confirm) { orgId: client.userobj.org_UUID, shortName: client.org, }; - if (get_deep(client, "constructor.name") && client._version) - rejcve["x_generator"] = { - engine: client.constructor.name + "/" + client._version, - }; + rejcve["x_generator"] = { engine: "cveClient/" + _version }; let cve = mr.cve_id; let ispublic = mr.state != "RESERVED"; let rejected = true; diff --git a/tests/api-client.test.js b/tests/api-client.test.js index ebc2037..e06ce9e 100644 --- a/tests/api-client.test.js +++ b/tests/api-client.test.js @@ -75,9 +75,9 @@ describe("cveClient — CVE operations", () => { await client.publishcve("CVE-2024-1234", { description: "test" }); expect(lastFetchUrl).toBe("https://api.example.com/cve/CVE-2024-1234/cna"); expect(lastFetchOpts.method).toBe("POST"); - expect(JSON.parse(lastFetchOpts.body)).toEqual({ - cnaContainer: { description: "test" }, - }); + const body = JSON.parse(lastFetchOpts.body); + expect(body.cnaContainer.description).toBe("test"); + expect(body.cnaContainer.x_generator.engine).toMatch(/^cveClient\//); }); it("publishcve uses PUT for update", async () => { @@ -122,6 +122,38 @@ describe("cveClient — CVE operations", () => { }); }); +describe("cveClient — x_generator", () => { + let client; + + beforeEach(() => { + client = new CveClient( + "test-org", + "test-user", + "key", + "https://api.example.com", + ); + }); + + it("injects default x_generator with cveClientlib version when not set", async () => { + const cnajson = { descriptions: [{ lang: "en", value: "test" }] }; + await client.publishcve("CVE-2024-1234", cnajson, true); + expect(cnajson["x_generator"]).toEqual({ + engine: "cveClient/" + client._version, + }); + }); + + it("preserves caller-provided x_generator (UI path)", async () => { + const cnajson = { + descriptions: [{ lang: "en", value: "test" }], + x_generator: { engine: "cveClient/1.0.25" }, + }; + await client.publishcve("CVE-2024-1234", cnajson, true); + expect(cnajson["x_generator"]).toEqual({ + engine: "cveClient/1.0.25", + }); + }); +}); + describe("cveClient — ADP operations", () => { let client;