diff --git a/.github/ISSUE_TEMPLATE/ask-for-help.yaml b/.github/ISSUE_TEMPLATE/ask-for-help.yaml index a1425c9c9..3442e8b73 100644 --- a/.github/ISSUE_TEMPLATE/ask-for-help.yaml +++ b/.github/ISSUE_TEMPLATE/ask-for-help.yaml @@ -1,8 +1,23 @@ name: "❓ Ask for help" description: "Submit any question related to Uptime Kuma" -title: "[Help]: " +#title: "[Help] " labels: [help] body: + - type: checkboxes + id: no-duplicate-issues + attributes: + label: "⚠️ Please verify that this bug has NOT been raised before." + description: "Search in the issues sections by clicking [HERE](https://github.com/louislam/uptime-kuma/issues?q=)" + options: + - label: "I checked and didn't find similar issue" + required: true + - type: checkboxes + attributes: + label: "🛡️ Security Policy" + description: Please review the security policy before reporting security related issues/bugs. + options: + - label: I agree to have read this project [Security Policy](https://github.com/louislam/uptime-kuma/security/policy) + required: true - type: textarea id: steps-to-reproduce validations: @@ -14,17 +29,17 @@ body: - type: input id: uptime-kuma-version attributes: - label: "🐻 Uptime-Kuma version" - description: "Which version of Uptime-Kuma are you running?" - placeholder: "Ex. 1.9.x" + label: "🐻 Uptime-Kuma Version" + description: "Which version of Uptime-Kuma are you running? Please do NOT provide the docker tag such as latest or 1" + placeholder: "Ex. 1.10.0" validations: required: true - type: input id: operating-system attributes: - label: "💻 Operating System" + label: "💻 Operating System and Arch" description: "Which OS is your server/device running on?" - placeholder: "Ex. Ubuntu 20.04" + placeholder: "Ex. Ubuntu 20.04 x86" validations: required: true - type: input @@ -32,23 +47,15 @@ body: attributes: label: "🌐 Browser" description: "Which browser are you running on?" - placeholder: "Ex. Firefox" + placeholder: "Ex. Google Chrome 95.0.4638.69" validations: required: true - type: input id: docker-version attributes: - label: "🐋 Docker" + label: "🐋 Docker Version" description: "If running with Docker, which version are you running?" - placeholder: "Ex. 20.10.9" - validations: - required: false - - type: input - id: docker-image-tag - attributes: - label: "🏷️ Docker Image Tag" - description: "Which Docker image tag are you using? If running '1' or 'latest', please specify image hash." - placeholder: "Ex. 1.9.1" + placeholder: "Ex. Docker 20.10.9 / K8S / Podman" validations: required: false - type: input @@ -56,21 +63,6 @@ body: attributes: label: "🟩 NodeJS Version" description: "If running with Node.js? which version are you running?" - placeholder: "14.x" + placeholder: "Ex. 14.18.0" validations: required: false - - type: checkboxes - id: no-duplicate-issues - attributes: - label: "⚠️ Please verify that this question has NOT been raised before." - description: "Search in the issues sections by clicking [HERE](https://github.com/louislam/uptime-kuma/issues?q=)" - options: - - label: "I checked and didn't find similar question" - required: true - - type: checkboxes - attributes: - label: "🛡️ Security Policy" - description: Please review the security policy before reporting security related issues/bugs. - options: - - label: I agree to have read this project [Security Policy](https://github.com/louislam/uptime-kuma/security/policy) - required: true diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 81ea9a32d..2dca1556a 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -1,88 +1,8 @@ name: "🐛 Bug Report" description: "Submit a bug report to help us improve" -title: "[Bug]: <title>" +#title: "[Bug] " labels: [bug] body: - - type: textarea - id: steps-to-reproduce - validations: - required: true - attributes: - label: "👟 Reproduction steps" - description: "How do you trigger this bug? Please walk us through it step by step." - placeholder: "..." - - type: textarea - id: expected-behavior - validations: - required: true - attributes: - label: "👍 Expected behavior" - description: "What did you think would happen?" - placeholder: "..." - - type: textarea - id: actual-behavior - validations: - required: true - attributes: - label: "👎 Actual Behavior" - description: "What actually happen?" - placeholder: "..." - - type: input - id: uptime-kuma-version - attributes: - label: "🐻 Uptime-Kuma version" - description: "Which version of Uptime-Kuma are you running?" - placeholder: "Ex. 1.9.x" - validations: - required: true - - type: input - id: operating-system - attributes: - label: "💻 Operating System" - description: "Which OS is your server/device running on?" - placeholder: "Ex. Ubuntu 20.04" - validations: - required: true - - type: input - id: browser-vendor - attributes: - label: "🌐 Browser" - description: "Which browser are you running on?" - placeholder: "Ex. Firefox" - validations: - required: true - - type: input - id: docker-version - attributes: - label: "🐋 Docker" - description: "If running with Docker, which version are you running?" - placeholder: "Ex. 20.10.9" - validations: - required: false - - type: input - id: docker-image-tag - attributes: - label: "🏷️ Docker Image Tag" - description: "Which Docker image tag are you using? If running '1' or 'latest', please specify image hash." - placeholder: "Ex. 1.9.1" - validations: - required: false - - type: input - id: nodejs-version - attributes: - label: "🟩 NodeJS Version" - description: "If running with Node.js? which version are you running?" - placeholder: "14.x" - validations: - required: false - - type: textarea - id: logs - attributes: - label: "📝 Relevant log output" - description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. - render: shell - validations: - required: false - type: checkboxes id: no-duplicate-issues attributes: @@ -98,3 +18,82 @@ body: options: - label: I agree to have read this project [Security Policy](https://github.com/louislam/uptime-kuma/security/policy) required: true + - type: textarea + id: description + validations: + required: false + attributes: + label: "Description" + description: "You could also upload screenshots" + - type: textarea + id: steps-to-reproduce + validations: + required: true + attributes: + label: "👟 Reproduction steps" + description: "How do you trigger this bug? Please walk us through it step by step." + placeholder: "..." + - type: textarea + id: expected-behavior + validations: + required: true + attributes: + label: "👀 Expected behavior" + description: "What did you think would happen?" + placeholder: "..." + - type: textarea + id: actual-behavior + validations: + required: true + attributes: + label: "😓 Actual Behavior" + description: "What actually happen?" + placeholder: "..." + - type: input + id: uptime-kuma-version + attributes: + label: "🐻 Uptime-Kuma Version" + description: "Which version of Uptime-Kuma are you running? Please do NOT provide the docker tag such as latest or 1" + placeholder: "Ex. 1.10.0" + validations: + required: true + - type: input + id: operating-system + attributes: + label: "💻 Operating System and Arch" + description: "Which OS is your server/device running on?" + placeholder: "Ex. Ubuntu 20.04 x86" + validations: + required: true + - type: input + id: browser-vendor + attributes: + label: "🌐 Browser" + description: "Which browser are you running on?" + placeholder: "Ex. Google Chrome 95.0.4638.69" + validations: + required: true + - type: input + id: docker-version + attributes: + label: "🐋 Docker Version" + description: "If running with Docker, which version are you running?" + placeholder: "Ex. Docker 20.10.9 / K8S / Podman" + validations: + required: false + - type: input + id: nodejs-version + attributes: + label: "🟩 NodeJS Version" + description: "If running with Node.js? which version are you running?" + placeholder: "Ex. 14.18.0" + validations: + required: false + - type: textarea + id: logs + attributes: + label: "📝 Relevant log output" + description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. + render: shell + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml index 1a3cebc09..b26841c42 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yaml +++ b/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -1,8 +1,16 @@ name: 🚀 Feature Request description: "Submit a proposal for a new feature" -title: "[Feature]: <title>" -labels: [enhancement] +#title: "[Feature] " +labels: [feature-request] body: + - type: checkboxes + id: no-duplicate-issues + attributes: + label: "⚠️ Please verify that this feature request has NOT been suggested before." + description: "Search in the issues sections by clicking [HERE](https://github.com/louislam/uptime-kuma/issues?q=)" + options: + - label: "I checked and didn't find similar feature request" + required: true - type: dropdown id: feature-area attributes: @@ -49,11 +57,3 @@ body: label: "📝 Additional Context" description: "Add any other context or screenshots about the feature request here." placeholder: "..." - - type: checkboxes - id: no-duplicate-issues - attributes: - label: "⚠️ Please verify that this feature request has NOT been suggested before." - description: "Search in the issues sections by clicking [HERE](https://github.com/louislam/uptime-kuma/issues?q=)" - options: - - label: "I checked and didn't find similar feature request" - required: true diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index fa0aa883b..3be229315 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -24,3 +24,5 @@ Please delete options that are not relevant. - [ ] My code needed automated testing. I have added them (this is optional task) ## Screenshots (if any) + +Please do not use any external image service. Instead, just paste in or drag and drop the image here and it will be uploaded automatically. diff --git a/SECURITY.md b/SECURITY.md index 7b9bfca41..3a11e8817 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,5 +1,11 @@ # Security Policy +## Reporting a Vulnerability + +Please report security issues to uptime@kuma.pet. + +Do not use the issue tracker or discuss it in the public as it will cause more damage. + ## Supported Versions Use this section to tell people about which versions of your project are @@ -23,9 +29,3 @@ currently being supported with security updates. | debian | :white_check_mark: | | alpine | :white_check_mark: | | All other tags | ❌ | - -## Reporting a Vulnerability - -Please report security issues to uptime@kuma.pet. - -Do not use the issue tracker or discuss it in the public as it will cause more damage. diff --git a/extra/healthcheck.js b/extra/healthcheck.js index 99f748fb5..c6e8a349a 100644 --- a/extra/healthcheck.js +++ b/extra/healthcheck.js @@ -1,25 +1,41 @@ /* * This script should be run after a period of time (180s), because the server may need some time to prepare. */ +const { FBSD } = require("../server/util-server"); + process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; let client; -if (process.env.SSL_KEY && process.env.SSL_CERT) { +const sslKey = process.env.UPTIME_KUMA_SSL_KEY || process.env.SSL_KEY || undefined; +const sslCert = process.env.UPTIME_KUMA_SSL_CERT || process.env.SSL_CERT || undefined; + +if (sslKey && sslCert) { client = require("https"); } else { client = require("http"); } +// If host is omitted, the server will accept connections on the unspecified IPv6 address (::) when IPv6 is available and the unspecified IPv4 address (0.0.0.0) otherwise. +// Dual-stack support for (::) +let hostname = process.env.UPTIME_KUMA_HOST; + +// Also read HOST if not FreeBSD, as HOST is a system environment variable in FreeBSD +if (!hostname && !FBSD) { + hostname = process.env.HOST; +} + +const port = parseInt(process.env.UPTIME_KUMA_PORT || process.env.PORT || 3001); + let options = { - host: process.env.HOST || "127.0.0.1", - port: parseInt(process.env.PORT) || 3001, + host: hostname || "127.0.0.1", + port: port, timeout: 28 * 1000, }; let request = client.request(options, (res) => { console.log(`Health Check OK [Res Code: ${res.statusCode}]`); - if (res.statusCode === 200) { + if (res.statusCode === 302) { process.exit(0); } else { process.exit(1); diff --git a/package.json b/package.json index 64be83ee1..c7ec3d8ee 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "uptime-kuma", - "version": "1.10.0", + "version": "1.10.2", "license": "MIT", "repository": { "type": "git", @@ -30,13 +30,13 @@ "build-docker": "npm run build-docker-debian && npm run build-docker-alpine", "build-docker-alpine-base": "docker buildx build -f docker/alpine-base.dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:base-alpine . --push", "build-docker-debian-base": "docker buildx build -f docker/debian-base.dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:base-debian . --push", - "build-docker-alpine": "docker buildx build -f docker/dockerfile-alpine --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:alpine -t louislam/uptime-kuma:1-alpine -t louislam/uptime-kuma:1.10.0-alpine --target release . --push", - "build-docker-debian": "docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma -t louislam/uptime-kuma:1 -t louislam/uptime-kuma:1.10.0 -t louislam/uptime-kuma:debian -t louislam/uptime-kuma:1-debian -t louislam/uptime-kuma:1.10.0-debian --target release . --push", + "build-docker-alpine": "docker buildx build -f docker/dockerfile-alpine --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:alpine -t louislam/uptime-kuma:1-alpine -t louislam/uptime-kuma:1.10.2-alpine --target release . --push", + "build-docker-debian": "docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma -t louislam/uptime-kuma:1 -t louislam/uptime-kuma:1.10.2 -t louislam/uptime-kuma:debian -t louislam/uptime-kuma:1-debian -t louislam/uptime-kuma:1.10.2-debian --target release . --push", "build-docker-nightly": "docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:nightly --target nightly . --push", "build-docker-nightly-alpine": "docker buildx build -f docker/dockerfile-alpine --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:nightly-alpine --target nightly . --push", "build-docker-nightly-amd64": "docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:nightly-amd64 --target nightly . --push --progress plain", "upload-artifacts": "docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:upload-artifact --build-arg GITHUB_TOKEN --target upload-artifact . --progress plain", - "setup": "git checkout 1.10.0 && npm ci --production && npm run download-dist", + "setup": "git checkout 1.10.2 && npm ci --production && npm run download-dist", "download-dist": "node extra/download-dist.js", "update-version": "node extra/update-version.js", "mark-as-nightly": "node extra/mark-as-nightly.js", @@ -61,7 +61,7 @@ "args-parser": "~1.3.0", "axios": "~0.21.4", "bcryptjs": "~2.4.3", - "bootstrap": "~5.1.3", + "bootstrap": "5.1.3", "bree": "~6.3.1", "chardet": "^1.3.0", "chart.js": "~3.6.0", diff --git a/server/model/monitor.js b/server/model/monitor.js index fc3292317..980e0ac69 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -141,6 +141,7 @@ class Monitor extends BeanModel { // Do not do any queries/high loading things before the "bean.ping" let startTime = dayjs().valueOf(); + debug(`[${this.name}] Prepare Options for axios`); const options = { url: this.url, method: (this.method || "get").toLowerCase(), @@ -160,6 +161,8 @@ class Monitor extends BeanModel { return checkStatusCode(status, this.getAcceptedStatuscodes()); }, }; + + debug(`[${this.name}] Axios Request`); let res = await axios.request(options); bean.msg = `${res.status} - ${res.statusText}`; bean.ping = dayjs().valueOf() - startTime; @@ -167,12 +170,13 @@ class Monitor extends BeanModel { // Check certificate if https is used let certInfoStartTime = dayjs().valueOf(); if (this.getUrl()?.protocol === "https:") { + debug(`[${this.name}] Check cert`); try { let tlsInfoObject = checkCertificate(res); tlsInfo = await this.updateTlsInfo(tlsInfoObject); if (!this.getIgnoreTls()) { - debug("call sendCertNotification"); + debug(`[${this.name}] call sendCertNotification`); await this.sendCertNotification(tlsInfoObject); } @@ -351,15 +355,19 @@ class Monitor extends BeanModel { let beatInterval = this.interval; + debug(`[${this.name}] Check isImportant`); let isImportant = Monitor.isImportantBeat(isFirstBeat, previousBeat?.status, bean.status); // Mark as important if status changed, ignore pending pings, // Don't notify if disrupted changes to up if (isImportant) { bean.important = true; + + debug(`[${this.name}] sendNotification`); await Monitor.sendNotification(isFirstBeat, this, bean); // Clear Status Page Cache + debug(`[${this.name}] apicache clear`); apicache.clear(); } else { @@ -377,10 +385,14 @@ class Monitor extends BeanModel { console.warn(`Monitor #${this.id} '${this.name}': Failing: ${bean.msg} | Interval: ${beatInterval} seconds | Type: ${this.type}`); } + debug(`[${this.name}] Send to socket`); io.to(this.user_id).emit("heartbeat", bean.toJSON()); Monitor.sendStats(io, this.id, this.user_id); + debug(`[${this.name}] Store`); await R.store(bean); + + debug(`[${this.name}] prometheus.update`); prometheus.update(bean, tlsInfo); previousBeat = bean; @@ -394,7 +406,10 @@ class Monitor extends BeanModel { } } + debug(`[${this.name}] SetTimeout for next check.`); this.heartbeatInterval = setTimeout(safeBeat, beatInterval * 1000); + } else { + console.log(`[${this.name}] isStop = true, no next check.`); } }; diff --git a/server/notification-providers/feishu.js b/server/notification-providers/feishu.js index a3e340301..05fc9c186 100644 --- a/server/notification-providers/feishu.js +++ b/server/notification-providers/feishu.js @@ -27,7 +27,7 @@ class Feishu extends NotificationProvider { content: { post: { zh_cn: { - title: "UptimeKuma Alert: " + monitorJSON["name"], + title: "UptimeKuma Alert: [Down] " + monitorJSON["name"], content: [ [ { @@ -54,7 +54,7 @@ class Feishu extends NotificationProvider { content: { post: { zh_cn: { - title: "UptimeKuma Alert: " + monitorJSON["name"], + title: "UptimeKuma Alert: [Up] " + monitorJSON["name"], content: [ [ { diff --git a/server/routers/api-router.js b/server/routers/api-router.js index fbe8136e5..79e828378 100644 --- a/server/routers/api-router.js +++ b/server/routers/api-router.js @@ -101,6 +101,10 @@ router.get("/api/status-page/config", async (_request, response) => { config.statusPagePublished = true; } + if (! config.statusPageTags) { + config.statusPageTags = false; + } + if (! config.title) { config.title = "Uptime Kuma"; } @@ -140,10 +144,25 @@ router.get("/api/status-page/monitor-list", cache("5 minutes"), async (_request, try { await checkPublished(); const publicGroupList = []; - let list = await R.find("group", " public = 1 ORDER BY weight "); - + const tagsVisible = (await getSettings("statusPage")).statusPageTags; + const list = await R.find("group", " public = 1 ORDER BY weight "); for (let groupBean of list) { - publicGroupList.push(await groupBean.toPublicJSON()); + let monitorGroup = await groupBean.toPublicJSON(); + if (tagsVisible) { + monitorGroup.monitorList = await Promise.all(monitorGroup.monitorList.map(async (monitor) => { + // Includes tags as an array in response, allows for tags to be displayed on public status page + const tags = await R.getAll( + `SELECT monitor_tag.monitor_id, monitor_tag.value, tag.name, tag.color + FROM monitor_tag + JOIN tag + ON monitor_tag.tag_id = tag.id + WHERE monitor_tag.monitor_id = ?`, [monitor.id] + ); + return {...monitor, tags: tags} + })); + } + + publicGroupList.push(monitorGroup); } response.json(publicGroupList); diff --git a/server/server.js b/server/server.js index 0af003d13..d1fd7ff29 100644 --- a/server/server.js +++ b/server/server.js @@ -186,6 +186,15 @@ exports.entryPage = "dashboard"; // Normal Router here // *************************** + // Entry Page + app.get("/", async (_request, response) => { + if (exports.entryPage === "statusPage") { + response.redirect("/status"); + } else { + response.redirect("/dashboard"); + } + }); + // Robots.txt app.get("/robots.txt", async (_request, response) => { let txt = "User-agent: *\nDisallow:"; diff --git a/server/util-server.js b/server/util-server.js index 5d65f46d3..68f59f67f 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -201,8 +201,13 @@ const getDaysRemaining = (validFrom, validTo) => { // param: info - the chain obtained from getPeerCertificate() const parseCertificateInfo = function (info) { let link = info; + let i = 0; + + const existingList = {}; while (link) { + debug(`[${i}] ${link.fingerprint}`); + if (!link.valid_from || !link.valid_to) { break; } @@ -210,15 +215,24 @@ const parseCertificateInfo = function (info) { link.validFor = link.subjectaltname?.replace(/DNS:|IP Address:/g, "").split(", "); link.daysRemaining = getDaysRemaining(new Date(), link.validTo); + existingList[link.fingerprint] = true; + // Move up the chain until loop is encountered if (link.issuerCertificate == null) { break; - } else if (link.fingerprint == link.issuerCertificate.fingerprint) { + } else if (link.issuerCertificate.fingerprint in existingList) { + debug(`[Last] ${link.issuerCertificate.fingerprint}`); link.issuerCertificate = null; break; } else { link = link.issuerCertificate; } + + // Should be no use, but just in case. + if (i > 500) { + throw new Error("Dead loop occurred in parseCertificateInfo"); + } + i++; } return info; @@ -228,6 +242,7 @@ exports.checkCertificate = function (res) { const info = res.request.res.socket.getPeerCertificate(true); const valid = res.request.res.socket.authorized || false; + debug("Parsing Certificate Info"); const parsedInfo = parseCertificateInfo(info); return { diff --git a/src/assets/app.scss b/src/assets/app.scss index e1a5d052d..5578946bd 100644 --- a/src/assets/app.scss +++ b/src/assets/app.scss @@ -189,7 +189,7 @@ textarea.form-control { opacity: 1; } - .table-hover > tbody > tr:hover { + .table-hover > tbody > tr:hover > * { --bs-table-accent-bg: #070a10; color: $dark-font-color; } @@ -346,6 +346,10 @@ textarea.form-control { &.active { background-color: #cdf8f4; } + .tags { + // Removes margin to line up tags list with uptime percentage + margin-left: -0.25rem; + } } } diff --git a/src/components/PublicGroupList.vue b/src/components/PublicGroupList.vue index 23d19e6cd..f30edcef5 100644 --- a/src/components/PublicGroupList.vue +++ b/src/components/PublicGroupList.vue @@ -41,6 +41,9 @@ <Uptime :monitor="monitor.element" type="24" :pill="true" /> {{ monitor.element.name }} </div> + <div class="tags"> + <Tag v-for="tag in monitor.element.tags" :key="tag" :item="tag" :size="'sm'" /> + </div> </div> <div :key="$root.userHeartbeatBar" class="col-3 col-md-4"> <HeartbeatBar size="small" :monitor-id="monitor.element.id" /> @@ -59,12 +62,14 @@ import Draggable from "vuedraggable"; import HeartbeatBar from "./HeartbeatBar.vue"; import Uptime from "./Uptime.vue"; +import Tag from "./Tag.vue"; export default { components: { Draggable, HeartbeatBar, Uptime, + Tag, }, props: { editMode: { diff --git a/src/components/Uptime.vue b/src/components/Uptime.vue index a4bf22f68..2717672c4 100644 --- a/src/components/Uptime.vue +++ b/src/components/Uptime.vue @@ -1,5 +1,5 @@ <template> - <span :class="className">{{ uptime }}</span> + <span :class="className" :title="24 + $t('-hour')">{{ uptime }}</span> </template> <script> diff --git a/src/languages/bg-BG.js b/src/languages/bg-BG.js index 0d5af783a..f1d9b0784 100644 --- a/src/languages/bg-BG.js +++ b/src/languages/bg-BG.js @@ -77,7 +77,7 @@ export default { "Accepted Status Codes": "Допустими статус кодове", Save: "Запази", Notifications: "Известявания", - "Not available, please setup.": "Не е налично. Моля, настройте.", + "Not available, please setup.": "Не са налични. Моля, настройте.", "Setup Notification": "Настройки за известявания", Light: "Светла", Dark: "Тъмна", @@ -141,7 +141,7 @@ export default { Overwrite: "Презапиши", Options: "Опции", "Keep both": "Запази двете", - "Verify Token": "Проверка на токен код", + "Verify Token": "Провери токен код", "Setup 2FA": "Настройка 2FA", "Enable 2FA": "Включи 2FA", "Disable 2FA": "Изключи 2FA", @@ -298,8 +298,13 @@ export default { HeadersInvalidFormat: "Заявените хедъри не са валидни JSON: ", BodyInvalidFormat: "Заявеното съобщение не е валиден JSON: ", "Monitor History": "История на мониторите", - clearDataOlderThan: "Ще се съхранява за {0} дни.", + clearDataOlderThan: "Ще се съхранява {0} дни.", records: "записа", "One record": "Един запис", steamApiKeyDescription: "За да мониторирате Steam Gameserver се нуждаете от Steam Web-API ключ. Може да регистрирате Вашия API ключ тук: ", + clicksendsms: "ClickSend SMS", + apiCredentials: "API удостоверяване", + PasswordsDoNotMatch: "Паролите не съвпадат.", + "Current User": "Текущ потребител", + recent: "Скорошни", }; diff --git a/src/languages/fr-FR.js b/src/languages/fr-FR.js index 062435d73..92083a387 100644 --- a/src/languages/fr-FR.js +++ b/src/languages/fr-FR.js @@ -279,4 +279,29 @@ export default { promosmsTypeSpeed: "SMS SPEED - La plus haute des priorités dans le système. Très rapide et fiable mais cher (environ le double du prix d'un SMS FULL).", promosmsPhoneNumber: "Numéro de téléphone (Poiur les déstinataires Polonais, vous pouvez enlever les codes interna.)", promosmsSMSSender: "SMS Expéditeur : Nom pré-enregistré ou l'un de base: InfoSMS, SMS Info, MaxSMS, INFO, SMS", + "Primary Base URL": "Primary Base URL", + emailCustomSubject: "Sujet personalisé", + clicksendsms: "ClickSend SMS", + checkPrice: "Vérification {0} tarifs:", + apiCredentials: "Crédentials de l'API", + octopushLegacyHint: "Vous utilisez l'ancienne version d'Octopush (2011-2020) ou la nouvelle version ?", + "Feishu WebHookUrl": "Feishu WebHookURL", + matrixHomeserverURL: "L'URL du serveur (avec http(s):// et le port de manière facultatif)", + "Internal Room Id": "ID de la salle interne", + matrixDesc1: "Vous pouvez trouvez l'ID de salle interne en regardant dans la section avancée des paramètres dans le client Matrix. C'est sensé ressembler à: !QMdRCpUIfLwsfjxye6:home.server.", + matrixDesc2: "Il est fortement recommandé de créer un nouvel utilisateur et de ne pas utiliser le jeton d'accès de votre propre utilisateur Matrix, car il vous donnera un accès complet à votre compte et à toutes les salles que vous avez rejointes. Au lieu de cela, créez un nouvel utilisateur et invitez-le uniquement dans la salle dans laquelle vous souhaitez recevoir la notification. Vous pouvez obtenir le jeton d'accès en exécutant {0}", + Method: "Méthode", + Body: "Le corps", + Headers: "En-têtes", + PushUrl: "Push URL", + HeadersInvalidFormat: "L'en-têtes de la requête n'est pas dans un format JSON valide: ", + BodyInvalidFormat: "Le corps de la requête n'est pas dans un format JSON valide: ", + "Monitor History": "Historique de la sonde", + clearDataOlderThan: "Garder l'historique des données de la sonde durant {0} jours.", + PasswordsDoNotMatch: "Les mots de passe ne correspondent pas.", + records: "Enregistrements", + "One record": "Un enregistrement", + steamApiKeyDescription: "Pour surveiller un serveur Steam, vous avez besoin d'une clé Steam Web-API. Vous pouvez enregistrer votre clé ici: ", + "Current User": "Utilisateur actuel", + recent: "Récent", }; diff --git a/src/languages/hr-HR.js b/src/languages/hr-HR.js index 35383a0f3..01674dce8 100644 --- a/src/languages/hr-HR.js +++ b/src/languages/hr-HR.js @@ -2,15 +2,14 @@ export default { languageName: "Hrvatski", checkEverySecond: "Provjera svake {0} sekunde", retryCheckEverySecond: "Ponovni pokušaj svake {0} sekunde", - retriesDescription: "Broj ponovnih pokušaja prije nego će se servis označiti kao DOWN te poslati obavijest", + retriesDescription: "Broj ponovnih pokušaja prije nego će se servis označiti kao nedostupan te poslati obavijest", ignoreTLSError: "Ignoriraj TLS/SSL pogreške za HTTPS web stranice", - upsideDownModeDescription: "Preokreni logiku statusa. Ako je usluga dostupna, smatra se da je DOWN.", + upsideDownModeDescription: "Preokreni logiku statusa. Ako se primi pozitivan odgovor, smatra se da je usluga nedostupna.", maxRedirectDescription: "Maksimalan broj preusmjeravanja. Postaviti na 0 kako bi se preusmjeravanja onemogućila.", acceptedStatusCodesDescription: "Odaberite statusne kodove koji se smatraju uspješnim odgovorom.", passwordNotMatchMsg: "Lozinke se ne poklapaju.", notificationDescription: "Obavijesti će funkcionirati samo ako su dodijeljene monitoru.", - keywordDescription: "Ključna riječ za pretragu kao običan HTML ili u JSON formatu. Pretraga je case-sensitive.", - pauseDashboardHome: "Pauziraj", + keywordDescription: "Ključna riječ za pretragu, u obliku običnog HTML-a ili u JSON formatu. Pretraga je osjetljiva na velika i mala slova.", deleteMonitorMsg: "Jeste li sigurni da želite izbrisati monitor?", deleteNotificationMsg: "Jeste li sigurni da želite izbrisati ovu obavijest za sve monitore?", resoverserverDescription: "Cloudflare je zadani DNS poslužitelj. Možete to promijeniti u bilo kojem trenutku.", @@ -25,7 +24,7 @@ export default { twoFAVerifyLabel: "Unesite svoj 2FA token:", tokenValidSettingsMsg: "Token je važeći! Sada možete spremiti postavke dvofaktorske autentikacije.", confirmEnableTwoFAMsg: "Želite li omogućiti dvofaktorsku autentikaciju?", - confirmDisableTwoFAMsg: "Are you sure you want to disable dvofaktorsku autentikaciju?", + confirmDisableTwoFAMsg: "Jeste li sigurni da želite onemogućiti dvofaktorsku autentikaciju?", Settings: "Postavke", Dashboard: "Kontrolna ploča", "New Update": "Novo ažuriranje", @@ -44,17 +43,18 @@ export default { Down: "Nedostupno", Pending: "U tijeku", Unknown: "Nepoznato", - Pause: "Pauzirano", - Name: "Naziv monitora", + pauseDashboardHome: "Pauzirano", + Name: "Naziv", Status: "Status", DateTime: "Vremenska oznaka", Message: "Izvještaj", "No important events": "Nema važnih događaja", + Pause: "Pauziraj", Resume: "Nastavi", Edit: "Uredi", Delete: "Obriši", Current: "Trenutno", - Uptime: "Uptime", + Uptime: "Dostupnost", "Cert Exp.": "Istek cert.", days: "dana", day: "dan", @@ -65,12 +65,12 @@ export default { Ping: "Odziv", "Monitor Type": "Vrsta Monitora", Keyword: "Ključna riječ", - "Friendly Name": "Lijep naziv", + "Friendly Name": "Prilagođen naziv", URL: "URL", Hostname: "Domaćin", Port: "Port", "Heartbeat Interval": "Interval provjere", - Retries: "Ponovnih pokušaja", + Retries: "Broj ponovnih pokušaja", "Heartbeat Retry Interval": "Interval ponovnih pokušaja", Advanced: "Napredne postavke", "Upside Down Mode": "Obrnuti način", @@ -86,14 +86,14 @@ export default { Light: "Svijetli način", Dark: "Tamni način", Auto: "Automatski", - "Theme - Heartbeat Bar": "Tema - Statusna traka", + "Theme - Heartbeat Bar": "Tema za traku dostupnosti", Normal: "Normalno", Bottom: "Ispod", None: "Isključeno", Timezone: "Vremenska zona", - "Search Engine Visibility": "Vidljivost pretraživačima", + "Search Engine Visibility": "Vidljivost tražilicama", "Allow indexing": "Dopusti indeksiranje", - "Discourage search engines from indexing site": "Sprječavanje indeksiranja stranice", + "Discourage search engines from indexing site": "Sprječavanje indeksiranja", "Change Password": "Promjena lozinke", "Current Password": "Trenutna lozinka", "New Password": "Nova lozinka", @@ -103,7 +103,7 @@ export default { "Enable Auth": "Omogući autentikaciju", Logout: "Odjava", Leave: "Poništi", - "I understand, please disable": "Razumijem, onemogući", + "I understand, please disable": "Razumijem, svejedno onemogući", Confirm: "Potvrda", Yes: "Da", No: "Ne", @@ -112,10 +112,10 @@ export default { "Remember me": "Zapamti me", Login: "Prijava", "No Monitors, please": "Nema monitora, ", - "add one": "dodaj jednog", + "add one": "dodaj jedan", "Notification Type": "Tip obavijesti", Email: "E-pošta", - Test: "Test", + Test: "Testiraj", "Certificate Info": "Informacije o certifikatu", "Resolver Server": "DNS poslužitelj", "Resource Record Type": "Vrsta DNS zapisa", @@ -130,14 +130,14 @@ export default { notAvailableShort: "N/A", "Default enabled": "Omogući za nove monitore", "Apply on all existing monitors": "Primijeni na postojeće monitore", - Create: "Create", - "Clear Data": "Clear Data", - Events: "Events", + Create: "Kreiraj", + "Clear Data": "Obriši podatke", + Events: "Događaji", Heartbeats: "Provjere", "Auto Get": "Automatski dohvat", backupDescription: "Moguće je napraviti sigurnosnu kopiju svih monitora i obavijesti koja će biti spremljena kao JSON datoteka.", backupDescription2: "Napomena: povijest i podaci o događajima nisu uključeni u sigurnosnu kopiju.", - backupDescription3: "Osjetljivi podaci poput tokena za obavijesti jesu uključeni u sigurnosnu kopiju. Zato je potrebno čuvati izvoz na sigurnom mjestu.", + backupDescription3: "Osjetljivi podaci poput tokena za obavijesti uključeni su u sigurnosnu kopiju. Zato je potrebno čuvati izvoz na sigurnom mjestu.", alertNoFile: "Datoteka za uvoz nije odabrana.", alertWrongFileType: "Datoteka za uvoz nije u JSON formatu.", "Clear all statistics": "Obriši sve statistike", @@ -152,7 +152,7 @@ export default { "2FA Settings": "Postavke 2FA", "Two Factor Authentication": "Dvofaktorska autentikacija", Active: "Aktivna", - Inactive: "Neaktivna", + Inactive: "Neaktivno", Token: "Token", "Show URI": "Pokaži URI", Tags: "Oznake", @@ -172,7 +172,7 @@ export default { "Search...": "Pretraga...", "Avg. Ping": "Prosječni odziv", "Avg. Response": "Prosječni odgovor", - "Entry Page": "Entry Page", + "Entry Page": "Početna stranica", statusPageNothing: "Ovdje nema ničega, dodajte grupu ili monitor.", "No Services": "Nema usluga", "All Systems Operational": "Svi sustavi su operativni", @@ -183,7 +183,7 @@ export default { "Edit Status Page": "Uredi Statusnu stranicu", "Go to Dashboard": "Na Kontrolnu ploču", "Status Page": "Statusna stranica", - defaultNotificationName: "Moja {notification} obavijest ({number})", + defaultNotificationName: "Moja {number}. {notification} obavijest", here: "ovdje", Required: "Potrebno", telegram: "Telegram", @@ -195,11 +195,11 @@ export default { "YOUR BOT TOKEN HERE": "OVDJE IDE TOKEN BOTA", chatIDNotFound: "ID razgovora nije pronađen; prvo morate poslati poruku botu", webhook: "Webhook", - "Post URL": "Post URL", + "Post URL": "URL Post zahtjeva", "Content Type": "Tip sadržaja (Content Type)", webhookJsonDesc: "{0} je dobra opcija za moderne HTTP poslužitelje poput Express.js-a", webhookFormDataDesc: "{multipart} je moguća alternativa za PHP, samo je potrebno parsirati JSON koristeći {decodeFunction}", - smtp: "E-pošta (SMTP)", + smtp: "E-mail (SMTP)", secureOptionNone: "Bez sigurnosti / STARTTLS (25, 587)", secureOptionTLS: "TLS (465)", "Ignore TLS Error": "Ignoriraj greške TLS-a", @@ -215,7 +215,7 @@ export default { "Prefix Custom Message": "Prefiks prilagođene poruke", "Hello @everyone is...": "Pozdrav {'@'}everyone...", teams: "Microsoft Teams", - "Webhook URL": "URL Teams webhooka", + "Webhook URL": "URL webhooka", wayToGetTeamsURL: "Više informacija o Teams webhookovima možete pročitati {0}.", signal: "Signal", Number: "Broj", @@ -242,7 +242,7 @@ export default { promosms: "PromoSMS", clicksendsms: "ClickSend SMS", lunasea: "LunaSea", - apprise: "Apprise (Support 50+ Notification services)", + apprise: "Apprise (Podržava preko 50 usluga za obavijesti)", pushbullet: "Pushbullet", line: "LINE", mattermost: "Mattermost", @@ -307,4 +307,5 @@ export default { "Showing {from} to {to} of {count} records": "Prikaz zapisa {from}-{to} od sveukupno {count}", steamApiKeyDescription: "Za praćenje Steam poslužitelja za igru, potrebno je imati Steam Web-API ključ. Možete registrirati vlastiti ključ ovdje: ", "Current User": "Trenutni korisnik", + recent: "Nedavno", }; diff --git a/src/languages/it-IT.js b/src/languages/it-IT.js index 5ddc414f7..5257a217f 100644 --- a/src/languages/it-IT.js +++ b/src/languages/it-IT.js @@ -33,6 +33,7 @@ export default { Appearance: "Aspetto", Theme: "Tema", General: "Generali", + "Primary Base URL": "URL base primario", Version: "Versione", "Check Update On GitHub": "Controlla aggiornamenti su GitHub", List: "Lista", @@ -64,7 +65,7 @@ export default { Ping: "Ping", "Monitor Type": "Tipo di Monitoraggio", Keyword: "Parola chiave", - "Friendly Name": "Nome Amichevole", + "Friendly Name": "Nomignolo", URL: "URL", Hostname: "Nome Host", Port: "Porta", @@ -75,6 +76,9 @@ export default { "Upside Down Mode": "Modalità capovolta", "Max. Redirects": "Reindirizzamenti massimi", "Accepted Status Codes": "Codici di stato accettati", + "Push URL": "Push URL", + needPushEvery: "Notificare questo URL ogni {0} secondi.", + pushOptionalParams: "Parametri aggiuntivi: {0}", Save: "Salva", Notifications: "Notifiche", "Not available, please setup.": "Non disponibili, da impostare.", @@ -166,8 +170,8 @@ export default { Purple: "Viola", Pink: "Rosa", "Search...": "Cerca...", - "Avg. Ping": "Ping medio", - "Avg. Response": "Risposta media", + "Avg. Ping": "Tempo di risposta al ping medio", + "Avg. Response": "Tempo di risposta medio", "Entry Page": "Entry Page", statusPageNothing: "Non c'è nulla qui, aggiungere un gruppo oppure un monitoraggio.", "No Services": "Nessun Servizio", @@ -178,23 +182,129 @@ export default { "Add a monitor": "Aggiungi un monitoraggio", "Edit Status Page": "Modifica pagina di stato", "Go to Dashboard": "Vai al Cruscotto", - "Status Page": "Status Page", - telegram: "Telegram", - webhook: "Webhook", - smtp: "Email (SMTP)", - discord: "Discord", - teams: "Microsoft Teams", - signal: "Signal", - gotify: "Gotify", - slack: "Slack", + "Status Page": "Pagina di stato", + defaultNotificationName: "Allarme {notification} ({number})", + here: "qui", + "Required": "Richiesto", + "telegram": "Telegram", + "Bot Token": "Token del Bot", + "You can get a token from": "Puoi ricevere un token da", + "Chat ID": "ID Chat", + supportTelegramChatID: "Supporta Chat dirette / di Gruppo / ID Canale", + wayToGetTelegramChatID: "Puoi ricereve l'ID chat mandando un messaggio al bot andando in questo url per visualizzare il chat_id:", + "YOUR BOT TOKEN HERE": "QUI IL TOKEN DEL BOT", + chatIDNotFound: "Non trovo l'ID chat. Prima bisogna mandare un messaggio al bot", + "webhook": "Webhook", + "Post URL": "Post URL", + "Content Type": "Content Type", + webhookJsonDesc: "{0} va bene per qualsiasi server http moderno ad esempio express.js", + webhookFormDataDesc: "{multipart} va bene per PHP, c'è solo bisogno di analizzare il json con {decodeFunction}", + "smtp": "E-mail (SMTP)", + secureOptionNone: "Nessuno / STARTTLS (25, 587)", + secureOptionTLS: "TLS (465)", + "Ignore TLS Error": "Ignora gli errori TLS", + "From Email": "Mittente", + emailCustomSubject: "Oggetto personalizzato", + "To Email": "Destinatario", + smtpCC: "CC", + smtpBCC: "CCn", + "discord": "Discord", + "Discord Webhook URL": "URL Webhook di Discord", + wayToGetDiscordURL: "È possibile recuperarlo da Impostazioni server -> Integrazioni -> Creare Webhook", + "Bot Display Name": "Nome del Bot", + "Prefix Custom Message": "Prefisso per il messaggio personalizzato", + "Hello @everyone is...": "Ciao a {'@'}everyone ...", + "teams": "Microsoft Teams", + "Webhook URL": "URL Webhook", + wayToGetTeamsURL: "È possibile imparare a creare un URL Webhook {0}.", + "signal": "Signal", + "Number": "Numero", + "Recipients": "Destinatari", + needSignalAPI: "È necessario avere un client Signal con le API REST.", + wayToCheckSignalURL: "Controllare questo url per capire come impostarne uno:", + signalImportant: "IMPORTANTE: Non è possibile mischiare gruppi e numeri all'interno dei destinatari!", + "gotify": "Gotify", + "Application Token": "Token Applicazione", + "Server URL": "URL Server", + "Priority": "Priorità", + "slack": "Slack", + "Icon Emoji": "Icona Emoji", + "Channel Name": "Nome Canale", + "Uptime Kuma URL": "Indirizzo Uptime Kuma", + aboutWebhooks: "Maggiori informazioni riguardo ai webhooks su: {0}", + aboutChannelName: "Inserire il nome del canale nel campo \"Nome Canale\" {0} se si vuole bypassare il canale webhook. Ad esempio: #altro-canale", + aboutKumaURL: "Se si lascia bianco il campo Indirizzo Uptime Kuma, la pagina GitHub sarà il valore predefinito.", + emojiCheatSheet: "Lista Emoji: {0}", "rocket.chat": "Rocket.chat", pushover: "Pushover", pushy: "Pushy", octopush: "Octopush", promosms: "PromoSMS", + clicksendsms: "ClickSend SMS", lunasea: "LunaSea", - apprise: "Apprise (Support 50+ Notification services)", + apprise: "Apprise (Supporta più di 50 servizi di notifica)", pushbullet: "Pushbullet", line: "Line Messenger", mattermost: "Mattermost", + "User Key": "Chiave Utente", + "Device": "Dispositivo", + "Message Title": "Titolo Messaggio", + "Notification Sound": "Suono di Notifica", + "More info on:": "Maggiori informazioni su: {0}", + pushoverDesc1: "Priorità di Emergenza (2) ha 30 secondi di timeout tra un tentativo e l'altro e scadrà dopo un'ora.", + pushoverDesc2: "Se si vuole inviare la notifica a dispositivi differenti, riempire il campo Dispositivi.", + "SMS Type": "Tipo di SMS", + octopushTypePremium: "Premium (Veloce - raccomandato per allertare)", + octopushTypeLowCost: "A Basso Costo (Lento - talvolta bloccato dall'operatore)", + checkPrice: "Controlla {0} prezzi:", + apiCredentials: "Credenziali API", + octopushLegacyHint: "Si vuole utilizzare la vecchia versione (2011-2020) oppure la nuova versione di Octopush?", + "Check octopush prices": "Controlla i prezzi di Octopush {0}.", + octopushPhoneNumber: "Numero di telefono (formato internazionale (p.e.): +33612345678) ", + octopushSMSSender: "Nome del mittente: 3-11 caratteri alfanumerici e spazi (a-zA-Z0-9)", + "LunaSea Device ID": "ID dispositivo LunaSea", + "Apprise URL": "URL Apprise", + "Example:": "Esempio: {0}", + "Read more:": "Maggiori informazioni: {0}", + "Status:": "Stato: {0}", + "Read more": "Maggiori informazioni", + appriseInstalled: "Apprise è installato.", + appriseNotInstalled: "Apprise non è installato. {0}", + "Access Token": "Token di accesso", + "Channel access token": "Token di accesso al canale", + "Line Developers Console": "Console sviluppatori Line", + lineDevConsoleTo: "Console sviluppatori Line - {0}", + "Basic Settings": "Impostazioni Base", + "User ID": "ID Utente", + "Messaging API": "API di Messaggistica", + wayToGetLineChannelToken: "Prima accedi a {0}, crea un provider e un canale (API di Messaggistica), dopodiché puoi avere il token di accesso e l'id utente dal menù sopra.", + "Icon URL": "URL Icona", + aboutIconURL: "È possibile impostare un collegameno a una immagine in \"URL Icona\" per modificare l'immagine di profilo. Non verrà utilizzata se è impostata l'Icona Emoji.", + aboutMattermostChannelName: "È possibile modificare il canale predefinito che dove il webhook manda messaggi immettendo il nome del canale nel campo \"Nome Canale\". Questo va abilitato nelle impostazioni webhook di Mattermost webhook. P.E.: #altro-canale", + "matrix": "Matrix", + promosmsTypeEco: "SMS ECO - economico, ma lento e spesso sovraccarico. Limitato solamente a destinatari Polacchi.", + promosmsTypeFlash: "SMS FLASH - Il messaggio sarà automaticamente mostrato sul dispositivo dei destinatari. Limitato solo a destinatari Polacchi.", + promosmsTypeFull: "SMS FULL - Premium, È possibile utilizzare il proprio come come mittente (è necessario prima registrare il nome). Affidabile per gli allarmi.", + promosmsTypeSpeed: "SMS SPEED - Maggior priorità. Rapido, affidabile, ma costoso (costa il doppio di SMS FULL).", + promosmsPhoneNumber: "Numero di Telefono (per destinatari Polacchi si può omettere il codice area)", + promosmsSMSSender: "Mittente SMS : Nome preregistrato oppure uno dei seguenti: InfoSMS, SMS Info, MaxSMS, INFO, SMS", + "Feishu WebHookUrl": "URL WebHook di Feishu", + matrixHomeserverURL: "URL Server (con http(s):// e opzionalmente la porta)", + "Internal Room Id": "ID Stanza Interna", + matrixDesc1: "È possibile recuperare l'ID della stanza all'interno delle impostazioni avanzate della stanza nel client Matrix. Dovrebbe essere simile a !QMdRCpUIfLwsfjxye6:server.di.casa.", + matrixDesc2: "È altamente raccomandata la creazione di un nuovo utente e di non utilizare il proprio token di accesso Matrix poiché darà pieno controllo al proprio account e a tutte le stanze in cui si ha accesso. Piuttosto, si crei un nuovo utente per invitarlo nella stanza dove si vuole ricevere le notifiche. Si può accedere al token eseguendo {0}", + Method: "Metodo", + Body: "Corpo", + Headers: "Headers", + PushUrl: "URL di Push", + HeadersInvalidFormat: "L'header di richiesta non è un JSON valido: ", + BodyInvalidFormat: "Il corpo di richiesta non è un JSON valido: ", + "Monitor History": "Storico monitoraggio", + clearDataOlderThan: "Mantieni lo storico per {0} giorni.", + PasswordsDoNotMatch: "Le password non corrispondono.", + records: "records", + "One record": "One record", + steamApiKeyDescription: "Per monitorare un server di gioco Steam si necessita della chiave Steam Web-API. È possibile registrare la propria chiave API qui: ", + "Current User": "Utente corrente", + recent: "Recenti", }; diff --git a/src/languages/nl-NL.js b/src/languages/nl-NL.js index 818893af6..ff18832d7 100644 --- a/src/languages/nl-NL.js +++ b/src/languages/nl-NL.js @@ -116,7 +116,7 @@ export default { "Repeat Password": "Herhaal wachtwoord", Export: "Exporteren", Import: "Importeren", - respTime: "resp. tijd (ms)", + respTime: "reactietijd (ms)", notAvailableShort: "N.v.t.", "Default enabled": "Default enabled", "Apply on all existing monitors": "Pas toe op alle bestaande monitors", @@ -138,48 +138,48 @@ export default { "Two Factor Authentication": "Two Factor Authenticatie", Active: "Actief", Inactive: "Inactief", - "Also apply to existing monitors": "Also apply to existing monitors", + "Also apply to existing monitors": "Voeg ook toe aan bestaande monitors", Token: "Token", "Show URI": "Toon URI", "Clear all statistics": "Wis alle statistieken", - retryCheckEverySecond: "Retry every {0} seconds.", - importHandleDescription: "Choose 'Skip existing' if you want to skip every monitor or notification with the same name. 'Overwrite' will delete every existing monitor and notification.", - confirmImportMsg: "Are you sure to import the backup? Please make sure you've selected the right import option.", + retryCheckEverySecond: "Probeer elke {0} seconden.", + importHandleDescription: "Kies 'Sla bestaande over' als je elke monitor of melding met dezelfde naam wilt overslaan. Kies 'Overschrijf' als je elke monitor of notificatie wilt verwijderen.", + confirmImportMsg: "Weet je zeker dat je dit bestand wilt importeren?", "Heartbeat Retry Interval": "Heartbeat Retry Interval", - "Import Backup": "Import Backup", - "Export Backup": "Export Backup", - "Skip existing": "Skip existing", - Overwrite: "Overwrite", - Options: "Options", - "Keep both": "Keep both", - Tags: "Tags", - "Add New below or Select...": "Add New below or Select...", - "Tag with this name already exist.": "Tag with this name already exist.", - "Tag with this value already exist.": "Tag with this value already exist.", - color: "color", - "value (optional)": "value (optional)", - Gray: "Gray", - Red: "Red", - Orange: "Orange", - Green: "Green", - Blue: "Blue", + "Import Backup": "Importeer Backup", + "Export Backup": "Exporteer Backup", + "Skip existing": "Sla bestaande over", + Overwrite: "Overschrijf", + Options: "Opties", + "Keep both": "Bewaar beide", + Tags: "Labels", + "Add New below or Select...": "Voeg nieuwe toe of selecteer...", + "Tag with this name already exist.": "Label met deze naam bestaat al", + "Tag with this value already exist.": "Label met deze waarde bestaat al", + color: "Kleur", + "value (optional)": "waarde (optioneel)", + Gray: "Grijs", + Red: "Rood", + Orange: "Oranje", + Green: "Groen", + Blue: "Blauw", Indigo: "Indigo", - Purple: "Purple", - Pink: "Pink", - "Search...": "Search...", - "Avg. Ping": "Avg. Ping", - "Avg. Response": "Avg. Response", + Purple: "Paars", + Pink: "Roze", + "Search...": "Zoeken...", + "Avg. Ping": "Gemiddelde Ping", + "Avg. Response": "Gemiddelde Response", "Entry Page": "Entry Page", - statusPageNothing: "Nothing here, please add a group or a monitor.", + statusPageNothing: "Niets hier, voeg een groep of monitor toe.", "No Services": "No Services", - "All Systems Operational": "All Systems Operational", - "Partially Degraded Service": "Partially Degraded Service", - "Degraded Service": "Degraded Service", - "Add Group": "Add Group", - "Add a monitor": "Add a monitor", - "Edit Status Page": "Edit Status Page", - "Go to Dashboard": "Go to Dashboard", - "Status Page": "Status Page", + "All Systems Operational": "Alle systemen operationeel", + "Partially Degraded Service": "Gedeeltelijk verminderde prestaties", + "Degraded Service": "Verminderde prestaties", + "Add Group": "Voeg groep toe", + "Add a monitor": "Voeg monitor toe", + "Edit Status Page": "Wijzig status pagina", + "Go to Dashboard": "Ga naar Dashboard", + "Status Page": "Status Pagina", telegram: "Telegram", webhook: "Webhook", smtp: "Email (SMTP)", diff --git a/src/languages/pl.js b/src/languages/pl.js index 747ca1ad1..082980d3b 100644 --- a/src/languages/pl.js +++ b/src/languages/pl.js @@ -28,7 +28,7 @@ export default { confirmDisableTwoFAMsg: "Jesteś pewien, że chcesz wyłączyć 2FA?", Settings: "Ustawienia", Dashboard: "Panel", - "New Update": "Nowa Aktualizacja", + "New Update": "Nowa aktualizacja", Language: "Język", Appearance: "Wygląd", Theme: "Motyw", @@ -37,7 +37,7 @@ export default { "Check Update On GitHub": "Sprawdź aktualizację na GitHub", List: "Lista", Add: "Dodaj", - "Add New Monitor": "Dodaj Monitor", + "Add New Monitor": "Dodaj monitor", "Quick Stats": "Szybki podgląd statystyk", Up: "Online", Down: "Offline", @@ -53,8 +53,8 @@ export default { Edit: "Edytuj", Delete: "Usuń", Current: "Aktualny", - Uptime: "Czas Pracy", - "Cert Exp.": "Certyfikat Wygasa", + Uptime: "Czas pracy", + "Cert Exp.": "Certyfikat wygasa", days: "dni", day: "dzień", "-day": " dni", @@ -62,9 +62,9 @@ export default { "-hour": " godzin", Response: "Odpowiedź", Ping: "Ping", - "Monitor Type": "Rodzaj Monitora", + "Monitor Type": "Rodzaj monitora", Keyword: "Słowo kluczowe", - "Friendly Name": "Przyjazna Nazwa", + "Friendly Name": "Przyjazna nazwa", URL: "URL", Hostname: "Hostname", Port: "Port", @@ -73,12 +73,12 @@ export default { "Heartbeat Retry Interval": "Częstotliwość ponawiania bicia serca", Advanced: "Zaawansowane", "Upside Down Mode": "Tryb odwrócony", - "Max. Redirects": "Maks. Przekierowań", + "Max. Redirects": "Maks. przekierowań", "Accepted Status Codes": "Akceptowane kody statusu", Save: "Zapisz", Notifications: "Powiadomienia", "Not available, please setup.": "Niedostępne, proszę skonfigurować.", - "Setup Notification": "Skonfiguruj Powiadomienie", + "Setup Notification": "Skonfiguruj powiadomienie", Light: "Jasny", Dark: "Ciemny", Auto: "Automatyczny", @@ -122,7 +122,7 @@ export default { "Export Backup": "Eksportuj kopię zapasową", Export: "Eksportuj", Import: "Importuj", - respTime: "Czas Odp. (ms)", + respTime: "Czas odp. (ms)", notAvailableShort: "N/A", "Default enabled": "Włącz domyślnie", "Apply on all existing monitors": "Zastosuj do istniejących monitorów", @@ -183,10 +183,10 @@ export default { here: "tutaj", Required: "Wymagane", telegram: "Telegram", - "Bot Token": "Token Bota", + "Bot Token": "Token bota", wayToGetTelegramToken: "Token można uzyskać z {0}.", - "Chat ID": "Identyfikator Czatu", - supportTelegramChatID: "Czat wsprarcia technicznego / Bezpośrednia Rozmowa / Czat Grupowy", + "Chat ID": "Identyfikator czatu", + supportTelegramChatID: "Czat wsparcia technicznego / Bezpośrednia rozmowa / Czat grupowy", wayToGetTelegramChatID: "Możesz uzyskać swój identyfikator czatu, wysyłając wiadomość do bota i przechodząc pod ten adres URL, aby wyświetlić identyfikator czatu:", "YOUR BOT TOKEN HERE": "TWOJ TOKEN BOTA", chatIDNotFound: "Identyfikator czatu nie znaleziony, najpierw napisz do bota", @@ -198,20 +198,20 @@ export default { smtp: "Email (SMTP)", secureOptionNone: "Brak / STARTTLS (25, 587)", secureOptionTLS: "TLS (465)", - "Ignore TLS Error": "Zignrouj Błędy TLS", + "Ignore TLS Error": "Zignoruj błędy TLS", "From Email": "Nadawca (OD)", "To Email": "Odbiorca (DO)", smtpCC: "DW", smtpBCC: "UDW", discord: "Discord", - "Discord Webhook URL": "URL Webhook Discorda", - wayToGetDiscordURL: "Możesz go uzyskać przechodząc do Ustawienia Serwera -> Integracje -> Tworzenie Webhooka", - "Bot Display Name": "Wyświetlana Nazwa Bota", - "Prefix Custom Message": "Własny Początek Wiadomości", + "Discord Webhook URL": "URL webhook Discorda", + wayToGetDiscordURL: "Możesz go uzyskać przechodząc do Ustawienia serwera -> Integracje -> Tworzenie webhooka", + "Bot Display Name": "Wyświetlana nazwa bota", + "Prefix Custom Message": "Własny początek wiadomości", "Hello @everyone is...": "Hej {'@'}everyone ...", teams: "Microsoft Teams", - "Webhook URL": "URL Webhooka", - wayToGetTeamsURL: "You can learn how to create a webhook url {0}.", + "Webhook URL": "URL webhooka", + wayToGetTeamsURL: "Możesz dowiedzieć się, jak utworzyć adres url webhooka {0}.", signal: "Signal", Number: "Numer", Recipients: "Odbiorcy", @@ -219,66 +219,66 @@ export default { wayToCheckSignalURL: "W celu dowiedzenia się, jak go skonfigurować, odwiedź poniższy link:", signalImportant: "UWAGA: Nie można mieszać nazw grup i numerów odbiorców!", gotify: "Gotify", - "Application Token": "Token Aplikacji", + "Application Token": "Token aplikacji", "Server URL": "Server URL", Priority: "Priorytet", slack: "Slack", - "Icon Emoji": "Ikona Emoji", - "Channel Name": "Nazwa Kanału", + "Icon Emoji": "Ikona emoji", + "Channel Name": "Nazwa kanału", "Uptime Kuma URL": "Adres Uptime Kuma", aboutWebhooks: "Więcej informacji na temat webhooków: {0}", - aboutChannelName: "Podaj nazwę kanału {0} w polu Nazwa Kanału, jeśli chcesz pominąć kanał webhooka. Np.: #inny-kanal", - aboutKumaURL: "Jeśli pozostawisz pole Adres Uptime Kuma puste, domyślnie będzie to strona projektu na Github.", - emojiCheatSheet: "Ściąga Emoji: {0}", + aboutChannelName: "Podaj nazwę kanału {0} w polu Nazwa kanału, jeśli chcesz pominąć kanał webhooka. Np.: #inny-kanal", + aboutKumaURL: "Jeśli pozostawisz pole Adres Uptime Kuma puste, domyślnie będzie to strona projektu na GitHub.", + emojiCheatSheet: "Ściąga emoji: {0}", "rocket.chat": "Rocket.chat", pushover: "Pushover", pushy: "Pushy", octopush: "Octopush", promosms: "PromoSMS", lunasea: "LunaSea", - apprise: "Apprise (Obsługuje 50+ usług powiadomień)", + apprise: "Apprise (obsługuje 50+ usług powiadomień)", pushbullet: "Pushbullet", line: "Line Messenger", mattermost: "Mattermost", - "User Key": "Klucz Użytkownika", + "User Key": "Klucz użytkownika", Device: "Urządzenie", - "Message Title": "Tytuł Wiadomości", - "Notification Sound": "Dźwięk Powiadomienia", + "Message Title": "Tytuł wiadomości", + "Notification Sound": "Dźwięk powiadomienia", "More info on:": "Więcej informacji na: {0}", pushoverDesc1: "Priorytet awaryjny (2) ma domyślny 30-sekundowy limit czasu między kolejnymi próbami i wygaśnie po 1 godzinie.", pushoverDesc2: "Jeśli chcesz wysyłać powiadomienia na różne urządzenia, wypełnij pole Urządzenie.", "SMS Type": "Rodzaj SMS", - octopushTypePremium: "Premium (Szybki - rekomendowany dla powiadomień)", - octopushTypeLowCost: "Low Cost (Wolny, czasami blokowany przez operatorów)", + octopushTypePremium: "Premium (szybki - rekomendowany dla powiadomień)", + octopushTypeLowCost: "Low Cost (wolny, czasami blokowany przez operatorów)", "Check octopush prices": "Sprawdź ceny Octopush {0}.", - octopushPhoneNumber: "Numer Telefonu (Format międzynarodowy np.: +33612345678)", - octopushSMSSender: "Nadawca SMS : 3-11 znaków alfanumerycznych i spacji (a-zA-Z0-9)", - "LunaSea Device ID": "Idetyfikator Urządzenia LunaSea", + octopushPhoneNumber: "Numer telefonu (format międzynarodowy np.: +33612345678)", + octopushSMSSender: "Nadawca SMS: 3-11 znaków alfanumerycznych i spacji (a-zA-Z0-9)", + "LunaSea Device ID": "Identyfikator urządzenia LunaSea", "Apprise URL": "URL Apprise", "Example:": "Przykład: {0}", - "Read more:": "Czytaj Dalej: {0}", + "Read more:": "Czytaj dalej: {0}", "Status:": "Status: {0}", "Read more": "Czytaj dalej", appriseInstalled: "Apprise jest zostało zainstalowane.", appriseNotInstalled: "Apprise nie zostało zainstalowane. {0}", - "Access Token": "Token Dostępu", - "Channel access token": "Token Dostępu Kanału", - "Line Developers Console": "Konsola Dewelopersja Line", - lineDevConsoleTo: "Konsola Dewelopersja Line - {0}", - "Basic Settings": "Ustawienia Ogólne", - "User ID": "Idetyfikator Użytkownika", - "Messaging API": "API Wiadomości", + "Access Token": "Token dostępu", + "Channel access token": "Token dostępu kanału", + "Line Developers Console": "Konsola deweloperska Line", + lineDevConsoleTo: "Konsola deweloperska Line - {0}", + "Basic Settings": "Ustawienia ogólne", + "User ID": "Identyfikator użytkownika", + "Messaging API": "API wiadomości", wayToGetLineChannelToken: "Najpierw uzyskaj dostęp do {0}, utwórz dostawcę i kanał (Messaging API), a następnie możesz uzyskać token dostępu do kanału i identyfikator użytkownika z wyżej wymienionych pozycji menu.", "Icon URL": "Adres Ikony", - aboutIconURL: "Możesz podać link do zdjęcia w \"Adres URL ikony\", aby zastąpić domyślne zdjęcie profilowe. Nie będzie używany, jeśli ustawiona jest ikona Emoji.", - aboutMattermostChannelName: "Możesz zastąpić domyślny kanał, na którym publikowane są posty webhooka, wpisując nazwę kanału w polu \"Nazwa Kanału\". Należy to włączyć w ustawieniach webhooka Mattermost. Np.: #inny-kanał", + aboutIconURL: "Możesz podać link do zdjęcia w \"Adres URL ikony\", aby zastąpić domyślne zdjęcie profilowe. Nie będzie używany, jeśli ustawiona jest ikona emoji.", + aboutMattermostChannelName: "Możesz zastąpić domyślny kanał, na którym publikowane są posty webhooka, wpisując nazwę kanału w polu \"Nazwa kanału\". Należy to włączyć w ustawieniach webhooka Mattermost. Np.: #inny-kanał", matrix: "Matrix", - promosmsTypeEco: "SMS ECO - Tanie, lecz wolne. Dostępne tylko w Polsce", - promosmsTypeFlash: "SMS FLASH - Wiadomość automatycznie wyświetli się na urządzeniu. Dostępne tylko w Polsce.", - promosmsTypeFull: "SMS FULL - Szybkie i dostępne międzynarodowo. Wersja premium usługi, która pozwala min. ustawić własną nazwę nadawcy.", - promosmsTypeSpeed: "SMS SPEED - Wysyłka priorytetowa, posiada wszystkie zalety SMS FULL", - promosmsPhoneNumber: "Numer Odbiorcy", - promosmsSMSSender: "Nadawca SMS (Wcześniej zatwierdzone nazwy z panelu PromoSMS)", + promosmsTypeEco: "SMS ECO - tanie, lecz wolne. Dostępne tylko w Polsce", + promosmsTypeFlash: "SMS FLASH - wiadomość automatycznie wyświetli się na urządzeniu. Dostępne tylko w Polsce.", + promosmsTypeFull: "SMS FULL - szybkie i dostępne międzynarodowo. Wersja premium usługi, która pozwala min. ustawić własną nazwę nadawcy.", + promosmsTypeSpeed: "SMS SPEED - wysyłka priorytetowa, posiada wszystkie zalety SMS FULL", + promosmsPhoneNumber: "Numer odbiorcy", + promosmsSMSSender: "Nadawca SMS (wcześniej zatwierdzone nazwy z panelu PromoSMS)", "Primary Base URL": "Główny URL", "Push URL": "Push URL", needPushEvery: "Powinieneś wywoływać ten URL co {0} sekund", @@ -305,4 +305,6 @@ export default { steamApiKeyDescription: "Do monitorowania serwera gier Steam potrzebny jest klucz Steam Web-API. Możesz zarejestrować swój klucz API tutaj: ", "Current User": "Aktualny użytkownik", recent: "Ostatnie", + clicksendsms: "ClickSend SMS", + apiCredentials: "Poświadczenia API", }; diff --git a/src/mixins/socket.js b/src/mixins/socket.js index 170a07a73..affac4f82 100644 --- a/src/mixins/socket.js +++ b/src/mixins/socket.js @@ -1,5 +1,6 @@ import { io } from "socket.io-client"; import { useToast } from "vue-toastification"; +import jwt_decode from "jwt-decode"; const toast = useToast(); let socket; @@ -217,6 +218,15 @@ export default { return (this.remember) ? localStorage : sessionStorage; }, + getJWTPayload() { + const jwtToken = this.$root.storage().token; + + if (jwtToken && jwtToken !== "autoLogin") { + return jwt_decode(jwtToken); + } + return undefined; + }, + getSocket() { return socket; }, diff --git a/src/pages/Settings.vue b/src/pages/Settings.vue index 9312b0c24..9d501407d 100644 --- a/src/pages/Settings.vue +++ b/src/pages/Settings.vue @@ -306,7 +306,7 @@ <p>这是为 <strong>有第三方认证</strong> 的用户提供的功能,如 Cloudflare Access</p> <p>请谨慎使用!</p> </template> - + <template v-else-if="$i18n.locale === 'zh-TW' "> <p>你是否要<strong>取消登入驗證</strong>?</p> <p>此功能是設計給已有<strong>第三方認證</strong>的使用者,例如 Cloudflare Access。</p> @@ -515,9 +515,11 @@ export default { }, loadUsername() { - const jwtToken = this.$root.storage().token; - const jwtPayload = jwt_decode(jwtToken); - this.username = jwtPayload.username; + const jwtPayload = this.$root.getJWTPayload(); + + if (jwtPayload) { + this.username = jwtPayload.username; + } }, loadSettings() { @@ -568,6 +570,7 @@ export default { this.settings.disableAuth = false; this.saveSettings(); this.$root.storage().removeItem("token"); + location.reload(); }, downloadBackup() { diff --git a/src/pages/StatusPage.vue b/src/pages/StatusPage.vue index 87634f35a..ce0f94b55 100644 --- a/src/pages/StatusPage.vue +++ b/src/pages/StatusPage.vue @@ -77,6 +77,17 @@ <font-awesome-icon icon="save" /> {{ $t("Switch to Dark Theme") }} </button> + + <button class="btn btn-secondary me-2" @click="changeTagsVisibilty(!tagsVisible)"> + <template v-if="tagsVisible"> + <font-awesome-icon icon="eye-slash" /> + {{ $t("Hide Tags") }} + </template> + <template v-else> + <font-awesome-icon icon="eye" /> + {{ $t("Show Tags") }} + </template> + </button> </div> </div> @@ -292,6 +303,10 @@ export default { return this.config.statusPageTheme; }, + tagsVisible() { + return this.config.statusPageTags + }, + logoClass() { if (this.editMode) { return { @@ -472,6 +487,25 @@ export default { changeTheme(name) { this.config.statusPageTheme = name; }, + changeTagsVisibilty(newState) { + this.config.statusPageTags = newState; + + // On load, the status page will not include tags if it's not enabled for security reasons + // Which means if we enable tags, it won't show in the UI until saved + // So we have this to enhance UX and load in the tags from the authenticated source instantly + this.$root.publicGroupList = this.$root.publicGroupList.map((group) => { + return { + ...group, + monitorList: group.monitorList.map((monitor) => { + // We only include the tags if visible so we can reuse the logic to hide the tags on disable + return { + ...monitor, + tags: newState ? this.$root.monitorList[monitor.id].tags : [] + } + }) + } + }); + }, /** * Crop Success diff --git a/test/backend.spec.js b/test/backend.spec.js index bd73d2022..bbfc6897b 100644 --- a/test/backend.spec.js +++ b/test/backend.spec.js @@ -1,4 +1,125 @@ const { genSecret, sleep } = require("../src/util"); +const utilServerRewire = require("../server/util-server"); + +describe("Test parseCertificateInfo", () => { + it("should handle undefined", async () => { + const parseCertificateInfo = utilServerRewire.__get__("parseCertificateInfo"); + const info = parseCertificateInfo(undefined); + expect(info).toEqual(undefined); + }, 5000); + + it("should handle normal cert chain", async () => { + const parseCertificateInfo = utilServerRewire.__get__("parseCertificateInfo"); + + const chain1 = { + fingerprint: "CF:2C:F3:6A:FE:6B:10:EC:44:77:C8:95:BB:96:2E:06:1F:0E:15:DA", + valid_from: "Oct 22 12:00:00 2013 GMT", + valid_to: "Oct 22 12:00:00 2028 GMT", + subjectaltname: "DNS:www.example.org, DNS:example.com, DNS:example.edu, DNS:example.net, DNS:example.org, DNS:www.example.com, DNS:www.example.edu, DNS:www.example.net", + }; + + const chain2 = { + fingerprint: "A0:31:C4:67:82:E6:E6:C6:62:C2:C8:7C:76:DA:9A:A6:2C:CA:BD:8E", + valid_from: "Oct 22 12:00:00 2013 GMT", + valid_to: "Oct 22 12:00:00 2028 GMT", + subjectaltname: "DNS:www.example.org, DNS:example.com, DNS:example.edu, DNS:example.net, DNS:example.org, DNS:www.example.com, DNS:www.example.edu, DNS:www.example.net", + }; + + const chain3 = { + fingerprint: "5F:B7:EE:06:33:E2:59:DB:AD:0C:4C:9A:E6:D3:8F:1A:61:C7:DC:25", + valid_from: "Oct 22 12:00:00 2013 GMT", + valid_to: "Oct 22 12:00:00 2028 GMT", + subjectaltname: "DNS:www.example.org, DNS:example.com, DNS:example.edu, DNS:example.net, DNS:example.org, DNS:www.example.com, DNS:www.example.edu, DNS:www.example.net", + }; + + chain1.issuerCertificate = chain2; + chain2.issuerCertificate = chain3; + chain3.issuerCertificate = chain3; + + const info = parseCertificateInfo(chain1); + expect(chain1).toEqual(info); + }, 5000); + + it("should handle cert chain with strange circle", async () => { + const parseCertificateInfo = utilServerRewire.__get__("parseCertificateInfo"); + + const chain1 = { + fingerprint: "CF:2C:F3:6A:FE:6B:10:EC:44:77:C8:95:BB:96:2E:06:1F:0E:15:DA", + valid_from: "Oct 22 12:00:00 2013 GMT", + valid_to: "Oct 22 12:00:00 2028 GMT", + subjectaltname: "DNS:www.example.org, DNS:example.com, DNS:example.edu, DNS:example.net, DNS:example.org, DNS:www.example.com, DNS:www.example.edu, DNS:www.example.net", + }; + + const chain2 = { + fingerprint: "A0:31:C4:67:82:E6:E6:C6:62:C2:C8:7C:76:DA:9A:A6:2C:CA:BD:8E", + valid_from: "Oct 22 12:00:00 2013 GMT", + valid_to: "Oct 22 12:00:00 2028 GMT", + subjectaltname: "DNS:www.example.org, DNS:example.com, DNS:example.edu, DNS:example.net, DNS:example.org, DNS:www.example.com, DNS:www.example.edu, DNS:www.example.net", + }; + + const chain3 = { + fingerprint: "5F:B7:EE:06:33:E2:59:DB:AD:0C:4C:9A:E6:D3:8F:1A:61:C7:DC:25", + valid_from: "Oct 22 12:00:00 2013 GMT", + valid_to: "Oct 22 12:00:00 2028 GMT", + subjectaltname: "DNS:www.example.org, DNS:example.com, DNS:example.edu, DNS:example.net, DNS:example.org, DNS:www.example.com, DNS:www.example.edu, DNS:www.example.net", + }; + + const chain4 = { + fingerprint: "haha", + valid_from: "Oct 22 12:00:00 2013 GMT", + valid_to: "Oct 22 12:00:00 2028 GMT", + subjectaltname: "DNS:www.example.org, DNS:example.com, DNS:example.edu, DNS:example.net, DNS:example.org, DNS:www.example.com, DNS:www.example.edu, DNS:www.example.net", + }; + + chain1.issuerCertificate = chain2; + chain2.issuerCertificate = chain3; + chain3.issuerCertificate = chain4; + chain4.issuerCertificate = chain2; + + const info = parseCertificateInfo(chain1); + expect(chain1).toEqual(info); + }, 5000); + + it("should handle cert chain with last undefined (should be happen in real, but just in case)", async () => { + const parseCertificateInfo = utilServerRewire.__get__("parseCertificateInfo"); + + const chain1 = { + fingerprint: "CF:2C:F3:6A:FE:6B:10:EC:44:77:C8:95:BB:96:2E:06:1F:0E:15:DA", + valid_from: "Oct 22 12:00:00 2013 GMT", + valid_to: "Oct 22 12:00:00 2028 GMT", + subjectaltname: "DNS:www.example.org, DNS:example.com, DNS:example.edu, DNS:example.net, DNS:example.org, DNS:www.example.com, DNS:www.example.edu, DNS:www.example.net", + }; + + const chain2 = { + fingerprint: "A0:31:C4:67:82:E6:E6:C6:62:C2:C8:7C:76:DA:9A:A6:2C:CA:BD:8E", + valid_from: "Oct 22 12:00:00 2013 GMT", + valid_to: "Oct 22 12:00:00 2028 GMT", + subjectaltname: "DNS:www.example.org, DNS:example.com, DNS:example.edu, DNS:example.net, DNS:example.org, DNS:www.example.com, DNS:www.example.edu, DNS:www.example.net", + }; + + const chain3 = { + fingerprint: "5F:B7:EE:06:33:E2:59:DB:AD:0C:4C:9A:E6:D3:8F:1A:61:C7:DC:25", + valid_from: "Oct 22 12:00:00 2013 GMT", + valid_to: "Oct 22 12:00:00 2028 GMT", + subjectaltname: "DNS:www.example.org, DNS:example.com, DNS:example.edu, DNS:example.net, DNS:example.org, DNS:www.example.com, DNS:www.example.edu, DNS:www.example.net", + }; + + const chain4 = { + fingerprint: "haha", + valid_from: "Oct 22 12:00:00 2013 GMT", + valid_to: "Oct 22 12:00:00 2028 GMT", + subjectaltname: "DNS:www.example.org, DNS:example.com, DNS:example.edu, DNS:example.net, DNS:example.org, DNS:www.example.com, DNS:www.example.edu, DNS:www.example.net", + }; + + chain1.issuerCertificate = chain2; + chain2.issuerCertificate = chain3; + chain3.issuerCertificate = chain4; + chain4.issuerCertificate = undefined; + + const info = parseCertificateInfo(chain1); + expect(chain1).toEqual(info); + }, 5000); +}); describe("Test genSecret", () => { @@ -42,3 +163,4 @@ describe("Test reset-password", () => { await require("../extra/reset-password").main(); }, 120000); }); +