From 6bc0bd84afb9ca1e594c6632288bde3ddc30f4f9 Mon Sep 17 00:00:00 2001
From: Matthew Nickson
Date: Sun, 8 Jan 2023 20:39:27 +0000
Subject: [PATCH 01/94] Allowed markdown in footer of status page
Markdown support has been added using the marked module. To secure
against XSS attacks, DOMPurify is used to sanitize the generated HTML
before it is loaded on the page.
Signed-off-by: Matthew Nickson
---
package-lock.json | 28 ++++++++++++++++++++++++++++
package.json | 2 ++
src/languages/en.js | 1 +
src/pages/StatusPage.vue | 12 +++++++++++-
4 files changed, 42 insertions(+), 1 deletion(-)
diff --git a/package-lock.json b/package-lock.json
index 7e88d1269..3efce2541 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -26,6 +26,7 @@
"compare-versions": "~3.6.0",
"compression": "~1.7.4",
"dayjs": "~1.11.5",
+ "dompurify": "^2.4.3",
"express": "~4.17.3",
"express-basic-auth": "~1.2.1",
"express-static-gzip": "~2.1.7",
@@ -38,6 +39,7 @@
"jsonwebtoken": "~9.0.0",
"jwt-decode": "~3.1.2",
"limiter": "~2.1.0",
+ "marked": "^4.2.5",
"mqtt": "~4.3.7",
"mssql": "~8.1.4",
"mysql2": "~2.3.3",
@@ -6499,6 +6501,11 @@
"url": "https://github.com/fb55/domhandler?sponsor=1"
}
},
+ "node_modules/dompurify": {
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.3.tgz",
+ "integrity": "sha512-q6QaLcakcRjebxjg8/+NP+h0rPfatOgOzc46Fst9VAA3jF2ApfKBNKMzdP4DYTqtUMXSCd5pRS/8Po/OmoCHZQ=="
+ },
"node_modules/domutils": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
@@ -12185,6 +12192,17 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/marked": {
+ "version": "4.2.5",
+ "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.5.tgz",
+ "integrity": "sha512-jPueVhumq7idETHkb203WDD4fMA3yV9emQ5vLwop58lu8bTclMghBWcYAavlDqIEMaisADinV1TooIFCfqOsYQ==",
+ "bin": {
+ "marked": "bin/marked.js"
+ },
+ "engines": {
+ "node": ">= 12"
+ }
+ },
"node_modules/mathml-tag-names": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz",
@@ -22155,6 +22173,11 @@
"domelementtype": "^2.3.0"
}
},
+ "dompurify": {
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.3.tgz",
+ "integrity": "sha512-q6QaLcakcRjebxjg8/+NP+h0rPfatOgOzc46Fst9VAA3jF2ApfKBNKMzdP4DYTqtUMXSCd5pRS/8Po/OmoCHZQ=="
+ },
"domutils": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
@@ -26299,6 +26322,11 @@
"integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==",
"dev": true
},
+ "marked": {
+ "version": "4.2.5",
+ "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.5.tgz",
+ "integrity": "sha512-jPueVhumq7idETHkb203WDD4fMA3yV9emQ5vLwop58lu8bTclMghBWcYAavlDqIEMaisADinV1TooIFCfqOsYQ=="
+ },
"mathml-tag-names": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz",
diff --git a/package.json b/package.json
index ebe305f92..fcda34371 100644
--- a/package.json
+++ b/package.json
@@ -81,6 +81,7 @@
"compare-versions": "~3.6.0",
"compression": "~1.7.4",
"dayjs": "~1.11.5",
+ "dompurify": "^2.4.3",
"express": "~4.17.3",
"express-basic-auth": "~1.2.1",
"express-static-gzip": "~2.1.7",
@@ -93,6 +94,7 @@
"jsonwebtoken": "~9.0.0",
"jwt-decode": "~3.1.2",
"limiter": "~2.1.0",
+ "marked": "^4.2.5",
"mqtt": "~4.3.7",
"mssql": "~8.1.4",
"mysql2": "~2.3.3",
diff --git a/src/languages/en.js b/src/languages/en.js
index 8d07db6dc..5824ea4ab 100644
--- a/src/languages/en.js
+++ b/src/languages/en.js
@@ -675,4 +675,5 @@ export default {
"General Monitor Type": "General Monitor Type",
"Passive Monitor Type": "Passive Monitor Type",
"Specific Monitor Type": "Specific Monitor Type",
+ markdownSupported: "Markdown syntax supported",
};
diff --git a/src/pages/StatusPage.vue b/src/pages/StatusPage.vue
index 6cecf6682..6fbbe69a1 100644
--- a/src/pages/StatusPage.vue
+++ b/src/pages/StatusPage.vue
@@ -26,6 +26,9 @@
+
+ {{ $t("markdownSupported") }}
+
@@ -855,6 +856,15 @@ export default {
this.config.domainNameList.splice(index, 1);
},
+ /**
+ * Generate sanitized HTML from maintenance description
+ * @param {string} description
+ * @returns {string} Sanitized HTML
+ */
+ maintenanceHTML(description) {
+ return DOMPurify.sanitize(marked(description));
+ },
+
}
};
From a8f0f1d872b359e53efada97ab8f9e84a72b8cad Mon Sep 17 00:00:00 2001
From: Louis Lam
Date: Wed, 1 Feb 2023 15:51:33 +0800
Subject: [PATCH 04/94] Merge manually and remove to devDependencies
---
package-lock.json | 36 ++++++++++++++++++++++++++++++++++--
package.json | 4 ++--
src/lang/en.json | 1 +
3 files changed, 37 insertions(+), 4 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 9da629687..c1e2645fc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "uptime-kuma",
- "version": "1.19.5",
+ "version": "1.19.6",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "uptime-kuma",
- "version": "1.19.5",
+ "version": "1.19.6",
"license": "MIT",
"dependencies": {
"@grpc/grpc-js": "~1.7.3",
@@ -88,10 +88,12 @@
"cypress": "^10.1.0",
"delay": "^5.0.0",
"dns2": "~2.0.1",
+ "dompurify": "~2.4.3",
"eslint": "~8.14.0",
"eslint-plugin-vue": "~8.7.1",
"favico.js": "~0.3.10",
"jest": "~27.2.5",
+ "marked": "~4.2.5",
"postcss-html": "~1.5.0",
"postcss-rtlcss": "~3.7.2",
"postcss-scss": "~4.0.4",
@@ -7800,6 +7802,12 @@
"url": "https://github.com/fb55/domhandler?sponsor=1"
}
},
+ "node_modules/dompurify": {
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.3.tgz",
+ "integrity": "sha512-q6QaLcakcRjebxjg8/+NP+h0rPfatOgOzc46Fst9VAA3jF2ApfKBNKMzdP4DYTqtUMXSCd5pRS/8Po/OmoCHZQ==",
+ "dev": true
+ },
"node_modules/domutils": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
@@ -13613,6 +13621,18 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/marked": {
+ "version": "4.2.12",
+ "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.12.tgz",
+ "integrity": "sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw==",
+ "dev": true,
+ "bin": {
+ "marked": "bin/marked.js"
+ },
+ "engines": {
+ "node": ">= 12"
+ }
+ },
"node_modules/mathml-tag-names": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz",
@@ -24871,6 +24891,12 @@
"domelementtype": "^2.3.0"
}
},
+ "dompurify": {
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.3.tgz",
+ "integrity": "sha512-q6QaLcakcRjebxjg8/+NP+h0rPfatOgOzc46Fst9VAA3jF2ApfKBNKMzdP4DYTqtUMXSCd5pRS/8Po/OmoCHZQ==",
+ "dev": true
+ },
"domutils": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
@@ -29100,6 +29126,12 @@
"integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==",
"dev": true
},
+ "marked": {
+ "version": "4.2.12",
+ "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.12.tgz",
+ "integrity": "sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw==",
+ "dev": true
+ },
"mathml-tag-names": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz",
diff --git a/package.json b/package.json
index 1dc87f082..7a148ec2e 100644
--- a/package.json
+++ b/package.json
@@ -84,7 +84,6 @@
"compare-versions": "~3.6.0",
"compression": "~1.7.4",
"dayjs": "~1.11.5",
- "dompurify": "^2.4.3",
"express": "~4.17.3",
"express-basic-auth": "~1.2.1",
"express-static-gzip": "~2.1.7",
@@ -98,7 +97,6 @@
"jsonwebtoken": "~9.0.0",
"jwt-decode": "~3.1.2",
"limiter": "~2.1.0",
- "marked": "^4.2.5",
"mongodb": "~4.13.0",
"mqtt": "~4.3.7",
"mssql": "~8.1.4",
@@ -147,9 +145,11 @@
"cypress": "^10.1.0",
"delay": "^5.0.0",
"dns2": "~2.0.1",
+ "dompurify": "~2.4.3",
"eslint": "~8.14.0",
"eslint-plugin-vue": "~8.7.1",
"favico.js": "~0.3.10",
+ "marked": "~4.2.5",
"jest": "~27.2.5",
"postcss-html": "~1.5.0",
"postcss-rtlcss": "~3.7.2",
diff --git a/src/lang/en.json b/src/lang/en.json
index cab3dcea3..072e07201 100644
--- a/src/lang/en.json
+++ b/src/lang/en.json
@@ -25,6 +25,7 @@
"General Monitor Type": "General Monitor Type",
"Passive Monitor Type": "Passive Monitor Type",
"Specific Monitor Type": "Specific Monitor Type",
+ "markdownSupported": "Markdown syntax supported",
"pauseDashboardHome": "Pause",
"Pause": "Pause",
"Name": "Name",
From 3819266fa83605fac57eed55bc003bb07f7f5c50 Mon Sep 17 00:00:00 2001
From: Matthew Nickson
Date: Thu, 2 Feb 2023 17:55:40 +0000
Subject: [PATCH 05/94] Fixed style of links in markdown
Signed-off-by: Matthew Nickson
---
src/assets/app.scss | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/src/assets/app.scss b/src/assets/app.scss
index 7da76fff0..f550406fd 100644
--- a/src/assets/app.scss
+++ b/src/assets/app.scss
@@ -35,6 +35,11 @@ textarea.form-control {
color: $maintenance !important;
}
+.incident a,
+.bg-maintenance a {
+ color: inherit;
+}
+
.list-group {
border-radius: 0.75rem;
@@ -248,6 +253,11 @@ optgroup {
}
}
+ .incident a,
+ .bg-maintenance a {
+ color: inherit;
+ }
+
.form-control,
.form-control:focus,
.form-select,
From 29e24e0de96c20a598e41a8a500a8be5848664c4 Mon Sep 17 00:00:00 2001
From: c
Date: Sun, 8 Jan 2023 17:19:07 +0000
Subject: [PATCH 06/94] Feature - Added Optional Google Analytics tag for
Status Page.
---
db/patch-add-google-analytics-status-page-tag.sql | 4 ++++
server/database.js | 1 +
server/model/status_page.js | 2 ++
.../socket-handlers/status-page-socket-handler.js | 1 +
src/pages/StatusPage.vue | 15 +++++++++++++++
5 files changed, 23 insertions(+)
create mode 100644 db/patch-add-google-analytics-status-page-tag.sql
diff --git a/db/patch-add-google-analytics-status-page-tag.sql b/db/patch-add-google-analytics-status-page-tag.sql
new file mode 100644
index 000000000..15305ae25
--- /dev/null
+++ b/db/patch-add-google-analytics-status-page-tag.sql
@@ -0,0 +1,4 @@
+-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
+BEGIN TRANSACTION;
+ALTER TABLE status_page ADD google_analytics_tag_id TEXT;
+COMMIT;
diff --git a/server/database.js b/server/database.js
index 06b811537..52c701fb5 100644
--- a/server/database.js
+++ b/server/database.js
@@ -69,6 +69,7 @@ class Database {
"patch-ping-packet-size.sql": true,
"patch-maintenance-table2.sql": true,
"patch-add-gamedig-monitor.sql": true,
+ "patch-add-google-analytics-status-page-tag.sql": true
};
/**
diff --git a/server/model/status_page.js b/server/model/status_page.js
index 0dabf5ab1..8dbf1a8c2 100644
--- a/server/model/status_page.js
+++ b/server/model/status_page.js
@@ -225,6 +225,7 @@ class StatusPage extends BeanModel {
customCSS: this.custom_css,
footerText: this.footer_text,
showPoweredBy: !!this.show_powered_by,
+ googleAnalyticsId: this.google_analytics_tag_id
};
}
@@ -245,6 +246,7 @@ class StatusPage extends BeanModel {
customCSS: this.custom_css,
footerText: this.footer_text,
showPoweredBy: !!this.show_powered_by,
+ googleAnalyticsId: this.google_analytics_tag_id
};
}
diff --git a/server/socket-handlers/status-page-socket-handler.js b/server/socket-handlers/status-page-socket-handler.js
index 16d6ee73b..717aba9c4 100644
--- a/server/socket-handlers/status-page-socket-handler.js
+++ b/server/socket-handlers/status-page-socket-handler.js
@@ -163,6 +163,7 @@ module.exports.statusPageSocketHandler = (socket) => {
statusPage.custom_css = config.customCSS;
statusPage.show_powered_by = config.showPoweredBy;
statusPage.modified_date = R.isoDateTime();
+ statusPage.google_analytics_tag_id = config.googleAnalyticsId;
await R.store(statusPage);
diff --git a/src/pages/StatusPage.vue b/src/pages/StatusPage.vue
index 6cecf6682..40a8e7c97 100644
--- a/src/pages/StatusPage.vue
+++ b/src/pages/StatusPage.vue
@@ -64,6 +64,12 @@
+
+
+
+
+
+
{{ $t("Custom CSS") }}
@@ -294,6 +300,15 @@
{{ config.customCSS }}
+
+
+
+
+ window.dataLayer = window.dataLayer || [];
+ function gtag(){dataLayer.push(arguments);}
+ gtag('js', new Date());
+ gtag('config', '{{ config.googleAnalyticsId }}');
+
From 99c0b8cb710a41f9cb09c26a3caa497daf48e635 Mon Sep 17 00:00:00 2001
From: c
Date: Tue, 10 Jan 2023 20:25:45 +0000
Subject: [PATCH 07/94] Feature - Google Analytics - Addressing PR Comments.
---
server/database.js | 2 +-
server/model/status_page.js | 11 +++++++++--
server/modules/google-analytics.js | 11 +++++++++++
src/languages/en.js | 0
src/pages/StatusPage.vue | 9 ---------
5 files changed, 21 insertions(+), 12 deletions(-)
create mode 100644 server/modules/google-analytics.js
create mode 100644 src/languages/en.js
diff --git a/server/database.js b/server/database.js
index 52c701fb5..19c09a00f 100644
--- a/server/database.js
+++ b/server/database.js
@@ -69,7 +69,7 @@ class Database {
"patch-ping-packet-size.sql": true,
"patch-maintenance-table2.sql": true,
"patch-add-gamedig-monitor.sql": true,
- "patch-add-google-analytics-status-page-tag.sql": true
+ "patch-add-google-analytics-status-page-tag.sql": true,
};
/**
diff --git a/server/model/status_page.js b/server/model/status_page.js
index 8dbf1a8c2..2d90b6392 100644
--- a/server/model/status_page.js
+++ b/server/model/status_page.js
@@ -4,6 +4,7 @@ const cheerio = require("cheerio");
const { UptimeKumaServer } = require("../uptime-kuma-server");
const jsesc = require("jsesc");
const Maintenance = require("./maintenance");
+const googleAnalytics = require("../modules/google-analytics");
class StatusPage extends BeanModel {
@@ -53,6 +54,12 @@ class StatusPage extends BeanModel {
const head = $("head");
+ await StatusPage.getStatusPageData(statusPage).then( (page) => {
+ if (page.config?.googleAnalyticsId) {
+ head.append($(googleAnalytics.getGoogleAnalyticsScript(page.config.googleAnalyticsId)));
+ }
+ });
+
// OG Meta Tags
head.append(``);
head.append(``);
@@ -225,7 +232,7 @@ class StatusPage extends BeanModel {
customCSS: this.custom_css,
footerText: this.footer_text,
showPoweredBy: !!this.show_powered_by,
- googleAnalyticsId: this.google_analytics_tag_id
+ googleAnalyticsId: this.google_analytics_tag_id,
};
}
@@ -246,7 +253,7 @@ class StatusPage extends BeanModel {
customCSS: this.custom_css,
footerText: this.footer_text,
showPoweredBy: !!this.show_powered_by,
- googleAnalyticsId: this.google_analytics_tag_id
+ googleAnalyticsId: this.google_analytics_tag_id,
};
}
diff --git a/server/modules/google-analytics.js b/server/modules/google-analytics.js
new file mode 100644
index 000000000..55820a857
--- /dev/null
+++ b/server/modules/google-analytics.js
@@ -0,0 +1,11 @@
+let GoogleAnalytics = (() => {
+ function getGoogleAnalyticsScript(tagId) {
+ return "" +
+ "";
+ }
+ return {
+ getGoogleAnalyticsScript: getGoogleAnalyticsScript
+ };
+})();
+
+module.exports = GoogleAnalytics;
diff --git a/src/languages/en.js b/src/languages/en.js
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/pages/StatusPage.vue b/src/pages/StatusPage.vue
index 40a8e7c97..41aa7993d 100644
--- a/src/pages/StatusPage.vue
+++ b/src/pages/StatusPage.vue
@@ -300,15 +300,6 @@
{{ config.customCSS }}
-
-
-
-
- window.dataLayer = window.dataLayer || [];
- function gtag(){dataLayer.push(arguments);}
- gtag('js', new Date());
- gtag('config', '{{ config.googleAnalyticsId }}');
-
From 2b3a3895b399c606e65aca83e5ebc4376ba86b02 Mon Sep 17 00:00:00 2001
From: c
Date: Wed, 11 Jan 2023 21:44:31 +0000
Subject: [PATCH 08/94] Feature - Google Analytics - Use Regex to validate UA
as per https://support.google.com/analytics/answer/9310895
---
server/modules/google-analytics.js | 7 ++++++-
server/socket-handlers/status-page-socket-handler.js | 3 ++-
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/server/modules/google-analytics.js b/server/modules/google-analytics.js
index 55820a857..0a40076d3 100644
--- a/server/modules/google-analytics.js
+++ b/server/modules/google-analytics.js
@@ -3,8 +3,13 @@ let GoogleAnalytics = (() => {
return "" +
"";
}
+ function isValidTag(tagInput) {
+ const re = /^\w{1,2}-\d{8}$/g;
+ return tagInput.match(re) != null;
+ }
return {
- getGoogleAnalyticsScript: getGoogleAnalyticsScript
+ getGoogleAnalyticsScript: getGoogleAnalyticsScript,
+ isValidTag: isValidTag
};
})();
diff --git a/server/socket-handlers/status-page-socket-handler.js b/server/socket-handlers/status-page-socket-handler.js
index 717aba9c4..359ed15bd 100644
--- a/server/socket-handlers/status-page-socket-handler.js
+++ b/server/socket-handlers/status-page-socket-handler.js
@@ -7,6 +7,7 @@ const Database = require("../database");
const apicache = require("../modules/apicache");
const StatusPage = require("../model/status_page");
const { UptimeKumaServer } = require("../uptime-kuma-server");
+const googleAnalytics = require("../modules/google-analytics");
/**
* Socket handlers for status page
@@ -163,7 +164,7 @@ module.exports.statusPageSocketHandler = (socket) => {
statusPage.custom_css = config.customCSS;
statusPage.show_powered_by = config.showPoweredBy;
statusPage.modified_date = R.isoDateTime();
- statusPage.google_analytics_tag_id = config.googleAnalyticsId;
+ statusPage.google_analytics_tag_id = googleAnalytics.isValidTag(config.googleAnalyticsId) ? config.googleAnalyticsId : "";
await R.store(statusPage);
From fb2999706c74de3c891ad8cd554fd1d82d895586 Mon Sep 17 00:00:00 2001
From: c
Date: Thu, 12 Jan 2023 00:02:11 +0000
Subject: [PATCH 09/94] Feature - Google Analytics - Added JSDoc to Google
Analytics functions.
---
server/modules/google-analytics.js | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/server/modules/google-analytics.js b/server/modules/google-analytics.js
index 0a40076d3..2c10e5841 100644
--- a/server/modules/google-analytics.js
+++ b/server/modules/google-analytics.js
@@ -1,8 +1,22 @@
let GoogleAnalytics = (() => {
+ /**
+ * Returns a string that represents the javascript that is required to insert the Google Analytics scripts
+ * into a webpage.
+ * @param tagId Google UA/G/AW/DC Property ID to use with the Google Analytics script.
+ * @returns {string}
+ */
function getGoogleAnalyticsScript(tagId) {
return "" +
"";
}
+
+ /**
+ * Returns true if the tag conforms to the format of 1-2 Letters followed by a dash and 8 numbers.
+ * This should take care of the following property tag formats:
+ * UA-########, G-########, AW-########, DC-########
+ * @param {String} tagInput Google UA/G/AW/DC Property ID
+ * @returns {boolean}
+ */
function isValidTag(tagInput) {
const re = /^\w{1,2}-\d{8}$/g;
return tagInput.match(re) != null;
From 3ff0cbe3116185afb316e3b14db33e701c52765b Mon Sep 17 00:00:00 2001
From: c
Date: Thu, 12 Jan 2023 13:17:26 +0000
Subject: [PATCH 10/94] Feature - Google Analytics - Simplified Module &
Escaped the Script to prevent XXS.
---
server/model/status_page.js | 5 ++-
server/modules/google-analytics.js | 53 ++++++++++++++----------------
2 files changed, 29 insertions(+), 29 deletions(-)
diff --git a/server/model/status_page.js b/server/model/status_page.js
index 2d90b6392..a65a7da1b 100644
--- a/server/model/status_page.js
+++ b/server/model/status_page.js
@@ -56,7 +56,10 @@ class StatusPage extends BeanModel {
await StatusPage.getStatusPageData(statusPage).then( (page) => {
if (page.config?.googleAnalyticsId) {
- head.append($(googleAnalytics.getGoogleAnalyticsScript(page.config.googleAnalyticsId)));
+ let escapedGoogleAnalyticsScript = jsesc(googleAnalytics.getGoogleAnalyticsScript(page.config.googleAnalyticsId), {
+ "isScriptContext": true
+ });
+ head.append($(escapedGoogleAnalyticsScript));
}
});
diff --git a/server/modules/google-analytics.js b/server/modules/google-analytics.js
index 2c10e5841..4e0c95b24 100644
--- a/server/modules/google-analytics.js
+++ b/server/modules/google-analytics.js
@@ -1,30 +1,27 @@
-let GoogleAnalytics = (() => {
- /**
- * Returns a string that represents the javascript that is required to insert the Google Analytics scripts
- * into a webpage.
- * @param tagId Google UA/G/AW/DC Property ID to use with the Google Analytics script.
- * @returns {string}
- */
- function getGoogleAnalyticsScript(tagId) {
- return "" +
- "";
- }
+/**
+ * Returns true if the tag conforms to the format of 1-2 Letters followed by a dash and 8 numbers.
+ * This should take care of the following property tag formats:
+ * UA-########, G-########, AW-########, DC-########
+ * @param {String} tagInput Google UA/G/AW/DC Property ID
+ * @returns {boolean}
+ */
+function isValidTag(tagInput) {
+ const re = /^\w{1,2}-\d{8}$/g;
+ return tagInput.match(re) != null;
+}
- /**
- * Returns true if the tag conforms to the format of 1-2 Letters followed by a dash and 8 numbers.
- * This should take care of the following property tag formats:
- * UA-########, G-########, AW-########, DC-########
- * @param {String} tagInput Google UA/G/AW/DC Property ID
- * @returns {boolean}
- */
- function isValidTag(tagInput) {
- const re = /^\w{1,2}-\d{8}$/g;
- return tagInput.match(re) != null;
- }
- return {
- getGoogleAnalyticsScript: getGoogleAnalyticsScript,
- isValidTag: isValidTag
- };
-})();
+/**
+ * Returns a string that represents the javascript that is required to insert the Google Analytics scripts
+ * into a webpage.
+ * @param tagId Google UA/G/AW/DC Property ID to use with the Google Analytics script.
+ * @returns {string}
+ */
+function getGoogleAnalyticsScript(tagId) {
+ return "" +
+ "";
+}
-module.exports = GoogleAnalytics;
+module.exports = {
+ getGoogleAnalyticsScript,
+ isValidTag,
+};
From c08d8a5eaffc5b707ddb9a59d1125c44cb425c53 Mon Sep 17 00:00:00 2001
From: c
Date: Sun, 22 Jan 2023 16:59:09 +0000
Subject: [PATCH 11/94] Google Analytics - Simplified retrieving Tag ID from
Status Page.
---
server/model/status_page.js | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/server/model/status_page.js b/server/model/status_page.js
index a65a7da1b..5b1c12408 100644
--- a/server/model/status_page.js
+++ b/server/model/status_page.js
@@ -54,14 +54,12 @@ class StatusPage extends BeanModel {
const head = $("head");
- await StatusPage.getStatusPageData(statusPage).then( (page) => {
- if (page.config?.googleAnalyticsId) {
- let escapedGoogleAnalyticsScript = jsesc(googleAnalytics.getGoogleAnalyticsScript(page.config.googleAnalyticsId), {
- "isScriptContext": true
- });
- head.append($(escapedGoogleAnalyticsScript));
- }
- });
+ if (statusPage.googleAnalyticsTagId) {
+ let escapedGoogleAnalyticsScript = jsesc(googleAnalytics.getGoogleAnalyticsScript(statusPage.googleAnalyticsTagId), {
+ "isScriptContext": true
+ });
+ head.append($(escapedGoogleAnalyticsScript));
+ }
// OG Meta Tags
head.append(``);
From 5a94a3fe3c27d4b51469a71bab990d7232b70a3c Mon Sep 17 00:00:00 2001
From: c
Date: Tue, 24 Jan 2023 14:09:56 +0000
Subject: [PATCH 12/94] Google Analytics - Moved string to updated file.
---
src/lang/en.json | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/lang/en.json b/src/lang/en.json
index 231fe29f1..df8288d22 100644
--- a/src/lang/en.json
+++ b/src/lang/en.json
@@ -690,5 +690,6 @@
"onebotSafetyTips": "For safety, must set access token",
"PushDeer Key": "PushDeer Key",
"wayToGetClickSendSMSToken": "You can get API Username and API Key from {0} .",
- "Custom Monitor Type": "Custom Monitor Type"
+ "Custom Monitor Type": "Custom Monitor Type",
+ "Google Analytics ID": "Google Analytics ID"
}
From 3afe8013ca330545d194a8ccbbcb86721b4c2b67 Mon Sep 17 00:00:00 2001
From: c
Date: Tue, 31 Jan 2023 13:17:43 +0000
Subject: [PATCH 13/94] Feature - Google Analytics - Change TEXT type to
VARCHAR.
---
db/patch-add-google-analytics-status-page-tag.sql | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/db/patch-add-google-analytics-status-page-tag.sql b/db/patch-add-google-analytics-status-page-tag.sql
index 15305ae25..5de6ff37b 100644
--- a/db/patch-add-google-analytics-status-page-tag.sql
+++ b/db/patch-add-google-analytics-status-page-tag.sql
@@ -1,4 +1,4 @@
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
BEGIN TRANSACTION;
-ALTER TABLE status_page ADD google_analytics_tag_id TEXT;
+ALTER TABLE status_page ADD google_analytics_tag_id VARCHAR;
COMMIT;
From 913bb611d589f70778ee80f6f0521bdb243e4652 Mon Sep 17 00:00:00 2001
From: c
Date: Tue, 31 Jan 2023 13:18:02 +0000
Subject: [PATCH 14/94] Feature - Google Analytics - Removed regex to validate
a Google Analytics tag.
---
server/modules/google-analytics.js | 13 -------------
.../socket-handlers/status-page-socket-handler.js | 2 +-
2 files changed, 1 insertion(+), 14 deletions(-)
diff --git a/server/modules/google-analytics.js b/server/modules/google-analytics.js
index 4e0c95b24..8b909b42f 100644
--- a/server/modules/google-analytics.js
+++ b/server/modules/google-analytics.js
@@ -1,15 +1,3 @@
-/**
- * Returns true if the tag conforms to the format of 1-2 Letters followed by a dash and 8 numbers.
- * This should take care of the following property tag formats:
- * UA-########, G-########, AW-########, DC-########
- * @param {String} tagInput Google UA/G/AW/DC Property ID
- * @returns {boolean}
- */
-function isValidTag(tagInput) {
- const re = /^\w{1,2}-\d{8}$/g;
- return tagInput.match(re) != null;
-}
-
/**
* Returns a string that represents the javascript that is required to insert the Google Analytics scripts
* into a webpage.
@@ -23,5 +11,4 @@ function getGoogleAnalyticsScript(tagId) {
module.exports = {
getGoogleAnalyticsScript,
- isValidTag,
};
diff --git a/server/socket-handlers/status-page-socket-handler.js b/server/socket-handlers/status-page-socket-handler.js
index 359ed15bd..c973d7edc 100644
--- a/server/socket-handlers/status-page-socket-handler.js
+++ b/server/socket-handlers/status-page-socket-handler.js
@@ -164,7 +164,7 @@ module.exports.statusPageSocketHandler = (socket) => {
statusPage.custom_css = config.customCSS;
statusPage.show_powered_by = config.showPoweredBy;
statusPage.modified_date = R.isoDateTime();
- statusPage.google_analytics_tag_id = googleAnalytics.isValidTag(config.googleAnalyticsId) ? config.googleAnalyticsId : "";
+ statusPage.google_analytics_tag_id = config.googleAnalyticsId;
await R.store(statusPage);
From f153082184bc7f220d23ae93acd38f123b028d32 Mon Sep 17 00:00:00 2001
From: Louis Lam
Date: Tue, 31 Jan 2023 14:23:40 +0800
Subject: [PATCH 15/94] Drop en.js
---
src/languages/en.js | 0
1 file changed, 0 insertions(+), 0 deletions(-)
delete mode 100644 src/languages/en.js
diff --git a/src/languages/en.js b/src/languages/en.js
deleted file mode 100644
index e69de29bb..000000000
From 2a6d98ff01cd8fd4d43a1380b129df96c3371a17 Mon Sep 17 00:00:00 2001
From: Joseph <40335314+JRedOW@users.noreply.github.com>
Date: Thu, 2 Feb 2023 23:33:48 -0500
Subject: [PATCH 16/94] Feat: Expand and Simplify Badge Functionality (#2211)
* [expanding badges] added new configs
* [expanding badges] recieve ping in getPreviousHeartbeat()
* [expanding badges] re-added original new badges
* [expanding badges] recreate parity between old and new badges
* [expanding badges] fix linting
---
server/config.js | 6 +
server/model/monitor.js | 2 +-
server/routers/api-router.js | 246 ++++++++++++++++++++++++++++++++++-
3 files changed, 248 insertions(+), 6 deletions(-)
diff --git a/server/config.js b/server/config.js
index 0523e7078..43a40f672 100644
--- a/server/config.js
+++ b/server/config.js
@@ -4,6 +4,7 @@ const demoMode = args["demo"] || false;
const badgeConstants = {
naColor: "#999",
defaultUpColor: "#66c20a",
+ defaultWarnColor: "#eed202",
defaultDownColor: "#c2290a",
defaultPendingColor: "#f8a306",
defaultMaintenanceColor: "#1747f5",
@@ -13,6 +14,11 @@ const badgeConstants = {
defaultPingLabelSuffix: "h",
defaultUptimeValueSuffix: "%",
defaultUptimeLabelSuffix: "h",
+ defaultCertExpValueSuffix: " days",
+ defaultCertExpLabelSuffix: "h",
+ // Values Come From Default Notification Times
+ defaultCertExpireWarnDays: "14",
+ defaultCertExpireDownDays: "7"
};
module.exports = {
diff --git a/server/model/monitor.js b/server/model/monitor.js
index c3e91f935..4cbb56e1a 100644
--- a/server/model/monitor.js
+++ b/server/model/monitor.js
@@ -1255,7 +1255,7 @@ class Monitor extends BeanModel {
*/
static async getPreviousHeartbeat(monitorID) {
return await R.getRow(`
- SELECT status, time FROM heartbeat
+ SELECT ping, status, time FROM heartbeat
WHERE id = (select MAX(id) from heartbeat where monitor_id = ?)
`, [
monitorID
diff --git a/server/routers/api-router.js b/server/routers/api-router.js
index e95fd045e..665163aee 100644
--- a/server/routers/api-router.js
+++ b/server/routers/api-router.js
@@ -145,7 +145,7 @@ router.get("/api/badge/:id/status", cache("5 minutes"), async (request, response
const heartbeat = await Monitor.getPreviousHeartbeat(requestedMonitorId);
const state = overrideValue !== undefined ? overrideValue : heartbeat.status;
- badgeValues.label = label ?? "";
+ badgeValues.label = label ?? "Status";
switch (state) {
case DOWN:
badgeValues.color = downColor;
@@ -212,7 +212,7 @@ router.get("/api/badge/:id/uptime/:duration?", cache("5 minutes"), async (reques
const badgeValues = { style };
if (!publicMonitor) {
- // return a "N/A" badge in naColor (grey), if monitor is not public / not available / non exsitant
+ // return a "N/A" badge in naColor (grey), if monitor is not public / not available / non existent
badgeValues.message = "N/A";
badgeValues.color = badgeConstants.naColor;
} else {
@@ -228,8 +228,11 @@ router.get("/api/badge/:id/uptime/:duration?", cache("5 minutes"), async (reques
badgeValues.color = color ?? percentageToColor(uptime);
// use a given, custom labelColor or use the default badge label color (defined by badge-maker)
badgeValues.labelColor = labelColor ?? "";
- // build a lable string. If a custom label is given, override the default one (requestedDuration)
- badgeValues.label = filterAndJoin([ labelPrefix, label ?? requestedDuration, labelSuffix ]);
+ // build a label string. If a custom label is given, override the default one (requestedDuration)
+ badgeValues.label = filterAndJoin([
+ labelPrefix,
+ label ?? `Uptime (${requestedDuration}${labelSuffix})`,
+ ]);
badgeValues.message = filterAndJoin([ prefix, `${cleanUptime * 100}`, suffix ]);
}
@@ -290,7 +293,7 @@ router.get("/api/badge/:id/ping/:duration?", cache("5 minutes"), async (request,
// use a given, custom labelColor or use the default badge label color (defined by badge-maker)
badgeValues.labelColor = labelColor ?? "";
// build a lable string. If a custom label is given, override the default one (requestedDuration)
- badgeValues.label = filterAndJoin([ labelPrefix, label ?? requestedDuration, labelSuffix ]);
+ badgeValues.label = filterAndJoin([ labelPrefix, label ?? `Avg. Ping (${requestedDuration}${labelSuffix})` ]);
badgeValues.message = filterAndJoin([ prefix, avgPing, suffix ]);
}
@@ -304,4 +307,237 @@ router.get("/api/badge/:id/ping/:duration?", cache("5 minutes"), async (request,
}
});
+router.get("/api/badge/:id/avg-response/:duration?", cache("5 minutes"), async (request, response) => {
+ allowAllOrigin(response);
+
+ const {
+ label,
+ labelPrefix,
+ labelSuffix,
+ prefix,
+ suffix = badgeConstants.defaultPingValueSuffix,
+ color = badgeConstants.defaultPingColor,
+ labelColor,
+ style = badgeConstants.defaultStyle,
+ value, // for demo purpose only
+ } = request.query;
+
+ try {
+ const requestedMonitorId = parseInt(request.params.id, 10);
+
+ // Default duration is 24 (h) if not defined in queryParam, limited to 720h (30d)
+ const requestedDuration = Math.min(
+ request.params.duration
+ ? parseInt(request.params.duration, 10)
+ : 24,
+ 720
+ );
+ const overrideValue = value && parseFloat(value);
+
+ const publicAvgPing = parseInt(await R.getCell(`
+ SELECT AVG(ping) FROM monitor_group, \`group\`, heartbeat
+ WHERE monitor_group.group_id = \`group\`.id
+ AND heartbeat.time > DATETIME('now', ? || ' hours')
+ AND heartbeat.ping IS NOT NULL
+ AND public = 1
+ AND heartbeat.monitor_id = ?
+ `,
+ [ -requestedDuration, requestedMonitorId ]
+ ));
+
+ const badgeValues = { style };
+
+ if (!publicAvgPing) {
+ // return a "N/A" badge in naColor (grey), if monitor is not public / not available / non existent
+
+ badgeValues.message = "N/A";
+ badgeValues.color = badgeConstants.naColor;
+ } else {
+ const avgPing = parseInt(overrideValue ?? publicAvgPing);
+
+ badgeValues.color = color;
+ // use a given, custom labelColor or use the default badge label color (defined by badge-maker)
+ badgeValues.labelColor = labelColor ?? "";
+ // build a label string. If a custom label is given, override the default one (requestedDuration)
+ badgeValues.label = filterAndJoin([
+ labelPrefix,
+ label ?? `Avg. Response (${requestedDuration}h)`,
+ labelSuffix,
+ ]);
+ badgeValues.message = filterAndJoin([ prefix, avgPing, suffix ]);
+ }
+
+ // build the SVG based on given values
+ const svg = makeBadge(badgeValues);
+
+ response.type("image/svg+xml");
+ response.send(svg);
+ } catch (error) {
+ send403(response, error.message);
+ }
+});
+
+router.get("/api/badge/:id/cert-exp", cache("5 minutes"), async (request, response) => {
+ allowAllOrigin(response);
+
+ const date = request.query.date;
+
+ const {
+ label,
+ labelPrefix,
+ labelSuffix,
+ prefix,
+ suffix = date ? "" : badgeConstants.defaultCertExpValueSuffix,
+ upColor = badgeConstants.defaultUpColor,
+ warnColor = badgeConstants.defaultWarnColor,
+ downColor = badgeConstants.defaultDownColor,
+ warnDays = badgeConstants.defaultCertExpireWarnDays,
+ downDays = badgeConstants.defaultCertExpireDownDays,
+ labelColor,
+ style = badgeConstants.defaultStyle,
+ value, // for demo purpose only
+ } = request.query;
+
+ try {
+ const requestedMonitorId = parseInt(request.params.id, 10);
+
+ const overrideValue = value && parseFloat(value);
+
+ let publicMonitor = await R.getRow(`
+ SELECT monitor_group.monitor_id FROM monitor_group, \`group\`
+ WHERE monitor_group.group_id = \`group\`.id
+ AND monitor_group.monitor_id = ?
+ AND public = 1
+ `,
+ [ requestedMonitorId ]
+ );
+
+ const badgeValues = { style };
+
+ if (!publicMonitor) {
+ // return a "N/A" badge in naColor (grey), if monitor is not public / not available / non existent
+
+ badgeValues.message = "N/A";
+ badgeValues.color = badgeConstants.naColor;
+ } else {
+ const tlsInfoBean = await R.findOne("monitor_tls_info", "monitor_id = ?", [
+ requestedMonitorId,
+ ]);
+
+ if (!tlsInfoBean) {
+ // return a "No/Bad Cert" badge in naColor (grey), if no cert saved (does not save bad certs?)
+ badgeValues.message = "No/Bad Cert";
+ badgeValues.color = badgeConstants.naColor;
+ } else {
+ const tlsInfo = JSON.parse(tlsInfoBean.info_json);
+
+ if (!tlsInfo.valid) {
+ // return a "Bad Cert" badge in naColor (grey), when cert is not valid
+ badgeValues.message = "Bad Cert";
+ badgeValues.color = badgeConstants.downColor;
+ } else {
+ const daysRemaining = parseInt(overrideValue ?? tlsInfo.certInfo.daysRemaining);
+
+ if (daysRemaining > warnDays) {
+ badgeValues.color = upColor;
+ } else if (daysRemaining > downDays) {
+ badgeValues.color = warnColor;
+ } else {
+ badgeValues.color = downColor;
+ }
+ // use a given, custom labelColor or use the default badge label color (defined by badge-maker)
+ badgeValues.labelColor = labelColor ?? "";
+ // build a label string. If a custom label is given, override the default one
+ badgeValues.label = filterAndJoin([
+ labelPrefix,
+ label ?? "Cert Exp.",
+ labelSuffix,
+ ]);
+ badgeValues.message = filterAndJoin([ prefix, date ? tlsInfo.certInfo.validTo : daysRemaining, suffix ]);
+ }
+ }
+ }
+
+ // build the SVG based on given values
+ const svg = makeBadge(badgeValues);
+
+ response.type("image/svg+xml");
+ response.send(svg);
+ } catch (error) {
+ send403(response, error.message);
+ }
+});
+
+router.get("/api/badge/:id/response", cache("5 minutes"), async (request, response) => {
+ allowAllOrigin(response);
+
+ const {
+ label,
+ labelPrefix,
+ labelSuffix,
+ prefix,
+ suffix = badgeConstants.defaultPingValueSuffix,
+ color = badgeConstants.defaultPingColor,
+ labelColor,
+ style = badgeConstants.defaultStyle,
+ value, // for demo purpose only
+ } = request.query;
+
+ try {
+ const requestedMonitorId = parseInt(request.params.id, 10);
+
+ const overrideValue = value && parseFloat(value);
+
+ let publicMonitor = await R.getRow(`
+ SELECT monitor_group.monitor_id FROM monitor_group, \`group\`
+ WHERE monitor_group.group_id = \`group\`.id
+ AND monitor_group.monitor_id = ?
+ AND public = 1
+ `,
+ [ requestedMonitorId ]
+ );
+
+ const badgeValues = { style };
+
+ if (!publicMonitor) {
+ // return a "N/A" badge in naColor (grey), if monitor is not public / not available / non existent
+
+ badgeValues.message = "N/A";
+ badgeValues.color = badgeConstants.naColor;
+ } else {
+ const heartbeat = await Monitor.getPreviousHeartbeat(
+ requestedMonitorId
+ );
+
+ if (!heartbeat.ping) {
+ // return a "N/A" badge in naColor (grey), if previous heartbeat has no ping
+
+ badgeValues.message = "N/A";
+ badgeValues.color = badgeConstants.naColor;
+ } else {
+ const ping = parseInt(overrideValue ?? heartbeat.ping);
+
+ badgeValues.color = color;
+ // use a given, custom labelColor or use the default badge label color (defined by badge-maker)
+ badgeValues.labelColor = labelColor ?? "";
+ // build a label string. If a custom label is given, override the default one
+ badgeValues.label = filterAndJoin([
+ labelPrefix,
+ label ?? "Response",
+ labelSuffix,
+ ]);
+ badgeValues.message = filterAndJoin([ prefix, ping, suffix ]);
+ }
+ }
+
+ // build the SVG based on given values
+ const svg = makeBadge(badgeValues);
+
+ response.type("image/svg+xml");
+ response.send(svg);
+ } catch (error) {
+ send403(response, error.message);
+ }
+});
+
module.exports = router;
From d39508a0073304f4dea294acec98973a3f982912 Mon Sep 17 00:00:00 2001
From: Louis Lam
Date: Fri, 3 Feb 2023 13:19:51 +0800
Subject: [PATCH 17/94] Change nightly version format
---
extra/mark-as-nightly.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/extra/mark-as-nightly.js b/extra/mark-as-nightly.js
index ebc67da31..ada2aca81 100644
--- a/extra/mark-as-nightly.js
+++ b/extra/mark-as-nightly.js
@@ -1,11 +1,12 @@
const pkg = require("../package.json");
const fs = require("fs");
const util = require("../src/util");
+const dayjs = require("dayjs");
util.polyfill();
const oldVersion = pkg.version;
-const newVersion = oldVersion + "-nightly-" + util.genSecret(8);
+const newVersion = oldVersion + "-nightly-" + dayjs().format("YYYYMMDDHHmmss");
console.log("Old Version: " + oldVersion);
console.log("New Version: " + newVersion);
From e631db89b84e70402cfec90ecd987d1b953ab0cd Mon Sep 17 00:00:00 2001
From: Louis Lam
Date: Fri, 3 Feb 2023 13:21:19 +0800
Subject: [PATCH 18/94] Update to 1.20.0-beta.0
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 38d55f4fa..d5d1c5fdd 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "uptime-kuma",
- "version": "1.19.6",
+ "version": "1.20.0-beta.0",
"license": "MIT",
"repository": {
"type": "git",
From ff09276de203b36d6c043677f07cd043c3a60a9f Mon Sep 17 00:00:00 2001
From: Louis Lam
Date: Fri, 3 Feb 2023 13:38:14 +0800
Subject: [PATCH 19/94] Update README.md
---
README.md | 1 -
1 file changed, 1 deletion(-)
diff --git a/README.md b/README.md
index f29622a6e..b96edd366 100644
--- a/README.md
+++ b/README.md
@@ -18,7 +18,6 @@ Uptime Kuma is an easy-to-use self-hosted monitoring tool.
Try it!
- Tokyo Demo Server: https://demo.uptime.kuma.pet (Sponsored by [Uptime Kuma Sponsors](https://github.com/louislam/uptime-kuma#%EF%B8%8F-sponsors))
-- Europe Demo Server: https://demo.uptime-kuma.karimi.dev:27000 (Provided by [@mhkarimi1383](https://github.com/mhkarimi1383))
It is a temporary live demo, all data will be deleted after 10 minutes. Use the one that is closer to you, but I suggest that you should install and try it out for the best demo experience.
From ec78d2a39b686ab446cfd8399ebf9f1ba3cd885c Mon Sep 17 00:00:00 2001
From: Louis Lam
Date: Fri, 3 Feb 2023 13:39:45 +0800
Subject: [PATCH 20/94] Update README.md
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index b96edd366..cdefe6a0c 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
# Uptime Kuma
-[![GitHub Sponsors](https://img.shields.io/github/sponsors/louislam?label=GitHub%20Sponsors)](https://github.com/sponsors/louislam)
+[![GitHub Sponsors](https://img.shields.io/github/sponsors/louislam?label=GitHub%20Sponsors)](https://github.com/sponsors/louislam)
From e0f017864482088ff8b99a0f74fd5146f03014d3 Mon Sep 17 00:00:00 2001
From: Adam Stachowicz
Date: Fri, 3 Feb 2023 07:10:10 +0100
Subject: [PATCH 21/94] Do not run auto-test for markdown-only commits. Update
versions
---
.github/workflows/auto-test.yml | 5 +++++
.github/workflows/close-incorrect-issue.yml | 7 +++----
.github/workflows/stale-bot.yml | 4 ++--
3 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/.github/workflows/auto-test.yml b/.github/workflows/auto-test.yml
index 273b1dba2..944627127 100644
--- a/.github/workflows/auto-test.yml
+++ b/.github/workflows/auto-test.yml
@@ -6,8 +6,12 @@ name: Auto Test
on:
push:
branches: [ master ]
+ paths-ignore:
+ - '*.md'
pull_request:
branches: [ master ]
+ paths-ignore:
+ - '*.md'
jobs:
auto-test:
@@ -36,6 +40,7 @@ jobs:
env:
HEADLESS_TEST: 1
JUST_FOR_TEST: ${{ secrets.JUST_FOR_TEST }}
+
check-linters:
runs-on: ubuntu-latest
diff --git a/.github/workflows/close-incorrect-issue.yml b/.github/workflows/close-incorrect-issue.yml
index 026022dfa..762bc9688 100644
--- a/.github/workflows/close-incorrect-issue.yml
+++ b/.github/workflows/close-incorrect-issue.yml
@@ -1,4 +1,3 @@
-
name: Close Incorrect Issue
on:
@@ -12,13 +11,13 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
- node-version: [16.x]
+ node-version: [16]
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v2
+ uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
diff --git a/.github/workflows/stale-bot.yml b/.github/workflows/stale-bot.yml
index 5b4568e1d..b39f68fc1 100644
--- a/.github/workflows/stale-bot.yml
+++ b/.github/workflows/stale-bot.yml
@@ -3,13 +3,13 @@ on:
workflow_dispatch:
schedule:
- cron: '0 */6 * * *'
-#Run every 6 hours
+#Run every 6 hours
jobs:
stale:
runs-on: ubuntu-latest
steps:
- - uses: actions/stale@v5
+ - uses: actions/stale@v7
with:
stale-issue-message: 'We are clearing up our old issues and your ticket has been open for 3 months with no activity. Remove stale label or comment or this will be closed in 2 days.'
close-issue-message: 'This issue was closed because it has been stalled for 2 days with no activity.'
From a823ed8ccc4d85230a3dd90e6f78fc4b9259c8fe Mon Sep 17 00:00:00 2001
From: c
Date: Fri, 3 Feb 2023 11:49:25 +0000
Subject: [PATCH 22/94] Feature - Google Analytics - Removed unused import.
---
server/socket-handlers/status-page-socket-handler.js | 1 -
1 file changed, 1 deletion(-)
diff --git a/server/socket-handlers/status-page-socket-handler.js b/server/socket-handlers/status-page-socket-handler.js
index c973d7edc..717aba9c4 100644
--- a/server/socket-handlers/status-page-socket-handler.js
+++ b/server/socket-handlers/status-page-socket-handler.js
@@ -7,7 +7,6 @@ const Database = require("../database");
const apicache = require("../modules/apicache");
const StatusPage = require("../model/status_page");
const { UptimeKumaServer } = require("../uptime-kuma-server");
-const googleAnalytics = require("../modules/google-analytics");
/**
* Socket handlers for status page
From 5f2affb38ccace2c41d637b2ce587b770270204a Mon Sep 17 00:00:00 2001
From: Louis Lam
Date: Sat, 4 Feb 2023 16:58:39 +0800
Subject: [PATCH 23/94] Relocate and fix jsesc issue
---
server/google-analytics.js | 19 +++++++++++++++++++
server/model/status_page.js | 6 ++----
server/modules/google-analytics.js | 14 --------------
3 files changed, 21 insertions(+), 18 deletions(-)
create mode 100644 server/google-analytics.js
delete mode 100644 server/modules/google-analytics.js
diff --git a/server/google-analytics.js b/server/google-analytics.js
new file mode 100644
index 000000000..b98ca8623
--- /dev/null
+++ b/server/google-analytics.js
@@ -0,0 +1,19 @@
+const jsesc = require("jsesc");
+
+/**
+ * Returns a string that represents the javascript that is required to insert the Google Analytics scripts
+ * into a webpage.
+ * @param tagId Google UA/G/AW/DC Property ID to use with the Google Analytics script.
+ * @returns {string}
+ */
+function getGoogleAnalyticsScript(tagId) {
+ let escapedTagId = jsesc(tagId, { isScriptContext: true });
+ return `
+
+
+ `;
+}
+
+module.exports = {
+ getGoogleAnalyticsScript,
+};
diff --git a/server/model/status_page.js b/server/model/status_page.js
index 5b1c12408..d7185a2e0 100644
--- a/server/model/status_page.js
+++ b/server/model/status_page.js
@@ -4,7 +4,7 @@ const cheerio = require("cheerio");
const { UptimeKumaServer } = require("../uptime-kuma-server");
const jsesc = require("jsesc");
const Maintenance = require("./maintenance");
-const googleAnalytics = require("../modules/google-analytics");
+const googleAnalytics = require("../google-analytics");
class StatusPage extends BeanModel {
@@ -55,9 +55,7 @@ class StatusPage extends BeanModel {
const head = $("head");
if (statusPage.googleAnalyticsTagId) {
- let escapedGoogleAnalyticsScript = jsesc(googleAnalytics.getGoogleAnalyticsScript(statusPage.googleAnalyticsTagId), {
- "isScriptContext": true
- });
+ let escapedGoogleAnalyticsScript = googleAnalytics.getGoogleAnalyticsScript(statusPage.googleAnalyticsTagId);
head.append($(escapedGoogleAnalyticsScript));
}
diff --git a/server/modules/google-analytics.js b/server/modules/google-analytics.js
deleted file mode 100644
index 8b909b42f..000000000
--- a/server/modules/google-analytics.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Returns a string that represents the javascript that is required to insert the Google Analytics scripts
- * into a webpage.
- * @param tagId Google UA/G/AW/DC Property ID to use with the Google Analytics script.
- * @returns {string}
- */
-function getGoogleAnalyticsScript(tagId) {
- return "" +
- "";
-}
-
-module.exports = {
- getGoogleAnalyticsScript,
-};
From afadfe32d5b2a43940bf5b22e5985b206d4a808b Mon Sep 17 00:00:00 2001
From: Louis Lam
Date: Sat, 4 Feb 2023 17:03:00 +0800
Subject: [PATCH 24/94] Trim
---
server/google-analytics.js | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/server/google-analytics.js b/server/google-analytics.js
index b98ca8623..fc9fbec84 100644
--- a/server/google-analytics.js
+++ b/server/google-analytics.js
@@ -8,6 +8,11 @@ const jsesc = require("jsesc");
*/
function getGoogleAnalyticsScript(tagId) {
let escapedTagId = jsesc(tagId, { isScriptContext: true });
+
+ if (escapedTagId) {
+ escapedTagId = escapedTagId.trim();
+ }
+
return `
From 5fff63cd5979efc7445518627f37193df60104ac Mon Sep 17 00:00:00 2001
From: cyril59310
Date: Sun, 5 Feb 2023 01:07:20 +0100
Subject: [PATCH 25/94] add keys for translation
---
src/lang/en.json | 5 ++++-
src/pages/ManageMaintenance.vue | 2 +-
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/lang/en.json b/src/lang/en.json
index 8a195a2a9..d907f4e0c 100644
--- a/src/lang/en.json
+++ b/src/lang/en.json
@@ -692,5 +692,8 @@
"PushDeer Key": "PushDeer Key",
"wayToGetClickSendSMSToken": "You can get API Username and API Key from {0} .",
"Custom Monitor Type": "Custom Monitor Type",
- "Google Analytics ID": "Google Analytics ID"
+ "Google Analytics ID": "Google Analytics ID",
+ "Edit Tag": "Edit Tag",
+ "Server Address": "Server Address",
+ "Learn More": "Learn More"
}
diff --git a/src/pages/ManageMaintenance.vue b/src/pages/ManageMaintenance.vue
index aaffbbf93..478927e87 100644
--- a/src/pages/ManageMaintenance.vue
+++ b/src/pages/ManageMaintenance.vue
@@ -62,7 +62,7 @@
From 271cca0d234914fc37a92088433b385ab05ac78e Mon Sep 17 00:00:00 2001
From: Louis Lam
Date: Mon, 6 Feb 2023 15:21:31 +0800
Subject: [PATCH 26/94] Add Romanian in the dropdown
---
src/i18n.js | 1 +
src/lang/ro.json | 3 +++
2 files changed, 4 insertions(+)
create mode 100644 src/lang/ro.json
diff --git a/src/i18n.js b/src/i18n.js
index b6a7beee2..f57408e4e 100644
--- a/src/i18n.js
+++ b/src/i18n.js
@@ -38,6 +38,7 @@ const languageList = {
"th-TH": "ไทย",
"el-GR": "Ελληνικά",
"yue": "繁體中文 (廣東話 / 粵語)",
+ "ro": "Limba română",
};
let messages = {
diff --git a/src/lang/ro.json b/src/lang/ro.json
new file mode 100644
index 000000000..a659e0bed
--- /dev/null
+++ b/src/lang/ro.json
@@ -0,0 +1,3 @@
+{
+ "languageName": "Limba română"
+}
From 0197778af12ba240aa0e1a29b660193410d45356 Mon Sep 17 00:00:00 2001
From: Louis Lam
Date: Mon, 6 Feb 2023 22:35:56 +0800
Subject: [PATCH 27/94] Fix change language issue in the setup page
---
src/pages/Setup.vue | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/src/pages/Setup.vue b/src/pages/Setup.vue
index cba7f8fce..cd2d149cd 100644
--- a/src/pages/Setup.vue
+++ b/src/pages/Setup.vue
@@ -14,7 +14,7 @@