diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d51dd18d7..0e37c68164 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ _This release is scheduled to be released on 2024-01-01._ ### Added - Added node 21 to the test matrix +- Added configuration option for `User-Agent`, used by calendar & news module ### Removed diff --git a/js/server_functions.js b/js/server_functions.js index 5693ad41c4..425fd38776 100644 --- a/js/server_functions.js +++ b/js/server_functions.js @@ -68,7 +68,7 @@ async function cors(req, res) { * @returns {object} An object specifying name and value of the headers. */ function getHeadersToSend(url) { - const headersToSend = { "User-Agent": `Mozilla/5.0 MagicMirror/${global.version}` }; + const headersToSend = { "User-Agent": getUserAgent() }; const headersToSendMatch = new RegExp("sendheaders=(.+?)(&|$)", "g").exec(url); if (headersToSendMatch) { const headers = headersToSendMatch[1].split(","); @@ -127,4 +127,25 @@ function getVersion(req, res) { res.send(global.version); } -module.exports = { cors, getConfig, getHtml, getVersion, getStartup }; +/** + * Gets the preferred `User-Agent` + * @returns {string} `User-Agent` to be used + */ +function getUserAgent() { + const defaultUserAgent = `Mozilla/5.0 (Node.js ${Number(process.version.match(/^v(\d+\.\d+)/)[1])}) MagicMirror/${global.version}`; + + if (typeof config === "undefined") { + return defaultUserAgent; + } + + switch (typeof config.userAgent) { + case "function": + return config.userAgent(); + case "string": + return config.userAgent; + default: + return defaultUserAgent; + } +} + +module.exports = { cors, getConfig, getHtml, getVersion, getStartup, getUserAgent }; diff --git a/modules/default/calendar/calendarfetcher.js b/modules/default/calendar/calendarfetcher.js index 51db30d7c7..23ad1c5a3e 100644 --- a/modules/default/calendar/calendarfetcher.js +++ b/modules/default/calendar/calendarfetcher.js @@ -9,6 +9,7 @@ const https = require("https"); const ical = require("node-ical"); const Log = require("logger"); const NodeHelper = require("node_helper"); +const { getUserAgent } = require("../../../js/server_functions"); const CalendarFetcherUtils = require("./calendarfetcherutils"); /** @@ -36,10 +37,9 @@ const CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumEn const fetchCalendar = () => { clearTimeout(reloadTimer); reloadTimer = null; - const nodeVersion = Number(process.version.match(/^v(\d+\.\d+)/)[1]); let httpsAgent = null; let headers = { - "User-Agent": `Mozilla/5.0 (Node.js ${nodeVersion}) MagicMirror/${global.version}` + "User-Agent": getUserAgent() }; if (selfSignedCert) { diff --git a/modules/default/newsfeed/newsfeedfetcher.js b/modules/default/newsfeed/newsfeedfetcher.js index 0f1b5d6c6d..f4012c32bc 100644 --- a/modules/default/newsfeed/newsfeedfetcher.js +++ b/modules/default/newsfeed/newsfeedfetcher.js @@ -11,6 +11,7 @@ const iconv = require("iconv-lite"); const { htmlToText } = require("html-to-text"); const Log = require("logger"); const NodeHelper = require("node_helper"); +const { getUserAgent } = require("../../../js/server_functions"); /** * Responsible for requesting an update on the set interval and broadcasting the data. @@ -100,9 +101,8 @@ const NewsfeedFetcher = function (url, reloadInterval, encoding, logFeedWarnings } }); - const nodeVersion = Number(process.version.match(/^v(\d+\.\d+)/)[1]); const headers = { - "User-Agent": `Mozilla/5.0 (Node.js ${nodeVersion}) MagicMirror/${global.version}`, + "User-Agent": getUserAgent(), "Cache-Control": "max-age=0, no-cache, no-store, must-revalidate", Pragma: "no-cache" }; diff --git a/tests/unit/functions/server_functions_spec.js b/tests/unit/functions/server_functions_spec.js index 6242c9a9b5..54638ae16f 100644 --- a/tests/unit/functions/server_functions_spec.js +++ b/tests/unit/functions/server_functions_spec.js @@ -1,4 +1,5 @@ -const { cors } = require("../../../js/server_functions"); +const { expect } = require("playwright/test"); +const { cors, getUserAgent } = require("../../../js/server_functions"); describe("server_functions tests", () => { describe("The cors method", () => { @@ -142,5 +143,21 @@ describe("server_functions tests", () => { expect(corsResponse.set.mock.calls[2][0]).toBe("header2"); expect(corsResponse.set.mock.calls[2][1]).toBe("value2"); }); + + test("Gets User-Agent from configuration", async () => { + config = {}; + let userAgent; + + userAgent = getUserAgent(); + expect(userAgent).toContain("Mozilla/5.0 (Node.js "); + + config.userAgent = "Mozilla/5.0 (Foo)"; + userAgent = getUserAgent(); + expect(userAgent).toBe("Mozilla/5.0 (Foo)"); + + config.userAgent = () => "Mozilla/5.0 (Bar)"; + userAgent = getUserAgent(); + expect(userAgent).toBe("Mozilla/5.0 (Bar)"); + }); }); });