chore: enable formatting over the entire codebase in CI (#6655)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
6658f2ce41
commit
0f61d7ee1b
113
.eslintrc.js
113
.eslintrc.js
@ -1,9 +1,5 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
ignorePatterns: [
|
ignorePatterns: ["test/*.js", "server/modules/*", "src/util.js"],
|
||||||
"test/*.js",
|
|
||||||
"server/modules/*",
|
|
||||||
"src/util.js"
|
|
||||||
],
|
|
||||||
root: true,
|
root: true,
|
||||||
env: {
|
env: {
|
||||||
browser: true,
|
browser: true,
|
||||||
@ -23,94 +19,93 @@ module.exports = {
|
|||||||
sourceType: "module",
|
sourceType: "module",
|
||||||
requireConfigFile: false,
|
requireConfigFile: false,
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: ["jsdoc", "@typescript-eslint"],
|
||||||
"jsdoc",
|
|
||||||
"@typescript-eslint",
|
|
||||||
],
|
|
||||||
rules: {
|
rules: {
|
||||||
"yoda": "error",
|
yoda: "error",
|
||||||
eqeqeq: [ "warn", "smart" ],
|
eqeqeq: ["warn", "smart"],
|
||||||
"camelcase": [ "warn", {
|
camelcase: [
|
||||||
"properties": "never",
|
"warn",
|
||||||
"ignoreImports": true
|
{
|
||||||
}],
|
properties: "never",
|
||||||
"no-unused-vars": [ "warn", {
|
ignoreImports: true,
|
||||||
"args": "none"
|
},
|
||||||
}],
|
],
|
||||||
|
"no-unused-vars": [
|
||||||
|
"warn",
|
||||||
|
{
|
||||||
|
args: "none",
|
||||||
|
},
|
||||||
|
],
|
||||||
"vue/max-attributes-per-line": "off",
|
"vue/max-attributes-per-line": "off",
|
||||||
"vue/singleline-html-element-content-newline": "off",
|
"vue/singleline-html-element-content-newline": "off",
|
||||||
"vue/html-self-closing": "off",
|
"vue/html-self-closing": "off",
|
||||||
"vue/require-component-is": "off", // not allow is="style" https://github.com/vuejs/eslint-plugin-vue/issues/462#issuecomment-430234675
|
"vue/require-component-is": "off", // not allow is="style" https://github.com/vuejs/eslint-plugin-vue/issues/462#issuecomment-430234675
|
||||||
"vue/attribute-hyphenation": "off", // This change noNL to "no-n-l" unexpectedly
|
"vue/attribute-hyphenation": "off", // This change noNL to "no-n-l" unexpectedly
|
||||||
"vue/multi-word-component-names": "off",
|
"vue/multi-word-component-names": "off",
|
||||||
"curly": "error",
|
curly: "error",
|
||||||
"no-var": "error",
|
"no-var": "error",
|
||||||
"no-throw-literal": "error",
|
"no-throw-literal": "error",
|
||||||
"no-constant-condition": [ "error", {
|
"no-constant-condition": [
|
||||||
"checkLoops": false,
|
"error",
|
||||||
}],
|
{
|
||||||
|
checkLoops: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
//"no-console": "warn",
|
//"no-console": "warn",
|
||||||
"no-extra-boolean-cast": "off",
|
"no-extra-boolean-cast": "off",
|
||||||
"no-unneeded-ternary": "error",
|
"no-unneeded-ternary": "error",
|
||||||
//"prefer-template": "error",
|
//"prefer-template": "error",
|
||||||
"no-empty": [ "error", {
|
"no-empty": [
|
||||||
"allowEmptyCatch": true
|
"error",
|
||||||
}],
|
{
|
||||||
|
allowEmptyCatch: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
"no-control-regex": "off",
|
"no-control-regex": "off",
|
||||||
"one-var": [ "error", "never" ],
|
"one-var": ["error", "never"],
|
||||||
"max-statements-per-line": [ "error", { "max": 1 }],
|
"max-statements-per-line": ["error", { max: 1 }],
|
||||||
"jsdoc/check-tag-names": [
|
"jsdoc/check-tag-names": [
|
||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
"definedTags": [ "link" ]
|
definedTags: ["link"],
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
"jsdoc/no-undefined-types": "off",
|
"jsdoc/no-undefined-types": "off",
|
||||||
"jsdoc/no-defaults": [
|
"jsdoc/no-defaults": ["error", { noOptionalParamNames: true }],
|
||||||
"error",
|
|
||||||
{ "noOptionalParamNames": true }
|
|
||||||
],
|
|
||||||
"jsdoc/require-throws": "warn",
|
"jsdoc/require-throws": "warn",
|
||||||
"jsdoc/require-jsdoc": [
|
"jsdoc/require-jsdoc": [
|
||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
"require": {
|
require: {
|
||||||
"FunctionDeclaration": true,
|
FunctionDeclaration: true,
|
||||||
"MethodDefinition": true,
|
MethodDefinition: true,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
"jsdoc/no-blank-block-descriptions": "error",
|
"jsdoc/no-blank-block-descriptions": "error",
|
||||||
"jsdoc/require-returns-description": "warn",
|
"jsdoc/require-returns-description": "warn",
|
||||||
"jsdoc/require-returns-check": [
|
"jsdoc/require-returns-check": ["error", { reportMissingReturnForUndefinedTypes: false }],
|
||||||
"error",
|
|
||||||
{ "reportMissingReturnForUndefinedTypes": false }
|
|
||||||
],
|
|
||||||
"jsdoc/require-returns": [
|
"jsdoc/require-returns": [
|
||||||
"warn",
|
"warn",
|
||||||
{
|
{
|
||||||
"forceRequireReturn": true,
|
forceRequireReturn: true,
|
||||||
"forceReturnsWithAsync": true
|
forceReturnsWithAsync: true,
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
"jsdoc/require-param-type": "warn",
|
"jsdoc/require-param-type": "warn",
|
||||||
"jsdoc/require-param-description": "warn"
|
"jsdoc/require-param-description": "warn",
|
||||||
},
|
},
|
||||||
"overrides": [
|
overrides: [
|
||||||
// Override for TypeScript
|
// Override for TypeScript
|
||||||
{
|
{
|
||||||
"files": [
|
files: ["**/*.ts"],
|
||||||
"**/*.ts",
|
extends: ["plugin:@typescript-eslint/recommended"],
|
||||||
],
|
rules: {
|
||||||
extends: [
|
|
||||||
"plugin:@typescript-eslint/recommended",
|
|
||||||
],
|
|
||||||
"rules": {
|
|
||||||
"jsdoc/require-returns-type": "off",
|
"jsdoc/require-returns-type": "off",
|
||||||
"jsdoc/require-param-type": "off",
|
"jsdoc/require-param-type": "off",
|
||||||
"@typescript-eslint/no-explicit-any": "off",
|
"@typescript-eslint/no-explicit-any": "off",
|
||||||
"prefer-const": "off",
|
"prefer-const": "off",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
};
|
};
|
||||||
|
|||||||
7
.github/workflows/autofix.yml
vendored
7
.github/workflows/autofix.yml
vendored
@ -38,9 +38,8 @@ jobs:
|
|||||||
run: npm run lint-fix:style
|
run: npm run lint-fix:style
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
|
|
||||||
# TODO: disabled until we have agreed that this is the formatting that we want to enforce
|
- name: Auto-format code with Prettier
|
||||||
# - name: Auto-format code with Prettier
|
run: npm run fmt
|
||||||
# run: npm run fmt
|
continue-on-error: true
|
||||||
# continue-on-error: true
|
|
||||||
|
|
||||||
- uses: autofix-ci/action@635ffb0c9798bd160680f18fd73371e355b85f27
|
- uses: autofix-ci/action@635ffb0c9798bd160680f18fd73371e355b85f27
|
||||||
|
|||||||
@ -1,38 +1,2 @@
|
|||||||
# Dependencies
|
# language files
|
||||||
node_modules/
|
src/lang/*.json
|
||||||
|
|
||||||
# Build output
|
|
||||||
dist/
|
|
||||||
build/
|
|
||||||
|
|
||||||
# Data directories
|
|
||||||
data/
|
|
||||||
|
|
||||||
# Test output
|
|
||||||
test-results/
|
|
||||||
playwright-report/
|
|
||||||
private/
|
|
||||||
|
|
||||||
# Logs
|
|
||||||
*.log
|
|
||||||
npm-debug.log*
|
|
||||||
|
|
||||||
# OS files
|
|
||||||
.DS_Store
|
|
||||||
Thumbs.db
|
|
||||||
|
|
||||||
# IDE
|
|
||||||
.vscode/
|
|
||||||
.idea/
|
|
||||||
|
|
||||||
# Lock files
|
|
||||||
package-lock.json
|
|
||||||
pnpm-lock.yaml
|
|
||||||
yarn.lock
|
|
||||||
|
|
||||||
# Generated files
|
|
||||||
*.min.js
|
|
||||||
*.min.css
|
|
||||||
|
|
||||||
# Docker
|
|
||||||
docker/
|
|
||||||
|
|||||||
@ -54,8 +54,7 @@ to review the appropriate one for your contribution.
|
|||||||
[**PLEASE SEE OUR SECURITY POLICY.**](SECURITY.md)
|
[**PLEASE SEE OUR SECURITY POLICY.**](SECURITY.md)
|
||||||
|
|
||||||
[advisory]: https://github.com/louislam/uptime-kuma/security/advisories/new
|
[advisory]: https://github.com/louislam/uptime-kuma/security/advisories/new
|
||||||
[issue]:
|
[issue]: https://github.com/louislam/uptime-kuma/issues/new?template=security_issue.yml
|
||||||
https://github.com/louislam/uptime-kuma/issues/new?template=security_issue.yml
|
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
</details>
|
</details>
|
||||||
@ -65,7 +64,6 @@ to review the appropriate one for your contribution.
|
|||||||
|
|
||||||
If you come across a bug and think you can solve, we appreciate your work.
|
If you come across a bug and think you can solve, we appreciate your work.
|
||||||
Please make sure that you follow these rules:
|
Please make sure that you follow these rules:
|
||||||
|
|
||||||
- keep the PR as small as possible, fix only one thing at a time => keeping it
|
- keep the PR as small as possible, fix only one thing at a time => keeping it
|
||||||
reviewable
|
reviewable
|
||||||
- test that your code does what you claim it does.
|
- test that your code does what you claim it does.
|
||||||
@ -79,16 +77,15 @@ to review the appropriate one for your contribution.
|
|||||||
- <details><summary><b>Translations / Internationalisation (i18n)</b> (click to expand)</summary>
|
- <details><summary><b>Translations / Internationalisation (i18n)</b> (click to expand)</summary>
|
||||||
<p>
|
<p>
|
||||||
|
|
||||||
Please add **all** strings that are translatable to `src/lang/en.json`. If translation keys are omitted, they cannot be translated. **Do not include any other languages in your initial pull request** (even if it is your mother tongue) to avoid merge conflicts between Weblate and `master`. Once your PR is merged into `master`, the strings can be translated by awesome people donating their language skills.
|
Please add **all** strings that are translatable to `src/lang/en.json`. If translation keys are omitted, they cannot be translated. **Do not include any other languages in your initial pull request** (even if it is your mother tongue) to avoid merge conflicts between Weblate and `master`. Once your PR is merged into `master`, the strings can be translated by awesome people donating their language skills.
|
||||||
|
|
||||||
We use Weblate to localise this project into many languages. If you want to help translate Uptime Kuma into your language, please see [these instructions on how to translate using Weblate](https://github.com/louislam/uptime-kuma/blob/master/src/lang/README.md).
|
We use Weblate to localise this project into many languages. If you want to help translate Uptime Kuma into your language, please see [these instructions on how to translate using Weblate](https://github.com/louislam/uptime-kuma/blob/master/src/lang/README.md).
|
||||||
|
|
||||||
There are some cases where a change cannot be done directly in Weblate and requires a PR:
|
There are some cases where a change cannot be done directly in Weblate and requires a PR:
|
||||||
|
- A text may not yet be localisable. In this case, **adding a new language key** via `{{ $t("Translation key") }}` or [`<i18n-t keypath="Translation key">`](https://vue-i18n.intlify.dev/guide/advanced/component.html) might be necessary.
|
||||||
- A text may not yet be localisable. In this case, **adding a new language key** via `{{ $t("Translation key") }}` or [`<i18n-t keypath="Translation key">`](https://vue-i18n.intlify.dev/guide/advanced/component.html) might be necessary.
|
- Language keys need to be **added to `en.json`** to appear in Weblate. If this has not been done, a PR is appreciated.
|
||||||
- Language keys need to be **added to `en.json`** to appear in Weblate. If this has not been done, a PR is appreciated.
|
- **Adding a new language** requires creating a new file. See [these instructions](https://github.com/louislam/uptime-kuma/blob/master/src/lang/README.md).
|
||||||
- **Adding a new language** requires creating a new file. See [these instructions](https://github.com/louislam/uptime-kuma/blob/master/src/lang/README.md).
|
|
||||||
|
|
||||||
<sub>Because maintainer time is precious, junior maintainers may merge uncontroversial PRs in this area.</sub>
|
<sub>Because maintainer time is precious, junior maintainers may merge uncontroversial PRs in this area.</sub>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
@ -98,7 +95,6 @@ to review the appropriate one for your contribution.
|
|||||||
<p>
|
<p>
|
||||||
|
|
||||||
To set up a new notification provider these files need to be modified/created:
|
To set up a new notification provider these files need to be modified/created:
|
||||||
|
|
||||||
- `server/notification-providers/PROVIDER_NAME.js` is where the heart of the
|
- `server/notification-providers/PROVIDER_NAME.js` is where the heart of the
|
||||||
notification provider lives.
|
notification provider lives.
|
||||||
|
|
||||||
@ -135,7 +131,6 @@ to review the appropriate one for your contribution.
|
|||||||
translations (`{{ $t("Translation key") }}`,
|
translations (`{{ $t("Translation key") }}`,
|
||||||
[`i18n-t keypath="Translation key">`](https://vue-i18n.intlify.dev/guide/advanced/component.html))
|
[`i18n-t keypath="Translation key">`](https://vue-i18n.intlify.dev/guide/advanced/component.html))
|
||||||
in `src/lang/en.json` to enable our translators to translate this
|
in `src/lang/en.json` to enable our translators to translate this
|
||||||
|
|
||||||
- `src/components/notifications/index.js` is where the frontend of the
|
- `src/components/notifications/index.js` is where the frontend of the
|
||||||
provider needs to be registered. _If you have an idea how we can skip this
|
provider needs to be registered. _If you have an idea how we can skip this
|
||||||
step, we would love to hear about it ^^_
|
step, we would love to hear about it ^^_
|
||||||
@ -147,7 +142,6 @@ to review the appropriate one for your contribution.
|
|||||||
|
|
||||||
To make sure you have tested the notification provider, please include
|
To make sure you have tested the notification provider, please include
|
||||||
screenshots of the following events in the pull-request description:
|
screenshots of the following events in the pull-request description:
|
||||||
|
|
||||||
- `UP`/`DOWN`
|
- `UP`/`DOWN`
|
||||||
- Certificate Expiry via <https://expired.badssl.com/>
|
- Certificate Expiry via <https://expired.badssl.com/>
|
||||||
- Domain Expiry via <https://google.com/> and a larger time set
|
- Domain Expiry via <https://google.com/> and a larger time set
|
||||||
@ -159,7 +153,7 @@ to review the appropriate one for your contribution.
|
|||||||
|
|
||||||
```md
|
```md
|
||||||
| Event | Before | After |
|
| Event | Before | After |
|
||||||
|--------------------|-----------------------|----------------------|
|
| ------------------ | --------------------- | -------------------- |
|
||||||
| `UP` |  |  |
|
| `UP` |  |  |
|
||||||
| `DOWN` |  |  |
|
| `DOWN` |  |  |
|
||||||
| Certificate-expiry |  |  |
|
| Certificate-expiry |  |  |
|
||||||
@ -177,7 +171,6 @@ to review the appropriate one for your contribution.
|
|||||||
<p>
|
<p>
|
||||||
|
|
||||||
To set up a new notification provider these files need to be modified/created:
|
To set up a new notification provider these files need to be modified/created:
|
||||||
|
|
||||||
- `server/monitor-types/MONITORING_TYPE.js` is the core of each monitor.
|
- `server/monitor-types/MONITORING_TYPE.js` is the core of each monitor.
|
||||||
The `async check(...)`-function should:
|
The `async check(...)`-function should:
|
||||||
- in the happy-path: set `heartbeat.msg` to a successful message and set `heartbeat.status = UP`
|
- in the happy-path: set `heartbeat.msg` to a successful message and set `heartbeat.status = UP`
|
||||||
@ -220,7 +213,6 @@ to review the appropriate one for your contribution.
|
|||||||
<p>
|
<p>
|
||||||
|
|
||||||
Contributing is easy and fun. We will guide you through the process:
|
Contributing is easy and fun. We will guide you through the process:
|
||||||
|
|
||||||
1. **Fork** the [Uptime-Kuma repository](https://github.com/louislam/uptime-kuma/) and **clone** it to your local machine.
|
1. **Fork** the [Uptime-Kuma repository](https://github.com/louislam/uptime-kuma/) and **clone** it to your local machine.
|
||||||
2. **Create a new branch** for your changes (e.g., `signal-notification-provider`).
|
2. **Create a new branch** for your changes (e.g., `signal-notification-provider`).
|
||||||
3. **Make your changes** and **commit** them with a clear message.
|
3. **Make your changes** and **commit** them with a clear message.
|
||||||
@ -235,7 +227,6 @@ to review the appropriate one for your contribution.
|
|||||||
|
|
||||||
A PR should remain in **draft status** until all tasks are completed.
|
A PR should remain in **draft status** until all tasks are completed.
|
||||||
Only change the status to **Ready for Review** when:
|
Only change the status to **Ready for Review** when:
|
||||||
|
|
||||||
- You have implemented all planned changes.
|
- You have implemented all planned changes.
|
||||||
- Your code is fully tested and ready for review.
|
- Your code is fully tested and ready for review.
|
||||||
- You have updated or created the necessary tests.
|
- You have updated or created the necessary tests.
|
||||||
@ -248,7 +239,6 @@ to review the appropriate one for your contribution.
|
|||||||
|
|
||||||
- Merging multiple issues by a huge PR is more difficult to review and causes
|
- Merging multiple issues by a huge PR is more difficult to review and causes
|
||||||
conflicts with other PRs. Please
|
conflicts with other PRs. Please
|
||||||
|
|
||||||
- (if possible) **create one PR for one issue** or
|
- (if possible) **create one PR for one issue** or
|
||||||
- (if not possible) **explain which issues a PR addresses and why this PR
|
- (if not possible) **explain which issues a PR addresses and why this PR
|
||||||
should not be broken apart**
|
should not be broken apart**
|
||||||
@ -269,6 +259,7 @@ to review the appropriate one for your contribution.
|
|||||||
### Continuous Integration
|
### Continuous Integration
|
||||||
|
|
||||||
All pull requests must pass our continuous integration checks. These checks include:
|
All pull requests must pass our continuous integration checks. These checks include:
|
||||||
|
|
||||||
- **Linting**: We use ESLint and Stylelint for code quality checks. You can run the linter locally with `npm run lint`.
|
- **Linting**: We use ESLint and Stylelint for code quality checks. You can run the linter locally with `npm run lint`.
|
||||||
- **Formatting**: We use Prettier for code formatting. You can format your code with `npm run fmt` (or CI will do this for you)
|
- **Formatting**: We use Prettier for code formatting. You can format your code with `npm run fmt` (or CI will do this for you)
|
||||||
- **Testing**: We use Playwright for end-to-end tests and have a suite of backend tests. You can run the tests locally with `npm test`.
|
- **Testing**: We use Playwright for end-to-end tests and have a suite of backend tests. You can run the tests locally with `npm test`.
|
||||||
@ -297,13 +288,11 @@ you can finally start the app. The goal is to make the Uptime Kuma installation
|
|||||||
as easy as installing a mobile app.
|
as easy as installing a mobile app.
|
||||||
|
|
||||||
- Easy to install for non-Docker users
|
- Easy to install for non-Docker users
|
||||||
|
|
||||||
- no native build dependency is needed (for `x86_64`/`armv7`/`arm64`)
|
- no native build dependency is needed (for `x86_64`/`armv7`/`arm64`)
|
||||||
- no extra configuration and
|
- no extra configuration and
|
||||||
- no extra effort required to get it running
|
- no extra effort required to get it running
|
||||||
|
|
||||||
- Single container for Docker users
|
- Single container for Docker users
|
||||||
|
|
||||||
- no complex docker-compose file
|
- no complex docker-compose file
|
||||||
- mapping the volume and exposing the port should be the only requirements
|
- mapping the volume and exposing the port should be the only requirements
|
||||||
|
|
||||||
@ -480,18 +469,16 @@ We have a few procedures we follow. These are documented here:
|
|||||||
|
|
||||||
- <details><summary><b>Set up a Docker Builder</b> (click to expand)</summary>
|
- <details><summary><b>Set up a Docker Builder</b> (click to expand)</summary>
|
||||||
<p>
|
<p>
|
||||||
|
|
||||||
- amd64, armv7 using local.
|
- amd64, armv7 using local.
|
||||||
- arm64 using remote arm64 cpu, as the emulator is too slow and can no longer
|
- arm64 using remote arm64 cpu, as the emulator is too slow and can no longer
|
||||||
pass the `npm ci` command.
|
pass the `npm ci` command.
|
||||||
|
|
||||||
1. Add the public key to the remote server.
|
1. Add the public key to the remote server.
|
||||||
2. Add the remote context. The remote machine must be arm64 and installed
|
2. Add the remote context. The remote machine must be arm64 and installed
|
||||||
Docker CE.
|
Docker CE.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker context create oracle-arm64-jp --docker "host=ssh://root@100.107.174.88"
|
docker context create oracle-arm64-jp --docker "host=ssh://root@100.107.174.88"
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Create a new builder.
|
3. Create a new builder.
|
||||||
|
|
||||||
@ -515,7 +502,6 @@ We have a few procedures we follow. These are documented here:
|
|||||||
|
|
||||||
- <details><summary><b>Release</b> (click to expand)</summary>
|
- <details><summary><b>Release</b> (click to expand)</summary>
|
||||||
<p>
|
<p>
|
||||||
|
|
||||||
1. Draft a release note
|
1. Draft a release note
|
||||||
2. Make sure the repo is cleared
|
2. Make sure the repo is cleared
|
||||||
3. If the healthcheck is updated, remember to re-compile it:
|
3. If the healthcheck is updated, remember to re-compile it:
|
||||||
@ -528,7 +514,6 @@ We have a few procedures we follow. These are documented here:
|
|||||||
9. Deploy to the demo server: `npm run deploy-demo-server`
|
9. Deploy to the demo server: `npm run deploy-demo-server`
|
||||||
|
|
||||||
These Items need to be checked:
|
These Items need to be checked:
|
||||||
|
|
||||||
- [ ] Check all tags is fine on
|
- [ ] Check all tags is fine on
|
||||||
<https://hub.docker.com/r/louislam/uptime-kuma/tags>
|
<https://hub.docker.com/r/louislam/uptime-kuma/tags>
|
||||||
- [ ] Try the Docker image with tag 1.X.X (Clean install / amd64 / arm64 /
|
- [ ] Try the Docker image with tag 1.X.X (Clean install / amd64 / arm64 /
|
||||||
@ -540,7 +525,6 @@ We have a few procedures we follow. These are documented here:
|
|||||||
|
|
||||||
- <details><summary><b>Release Beta</b> (click to expand)</summary>
|
- <details><summary><b>Release Beta</b> (click to expand)</summary>
|
||||||
<p>
|
<p>
|
||||||
|
|
||||||
1. Draft a release note, check `This is a pre-release`
|
1. Draft a release note, check `This is a pre-release`
|
||||||
2. Make sure the repo is cleared
|
2. Make sure the repo is cleared
|
||||||
3. `npm run release-beta` with env vars: `VERSION` and `GITHUB_TOKEN`
|
3. `npm run release-beta` with env vars: `VERSION` and `GITHUB_TOKEN`
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
Uptime Kuma is an easy-to-use self-hosted monitoring tool.
|
Uptime Kuma is an easy-to-use self-hosted monitoring tool.
|
||||||
|
|
||||||
<a target="_blank" href="https://github.com/louislam/uptime-kuma"><img src="https://img.shields.io/github/stars/louislam/uptime-kuma?style=flat" /></a> <a target="_blank" href="https://hub.docker.com/r/louislam/uptime-kuma"><img src="https://img.shields.io/docker/pulls/louislam/uptime-kuma" /></a> <a target="_blank" href="https://hub.docker.com/r/louislam/uptime-kuma"><img src="https://img.shields.io/docker/v/louislam/uptime-kuma/2?label=docker%20image%20ver." /></a> <a target="_blank" href="https://github.com/louislam/uptime-kuma"><img src="https://img.shields.io/github/last-commit/louislam/uptime-kuma" /></a> <a target="_blank" href="https://opencollective.com/uptime-kuma"><img src="https://opencollective.com/uptime-kuma/total/badge.svg?label=Open%20Collective%20Backers&color=brightgreen" /></a>
|
<a target="_blank" href="https://github.com/louislam/uptime-kuma"><img src="https://img.shields.io/github/stars/louislam/uptime-kuma?style=flat" /></a> <a target="_blank" href="https://hub.docker.com/r/louislam/uptime-kuma"><img src="https://img.shields.io/docker/pulls/louislam/uptime-kuma" /></a> <a target="_blank" href="https://hub.docker.com/r/louislam/uptime-kuma"><img src="https://img.shields.io/docker/v/louislam/uptime-kuma/2?label=docker%20image%20ver." /></a> <a target="_blank" href="https://github.com/louislam/uptime-kuma"><img src="https://img.shields.io/github/last-commit/louislam/uptime-kuma" /></a> <a target="_blank" href="https://opencollective.com/uptime-kuma"><img src="https://opencollective.com/uptime-kuma/total/badge.svg?label=Open%20Collective%20Backers&color=brightgreen" /></a>
|
||||||
[](https://github.com/sponsors/louislam) <a href="https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/">
|
[](https://github.com/sponsors/louislam) <a href="https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/">
|
||||||
<img src="https://weblate.kuma.pet/widgets/uptime-kuma/-/svg-badge.svg" alt="Translation status" />
|
<img src="https://weblate.kuma.pet/widgets/uptime-kuma/-/svg-badge.svg" alt="Translation status" />
|
||||||
</a>
|
</a>
|
||||||
@ -45,6 +45,7 @@ cd uptime-kuma
|
|||||||
curl -o compose.yaml https://raw.githubusercontent.com/louislam/uptime-kuma/master/compose.yaml
|
curl -o compose.yaml https://raw.githubusercontent.com/louislam/uptime-kuma/master/compose.yaml
|
||||||
docker compose up -d
|
docker compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
Uptime Kuma is now running on all network interfaces (e.g. http://localhost:3001 or http://your-ip:3001).
|
Uptime Kuma is now running on all network interfaces (e.g. http://localhost:3001 or http://your-ip:3001).
|
||||||
|
|
||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
@ -55,6 +56,7 @@ Uptime Kuma is now running on all network interfaces (e.g. http://localhost:3001
|
|||||||
```bash
|
```bash
|
||||||
docker run -d --restart=always -p 3001:3001 -v uptime-kuma:/app/data --name uptime-kuma louislam/uptime-kuma:2
|
docker run -d --restart=always -p 3001:3001 -v uptime-kuma:/app/data --name uptime-kuma louislam/uptime-kuma:2
|
||||||
```
|
```
|
||||||
|
|
||||||
Uptime Kuma is now running on all network interfaces (e.g. http://localhost:3001 or http://your-ip:3001).
|
Uptime Kuma is now running on all network interfaces (e.g. http://localhost:3001 or http://your-ip:3001).
|
||||||
|
|
||||||
If you want to limit exposure to localhost only:
|
If you want to limit exposure to localhost only:
|
||||||
@ -63,8 +65,6 @@ If you want to limit exposure to localhost only:
|
|||||||
docker run ... -p 127.0.0.1:3001:3001 ...
|
docker run ... -p 127.0.0.1:3001:3001 ...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 💪🏻 Non-Docker
|
### 💪🏻 Non-Docker
|
||||||
|
|
||||||
Requirements:
|
Requirements:
|
||||||
@ -93,6 +93,7 @@ npm install pm2 -g && pm2 install pm2-logrotate
|
|||||||
# Start Server
|
# Start Server
|
||||||
pm2 start server/server.js --name uptime-kuma
|
pm2 start server/server.js --name uptime-kuma
|
||||||
```
|
```
|
||||||
|
|
||||||
Uptime Kuma is now running on all network interfaces (e.g. http://localhost:3001 or http://your-ip:3001).
|
Uptime Kuma is now running on all network interfaces (e.g. http://localhost:3001 or http://your-ip:3001).
|
||||||
|
|
||||||
More useful PM2 Commands
|
More useful PM2 Commands
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
- Do not report any upstream dependency issues / scan result by any tools. It will be closed immediately without explanations. Unless you have PoC to prove that the upstream issue affected Uptime Kuma.
|
- Do not report any upstream dependency issues / scan result by any tools. It will be closed immediately without explanations. Unless you have PoC to prove that the upstream issue affected Uptime Kuma.
|
||||||
- Do not use the public issue tracker or discuss it in public as it will cause
|
- Do not use the public issue tracker or discuss it in public as it will cause
|
||||||
more damage.
|
more damage.
|
||||||
|
|
||||||
## Do you accept other 3rd-party bug bounty platforms?
|
## Do you accept other 3rd-party bug bounty platforms?
|
||||||
|
|
||||||
|
|||||||
@ -22,10 +22,11 @@ export default defineConfig({
|
|||||||
// Reporter to use
|
// Reporter to use
|
||||||
reporter: [
|
reporter: [
|
||||||
[
|
[
|
||||||
"html", {
|
"html",
|
||||||
|
{
|
||||||
outputFolder: "../private/playwright-report",
|
outputFolder: "../private/playwright-report",
|
||||||
open: "never",
|
open: "never",
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|
||||||
@ -47,7 +48,7 @@ export default defineConfig({
|
|||||||
{
|
{
|
||||||
name: "specs",
|
name: "specs",
|
||||||
use: { ...devices["Desktop Chrome"] },
|
use: { ...devices["Desktop Chrome"] },
|
||||||
dependencies: [ "run-once setup" ],
|
dependencies: ["run-once setup"],
|
||||||
},
|
},
|
||||||
/*
|
/*
|
||||||
{
|
{
|
||||||
|
|||||||
@ -15,13 +15,13 @@ export default defineConfig({
|
|||||||
port: 3000,
|
port: 3000,
|
||||||
},
|
},
|
||||||
define: {
|
define: {
|
||||||
"FRONTEND_VERSION": JSON.stringify(process.env.npm_package_version),
|
FRONTEND_VERSION: JSON.stringify(process.env.npm_package_version),
|
||||||
"process.env": {},
|
"process.env": {},
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
vue(),
|
vue(),
|
||||||
visualizer({
|
visualizer({
|
||||||
filename: "tmp/dist-stats.html"
|
filename: "tmp/dist-stats.html",
|
||||||
}),
|
}),
|
||||||
viteCompression({
|
viteCompression({
|
||||||
algorithm: "gzip",
|
algorithm: "gzip",
|
||||||
@ -40,21 +40,19 @@ export default defineConfig({
|
|||||||
],
|
],
|
||||||
css: {
|
css: {
|
||||||
postcss: {
|
postcss: {
|
||||||
"parser": postCssScss,
|
parser: postCssScss,
|
||||||
"map": false,
|
map: false,
|
||||||
"plugins": [ postcssRTLCSS ]
|
plugins: [postcssRTLCSS],
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
commonjsOptions: {
|
commonjsOptions: {
|
||||||
include: [ /.js$/ ],
|
include: [/.js$/],
|
||||||
},
|
},
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
output: {
|
output: {
|
||||||
manualChunks(id, { getModuleInfo, getModuleIds }) {
|
manualChunks(id, { getModuleInfo, getModuleIds }) {},
|
||||||
|
},
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@ -39,7 +39,7 @@ async function createTables() {
|
|||||||
table.integer("user_id").unsigned().notNullable();
|
table.integer("user_id").unsigned().notNullable();
|
||||||
table.string("protocol", 10).notNullable();
|
table.string("protocol", 10).notNullable();
|
||||||
table.string("host", 255).notNullable();
|
table.string("host", 255).notNullable();
|
||||||
table.smallint("port").notNullable(); // TODO: Maybe a issue with MariaDB, need migration to int
|
table.smallint("port").notNullable(); // TODO: Maybe a issue with MariaDB, need migration to int
|
||||||
table.boolean("auth").notNullable();
|
table.boolean("auth").notNullable();
|
||||||
table.string("username", 255).nullable();
|
table.string("username", 255).nullable();
|
||||||
table.string("password", 255).nullable();
|
table.string("password", 255).nullable();
|
||||||
@ -67,10 +67,7 @@ async function createTables() {
|
|||||||
table.increments("id");
|
table.increments("id");
|
||||||
table.string("name", 150);
|
table.string("name", 150);
|
||||||
table.boolean("active").notNullable().defaultTo(true);
|
table.boolean("active").notNullable().defaultTo(true);
|
||||||
table.integer("user_id").unsigned()
|
table.integer("user_id").unsigned().references("id").inTable("user").onDelete("SET NULL").onUpdate("CASCADE");
|
||||||
.references("id").inTable("user")
|
|
||||||
.onDelete("SET NULL")
|
|
||||||
.onUpdate("CASCADE");
|
|
||||||
table.integer("interval").notNullable().defaultTo(20);
|
table.integer("interval").notNullable().defaultTo(20);
|
||||||
table.text("url");
|
table.text("url");
|
||||||
table.string("type", 20);
|
table.string("type", 20);
|
||||||
@ -83,7 +80,7 @@ async function createTables() {
|
|||||||
table.boolean("ignore_tls").notNullable().defaultTo(false);
|
table.boolean("ignore_tls").notNullable().defaultTo(false);
|
||||||
table.boolean("upside_down").notNullable().defaultTo(false);
|
table.boolean("upside_down").notNullable().defaultTo(false);
|
||||||
table.integer("maxredirects").notNullable().defaultTo(10);
|
table.integer("maxredirects").notNullable().defaultTo(10);
|
||||||
table.text("accepted_statuscodes_json").notNullable().defaultTo("[\"200-299\"]");
|
table.text("accepted_statuscodes_json").notNullable().defaultTo('["200-299"]');
|
||||||
table.string("dns_resolve_type", 5);
|
table.string("dns_resolve_type", 5);
|
||||||
table.string("dns_resolve_server", 255);
|
table.string("dns_resolve_server", 255);
|
||||||
table.string("dns_last_result", 255);
|
table.string("dns_last_result", 255);
|
||||||
@ -94,11 +91,9 @@ async function createTables() {
|
|||||||
table.text("headers").defaultTo(null);
|
table.text("headers").defaultTo(null);
|
||||||
table.text("basic_auth_user").defaultTo(null);
|
table.text("basic_auth_user").defaultTo(null);
|
||||||
table.text("basic_auth_pass").defaultTo(null);
|
table.text("basic_auth_pass").defaultTo(null);
|
||||||
table.integer("docker_host").unsigned()
|
table.integer("docker_host").unsigned().references("id").inTable("docker_host");
|
||||||
.references("id").inTable("docker_host");
|
|
||||||
table.string("docker_container", 255);
|
table.string("docker_container", 255);
|
||||||
table.integer("proxy_id").unsigned()
|
table.integer("proxy_id").unsigned().references("id").inTable("proxy");
|
||||||
.references("id").inTable("proxy");
|
|
||||||
table.boolean("expiry_notification").defaultTo(true);
|
table.boolean("expiry_notification").defaultTo(true);
|
||||||
table.text("mqtt_topic");
|
table.text("mqtt_topic");
|
||||||
table.string("mqtt_success_message", 255);
|
table.string("mqtt_success_message", 255);
|
||||||
@ -130,8 +125,12 @@ async function createTables() {
|
|||||||
await knex.schema.createTable("heartbeat", (table) => {
|
await knex.schema.createTable("heartbeat", (table) => {
|
||||||
table.increments("id");
|
table.increments("id");
|
||||||
table.boolean("important").notNullable().defaultTo(false);
|
table.boolean("important").notNullable().defaultTo(false);
|
||||||
table.integer("monitor_id").unsigned().notNullable()
|
table
|
||||||
.references("id").inTable("monitor")
|
.integer("monitor_id")
|
||||||
|
.unsigned()
|
||||||
|
.notNullable()
|
||||||
|
.references("id")
|
||||||
|
.inTable("monitor")
|
||||||
.onDelete("CASCADE")
|
.onDelete("CASCADE")
|
||||||
.onUpdate("CASCADE");
|
.onUpdate("CASCADE");
|
||||||
table.smallint("status").notNullable();
|
table.smallint("status").notNullable();
|
||||||
@ -143,9 +142,9 @@ async function createTables() {
|
|||||||
table.integer("down_count").notNullable().defaultTo(0);
|
table.integer("down_count").notNullable().defaultTo(0);
|
||||||
|
|
||||||
table.index("important");
|
table.index("important");
|
||||||
table.index([ "monitor_id", "time" ], "monitor_time_index");
|
table.index(["monitor_id", "time"], "monitor_time_index");
|
||||||
table.index("monitor_id");
|
table.index("monitor_id");
|
||||||
table.index([ "monitor_id", "important", "time" ], "monitor_important_time_index");
|
table.index(["monitor_id", "important", "time"], "monitor_important_time_index");
|
||||||
});
|
});
|
||||||
|
|
||||||
// incident
|
// incident
|
||||||
@ -166,10 +165,7 @@ async function createTables() {
|
|||||||
table.increments("id");
|
table.increments("id");
|
||||||
table.string("title", 150).notNullable();
|
table.string("title", 150).notNullable();
|
||||||
table.text("description").notNullable();
|
table.text("description").notNullable();
|
||||||
table.integer("user_id").unsigned()
|
table.integer("user_id").unsigned().references("id").inTable("user").onDelete("SET NULL").onUpdate("CASCADE");
|
||||||
.references("id").inTable("user")
|
|
||||||
.onDelete("SET NULL")
|
|
||||||
.onUpdate("CASCADE");
|
|
||||||
table.boolean("active").notNullable().defaultTo(true);
|
table.boolean("active").notNullable().defaultTo(true);
|
||||||
table.string("strategy", 50).notNullable().defaultTo("single");
|
table.string("strategy", 50).notNullable().defaultTo("single");
|
||||||
table.datetime("start_date");
|
table.datetime("start_date");
|
||||||
@ -181,7 +177,7 @@ async function createTables() {
|
|||||||
table.integer("interval_day");
|
table.integer("interval_day");
|
||||||
|
|
||||||
table.index("active");
|
table.index("active");
|
||||||
table.index([ "strategy", "active" ], "manual_active");
|
table.index(["strategy", "active"], "manual_active");
|
||||||
table.index("user_id", "maintenance_user_id");
|
table.index("user_id", "maintenance_user_id");
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -209,13 +205,21 @@ async function createTables() {
|
|||||||
await knex.schema.createTable("maintenance_status_page", (table) => {
|
await knex.schema.createTable("maintenance_status_page", (table) => {
|
||||||
table.increments("id");
|
table.increments("id");
|
||||||
|
|
||||||
table.integer("status_page_id").unsigned().notNullable()
|
table
|
||||||
.references("id").inTable("status_page")
|
.integer("status_page_id")
|
||||||
|
.unsigned()
|
||||||
|
.notNullable()
|
||||||
|
.references("id")
|
||||||
|
.inTable("status_page")
|
||||||
.onDelete("CASCADE")
|
.onDelete("CASCADE")
|
||||||
.onUpdate("CASCADE");
|
.onUpdate("CASCADE");
|
||||||
|
|
||||||
table.integer("maintenance_id").unsigned().notNullable()
|
table
|
||||||
.references("id").inTable("maintenance")
|
.integer("maintenance_id")
|
||||||
|
.unsigned()
|
||||||
|
.notNullable()
|
||||||
|
.references("id")
|
||||||
|
.inTable("maintenance")
|
||||||
.onDelete("CASCADE")
|
.onDelete("CASCADE")
|
||||||
.onUpdate("CASCADE");
|
.onUpdate("CASCADE");
|
||||||
});
|
});
|
||||||
@ -223,8 +227,12 @@ async function createTables() {
|
|||||||
// maintenance_timeslot
|
// maintenance_timeslot
|
||||||
await knex.schema.createTable("maintenance_timeslot", (table) => {
|
await knex.schema.createTable("maintenance_timeslot", (table) => {
|
||||||
table.increments("id");
|
table.increments("id");
|
||||||
table.integer("maintenance_id").unsigned().notNullable()
|
table
|
||||||
.references("id").inTable("maintenance")
|
.integer("maintenance_id")
|
||||||
|
.unsigned()
|
||||||
|
.notNullable()
|
||||||
|
.references("id")
|
||||||
|
.inTable("maintenance")
|
||||||
.onDelete("CASCADE")
|
.onDelete("CASCADE")
|
||||||
.onUpdate("CASCADE");
|
.onUpdate("CASCADE");
|
||||||
table.datetime("start_date").notNullable();
|
table.datetime("start_date").notNullable();
|
||||||
@ -232,35 +240,51 @@ async function createTables() {
|
|||||||
table.boolean("generated_next").defaultTo(false);
|
table.boolean("generated_next").defaultTo(false);
|
||||||
|
|
||||||
table.index("maintenance_id");
|
table.index("maintenance_id");
|
||||||
table.index([ "maintenance_id", "start_date", "end_date" ], "active_timeslot_index");
|
table.index(["maintenance_id", "start_date", "end_date"], "active_timeslot_index");
|
||||||
table.index("generated_next", "generated_next_index");
|
table.index("generated_next", "generated_next_index");
|
||||||
});
|
});
|
||||||
|
|
||||||
// monitor_group
|
// monitor_group
|
||||||
await knex.schema.createTable("monitor_group", (table) => {
|
await knex.schema.createTable("monitor_group", (table) => {
|
||||||
table.increments("id");
|
table.increments("id");
|
||||||
table.integer("monitor_id").unsigned().notNullable()
|
table
|
||||||
.references("id").inTable("monitor")
|
.integer("monitor_id")
|
||||||
|
.unsigned()
|
||||||
|
.notNullable()
|
||||||
|
.references("id")
|
||||||
|
.inTable("monitor")
|
||||||
.onDelete("CASCADE")
|
.onDelete("CASCADE")
|
||||||
.onUpdate("CASCADE");
|
.onUpdate("CASCADE");
|
||||||
table.integer("group_id").unsigned().notNullable()
|
table
|
||||||
.references("id").inTable("group")
|
.integer("group_id")
|
||||||
|
.unsigned()
|
||||||
|
.notNullable()
|
||||||
|
.references("id")
|
||||||
|
.inTable("group")
|
||||||
.onDelete("CASCADE")
|
.onDelete("CASCADE")
|
||||||
.onUpdate("CASCADE");
|
.onUpdate("CASCADE");
|
||||||
table.integer("weight").notNullable().defaultTo(1000);
|
table.integer("weight").notNullable().defaultTo(1000);
|
||||||
table.boolean("send_url").notNullable().defaultTo(false);
|
table.boolean("send_url").notNullable().defaultTo(false);
|
||||||
|
|
||||||
table.index([ "monitor_id", "group_id" ], "fk");
|
table.index(["monitor_id", "group_id"], "fk");
|
||||||
});
|
});
|
||||||
// monitor_maintenance
|
// monitor_maintenance
|
||||||
await knex.schema.createTable("monitor_maintenance", (table) => {
|
await knex.schema.createTable("monitor_maintenance", (table) => {
|
||||||
table.increments("id");
|
table.increments("id");
|
||||||
table.integer("monitor_id").unsigned().notNullable()
|
table
|
||||||
.references("id").inTable("monitor")
|
.integer("monitor_id")
|
||||||
|
.unsigned()
|
||||||
|
.notNullable()
|
||||||
|
.references("id")
|
||||||
|
.inTable("monitor")
|
||||||
.onDelete("CASCADE")
|
.onDelete("CASCADE")
|
||||||
.onUpdate("CASCADE");
|
.onUpdate("CASCADE");
|
||||||
table.integer("maintenance_id").unsigned().notNullable()
|
table
|
||||||
.references("id").inTable("maintenance")
|
.integer("maintenance_id")
|
||||||
|
.unsigned()
|
||||||
|
.notNullable()
|
||||||
|
.references("id")
|
||||||
|
.inTable("maintenance")
|
||||||
.onDelete("CASCADE")
|
.onDelete("CASCADE")
|
||||||
.onUpdate("CASCADE");
|
.onUpdate("CASCADE");
|
||||||
|
|
||||||
@ -280,17 +304,25 @@ async function createTables() {
|
|||||||
|
|
||||||
// monitor_notification
|
// monitor_notification
|
||||||
await knex.schema.createTable("monitor_notification", (table) => {
|
await knex.schema.createTable("monitor_notification", (table) => {
|
||||||
table.increments("id").unsigned(); // TODO: no auto increment????
|
table.increments("id").unsigned(); // TODO: no auto increment????
|
||||||
table.integer("monitor_id").unsigned().notNullable()
|
table
|
||||||
.references("id").inTable("monitor")
|
.integer("monitor_id")
|
||||||
|
.unsigned()
|
||||||
|
.notNullable()
|
||||||
|
.references("id")
|
||||||
|
.inTable("monitor")
|
||||||
.onDelete("CASCADE")
|
.onDelete("CASCADE")
|
||||||
.onUpdate("CASCADE");
|
.onUpdate("CASCADE");
|
||||||
table.integer("notification_id").unsigned().notNullable()
|
table
|
||||||
.references("id").inTable("notification")
|
.integer("notification_id")
|
||||||
|
.unsigned()
|
||||||
|
.notNullable()
|
||||||
|
.references("id")
|
||||||
|
.inTable("notification")
|
||||||
.onDelete("CASCADE")
|
.onDelete("CASCADE")
|
||||||
.onUpdate("CASCADE");
|
.onUpdate("CASCADE");
|
||||||
|
|
||||||
table.index([ "monitor_id", "notification_id" ], "monitor_notification_index");
|
table.index(["monitor_id", "notification_id"], "monitor_notification_index");
|
||||||
});
|
});
|
||||||
|
|
||||||
// tag
|
// tag
|
||||||
@ -304,12 +336,20 @@ async function createTables() {
|
|||||||
// monitor_tag
|
// monitor_tag
|
||||||
await knex.schema.createTable("monitor_tag", (table) => {
|
await knex.schema.createTable("monitor_tag", (table) => {
|
||||||
table.increments("id");
|
table.increments("id");
|
||||||
table.integer("monitor_id").unsigned().notNullable()
|
table
|
||||||
.references("id").inTable("monitor")
|
.integer("monitor_id")
|
||||||
|
.unsigned()
|
||||||
|
.notNullable()
|
||||||
|
.references("id")
|
||||||
|
.inTable("monitor")
|
||||||
.onDelete("CASCADE")
|
.onDelete("CASCADE")
|
||||||
.onUpdate("CASCADE");
|
.onUpdate("CASCADE");
|
||||||
table.integer("tag_id").unsigned().notNullable()
|
table
|
||||||
.references("id").inTable("tag")
|
.integer("tag_id")
|
||||||
|
.unsigned()
|
||||||
|
.notNullable()
|
||||||
|
.references("id")
|
||||||
|
.inTable("tag")
|
||||||
.onDelete("CASCADE")
|
.onDelete("CASCADE")
|
||||||
.onUpdate("CASCADE");
|
.onUpdate("CASCADE");
|
||||||
table.text("value");
|
table.text("value");
|
||||||
@ -318,8 +358,12 @@ async function createTables() {
|
|||||||
// monitor_tls_info
|
// monitor_tls_info
|
||||||
await knex.schema.createTable("monitor_tls_info", (table) => {
|
await knex.schema.createTable("monitor_tls_info", (table) => {
|
||||||
table.increments("id");
|
table.increments("id");
|
||||||
table.integer("monitor_id").unsigned().notNullable()
|
table
|
||||||
.references("id").inTable("monitor")
|
.integer("monitor_id")
|
||||||
|
.unsigned()
|
||||||
|
.notNullable()
|
||||||
|
.references("id")
|
||||||
|
.inTable("monitor")
|
||||||
.onDelete("CASCADE")
|
.onDelete("CASCADE")
|
||||||
.onUpdate("CASCADE");
|
.onUpdate("CASCADE");
|
||||||
table.text("info_json");
|
table.text("info_json");
|
||||||
@ -331,8 +375,8 @@ async function createTables() {
|
|||||||
table.string("type", 50).notNullable();
|
table.string("type", 50).notNullable();
|
||||||
table.integer("monitor_id").unsigned().notNullable();
|
table.integer("monitor_id").unsigned().notNullable();
|
||||||
table.integer("days").notNullable();
|
table.integer("days").notNullable();
|
||||||
table.unique([ "type", "monitor_id", "days" ]);
|
table.unique(["type", "monitor_id", "days"]);
|
||||||
table.index([ "type", "monitor_id", "days" ], "good_index");
|
table.index(["type", "monitor_id", "days"], "good_index");
|
||||||
});
|
});
|
||||||
|
|
||||||
// setting
|
// setting
|
||||||
@ -346,16 +390,19 @@ async function createTables() {
|
|||||||
// status_page_cname
|
// status_page_cname
|
||||||
await knex.schema.createTable("status_page_cname", (table) => {
|
await knex.schema.createTable("status_page_cname", (table) => {
|
||||||
table.increments("id");
|
table.increments("id");
|
||||||
table.integer("status_page_id").unsigned()
|
table
|
||||||
.references("id").inTable("status_page")
|
.integer("status_page_id")
|
||||||
|
.unsigned()
|
||||||
|
.references("id")
|
||||||
|
.inTable("status_page")
|
||||||
.onDelete("CASCADE")
|
.onDelete("CASCADE")
|
||||||
.onUpdate("CASCADE");
|
.onUpdate("CASCADE");
|
||||||
table.string("domain").notNullable().unique().collate("utf8_general_ci");
|
table.string("domain").notNullable().unique().collate("utf8_general_ci");
|
||||||
});
|
});
|
||||||
|
|
||||||
/*********************
|
/*********************
|
||||||
* Converted Patch here
|
* Converted Patch here
|
||||||
*********************/
|
*********************/
|
||||||
|
|
||||||
// 2023-06-30-1348-http-body-encoding.js
|
// 2023-06-30-1348-http-body-encoding.js
|
||||||
// ALTER TABLE monitor ADD http_body_encoding VARCHAR(25);
|
// ALTER TABLE monitor ADD http_body_encoding VARCHAR(25);
|
||||||
@ -396,8 +443,12 @@ async function createTables() {
|
|||||||
table.increments("id").primary();
|
table.increments("id").primary();
|
||||||
table.string("key", 255).notNullable();
|
table.string("key", 255).notNullable();
|
||||||
table.string("name", 255).notNullable();
|
table.string("name", 255).notNullable();
|
||||||
table.integer("user_id").unsigned().notNullable()
|
table
|
||||||
.references("id").inTable("user")
|
.integer("user_id")
|
||||||
|
.unsigned()
|
||||||
|
.notNullable()
|
||||||
|
.references("id")
|
||||||
|
.inTable("user")
|
||||||
.onDelete("CASCADE")
|
.onDelete("CASCADE")
|
||||||
.onUpdate("CASCADE");
|
.onUpdate("CASCADE");
|
||||||
table.dateTime("created_date").defaultTo(knex.fn.now()).notNullable();
|
table.dateTime("created_date").defaultTo(knex.fn.now()).notNullable();
|
||||||
@ -430,13 +481,11 @@ async function createTables() {
|
|||||||
ALTER TABLE maintenance ADD timezone VARCHAR(255);
|
ALTER TABLE maintenance ADD timezone VARCHAR(255);
|
||||||
ALTER TABLE maintenance ADD duration INTEGER;
|
ALTER TABLE maintenance ADD duration INTEGER;
|
||||||
*/
|
*/
|
||||||
await knex.schema
|
await knex.schema.dropTableIfExists("maintenance_timeslot").table("maintenance", function (table) {
|
||||||
.dropTableIfExists("maintenance_timeslot")
|
table.text("cron");
|
||||||
.table("maintenance", function (table) {
|
table.string("timezone", 255);
|
||||||
table.text("cron");
|
table.integer("duration");
|
||||||
table.string("timezone", 255);
|
});
|
||||||
table.integer("duration");
|
|
||||||
});
|
|
||||||
|
|
||||||
// 2023-06-30-1413-add-parent-monitor.js.
|
// 2023-06-30-1413-add-parent-monitor.js.
|
||||||
/*
|
/*
|
||||||
@ -444,10 +493,7 @@ async function createTables() {
|
|||||||
ADD parent INTEGER REFERENCES [monitor] ([id]) ON DELETE SET NULL ON UPDATE CASCADE;
|
ADD parent INTEGER REFERENCES [monitor] ([id]) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
*/
|
*/
|
||||||
await knex.schema.table("monitor", function (table) {
|
await knex.schema.table("monitor", function (table) {
|
||||||
table.integer("parent").unsigned()
|
table.integer("parent").unsigned().references("id").inTable("monitor").onDelete("SET NULL").onUpdate("CASCADE");
|
||||||
.references("id").inTable("monitor")
|
|
||||||
.onDelete("SET NULL")
|
|
||||||
.onUpdate("CASCADE");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@ -3,39 +3,41 @@ exports.up = function (knex) {
|
|||||||
.createTable("stat_minutely", function (table) {
|
.createTable("stat_minutely", function (table) {
|
||||||
table.increments("id");
|
table.increments("id");
|
||||||
table.comment("This table contains the minutely aggregate statistics for each monitor");
|
table.comment("This table contains the minutely aggregate statistics for each monitor");
|
||||||
table.integer("monitor_id").unsigned().notNullable()
|
table
|
||||||
.references("id").inTable("monitor")
|
.integer("monitor_id")
|
||||||
|
.unsigned()
|
||||||
|
.notNullable()
|
||||||
|
.references("id")
|
||||||
|
.inTable("monitor")
|
||||||
.onDelete("CASCADE")
|
.onDelete("CASCADE")
|
||||||
.onUpdate("CASCADE");
|
.onUpdate("CASCADE");
|
||||||
table.integer("timestamp")
|
table.integer("timestamp").notNullable().comment("Unix timestamp rounded down to the nearest minute");
|
||||||
.notNullable()
|
|
||||||
.comment("Unix timestamp rounded down to the nearest minute");
|
|
||||||
table.float("ping").notNullable().comment("Average ping in milliseconds");
|
table.float("ping").notNullable().comment("Average ping in milliseconds");
|
||||||
table.smallint("up").notNullable();
|
table.smallint("up").notNullable();
|
||||||
table.smallint("down").notNullable();
|
table.smallint("down").notNullable();
|
||||||
|
|
||||||
table.unique([ "monitor_id", "timestamp" ]);
|
table.unique(["monitor_id", "timestamp"]);
|
||||||
})
|
})
|
||||||
.createTable("stat_daily", function (table) {
|
.createTable("stat_daily", function (table) {
|
||||||
table.increments("id");
|
table.increments("id");
|
||||||
table.comment("This table contains the daily aggregate statistics for each monitor");
|
table.comment("This table contains the daily aggregate statistics for each monitor");
|
||||||
table.integer("monitor_id").unsigned().notNullable()
|
table
|
||||||
.references("id").inTable("monitor")
|
.integer("monitor_id")
|
||||||
|
.unsigned()
|
||||||
|
.notNullable()
|
||||||
|
.references("id")
|
||||||
|
.inTable("monitor")
|
||||||
.onDelete("CASCADE")
|
.onDelete("CASCADE")
|
||||||
.onUpdate("CASCADE");
|
.onUpdate("CASCADE");
|
||||||
table.integer("timestamp")
|
table.integer("timestamp").notNullable().comment("Unix timestamp rounded down to the nearest day");
|
||||||
.notNullable()
|
|
||||||
.comment("Unix timestamp rounded down to the nearest day");
|
|
||||||
table.float("ping").notNullable().comment("Average ping in milliseconds");
|
table.float("ping").notNullable().comment("Average ping in milliseconds");
|
||||||
table.smallint("up").notNullable();
|
table.smallint("up").notNullable();
|
||||||
table.smallint("down").notNullable();
|
table.smallint("down").notNullable();
|
||||||
|
|
||||||
table.unique([ "monitor_id", "timestamp" ]);
|
table.unique(["monitor_id", "timestamp"]);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.down = function (knex) {
|
exports.down = function (knex) {
|
||||||
return knex.schema
|
return knex.schema.dropTable("stat_minutely").dropTable("stat_daily");
|
||||||
.dropTable("stat_minutely")
|
|
||||||
.dropTable("stat_daily");
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,16 +1,13 @@
|
|||||||
exports.up = function (knex) {
|
exports.up = function (knex) {
|
||||||
// Add new column heartbeat.end_time
|
// Add new column heartbeat.end_time
|
||||||
return knex.schema
|
return knex.schema.alterTable("heartbeat", function (table) {
|
||||||
.alterTable("heartbeat", function (table) {
|
table.datetime("end_time").nullable().defaultTo(null);
|
||||||
table.datetime("end_time").nullable().defaultTo(null);
|
});
|
||||||
});
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.down = function (knex) {
|
exports.down = function (knex) {
|
||||||
// Rename heartbeat.start_time to heartbeat.time
|
// Rename heartbeat.start_time to heartbeat.time
|
||||||
return knex.schema
|
return knex.schema.alterTable("heartbeat", function (table) {
|
||||||
.alterTable("heartbeat", function (table) {
|
table.dropColumn("end_time");
|
||||||
table.dropColumn("end_time");
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,15 +1,12 @@
|
|||||||
exports.up = function (knex) {
|
exports.up = function (knex) {
|
||||||
// Add new column heartbeat.retries
|
// Add new column heartbeat.retries
|
||||||
return knex.schema
|
return knex.schema.alterTable("heartbeat", function (table) {
|
||||||
.alterTable("heartbeat", function (table) {
|
table.integer("retries").notNullable().defaultTo(0);
|
||||||
table.integer("retries").notNullable().defaultTo(0);
|
});
|
||||||
});
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.down = function (knex) {
|
exports.down = function (knex) {
|
||||||
return knex.schema
|
return knex.schema.alterTable("heartbeat", function (table) {
|
||||||
.alterTable("heartbeat", function (table) {
|
table.dropColumn("retries");
|
||||||
table.dropColumn("retries");
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,16 +1,13 @@
|
|||||||
exports.up = function (knex) {
|
exports.up = function (knex) {
|
||||||
// Add new column monitor.mqtt_check_type
|
// Add new column monitor.mqtt_check_type
|
||||||
return knex.schema
|
return knex.schema.alterTable("monitor", function (table) {
|
||||||
.alterTable("monitor", function (table) {
|
table.string("mqtt_check_type", 255).notNullable().defaultTo("keyword");
|
||||||
table.string("mqtt_check_type", 255).notNullable().defaultTo("keyword");
|
});
|
||||||
});
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.down = function (knex) {
|
exports.down = function (knex) {
|
||||||
// Drop column monitor.mqtt_check_type
|
// Drop column monitor.mqtt_check_type
|
||||||
return knex.schema
|
return knex.schema.alterTable("monitor", function (table) {
|
||||||
.alterTable("monitor", function (table) {
|
table.dropColumn("mqtt_check_type");
|
||||||
table.dropColumn("mqtt_check_type");
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,14 +1,12 @@
|
|||||||
exports.up = function (knex) {
|
exports.up = function (knex) {
|
||||||
// update monitor.push_token to 32 length
|
// update monitor.push_token to 32 length
|
||||||
return knex.schema
|
return knex.schema.alterTable("monitor", function (table) {
|
||||||
.alterTable("monitor", function (table) {
|
table.string("push_token", 32).alter();
|
||||||
table.string("push_token", 32).alter();
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.down = function (knex) {
|
exports.down = function (knex) {
|
||||||
return knex.schema
|
return knex.schema.alterTable("monitor", function (table) {
|
||||||
.alterTable("monitor", function (table) {
|
table.string("push_token", 20).alter();
|
||||||
table.string("push_token", 20).alter();
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -5,9 +5,14 @@ exports.up = function (knex) {
|
|||||||
table.string("name", 255).notNullable();
|
table.string("name", 255).notNullable();
|
||||||
table.string("url", 255).notNullable();
|
table.string("url", 255).notNullable();
|
||||||
table.integer("user_id").unsigned();
|
table.integer("user_id").unsigned();
|
||||||
}).alterTable("monitor", function (table) {
|
})
|
||||||
|
.alterTable("monitor", function (table) {
|
||||||
// Add new column monitor.remote_browser
|
// Add new column monitor.remote_browser
|
||||||
table.integer("remote_browser").nullable().defaultTo(null).unsigned()
|
table
|
||||||
|
.integer("remote_browser")
|
||||||
|
.nullable()
|
||||||
|
.defaultTo(null)
|
||||||
|
.unsigned()
|
||||||
.index()
|
.index()
|
||||||
.references("id")
|
.references("id")
|
||||||
.inTable("remote_browser");
|
.inTable("remote_browser");
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
exports.up = function (knex) {
|
exports.up = function (knex) {
|
||||||
return knex.schema
|
return knex.schema.alterTable("status_page", function (table) {
|
||||||
.alterTable("status_page", function (table) {
|
table.integer("auto_refresh_interval").defaultTo(300).unsigned();
|
||||||
table.integer("auto_refresh_interval").defaultTo(300).unsigned();
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.down = function (knex) {
|
exports.down = function (knex) {
|
||||||
|
|||||||
@ -1,14 +1,29 @@
|
|||||||
exports.up = function (knex) {
|
exports.up = function (knex) {
|
||||||
return knex.schema
|
return knex.schema
|
||||||
.alterTable("stat_daily", function (table) {
|
.alterTable("stat_daily", function (table) {
|
||||||
table.float("ping_min").notNullable().defaultTo(0).comment("Minimum ping during this period in milliseconds");
|
table
|
||||||
table.float("ping_max").notNullable().defaultTo(0).comment("Maximum ping during this period in milliseconds");
|
.float("ping_min")
|
||||||
|
.notNullable()
|
||||||
|
.defaultTo(0)
|
||||||
|
.comment("Minimum ping during this period in milliseconds");
|
||||||
|
table
|
||||||
|
.float("ping_max")
|
||||||
|
.notNullable()
|
||||||
|
.defaultTo(0)
|
||||||
|
.comment("Maximum ping during this period in milliseconds");
|
||||||
})
|
})
|
||||||
.alterTable("stat_minutely", function (table) {
|
.alterTable("stat_minutely", function (table) {
|
||||||
table.float("ping_min").notNullable().defaultTo(0).comment("Minimum ping during this period in milliseconds");
|
table
|
||||||
table.float("ping_max").notNullable().defaultTo(0).comment("Maximum ping during this period in milliseconds");
|
.float("ping_min")
|
||||||
|
.notNullable()
|
||||||
|
.defaultTo(0)
|
||||||
|
.comment("Minimum ping during this period in milliseconds");
|
||||||
|
table
|
||||||
|
.float("ping_max")
|
||||||
|
.notNullable()
|
||||||
|
.defaultTo(0)
|
||||||
|
.comment("Maximum ping during this period in milliseconds");
|
||||||
});
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.down = function (knex) {
|
exports.down = function (knex) {
|
||||||
|
|||||||
@ -1,26 +1,26 @@
|
|||||||
exports.up = function (knex) {
|
exports.up = function (knex) {
|
||||||
return knex.schema
|
return knex.schema.createTable("stat_hourly", function (table) {
|
||||||
.createTable("stat_hourly", function (table) {
|
table.increments("id");
|
||||||
table.increments("id");
|
table.comment("This table contains the hourly aggregate statistics for each monitor");
|
||||||
table.comment("This table contains the hourly aggregate statistics for each monitor");
|
table
|
||||||
table.integer("monitor_id").unsigned().notNullable()
|
.integer("monitor_id")
|
||||||
.references("id").inTable("monitor")
|
.unsigned()
|
||||||
.onDelete("CASCADE")
|
.notNullable()
|
||||||
.onUpdate("CASCADE");
|
.references("id")
|
||||||
table.integer("timestamp")
|
.inTable("monitor")
|
||||||
.notNullable()
|
.onDelete("CASCADE")
|
||||||
.comment("Unix timestamp rounded down to the nearest hour");
|
.onUpdate("CASCADE");
|
||||||
table.float("ping").notNullable().comment("Average ping in milliseconds");
|
table.integer("timestamp").notNullable().comment("Unix timestamp rounded down to the nearest hour");
|
||||||
table.float("ping_min").notNullable().defaultTo(0).comment("Minimum ping during this period in milliseconds");
|
table.float("ping").notNullable().comment("Average ping in milliseconds");
|
||||||
table.float("ping_max").notNullable().defaultTo(0).comment("Maximum ping during this period in milliseconds");
|
table.float("ping_min").notNullable().defaultTo(0).comment("Minimum ping during this period in milliseconds");
|
||||||
table.smallint("up").notNullable();
|
table.float("ping_max").notNullable().defaultTo(0).comment("Maximum ping during this period in milliseconds");
|
||||||
table.smallint("down").notNullable();
|
table.smallint("up").notNullable();
|
||||||
|
table.smallint("down").notNullable();
|
||||||
|
|
||||||
table.unique([ "monitor_id", "timestamp" ]);
|
table.unique(["monitor_id", "timestamp"]);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.down = function (knex) {
|
exports.down = function (knex) {
|
||||||
return knex.schema
|
return knex.schema.dropTable("stat_hourly");
|
||||||
.dropTable("stat_hourly");
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -9,7 +9,6 @@ exports.up = function (knex) {
|
|||||||
.alterTable("stat_hourly", function (table) {
|
.alterTable("stat_hourly", function (table) {
|
||||||
table.text("extras").defaultTo(null).comment("Extra statistics during this time period");
|
table.text("extras").defaultTo(null).comment("Extra statistics during this time period");
|
||||||
});
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.down = function (knex) {
|
exports.down = function (knex) {
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
exports.up = function (knex) {
|
exports.up = function (knex) {
|
||||||
return knex.schema
|
return knex.schema.alterTable("monitor", function (table) {
|
||||||
.alterTable("monitor", function (table) {
|
table.string("snmp_oid").defaultTo(null);
|
||||||
table.string("snmp_oid").defaultTo(null);
|
table.enum("snmp_version", ["1", "2c", "3"]).defaultTo("2c");
|
||||||
table.enum("snmp_version", [ "1", "2c", "3" ]).defaultTo("2c");
|
table.string("json_path_operator").defaultTo(null);
|
||||||
table.string("json_path_operator").defaultTo(null);
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.down = function (knex) {
|
exports.down = function (knex) {
|
||||||
|
|||||||
@ -1,13 +1,11 @@
|
|||||||
exports.up = function (knex) {
|
exports.up = function (knex) {
|
||||||
return knex.schema
|
return knex.schema.alterTable("monitor", function (table) {
|
||||||
.alterTable("monitor", function (table) {
|
table.boolean("cache_bust").notNullable().defaultTo(false);
|
||||||
table.boolean("cache_bust").notNullable().defaultTo(false);
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.down = function (knex) {
|
exports.down = function (knex) {
|
||||||
return knex.schema
|
return knex.schema.alterTable("monitor", function (table) {
|
||||||
.alterTable("monitor", function (table) {
|
table.dropColumn("cache_bust");
|
||||||
table.dropColumn("cache_bust");
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
exports.up = function (knex) {
|
exports.up = function (knex) {
|
||||||
return knex.schema
|
return knex.schema.alterTable("monitor", function (table) {
|
||||||
.alterTable("monitor", function (table) {
|
table.text("conditions").notNullable().defaultTo("[]");
|
||||||
table.text("conditions").notNullable().defaultTo("[]");
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.down = function (knex) {
|
exports.down = function (knex) {
|
||||||
|
|||||||
@ -4,7 +4,6 @@ exports.up = function (knex) {
|
|||||||
table.string("rabbitmq_username");
|
table.string("rabbitmq_username");
|
||||||
table.string("rabbitmq_password");
|
table.string("rabbitmq_password");
|
||||||
});
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.down = function (knex) {
|
exports.down = function (knex) {
|
||||||
@ -13,5 +12,4 @@ exports.down = function (knex) {
|
|||||||
table.dropColumn("rabbitmq_username");
|
table.dropColumn("rabbitmq_username");
|
||||||
table.dropColumn("rabbitmq_password");
|
table.dropColumn("rabbitmq_password");
|
||||||
});
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
// Update info_json column to LONGTEXT mainly for MariaDB
|
// Update info_json column to LONGTEXT mainly for MariaDB
|
||||||
exports.up = function (knex) {
|
exports.up = function (knex) {
|
||||||
return knex.schema
|
return knex.schema.alterTable("monitor_tls_info", function (table) {
|
||||||
.alterTable("monitor_tls_info", function (table) {
|
table.text("info_json", "longtext").alter();
|
||||||
table.text("info_json", "longtext").alter();
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.down = function (knex) {
|
exports.down = function (knex) {
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
exports.up = function (knex) {
|
exports.up = function (knex) {
|
||||||
return knex.schema
|
return knex.schema.alterTable("monitor", function (table) {
|
||||||
.alterTable("monitor", function (table) {
|
table.string("smtp_security").defaultTo(null);
|
||||||
table.string("smtp_security").defaultTo(null);
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.down = function (knex) {
|
exports.down = function (knex) {
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
// Add websocket ignore headers and websocket subprotocol
|
// Add websocket ignore headers and websocket subprotocol
|
||||||
exports.up = function (knex) {
|
exports.up = function (knex) {
|
||||||
return knex.schema
|
return knex.schema.alterTable("monitor", function (table) {
|
||||||
.alterTable("monitor", function (table) {
|
table.boolean("ws_ignore_sec_websocket_accept_header").notNullable().defaultTo(false);
|
||||||
table.boolean("ws_ignore_sec_websocket_accept_header").notNullable().defaultTo(false);
|
table.string("ws_subprotocol", 255).notNullable().defaultTo("");
|
||||||
table.string("ws_subprotocol", 255).notNullable().defaultTo("");
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.down = function (knex) {
|
exports.down = function (knex) {
|
||||||
|
|||||||
@ -4,12 +4,12 @@ exports.up = function (knex) {
|
|||||||
.alterTable("status_page", function (table) {
|
.alterTable("status_page", function (table) {
|
||||||
table.renameColumn("google_analytics_tag_id", "analytics_id");
|
table.renameColumn("google_analytics_tag_id", "analytics_id");
|
||||||
table.string("analytics_script_url");
|
table.string("analytics_script_url");
|
||||||
table.enu("analytics_type", [ "google", "umami", "plausible", "matomo" ]).defaultTo(null);
|
table.enu("analytics_type", ["google", "umami", "plausible", "matomo"]).defaultTo(null);
|
||||||
|
})
|
||||||
}).then(() => {
|
.then(() => {
|
||||||
// After a succesful migration, add google as default for previous pages
|
// After a succesful migration, add google as default for previous pages
|
||||||
knex("status_page").whereNotNull("analytics_id").update({
|
knex("status_page").whereNotNull("analytics_id").update({
|
||||||
"analytics_type": "google",
|
analytics_type: "google",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -5,20 +5,17 @@ ALTER TABLE monitor ADD ping_per_request_timeout INTEGER default 2 not null;
|
|||||||
*/
|
*/
|
||||||
exports.up = function (knex) {
|
exports.up = function (knex) {
|
||||||
// Add new columns to table monitor
|
// Add new columns to table monitor
|
||||||
return knex.schema
|
return knex.schema.alterTable("monitor", function (table) {
|
||||||
.alterTable("monitor", function (table) {
|
table.integer("ping_count").defaultTo(1).notNullable();
|
||||||
table.integer("ping_count").defaultTo(1).notNullable();
|
table.boolean("ping_numeric").defaultTo(true).notNullable();
|
||||||
table.boolean("ping_numeric").defaultTo(true).notNullable();
|
table.integer("ping_per_request_timeout").defaultTo(2).notNullable();
|
||||||
table.integer("ping_per_request_timeout").defaultTo(2).notNullable();
|
});
|
||||||
});
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.down = function (knex) {
|
exports.down = function (knex) {
|
||||||
return knex.schema
|
return knex.schema.alterTable("monitor", function (table) {
|
||||||
.alterTable("monitor", function (table) {
|
table.dropColumn("ping_count");
|
||||||
table.dropColumn("ping_count");
|
table.dropColumn("ping_numeric");
|
||||||
table.dropColumn("ping_numeric");
|
table.dropColumn("ping_per_request_timeout");
|
||||||
table.dropColumn("ping_per_request_timeout");
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
// Fix #5721: Change proxy port column type to integer to support larger port numbers
|
// Fix #5721: Change proxy port column type to integer to support larger port numbers
|
||||||
exports.up = function (knex) {
|
exports.up = function (knex) {
|
||||||
return knex.schema
|
return knex.schema.alterTable("proxy", function (table) {
|
||||||
.alterTable("proxy", function (table) {
|
table.integer("port").alter();
|
||||||
table.integer("port").alter();
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.down = function (knex) {
|
exports.down = function (knex) {
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
// Add column custom_url to monitor_group table
|
// Add column custom_url to monitor_group table
|
||||||
exports.up = function (knex) {
|
exports.up = function (knex) {
|
||||||
return knex.schema
|
return knex.schema.alterTable("monitor_group", function (table) {
|
||||||
.alterTable("monitor_group", function (table) {
|
table.text("custom_url", "text");
|
||||||
table.text("custom_url", "text");
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.down = function (knex) {
|
exports.down = function (knex) {
|
||||||
|
|||||||
@ -1,13 +1,11 @@
|
|||||||
exports.up = function (knex) {
|
exports.up = function (knex) {
|
||||||
return knex.schema
|
return knex.schema.alterTable("monitor", function (table) {
|
||||||
.alterTable("monitor", function (table) {
|
table.boolean("ip_family").defaultTo(null);
|
||||||
table.boolean("ip_family").defaultTo(null);
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.down = function (knex) {
|
exports.down = function (knex) {
|
||||||
return knex.schema
|
return knex.schema.alterTable("monitor", function (table) {
|
||||||
.alterTable("monitor", function (table) {
|
table.dropColumn("ip_family");
|
||||||
table.dropColumn("ip_family");
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
exports.up = function (knex) {
|
exports.up = function (knex) {
|
||||||
return knex.schema
|
return knex.schema.alterTable("monitor", function (table) {
|
||||||
.alterTable("monitor", function (table) {
|
table.string("manual_status").defaultTo(null);
|
||||||
table.string("manual_status").defaultTo(null);
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.down = function (knex) {
|
exports.down = function (knex) {
|
||||||
|
|||||||
@ -1,28 +1,27 @@
|
|||||||
// Add column last_start_date to maintenance table
|
// Add column last_start_date to maintenance table
|
||||||
exports.up = async function (knex) {
|
exports.up = async function (knex) {
|
||||||
await knex.schema
|
await knex.schema.alterTable("maintenance", function (table) {
|
||||||
.alterTable("maintenance", function (table) {
|
table.datetime("last_start_date");
|
||||||
table.datetime("last_start_date");
|
});
|
||||||
});
|
|
||||||
|
|
||||||
// Perform migration for recurring-interval strategy
|
// Perform migration for recurring-interval strategy
|
||||||
const recurringMaintenances = await knex("maintenance").where({
|
const recurringMaintenances = await knex("maintenance")
|
||||||
strategy: "recurring-interval",
|
.where({
|
||||||
cron: "* * * * *"
|
strategy: "recurring-interval",
|
||||||
}).select("id", "start_time");
|
cron: "* * * * *",
|
||||||
|
})
|
||||||
|
.select("id", "start_time");
|
||||||
|
|
||||||
// eslint-disable-next-line camelcase
|
// eslint-disable-next-line camelcase
|
||||||
const maintenanceUpdates = recurringMaintenances.map(async ({ start_time, id }) => {
|
const maintenanceUpdates = recurringMaintenances.map(async ({ start_time, id }) => {
|
||||||
// eslint-disable-next-line camelcase
|
// eslint-disable-next-line camelcase
|
||||||
const [ hourStr, minuteStr ] = start_time.split(":");
|
const [hourStr, minuteStr] = start_time.split(":");
|
||||||
const hour = parseInt(hourStr, 10);
|
const hour = parseInt(hourStr, 10);
|
||||||
const minute = parseInt(minuteStr, 10);
|
const minute = parseInt(minuteStr, 10);
|
||||||
|
|
||||||
const cron = `${minute} ${hour} * * *`;
|
const cron = `${minute} ${hour} * * *`;
|
||||||
|
|
||||||
await knex("maintenance")
|
await knex("maintenance").where({ id }).update({ cron });
|
||||||
.where({ id })
|
|
||||||
.update({ cron });
|
|
||||||
});
|
});
|
||||||
await Promise.all(maintenanceUpdates);
|
await Promise.all(maintenanceUpdates);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
// Fix: Change manual_status column type to smallint
|
// Fix: Change manual_status column type to smallint
|
||||||
exports.up = function (knex) {
|
exports.up = function (knex) {
|
||||||
return knex.schema
|
return knex.schema.alterTable("monitor", function (table) {
|
||||||
.alterTable("monitor", function (table) {
|
table.smallint("manual_status").alter();
|
||||||
table.smallint("manual_status").alter();
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.down = function (knex) {
|
exports.down = function (knex) {
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
exports.up = function (knex) {
|
exports.up = function (knex) {
|
||||||
return knex.schema
|
return knex.schema.alterTable("monitor", function (table) {
|
||||||
.alterTable("monitor", function (table) {
|
table.string("oauth_audience").nullable().defaultTo(null);
|
||||||
table.string("oauth_audience").nullable().defaultTo(null);
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.down = function (knex) {
|
exports.down = function (knex) {
|
||||||
|
|||||||
@ -1,15 +1,13 @@
|
|||||||
exports.up = function (knex) {
|
exports.up = function (knex) {
|
||||||
// Add new column monitor.mqtt_websocket_path
|
// Add new column monitor.mqtt_websocket_path
|
||||||
return knex.schema
|
return knex.schema.alterTable("monitor", function (table) {
|
||||||
.alterTable("monitor", function (table) {
|
table.string("mqtt_websocket_path", 255).nullable();
|
||||||
table.string("mqtt_websocket_path", 255).nullable();
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.down = function (knex) {
|
exports.down = function (knex) {
|
||||||
// Drop column monitor.mqtt_websocket_path
|
// Drop column monitor.mqtt_websocket_path
|
||||||
return knex.schema
|
return knex.schema.alterTable("monitor", function (table) {
|
||||||
.alterTable("monitor", function (table) {
|
table.dropColumn("mqtt_websocket_path");
|
||||||
table.dropColumn("mqtt_websocket_path");
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,16 +1,14 @@
|
|||||||
exports.up = function (knex) {
|
exports.up = function (knex) {
|
||||||
return knex.schema
|
return knex.schema.alterTable("monitor", function (table) {
|
||||||
.alterTable("monitor", function (table) {
|
// Fix ip_family, change to varchar instead of boolean
|
||||||
// Fix ip_family, change to varchar instead of boolean
|
// possible values are "ipv4" and "ipv6"
|
||||||
// possible values are "ipv4" and "ipv6"
|
table.string("ip_family", 4).defaultTo(null).alter();
|
||||||
table.string("ip_family", 4).defaultTo(null).alter();
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.down = function (knex) {
|
exports.down = function (knex) {
|
||||||
return knex.schema
|
return knex.schema.alterTable("monitor", function (table) {
|
||||||
.alterTable("monitor", function (table) {
|
// Rollback to boolean
|
||||||
// Rollback to boolean
|
table.boolean("ip_family").defaultTo(null).alter();
|
||||||
table.boolean("ip_family").defaultTo(null).alter();
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,15 +1,13 @@
|
|||||||
exports.up = function (knex) {
|
exports.up = function (knex) {
|
||||||
// Add new column status_page.show_only_last_heartbeat
|
// Add new column status_page.show_only_last_heartbeat
|
||||||
return knex.schema
|
return knex.schema.alterTable("status_page", function (table) {
|
||||||
.alterTable("status_page", function (table) {
|
table.boolean("show_only_last_heartbeat").notNullable().defaultTo(false);
|
||||||
table.boolean("show_only_last_heartbeat").notNullable().defaultTo(false);
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.down = function (knex) {
|
exports.down = function (knex) {
|
||||||
// Drop column status_page.show_only_last_heartbeat
|
// Drop column status_page.show_only_last_heartbeat
|
||||||
return knex.schema
|
return knex.schema.alterTable("status_page", function (table) {
|
||||||
.alterTable("status_page", function (table) {
|
table.dropColumn("show_only_last_heartbeat");
|
||||||
table.dropColumn("show_only_last_heartbeat");
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -9,11 +9,11 @@ exports.up = async function (knex) {
|
|||||||
|
|
||||||
// Create partial indexes with predicate
|
// Create partial indexes with predicate
|
||||||
await knex.schema.alterTable("heartbeat", function (table) {
|
await knex.schema.alterTable("heartbeat", function (table) {
|
||||||
table.index([ "monitor_id", "time" ], "monitor_important_time_index", {
|
table.index(["monitor_id", "time"], "monitor_important_time_index", {
|
||||||
predicate: knex.whereRaw("important = 1")
|
predicate: knex.whereRaw("important = 1"),
|
||||||
});
|
});
|
||||||
table.index([ "important" ], "heartbeat_important_index", {
|
table.index(["important"], "heartbeat_important_index", {
|
||||||
predicate: knex.whereRaw("important = 1")
|
predicate: knex.whereRaw("important = 1"),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -29,8 +29,8 @@ exports.down = async function (knex) {
|
|||||||
await knex.raw("DROP INDEX IF EXISTS heartbeat_important_index");
|
await knex.raw("DROP INDEX IF EXISTS heartbeat_important_index");
|
||||||
|
|
||||||
await knex.schema.alterTable("heartbeat", function (table) {
|
await knex.schema.alterTable("heartbeat", function (table) {
|
||||||
table.index([ "monitor_id", "important", "time" ], "monitor_important_time_index");
|
table.index(["monitor_id", "important", "time"], "monitor_important_time_index");
|
||||||
table.index([ "important" ]);
|
table.index(["important"]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// For MariaDB/MySQL: No changes
|
// For MariaDB/MySQL: No changes
|
||||||
|
|||||||
@ -1,14 +1,12 @@
|
|||||||
// Change dns_last_result column from VARCHAR(255) to TEXT to handle longer DNS TXT records
|
// Change dns_last_result column from VARCHAR(255) to TEXT to handle longer DNS TXT records
|
||||||
exports.up = function (knex) {
|
exports.up = function (knex) {
|
||||||
return knex.schema
|
return knex.schema.alterTable("monitor", function (table) {
|
||||||
.alterTable("monitor", function (table) {
|
table.text("dns_last_result").alter();
|
||||||
table.text("dns_last_result").alter();
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.down = function (knex) {
|
exports.down = function (knex) {
|
||||||
return knex.schema
|
return knex.schema.alterTable("monitor", function (table) {
|
||||||
.alterTable("monitor", function (table) {
|
table.string("dns_last_result", 255).alter();
|
||||||
table.string("dns_last_result", 255).alter();
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,139 +3,139 @@
|
|||||||
|
|
||||||
// Lookup table mapping v4 game IDs to v5 game IDs
|
// Lookup table mapping v4 game IDs to v5 game IDs
|
||||||
const gameDig4to5IdMap = {
|
const gameDig4to5IdMap = {
|
||||||
"americasarmypg": "aapg",
|
americasarmypg: "aapg",
|
||||||
"7d2d": "sdtd",
|
"7d2d": "sdtd",
|
||||||
"as": "actionsource",
|
as: "actionsource",
|
||||||
"ageofchivalry": "aoc",
|
ageofchivalry: "aoc",
|
||||||
"arkse": "ase",
|
arkse: "ase",
|
||||||
"arcasimracing": "asr08",
|
arcasimracing: "asr08",
|
||||||
"arma": "aaa",
|
arma: "aaa",
|
||||||
"arma2oa": "a2oa",
|
arma2oa: "a2oa",
|
||||||
"armacwa": "acwa",
|
armacwa: "acwa",
|
||||||
"armar": "armaresistance",
|
armar: "armaresistance",
|
||||||
"armare": "armareforger",
|
armare: "armareforger",
|
||||||
"armagetron": "armagetronadvanced",
|
armagetron: "armagetronadvanced",
|
||||||
"bat1944": "battalion1944",
|
bat1944: "battalion1944",
|
||||||
"bf1942": "battlefield1942",
|
bf1942: "battlefield1942",
|
||||||
"bfv": "battlefieldvietnam",
|
bfv: "battlefieldvietnam",
|
||||||
"bf2": "battlefield2",
|
bf2: "battlefield2",
|
||||||
"bf2142": "battlefield2142",
|
bf2142: "battlefield2142",
|
||||||
"bfbc2": "bbc2",
|
bfbc2: "bbc2",
|
||||||
"bf3": "battlefield3",
|
bf3: "battlefield3",
|
||||||
"bf4": "battlefield4",
|
bf4: "battlefield4",
|
||||||
"bfh": "battlefieldhardline",
|
bfh: "battlefieldhardline",
|
||||||
"bd": "basedefense",
|
bd: "basedefense",
|
||||||
"bs": "bladesymphony",
|
bs: "bladesymphony",
|
||||||
"buildandshoot": "bas",
|
buildandshoot: "bas",
|
||||||
"cod4": "cod4mw",
|
cod4: "cod4mw",
|
||||||
"callofjuarez": "coj",
|
callofjuarez: "coj",
|
||||||
"chivalry": "cmw",
|
chivalry: "cmw",
|
||||||
"commandos3": "c3db",
|
commandos3: "c3db",
|
||||||
"cacrenegade": "cacr",
|
cacrenegade: "cacr",
|
||||||
"contactjack": "contractjack",
|
contactjack: "contractjack",
|
||||||
"cs15": "counterstrike15",
|
cs15: "counterstrike15",
|
||||||
"cs16": "counterstrike16",
|
cs16: "counterstrike16",
|
||||||
"cs2": "counterstrike2",
|
cs2: "counterstrike2",
|
||||||
"crossracing": "crce",
|
crossracing: "crce",
|
||||||
"darkesthour": "dhe4445",
|
darkesthour: "dhe4445",
|
||||||
"daysofwar": "dow",
|
daysofwar: "dow",
|
||||||
"deadlydozenpt": "ddpt",
|
deadlydozenpt: "ddpt",
|
||||||
"dh2005": "deerhunter2005",
|
dh2005: "deerhunter2005",
|
||||||
"dinodday": "ddd",
|
dinodday: "ddd",
|
||||||
"dirttrackracing2": "dtr2",
|
dirttrackracing2: "dtr2",
|
||||||
"dmc": "deathmatchclassic",
|
dmc: "deathmatchclassic",
|
||||||
"dnl": "dal",
|
dnl: "dal",
|
||||||
"drakan": "dootf",
|
drakan: "dootf",
|
||||||
"dys": "dystopia",
|
dys: "dystopia",
|
||||||
"em": "empiresmod",
|
em: "empiresmod",
|
||||||
"empyrion": "egs",
|
empyrion: "egs",
|
||||||
"f12002": "formulaone2002",
|
f12002: "formulaone2002",
|
||||||
"flashpointresistance": "ofr",
|
flashpointresistance: "ofr",
|
||||||
"fivem": "gta5f",
|
fivem: "gta5f",
|
||||||
"forrest": "theforrest",
|
forrest: "theforrest",
|
||||||
"graw": "tcgraw",
|
graw: "tcgraw",
|
||||||
"graw2": "tcgraw2",
|
graw2: "tcgraw2",
|
||||||
"giantscitizenkabuto": "gck",
|
giantscitizenkabuto: "gck",
|
||||||
"ges": "goldeneyesource",
|
ges: "goldeneyesource",
|
||||||
"gore": "gus",
|
gore: "gus",
|
||||||
"hldm": "hld",
|
hldm: "hld",
|
||||||
"hldms": "hlds",
|
hldms: "hlds",
|
||||||
"hlopfor": "hlof",
|
hlopfor: "hlof",
|
||||||
"hl2dm": "hl2d",
|
hl2dm: "hl2d",
|
||||||
"hidden": "thehidden",
|
hidden: "thehidden",
|
||||||
"had2": "hiddendangerous2",
|
had2: "hiddendangerous2",
|
||||||
"igi2": "i2cs",
|
igi2: "i2cs",
|
||||||
"il2": "il2sturmovik",
|
il2: "il2sturmovik",
|
||||||
"insurgencymic": "imic",
|
insurgencymic: "imic",
|
||||||
"isle": "theisle",
|
isle: "theisle",
|
||||||
"jamesbondnightfire": "jb007n",
|
jamesbondnightfire: "jb007n",
|
||||||
"jc2mp": "jc2m",
|
jc2mp: "jc2m",
|
||||||
"jc3mp": "jc3m",
|
jc3mp: "jc3m",
|
||||||
"kingpin": "kloc",
|
kingpin: "kloc",
|
||||||
"kisspc": "kpctnc",
|
kisspc: "kpctnc",
|
||||||
"kspdmp": "kspd",
|
kspdmp: "kspd",
|
||||||
"kzmod": "kreedzclimbing",
|
kzmod: "kreedzclimbing",
|
||||||
"left4dead": "l4d",
|
left4dead: "l4d",
|
||||||
"left4dead2": "l4d2",
|
left4dead2: "l4d2",
|
||||||
"m2mp": "m2m",
|
m2mp: "m2m",
|
||||||
"mohsh": "mohaas",
|
mohsh: "mohaas",
|
||||||
"mohbt": "mohaab",
|
mohbt: "mohaab",
|
||||||
"mohab": "moha",
|
mohab: "moha",
|
||||||
"moh2010": "moh",
|
moh2010: "moh",
|
||||||
"mohwf": "mohw",
|
mohwf: "mohw",
|
||||||
"minecraftbe": "mbe",
|
minecraftbe: "mbe",
|
||||||
"mtavc": "gtavcmta",
|
mtavc: "gtavcmta",
|
||||||
"mtasa": "gtasamta",
|
mtasa: "gtasamta",
|
||||||
"ns": "naturalselection",
|
ns: "naturalselection",
|
||||||
"ns2": "naturalselection2",
|
ns2: "naturalselection2",
|
||||||
"nwn": "neverwinternights",
|
nwn: "neverwinternights",
|
||||||
"nwn2": "neverwinternights2",
|
nwn2: "neverwinternights2",
|
||||||
"nolf": "tonolf",
|
nolf: "tonolf",
|
||||||
"nolf2": "nolf2asihw",
|
nolf2: "nolf2asihw",
|
||||||
"pvkii": "pvak2",
|
pvkii: "pvak2",
|
||||||
"ps": "postscriptum",
|
ps: "postscriptum",
|
||||||
"primalcarnage": "pce",
|
primalcarnage: "pce",
|
||||||
"pc": "projectcars",
|
pc: "projectcars",
|
||||||
"pc2": "projectcars2",
|
pc2: "projectcars2",
|
||||||
"prbf2": "prb2",
|
prbf2: "prb2",
|
||||||
"przomboid": "projectzomboid",
|
przomboid: "projectzomboid",
|
||||||
"quake1": "quake",
|
quake1: "quake",
|
||||||
"quake3": "q3a",
|
quake3: "q3a",
|
||||||
"ragdollkungfu": "rdkf",
|
ragdollkungfu: "rdkf",
|
||||||
"r6": "rainbowsix",
|
r6: "rainbowsix",
|
||||||
"r6roguespear": "rs2rs",
|
r6roguespear: "rs2rs",
|
||||||
"r6ravenshield": "rs3rs",
|
r6ravenshield: "rs3rs",
|
||||||
"redorchestraost": "roo4145",
|
redorchestraost: "roo4145",
|
||||||
"redm": "rdr2r",
|
redm: "rdr2r",
|
||||||
"riseofnations": "ron",
|
riseofnations: "ron",
|
||||||
"rs2": "rs2v",
|
rs2: "rs2v",
|
||||||
"samp": "gtasam",
|
samp: "gtasam",
|
||||||
"saomp": "gtasao",
|
saomp: "gtasao",
|
||||||
"savage2": "s2ats",
|
savage2: "s2ats",
|
||||||
"ss": "serioussam",
|
ss: "serioussam",
|
||||||
"ss2": "serioussam2",
|
ss2: "serioussam2",
|
||||||
"ship": "theship",
|
ship: "theship",
|
||||||
"sinep": "sinepisodes",
|
sinep: "sinepisodes",
|
||||||
"sonsoftheforest": "sotf",
|
sonsoftheforest: "sotf",
|
||||||
"swbf": "swb",
|
swbf: "swb",
|
||||||
"swbf2": "swb2",
|
swbf2: "swb2",
|
||||||
"swjk": "swjkja",
|
swjk: "swjkja",
|
||||||
"swjk2": "swjk2jo",
|
swjk2: "swjk2jo",
|
||||||
"takeonhelicopters": "toh",
|
takeonhelicopters: "toh",
|
||||||
"tf2": "teamfortress2",
|
tf2: "teamfortress2",
|
||||||
"terraria": "terrariatshock",
|
terraria: "terrariatshock",
|
||||||
"tribes1": "t1s",
|
tribes1: "t1s",
|
||||||
"ut": "unrealtournament",
|
ut: "unrealtournament",
|
||||||
"ut2003": "unrealtournament2003",
|
ut2003: "unrealtournament2003",
|
||||||
"ut2004": "unrealtournament2004",
|
ut2004: "unrealtournament2004",
|
||||||
"ut3": "unrealtournament3",
|
ut3: "unrealtournament3",
|
||||||
"v8supercar": "v8sc",
|
v8supercar: "v8sc",
|
||||||
"vcmp": "vcm",
|
vcmp: "vcm",
|
||||||
"vs": "vampireslayer",
|
vs: "vampireslayer",
|
||||||
"wheeloftime": "wot",
|
wheeloftime: "wot",
|
||||||
"wolfenstein2009": "wolfenstein",
|
wolfenstein2009: "wolfenstein",
|
||||||
"wolfensteinet": "wet",
|
wolfensteinet: "wet",
|
||||||
"wurm": "wurmunlimited",
|
wurm: "wurmunlimited",
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -146,10 +146,7 @@ const gameDig4to5IdMap = {
|
|||||||
exports.up = async function (knex) {
|
exports.up = async function (knex) {
|
||||||
await knex.transaction(async (trx) => {
|
await knex.transaction(async (trx) => {
|
||||||
// Get all monitors that use the gamedig type
|
// Get all monitors that use the gamedig type
|
||||||
const monitors = await trx("monitor")
|
const monitors = await trx("monitor").select("id", "game").where("type", "gamedig").whereNotNull("game");
|
||||||
.select("id", "game")
|
|
||||||
.where("type", "gamedig")
|
|
||||||
.whereNotNull("game");
|
|
||||||
|
|
||||||
// Update each monitor with the new game ID if it needs migration
|
// Update each monitor with the new game ID if it needs migration
|
||||||
for (const monitor of monitors) {
|
for (const monitor of monitors) {
|
||||||
@ -157,9 +154,7 @@ exports.up = async function (knex) {
|
|||||||
const newGameId = gameDig4to5IdMap[oldGameId];
|
const newGameId = gameDig4to5IdMap[oldGameId];
|
||||||
|
|
||||||
if (newGameId) {
|
if (newGameId) {
|
||||||
await trx("monitor")
|
await trx("monitor").where("id", monitor.id).update({ game: newGameId });
|
||||||
.where("id", monitor.id)
|
|
||||||
.update({ game: newGameId });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -172,16 +167,11 @@ exports.up = async function (knex) {
|
|||||||
*/
|
*/
|
||||||
exports.down = async function (knex) {
|
exports.down = async function (knex) {
|
||||||
// Create reverse mapping from the same LUT
|
// Create reverse mapping from the same LUT
|
||||||
const gameDig5to4IdMap = Object.fromEntries(
|
const gameDig5to4IdMap = Object.fromEntries(Object.entries(gameDig4to5IdMap).map(([v4, v5]) => [v5, v4]));
|
||||||
Object.entries(gameDig4to5IdMap).map(([ v4, v5 ]) => [ v5, v4 ])
|
|
||||||
);
|
|
||||||
|
|
||||||
await knex.transaction(async (trx) => {
|
await knex.transaction(async (trx) => {
|
||||||
// Get all monitors that use the gamedig type
|
// Get all monitors that use the gamedig type
|
||||||
const monitors = await trx("monitor")
|
const monitors = await trx("monitor").select("id", "game").where("type", "gamedig").whereNotNull("game");
|
||||||
.select("id", "game")
|
|
||||||
.where("type", "gamedig")
|
|
||||||
.whereNotNull("game");
|
|
||||||
|
|
||||||
// Revert each monitor back to the old game ID if it was migrated
|
// Revert each monitor back to the old game ID if it was migrated
|
||||||
for (const monitor of monitors) {
|
for (const monitor of monitors) {
|
||||||
@ -189,9 +179,7 @@ exports.down = async function (knex) {
|
|||||||
const oldGameId = gameDig5to4IdMap[newGameId];
|
const oldGameId = gameDig5to4IdMap[newGameId];
|
||||||
|
|
||||||
if (oldGameId) {
|
if (oldGameId) {
|
||||||
await trx("monitor")
|
await trx("monitor").where("id", monitor.id).update({ game: oldGameId });
|
||||||
.where("id", monitor.id)
|
|
||||||
.update({ game: oldGameId });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -11,13 +11,9 @@ https://knexjs.org/guide/migrations.html#knexfile-in-other-languages
|
|||||||
## Template
|
## Template
|
||||||
|
|
||||||
```js
|
```js
|
||||||
exports.up = function(knex) {
|
exports.up = function (knex) {};
|
||||||
|
|
||||||
};
|
exports.down = function (knex) {};
|
||||||
|
|
||||||
exports.down = function(knex) {
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// exports.config = { transaction: false };
|
// exports.config = { transaction: false };
|
||||||
```
|
```
|
||||||
@ -27,29 +23,28 @@ exports.down = function(knex) {
|
|||||||
Filename: 2023-06-30-1348-create-user-and-product.js
|
Filename: 2023-06-30-1348-create-user-and-product.js
|
||||||
|
|
||||||
```js
|
```js
|
||||||
exports.up = function(knex) {
|
exports.up = function (knex) {
|
||||||
return knex.schema
|
return knex.schema
|
||||||
.createTable('user', function (table) {
|
.createTable("user", function (table) {
|
||||||
table.increments('id');
|
table.increments("id");
|
||||||
table.string('first_name', 255).notNullable();
|
table.string("first_name", 255).notNullable();
|
||||||
table.string('last_name', 255).notNullable();
|
table.string("last_name", 255).notNullable();
|
||||||
})
|
})
|
||||||
.createTable('product', function (table) {
|
.createTable("product", function (table) {
|
||||||
table.increments('id');
|
table.increments("id");
|
||||||
table.decimal('price').notNullable();
|
table.decimal("price").notNullable();
|
||||||
table.string('name', 1000).notNullable();
|
table.string("name", 1000).notNullable();
|
||||||
}).then(() => {
|
})
|
||||||
knex("products").insert([
|
.then(() => {
|
||||||
{ price: 10, name: "Apple" },
|
knex("products").insert([
|
||||||
{ price: 20, name: "Orange" },
|
{ price: 10, name: "Apple" },
|
||||||
]);
|
{ price: 20, name: "Orange" },
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.down = function(knex) {
|
exports.down = function (knex) {
|
||||||
return knex.schema
|
return knex.schema.dropTable("product").dropTable("user");
|
||||||
.dropTable("product")
|
|
||||||
.dropTable("user");
|
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
version: '3.8'
|
version: "3.8"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
uptime-kuma:
|
uptime-kuma:
|
||||||
@ -9,6 +9,5 @@ services:
|
|||||||
- ../server:/app/server
|
- ../server:/app/server
|
||||||
- ../db:/app/db
|
- ../db:/app/db
|
||||||
ports:
|
ports:
|
||||||
- "3001:3001" # <Host Port>:<Container Port>
|
- "3001:3001" # <Host Port>:<Container Port>
|
||||||
- "3307:3306"
|
- "3307:3306"
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
apps: [{
|
apps: [
|
||||||
name: "uptime-kuma",
|
{
|
||||||
script: "./server/server.js",
|
name: "uptime-kuma",
|
||||||
}]
|
script: "./server/server.js",
|
||||||
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|||||||
@ -16,27 +16,26 @@ if (!version || !version.includes("-beta.")) {
|
|||||||
|
|
||||||
const exists = tagExists(version);
|
const exists = tagExists(version);
|
||||||
|
|
||||||
if (! exists) {
|
if (!exists) {
|
||||||
// Process package.json
|
// Process package.json
|
||||||
pkg.version = version;
|
pkg.version = version;
|
||||||
fs.writeFileSync("package.json", JSON.stringify(pkg, null, 4) + "\n");
|
fs.writeFileSync("package.json", JSON.stringify(pkg, null, 4) + "\n");
|
||||||
|
|
||||||
// Also update package-lock.json
|
// Also update package-lock.json
|
||||||
const npm = /^win/.test(process.platform) ? "npm.cmd" : "npm";
|
const npm = /^win/.test(process.platform) ? "npm.cmd" : "npm";
|
||||||
const resultVersion = childProcess.spawnSync(npm, [ "--no-git-tag-version", "version", version ], { shell: true });
|
const resultVersion = childProcess.spawnSync(npm, ["--no-git-tag-version", "version", version], { shell: true });
|
||||||
if (resultVersion.error) {
|
if (resultVersion.error) {
|
||||||
console.error(resultVersion.error);
|
console.error(resultVersion.error);
|
||||||
console.error("error npm version!");
|
console.error("error npm version!");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
const resultInstall = childProcess.spawnSync(npm, [ "install" ], { shell: true });
|
const resultInstall = childProcess.spawnSync(npm, ["install"], { shell: true });
|
||||||
if (resultInstall.error) {
|
if (resultInstall.error) {
|
||||||
console.error(resultInstall.error);
|
console.error(resultInstall.error);
|
||||||
console.error("error update package-lock!");
|
console.error("error update package-lock!");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
commit(version);
|
commit(version);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
console.log("version tag exists, please delete the tag or use another tag");
|
console.log("version tag exists, please delete the tag or use another tag");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
@ -51,7 +50,7 @@ if (! exists) {
|
|||||||
function commit(version) {
|
function commit(version) {
|
||||||
let msg = "Update to " + version;
|
let msg = "Update to " + version;
|
||||||
|
|
||||||
let res = childProcess.spawnSync("git", [ "commit", "-m", msg, "-a" ]);
|
let res = childProcess.spawnSync("git", ["commit", "-m", msg, "-a"]);
|
||||||
let stdout = res.stdout.toString().trim();
|
let stdout = res.stdout.toString().trim();
|
||||||
console.log(stdout);
|
console.log(stdout);
|
||||||
|
|
||||||
@ -59,7 +58,7 @@ function commit(version) {
|
|||||||
throw new Error("commit error");
|
throw new Error("commit error");
|
||||||
}
|
}
|
||||||
|
|
||||||
res = childProcess.spawnSync("git", [ "push", "origin", "master" ]);
|
res = childProcess.spawnSync("git", ["push", "origin", "master"]);
|
||||||
console.log(res.stdout.toString().trim());
|
console.log(res.stdout.toString().trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,11 +69,11 @@ function commit(version) {
|
|||||||
* @throws Version is not valid
|
* @throws Version is not valid
|
||||||
*/
|
*/
|
||||||
function tagExists(version) {
|
function tagExists(version) {
|
||||||
if (! version) {
|
if (!version) {
|
||||||
throw new Error("invalid version");
|
throw new Error("invalid version");
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = childProcess.spawnSync("git", [ "tag", "-l", version ]);
|
let res = childProcess.spawnSync("git", ["tag", "-l", version]);
|
||||||
|
|
||||||
return res.stdout.toString().trim() === version;
|
return res.stdout.toString().trim() === version;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,9 @@ if (platform === "linux/arm/v7") {
|
|||||||
console.log("Already built in the host, skip.");
|
console.log("Already built in the host, skip.");
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
} else {
|
} else {
|
||||||
console.log("prebuilt not found, it will be slow! You should execute `npm run build-healthcheck-armv7` before build.");
|
console.log(
|
||||||
|
"prebuilt not found, it will be slow! You should execute `npm run build-healthcheck-armv7` before build."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (fs.existsSync("./extra/healthcheck-armv7")) {
|
if (fs.existsSync("./extra/healthcheck-armv7")) {
|
||||||
@ -24,4 +26,3 @@ if (platform === "linux/arm/v7") {
|
|||||||
|
|
||||||
const output = childProcess.execSync("go build -x -o ./extra/healthcheck ./extra/healthcheck.go").toString("utf8");
|
const output = childProcess.execSync("go build -x -o ./extra/healthcheck ./extra/healthcheck.go").toString("utf8");
|
||||||
console.log(output);
|
console.log(output);
|
||||||
|
|
||||||
|
|||||||
@ -18,7 +18,7 @@ const github = require("@actions/github");
|
|||||||
await client.issues.listLabelsOnIssue({
|
await client.issues.listLabelsOnIssue({
|
||||||
owner: issue.owner,
|
owner: issue.owner,
|
||||||
repo: issue.repo,
|
repo: issue.repo,
|
||||||
issue_number: issue.number
|
issue_number: issue.number,
|
||||||
})
|
})
|
||||||
).data.map(({ name }) => name);
|
).data.map(({ name }) => name);
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ const github = require("@actions/github");
|
|||||||
owner: issue.owner,
|
owner: issue.owner,
|
||||||
repo: issue.repo,
|
repo: issue.repo,
|
||||||
issue_number: issue.number,
|
issue_number: issue.number,
|
||||||
labels: [ "invalid-format" ]
|
labels: ["invalid-format"],
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add the issue closing comment
|
// Add the issue closing comment
|
||||||
@ -37,7 +37,7 @@ const github = require("@actions/github");
|
|||||||
owner: issue.owner,
|
owner: issue.owner,
|
||||||
repo: issue.repo,
|
repo: issue.repo,
|
||||||
issue_number: issue.number,
|
issue_number: issue.number,
|
||||||
body: `@${username}: Hello! :wave:\n\nThis issue is being automatically closed because it does not follow the issue template. Please **DO NOT open blank issues and use our [issue-templates](https://github.com/louislam/uptime-kuma/issues/new/choose) instead**.\nBlank Issues do not contain the context necessary for a good discussions.`
|
body: `@${username}: Hello! :wave:\n\nThis issue is being automatically closed because it does not follow the issue template. Please **DO NOT open blank issues and use our [issue-templates](https://github.com/louislam/uptime-kuma/issues/new/choose) instead**.\nBlank Issues do not contain the context necessary for a good discussions.`,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Close the issue
|
// Close the issue
|
||||||
@ -45,7 +45,7 @@ const github = require("@actions/github");
|
|||||||
owner: issue.owner,
|
owner: issue.owner,
|
||||||
repo: issue.repo,
|
repo: issue.repo,
|
||||||
issue_number: issue.number,
|
issue_number: issue.number,
|
||||||
state: "closed"
|
state: "closed",
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
console.log("Pass!");
|
console.log("Pass!");
|
||||||
@ -53,5 +53,4 @@ const github = require("@actions/github");
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
require("dotenv").config();
|
require("dotenv").config();
|
||||||
const { NodeSSH } = require("node-ssh");
|
const { NodeSSH } = require("node-ssh");
|
||||||
const readline = require("readline");
|
const readline = require("readline");
|
||||||
const rl = readline.createInterface({ input: process.stdin,
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
||||||
output: process.stdout });
|
|
||||||
const prompt = (query) => new Promise((resolve) => rl.question(query, resolve));
|
const prompt = (query) => new Promise((resolve) => rl.question(query, resolve));
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
@ -13,7 +12,7 @@ const prompt = (query) => new Promise((resolve) => rl.question(query, resolve));
|
|||||||
host: process.env.UPTIME_KUMA_DEMO_HOST,
|
host: process.env.UPTIME_KUMA_DEMO_HOST,
|
||||||
port: process.env.UPTIME_KUMA_DEMO_PORT,
|
port: process.env.UPTIME_KUMA_DEMO_PORT,
|
||||||
username: process.env.UPTIME_KUMA_DEMO_USERNAME,
|
username: process.env.UPTIME_KUMA_DEMO_USERNAME,
|
||||||
privateKeyPath: process.env.UPTIME_KUMA_DEMO_PRIVATE_KEY_PATH
|
privateKeyPath: process.env.UPTIME_KUMA_DEMO_PRIVATE_KEY_PATH,
|
||||||
});
|
});
|
||||||
|
|
||||||
let cwd = process.env.UPTIME_KUMA_DEMO_CWD;
|
let cwd = process.env.UPTIME_KUMA_DEMO_CWD;
|
||||||
@ -48,7 +47,6 @@ const prompt = (query) => new Promise((resolve) => rl.question(query, resolve));
|
|||||||
cwd,
|
cwd,
|
||||||
});
|
});
|
||||||
console.log(result.stdout + result.stderr);*/
|
console.log(result.stdout + result.stderr);*/
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@ -26,7 +26,6 @@ function download(url) {
|
|||||||
console.log("Extracting dist...");
|
console.log("Extracting dist...");
|
||||||
|
|
||||||
if (fs.existsSync("./dist")) {
|
if (fs.existsSync("./dist")) {
|
||||||
|
|
||||||
if (fs.existsSync("./dist-backup")) {
|
if (fs.existsSync("./dist-backup")) {
|
||||||
fs.rmSync("./dist-backup", {
|
fs.rmSync("./dist-backup", {
|
||||||
recursive: true,
|
recursive: true,
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "kuma-pr",
|
"name": "kuma-pr",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"bin": {
|
"bin": {
|
||||||
"kuma-pr": "./index.mjs"
|
"kuma-pr": "./index.mjs"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node index.js"
|
"start": "node index.js"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
// Supports: Deno, Bun, Node.js >= 18 (ts-node)
|
// Supports: Deno, Bun, Node.js >= 18 (ts-node)
|
||||||
const pushURL : string = "https://example.com/api/push/key?status=up&msg=OK&ping=";
|
const pushURL: string = "https://example.com/api/push/key?status=up&msg=OK&ping=";
|
||||||
const interval : number = 60;
|
const interval: number = 60;
|
||||||
|
|
||||||
const push = async () => {
|
const push = async () => {
|
||||||
await fetch(pushURL);
|
await fetch(pushURL);
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"ts-node": "ts-node index.ts",
|
"ts-node": "ts-node index.ts",
|
||||||
"deno": "deno run --allow-net index.ts",
|
"deno": "deno run --allow-net index.ts",
|
||||||
"bun": "bun index.ts"
|
"bun": "bun index.ts"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^20.6.0",
|
"@types/node": "^20.6.0",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
"tslib": "^2.6.2",
|
"tslib": "^2.6.2",
|
||||||
"typescript": "^5.2.2"
|
"typescript": "^5.2.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,7 @@ async function main() {
|
|||||||
const branch = process.argv[2];
|
const branch = process.argv[2];
|
||||||
|
|
||||||
// Use gh to get current branch's pr id
|
// Use gh to get current branch's pr id
|
||||||
let currentBranchPRID = execSync("gh pr view --json number --jq \".number\"").toString().trim();
|
let currentBranchPRID = execSync('gh pr view --json number --jq ".number"').toString().trim();
|
||||||
console.log("Pr ID: ", currentBranchPRID);
|
console.log("Pr ID: ", currentBranchPRID);
|
||||||
|
|
||||||
// Use gh commend to get pr commits
|
// Use gh commend to get pr commits
|
||||||
|
|||||||
@ -8,7 +8,7 @@ const TwoFA = require("../server/2fa");
|
|||||||
const args = require("args-parser")(process.argv);
|
const args = require("args-parser")(process.argv);
|
||||||
const rl = readline.createInterface({
|
const rl = readline.createInterface({
|
||||||
input: process.stdin,
|
input: process.stdin,
|
||||||
output: process.stdout
|
output: process.stdout,
|
||||||
});
|
});
|
||||||
|
|
||||||
const main = async () => {
|
const main = async () => {
|
||||||
@ -19,7 +19,7 @@ const main = async () => {
|
|||||||
// No need to actually reset the password for testing, just make sure no connection problem. It is ok for now.
|
// No need to actually reset the password for testing, just make sure no connection problem. It is ok for now.
|
||||||
if (!process.env.TEST_BACKEND) {
|
if (!process.env.TEST_BACKEND) {
|
||||||
const user = await R.findOne("user");
|
const user = await R.findOne("user");
|
||||||
if (! user) {
|
if (!user) {
|
||||||
throw new Error("user not found, have you installed?");
|
throw new Error("user not found, have you installed?");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,7 +31,6 @@ const main = async () => {
|
|||||||
await TwoFA.disable2FA(user.id);
|
await TwoFA.disable2FA(user.id);
|
||||||
console.log("2FA has been removed successfully.");
|
console.log("2FA has been removed successfully.");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Error: " + e.message);
|
console.error("Error: " + e.message);
|
||||||
|
|||||||
@ -21,4 +21,3 @@ const main = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
main();
|
main();
|
||||||
|
|
||||||
|
|||||||
@ -12,7 +12,7 @@ const args = require("args-parser")(process.argv);
|
|||||||
|
|
||||||
const rl = readline.createInterface({
|
const rl = readline.createInterface({
|
||||||
input: process.stdin,
|
input: process.stdin,
|
||||||
output: process.stdout
|
output: process.stdout,
|
||||||
});
|
});
|
||||||
|
|
||||||
const main = async () => {
|
const main = async () => {
|
||||||
@ -28,7 +28,7 @@ const main = async () => {
|
|||||||
// No need to actually reset the password for testing, just make sure no connection problem. It is ok for now.
|
// No need to actually reset the password for testing, just make sure no connection problem. It is ok for now.
|
||||||
if (!process.env.TEST_BACKEND) {
|
if (!process.env.TEST_BACKEND) {
|
||||||
const user = await R.findOne("user");
|
const user = await R.findOne("user");
|
||||||
if (! user) {
|
if (!user) {
|
||||||
throw new Error("user not found, have you installed?");
|
throw new Error("user not found, have you installed?");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,7 +41,10 @@ const main = async () => {
|
|||||||
// When called with "--new-password" argument for unattended modification (e.g. npm run reset-password -- --new_password=secret)
|
// When called with "--new-password" argument for unattended modification (e.g. npm run reset-password -- --new_password=secret)
|
||||||
if ("new-password" in args) {
|
if ("new-password" in args) {
|
||||||
console.log("Using password from argument");
|
console.log("Using password from argument");
|
||||||
console.warn("\x1b[31m%s\x1b[0m", "Warning: the password might be stored, in plain text, in your shell's history");
|
console.warn(
|
||||||
|
"\x1b[31m%s\x1b[0m",
|
||||||
|
"Warning: the password might be stored, in plain text, in your shell's history"
|
||||||
|
);
|
||||||
password = confirmPassword = args["new-password"] + "";
|
password = confirmPassword = args["new-password"] + "";
|
||||||
if (passwordStrength(password).value === "Too weak") {
|
if (passwordStrength(password).value === "Too weak") {
|
||||||
throw new Error("Password is too weak, please use a stronger password.");
|
throw new Error("Password is too weak, please use a stronger password.");
|
||||||
@ -71,7 +74,6 @@ const main = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log("Password reset successfully.");
|
console.log("Password reset successfully.");
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Error: " + e.message);
|
console.error("Error: " + e.message);
|
||||||
@ -112,19 +114,23 @@ function disconnectAllSocketClients(username, password) {
|
|||||||
timeout: 5000,
|
timeout: 5000,
|
||||||
});
|
});
|
||||||
socket.on("connect", () => {
|
socket.on("connect", () => {
|
||||||
socket.emit("login", {
|
socket.emit(
|
||||||
username,
|
"login",
|
||||||
password,
|
{
|
||||||
}, (res) => {
|
username,
|
||||||
if (res.ok) {
|
password,
|
||||||
console.log("Logged in.");
|
},
|
||||||
socket.emit("disconnectOtherSocketClients");
|
(res) => {
|
||||||
} else {
|
if (res.ok) {
|
||||||
console.warn("Login failed.");
|
console.log("Logged in.");
|
||||||
console.warn("Please restart the server to disconnect all sessions.");
|
socket.emit("disconnectOtherSocketClients");
|
||||||
|
} else {
|
||||||
|
console.warn("Login failed.");
|
||||||
|
console.warn("Please restart the server to disconnect all sessions.");
|
||||||
|
}
|
||||||
|
socket.close();
|
||||||
}
|
}
|
||||||
socket.close();
|
);
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("connect_error", function () {
|
socket.on("connect_error", function () {
|
||||||
|
|||||||
@ -7,7 +7,7 @@ const dns2 = require("dns2");
|
|||||||
const { Packet } = dns2;
|
const { Packet } = dns2;
|
||||||
|
|
||||||
const server = dns2.createServer({
|
const server = dns2.createServer({
|
||||||
udp: true
|
udp: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
server.on("request", (request, send, rinfo) => {
|
server.on("request", (request, send, rinfo) => {
|
||||||
@ -17,14 +17,13 @@ server.on("request", (request, send, rinfo) => {
|
|||||||
const response = Packet.createResponseFromRequest(request);
|
const response = Packet.createResponseFromRequest(request);
|
||||||
|
|
||||||
if (question.name === "existing.com") {
|
if (question.name === "existing.com") {
|
||||||
|
|
||||||
if (question.type === Packet.TYPE.A) {
|
if (question.type === Packet.TYPE.A) {
|
||||||
response.answers.push({
|
response.answers.push({
|
||||||
name: question.name,
|
name: question.name,
|
||||||
type: question.type,
|
type: question.type,
|
||||||
class: question.class,
|
class: question.class,
|
||||||
ttl: 300,
|
ttl: 300,
|
||||||
address: "1.2.3.4"
|
address: "1.2.3.4",
|
||||||
});
|
});
|
||||||
} else if (question.type === Packet.TYPE.AAAA) {
|
} else if (question.type === Packet.TYPE.AAAA) {
|
||||||
response.answers.push({
|
response.answers.push({
|
||||||
@ -49,7 +48,7 @@ server.on("request", (request, send, rinfo) => {
|
|||||||
class: question.class,
|
class: question.class,
|
||||||
ttl: 300,
|
ttl: 300,
|
||||||
exchange: "mx1.existing.com",
|
exchange: "mx1.existing.com",
|
||||||
priority: 5
|
priority: 5,
|
||||||
});
|
});
|
||||||
} else if (question.type === Packet.TYPE.NS) {
|
} else if (question.type === Packet.TYPE.NS) {
|
||||||
response.answers.push({
|
response.answers.push({
|
||||||
@ -103,7 +102,6 @@ server.on("request", (request, send, rinfo) => {
|
|||||||
value: "ca.existing.com",
|
value: "ca.existing.com",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (question.name === "4.3.2.1.in-addr.arpa") {
|
if (question.name === "4.3.2.1.in-addr.arpa") {
|
||||||
@ -132,7 +130,7 @@ server.on("close", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
server.listen({
|
server.listen({
|
||||||
udp: 5300
|
udp: 5300,
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -41,17 +41,19 @@ server1.aedes.on("subscribe", (subscriptions, client) => {
|
|||||||
|
|
||||||
for (let s of subscriptions) {
|
for (let s of subscriptions) {
|
||||||
if (s.topic === "test") {
|
if (s.topic === "test") {
|
||||||
server1.aedes.publish({
|
server1.aedes.publish(
|
||||||
topic: "test",
|
{
|
||||||
payload: Buffer.from("ok"),
|
topic: "test",
|
||||||
}, (error) => {
|
payload: Buffer.from("ok"),
|
||||||
if (error) {
|
},
|
||||||
log.error("mqtt_server", error);
|
(error) => {
|
||||||
|
if (error) {
|
||||||
|
log.error("mqtt_server", error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
server1.start();
|
server1.start();
|
||||||
|
|||||||
@ -10,7 +10,7 @@ let lines = file.split("\n");
|
|||||||
lines = lines.filter((line) => line !== "");
|
lines = lines.filter((line) => line !== "");
|
||||||
|
|
||||||
// Remove duplicates
|
// Remove duplicates
|
||||||
lines = [ ...new Set(lines) ];
|
lines = [...new Set(lines)];
|
||||||
|
|
||||||
// Remove @weblate and @UptimeKumaBot
|
// Remove @weblate and @UptimeKumaBot
|
||||||
lines = lines.filter((line) => line !== "@weblate" && line !== "@UptimeKumaBot" && line !== "@louislam");
|
lines = lines.filter((line) => line !== "@weblate" && line !== "@UptimeKumaBot" && line !== "@louislam");
|
||||||
|
|||||||
@ -54,13 +54,13 @@ async function updateLanguage(langCode, baseLangCode) {
|
|||||||
} else {
|
} else {
|
||||||
console.log("Empty file");
|
console.log("Empty file");
|
||||||
obj = {
|
obj = {
|
||||||
languageName: "<Your Language name in your language (not in English)>"
|
languageName: "<Your Language name in your language (not in English)>",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// En first
|
// En first
|
||||||
for (const key in en) {
|
for (const key in en) {
|
||||||
if (! obj[key]) {
|
if (!obj[key]) {
|
||||||
obj[key] = en[key];
|
obj[key] = en[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -68,15 +68,17 @@ async function updateLanguage(langCode, baseLangCode) {
|
|||||||
if (baseLang !== en) {
|
if (baseLang !== en) {
|
||||||
// Base second
|
// Base second
|
||||||
for (const key in baseLang) {
|
for (const key in baseLang) {
|
||||||
if (! obj[key]) {
|
if (!obj[key]) {
|
||||||
obj[key] = key;
|
obj[key] = key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const code = "export default " + util.inspect(obj, {
|
const code =
|
||||||
depth: null,
|
"export default " +
|
||||||
});
|
util.inspect(obj, {
|
||||||
|
depth: null,
|
||||||
|
});
|
||||||
|
|
||||||
fs.writeFileSync(`../../src/languages/${file}`, code);
|
fs.writeFileSync(`../../src/languages/${file}`, code);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "update-language-files",
|
"name": "update-language-files",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,15 +9,14 @@ const newVersion = process.env.RELEASE_VERSION;
|
|||||||
|
|
||||||
console.log("New Version: " + newVersion);
|
console.log("New Version: " + newVersion);
|
||||||
|
|
||||||
if (! newVersion) {
|
if (!newVersion) {
|
||||||
console.error("invalid version");
|
console.error("invalid version");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const exists = tagExists(newVersion);
|
const exists = tagExists(newVersion);
|
||||||
|
|
||||||
if (! exists) {
|
if (!exists) {
|
||||||
|
|
||||||
// Process package.json
|
// Process package.json
|
||||||
pkg.version = newVersion;
|
pkg.version = newVersion;
|
||||||
|
|
||||||
@ -27,20 +26,19 @@ if (! exists) {
|
|||||||
|
|
||||||
// Also update package-lock.json
|
// Also update package-lock.json
|
||||||
const npm = /^win/.test(process.platform) ? "npm.cmd" : "npm";
|
const npm = /^win/.test(process.platform) ? "npm.cmd" : "npm";
|
||||||
const resultVersion = childProcess.spawnSync(npm, [ "--no-git-tag-version", "version", newVersion ], { shell: true });
|
const resultVersion = childProcess.spawnSync(npm, ["--no-git-tag-version", "version", newVersion], { shell: true });
|
||||||
if (resultVersion.error) {
|
if (resultVersion.error) {
|
||||||
console.error(resultVersion.error);
|
console.error(resultVersion.error);
|
||||||
console.error("error npm version!");
|
console.error("error npm version!");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
const resultInstall = childProcess.spawnSync(npm, [ "install" ], { shell: true });
|
const resultInstall = childProcess.spawnSync(npm, ["install"], { shell: true });
|
||||||
if (resultInstall.error) {
|
if (resultInstall.error) {
|
||||||
console.error(resultInstall.error);
|
console.error(resultInstall.error);
|
||||||
console.error("error update package-lock!");
|
console.error("error update package-lock!");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
commit(newVersion);
|
commit(newVersion);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
console.log("version exists");
|
console.log("version exists");
|
||||||
}
|
}
|
||||||
@ -54,7 +52,7 @@ if (! exists) {
|
|||||||
function commit(version) {
|
function commit(version) {
|
||||||
let msg = "Update to " + version;
|
let msg = "Update to " + version;
|
||||||
|
|
||||||
let res = childProcess.spawnSync("git", [ "commit", "-m", msg, "-a" ]);
|
let res = childProcess.spawnSync("git", ["commit", "-m", msg, "-a"]);
|
||||||
let stdout = res.stdout.toString().trim();
|
let stdout = res.stdout.toString().trim();
|
||||||
console.log(stdout);
|
console.log(stdout);
|
||||||
|
|
||||||
@ -70,11 +68,11 @@ function commit(version) {
|
|||||||
* @throws Version is not valid
|
* @throws Version is not valid
|
||||||
*/
|
*/
|
||||||
function tagExists(version) {
|
function tagExists(version) {
|
||||||
if (! version) {
|
if (!version) {
|
||||||
throw new Error("invalid version");
|
throw new Error("invalid version");
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = childProcess.spawnSync("git", [ "tag", "-l", version ]);
|
let res = childProcess.spawnSync("git", ["tag", "-l", version]);
|
||||||
|
|
||||||
return res.stdout.toString().trim() === version;
|
return res.stdout.toString().trim() === version;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,23 +21,23 @@ function updateWiki(newVersion) {
|
|||||||
|
|
||||||
safeDelete(wikiDir);
|
safeDelete(wikiDir);
|
||||||
|
|
||||||
childProcess.spawnSync("git", [ "clone", "https://github.com/louislam/uptime-kuma.wiki.git", wikiDir ]);
|
childProcess.spawnSync("git", ["clone", "https://github.com/louislam/uptime-kuma.wiki.git", wikiDir]);
|
||||||
let content = fs.readFileSync(howToUpdateFilename).toString();
|
let content = fs.readFileSync(howToUpdateFilename).toString();
|
||||||
|
|
||||||
// Replace the version: https://regex101.com/r/hmj2Bc/1
|
// Replace the version: https://regex101.com/r/hmj2Bc/1
|
||||||
content = content.replace(/(git checkout )([^\s]+)/, `$1${newVersion}`);
|
content = content.replace(/(git checkout )([^\s]+)/, `$1${newVersion}`);
|
||||||
fs.writeFileSync(howToUpdateFilename, content);
|
fs.writeFileSync(howToUpdateFilename, content);
|
||||||
|
|
||||||
childProcess.spawnSync("git", [ "add", "-A" ], {
|
childProcess.spawnSync("git", ["add", "-A"], {
|
||||||
cwd: wikiDir,
|
cwd: wikiDir,
|
||||||
});
|
});
|
||||||
|
|
||||||
childProcess.spawnSync("git", [ "commit", "-m", `Update to ${newVersion}` ], {
|
childProcess.spawnSync("git", ["commit", "-m", `Update to ${newVersion}`], {
|
||||||
cwd: wikiDir,
|
cwd: wikiDir,
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("Pushing to Github");
|
console.log("Pushing to Github");
|
||||||
childProcess.spawnSync("git", [ "push" ], {
|
childProcess.spawnSync("git", ["push"], {
|
||||||
cwd: wikiDir,
|
cwd: wikiDir,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -9,16 +9,16 @@ if (!platform) {
|
|||||||
const supportedPlatforms = [
|
const supportedPlatforms = [
|
||||||
{
|
{
|
||||||
name: "linux/amd64",
|
name: "linux/amd64",
|
||||||
bin: "./build/uptime-kuma-push-amd64"
|
bin: "./build/uptime-kuma-push-amd64",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "linux/arm64",
|
name: "linux/arm64",
|
||||||
bin: "./build/uptime-kuma-push-arm64"
|
bin: "./build/uptime-kuma-push-arm64",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "linux/arm/v7",
|
name: "linux/arm/v7",
|
||||||
bin: "./build/uptime-kuma-push-armv7"
|
bin: "./build/uptime-kuma-push-armv7",
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
let platformObj = null;
|
let platformObj = null;
|
||||||
@ -45,4 +45,3 @@ if (platformObj) {
|
|||||||
console.error("Unsupported platform: " + platform);
|
console.error("Unsupported platform: " + platform);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build-docker": "npm run build-all && docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:push . --push --target release",
|
"build-docker": "npm run build-all && docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:push . --push --target release",
|
||||||
"build-all": "npm run build-win && npm run build-linux-amd64 && npm run build-linux-arm64 && npm run build-linux-armv7 && npm run build-linux-armv6 && npm run build-linux-armv5 && npm run build-linux-riscv64",
|
"build-all": "npm run build-win && npm run build-linux-amd64 && npm run build-linux-arm64 && npm run build-linux-armv7 && npm run build-linux-armv6 && npm run build-linux-armv5 && npm run build-linux-riscv64",
|
||||||
"build-win": "cross-env GOOS=windows GOARCH=amd64 go build -x -o ./build/uptime-kuma-push.exe uptime-kuma-push.go",
|
"build-win": "cross-env GOOS=windows GOARCH=amd64 go build -x -o ./build/uptime-kuma-push.exe uptime-kuma-push.go",
|
||||||
"build-linux-amd64": "cross-env GOOS=linux GOARCH=amd64 go build -x -o ./build/uptime-kuma-push-amd64 uptime-kuma-push.go",
|
"build-linux-amd64": "cross-env GOOS=linux GOARCH=amd64 go build -x -o ./build/uptime-kuma-push-amd64 uptime-kuma-push.go",
|
||||||
"build-linux-arm64": "cross-env GOOS=linux GOARCH=arm64 go build -x -o ./build/uptime-kuma-push-arm64 uptime-kuma-push.go",
|
"build-linux-arm64": "cross-env GOOS=linux GOARCH=arm64 go build -x -o ./build/uptime-kuma-push-arm64 uptime-kuma-push.go",
|
||||||
"build-linux-armv7": "cross-env GOOS=linux GOARCH=arm GOARM=7 go build -x -o ./build/uptime-kuma-push-armv7 uptime-kuma-push.go",
|
"build-linux-armv7": "cross-env GOOS=linux GOARCH=arm GOARM=7 go build -x -o ./build/uptime-kuma-push-armv7 uptime-kuma-push.go",
|
||||||
"build-linux-armv6": "cross-env GOOS=linux GOARCH=arm GOARM=6 go build -x -o ./build/uptime-kuma-push-armv6 uptime-kuma-push.go",
|
"build-linux-armv6": "cross-env GOOS=linux GOARCH=arm GOARM=6 go build -x -o ./build/uptime-kuma-push-armv6 uptime-kuma-push.go",
|
||||||
"build-linux-armv5": "cross-env GOOS=linux GOARCH=arm GOARM=5 go build -x -o ./build/uptime-kuma-push-armv5 uptime-kuma-push.go",
|
"build-linux-armv5": "cross-env GOOS=linux GOARCH=arm GOARM=5 go build -x -o ./build/uptime-kuma-push-armv5 uptime-kuma-push.go",
|
||||||
"build-linux-riscv64": "cross-env GOOS=linux GOARCH=riscv64 go build -x -o ./build/uptime-kuma-push-riscv64 uptime-kuma-push.go"
|
"build-linux-riscv64": "cross-env GOOS=linux GOARCH=riscv64 go build -x -o ./build/uptime-kuma-push-riscv64 uptime-kuma-push.go"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
40062
package-lock.json
generated
40062
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
458
package.json
458
package.json
@ -1,231 +1,231 @@
|
|||||||
{
|
{
|
||||||
"name": "uptime-kuma",
|
"name": "uptime-kuma",
|
||||||
"version": "2.1.0-beta.1",
|
"version": "2.1.0-beta.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/louislam/uptime-kuma.git"
|
"url": "https://github.com/louislam/uptime-kuma.git"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 20.4.0"
|
"node": ">= 20.4.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint:js": "eslint --ext \".js,.vue\" --ignore-path .gitignore .",
|
"lint:js": "eslint --ext \".js,.vue\" --ignore-path .gitignore .",
|
||||||
"lint:js-prod": "npm run lint:js -- --max-warnings 0",
|
"lint:js-prod": "npm run lint:js -- --max-warnings 0",
|
||||||
"lint-fix:js": "eslint --ext \".js,.vue\" --fix --ignore-path .gitignore .",
|
"lint-fix:js": "eslint --ext \".js,.vue\" --fix --ignore-path .gitignore .",
|
||||||
"lint:style": "stylelint \"**/*.{vue,css,scss}\" --ignore-path .gitignore",
|
"lint:style": "stylelint \"**/*.{vue,css,scss}\" --ignore-path .gitignore",
|
||||||
"lint-fix:style": "stylelint \"**/*.{vue,css,scss}\" --fix --ignore-path .gitignore",
|
"lint-fix:style": "stylelint \"**/*.{vue,css,scss}\" --fix --ignore-path .gitignore",
|
||||||
"lint": "npm run lint:js && npm run lint:style",
|
"lint": "npm run lint:js && npm run lint:style",
|
||||||
"fmt": "prettier --write \"**/*.{js,ts,vue,css,scss,json,md,yml,yaml}\" --ignore-path .gitignore",
|
"fmt": "prettier --write \"**/*.{js,ts,vue,css,scss,json,md,yml,yaml}\"",
|
||||||
"lint:prod": "npm run lint:js-prod && npm run lint:style",
|
"lint:prod": "npm run lint:js-prod && npm run lint:style",
|
||||||
"dev": "concurrently -k -r \"wait-on tcp:3000 && npm run start-server-dev \" \"npm run start-frontend-dev\"",
|
"dev": "concurrently -k -r \"wait-on tcp:3000 && npm run start-server-dev \" \"npm run start-frontend-dev\"",
|
||||||
"start-frontend-dev": "cross-env NODE_ENV=development vite --host --config ./config/vite.config.js",
|
"start-frontend-dev": "cross-env NODE_ENV=development vite --host --config ./config/vite.config.js",
|
||||||
"start-frontend-devcontainer": "cross-env NODE_ENV=development DEVCONTAINER=1 vite --host --config ./config/vite.config.js",
|
"start-frontend-devcontainer": "cross-env NODE_ENV=development DEVCONTAINER=1 vite --host --config ./config/vite.config.js",
|
||||||
"start": "npm run start-server",
|
"start": "npm run start-server",
|
||||||
"start-server": "node server/server.js",
|
"start-server": "node server/server.js",
|
||||||
"start-server-dev": "cross-env NODE_ENV=development node server/server.js",
|
"start-server-dev": "cross-env NODE_ENV=development node server/server.js",
|
||||||
"start-server-dev:watch": "cross-env NODE_ENV=development node --watch server/server.js",
|
"start-server-dev:watch": "cross-env NODE_ENV=development node --watch server/server.js",
|
||||||
"build": "vite build --config ./config/vite.config.js",
|
"build": "vite build --config ./config/vite.config.js",
|
||||||
"test": "npm run test-backend && npm run test-e2e",
|
"test": "npm run test-backend && npm run test-e2e",
|
||||||
"test-with-build": "npm run build && npm test",
|
"test-with-build": "npm run build && npm test",
|
||||||
"test-backend": "node test/test-backend.mjs",
|
"test-backend": "node test/test-backend.mjs",
|
||||||
"test-backend-22": "cross-env TEST_BACKEND=1 node --test --test-reporter=spec \"test/backend-test/**/*.js\"",
|
"test-backend-22": "cross-env TEST_BACKEND=1 node --test --test-reporter=spec \"test/backend-test/**/*.js\"",
|
||||||
"test-backend-20": "cross-env TEST_BACKEND=1 node --test --test-reporter=spec test/backend-test",
|
"test-backend-20": "cross-env TEST_BACKEND=1 node --test --test-reporter=spec test/backend-test",
|
||||||
"test-e2e": "playwright test --config ./config/playwright.config.js",
|
"test-e2e": "playwright test --config ./config/playwright.config.js",
|
||||||
"test-e2e-ui": "playwright test --config ./config/playwright.config.js --ui --ui-port=51063",
|
"test-e2e-ui": "playwright test --config ./config/playwright.config.js --ui --ui-port=51063",
|
||||||
"playwright-codegen": "playwright codegen localhost:3000 --save-storage=./private/e2e-auth.json",
|
"playwright-codegen": "playwright codegen localhost:3000 --save-storage=./private/e2e-auth.json",
|
||||||
"playwright-show-report": "playwright show-report ./private/playwright-report",
|
"playwright-show-report": "playwright show-report ./private/playwright-report",
|
||||||
"tsc": "tsc --project ./tsconfig-backend.json",
|
"tsc": "tsc --project ./tsconfig-backend.json",
|
||||||
"vite-preview-dist": "vite preview --host --config ./config/vite.config.js",
|
"vite-preview-dist": "vite preview --host --config ./config/vite.config.js",
|
||||||
"build-docker-base": "docker buildx build -f docker/debian-base.dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:base2 --target base2 . --push",
|
"build-docker-base": "docker buildx build -f docker/debian-base.dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:base2 --target base2 . --push",
|
||||||
"build-docker-base-slim": "docker buildx build -f docker/debian-base.dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:base2-slim --target base2-slim . --push",
|
"build-docker-base-slim": "docker buildx build -f docker/debian-base.dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:base2-slim --target base2-slim . --push",
|
||||||
"build-docker-builder-go": "docker buildx build -f docker/builder-go.dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:builder-go . --push",
|
"build-docker-builder-go": "docker buildx build -f docker/builder-go.dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:builder-go . --push",
|
||||||
"build-docker-nightly-local": "npm run build && docker build -f docker/dockerfile -t louislam/uptime-kuma:nightly2 --target nightly .",
|
"build-docker-nightly-local": "npm run build && docker build -f docker/dockerfile -t louislam/uptime-kuma:nightly2 --target nightly .",
|
||||||
"build-docker-pr-test": "docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64 -t louislam/uptime-kuma:pr-test2 --target pr-test2 . --push",
|
"build-docker-pr-test": "docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64 -t louislam/uptime-kuma:pr-test2 --target pr-test2 . --push",
|
||||||
"upload-artifacts": "node extra/release/upload-artifacts.mjs",
|
"upload-artifacts": "node extra/release/upload-artifacts.mjs",
|
||||||
"upload-artifacts-beta": "node extra/release/upload-artifacts-beta.mjs",
|
"upload-artifacts-beta": "node extra/release/upload-artifacts-beta.mjs",
|
||||||
"setup": "git checkout 2.0.2 && npm ci --omit dev --no-audit && npm run download-dist",
|
"setup": "git checkout 2.0.2 && npm ci --omit dev --no-audit && npm run download-dist",
|
||||||
"download-dist": "node extra/download-dist.js",
|
"download-dist": "node extra/download-dist.js",
|
||||||
"mark-as-nightly": "node extra/mark-as-nightly.js",
|
"mark-as-nightly": "node extra/mark-as-nightly.js",
|
||||||
"reset-password": "node extra/reset-password.js",
|
"reset-password": "node extra/reset-password.js",
|
||||||
"remove-2fa": "node extra/remove-2fa.js",
|
"remove-2fa": "node extra/remove-2fa.js",
|
||||||
"simple-dns-server": "node extra/simple-dns-server.js",
|
"simple-dns-server": "node extra/simple-dns-server.js",
|
||||||
"simple-mqtt-server": "node extra/simple-mqtt-server.js",
|
"simple-mqtt-server": "node extra/simple-mqtt-server.js",
|
||||||
"simple-mongo": "docker run --rm -p 27017:27017 mongo",
|
"simple-mongo": "docker run --rm -p 27017:27017 mongo",
|
||||||
"simple-postgres": "docker run --rm -p 5432:5432 -e POSTGRES_PASSWORD=postgres postgres",
|
"simple-postgres": "docker run --rm -p 5432:5432 -e POSTGRES_PASSWORD=postgres postgres",
|
||||||
"simple-mariadb": "docker run --rm -p 3306:3306 -e MYSQL_ROOT_PASSWORD=mariadb# mariadb",
|
"simple-mariadb": "docker run --rm -p 3306:3306 -e MYSQL_ROOT_PASSWORD=mariadb# mariadb",
|
||||||
"update-language-files": "cd extra/update-language-files && node index.js && cross-env-shell eslint ../../src/languages/$npm_config_language.js --fix",
|
"update-language-files": "cd extra/update-language-files && node index.js && cross-env-shell eslint ../../src/languages/$npm_config_language.js --fix",
|
||||||
"release-final": "node ./extra/release/final.mjs",
|
"release-final": "node ./extra/release/final.mjs",
|
||||||
"release-beta": "node ./extra/release/beta.mjs",
|
"release-beta": "node ./extra/release/beta.mjs",
|
||||||
"release-nightly": "node ./extra/release/nightly.mjs",
|
"release-nightly": "node ./extra/release/nightly.mjs",
|
||||||
"git-remove-tag": "git tag -d",
|
"git-remove-tag": "git tag -d",
|
||||||
"build-dist-and-restart": "npm run build && npm run start-server-dev",
|
"build-dist-and-restart": "npm run build && npm run start-server-dev",
|
||||||
"start-pr-test": "node extra/checkout-pr.mjs && npm install && npm run dev",
|
"start-pr-test": "node extra/checkout-pr.mjs && npm install && npm run dev",
|
||||||
"build-healthcheck-armv7": "cross-env GOOS=linux GOARCH=arm GOARM=7 go build -x -o ./extra/healthcheck-armv7 ./extra/healthcheck.go",
|
"build-healthcheck-armv7": "cross-env GOOS=linux GOARCH=arm GOARM=7 go build -x -o ./extra/healthcheck-armv7 ./extra/healthcheck.go",
|
||||||
"deploy-demo-server": "node extra/deploy-demo-server.js",
|
"deploy-demo-server": "node extra/deploy-demo-server.js",
|
||||||
"sort-contributors": "node extra/sort-contributors.js",
|
"sort-contributors": "node extra/sort-contributors.js",
|
||||||
"quick-run-nightly": "docker run --rm --env NODE_ENV=development -p 3001:3001 louislam/uptime-kuma:nightly2",
|
"quick-run-nightly": "docker run --rm --env NODE_ENV=development -p 3001:3001 louislam/uptime-kuma:nightly2",
|
||||||
"start-dev-container": "cd docker && docker-compose -f docker-compose-dev.yml up --force-recreate",
|
"start-dev-container": "cd docker && docker-compose -f docker-compose-dev.yml up --force-recreate",
|
||||||
"rebase-pr-to-1.23.X": "node extra/rebase-pr.js 1.23.X",
|
"rebase-pr-to-1.23.X": "node extra/rebase-pr.js 1.23.X",
|
||||||
"reset-migrate-aggregate-table-state": "node extra/reset-migrate-aggregate-table-state.js",
|
"reset-migrate-aggregate-table-state": "node extra/reset-migrate-aggregate-table-state.js",
|
||||||
"generate-changelog": "node ./extra/generate-changelog.mjs"
|
"generate-changelog": "node ./extra/generate-changelog.mjs"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@grpc/grpc-js": "~1.8.22",
|
"@grpc/grpc-js": "~1.8.22",
|
||||||
"@louislam/ping": "~0.4.4-mod.1",
|
"@louislam/ping": "~0.4.4-mod.1",
|
||||||
"@louislam/sqlite3": "15.1.6",
|
"@louislam/sqlite3": "15.1.6",
|
||||||
"@vvo/tzdb": "^6.125.0",
|
"@vvo/tzdb": "^6.125.0",
|
||||||
"args-parser": "~1.3.0",
|
"args-parser": "~1.3.0",
|
||||||
"axios": "~0.30.0",
|
"axios": "~0.30.0",
|
||||||
"badge-maker": "~3.3.1",
|
"badge-maker": "~3.3.1",
|
||||||
"bcryptjs": "~2.4.3",
|
"bcryptjs": "~2.4.3",
|
||||||
"chardet": "~1.4.0",
|
"chardet": "~1.4.0",
|
||||||
"check-password-strength": "^2.0.5",
|
"check-password-strength": "^2.0.5",
|
||||||
"cheerio": "~1.0.0-rc.12",
|
"cheerio": "~1.0.0-rc.12",
|
||||||
"chroma-js": "~2.4.2",
|
"chroma-js": "~2.4.2",
|
||||||
"command-exists": "~1.2.9",
|
"command-exists": "~1.2.9",
|
||||||
"compare-versions": "~3.6.0",
|
"compare-versions": "~3.6.0",
|
||||||
"compression": "~1.8.1",
|
"compression": "~1.8.1",
|
||||||
"country-flag-emoji-polyfill": "^0.1.8",
|
"country-flag-emoji-polyfill": "^0.1.8",
|
||||||
"croner": "~8.1.0",
|
"croner": "~8.1.0",
|
||||||
"dayjs": "~1.11.5",
|
"dayjs": "~1.11.5",
|
||||||
"dev-null": "^0.1.1",
|
"dev-null": "^0.1.1",
|
||||||
"dotenv": "~16.0.3",
|
"dotenv": "~16.0.3",
|
||||||
"express": "~4.21.0",
|
"express": "~4.21.0",
|
||||||
"express-basic-auth": "~1.2.1",
|
"express-basic-auth": "~1.2.1",
|
||||||
"express-static-gzip": "~2.1.7",
|
"express-static-gzip": "~2.1.7",
|
||||||
"feed": "^4.2.2",
|
"feed": "^4.2.2",
|
||||||
"form-data": "~4.0.0",
|
"form-data": "~4.0.0",
|
||||||
"gamedig": "^5.0.1",
|
"gamedig": "^5.0.1",
|
||||||
"html-escaper": "^3.0.3",
|
"html-escaper": "^3.0.3",
|
||||||
"http-cookie-agent": "~5.0.4",
|
"http-cookie-agent": "~5.0.4",
|
||||||
"http-graceful-shutdown": "~3.1.7",
|
"http-graceful-shutdown": "~3.1.7",
|
||||||
"http-proxy-agent": "~7.0.2",
|
"http-proxy-agent": "~7.0.2",
|
||||||
"https-proxy-agent": "~7.0.6",
|
"https-proxy-agent": "~7.0.6",
|
||||||
"iconv-lite": "~0.6.3",
|
"iconv-lite": "~0.6.3",
|
||||||
"is-url": "^1.2.4",
|
"is-url": "^1.2.4",
|
||||||
"isomorphic-ws": "^5.0.0",
|
"isomorphic-ws": "^5.0.0",
|
||||||
"jsesc": "~3.0.2",
|
"jsesc": "~3.0.2",
|
||||||
"jsonata": "^2.0.3",
|
"jsonata": "^2.0.3",
|
||||||
"jsonwebtoken": "~9.0.0",
|
"jsonwebtoken": "~9.0.0",
|
||||||
"jwt-decode": "~3.1.2",
|
"jwt-decode": "~3.1.2",
|
||||||
"kafkajs": "^2.2.4",
|
"kafkajs": "^2.2.4",
|
||||||
"knex": "~3.1.0",
|
"knex": "~3.1.0",
|
||||||
"limiter": "~2.1.0",
|
"limiter": "~2.1.0",
|
||||||
"liquidjs": "^10.7.0",
|
"liquidjs": "^10.7.0",
|
||||||
"marked": "^14.0.0",
|
"marked": "^14.0.0",
|
||||||
"mitt": "~3.0.1",
|
"mitt": "~3.0.1",
|
||||||
"mongodb": "~4.17.1",
|
"mongodb": "~4.17.1",
|
||||||
"mqtt": "~4.3.7",
|
"mqtt": "~4.3.7",
|
||||||
"mssql": "~12.0.0",
|
"mssql": "~12.0.0",
|
||||||
"mysql2": "~3.11.3",
|
"mysql2": "~3.11.3",
|
||||||
"nanoid": "~3.3.4",
|
"nanoid": "~3.3.4",
|
||||||
"net-snmp": "^3.11.2",
|
"net-snmp": "^3.11.2",
|
||||||
"node-cloudflared-tunnel": "~1.0.9",
|
"node-cloudflared-tunnel": "~1.0.9",
|
||||||
"node-fetch-cache": "^5.1.0",
|
"node-fetch-cache": "^5.1.0",
|
||||||
"node-radius-utils": "~1.2.0",
|
"node-radius-utils": "~1.2.0",
|
||||||
"nodemailer": "~7.0.12",
|
"nodemailer": "~7.0.12",
|
||||||
"nostr-tools": "^2.10.4",
|
"nostr-tools": "^2.10.4",
|
||||||
"notp": "~2.0.3",
|
"notp": "~2.0.3",
|
||||||
"openid-client": "^5.4.2",
|
"openid-client": "^5.4.2",
|
||||||
"password-hash": "~1.2.2",
|
"password-hash": "~1.2.2",
|
||||||
"pg": "~8.11.3",
|
"pg": "~8.11.3",
|
||||||
"pg-connection-string": "~2.6.2",
|
"pg-connection-string": "~2.6.2",
|
||||||
"playwright-core": "~1.39.0",
|
"playwright-core": "~1.39.0",
|
||||||
"prom-client": "~13.2.0",
|
"prom-client": "~13.2.0",
|
||||||
"prometheus-api-metrics": "~3.2.1",
|
"prometheus-api-metrics": "~3.2.1",
|
||||||
"promisify-child-process": "~4.1.2",
|
"promisify-child-process": "~4.1.2",
|
||||||
"protobufjs": "~7.2.4",
|
"protobufjs": "~7.2.4",
|
||||||
"qs": "~6.14.1",
|
"qs": "~6.14.1",
|
||||||
"radius": "~1.1.4",
|
"radius": "~1.1.4",
|
||||||
"redbean-node": "~0.3.0",
|
"redbean-node": "~0.3.0",
|
||||||
"redis": "~5.9.0",
|
"redis": "~5.9.0",
|
||||||
"semver": "~7.5.4",
|
"semver": "~7.5.4",
|
||||||
"socket.io": "~4.8.0",
|
"socket.io": "~4.8.0",
|
||||||
"socket.io-client": "~4.8.0",
|
"socket.io-client": "~4.8.0",
|
||||||
"socks-proxy-agent": "~8.0.5",
|
"socks-proxy-agent": "~8.0.5",
|
||||||
"sqlstring": "~2.3.3",
|
"sqlstring": "~2.3.3",
|
||||||
"tar": "~6.2.1",
|
"tar": "~6.2.1",
|
||||||
"tcp-ping": "~0.1.1",
|
"tcp-ping": "~0.1.1",
|
||||||
"thirty-two": "~1.0.2",
|
"thirty-two": "~1.0.2",
|
||||||
"tldts": "^7.0.19",
|
"tldts": "^7.0.19",
|
||||||
"tough-cookie": "~4.1.3",
|
"tough-cookie": "~4.1.3",
|
||||||
"validator": "^13.15.26",
|
"validator": "^13.15.26",
|
||||||
"web-push": "^3.6.7",
|
"web-push": "^3.6.7",
|
||||||
"ws": "^8.13.0"
|
"ws": "^8.13.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@actions/github": "~6.0.0",
|
"@actions/github": "~6.0.0",
|
||||||
"@fortawesome/fontawesome-svg-core": "~1.2.36",
|
"@fortawesome/fontawesome-svg-core": "~1.2.36",
|
||||||
"@fortawesome/free-regular-svg-icons": "~5.15.4",
|
"@fortawesome/free-regular-svg-icons": "~5.15.4",
|
||||||
"@fortawesome/free-solid-svg-icons": "~5.15.4",
|
"@fortawesome/free-solid-svg-icons": "~5.15.4",
|
||||||
"@fortawesome/vue-fontawesome": "~3.0.0-5",
|
"@fortawesome/vue-fontawesome": "~3.0.0-5",
|
||||||
"@playwright/test": "~1.39.0",
|
"@playwright/test": "~1.39.0",
|
||||||
"@popperjs/core": "~2.10.2",
|
"@popperjs/core": "~2.10.2",
|
||||||
"@testcontainers/hivemq": "^10.13.1",
|
"@testcontainers/hivemq": "^10.13.1",
|
||||||
"@testcontainers/mariadb": "^10.13.0",
|
"@testcontainers/mariadb": "^10.13.0",
|
||||||
"@testcontainers/mssqlserver": "^10.28.0",
|
"@testcontainers/mssqlserver": "^10.28.0",
|
||||||
"@testcontainers/mysql": "^11.11.0",
|
"@testcontainers/mysql": "^11.11.0",
|
||||||
"@testcontainers/postgresql": "^11.9.0",
|
"@testcontainers/postgresql": "^11.9.0",
|
||||||
"@testcontainers/rabbitmq": "^10.13.2",
|
"@testcontainers/rabbitmq": "^10.13.2",
|
||||||
"@types/bootstrap": "~5.1.9",
|
"@types/bootstrap": "~5.1.9",
|
||||||
"@types/node": "^20.8.6",
|
"@types/node": "^20.8.6",
|
||||||
"@types/web-push": "^3.6.4",
|
"@types/web-push": "^3.6.4",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.7.5",
|
"@typescript-eslint/eslint-plugin": "^6.7.5",
|
||||||
"@typescript-eslint/parser": "^6.7.5",
|
"@typescript-eslint/parser": "^6.7.5",
|
||||||
"@vitejs/plugin-vue": "~5.0.1",
|
"@vitejs/plugin-vue": "~5.0.1",
|
||||||
"@vue/compiler-sfc": "~3.4.2",
|
"@vue/compiler-sfc": "~3.4.2",
|
||||||
"@vuepic/vue-datepicker": "~3.4.8",
|
"@vuepic/vue-datepicker": "~3.4.8",
|
||||||
"aedes": "^0.46.3",
|
"aedes": "^0.46.3",
|
||||||
"bootstrap": "5.1.3",
|
"bootstrap": "5.1.3",
|
||||||
"chart.js": "~4.2.1",
|
"chart.js": "~4.2.1",
|
||||||
"chartjs-adapter-dayjs-4": "~1.0.4",
|
"chartjs-adapter-dayjs-4": "~1.0.4",
|
||||||
"concurrently": "^7.1.0",
|
"concurrently": "^7.1.0",
|
||||||
"core-js": "~3.26.1",
|
"core-js": "~3.26.1",
|
||||||
"cronstrue": "~2.24.0",
|
"cronstrue": "~2.24.0",
|
||||||
"cross-env": "~7.0.3",
|
"cross-env": "~7.0.3",
|
||||||
"delay": "^5.0.0",
|
"delay": "^5.0.0",
|
||||||
"dns2": "~2.0.1",
|
"dns2": "~2.0.1",
|
||||||
"dompurify": "~3.2.4",
|
"dompurify": "~3.2.4",
|
||||||
"eslint": "~8.14.0",
|
"eslint": "~8.14.0",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
"eslint-plugin-jsdoc": "~46.4.6",
|
"eslint-plugin-jsdoc": "~46.4.6",
|
||||||
"eslint-plugin-vue": "~8.7.1",
|
"eslint-plugin-vue": "~8.7.1",
|
||||||
"favico.js": "~0.3.10",
|
"favico.js": "~0.3.10",
|
||||||
"get-port-please": "^3.1.1",
|
"get-port-please": "^3.1.1",
|
||||||
"node-ssh": "~13.1.0",
|
"node-ssh": "~13.1.0",
|
||||||
"postcss-html": "~1.5.0",
|
"postcss-html": "~1.5.0",
|
||||||
"postcss-rtlcss": "~3.7.2",
|
"postcss-rtlcss": "~3.7.2",
|
||||||
"postcss-scss": "~4.0.4",
|
"postcss-scss": "~4.0.4",
|
||||||
"prettier": "^3.7.4",
|
"prettier": "^3.7.4",
|
||||||
"prismjs": "~1.30.0",
|
"prismjs": "~1.30.0",
|
||||||
"qrcode": "~1.5.0",
|
"qrcode": "~1.5.0",
|
||||||
"rollup-plugin-visualizer": "^5.6.0",
|
"rollup-plugin-visualizer": "^5.6.0",
|
||||||
"sass": "~1.42.1",
|
"sass": "~1.42.1",
|
||||||
"stylelint": "^15.10.1",
|
"stylelint": "^15.10.1",
|
||||||
"stylelint-config-prettier": "^9.0.5",
|
"stylelint-config-prettier": "^9.0.5",
|
||||||
"stylelint-config-standard": "~25.0.0",
|
"stylelint-config-standard": "~25.0.0",
|
||||||
"terser": "~5.15.0",
|
"terser": "~5.15.0",
|
||||||
"test": "~3.3.0",
|
"test": "~3.3.0",
|
||||||
"testcontainers": "^10.13.1",
|
"testcontainers": "^10.13.1",
|
||||||
"typescript": "~4.4.4",
|
"typescript": "~4.4.4",
|
||||||
"v-pagination-3": "~0.1.7",
|
"v-pagination-3": "~0.1.7",
|
||||||
"vite": "~5.4.15",
|
"vite": "~5.4.15",
|
||||||
"vite-plugin-compression": "^0.5.1",
|
"vite-plugin-compression": "^0.5.1",
|
||||||
"vite-plugin-pwa": "^1.1.0",
|
"vite-plugin-pwa": "^1.1.0",
|
||||||
"vue": "~3.4.2",
|
"vue": "~3.4.2",
|
||||||
"vue-chartjs": "~5.2.0",
|
"vue-chartjs": "~5.2.0",
|
||||||
"vue-confirm-dialog": "~1.0.2",
|
"vue-confirm-dialog": "~1.0.2",
|
||||||
"vue-contenteditable": "~3.0.4",
|
"vue-contenteditable": "~3.0.4",
|
||||||
"vue-i18n": "~9.14.3",
|
"vue-i18n": "~9.14.3",
|
||||||
"vue-image-crop-upload": "~3.0.3",
|
"vue-image-crop-upload": "~3.0.3",
|
||||||
"vue-multiselect": "~3.0.0-alpha.2",
|
"vue-multiselect": "~3.0.0-alpha.2",
|
||||||
"vue-prism-editor": "~2.0.0-alpha.2",
|
"vue-prism-editor": "~2.0.0-alpha.2",
|
||||||
"vue-qrcode": "~1.0.0",
|
"vue-qrcode": "~1.0.0",
|
||||||
"vue-router": "~4.2.5",
|
"vue-router": "~4.2.5",
|
||||||
"vue-toastification": "~2.0.0-rc.5",
|
"vue-toastification": "~2.0.0-rc.5",
|
||||||
"vuedraggable": "~4.1.0",
|
"vuedraggable": "~4.1.0",
|
||||||
"wait-on": "^7.2.0",
|
"wait-on": "^7.2.0",
|
||||||
"whatwg-url": "~12.0.1"
|
"whatwg-url": "~12.0.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,88 +1,88 @@
|
|||||||
{
|
{
|
||||||
"name": "Uptime Kuma",
|
"name": "Uptime Kuma",
|
||||||
"short_name": "Uptime Kuma",
|
"short_name": "Uptime Kuma",
|
||||||
"description": "An easy-to-use self-hosted monitoring tool.",
|
"description": "An easy-to-use self-hosted monitoring tool.",
|
||||||
"theme_color": "#5cdd8b",
|
"theme_color": "#5cdd8b",
|
||||||
"start_url": "/",
|
"start_url": "/",
|
||||||
"background_color": "#fff",
|
"background_color": "#fff",
|
||||||
"display": "standalone",
|
"display": "standalone",
|
||||||
"icons": [
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "icon-192x192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "icon-512x512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"shortcuts": [
|
||||||
|
{
|
||||||
|
"name": "Dashboard",
|
||||||
|
"short_name": "Dashboard",
|
||||||
|
"description": "View monitoring dashboard",
|
||||||
|
"url": "/dashboard",
|
||||||
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "icon-192x192.png",
|
"src": "icon-192x192.png",
|
||||||
"sizes": "192x192",
|
"sizes": "192x192",
|
||||||
"type": "image/png"
|
"type": "image/png"
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "icon-512x512.png",
|
|
||||||
"sizes": "512x512",
|
|
||||||
"type": "image/png"
|
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"shortcuts": [
|
},
|
||||||
|
{
|
||||||
|
"name": "Add Monitor",
|
||||||
|
"short_name": "Add Monitor",
|
||||||
|
"description": "Add a new monitor",
|
||||||
|
"url": "/add",
|
||||||
|
"icons": [
|
||||||
{
|
{
|
||||||
"name": "Dashboard",
|
"src": "icon-192x192.png",
|
||||||
"short_name": "Dashboard",
|
"sizes": "192x192",
|
||||||
"description": "View monitoring dashboard",
|
"type": "image/png"
|
||||||
"url": "/dashboard",
|
|
||||||
"icons": [
|
|
||||||
{
|
|
||||||
"src": "icon-192x192.png",
|
|
||||||
"sizes": "192x192",
|
|
||||||
"type": "image/png"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Add Monitor",
|
|
||||||
"short_name": "Add Monitor",
|
|
||||||
"description": "Add a new monitor",
|
|
||||||
"url": "/add",
|
|
||||||
"icons": [
|
|
||||||
{
|
|
||||||
"src": "icon-192x192.png",
|
|
||||||
"sizes": "192x192",
|
|
||||||
"type": "image/png"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Monitor List",
|
|
||||||
"short_name": "List",
|
|
||||||
"description": "View all monitors",
|
|
||||||
"url": "/list",
|
|
||||||
"icons": [
|
|
||||||
{
|
|
||||||
"src": "icon-192x192.png",
|
|
||||||
"sizes": "192x192",
|
|
||||||
"type": "image/png"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Settings",
|
|
||||||
"short_name": "Settings",
|
|
||||||
"description": "Open settings",
|
|
||||||
"url": "/settings",
|
|
||||||
"icons": [
|
|
||||||
{
|
|
||||||
"src": "icon-192x192.png",
|
|
||||||
"sizes": "192x192",
|
|
||||||
"type": "image/png"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Maintenance",
|
|
||||||
"short_name": "Maintenance",
|
|
||||||
"description": "Manage maintenance windows",
|
|
||||||
"url": "/maintenance",
|
|
||||||
"icons": [
|
|
||||||
{
|
|
||||||
"src": "icon-192x192.png",
|
|
||||||
"sizes": "192x192",
|
|
||||||
"type": "image/png"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Monitor List",
|
||||||
|
"short_name": "List",
|
||||||
|
"description": "View all monitors",
|
||||||
|
"url": "/list",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "icon-192x192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Settings",
|
||||||
|
"short_name": "Settings",
|
||||||
|
"description": "Open settings",
|
||||||
|
"url": "/settings",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "icon-192x192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Maintenance",
|
||||||
|
"short_name": "Maintenance",
|
||||||
|
"description": "Manage maintenance windows",
|
||||||
|
"url": "/maintenance",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "icon-192x192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,18 +1,14 @@
|
|||||||
const { R } = require("redbean-node");
|
const { R } = require("redbean-node");
|
||||||
|
|
||||||
class TwoFA {
|
class TwoFA {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disable 2FA for specified user
|
* Disable 2FA for specified user
|
||||||
* @param {number} userID ID of user to disable
|
* @param {number} userID ID of user to disable
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
static async disable2FA(userID) {
|
static async disable2FA(userID) {
|
||||||
return await R.exec("UPDATE `user` SET twofa_status = 0 WHERE id = ? ", [
|
return await R.exec("UPDATE `user` SET twofa_status = 0 WHERE id = ? ", [userID]);
|
||||||
userID,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = TwoFA;
|
module.exports = TwoFA;
|
||||||
|
|||||||
@ -16,7 +16,10 @@ function getAnalyticsScript(statusPage) {
|
|||||||
case "umami":
|
case "umami":
|
||||||
return umamiAnalytics.getUmamiAnalyticsScript(statusPage.analyticsScriptUrl, statusPage.analyticsId);
|
return umamiAnalytics.getUmamiAnalyticsScript(statusPage.analyticsScriptUrl, statusPage.analyticsId);
|
||||||
case "plausible":
|
case "plausible":
|
||||||
return plausibleAnalytics.getPlausibleAnalyticsScript(statusPage.analyticsScriptUrl, statusPage.analyticsId);
|
return plausibleAnalytics.getPlausibleAnalyticsScript(
|
||||||
|
statusPage.analyticsScriptUrl,
|
||||||
|
statusPage.analyticsId
|
||||||
|
);
|
||||||
case "matomo":
|
case "matomo":
|
||||||
return matomoAnalytics.getMatomoAnalyticsScript(statusPage.analyticsScriptUrl, statusPage.analyticsId);
|
return matomoAnalytics.getMatomoAnalyticsScript(statusPage.analyticsScriptUrl, statusPage.analyticsId);
|
||||||
default:
|
default:
|
||||||
@ -44,5 +47,5 @@ function isValidAnalyticsConfig(statusPage) {
|
|||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getAnalyticsScript,
|
getAnalyticsScript,
|
||||||
isValidAnalyticsConfig
|
isValidAnalyticsConfig,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -32,5 +32,5 @@ function getPlausibleAnalyticsScript(scriptUrl, domainsToMonitor) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getPlausibleAnalyticsScript
|
getPlausibleAnalyticsScript,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -18,9 +18,7 @@ exports.login = async function (username, password) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let user = await R.findOne("user", "TRIM(username) = ? AND active = 1 ", [
|
let user = await R.findOne("user", "TRIM(username) = ? AND active = 1 ", [username.trim()]);
|
||||||
username.trim(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (user && passwordHash.verify(password, user.password)) {
|
if (user && passwordHash.verify(password, user.password)) {
|
||||||
// Upgrade the hash to bcrypt
|
// Upgrade the hash to bcrypt
|
||||||
@ -50,7 +48,7 @@ async function verifyAPIKey(key) {
|
|||||||
let index = key.substring(2, key.indexOf("_"));
|
let index = key.substring(2, key.indexOf("_"));
|
||||||
let clear = key.substring(key.indexOf("_") + 1, key.length);
|
let clear = key.substring(key.indexOf("_") + 1, key.length);
|
||||||
|
|
||||||
let hash = await R.findOne("api_key", " id=? ", [ index ]);
|
let hash = await R.findOne("api_key", " id=? ", [index]);
|
||||||
|
|
||||||
if (hash === null) {
|
if (hash === null) {
|
||||||
return false;
|
return false;
|
||||||
@ -156,7 +154,7 @@ exports.basicAuth = async function (req, res, next) {
|
|||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
exports.apiAuth = async function (req, res, next) {
|
exports.apiAuth = async function (req, res, next) {
|
||||||
if (!await Settings.get("disableAuth")) {
|
if (!(await Settings.get("disableAuth"))) {
|
||||||
let usingAPIKeys = await Settings.get("apiKeysEnabled");
|
let usingAPIKeys = await Settings.get("apiKeysEnabled");
|
||||||
let middleware;
|
let middleware;
|
||||||
if (usingAPIKeys) {
|
if (usingAPIKeys) {
|
||||||
|
|||||||
@ -14,7 +14,7 @@ let interval;
|
|||||||
|
|
||||||
exports.startInterval = () => {
|
exports.startInterval = () => {
|
||||||
let check = async () => {
|
let check = async () => {
|
||||||
if (await setting("checkUpdate") === false) {
|
if ((await setting("checkUpdate")) === false) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,11 +40,9 @@ exports.startInterval = () => {
|
|||||||
if (res.data.slow) {
|
if (res.data.slow) {
|
||||||
exports.latestVersion = res.data.slow;
|
exports.latestVersion = res.data.slow;
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
log.info("update-checker", "Failed to check for new versions");
|
log.info("update-checker", "Failed to check for new versions");
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
check();
|
check();
|
||||||
|
|||||||
@ -19,14 +19,12 @@ async function sendNotificationList(socket) {
|
|||||||
const timeLogger = new TimeLogger();
|
const timeLogger = new TimeLogger();
|
||||||
|
|
||||||
let result = [];
|
let result = [];
|
||||||
let list = await R.find("notification", " user_id = ? ", [
|
let list = await R.find("notification", " user_id = ? ", [socket.userID]);
|
||||||
socket.userID,
|
|
||||||
]);
|
|
||||||
|
|
||||||
for (let bean of list) {
|
for (let bean of list) {
|
||||||
let notificationObject = bean.export();
|
let notificationObject = bean.export();
|
||||||
notificationObject.isDefault = (notificationObject.isDefault === 1);
|
notificationObject.isDefault = notificationObject.isDefault === 1;
|
||||||
notificationObject.active = (notificationObject.active === 1);
|
notificationObject.active = notificationObject.active === 1;
|
||||||
result.push(notificationObject);
|
result.push(notificationObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,14 +44,15 @@ async function sendNotificationList(socket) {
|
|||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
async function sendHeartbeatList(socket, monitorID, toUser = false, overwrite = false) {
|
async function sendHeartbeatList(socket, monitorID, toUser = false, overwrite = false) {
|
||||||
let list = await R.getAll(`
|
let list = await R.getAll(
|
||||||
|
`
|
||||||
SELECT * FROM heartbeat
|
SELECT * FROM heartbeat
|
||||||
WHERE monitor_id = ?
|
WHERE monitor_id = ?
|
||||||
ORDER BY time DESC
|
ORDER BY time DESC
|
||||||
LIMIT 100
|
LIMIT 100
|
||||||
`, [
|
`,
|
||||||
monitorID,
|
[monitorID]
|
||||||
]);
|
);
|
||||||
|
|
||||||
let result = list.reverse();
|
let result = list.reverse();
|
||||||
|
|
||||||
@ -75,14 +74,16 @@ async function sendHeartbeatList(socket, monitorID, toUser = false, overwrite =
|
|||||||
async function sendImportantHeartbeatList(socket, monitorID, toUser = false, overwrite = false) {
|
async function sendImportantHeartbeatList(socket, monitorID, toUser = false, overwrite = false) {
|
||||||
const timeLogger = new TimeLogger();
|
const timeLogger = new TimeLogger();
|
||||||
|
|
||||||
let list = await R.find("heartbeat", `
|
let list = await R.find(
|
||||||
|
"heartbeat",
|
||||||
|
`
|
||||||
monitor_id = ?
|
monitor_id = ?
|
||||||
AND important = 1
|
AND important = 1
|
||||||
ORDER BY time DESC
|
ORDER BY time DESC
|
||||||
LIMIT 500
|
LIMIT 500
|
||||||
`, [
|
`,
|
||||||
monitorID,
|
[monitorID]
|
||||||
]);
|
);
|
||||||
|
|
||||||
timeLogger.print(`[Monitor: ${monitorID}] sendImportantHeartbeatList`);
|
timeLogger.print(`[Monitor: ${monitorID}] sendImportantHeartbeatList`);
|
||||||
|
|
||||||
@ -91,7 +92,6 @@ async function sendImportantHeartbeatList(socket, monitorID, toUser = false, ove
|
|||||||
} else {
|
} else {
|
||||||
socket.emit("importantHeartbeatList", monitorID, list, overwrite);
|
socket.emit("importantHeartbeatList", monitorID, list, overwrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -102,8 +102,11 @@ async function sendImportantHeartbeatList(socket, monitorID, toUser = false, ove
|
|||||||
async function sendProxyList(socket) {
|
async function sendProxyList(socket) {
|
||||||
const timeLogger = new TimeLogger();
|
const timeLogger = new TimeLogger();
|
||||||
|
|
||||||
const list = await R.find("proxy", " user_id = ? ", [ socket.userID ]);
|
const list = await R.find("proxy", " user_id = ? ", [socket.userID]);
|
||||||
io.to(socket.userID).emit("proxyList", list.map(bean => bean.export()));
|
io.to(socket.userID).emit(
|
||||||
|
"proxyList",
|
||||||
|
list.map((bean) => bean.export())
|
||||||
|
);
|
||||||
|
|
||||||
timeLogger.print("Send Proxy List");
|
timeLogger.print("Send Proxy List");
|
||||||
|
|
||||||
@ -119,11 +122,7 @@ async function sendAPIKeyList(socket) {
|
|||||||
const timeLogger = new TimeLogger();
|
const timeLogger = new TimeLogger();
|
||||||
|
|
||||||
let result = [];
|
let result = [];
|
||||||
const list = await R.find(
|
const list = await R.find("api_key", "user_id=?", [socket.userID]);
|
||||||
"api_key",
|
|
||||||
"user_id=?",
|
|
||||||
[ socket.userID ],
|
|
||||||
);
|
|
||||||
|
|
||||||
for (let bean of list) {
|
for (let bean of list) {
|
||||||
result.push(bean.toPublicJSON());
|
result.push(bean.toPublicJSON());
|
||||||
@ -150,7 +149,7 @@ async function sendInfo(socket, hideVersion = false) {
|
|||||||
if (!hideVersion) {
|
if (!hideVersion) {
|
||||||
info.version = checkVersion.version;
|
info.version = checkVersion.version;
|
||||||
info.latestVersion = checkVersion.latestVersion;
|
info.latestVersion = checkVersion.latestVersion;
|
||||||
info.isContainer = (process.env.UPTIME_KUMA_IS_CONTAINER === "1");
|
info.isContainer = process.env.UPTIME_KUMA_IS_CONTAINER === "1";
|
||||||
info.dbType = Database.dbConfig.type;
|
info.dbType = Database.dbConfig.type;
|
||||||
info.runtime = {
|
info.runtime = {
|
||||||
platform: process.platform, // linux or win32
|
platform: process.platform, // linux or win32
|
||||||
@ -170,9 +169,7 @@ async function sendDockerHostList(socket) {
|
|||||||
const timeLogger = new TimeLogger();
|
const timeLogger = new TimeLogger();
|
||||||
|
|
||||||
let result = [];
|
let result = [];
|
||||||
let list = await R.find("docker_host", " user_id = ? ", [
|
let list = await R.find("docker_host", " user_id = ? ", [socket.userID]);
|
||||||
socket.userID,
|
|
||||||
]);
|
|
||||||
|
|
||||||
for (let bean of list) {
|
for (let bean of list) {
|
||||||
result.push(bean.toJSON());
|
result.push(bean.toJSON());
|
||||||
@ -194,9 +191,7 @@ async function sendRemoteBrowserList(socket) {
|
|||||||
const timeLogger = new TimeLogger();
|
const timeLogger = new TimeLogger();
|
||||||
|
|
||||||
let result = [];
|
let result = [];
|
||||||
let list = await R.find("remote_browser", " user_id = ? ", [
|
let list = await R.find("remote_browser", " user_id = ? ", [socket.userID]);
|
||||||
socket.userID,
|
|
||||||
]);
|
|
||||||
|
|
||||||
for (let bean of list) {
|
for (let bean of list) {
|
||||||
result.push(bean.toJSON());
|
result.push(bean.toJSON());
|
||||||
@ -215,21 +210,24 @@ async function sendRemoteBrowserList(socket) {
|
|||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
async function sendMonitorTypeList(socket) {
|
async function sendMonitorTypeList(socket) {
|
||||||
const result = Object.entries(UptimeKumaServer.monitorTypeList).map(([ key, type ]) => {
|
const result = Object.entries(UptimeKumaServer.monitorTypeList).map(([key, type]) => {
|
||||||
return [ key, {
|
return [
|
||||||
supportsConditions: type.supportsConditions,
|
key,
|
||||||
conditionVariables: type.conditionVariables.map(v => {
|
{
|
||||||
return {
|
supportsConditions: type.supportsConditions,
|
||||||
id: v.id,
|
conditionVariables: type.conditionVariables.map((v) => {
|
||||||
operators: v.operators.map(o => {
|
return {
|
||||||
return {
|
id: v.id,
|
||||||
id: o.id,
|
operators: v.operators.map((o) => {
|
||||||
caption: o.caption,
|
return {
|
||||||
};
|
id: o.id,
|
||||||
}),
|
caption: o.caption,
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
}];
|
};
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
io.to(socket.userID).emit("monitorTypeList", Object.fromEntries(result));
|
io.to(socket.userID).emit("monitorTypeList", Object.fromEntries(result));
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
const isFreeBSD = /^freebsd/.test(process.platform);
|
const isFreeBSD = /^freebsd/.test(process.platform);
|
||||||
|
|
||||||
// Interop with browser
|
// Interop with browser
|
||||||
const args = (typeof process !== "undefined") ? require("args-parser")(process.argv) : {};
|
const args = typeof process !== "undefined" ? require("args-parser")(process.argv) : {};
|
||||||
|
|
||||||
// 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.
|
// 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 (::)
|
// Dual-stack support for (::)
|
||||||
@ -9,13 +9,17 @@ const args = (typeof process !== "undefined") ? require("args-parser")(process.a
|
|||||||
let hostEnv = isFreeBSD ? null : process.env.HOST;
|
let hostEnv = isFreeBSD ? null : process.env.HOST;
|
||||||
const hostname = args.host || process.env.UPTIME_KUMA_HOST || hostEnv;
|
const hostname = args.host || process.env.UPTIME_KUMA_HOST || hostEnv;
|
||||||
|
|
||||||
const port = [ args.port, process.env.UPTIME_KUMA_PORT, process.env.PORT, 3001 ]
|
const port = [args.port, process.env.UPTIME_KUMA_PORT, process.env.PORT, 3001]
|
||||||
.map(portValue => parseInt(portValue))
|
.map((portValue) => parseInt(portValue))
|
||||||
.find(portValue => !isNaN(portValue));
|
.find((portValue) => !isNaN(portValue));
|
||||||
|
|
||||||
const sslKey = args["ssl-key"] || process.env.UPTIME_KUMA_SSL_KEY || process.env.SSL_KEY || undefined;
|
const sslKey = args["ssl-key"] || process.env.UPTIME_KUMA_SSL_KEY || process.env.SSL_KEY || undefined;
|
||||||
const sslCert = args["ssl-cert"] || process.env.UPTIME_KUMA_SSL_CERT || process.env.SSL_CERT || undefined;
|
const sslCert = args["ssl-cert"] || process.env.UPTIME_KUMA_SSL_CERT || process.env.SSL_CERT || undefined;
|
||||||
const sslKeyPassphrase = args["ssl-key-passphrase"] || process.env.UPTIME_KUMA_SSL_KEY_PASSPHRASE || process.env.SSL_KEY_PASSPHRASE || undefined;
|
const sslKeyPassphrase =
|
||||||
|
args["ssl-key-passphrase"] ||
|
||||||
|
process.env.UPTIME_KUMA_SSL_KEY_PASSPHRASE ||
|
||||||
|
process.env.SSL_KEY_PASSPHRASE ||
|
||||||
|
undefined;
|
||||||
|
|
||||||
const isSSL = sslKey && sslCert;
|
const isSSL = sslKey && sslCert;
|
||||||
|
|
||||||
|
|||||||
@ -18,7 +18,6 @@ const SqlString = require("sqlstring");
|
|||||||
* Database & App Data Folder
|
* Database & App Data Folder
|
||||||
*/
|
*/
|
||||||
class Database {
|
class Database {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bootstrap database for SQLite
|
* Bootstrap database for SQLite
|
||||||
* @type {string}
|
* @type {string}
|
||||||
@ -89,7 +88,7 @@ class Database {
|
|||||||
"patch-added-mqtt-monitor.sql": true,
|
"patch-added-mqtt-monitor.sql": true,
|
||||||
"patch-add-clickable-status-page-link.sql": true,
|
"patch-add-clickable-status-page-link.sql": true,
|
||||||
"patch-add-sqlserver-monitor.sql": true,
|
"patch-add-sqlserver-monitor.sql": true,
|
||||||
"patch-add-other-auth.sql": { parents: [ "patch-monitor-basic-auth.sql" ] },
|
"patch-add-other-auth.sql": { parents: ["patch-monitor-basic-auth.sql"] },
|
||||||
"patch-grpc-monitor.sql": true,
|
"patch-grpc-monitor.sql": true,
|
||||||
"patch-add-radius-monitor.sql": true,
|
"patch-add-radius-monitor.sql": true,
|
||||||
"patch-monitor-add-resend-interval.sql": true,
|
"patch-monitor-add-resend-interval.sql": true,
|
||||||
@ -138,24 +137,24 @@ class Database {
|
|||||||
Database.dataDir = process.env.DATA_DIR || args["data-dir"] || "./data/";
|
Database.dataDir = process.env.DATA_DIR || args["data-dir"] || "./data/";
|
||||||
|
|
||||||
Database.sqlitePath = path.join(Database.dataDir, "kuma.db");
|
Database.sqlitePath = path.join(Database.dataDir, "kuma.db");
|
||||||
if (! fs.existsSync(Database.dataDir)) {
|
if (!fs.existsSync(Database.dataDir)) {
|
||||||
fs.mkdirSync(Database.dataDir, { recursive: true });
|
fs.mkdirSync(Database.dataDir, { recursive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
Database.uploadDir = path.join(Database.dataDir, "upload/");
|
Database.uploadDir = path.join(Database.dataDir, "upload/");
|
||||||
|
|
||||||
if (! fs.existsSync(Database.uploadDir)) {
|
if (!fs.existsSync(Database.uploadDir)) {
|
||||||
fs.mkdirSync(Database.uploadDir, { recursive: true });
|
fs.mkdirSync(Database.uploadDir, { recursive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create screenshot dir
|
// Create screenshot dir
|
||||||
Database.screenshotDir = path.join(Database.dataDir, "screenshots/");
|
Database.screenshotDir = path.join(Database.dataDir, "screenshots/");
|
||||||
if (! fs.existsSync(Database.screenshotDir)) {
|
if (!fs.existsSync(Database.screenshotDir)) {
|
||||||
fs.mkdirSync(Database.screenshotDir, { recursive: true });
|
fs.mkdirSync(Database.screenshotDir, { recursive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
Database.dockerTLSDir = path.join(Database.dataDir, "docker-tls/");
|
Database.dockerTLSDir = path.join(Database.dataDir, "docker-tls/");
|
||||||
if (! fs.existsSync(Database.dockerTLSDir)) {
|
if (!fs.existsSync(Database.dockerTLSDir)) {
|
||||||
fs.mkdirSync(Database.dockerTLSDir, { recursive: true });
|
fs.mkdirSync(Database.dockerTLSDir, { recursive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,13 +227,22 @@ class Database {
|
|||||||
if (!process.env.UPTIME_KUMA_DB_POOL_MAX_CONNECTIONS) {
|
if (!process.env.UPTIME_KUMA_DB_POOL_MAX_CONNECTIONS) {
|
||||||
parsedMaxPoolConnections = 10;
|
parsedMaxPoolConnections = 10;
|
||||||
} else if (Number.isNaN(parsedMaxPoolConnections)) {
|
} else if (Number.isNaN(parsedMaxPoolConnections)) {
|
||||||
log.warn("db", "Max database connections defaulted to 10 because UPTIME_KUMA_DB_POOL_MAX_CONNECTIONS was invalid.");
|
log.warn(
|
||||||
|
"db",
|
||||||
|
"Max database connections defaulted to 10 because UPTIME_KUMA_DB_POOL_MAX_CONNECTIONS was invalid."
|
||||||
|
);
|
||||||
parsedMaxPoolConnections = 10;
|
parsedMaxPoolConnections = 10;
|
||||||
} else if (parsedMaxPoolConnections < 1) {
|
} else if (parsedMaxPoolConnections < 1) {
|
||||||
log.warn("db", "Max database connections defaulted to 10 because UPTIME_KUMA_DB_POOL_MAX_CONNECTIONS was less than 1.");
|
log.warn(
|
||||||
|
"db",
|
||||||
|
"Max database connections defaulted to 10 because UPTIME_KUMA_DB_POOL_MAX_CONNECTIONS was less than 1."
|
||||||
|
);
|
||||||
parsedMaxPoolConnections = 10;
|
parsedMaxPoolConnections = 10;
|
||||||
} else if (parsedMaxPoolConnections > 100) {
|
} else if (parsedMaxPoolConnections > 100) {
|
||||||
log.warn("db", "Max database connections capped to 100 because Mysql/Mariadb connections are heavy. consider using a proxy like ProxySQL or MaxScale.");
|
log.warn(
|
||||||
|
"db",
|
||||||
|
"Max database connections capped to 100 because Mysql/Mariadb connections are heavy. consider using a proxy like ProxySQL or MaxScale."
|
||||||
|
);
|
||||||
parsedMaxPoolConnections = 100;
|
parsedMaxPoolConnections = 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,8 +255,7 @@ class Database {
|
|||||||
log.info("db", `Database Type: ${dbConfig.type}`);
|
log.info("db", `Database Type: ${dbConfig.type}`);
|
||||||
|
|
||||||
if (dbConfig.type === "sqlite") {
|
if (dbConfig.type === "sqlite") {
|
||||||
|
if (!fs.existsSync(Database.sqlitePath)) {
|
||||||
if (! fs.existsSync(Database.sqlitePath)) {
|
|
||||||
log.info("server", "Copying Database");
|
log.info("server", "Copying Database");
|
||||||
fs.copyFileSync(Database.templatePath, Database.sqlitePath);
|
fs.copyFileSync(Database.templatePath, Database.sqlitePath);
|
||||||
}
|
}
|
||||||
@ -269,7 +276,7 @@ class Database {
|
|||||||
idleTimeoutMillis: 120 * 1000,
|
idleTimeoutMillis: 120 * 1000,
|
||||||
propagateCreateError: false,
|
propagateCreateError: false,
|
||||||
acquireTimeoutMillis: acquireConnectionTimeout,
|
acquireTimeoutMillis: acquireConnectionTimeout,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
} else if (dbConfig.type === "mariadb") {
|
} else if (dbConfig.type === "mariadb") {
|
||||||
const connection = await mysql.createConnection({
|
const connection = await mysql.createConnection({
|
||||||
@ -387,7 +394,7 @@ class Database {
|
|||||||
log.debug("db", "SQLite config:");
|
log.debug("db", "SQLite config:");
|
||||||
log.debug("db", await R.getAll("PRAGMA journal_mode"));
|
log.debug("db", await R.getAll("PRAGMA journal_mode"));
|
||||||
log.debug("db", await R.getAll("PRAGMA cache_size"));
|
log.debug("db", await R.getAll("PRAGMA cache_size"));
|
||||||
log.debug("db", "SQLite Version: " + await R.getCell("SELECT sqlite_version()"));
|
log.debug("db", "SQLite Version: " + (await R.getCell("SELECT sqlite_version()")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -439,7 +446,6 @@ class Database {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await this.migrateAggregateTable(port, hostname);
|
await this.migrateAggregateTable(port, hostname);
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Allow missing patch files for downgrade or testing pr.
|
// Allow missing patch files for downgrade or testing pr.
|
||||||
if (e.message.includes("the following files are missing:")) {
|
if (e.message.includes("the following files are missing:")) {
|
||||||
@ -456,9 +462,7 @@ class Database {
|
|||||||
* TODO
|
* TODO
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
static async rollbackLatestPatch() {
|
static async rollbackLatestPatch() {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patch the database for SQLite
|
* Patch the database for SQLite
|
||||||
@ -468,7 +472,7 @@ class Database {
|
|||||||
static async patchSqlite() {
|
static async patchSqlite() {
|
||||||
let version = parseInt(await setting("database_version"));
|
let version = parseInt(await setting("database_version"));
|
||||||
|
|
||||||
if (! version) {
|
if (!version) {
|
||||||
version = 0;
|
version = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -498,7 +502,10 @@ class Database {
|
|||||||
|
|
||||||
log.error("db", ex);
|
log.error("db", ex);
|
||||||
log.error("db", "Start Uptime-Kuma failed due to issue patching the database");
|
log.error("db", "Start Uptime-Kuma failed due to issue patching the database");
|
||||||
log.error("db", "Please submit a bug report if you still encounter the problem after restart: https://github.com/louislam/uptime-kuma/issues");
|
log.error(
|
||||||
|
"db",
|
||||||
|
"Please submit a bug report if you still encounter the problem after restart: https://github.com/louislam/uptime-kuma/issues"
|
||||||
|
);
|
||||||
|
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
@ -519,7 +526,7 @@ class Database {
|
|||||||
log.debug("db", "Database Patch 2.0 Process");
|
log.debug("db", "Database Patch 2.0 Process");
|
||||||
let databasePatchedFiles = await setting("databasePatchedFiles");
|
let databasePatchedFiles = await setting("databasePatchedFiles");
|
||||||
|
|
||||||
if (! databasePatchedFiles) {
|
if (!databasePatchedFiles) {
|
||||||
databasePatchedFiles = {};
|
databasePatchedFiles = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -534,13 +541,15 @@ class Database {
|
|||||||
if (this.patched) {
|
if (this.patched) {
|
||||||
log.info("db", "Database Patched Successfully");
|
log.info("db", "Database Patched Successfully");
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
await Database.close();
|
await Database.close();
|
||||||
|
|
||||||
log.error("db", ex);
|
log.error("db", ex);
|
||||||
log.error("db", "Start Uptime-Kuma failed due to issue patching the database");
|
log.error("db", "Start Uptime-Kuma failed due to issue patching the database");
|
||||||
log.error("db", "Please submit the bug report if you still encounter the problem after restart: https://github.com/louislam/uptime-kuma/issues");
|
log.error(
|
||||||
|
"db",
|
||||||
|
"Please submit the bug report if you still encounter the problem after restart: https://github.com/louislam/uptime-kuma/issues"
|
||||||
|
);
|
||||||
|
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
@ -554,7 +563,6 @@ class Database {
|
|||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
static async migrateNewStatusPage() {
|
static async migrateNewStatusPage() {
|
||||||
|
|
||||||
// Fix 1.13.0 empty slug bug
|
// Fix 1.13.0 empty slug bug
|
||||||
await R.exec("UPDATE status_page SET slug = 'empty-slug-recover' WHERE TRIM(slug) = ''");
|
await R.exec("UPDATE status_page SET slug = 'empty-slug-recover' WHERE TRIM(slug) = ''");
|
||||||
|
|
||||||
@ -576,9 +584,9 @@ class Database {
|
|||||||
statusPage.description = await setting("description");
|
statusPage.description = await setting("description");
|
||||||
statusPage.icon = await setting("icon");
|
statusPage.icon = await setting("icon");
|
||||||
statusPage.theme = await setting("statusPageTheme");
|
statusPage.theme = await setting("statusPageTheme");
|
||||||
statusPage.published = !!await setting("statusPagePublished");
|
statusPage.published = !!(await setting("statusPagePublished"));
|
||||||
statusPage.search_engine_index = !!await setting("searchEngineIndex");
|
statusPage.search_engine_index = !!(await setting("searchEngineIndex"));
|
||||||
statusPage.show_tags = !!await setting("statusPageTags");
|
statusPage.show_tags = !!(await setting("statusPageTags"));
|
||||||
statusPage.password = null;
|
statusPage.password = null;
|
||||||
|
|
||||||
if (!statusPage.title) {
|
if (!statusPage.title) {
|
||||||
@ -595,13 +603,9 @@ class Database {
|
|||||||
|
|
||||||
let id = await R.store(statusPage);
|
let id = await R.store(statusPage);
|
||||||
|
|
||||||
await R.exec("UPDATE incident SET status_page_id = ? WHERE status_page_id IS NULL", [
|
await R.exec("UPDATE incident SET status_page_id = ? WHERE status_page_id IS NULL", [id]);
|
||||||
id
|
|
||||||
]);
|
|
||||||
|
|
||||||
await R.exec("UPDATE [group] SET status_page_id = ? WHERE status_page_id IS NULL", [
|
await R.exec("UPDATE [group] SET status_page_id = ? WHERE status_page_id IS NULL", [id]);
|
||||||
id
|
|
||||||
]);
|
|
||||||
|
|
||||||
await R.exec("DELETE FROM setting WHERE type = 'statusPage'");
|
await R.exec("DELETE FROM setting WHERE type = 'statusPage'");
|
||||||
|
|
||||||
@ -614,7 +618,6 @@ class Database {
|
|||||||
|
|
||||||
console.log("Migrating Status Page - Done");
|
console.log("Migrating Status Page - Done");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -628,13 +631,13 @@ class Database {
|
|||||||
static async patch2Recursion(sqlFilename, databasePatchedFiles) {
|
static async patch2Recursion(sqlFilename, databasePatchedFiles) {
|
||||||
let value = this.patchList[sqlFilename];
|
let value = this.patchList[sqlFilename];
|
||||||
|
|
||||||
if (! value) {
|
if (!value) {
|
||||||
log.info("db", sqlFilename + " skip");
|
log.info("db", sqlFilename + " skip");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if patched
|
// Check if patched
|
||||||
if (! databasePatchedFiles[sqlFilename]) {
|
if (!databasePatchedFiles[sqlFilename]) {
|
||||||
log.info("db", sqlFilename + " is not patched");
|
log.info("db", sqlFilename + " is not patched");
|
||||||
|
|
||||||
if (value.parents) {
|
if (value.parents) {
|
||||||
@ -649,7 +652,6 @@ class Database {
|
|||||||
await this.importSQLFile("./db/old_migrations/" + sqlFilename);
|
await this.importSQLFile("./db/old_migrations/" + sqlFilename);
|
||||||
databasePatchedFiles[sqlFilename] = true;
|
databasePatchedFiles[sqlFilename] = true;
|
||||||
log.info("db", sqlFilename + " was patched successfully");
|
log.info("db", sqlFilename + " was patched successfully");
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
log.debug("db", sqlFilename + " is already patched, skip");
|
log.debug("db", sqlFilename + " is already patched, skip");
|
||||||
}
|
}
|
||||||
@ -669,14 +671,15 @@ class Database {
|
|||||||
// Remove all comments (--)
|
// Remove all comments (--)
|
||||||
let lines = text.split("\n");
|
let lines = text.split("\n");
|
||||||
lines = lines.filter((line) => {
|
lines = lines.filter((line) => {
|
||||||
return ! line.startsWith("--");
|
return !line.startsWith("--");
|
||||||
});
|
});
|
||||||
|
|
||||||
// Split statements by semicolon
|
// Split statements by semicolon
|
||||||
// Filter out empty line
|
// Filter out empty line
|
||||||
text = lines.join("\n");
|
text = lines.join("\n");
|
||||||
|
|
||||||
let statements = text.split(";")
|
let statements = text
|
||||||
|
.split(";")
|
||||||
.map((statement) => {
|
.map((statement) => {
|
||||||
return statement.trim();
|
return statement.trim();
|
||||||
})
|
})
|
||||||
@ -773,7 +776,10 @@ class Database {
|
|||||||
|
|
||||||
// Add a setting for 2.0.0-dev users to skip this migration
|
// Add a setting for 2.0.0-dev users to skip this migration
|
||||||
if (process.env.SET_MIGRATE_AGGREGATE_TABLE_TO_TRUE === "1") {
|
if (process.env.SET_MIGRATE_AGGREGATE_TABLE_TO_TRUE === "1") {
|
||||||
log.warn("db", "SET_MIGRATE_AGGREGATE_TABLE_TO_TRUE is set to 1, skipping aggregate table migration forever (for 2.0.0-dev users)");
|
log.warn(
|
||||||
|
"db",
|
||||||
|
"SET_MIGRATE_AGGREGATE_TABLE_TO_TRUE is set to 1, skipping aggregate table migration forever (for 2.0.0-dev users)"
|
||||||
|
);
|
||||||
await Settings.set("migrateAggregateTableState", "migrated");
|
await Settings.set("migrateAggregateTableState", "migrated");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -813,11 +819,14 @@ class Database {
|
|||||||
`);
|
`);
|
||||||
|
|
||||||
// Stop if stat_* tables are not empty
|
// Stop if stat_* tables are not empty
|
||||||
for (let table of [ "stat_minutely", "stat_hourly", "stat_daily" ]) {
|
for (let table of ["stat_minutely", "stat_hourly", "stat_daily"]) {
|
||||||
let countResult = await R.getRow(`SELECT COUNT(*) AS count FROM ${table}`);
|
let countResult = await R.getRow(`SELECT COUNT(*) AS count FROM ${table}`);
|
||||||
let count = countResult.count;
|
let count = countResult.count;
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
log.warn("db", `Aggregate table ${table} is not empty, migration will not be started (Maybe you were using 2.0.0-dev?)`);
|
log.warn(
|
||||||
|
"db",
|
||||||
|
`Aggregate table ${table} is not empty, migration will not be started (Maybe you were using 2.0.0-dev?)`
|
||||||
|
);
|
||||||
await migrationServer?.stop();
|
await migrationServer?.stop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -826,31 +835,35 @@ class Database {
|
|||||||
await Settings.set("migrateAggregateTableState", "migrating");
|
await Settings.set("migrateAggregateTableState", "migrating");
|
||||||
|
|
||||||
let progressPercent = 0;
|
let progressPercent = 0;
|
||||||
for (const [ i, monitor ] of monitors.entries()) {
|
for (const [i, monitor] of monitors.entries()) {
|
||||||
// Get a list of unique dates from the heartbeat table, using raw sql
|
// Get a list of unique dates from the heartbeat table, using raw sql
|
||||||
let dates = await R.getAll(`
|
let dates = await R.getAll(
|
||||||
|
`
|
||||||
SELECT DISTINCT DATE(time) AS date
|
SELECT DISTINCT DATE(time) AS date
|
||||||
FROM heartbeat
|
FROM heartbeat
|
||||||
WHERE monitor_id = ?
|
WHERE monitor_id = ?
|
||||||
ORDER BY date ASC
|
ORDER BY date ASC
|
||||||
`, [
|
`,
|
||||||
monitor.monitor_id
|
[monitor.monitor_id]
|
||||||
]);
|
);
|
||||||
|
|
||||||
for (const [ dateIndex, date ] of dates.entries()) {
|
for (const [dateIndex, date] of dates.entries()) {
|
||||||
// New Uptime Calculator
|
// New Uptime Calculator
|
||||||
let calculator = new UptimeCalculator();
|
let calculator = new UptimeCalculator();
|
||||||
calculator.monitorID = monitor.monitor_id;
|
calculator.monitorID = monitor.monitor_id;
|
||||||
calculator.setMigrationMode(true);
|
calculator.setMigrationMode(true);
|
||||||
|
|
||||||
// Get all the heartbeats for this monitor and date
|
// Get all the heartbeats for this monitor and date
|
||||||
let heartbeats = await R.getAll(`
|
let heartbeats = await R.getAll(
|
||||||
|
`
|
||||||
SELECT status, ping, time
|
SELECT status, ping, time
|
||||||
FROM heartbeat
|
FROM heartbeat
|
||||||
WHERE monitor_id = ?
|
WHERE monitor_id = ?
|
||||||
AND DATE(time) = ?
|
AND DATE(time) = ?
|
||||||
ORDER BY time ASC
|
ORDER BY time ASC
|
||||||
`, [ monitor.monitor_id, date.date ]);
|
`,
|
||||||
|
[monitor.monitor_id, date.date]
|
||||||
|
);
|
||||||
|
|
||||||
if (heartbeats.length > 0) {
|
if (heartbeats.length > 0) {
|
||||||
msg = `[DON'T STOP] Migrating monitor ${monitor.monitor_id}s' (${i + 1} of ${monitors.length} total) data - ${date.date} - total migration progress ${progressPercent.toFixed(2)}%`;
|
msg = `[DON'T STOP] Migrating monitor ${monitor.monitor_id}s' (${i + 1} of ${monitors.length} total) data - ${date.date} - total migration progress ${progressPercent.toFixed(2)}%`;
|
||||||
@ -863,7 +876,7 @@ class Database {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Calculate progress: (current_monitor_index + relative_date_progress) / total_monitors
|
// Calculate progress: (current_monitor_index + relative_date_progress) / total_monitors
|
||||||
progressPercent = (i + (dateIndex + 1) / dates.length) / monitors.length * 100;
|
progressPercent = ((i + (dateIndex + 1) / dates.length) / monitors.length) * 100;
|
||||||
|
|
||||||
// Lazy to fix the floating point issue, it is acceptable since it is just a progress bar
|
// Lazy to fix the floating point issue, it is acceptable since it is just a progress bar
|
||||||
if (progressPercent > 100) {
|
if (progressPercent > 100) {
|
||||||
@ -900,7 +913,8 @@ class Database {
|
|||||||
if (detailedLog) {
|
if (detailedLog) {
|
||||||
log.info("db", "Deleting non-important heartbeats for monitor " + monitor.id);
|
log.info("db", "Deleting non-important heartbeats for monitor " + monitor.id);
|
||||||
}
|
}
|
||||||
await R.exec(`
|
await R.exec(
|
||||||
|
`
|
||||||
DELETE FROM heartbeat
|
DELETE FROM heartbeat
|
||||||
WHERE monitor_id = ?
|
WHERE monitor_id = ?
|
||||||
AND important = 0
|
AND important = 0
|
||||||
@ -914,15 +928,11 @@ class Database {
|
|||||||
LIMIT ?
|
LIMIT ?
|
||||||
) AS limited_ids
|
) AS limited_ids
|
||||||
)
|
)
|
||||||
`, [
|
`,
|
||||||
monitor.id,
|
[monitor.id, -24, monitor.id, 100]
|
||||||
-24,
|
);
|
||||||
monitor.id,
|
|
||||||
100,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Database;
|
module.exports = Database;
|
||||||
|
|||||||
@ -7,7 +7,6 @@ const Database = require("./database");
|
|||||||
const { axiosAbortSignal, fsExists } = require("./util-server");
|
const { axiosAbortSignal, fsExists } = require("./util-server");
|
||||||
|
|
||||||
class DockerHost {
|
class DockerHost {
|
||||||
|
|
||||||
static CertificateFileNameCA = "ca.pem";
|
static CertificateFileNameCA = "ca.pem";
|
||||||
static CertificateFileNameCert = "cert.pem";
|
static CertificateFileNameCert = "cert.pem";
|
||||||
static CertificateFileNameKey = "key.pem";
|
static CertificateFileNameKey = "key.pem";
|
||||||
@ -23,12 +22,11 @@ class DockerHost {
|
|||||||
let bean;
|
let bean;
|
||||||
|
|
||||||
if (dockerHostID) {
|
if (dockerHostID) {
|
||||||
bean = await R.findOne("docker_host", " id = ? AND user_id = ? ", [ dockerHostID, userID ]);
|
bean = await R.findOne("docker_host", " id = ? AND user_id = ? ", [dockerHostID, userID]);
|
||||||
|
|
||||||
if (!bean) {
|
if (!bean) {
|
||||||
throw new Error("docker host not found");
|
throw new Error("docker host not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
bean = R.dispense("docker_host");
|
bean = R.dispense("docker_host");
|
||||||
}
|
}
|
||||||
@ -50,14 +48,14 @@ class DockerHost {
|
|||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
static async delete(dockerHostID, userID) {
|
static async delete(dockerHostID, userID) {
|
||||||
let bean = await R.findOne("docker_host", " id = ? AND user_id = ? ", [ dockerHostID, userID ]);
|
let bean = await R.findOne("docker_host", " id = ? AND user_id = ? ", [dockerHostID, userID]);
|
||||||
|
|
||||||
if (!bean) {
|
if (!bean) {
|
||||||
throw new Error("docker host not found");
|
throw new Error("docker host not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete removed proxy from monitors if exists
|
// Delete removed proxy from monitors if exists
|
||||||
await R.exec("UPDATE monitor SET docker_host = null WHERE docker_host = ?", [ dockerHostID ]);
|
await R.exec("UPDATE monitor SET docker_host = null WHERE docker_host = ?", [dockerHostID]);
|
||||||
|
|
||||||
await R.trash(bean);
|
await R.trash(bean);
|
||||||
}
|
}
|
||||||
@ -72,7 +70,7 @@ class DockerHost {
|
|||||||
url: "/containers/json?all=true",
|
url: "/containers/json?all=true",
|
||||||
timeout: 5000,
|
timeout: 5000,
|
||||||
headers: {
|
headers: {
|
||||||
"Accept": "*/*",
|
Accept: "*/*",
|
||||||
},
|
},
|
||||||
signal: axiosAbortSignal(6000),
|
signal: axiosAbortSignal(6000),
|
||||||
};
|
};
|
||||||
@ -81,26 +79,24 @@ class DockerHost {
|
|||||||
options.socketPath = dockerHost.dockerDaemon;
|
options.socketPath = dockerHost.dockerDaemon;
|
||||||
} else if (dockerHost.dockerType === "tcp") {
|
} else if (dockerHost.dockerType === "tcp") {
|
||||||
options.baseURL = DockerHost.patchDockerURL(dockerHost.dockerDaemon);
|
options.baseURL = DockerHost.patchDockerURL(dockerHost.dockerDaemon);
|
||||||
options.httpsAgent = new https.Agent(await DockerHost.getHttpsAgentOptions(dockerHost.dockerType, options.baseURL));
|
options.httpsAgent = new https.Agent(
|
||||||
|
await DockerHost.getHttpsAgentOptions(dockerHost.dockerType, options.baseURL)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let res = await axios.request(options);
|
let res = await axios.request(options);
|
||||||
|
|
||||||
if (Array.isArray(res.data)) {
|
if (Array.isArray(res.data)) {
|
||||||
|
|
||||||
if (res.data.length > 1) {
|
if (res.data.length > 1) {
|
||||||
|
|
||||||
if ("ImageID" in res.data[0]) {
|
if ("ImageID" in res.data[0]) {
|
||||||
return res.data.length;
|
return res.data.length;
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Invalid Docker response, is it Docker really a daemon?");
|
throw new Error("Invalid Docker response, is it Docker really a daemon?");
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return res.data.length;
|
return res.data.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Invalid Docker response, is it Docker really a daemon?");
|
throw new Error("Invalid Docker response, is it Docker really a daemon?");
|
||||||
}
|
}
|
||||||
@ -146,30 +142,35 @@ class DockerHost {
|
|||||||
static async getHttpsAgentOptions(dockerType, url) {
|
static async getHttpsAgentOptions(dockerType, url) {
|
||||||
let baseOptions = {
|
let baseOptions = {
|
||||||
maxCachedSessions: 0,
|
maxCachedSessions: 0,
|
||||||
rejectUnauthorized: true
|
rejectUnauthorized: true,
|
||||||
};
|
};
|
||||||
let certOptions = {};
|
let certOptions = {};
|
||||||
|
|
||||||
let dirName = (new URL(url)).hostname;
|
let dirName = new URL(url).hostname;
|
||||||
|
|
||||||
let caPath = path.join(Database.dockerTLSDir, dirName, DockerHost.CertificateFileNameCA);
|
let caPath = path.join(Database.dockerTLSDir, dirName, DockerHost.CertificateFileNameCA);
|
||||||
let certPath = path.join(Database.dockerTLSDir, dirName, DockerHost.CertificateFileNameCert);
|
let certPath = path.join(Database.dockerTLSDir, dirName, DockerHost.CertificateFileNameCert);
|
||||||
let keyPath = path.join(Database.dockerTLSDir, dirName, DockerHost.CertificateFileNameKey);
|
let keyPath = path.join(Database.dockerTLSDir, dirName, DockerHost.CertificateFileNameKey);
|
||||||
|
|
||||||
if (dockerType === "tcp" && await fsExists(caPath) && await fsExists(certPath) && await fsExists(keyPath)) {
|
if (
|
||||||
|
dockerType === "tcp" &&
|
||||||
|
(await fsExists(caPath)) &&
|
||||||
|
(await fsExists(certPath)) &&
|
||||||
|
(await fsExists(keyPath))
|
||||||
|
) {
|
||||||
let ca = await fsAsync.readFile(caPath);
|
let ca = await fsAsync.readFile(caPath);
|
||||||
let key = await fsAsync.readFile(keyPath);
|
let key = await fsAsync.readFile(keyPath);
|
||||||
let cert = await fsAsync.readFile(certPath);
|
let cert = await fsAsync.readFile(certPath);
|
||||||
certOptions = {
|
certOptions = {
|
||||||
ca,
|
ca,
|
||||||
key,
|
key,
|
||||||
cert
|
cert,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...baseOptions,
|
...baseOptions,
|
||||||
...certOptions
|
...certOptions,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,6 @@ const mysql = require("mysql2");
|
|||||||
* It is only used inside the docker container
|
* It is only used inside the docker container
|
||||||
*/
|
*/
|
||||||
class EmbeddedMariaDB {
|
class EmbeddedMariaDB {
|
||||||
|
|
||||||
static instance = null;
|
static instance = null;
|
||||||
|
|
||||||
exec = "mariadbd";
|
exec = "mariadbd";
|
||||||
@ -59,7 +58,9 @@ class EmbeddedMariaDB {
|
|||||||
// Check if the current user is "node" or "root"
|
// Check if the current user is "node" or "root"
|
||||||
this.username = require("os").userInfo().username;
|
this.username = require("os").userInfo().username;
|
||||||
if (this.username !== "node" && this.username !== "root") {
|
if (this.username !== "node" && this.username !== "root") {
|
||||||
throw new Error("Embedded Mariadb supports only 'node' or 'root' user, but the current user is: " + this.username);
|
throw new Error(
|
||||||
|
"Embedded Mariadb supports only 'node' or 'root' user, but the current user is: " + this.username
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.initDB();
|
this.initDB();
|
||||||
@ -211,7 +212,6 @@ class EmbeddedMariaDB {
|
|||||||
log.info("mariadb", "Embedded MariaDB is ready for connections");
|
log.info("mariadb", "Embedded MariaDB is ready for connections");
|
||||||
this.started = true;
|
this.started = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|||||||
@ -6,7 +6,6 @@ let fs = require("fs");
|
|||||||
const { log } = require("../src/util");
|
const { log } = require("../src/util");
|
||||||
|
|
||||||
let ImageDataURI = (() => {
|
let ImageDataURI = (() => {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decode the data:image/ URI
|
* Decode the data:image/ URI
|
||||||
* @param {string} dataURI data:image/ URI to decode
|
* @param {string} dataURI data:image/ URI to decode
|
||||||
@ -17,7 +16,7 @@ let ImageDataURI = (() => {
|
|||||||
*/
|
*/
|
||||||
function decode(dataURI) {
|
function decode(dataURI) {
|
||||||
if (!/data:image\//.test(dataURI)) {
|
if (!/data:image\//.test(dataURI)) {
|
||||||
log.error("image-data-uri", "It seems that it is not an Image Data URI. Couldn't match \"data:image/\"");
|
log.error("image-data-uri", 'It seems that it is not an Image Data URI. Couldn\'t match "data:image/"');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,7 +24,7 @@ let ImageDataURI = (() => {
|
|||||||
return {
|
return {
|
||||||
imageType: regExMatches[1],
|
imageType: regExMatches[1],
|
||||||
dataBase64: regExMatches[2],
|
dataBase64: regExMatches[2],
|
||||||
dataBuffer: new Buffer(regExMatches[2], "base64")
|
dataBuffer: new Buffer(regExMatches[2], "base64"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,8 +41,8 @@ let ImageDataURI = (() => {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
mediaType = (/\//.test(mediaType)) ? mediaType : "image/" + mediaType;
|
mediaType = /\//.test(mediaType) ? mediaType : "image/" + mediaType;
|
||||||
let dataBase64 = (Buffer.isBuffer(data)) ? data.toString("base64") : new Buffer(data).toString("base64");
|
let dataBase64 = Buffer.isBuffer(data) ? data.toString("base64") : new Buffer(data).toString("base64");
|
||||||
let dataImgBase64 = "data:" + mediaType + ";base64," + dataBase64;
|
let dataImgBase64 = "data:" + mediaType + ";base64," + dataBase64;
|
||||||
|
|
||||||
return dataImgBase64;
|
return dataImgBase64;
|
||||||
@ -60,7 +59,7 @@ let ImageDataURI = (() => {
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let imageDecoded = decode(dataURI);
|
let imageDecoded = decode(dataURI);
|
||||||
|
|
||||||
fs.writeFile(filePath, imageDecoded.dataBuffer, err => {
|
fs.writeFile(filePath, imageDecoded.dataBuffer, (err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return reject("ImageDataURI :: Error :: " + JSON.stringify(err, null, 4));
|
return reject("ImageDataURI :: Error :: " + JSON.stringify(err, null, 4));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,7 +15,7 @@ const jobs = [
|
|||||||
interval: "*/5 * * * *",
|
interval: "*/5 * * * *",
|
||||||
jobFunc: incrementalVacuum,
|
jobFunc: incrementalVacuum,
|
||||||
croner: null,
|
croner: null,
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,11 +32,10 @@ const initBackgroundJobs = async function () {
|
|||||||
name: job.name,
|
name: job.name,
|
||||||
timezone,
|
timezone,
|
||||||
},
|
},
|
||||||
job.jobFunc,
|
job.jobFunc
|
||||||
);
|
);
|
||||||
job.croner = cornerJob;
|
job.croner = cornerJob;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,5 +53,5 @@ const stopBackgroundJobs = function () {
|
|||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
initBackgroundJobs,
|
initBackgroundJobs,
|
||||||
stopBackgroundJobs
|
stopBackgroundJobs,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -31,23 +31,22 @@ const clearOldData = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (parsedPeriod < 1) {
|
if (parsedPeriod < 1) {
|
||||||
log.info("clearOldData", `Data deletion has been disabled as period is less than 1. Period is ${parsedPeriod} days.`);
|
log.info(
|
||||||
|
"clearOldData",
|
||||||
|
`Data deletion has been disabled as period is less than 1. Period is ${parsedPeriod} days.`
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
log.debug("clearOldData", `Clearing Data older than ${parsedPeriod} days...`);
|
log.debug("clearOldData", `Clearing Data older than ${parsedPeriod} days...`);
|
||||||
const sqlHourOffset = Database.sqlHourOffset();
|
const sqlHourOffset = Database.sqlHourOffset();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Heartbeat
|
// Heartbeat
|
||||||
await R.exec("DELETE FROM heartbeat WHERE time < " + sqlHourOffset, [
|
await R.exec("DELETE FROM heartbeat WHERE time < " + sqlHourOffset, [parsedPeriod * -24]);
|
||||||
parsedPeriod * -24,
|
|
||||||
]);
|
|
||||||
|
|
||||||
let timestamp = dayjs().subtract(parsedPeriod, "day").utc().startOf("day").unix();
|
let timestamp = dayjs().subtract(parsedPeriod, "day").utc().startOf("day").unix();
|
||||||
|
|
||||||
// stat_daily
|
// stat_daily
|
||||||
await R.exec("DELETE FROM stat_daily WHERE timestamp < ? ", [
|
await R.exec("DELETE FROM stat_daily WHERE timestamp < ? ", [timestamp]);
|
||||||
timestamp,
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (Database.dbConfig.type === "sqlite") {
|
if (Database.dbConfig.type === "sqlite") {
|
||||||
await R.exec("PRAGMA optimize;");
|
await R.exec("PRAGMA optimize;");
|
||||||
|
|||||||
@ -7,10 +7,12 @@ const { Notification } = require("../notification");
|
|||||||
const { default: NodeFetchCache, MemoryCache } = require("node-fetch-cache");
|
const { default: NodeFetchCache, MemoryCache } = require("node-fetch-cache");
|
||||||
const TranslatableError = require("../translatable-error");
|
const TranslatableError = require("../translatable-error");
|
||||||
|
|
||||||
const cachedFetch = process.env.NODE_ENV ? NodeFetchCache.create({
|
const cachedFetch = process.env.NODE_ENV
|
||||||
// cache for 8h
|
? NodeFetchCache.create({
|
||||||
cache: new MemoryCache({ ttl: 1000 * 60 * 60 * 8 })
|
// cache for 8h
|
||||||
}) : fetch;
|
cache: new MemoryCache({ ttl: 1000 * 60 * 60 * 8 }),
|
||||||
|
})
|
||||||
|
: fetch;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the RDAP server for a given TLD
|
* Find the RDAP server for a given TLD
|
||||||
@ -28,7 +30,7 @@ async function getRdapServer(tld) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const service of rdapList["services"]) {
|
for (const service of rdapList["services"]) {
|
||||||
const [ tlds, urls ] = service;
|
const [tlds, urls] = service;
|
||||||
if (tlds.includes(tld)) {
|
if (tlds.includes(tld)) {
|
||||||
return urls[0];
|
return urls[0];
|
||||||
}
|
}
|
||||||
@ -108,7 +110,7 @@ class DomainExpiry extends BeanModel {
|
|||||||
* @returns {Promise<DomainExpiry>} Domain bean
|
* @returns {Promise<DomainExpiry>} Domain bean
|
||||||
*/
|
*/
|
||||||
static async findByName(domain) {
|
static async findByName(domain) {
|
||||||
return R.findOne("domain_expiry", "domain = ?", [ domain ]);
|
return R.findOne("domain_expiry", "domain = ?", [domain]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -159,7 +161,7 @@ class DomainExpiry extends BeanModel {
|
|||||||
if (!tld.domain) {
|
if (!tld.domain) {
|
||||||
throw new TranslatableError("domain_expiry_unsupported_invalid_domain", { hostname: tld.hostname });
|
throw new TranslatableError("domain_expiry_unsupported_invalid_domain", { hostname: tld.hostname });
|
||||||
}
|
}
|
||||||
if ( !tld.publicSuffix) {
|
if (!tld.publicSuffix) {
|
||||||
throw new TranslatableError("domain_expiry_unsupported_public_suffix", { publicSuffix: tld.publicSuffix });
|
throw new TranslatableError("domain_expiry_unsupported_public_suffix", { publicSuffix: tld.publicSuffix });
|
||||||
}
|
}
|
||||||
if (tld.isIp) {
|
if (tld.isIp) {
|
||||||
@ -176,9 +178,14 @@ class DomainExpiry extends BeanModel {
|
|||||||
// Only warn when the monitor actually has domain expiry notifications enabled.
|
// Only warn when the monitor actually has domain expiry notifications enabled.
|
||||||
// The edit monitor page calls this method frequently while the user is typing.
|
// The edit monitor page calls this method frequently while the user is typing.
|
||||||
if (Boolean(monitor.domainExpiryNotification)) {
|
if (Boolean(monitor.domainExpiryNotification)) {
|
||||||
log.warn("domain_expiry", `Domain expiry unsupported for '.${tld.publicSuffix}' because its RDAP endpoint is not listed in the IANA database.`);
|
log.warn(
|
||||||
|
"domain_expiry",
|
||||||
|
`Domain expiry unsupported for '.${tld.publicSuffix}' because its RDAP endpoint is not listed in the IANA database.`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
throw new TranslatableError("domain_expiry_unsupported_unsupported_tld_no_rdap_endpoint", { publicSuffix: tld.publicSuffix });
|
throw new TranslatableError("domain_expiry_unsupported_unsupported_tld_no_rdap_endpoint", {
|
||||||
|
publicSuffix: tld.publicSuffix,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -258,7 +265,10 @@ class DomainExpiry extends BeanModel {
|
|||||||
}
|
}
|
||||||
// sanity check if expiry date is valid before calculating days remaining. Should not happen and likely indicates a bug in the code.
|
// sanity check if expiry date is valid before calculating days remaining. Should not happen and likely indicates a bug in the code.
|
||||||
if (!domain.expiry || isNaN(new Date(domain.expiry).getTime())) {
|
if (!domain.expiry || isNaN(new Date(domain.expiry).getTime())) {
|
||||||
log.warn("domain_expiry", `No valid expiry date passed to sendNotifications for ${domainName} (expiry: ${domain.expiry}), skipping notification`);
|
log.warn(
|
||||||
|
"domain_expiry",
|
||||||
|
`No valid expiry date passed to sendNotifications for ${domainName} (expiry: ${domain.expiry}), skipping notification`
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,8 +279,8 @@ class DomainExpiry extends BeanModel {
|
|||||||
let notifyDays = await setting("domainExpiryNotifyDays");
|
let notifyDays = await setting("domainExpiryNotifyDays");
|
||||||
if (notifyDays == null || !Array.isArray(notifyDays)) {
|
if (notifyDays == null || !Array.isArray(notifyDays)) {
|
||||||
// Reset Default
|
// Reset Default
|
||||||
await setSetting("domainExpiryNotifyDays", [ 7, 14, 21 ], "general");
|
await setSetting("domainExpiryNotifyDays", [7, 14, 21], "general");
|
||||||
notifyDays = [ 7, 14, 21 ];
|
notifyDays = [7, 14, 21];
|
||||||
}
|
}
|
||||||
if (Array.isArray(notifyDays)) {
|
if (Array.isArray(notifyDays)) {
|
||||||
// Asc sort to avoid sending multiple notifications if daysRemaining is below multiple targetDays
|
// Asc sort to avoid sending multiple notifications if daysRemaining is below multiple targetDays
|
||||||
|
|||||||
@ -2,7 +2,6 @@ const { BeanModel } = require("redbean-node/dist/bean-model");
|
|||||||
const { R } = require("redbean-node");
|
const { R } = require("redbean-node");
|
||||||
|
|
||||||
class Group extends BeanModel {
|
class Group extends BeanModel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return an object that ready to parse to JSON for public Only show
|
* Return an object that ready to parse to JSON for public Only show
|
||||||
* necessary data to public
|
* necessary data to public
|
||||||
@ -32,14 +31,18 @@ class Group extends BeanModel {
|
|||||||
* @returns {Promise<Bean[]>} List of monitors
|
* @returns {Promise<Bean[]>} List of monitors
|
||||||
*/
|
*/
|
||||||
async getMonitorList() {
|
async getMonitorList() {
|
||||||
return R.convertToBeans("monitor", await R.getAll(`
|
return R.convertToBeans(
|
||||||
|
"monitor",
|
||||||
|
await R.getAll(
|
||||||
|
`
|
||||||
SELECT monitor.*, monitor_group.send_url, monitor_group.custom_url FROM monitor, monitor_group
|
SELECT monitor.*, monitor_group.send_url, monitor_group.custom_url FROM monitor, monitor_group
|
||||||
WHERE monitor.id = monitor_group.monitor_id
|
WHERE monitor.id = monitor_group.monitor_id
|
||||||
AND group_id = ?
|
AND group_id = ?
|
||||||
ORDER BY monitor_group.weight
|
ORDER BY monitor_group.weight
|
||||||
`, [
|
`,
|
||||||
this.id,
|
[this.id]
|
||||||
]));
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,6 @@ const { BeanModel } = require("redbean-node/dist/bean-model");
|
|||||||
* 3 = MAINTENANCE
|
* 3 = MAINTENANCE
|
||||||
*/
|
*/
|
||||||
class Heartbeat extends BeanModel {
|
class Heartbeat extends BeanModel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return an object that ready to parse to JSON for public
|
* Return an object that ready to parse to JSON for public
|
||||||
* Only show necessary data to public
|
* Only show necessary data to public
|
||||||
@ -18,7 +17,7 @@ class Heartbeat extends BeanModel {
|
|||||||
return {
|
return {
|
||||||
status: this.status,
|
status: this.status,
|
||||||
time: this.time,
|
time: this.time,
|
||||||
msg: "", // Hide for public
|
msg: "", // Hide for public
|
||||||
ping: this.ping,
|
ping: this.ping,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -39,7 +38,6 @@ class Heartbeat extends BeanModel {
|
|||||||
retries: this._retries,
|
retries: this._retries,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Heartbeat;
|
module.exports = Heartbeat;
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
const { BeanModel } = require("redbean-node/dist/bean-model");
|
const { BeanModel } = require("redbean-node/dist/bean-model");
|
||||||
|
|
||||||
class Incident extends BeanModel {
|
class Incident extends BeanModel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return an object that ready to parse to JSON for public
|
* Return an object that ready to parse to JSON for public
|
||||||
* Only show necessary data to public
|
* Only show necessary data to public
|
||||||
|
|||||||
@ -7,14 +7,12 @@ const { UptimeKumaServer } = require("../uptime-kuma-server");
|
|||||||
const apicache = require("../modules/apicache");
|
const apicache = require("../modules/apicache");
|
||||||
|
|
||||||
class Maintenance extends BeanModel {
|
class Maintenance extends BeanModel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return an object that ready to parse to JSON for public
|
* Return an object that ready to parse to JSON for public
|
||||||
* Only show necessary data to public
|
* Only show necessary data to public
|
||||||
* @returns {Promise<object>} Object ready to parse
|
* @returns {Promise<object>} Object ready to parse
|
||||||
*/
|
*/
|
||||||
async toPublicJSON() {
|
async toPublicJSON() {
|
||||||
|
|
||||||
let dateRange = [];
|
let dateRange = [];
|
||||||
if (this.start_date) {
|
if (this.start_date) {
|
||||||
dateRange.push(this.start_date);
|
dateRange.push(this.start_date);
|
||||||
@ -41,14 +39,14 @@ class Maintenance extends BeanModel {
|
|||||||
active: !!this.active,
|
active: !!this.active,
|
||||||
dateRange: dateRange,
|
dateRange: dateRange,
|
||||||
timeRange: timeRange,
|
timeRange: timeRange,
|
||||||
weekdays: (this.weekdays) ? JSON.parse(this.weekdays) : [],
|
weekdays: this.weekdays ? JSON.parse(this.weekdays) : [],
|
||||||
daysOfMonth: (this.days_of_month) ? JSON.parse(this.days_of_month) : [],
|
daysOfMonth: this.days_of_month ? JSON.parse(this.days_of_month) : [],
|
||||||
timeslotList: [],
|
timeslotList: [],
|
||||||
cron: this.cron,
|
cron: this.cron,
|
||||||
duration: this.duration,
|
duration: this.duration,
|
||||||
durationMinutes: parseInt(this.duration / 60),
|
durationMinutes: parseInt(this.duration / 60),
|
||||||
timezone: await this.getTimezone(), // Only valid timezone
|
timezone: await this.getTimezone(), // Only valid timezone
|
||||||
timezoneOption: this.timezone, // Mainly for dropdown menu, because there is a option "SAME_AS_SERVER"
|
timezoneOption: this.timezone, // Mainly for dropdown menu, because there is a option "SAME_AS_SERVER"
|
||||||
timezoneOffset: await this.getTimezoneOffset(),
|
timezoneOffset: await this.getTimezoneOffset(),
|
||||||
status: await this.getStatus(),
|
status: await this.getStatus(),
|
||||||
};
|
};
|
||||||
@ -202,7 +200,7 @@ class Maintenance extends BeanModel {
|
|||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
static validateCron(cron) {
|
static validateCron(cron) {
|
||||||
let job = new Cron(cron, () => { });
|
let job = new Cron(cron, () => {});
|
||||||
job.stop();
|
job.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,7 +268,7 @@ class Maintenance extends BeanModel {
|
|||||||
if (this.strategy === "recurring-interval") {
|
if (this.strategy === "recurring-interval") {
|
||||||
// For recurring-interval, Croner needs to have interval and startAt
|
// For recurring-interval, Croner needs to have interval and startAt
|
||||||
const startDate = dayjs(this.startDate);
|
const startDate = dayjs(this.startDate);
|
||||||
const [ hour, minute ] = this.startTime.split(":");
|
const [hour, minute] = this.startTime.split(":");
|
||||||
const startDateTime = startDate.hour(hour).minute(minute);
|
const startDateTime = startDate.hour(hour).minute(minute);
|
||||||
|
|
||||||
// Fix #6118, since the startDateTime is optional, it will throw error if the date is null when using toISOString()
|
// Fix #6118, since the startDateTime is optional, it will throw error if the date is null when using toISOString()
|
||||||
@ -279,31 +277,44 @@ class Maintenance extends BeanModel {
|
|||||||
startAt = startDateTime.toISOString();
|
startAt = startDateTime.toISOString();
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
|
|
||||||
this.beanMeta.job = new Cron(this.cron, {
|
this.beanMeta.job = new Cron(
|
||||||
timezone: await this.getTimezone(),
|
this.cron,
|
||||||
startAt,
|
{
|
||||||
}, () => {
|
timezone: await this.getTimezone(),
|
||||||
if (!this.lastStartDate || this.interval_day === 1) {
|
startAt,
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
if (!this.lastStartDate || this.interval_day === 1) {
|
||||||
|
return startEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If last start date is set, it means the maintenance has been started before
|
||||||
|
let lastStartDate = dayjs(this.lastStartDate).subtract(1.1, "hour"); // Subtract 1.1 hour to avoid issues with timezone differences
|
||||||
|
|
||||||
|
// Check if the interval is enough
|
||||||
|
if (current.diff(lastStartDate, "day") < this.interval_day) {
|
||||||
|
log.debug(
|
||||||
|
"maintenance",
|
||||||
|
"Maintenance id: " + this.id + " is still in the window, skipping start event"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug(
|
||||||
|
"maintenance",
|
||||||
|
"Maintenance id: " + this.id + " is not in the window, starting event"
|
||||||
|
);
|
||||||
return startEvent();
|
return startEvent();
|
||||||
}
|
}
|
||||||
|
);
|
||||||
// If last start date is set, it means the maintenance has been started before
|
|
||||||
let lastStartDate = dayjs(this.lastStartDate)
|
|
||||||
.subtract(1.1, "hour"); // Subtract 1.1 hour to avoid issues with timezone differences
|
|
||||||
|
|
||||||
// Check if the interval is enough
|
|
||||||
if (current.diff(lastStartDate, "day") < this.interval_day) {
|
|
||||||
log.debug("maintenance", "Maintenance id: " + this.id + " is still in the window, skipping start event");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
log.debug("maintenance", "Maintenance id: " + this.id + " is not in the window, starting event");
|
|
||||||
return startEvent();
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
this.beanMeta.job = new Cron(this.cron, {
|
this.beanMeta.job = new Cron(
|
||||||
timezone: await this.getTimezone(),
|
this.cron,
|
||||||
}, startEvent);
|
{
|
||||||
|
timezone: await this.getTimezone(),
|
||||||
|
},
|
||||||
|
startEvent
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Continue if the maintenance is still in the window
|
// Continue if the maintenance is still in the window
|
||||||
@ -314,7 +325,6 @@ class Maintenance extends BeanModel {
|
|||||||
log.debug("maintenance", "Maintenance id: " + this.id + " Remaining duration: " + duration + "ms");
|
log.debug("maintenance", "Maintenance id: " + this.id + " Remaining duration: " + duration + "ms");
|
||||||
startEvent(duration);
|
startEvent(duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.error("maintenance", "Error in maintenance id: " + this.id);
|
log.error("maintenance", "Error in maintenance id: " + this.id);
|
||||||
log.error("maintenance", "Cron: " + this.cron);
|
log.error("maintenance", "Cron: " + this.cron);
|
||||||
@ -324,7 +334,6 @@ class Maintenance extends BeanModel {
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
log.error("maintenance", "Maintenance id: " + this.id + " has no cron");
|
log.error("maintenance", "Maintenance id: " + this.id + " has no cron");
|
||||||
}
|
}
|
||||||
@ -486,12 +495,11 @@ class Maintenance extends BeanModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove duplicate
|
// Remove duplicate
|
||||||
dayList = [ ...new Set(dayList) ];
|
dayList = [...new Set(dayList)];
|
||||||
|
|
||||||
this.cron = minute + " " + hour + " " + dayList.join(",") + " * *";
|
this.cron = minute + " " + hour + " " + dayList.join(",") + " * *";
|
||||||
this.duration = this.calcDuration();
|
this.duration = this.calcDuration();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -9,15 +9,22 @@ const { Feed } = require("feed");
|
|||||||
const config = require("../config");
|
const config = require("../config");
|
||||||
const { setting } = require("../util-server");
|
const { setting } = require("../util-server");
|
||||||
|
|
||||||
const { STATUS_PAGE_ALL_DOWN, STATUS_PAGE_ALL_UP, STATUS_PAGE_MAINTENANCE, STATUS_PAGE_PARTIAL_DOWN, UP, MAINTENANCE, DOWN } = require("../../src/util");
|
const {
|
||||||
|
STATUS_PAGE_ALL_DOWN,
|
||||||
|
STATUS_PAGE_ALL_UP,
|
||||||
|
STATUS_PAGE_MAINTENANCE,
|
||||||
|
STATUS_PAGE_PARTIAL_DOWN,
|
||||||
|
UP,
|
||||||
|
MAINTENANCE,
|
||||||
|
DOWN,
|
||||||
|
} = require("../../src/util");
|
||||||
|
|
||||||
class StatusPage extends BeanModel {
|
class StatusPage extends BeanModel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Like this: { "test-uptime.kuma.pet": "default" }
|
* Like this: { "test-uptime.kuma.pet": "default" }
|
||||||
* @type {{}}
|
* @type {{}}
|
||||||
*/
|
*/
|
||||||
static domainMappingList = { };
|
static domainMappingList = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle responses to RSS pages
|
* Handle responses to RSS pages
|
||||||
@ -27,9 +34,7 @@ class StatusPage extends BeanModel {
|
|||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
static async handleStatusPageRSSResponse(response, slug, request) {
|
static async handleStatusPageRSSResponse(response, slug, request) {
|
||||||
let statusPage = await R.findOne("status_page", " slug = ? ", [
|
let statusPage = await R.findOne("status_page", " slug = ? ", [slug]);
|
||||||
slug
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (statusPage) {
|
if (statusPage) {
|
||||||
const feedUrl = await StatusPage.buildRSSUrl(slug, request);
|
const feedUrl = await StatusPage.buildRSSUrl(slug, request);
|
||||||
@ -54,9 +59,7 @@ class StatusPage extends BeanModel {
|
|||||||
slug = "default";
|
slug = "default";
|
||||||
}
|
}
|
||||||
|
|
||||||
let statusPage = await R.findOne("status_page", " slug = ? ", [
|
let statusPage = await R.findOne("status_page", " slug = ? ", [slug]);
|
||||||
slug
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (statusPage) {
|
if (statusPage) {
|
||||||
response.send(await StatusPage.renderHTML(indexHTML, statusPage));
|
response.send(await StatusPage.renderHTML(indexHTML, statusPage));
|
||||||
@ -90,7 +93,7 @@ class StatusPage extends BeanModel {
|
|||||||
updated: new Date(), // optional, default = today
|
updated: new Date(), // optional, default = today
|
||||||
});
|
});
|
||||||
|
|
||||||
heartbeats.forEach(heartbeat => {
|
heartbeats.forEach((heartbeat) => {
|
||||||
feed.addItem({
|
feed.addItem({
|
||||||
title: `${heartbeat.name} is down`,
|
title: `${heartbeat.name} is down`,
|
||||||
description: `${heartbeat.name} has been down since ${heartbeat.time} UTC`,
|
description: `${heartbeat.name} has been down since ${heartbeat.time} UTC`,
|
||||||
@ -153,9 +156,7 @@ class StatusPage extends BeanModel {
|
|||||||
$("meta[name=description]").attr("content", description155);
|
$("meta[name=description]").attr("content", description155);
|
||||||
|
|
||||||
if (statusPage.icon) {
|
if (statusPage.icon) {
|
||||||
$("link[rel=icon]")
|
$("link[rel=icon]").attr("href", statusPage.icon).removeAttr("type");
|
||||||
.attr("href", statusPage.icon)
|
|
||||||
.removeAttr("type");
|
|
||||||
|
|
||||||
$("link[rel=apple-touch-icon]").remove();
|
$("link[rel=apple-touch-icon]").remove();
|
||||||
}
|
}
|
||||||
@ -168,19 +169,19 @@ class StatusPage extends BeanModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// OG Meta Tags
|
// OG Meta Tags
|
||||||
let ogTitle = $("<meta property=\"og:title\" content=\"\" />").attr("content", statusPage.title);
|
let ogTitle = $('<meta property="og:title" content="" />').attr("content", statusPage.title);
|
||||||
head.append(ogTitle);
|
head.append(ogTitle);
|
||||||
|
|
||||||
let ogDescription = $("<meta property=\"og:description\" content=\"\" />").attr("content", description155);
|
let ogDescription = $('<meta property="og:description" content="" />').attr("content", description155);
|
||||||
head.append(ogDescription);
|
head.append(ogDescription);
|
||||||
|
|
||||||
let ogType = $("<meta property=\"og:type\" content=\"website\" />");
|
let ogType = $('<meta property="og:type" content="website" />');
|
||||||
head.append(ogType);
|
head.append(ogType);
|
||||||
|
|
||||||
// Preload data
|
// Preload data
|
||||||
// Add jsesc, fix https://github.com/louislam/uptime-kuma/issues/2186
|
// Add jsesc, fix https://github.com/louislam/uptime-kuma/issues/2186
|
||||||
const escapedJSONObject = jsesc(await StatusPage.getStatusPageData(statusPage), {
|
const escapedJSONObject = jsesc(await StatusPage.getStatusPageData(statusPage), {
|
||||||
"isScriptContext": true
|
isScriptContext: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const script = $(`
|
const script = $(`
|
||||||
@ -219,7 +220,7 @@ class StatusPage extends BeanModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! hasUp) {
|
if (!hasUp) {
|
||||||
status = STATUS_PAGE_ALL_DOWN;
|
status = STATUS_PAGE_ALL_DOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,21 +268,19 @@ class StatusPage extends BeanModel {
|
|||||||
// Public Group List
|
// Public Group List
|
||||||
const showTags = !!statusPage.show_tags;
|
const showTags = !!statusPage.show_tags;
|
||||||
|
|
||||||
const list = await R.find("group", " public = 1 AND status_page_id = ? ORDER BY weight ", [
|
const list = await R.find("group", " public = 1 AND status_page_id = ? ORDER BY weight ", [statusPage.id]);
|
||||||
statusPage.id
|
|
||||||
]);
|
|
||||||
|
|
||||||
let heartbeats = [];
|
let heartbeats = [];
|
||||||
|
|
||||||
for (let groupBean of list) {
|
for (let groupBean of list) {
|
||||||
let monitorGroup = await groupBean.toPublicJSON(showTags, config?.showCertificateExpiry);
|
let monitorGroup = await groupBean.toPublicJSON(showTags, config?.showCertificateExpiry);
|
||||||
for (const monitor of monitorGroup.monitorList) {
|
for (const monitor of monitorGroup.monitorList) {
|
||||||
const heartbeat = await R.findOne("heartbeat", "monitor_id = ? ORDER BY time DESC", [ monitor.id ]);
|
const heartbeat = await R.findOne("heartbeat", "monitor_id = ? ORDER BY time DESC", [monitor.id]);
|
||||||
if (heartbeat) {
|
if (heartbeat) {
|
||||||
heartbeats.push({
|
heartbeats.push({
|
||||||
...monitor,
|
...monitor,
|
||||||
status: heartbeat.status,
|
status: heartbeat.status,
|
||||||
time: heartbeat.time
|
time: heartbeat.time,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -292,11 +291,11 @@ class StatusPage extends BeanModel {
|
|||||||
let statusDescription = StatusPage.getStatusDescription(status);
|
let statusDescription = StatusPage.getStatusDescription(status);
|
||||||
|
|
||||||
// keep only DOWN heartbeats in the RSS feed
|
// keep only DOWN heartbeats in the RSS feed
|
||||||
heartbeats = heartbeats.filter(heartbeat => heartbeat.status === DOWN);
|
heartbeats = heartbeats.filter((heartbeat) => heartbeat.status === DOWN);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
heartbeats,
|
heartbeats,
|
||||||
statusDescription
|
statusDescription,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,9 +308,7 @@ class StatusPage extends BeanModel {
|
|||||||
const config = await statusPage.toPublicJSON();
|
const config = await statusPage.toPublicJSON();
|
||||||
|
|
||||||
// Incident
|
// Incident
|
||||||
let incident = await R.findOne("incident", " pin = 1 AND active = 1 AND status_page_id = ? ", [
|
let incident = await R.findOne("incident", " pin = 1 AND active = 1 AND status_page_id = ? ", [statusPage.id]);
|
||||||
statusPage.id,
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (incident) {
|
if (incident) {
|
||||||
incident = incident.toPublicJSON();
|
incident = incident.toPublicJSON();
|
||||||
@ -323,9 +320,7 @@ class StatusPage extends BeanModel {
|
|||||||
const publicGroupList = [];
|
const publicGroupList = [];
|
||||||
const showTags = !!statusPage.show_tags;
|
const showTags = !!statusPage.show_tags;
|
||||||
|
|
||||||
const list = await R.find("group", " public = 1 AND status_page_id = ? ORDER BY weight ", [
|
const list = await R.find("group", " public = 1 AND status_page_id = ? ORDER BY weight ", [statusPage.id]);
|
||||||
statusPage.id
|
|
||||||
]);
|
|
||||||
|
|
||||||
for (let groupBean of list) {
|
for (let groupBean of list) {
|
||||||
let monitorGroup = await groupBean.toPublicJSON(showTags, config?.showCertificateExpiry);
|
let monitorGroup = await groupBean.toPublicJSON(showTags, config?.showCertificateExpiry);
|
||||||
@ -379,16 +374,13 @@ class StatusPage extends BeanModel {
|
|||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
async updateDomainNameList(domainNameList) {
|
async updateDomainNameList(domainNameList) {
|
||||||
|
|
||||||
if (!Array.isArray(domainNameList)) {
|
if (!Array.isArray(domainNameList)) {
|
||||||
throw new Error("Invalid array");
|
throw new Error("Invalid array");
|
||||||
}
|
}
|
||||||
|
|
||||||
let trx = await R.begin();
|
let trx = await R.begin();
|
||||||
|
|
||||||
await trx.exec("DELETE FROM status_page_cname WHERE status_page_id = ?", [
|
await trx.exec("DELETE FROM status_page_cname WHERE status_page_id = ?", [this.id]);
|
||||||
this.id,
|
|
||||||
]);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (let domain of domainNameList) {
|
for (let domain of domainNameList) {
|
||||||
@ -401,9 +393,7 @@ class StatusPage extends BeanModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If the domain name is used in another status page, delete it
|
// If the domain name is used in another status page, delete it
|
||||||
await trx.exec("DELETE FROM status_page_cname WHERE domain = ?", [
|
await trx.exec("DELETE FROM status_page_cname WHERE domain = ?", [domain]);
|
||||||
domain,
|
|
||||||
]);
|
|
||||||
|
|
||||||
let mapping = trx.dispense("status_page_cname");
|
let mapping = trx.dispense("status_page_cname");
|
||||||
mapping.status_page_id = this.id;
|
mapping.status_page_id = this.id;
|
||||||
@ -494,9 +484,7 @@ class StatusPage extends BeanModel {
|
|||||||
* @returns {Promise<number>} ID of status page
|
* @returns {Promise<number>} ID of status page
|
||||||
*/
|
*/
|
||||||
static async slugToID(slug) {
|
static async slugToID(slug) {
|
||||||
return await R.getCell("SELECT id FROM status_page WHERE slug = ? ", [
|
return await R.getCell("SELECT id FROM status_page WHERE slug = ? ", [slug]);
|
||||||
slug
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -520,21 +508,23 @@ class StatusPage extends BeanModel {
|
|||||||
try {
|
try {
|
||||||
const publicMaintenanceList = [];
|
const publicMaintenanceList = [];
|
||||||
|
|
||||||
let maintenanceIDList = await R.getCol(`
|
let maintenanceIDList = await R.getCol(
|
||||||
|
`
|
||||||
SELECT DISTINCT maintenance_id
|
SELECT DISTINCT maintenance_id
|
||||||
FROM maintenance_status_page
|
FROM maintenance_status_page
|
||||||
WHERE status_page_id = ?
|
WHERE status_page_id = ?
|
||||||
`, [ statusPageId ]);
|
`,
|
||||||
|
[statusPageId]
|
||||||
|
);
|
||||||
|
|
||||||
for (const maintenanceID of maintenanceIDList) {
|
for (const maintenanceID of maintenanceIDList) {
|
||||||
let maintenance = UptimeKumaServer.getInstance().getMaintenance(maintenanceID);
|
let maintenance = UptimeKumaServer.getInstance().getMaintenance(maintenanceID);
|
||||||
if (maintenance && await maintenance.isUnderMaintenance()) {
|
if (maintenance && (await maintenance.isUnderMaintenance())) {
|
||||||
publicMaintenanceList.push(await maintenance.toPublicJSON());
|
publicMaintenanceList.push(await maintenance.toPublicJSON());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return publicMaintenanceList;
|
return publicMaintenanceList;
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
const { BeanModel } = require("redbean-node/dist/bean-model");
|
const { BeanModel } = require("redbean-node/dist/bean-model");
|
||||||
|
|
||||||
class Tag extends BeanModel {
|
class Tag extends BeanModel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return an object that ready to parse to JSON
|
* Return an object that ready to parse to JSON
|
||||||
* @returns {object} Object ready to parse
|
* @returns {object} Object ready to parse
|
||||||
|
|||||||
@ -15,7 +15,7 @@ class User extends BeanModel {
|
|||||||
static async resetPassword(userID, newPassword) {
|
static async resetPassword(userID, newPassword) {
|
||||||
await R.exec("UPDATE `user` SET password = ? WHERE id = ? ", [
|
await R.exec("UPDATE `user` SET password = ? WHERE id = ? ", [
|
||||||
await passwordHash.generate(newPassword),
|
await passwordHash.generate(newPassword),
|
||||||
userID
|
userID,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,10 +27,7 @@ class User extends BeanModel {
|
|||||||
async resetPassword(newPassword) {
|
async resetPassword(newPassword) {
|
||||||
const hashedPassword = await passwordHash.generate(newPassword);
|
const hashedPassword = await passwordHash.generate(newPassword);
|
||||||
|
|
||||||
await R.exec("UPDATE `user` SET password = ? WHERE id = ? ", [
|
await R.exec("UPDATE `user` SET password = ? WHERE id = ? ", [hashedPassword, this.id]);
|
||||||
hashedPassword,
|
|
||||||
this.id
|
|
||||||
]);
|
|
||||||
|
|
||||||
this.password = hashedPassword;
|
this.password = hashedPassword;
|
||||||
}
|
}
|
||||||
@ -42,12 +39,14 @@ class User extends BeanModel {
|
|||||||
* @returns {string} the JsonWebToken as a string
|
* @returns {string} the JsonWebToken as a string
|
||||||
*/
|
*/
|
||||||
static createJWT(user, jwtSecret) {
|
static createJWT(user, jwtSecret) {
|
||||||
return jwt.sign({
|
return jwt.sign(
|
||||||
username: user.username,
|
{
|
||||||
h: shake256(user.password, SHAKE256_LENGTH),
|
username: user.username,
|
||||||
}, jwtSecret);
|
h: shake256(user.password, SHAKE256_LENGTH),
|
||||||
|
},
|
||||||
|
jwtSecret
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = User;
|
module.exports = User;
|
||||||
|
|||||||
@ -146,7 +146,7 @@ function ApiCache() {
|
|||||||
let groupName = req.apicacheGroup;
|
let groupName = req.apicacheGroup;
|
||||||
|
|
||||||
if (groupName) {
|
if (groupName) {
|
||||||
debug("group detected \"" + groupName + "\"");
|
debug('group detected "' + groupName + '"');
|
||||||
let group = (index.groups[groupName] = index.groups[groupName] || []);
|
let group = (index.groups[groupName] = index.groups[groupName] || []);
|
||||||
group.unshift(key);
|
group.unshift(key);
|
||||||
}
|
}
|
||||||
@ -219,9 +219,12 @@ function ApiCache() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add automatic cache clearing from duration, includes max limit on setTimeout
|
// add automatic cache clearing from duration, includes max limit on setTimeout
|
||||||
timers[key] = setTimeout(function () {
|
timers[key] = setTimeout(
|
||||||
instance.clear(key, true);
|
function () {
|
||||||
}, Math.min(duration, 2147483647));
|
instance.clear(key, true);
|
||||||
|
},
|
||||||
|
Math.min(duration, 2147483647)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -246,10 +249,7 @@ function ApiCache() {
|
|||||||
oldContent = !Buffer.alloc ? new Buffer(0) : Buffer.alloc(0);
|
oldContent = !Buffer.alloc ? new Buffer(0) : Buffer.alloc(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
res._apicache.content = Buffer.concat(
|
res._apicache.content = Buffer.concat([oldContent, content], oldContent.length + content.length);
|
||||||
[oldContent, content],
|
|
||||||
oldContent.length + content.length
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
res._apicache.content = content;
|
res._apicache.content = content;
|
||||||
}
|
}
|
||||||
@ -268,7 +268,7 @@ function ApiCache() {
|
|||||||
* @param {function(Object, Object):boolean} toggle
|
* @param {function(Object, Object):boolean} toggle
|
||||||
*/
|
*/
|
||||||
function makeResponseCacheable(req, res, next, key, duration, strDuration, toggle) {
|
function makeResponseCacheable(req, res, next, key, duration, strDuration, toggle) {
|
||||||
// monkeypatch res.end to create cache object
|
// monkeypatch res.end to create cache object
|
||||||
res._apicache = {
|
res._apicache = {
|
||||||
write: res.write,
|
write: res.write,
|
||||||
writeHead: res.writeHead,
|
writeHead: res.writeHead,
|
||||||
@ -310,17 +310,12 @@ function ApiCache() {
|
|||||||
if (res._apicache.cacheable && res._apicache.content) {
|
if (res._apicache.cacheable && res._apicache.content) {
|
||||||
addIndexEntries(key, req);
|
addIndexEntries(key, req);
|
||||||
let headers = res._apicache.headers || getSafeHeaders(res);
|
let headers = res._apicache.headers || getSafeHeaders(res);
|
||||||
let cacheObject = createCacheObject(
|
let cacheObject = createCacheObject(res.statusCode, headers, res._apicache.content, encoding);
|
||||||
res.statusCode,
|
|
||||||
headers,
|
|
||||||
res._apicache.content,
|
|
||||||
encoding
|
|
||||||
);
|
|
||||||
cacheResponse(key, cacheObject, duration);
|
cacheResponse(key, cacheObject, duration);
|
||||||
|
|
||||||
// display log entry
|
// display log entry
|
||||||
let elapsed = new Date() - req.apicacheTimer;
|
let elapsed = new Date() - req.apicacheTimer;
|
||||||
debug("adding cache entry for \"" + key + "\" @ " + strDuration, logDuration(elapsed));
|
debug('adding cache entry for "' + key + '" @ ' + strDuration, logDuration(elapsed));
|
||||||
debug("_apicache.headers: ", res._apicache.headers);
|
debug("_apicache.headers: ", res._apicache.headers);
|
||||||
debug("res.getHeaders(): ", getSafeHeaders(res));
|
debug("res.getHeaders(): ", getSafeHeaders(res));
|
||||||
debug("cacheObject: ", cacheObject);
|
debug("cacheObject: ", cacheObject);
|
||||||
@ -366,8 +361,7 @@ function ApiCache() {
|
|||||||
// unstringify buffers
|
// unstringify buffers
|
||||||
let data = cacheObject.data;
|
let data = cacheObject.data;
|
||||||
if (data && data.type === "Buffer") {
|
if (data && data.type === "Buffer") {
|
||||||
data =
|
data = typeof data.data === "number" ? new Buffer.alloc(data.data) : new Buffer.from(data.data);
|
||||||
typeof data.data === "number" ? new Buffer.alloc(data.data) : new Buffer.from(data.data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// test Etag against If-None-Match for 304
|
// test Etag against If-None-Match for 304
|
||||||
@ -402,10 +396,10 @@ function ApiCache() {
|
|||||||
let redis = globalOptions.redisClient;
|
let redis = globalOptions.redisClient;
|
||||||
|
|
||||||
if (group) {
|
if (group) {
|
||||||
debug("clearing group \"" + target + "\"");
|
debug('clearing group "' + target + '"');
|
||||||
|
|
||||||
group.forEach(function (key) {
|
group.forEach(function (key) {
|
||||||
debug("clearing cached entry for \"" + key + "\"");
|
debug('clearing cached entry for "' + key + '"');
|
||||||
clearTimeout(timers[key]);
|
clearTimeout(timers[key]);
|
||||||
delete timers[key];
|
delete timers[key];
|
||||||
if (!globalOptions.redisClient) {
|
if (!globalOptions.redisClient) {
|
||||||
@ -414,7 +408,7 @@ function ApiCache() {
|
|||||||
try {
|
try {
|
||||||
redis.del(key);
|
redis.del(key);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("[apicache] error in redis.del(\"" + key + "\")");
|
console.log('[apicache] error in redis.del("' + key + '")');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
index.all = index.all.filter(doesntMatch(key));
|
index.all = index.all.filter(doesntMatch(key));
|
||||||
@ -422,7 +416,7 @@ function ApiCache() {
|
|||||||
|
|
||||||
delete index.groups[target];
|
delete index.groups[target];
|
||||||
} else if (target) {
|
} else if (target) {
|
||||||
debug("clearing " + (isAutomatic ? "expired" : "cached") + " entry for \"" + target + "\"");
|
debug("clearing " + (isAutomatic ? "expired" : "cached") + ' entry for "' + target + '"');
|
||||||
clearTimeout(timers[target]);
|
clearTimeout(timers[target]);
|
||||||
delete timers[target];
|
delete timers[target];
|
||||||
// clear actual cached entry
|
// clear actual cached entry
|
||||||
@ -432,7 +426,7 @@ function ApiCache() {
|
|||||||
try {
|
try {
|
||||||
redis.del(target);
|
redis.del(target);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("[apicache] error in redis.del(\"" + target + "\")");
|
console.log('[apicache] error in redis.del("' + target + '")');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -461,7 +455,7 @@ function ApiCache() {
|
|||||||
try {
|
try {
|
||||||
redis.del(key);
|
redis.del(key);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("[apicache] error in redis.del(\"" + key + "\")");
|
console.log('[apicache] error in redis.del("' + key + '")');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -511,15 +505,15 @@ function ApiCache() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return cache performance statistics (hit rate). Suitable for
|
* Return cache performance statistics (hit rate). Suitable for
|
||||||
* putting into a route:
|
* putting into a route:
|
||||||
* <code>
|
* <code>
|
||||||
* app.get('/api/cache/performance', (req, res) => {
|
* app.get('/api/cache/performance', (req, res) => {
|
||||||
* res.json(apicache.getPerformance())
|
* res.json(apicache.getPerformance())
|
||||||
* })
|
* })
|
||||||
* </code>
|
* </code>
|
||||||
* @returns {any[]}
|
* @returns {any[]}
|
||||||
*/
|
*/
|
||||||
this.getPerformance = function () {
|
this.getPerformance = function () {
|
||||||
return performanceArray.map(function (p) {
|
return performanceArray.map(function (p) {
|
||||||
return p.report();
|
return p.report();
|
||||||
@ -528,7 +522,7 @@ function ApiCache() {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get index of a group
|
* Get index of a group
|
||||||
* @param {string} group
|
* @param {string} group
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
this.getIndex = function (group) {
|
this.getIndex = function (group) {
|
||||||
@ -543,9 +537,9 @@ function ApiCache() {
|
|||||||
* Express middleware
|
* Express middleware
|
||||||
* @param {(string|number)} strDuration Duration to cache responses
|
* @param {(string|number)} strDuration Duration to cache responses
|
||||||
* for.
|
* for.
|
||||||
* @param {function(Object, Object):boolean} middlewareToggle
|
* @param {function(Object, Object):boolean} middlewareToggle
|
||||||
* @param {Object} localOptions Options for APICache
|
* @param {Object} localOptions Options for APICache
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
this.middleware = function cache(strDuration, middlewareToggle, localOptions) {
|
this.middleware = function cache(strDuration, middlewareToggle, localOptions) {
|
||||||
let duration = instance.getDuration(strDuration);
|
let duration = instance.getDuration(strDuration);
|
||||||
@ -762,8 +756,8 @@ function ApiCache() {
|
|||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
req.headers["x-apicache-bypass"] ||
|
req.headers["x-apicache-bypass"] ||
|
||||||
req.headers["x-apicache-force-fetch"] ||
|
req.headers["x-apicache-force-fetch"] ||
|
||||||
(opt.respectCacheControl && req.headers["cache-control"] == "no-cache")
|
(opt.respectCacheControl && req.headers["cache-control"] == "no-cache")
|
||||||
) {
|
) {
|
||||||
return bypass();
|
return bypass();
|
||||||
}
|
}
|
||||||
@ -830,15 +824,7 @@ function ApiCache() {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
perf.miss(key);
|
perf.miss(key);
|
||||||
return makeResponseCacheable(
|
return makeResponseCacheable(req, res, next, key, duration, strDuration, middlewareToggle);
|
||||||
req,
|
|
||||||
res,
|
|
||||||
next,
|
|
||||||
key,
|
|
||||||
duration,
|
|
||||||
strDuration,
|
|
||||||
middlewareToggle
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -859,7 +845,7 @@ function ApiCache() {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Process options
|
* Process options
|
||||||
* @param {Object} options
|
* @param {Object} options
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
this.options = function (options) {
|
this.options = function (options) {
|
||||||
|
|||||||
@ -1,9 +1,7 @@
|
|||||||
const apicache = require("./apicache");
|
const apicache = require("./apicache");
|
||||||
|
|
||||||
apicache.options({
|
apicache.options({
|
||||||
headerBlacklist: [
|
headerBlacklist: ["cache-control"],
|
||||||
"cache-control"
|
|
||||||
],
|
|
||||||
headers: {
|
headers: {
|
||||||
// Disable client side cache, only server side cache.
|
// Disable client side cache, only server side cache.
|
||||||
// BUG! Not working for the second request
|
// BUG! Not working for the second request
|
||||||
|
|||||||
@ -4,7 +4,7 @@ function MemoryCache() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {string} key Key to store cache as
|
* @param {string} key Key to store cache as
|
||||||
* @param {any} value Value to store
|
* @param {any} value Value to store
|
||||||
* @param {number} time Time to store for
|
* @param {number} time Time to store for
|
||||||
@ -22,7 +22,7 @@ MemoryCache.prototype.add = function (key, value, time, timeoutCallback) {
|
|||||||
timeout: setTimeout(function () {
|
timeout: setTimeout(function () {
|
||||||
instance.delete(key);
|
instance.delete(key);
|
||||||
return timeoutCallback && typeof timeoutCallback === "function" && timeoutCallback(value, key);
|
return timeoutCallback && typeof timeoutCallback === "function" && timeoutCallback(value, key);
|
||||||
}, time)
|
}, time),
|
||||||
};
|
};
|
||||||
|
|
||||||
this.cache[key] = entry;
|
this.cache[key] = entry;
|
||||||
@ -52,7 +52,7 @@ MemoryCache.prototype.delete = function (key) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get value of key
|
* Get value of key
|
||||||
* @param {string} key
|
* @param {string} key
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
MemoryCache.prototype.get = function (key) {
|
MemoryCache.prototype.get = function (key) {
|
||||||
@ -63,7 +63,7 @@ MemoryCache.prototype.get = function (key) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get value of cache entry
|
* Get value of cache entry
|
||||||
* @param {string} key
|
* @param {string} key
|
||||||
* @returns {any}
|
* @returns {any}
|
||||||
*/
|
*/
|
||||||
MemoryCache.prototype.getValue = function (key) {
|
MemoryCache.prototype.getValue = function (key) {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
// Original file https://raw.githubusercontent.com/elasticio/node-ntlm-client/master/lib/flags.js
|
// Original file https://raw.githubusercontent.com/elasticio/node-ntlm-client/master/lib/flags.js
|
||||||
module.exports.NTLMFLAG_NEGOTIATE_UNICODE = 1 << 0;
|
module.exports.NTLMFLAG_NEGOTIATE_UNICODE = 1 << 0;
|
||||||
/* Indicates that Unicode strings are supported for use in security buffer
|
/* Indicates that Unicode strings are supported for use in security buffer
|
||||||
@ -74,4 +74,4 @@ module.exports.NTLMFLAG_NEGOTIATE_KEY_EXCHANGE = 1 << 30;
|
|||||||
/* Indicates that the client will provide an encrypted master key in
|
/* Indicates that the client will provide an encrypted master key in
|
||||||
the "Session Key" field of the Type 3 message. */
|
the "Session Key" field of the Type 3 message. */
|
||||||
module.exports.NTLMFLAG_NEGOTIATE_56 = 1 << 31;
|
module.exports.NTLMFLAG_NEGOTIATE_56 = 1 << 31;
|
||||||
//# sourceMappingURL=flags.js.map
|
//# sourceMappingURL=flags.js.map
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
// Original source at https://github.com/elasticio/node-ntlm-client/blob/master/lib/hash.js
|
// Original source at https://github.com/elasticio/node-ntlm-client/blob/master/lib/hash.js
|
||||||
var crypto = require('crypto');
|
var crypto = require("crypto");
|
||||||
function createLMResponse(challenge, lmhash) {
|
function createLMResponse(challenge, lmhash) {
|
||||||
var buf = new Buffer.alloc(24), pwBuffer = new Buffer.alloc(21).fill(0);
|
var buf = new Buffer.alloc(24),
|
||||||
|
pwBuffer = new Buffer.alloc(21).fill(0);
|
||||||
lmhash.copy(pwBuffer);
|
lmhash.copy(pwBuffer);
|
||||||
calculateDES(pwBuffer.slice(0, 7), challenge).copy(buf);
|
calculateDES(pwBuffer.slice(0, 7), challenge).copy(buf);
|
||||||
calculateDES(pwBuffer.slice(7, 14), challenge).copy(buf, 8);
|
calculateDES(pwBuffer.slice(7, 14), challenge).copy(buf, 8);
|
||||||
@ -10,40 +11,40 @@ function createLMResponse(challenge, lmhash) {
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
function createLMHash(password) {
|
function createLMHash(password) {
|
||||||
var buf = new Buffer.alloc(16), pwBuffer = new Buffer.alloc(14), magicKey = new Buffer.from('KGS!@#$%', 'ascii');
|
var buf = new Buffer.alloc(16),
|
||||||
|
pwBuffer = new Buffer.alloc(14),
|
||||||
|
magicKey = new Buffer.from("KGS!@#$%", "ascii");
|
||||||
if (password.length > 14) {
|
if (password.length > 14) {
|
||||||
buf.fill(0);
|
buf.fill(0);
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
pwBuffer.fill(0);
|
pwBuffer.fill(0);
|
||||||
pwBuffer.write(password.toUpperCase(), 0, 'ascii');
|
pwBuffer.write(password.toUpperCase(), 0, "ascii");
|
||||||
return Buffer.concat([
|
return Buffer.concat([calculateDES(pwBuffer.slice(0, 7), magicKey), calculateDES(pwBuffer.slice(7), magicKey)]);
|
||||||
calculateDES(pwBuffer.slice(0, 7), magicKey),
|
|
||||||
calculateDES(pwBuffer.slice(7), magicKey)
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
function calculateDES(key, message) {
|
function calculateDES(key, message) {
|
||||||
var desKey = new Buffer.alloc(8);
|
var desKey = new Buffer.alloc(8);
|
||||||
desKey[0] = key[0] & 0xFE;
|
desKey[0] = key[0] & 0xfe;
|
||||||
desKey[1] = ((key[0] << 7) & 0xFF) | (key[1] >> 1);
|
desKey[1] = ((key[0] << 7) & 0xff) | (key[1] >> 1);
|
||||||
desKey[2] = ((key[1] << 6) & 0xFF) | (key[2] >> 2);
|
desKey[2] = ((key[1] << 6) & 0xff) | (key[2] >> 2);
|
||||||
desKey[3] = ((key[2] << 5) & 0xFF) | (key[3] >> 3);
|
desKey[3] = ((key[2] << 5) & 0xff) | (key[3] >> 3);
|
||||||
desKey[4] = ((key[3] << 4) & 0xFF) | (key[4] >> 4);
|
desKey[4] = ((key[3] << 4) & 0xff) | (key[4] >> 4);
|
||||||
desKey[5] = ((key[4] << 3) & 0xFF) | (key[5] >> 5);
|
desKey[5] = ((key[4] << 3) & 0xff) | (key[5] >> 5);
|
||||||
desKey[6] = ((key[5] << 2) & 0xFF) | (key[6] >> 6);
|
desKey[6] = ((key[5] << 2) & 0xff) | (key[6] >> 6);
|
||||||
desKey[7] = (key[6] << 1) & 0xFF;
|
desKey[7] = (key[6] << 1) & 0xff;
|
||||||
for (var i = 0; i < 8; i++) {
|
for (var i = 0; i < 8; i++) {
|
||||||
var parity = 0;
|
var parity = 0;
|
||||||
for (var j = 1; j < 8; j++) {
|
for (var j = 1; j < 8; j++) {
|
||||||
parity += (desKey[i] >> j) % 2;
|
parity += (desKey[i] >> j) % 2;
|
||||||
}
|
}
|
||||||
desKey[i] |= (parity % 2) === 0 ? 1 : 0;
|
desKey[i] |= parity % 2 === 0 ? 1 : 0;
|
||||||
}
|
}
|
||||||
var des = crypto.createCipheriv('DES-ECB', desKey, '');
|
var des = crypto.createCipheriv("DES-ECB", desKey, "");
|
||||||
return des.update(message);
|
return des.update(message);
|
||||||
}
|
}
|
||||||
function createNTLMResponse(challenge, ntlmhash) {
|
function createNTLMResponse(challenge, ntlmhash) {
|
||||||
var buf = new Buffer.alloc(24), ntlmBuffer = new Buffer.alloc(21).fill(0);
|
var buf = new Buffer.alloc(24),
|
||||||
|
ntlmBuffer = new Buffer.alloc(21).fill(0);
|
||||||
ntlmhash.copy(ntlmBuffer);
|
ntlmhash.copy(ntlmBuffer);
|
||||||
calculateDES(ntlmBuffer.slice(0, 7), challenge).copy(buf);
|
calculateDES(ntlmBuffer.slice(0, 7), challenge).copy(buf);
|
||||||
calculateDES(ntlmBuffer.slice(7, 14), challenge).copy(buf, 8);
|
calculateDES(ntlmBuffer.slice(7, 14), challenge).copy(buf, 8);
|
||||||
@ -51,21 +52,23 @@ function createNTLMResponse(challenge, ntlmhash) {
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
function createNTLMHash(password) {
|
function createNTLMHash(password) {
|
||||||
var md4sum = crypto.createHash('md4');
|
var md4sum = crypto.createHash("md4");
|
||||||
md4sum.update(new Buffer.from(password, 'ucs2'));
|
md4sum.update(new Buffer.from(password, "ucs2"));
|
||||||
return md4sum.digest();
|
return md4sum.digest();
|
||||||
}
|
}
|
||||||
function createNTLMv2Hash(ntlmhash, username, authTargetName) {
|
function createNTLMv2Hash(ntlmhash, username, authTargetName) {
|
||||||
var hmac = crypto.createHmac('md5', ntlmhash);
|
var hmac = crypto.createHmac("md5", ntlmhash);
|
||||||
hmac.update(new Buffer.from(username.toUpperCase() + authTargetName, 'ucs2'));
|
hmac.update(new Buffer.from(username.toUpperCase() + authTargetName, "ucs2"));
|
||||||
return hmac.digest();
|
return hmac.digest();
|
||||||
}
|
}
|
||||||
function createLMv2Response(type2message, username, ntlmhash, nonce, targetName) {
|
function createLMv2Response(type2message, username, ntlmhash, nonce, targetName) {
|
||||||
var buf = new Buffer.alloc(24), ntlm2hash = createNTLMv2Hash(ntlmhash, username, targetName), hmac = crypto.createHmac('md5', ntlm2hash);
|
var buf = new Buffer.alloc(24),
|
||||||
|
ntlm2hash = createNTLMv2Hash(ntlmhash, username, targetName),
|
||||||
|
hmac = crypto.createHmac("md5", ntlm2hash);
|
||||||
//server challenge
|
//server challenge
|
||||||
type2message.challenge.copy(buf, 8);
|
type2message.challenge.copy(buf, 8);
|
||||||
//client nonce
|
//client nonce
|
||||||
buf.write(nonce || createPseudoRandomValue(16), 16, 'hex');
|
buf.write(nonce || createPseudoRandomValue(16), 16, "hex");
|
||||||
//create hash
|
//create hash
|
||||||
hmac.update(buf.slice(8));
|
hmac.update(buf.slice(8));
|
||||||
var hashedBuffer = hmac.digest();
|
var hashedBuffer = hmac.digest();
|
||||||
@ -73,7 +76,9 @@ function createLMv2Response(type2message, username, ntlmhash, nonce, targetName)
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
function createNTLMv2Response(type2message, username, ntlmhash, nonce, targetName) {
|
function createNTLMv2Response(type2message, username, ntlmhash, nonce, targetName) {
|
||||||
var buf = new Buffer.alloc(48 + type2message.targetInfo.buffer.length), ntlm2hash = createNTLMv2Hash(ntlmhash, username, targetName), hmac = crypto.createHmac('md5', ntlm2hash);
|
var buf = new Buffer.alloc(48 + type2message.targetInfo.buffer.length),
|
||||||
|
ntlm2hash = createNTLMv2Hash(ntlmhash, username, targetName),
|
||||||
|
hmac = crypto.createHmac("md5", ntlm2hash);
|
||||||
//the first 8 bytes are spare to store the hashed value before the blob
|
//the first 8 bytes are spare to store the hashed value before the blob
|
||||||
//server challenge
|
//server challenge
|
||||||
type2message.challenge.copy(buf, 8);
|
type2message.challenge.copy(buf, 8);
|
||||||
@ -86,12 +91,12 @@ function createNTLMv2Response(type2message, username, ntlmhash, nonce, targetNam
|
|||||||
// maybe think about a different solution here
|
// maybe think about a different solution here
|
||||||
// 11644473600000 = diff between 1970 and 1601
|
// 11644473600000 = diff between 1970 and 1601
|
||||||
var timestamp = ((Date.now() + 11644473600000) * 10000).toString(16);
|
var timestamp = ((Date.now() + 11644473600000) * 10000).toString(16);
|
||||||
var timestampLow = Number('0x' + timestamp.substring(Math.max(0, timestamp.length - 8)));
|
var timestampLow = Number("0x" + timestamp.substring(Math.max(0, timestamp.length - 8)));
|
||||||
var timestampHigh = Number('0x' + timestamp.substring(0, Math.max(0, timestamp.length - 8)));
|
var timestampHigh = Number("0x" + timestamp.substring(0, Math.max(0, timestamp.length - 8)));
|
||||||
buf.writeUInt32LE(timestampLow, 24, false);
|
buf.writeUInt32LE(timestampLow, 24, false);
|
||||||
buf.writeUInt32LE(timestampHigh, 28, false);
|
buf.writeUInt32LE(timestampHigh, 28, false);
|
||||||
//random client nonce
|
//random client nonce
|
||||||
buf.write(nonce || createPseudoRandomValue(16), 32, 'hex');
|
buf.write(nonce || createPseudoRandomValue(16), 32, "hex");
|
||||||
//zero
|
//zero
|
||||||
buf.writeUInt32LE(0, 40);
|
buf.writeUInt32LE(0, 40);
|
||||||
//complete target information block from type 2 message
|
//complete target information block from type 2 message
|
||||||
@ -104,7 +109,7 @@ function createNTLMv2Response(type2message, username, ntlmhash, nonce, targetNam
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
function createPseudoRandomValue(length) {
|
function createPseudoRandomValue(length) {
|
||||||
var str = '';
|
var str = "";
|
||||||
while (str.length < length) {
|
while (str.length < length) {
|
||||||
str += crypto.randomInt(16).toString(16);
|
str += crypto.randomInt(16).toString(16);
|
||||||
}
|
}
|
||||||
@ -117,6 +122,6 @@ module.exports = {
|
|||||||
createNTLMResponse: createNTLMResponse,
|
createNTLMResponse: createNTLMResponse,
|
||||||
createLMv2Response: createLMv2Response,
|
createLMv2Response: createLMv2Response,
|
||||||
createNTLMv2Response: createNTLMv2Response,
|
createNTLMv2Response: createNTLMv2Response,
|
||||||
createPseudoRandomValue: createPseudoRandomValue
|
createPseudoRandomValue: createPseudoRandomValue,
|
||||||
};
|
};
|
||||||
//# sourceMappingURL=hash.js.map
|
//# sourceMappingURL=hash.js.map
|
||||||
|
|||||||
@ -1,23 +1,30 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
// Original file https://raw.githubusercontent.com/elasticio/node-ntlm-client/master/lib/ntlm.js
|
// Original file https://raw.githubusercontent.com/elasticio/node-ntlm-client/master/lib/ntlm.js
|
||||||
var os = require('os'), flags = require('./flags'), hash = require('./hash');
|
var os = require("os"),
|
||||||
|
flags = require("./flags"),
|
||||||
|
hash = require("./hash");
|
||||||
var NTLMSIGNATURE = "NTLMSSP\0";
|
var NTLMSIGNATURE = "NTLMSSP\0";
|
||||||
function createType1Message(workstation, target) {
|
function createType1Message(workstation, target) {
|
||||||
var dataPos = 32, pos = 0, buf = new Buffer.alloc(1024);
|
var dataPos = 32,
|
||||||
|
pos = 0,
|
||||||
|
buf = new Buffer.alloc(1024);
|
||||||
workstation = workstation === undefined ? os.hostname() : workstation;
|
workstation = workstation === undefined ? os.hostname() : workstation;
|
||||||
target = target === undefined ? '' : target;
|
target = target === undefined ? "" : target;
|
||||||
//signature
|
//signature
|
||||||
buf.write(NTLMSIGNATURE, pos, NTLMSIGNATURE.length, 'ascii');
|
buf.write(NTLMSIGNATURE, pos, NTLMSIGNATURE.length, "ascii");
|
||||||
pos += NTLMSIGNATURE.length;
|
pos += NTLMSIGNATURE.length;
|
||||||
//message type
|
//message type
|
||||||
buf.writeUInt32LE(1, pos);
|
buf.writeUInt32LE(1, pos);
|
||||||
pos += 4;
|
pos += 4;
|
||||||
//flags
|
//flags
|
||||||
buf.writeUInt32LE(flags.NTLMFLAG_NEGOTIATE_OEM |
|
buf.writeUInt32LE(
|
||||||
flags.NTLMFLAG_REQUEST_TARGET |
|
flags.NTLMFLAG_NEGOTIATE_OEM |
|
||||||
flags.NTLMFLAG_NEGOTIATE_NTLM_KEY |
|
flags.NTLMFLAG_REQUEST_TARGET |
|
||||||
flags.NTLMFLAG_NEGOTIATE_NTLM2_KEY |
|
flags.NTLMFLAG_NEGOTIATE_NTLM_KEY |
|
||||||
flags.NTLMFLAG_NEGOTIATE_ALWAYS_SIGN, pos);
|
flags.NTLMFLAG_NEGOTIATE_NTLM2_KEY |
|
||||||
|
flags.NTLMFLAG_NEGOTIATE_ALWAYS_SIGN,
|
||||||
|
pos
|
||||||
|
);
|
||||||
pos += 4;
|
pos += 4;
|
||||||
//domain security buffer
|
//domain security buffer
|
||||||
buf.writeUInt16LE(target.length, pos);
|
buf.writeUInt16LE(target.length, pos);
|
||||||
@ -27,7 +34,7 @@ function createType1Message(workstation, target) {
|
|||||||
buf.writeUInt32LE(target.length === 0 ? 0 : dataPos, pos);
|
buf.writeUInt32LE(target.length === 0 ? 0 : dataPos, pos);
|
||||||
pos += 4;
|
pos += 4;
|
||||||
if (target.length > 0) {
|
if (target.length > 0) {
|
||||||
dataPos += buf.write(target, dataPos, 'ascii');
|
dataPos += buf.write(target, dataPos, "ascii");
|
||||||
}
|
}
|
||||||
//workstation security buffer
|
//workstation security buffer
|
||||||
buf.writeUInt16LE(workstation.length, pos);
|
buf.writeUInt16LE(workstation.length, pos);
|
||||||
@ -37,40 +44,40 @@ function createType1Message(workstation, target) {
|
|||||||
buf.writeUInt32LE(workstation.length === 0 ? 0 : dataPos, pos);
|
buf.writeUInt32LE(workstation.length === 0 ? 0 : dataPos, pos);
|
||||||
pos += 4;
|
pos += 4;
|
||||||
if (workstation.length > 0) {
|
if (workstation.length > 0) {
|
||||||
dataPos += buf.write(workstation, dataPos, 'ascii');
|
dataPos += buf.write(workstation, dataPos, "ascii");
|
||||||
}
|
}
|
||||||
return 'NTLM ' + buf.toString('base64', 0, dataPos);
|
return "NTLM " + buf.toString("base64", 0, dataPos);
|
||||||
}
|
}
|
||||||
function decodeType2Message(str) {
|
function decodeType2Message(str) {
|
||||||
if (str === undefined) {
|
if (str === undefined) {
|
||||||
throw new Error('Invalid argument');
|
throw new Error("Invalid argument");
|
||||||
}
|
}
|
||||||
//convenience
|
//convenience
|
||||||
if (Object.prototype.toString.call(str) !== '[object String]') {
|
if (Object.prototype.toString.call(str) !== "[object String]") {
|
||||||
if (str.hasOwnProperty('headers') && str.headers.hasOwnProperty('www-authenticate')) {
|
if (str.hasOwnProperty("headers") && str.headers.hasOwnProperty("www-authenticate")) {
|
||||||
str = str.headers['www-authenticate'];
|
str = str.headers["www-authenticate"];
|
||||||
}
|
} else {
|
||||||
else {
|
throw new Error("Invalid argument");
|
||||||
throw new Error('Invalid argument');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var ntlmMatch = /^NTLM ([^,\s]+)/.exec(str);
|
var ntlmMatch = /^NTLM ([^,\s]+)/.exec(str);
|
||||||
if (ntlmMatch) {
|
if (ntlmMatch) {
|
||||||
str = ntlmMatch[1];
|
str = ntlmMatch[1];
|
||||||
}
|
}
|
||||||
var buf = new Buffer.from(str, 'base64'), obj = {};
|
var buf = new Buffer.from(str, "base64"),
|
||||||
|
obj = {};
|
||||||
//check signature
|
//check signature
|
||||||
if (buf.toString('ascii', 0, NTLMSIGNATURE.length) !== NTLMSIGNATURE) {
|
if (buf.toString("ascii", 0, NTLMSIGNATURE.length) !== NTLMSIGNATURE) {
|
||||||
throw new Error('Invalid message signature: ' + str);
|
throw new Error("Invalid message signature: " + str);
|
||||||
}
|
}
|
||||||
//check message type
|
//check message type
|
||||||
if (buf.readUInt32LE(NTLMSIGNATURE.length) !== 2) {
|
if (buf.readUInt32LE(NTLMSIGNATURE.length) !== 2) {
|
||||||
throw new Error('Invalid message type (no type 2)');
|
throw new Error("Invalid message type (no type 2)");
|
||||||
}
|
}
|
||||||
//read flags
|
//read flags
|
||||||
obj.flags = buf.readUInt32LE(20);
|
obj.flags = buf.readUInt32LE(20);
|
||||||
obj.encoding = (obj.flags & flags.NTLMFLAG_NEGOTIATE_OEM) ? 'ascii' : 'ucs2';
|
obj.encoding = obj.flags & flags.NTLMFLAG_NEGOTIATE_OEM ? "ascii" : "ucs2";
|
||||||
obj.version = (obj.flags & flags.NTLMFLAG_NEGOTIATE_NTLM2_KEY) ? 2 : 1;
|
obj.version = obj.flags & flags.NTLMFLAG_NEGOTIATE_NTLM2_KEY ? 2 : 1;
|
||||||
obj.challenge = buf.slice(24, 32);
|
obj.challenge = buf.slice(24, 32);
|
||||||
//read target name
|
//read target name
|
||||||
obj.targetName = (function () {
|
obj.targetName = (function () {
|
||||||
@ -78,10 +85,10 @@ function decodeType2Message(str) {
|
|||||||
//skipping allocated space
|
//skipping allocated space
|
||||||
var offset = buf.readUInt32LE(16);
|
var offset = buf.readUInt32LE(16);
|
||||||
if (length === 0) {
|
if (length === 0) {
|
||||||
return '';
|
return "";
|
||||||
}
|
}
|
||||||
if ((offset + length) > buf.length || offset < 32) {
|
if (offset + length > buf.length || offset < 32) {
|
||||||
throw new Error('Bad type 2 message');
|
throw new Error("Bad type 2 message");
|
||||||
}
|
}
|
||||||
return buf.toString(obj.encoding, offset, offset + length);
|
return buf.toString(obj.encoding, offset, offset + length);
|
||||||
})();
|
})();
|
||||||
@ -97,11 +104,11 @@ function decodeType2Message(str) {
|
|||||||
if (length === 0) {
|
if (length === 0) {
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
if ((offset + length) > buf.length || offset < 32) {
|
if (offset + length > buf.length || offset < 32) {
|
||||||
throw new Error('Bad type 2 message');
|
throw new Error("Bad type 2 message");
|
||||||
}
|
}
|
||||||
var pos = offset;
|
var pos = offset;
|
||||||
while (pos < (offset + length)) {
|
while (pos < offset + length) {
|
||||||
var blockType = buf.readUInt16LE(pos);
|
var blockType = buf.readUInt16LE(pos);
|
||||||
pos += 2;
|
pos += 2;
|
||||||
var blockLength = buf.readUInt16LE(pos);
|
var blockLength = buf.readUInt16LE(pos);
|
||||||
@ -113,39 +120,40 @@ function decodeType2Message(str) {
|
|||||||
var blockTypeStr = void 0;
|
var blockTypeStr = void 0;
|
||||||
switch (blockType) {
|
switch (blockType) {
|
||||||
case 1:
|
case 1:
|
||||||
blockTypeStr = 'SERVER';
|
blockTypeStr = "SERVER";
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
blockTypeStr = 'DOMAIN';
|
blockTypeStr = "DOMAIN";
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
blockTypeStr = 'FQDN';
|
blockTypeStr = "FQDN";
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
blockTypeStr = 'DNS';
|
blockTypeStr = "DNS";
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
blockTypeStr = 'PARENT_DNS';
|
blockTypeStr = "PARENT_DNS";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
blockTypeStr = '';
|
blockTypeStr = "";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (blockTypeStr) {
|
if (blockTypeStr) {
|
||||||
info[blockTypeStr] = buf.toString('ucs2', pos, pos + blockLength);
|
info[blockTypeStr] = buf.toString("ucs2", pos, pos + blockLength);
|
||||||
}
|
}
|
||||||
pos += blockLength;
|
pos += blockLength;
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
parsed: info,
|
parsed: info,
|
||||||
buffer: targetInfoBuffer
|
buffer: targetInfoBuffer,
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
function createType3Message(type2Message, username, password, workstation, target) {
|
function createType3Message(type2Message, username, password, workstation, target) {
|
||||||
var dataPos = 52, buf = new Buffer.alloc(1024);
|
var dataPos = 52,
|
||||||
|
buf = new Buffer.alloc(1024);
|
||||||
if (workstation === undefined) {
|
if (workstation === undefined) {
|
||||||
workstation = os.hostname();
|
workstation = os.hostname();
|
||||||
}
|
}
|
||||||
@ -153,12 +161,15 @@ function createType3Message(type2Message, username, password, workstation, targe
|
|||||||
target = type2Message.targetName;
|
target = type2Message.targetName;
|
||||||
}
|
}
|
||||||
//signature
|
//signature
|
||||||
buf.write(NTLMSIGNATURE, 0, NTLMSIGNATURE.length, 'ascii');
|
buf.write(NTLMSIGNATURE, 0, NTLMSIGNATURE.length, "ascii");
|
||||||
//message type
|
//message type
|
||||||
buf.writeUInt32LE(3, 8);
|
buf.writeUInt32LE(3, 8);
|
||||||
if (type2Message.version === 2) {
|
if (type2Message.version === 2) {
|
||||||
dataPos = 64;
|
dataPos = 64;
|
||||||
var ntlmHash = hash.createNTLMHash(password), nonce = hash.createPseudoRandomValue(16), lmv2 = hash.createLMv2Response(type2Message, username, ntlmHash, nonce, target), ntlmv2 = hash.createNTLMv2Response(type2Message, username, ntlmHash, nonce, target);
|
var ntlmHash = hash.createNTLMHash(password),
|
||||||
|
nonce = hash.createPseudoRandomValue(16),
|
||||||
|
lmv2 = hash.createLMv2Response(type2Message, username, ntlmHash, nonce, target),
|
||||||
|
ntlmv2 = hash.createNTLMv2Response(type2Message, username, ntlmHash, nonce, target);
|
||||||
//lmv2 security buffer
|
//lmv2 security buffer
|
||||||
buf.writeUInt16LE(lmv2.length, 12);
|
buf.writeUInt16LE(lmv2.length, 12);
|
||||||
buf.writeUInt16LE(lmv2.length, 14);
|
buf.writeUInt16LE(lmv2.length, 14);
|
||||||
@ -171,9 +182,11 @@ function createType3Message(type2Message, username, password, workstation, targe
|
|||||||
buf.writeUInt32LE(dataPos, 24);
|
buf.writeUInt32LE(dataPos, 24);
|
||||||
ntlmv2.copy(buf, dataPos);
|
ntlmv2.copy(buf, dataPos);
|
||||||
dataPos += ntlmv2.length;
|
dataPos += ntlmv2.length;
|
||||||
}
|
} else {
|
||||||
else {
|
var lmHash = hash.createLMHash(password),
|
||||||
var lmHash = hash.createLMHash(password), ntlmHash = hash.createNTLMHash(password), lm = hash.createLMResponse(type2Message.challenge, lmHash), ntlm = hash.createNTLMResponse(type2Message.challenge, ntlmHash);
|
ntlmHash = hash.createNTLMHash(password),
|
||||||
|
lm = hash.createLMResponse(type2Message.challenge, lmHash),
|
||||||
|
ntlm = hash.createNTLMResponse(type2Message.challenge, ntlmHash);
|
||||||
//lm security buffer
|
//lm security buffer
|
||||||
buf.writeUInt16LE(lm.length, 12);
|
buf.writeUInt16LE(lm.length, 12);
|
||||||
buf.writeUInt16LE(lm.length, 14);
|
buf.writeUInt16LE(lm.length, 14);
|
||||||
@ -188,18 +201,18 @@ function createType3Message(type2Message, username, password, workstation, targe
|
|||||||
dataPos += ntlm.length;
|
dataPos += ntlm.length;
|
||||||
}
|
}
|
||||||
//target name security buffer
|
//target name security buffer
|
||||||
buf.writeUInt16LE(type2Message.encoding === 'ascii' ? target.length : target.length * 2, 28);
|
buf.writeUInt16LE(type2Message.encoding === "ascii" ? target.length : target.length * 2, 28);
|
||||||
buf.writeUInt16LE(type2Message.encoding === 'ascii' ? target.length : target.length * 2, 30);
|
buf.writeUInt16LE(type2Message.encoding === "ascii" ? target.length : target.length * 2, 30);
|
||||||
buf.writeUInt32LE(dataPos, 32);
|
buf.writeUInt32LE(dataPos, 32);
|
||||||
dataPos += buf.write(target, dataPos, type2Message.encoding);
|
dataPos += buf.write(target, dataPos, type2Message.encoding);
|
||||||
//user name security buffer
|
//user name security buffer
|
||||||
buf.writeUInt16LE(type2Message.encoding === 'ascii' ? username.length : username.length * 2, 36);
|
buf.writeUInt16LE(type2Message.encoding === "ascii" ? username.length : username.length * 2, 36);
|
||||||
buf.writeUInt16LE(type2Message.encoding === 'ascii' ? username.length : username.length * 2, 38);
|
buf.writeUInt16LE(type2Message.encoding === "ascii" ? username.length : username.length * 2, 38);
|
||||||
buf.writeUInt32LE(dataPos, 40);
|
buf.writeUInt32LE(dataPos, 40);
|
||||||
dataPos += buf.write(username, dataPos, type2Message.encoding);
|
dataPos += buf.write(username, dataPos, type2Message.encoding);
|
||||||
//workstation name security buffer
|
//workstation name security buffer
|
||||||
buf.writeUInt16LE(type2Message.encoding === 'ascii' ? workstation.length : workstation.length * 2, 44);
|
buf.writeUInt16LE(type2Message.encoding === "ascii" ? workstation.length : workstation.length * 2, 44);
|
||||||
buf.writeUInt16LE(type2Message.encoding === 'ascii' ? workstation.length : workstation.length * 2, 46);
|
buf.writeUInt16LE(type2Message.encoding === "ascii" ? workstation.length : workstation.length * 2, 46);
|
||||||
buf.writeUInt32LE(dataPos, 48);
|
buf.writeUInt32LE(dataPos, 48);
|
||||||
dataPos += buf.write(workstation, dataPos, type2Message.encoding);
|
dataPos += buf.write(workstation, dataPos, type2Message.encoding);
|
||||||
if (type2Message.version === 2) {
|
if (type2Message.version === 2) {
|
||||||
@ -210,11 +223,11 @@ function createType3Message(type2Message, username, password, workstation, targe
|
|||||||
//flags
|
//flags
|
||||||
buf.writeUInt32LE(type2Message.flags, 60);
|
buf.writeUInt32LE(type2Message.flags, 60);
|
||||||
}
|
}
|
||||||
return 'NTLM ' + buf.toString('base64', 0, dataPos);
|
return "NTLM " + buf.toString("base64", 0, dataPos);
|
||||||
}
|
}
|
||||||
module.exports = {
|
module.exports = {
|
||||||
createType1Message: createType1Message,
|
createType1Message: createType1Message,
|
||||||
decodeType2Message: decodeType2Message,
|
decodeType2Message: decodeType2Message,
|
||||||
createType3Message: createType3Message
|
createType3Message: createType3Message,
|
||||||
};
|
};
|
||||||
//# sourceMappingURL=ntlm.js.map
|
//# sourceMappingURL=ntlm.js.map
|
||||||
|
|||||||
@ -1,62 +1,176 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
var __createBinding =
|
||||||
if (k2 === undefined) k2 = k;
|
(this && this.__createBinding) ||
|
||||||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
(Object.create
|
||||||
}) : (function(o, m, k, k2) {
|
? function (o, m, k, k2) {
|
||||||
if (k2 === undefined) k2 = k;
|
if (k2 === undefined) k2 = k;
|
||||||
o[k2] = m[k];
|
Object.defineProperty(o, k2, {
|
||||||
}));
|
enumerable: true,
|
||||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
get: function () {
|
||||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
return m[k];
|
||||||
}) : function(o, v) {
|
},
|
||||||
o["default"] = v;
|
});
|
||||||
});
|
}
|
||||||
var __importStar = (this && this.__importStar) || function (mod) {
|
: function (o, m, k, k2) {
|
||||||
if (mod && mod.__esModule) return mod;
|
if (k2 === undefined) k2 = k;
|
||||||
var result = {};
|
o[k2] = m[k];
|
||||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
});
|
||||||
__setModuleDefault(result, mod);
|
var __setModuleDefault =
|
||||||
return result;
|
(this && this.__setModuleDefault) ||
|
||||||
};
|
(Object.create
|
||||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
? function (o, v) {
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
}
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
: function (o, v) {
|
||||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
o["default"] = v;
|
||||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
});
|
||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
var __importStar =
|
||||||
});
|
(this && this.__importStar) ||
|
||||||
};
|
function (mod) {
|
||||||
var __generator = (this && this.__generator) || function (thisArg, body) {
|
if (mod && mod.__esModule) return mod;
|
||||||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
var result = {};
|
||||||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
if (mod != null)
|
||||||
function verb(n) { return function (v) { return step([n, v]); }; }
|
for (var k in mod)
|
||||||
function step(op) {
|
if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||||
if (f) throw new TypeError("Generator is already executing.");
|
__setModuleDefault(result, mod);
|
||||||
while (_) try {
|
return result;
|
||||||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
};
|
||||||
if (y = 0, t) op = [op[0] & 2, t.value];
|
var __awaiter =
|
||||||
switch (op[0]) {
|
(this && this.__awaiter) ||
|
||||||
case 0: case 1: t = op; break;
|
function (thisArg, _arguments, P, generator) {
|
||||||
case 4: _.label++; return { value: op[1], done: false };
|
function adopt(value) {
|
||||||
case 5: _.label++; y = op[1]; op = [0]; continue;
|
return value instanceof P
|
||||||
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
? value
|
||||||
default:
|
: new P(function (resolve) {
|
||||||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
resolve(value);
|
||||||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
});
|
||||||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
}
|
||||||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
if (t[2]) _.ops.pop();
|
function fulfilled(value) {
|
||||||
_.trys.pop(); continue;
|
try {
|
||||||
|
step(generator.next(value));
|
||||||
|
} catch (e) {
|
||||||
|
reject(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
op = body.call(thisArg, _);
|
function rejected(value) {
|
||||||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
try {
|
||||||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
step(generator["throw"](value));
|
||||||
}
|
} catch (e) {
|
||||||
};
|
reject(e);
|
||||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
}
|
||||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
}
|
||||||
};
|
function step(result) {
|
||||||
|
result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
|
||||||
|
}
|
||||||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
var __generator =
|
||||||
|
(this && this.__generator) ||
|
||||||
|
function (thisArg, body) {
|
||||||
|
var _ = {
|
||||||
|
label: 0,
|
||||||
|
sent: function () {
|
||||||
|
if (t[0] & 1) throw t[1];
|
||||||
|
return t[1];
|
||||||
|
},
|
||||||
|
trys: [],
|
||||||
|
ops: [],
|
||||||
|
},
|
||||||
|
f,
|
||||||
|
y,
|
||||||
|
t,
|
||||||
|
g;
|
||||||
|
return (
|
||||||
|
(g = { next: verb(0), throw: verb(1), return: verb(2) }),
|
||||||
|
typeof Symbol === "function" &&
|
||||||
|
(g[Symbol.iterator] = function () {
|
||||||
|
return this;
|
||||||
|
}),
|
||||||
|
g
|
||||||
|
);
|
||||||
|
function verb(n) {
|
||||||
|
return function (v) {
|
||||||
|
return step([n, v]);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function step(op) {
|
||||||
|
if (f) throw new TypeError("Generator is already executing.");
|
||||||
|
while (_)
|
||||||
|
try {
|
||||||
|
if (
|
||||||
|
((f = 1),
|
||||||
|
y &&
|
||||||
|
(t =
|
||||||
|
op[0] & 2
|
||||||
|
? y["return"]
|
||||||
|
: op[0]
|
||||||
|
? y["throw"] || ((t = y["return"]) && t.call(y), 0)
|
||||||
|
: y.next) &&
|
||||||
|
!(t = t.call(y, op[1])).done)
|
||||||
|
)
|
||||||
|
return t;
|
||||||
|
if (((y = 0), t)) op = [op[0] & 2, t.value];
|
||||||
|
switch (op[0]) {
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
t = op;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
_.label++;
|
||||||
|
return { value: op[1], done: false };
|
||||||
|
case 5:
|
||||||
|
_.label++;
|
||||||
|
y = op[1];
|
||||||
|
op = [0];
|
||||||
|
continue;
|
||||||
|
case 7:
|
||||||
|
op = _.ops.pop();
|
||||||
|
_.trys.pop();
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
if (
|
||||||
|
!((t = _.trys), (t = t.length > 0 && t[t.length - 1])) &&
|
||||||
|
(op[0] === 6 || op[0] === 2)
|
||||||
|
) {
|
||||||
|
_ = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) {
|
||||||
|
_.label = op[1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (op[0] === 6 && _.label < t[1]) {
|
||||||
|
_.label = t[1];
|
||||||
|
t = op;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (t && _.label < t[2]) {
|
||||||
|
_.label = t[2];
|
||||||
|
_.ops.push(op);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (t[2]) _.ops.pop();
|
||||||
|
_.trys.pop();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
op = body.call(thisArg, _);
|
||||||
|
} catch (e) {
|
||||||
|
op = [6, e];
|
||||||
|
y = 0;
|
||||||
|
} finally {
|
||||||
|
f = t = 0;
|
||||||
|
}
|
||||||
|
if (op[0] & 5) throw op[1];
|
||||||
|
return { value: op[0] ? op[1] : void 0, done: true };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var __importDefault =
|
||||||
|
(this && this.__importDefault) ||
|
||||||
|
function (mod) {
|
||||||
|
return mod && mod.__esModule ? mod : { default: mod };
|
||||||
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.NtlmClient = void 0;
|
exports.NtlmClient = void 0;
|
||||||
var axios_1 = __importDefault(require("axios"));
|
var axios_1 = __importDefault(require("axios"));
|
||||||
@ -65,11 +179,11 @@ var https = __importStar(require("https"));
|
|||||||
var http = __importStar(require("http"));
|
var http = __importStar(require("http"));
|
||||||
var dev_null_1 = __importDefault(require("dev-null"));
|
var dev_null_1 = __importDefault(require("dev-null"));
|
||||||
/**
|
/**
|
||||||
* @param credentials An NtlmCredentials object containing the username and password
|
* @param credentials An NtlmCredentials object containing the username and password
|
||||||
* @param AxiosConfig The Axios config for the instance you wish to create
|
* @param AxiosConfig The Axios config for the instance you wish to create
|
||||||
*
|
*
|
||||||
* @returns This function returns an axios instance configured to use the provided credentials
|
* @returns This function returns an axios instance configured to use the provided credentials
|
||||||
*/
|
*/
|
||||||
function NtlmClient(credentials, AxiosConfig) {
|
function NtlmClient(credentials, AxiosConfig) {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
var config = AxiosConfig !== null && AxiosConfig !== void 0 ? AxiosConfig : {};
|
var config = AxiosConfig !== null && AxiosConfig !== void 0 ? AxiosConfig : {};
|
||||||
@ -80,51 +194,76 @@ function NtlmClient(credentials, AxiosConfig) {
|
|||||||
config.httpsAgent = new https.Agent({ keepAlive: true });
|
config.httpsAgent = new https.Agent({ keepAlive: true });
|
||||||
}
|
}
|
||||||
var client = axios_1.default.create(config);
|
var client = axios_1.default.create(config);
|
||||||
client.interceptors.response.use(function (response) {
|
client.interceptors.response.use(
|
||||||
return response;
|
function (response) {
|
||||||
}, function (err) { return __awaiter(_this, void 0, void 0, function () {
|
return response;
|
||||||
var error, t1Msg, t2Msg, t3Msg, stream_1;
|
},
|
||||||
var _a;
|
function (err) {
|
||||||
return __generator(this, function (_b) {
|
return __awaiter(_this, void 0, void 0, function () {
|
||||||
switch (_b.label) {
|
var error, t1Msg, t2Msg, t3Msg, stream_1;
|
||||||
case 0:
|
var _a;
|
||||||
error = err.response;
|
return __generator(this, function (_b) {
|
||||||
// The header may look like this: `Negotiate, NTLM, Basic realm="itsahiddenrealm.example.net"`Add commentMore actions
|
switch (_b.label) {
|
||||||
// so extract the 'NTLM' part first
|
case 0:
|
||||||
const ntlmheader = error.headers['www-authenticate'].split(',').find(_ => _.match(/ *NTLM/))?.trim() || '';
|
error = err.response;
|
||||||
if (!(error && error.status === 401
|
// The header may look like this: `Negotiate, NTLM, Basic realm="itsahiddenrealm.example.net"`Add commentMore actions
|
||||||
&& error.headers['www-authenticate']
|
// so extract the 'NTLM' part first
|
||||||
&& error.headers['www-authenticate'].includes('NTLM'))) return [3 /*break*/, 3];
|
const ntlmheader =
|
||||||
// This length check is a hack because SharePoint is awkward and will
|
error.headers["www-authenticate"]
|
||||||
// include the Negotiate option when responding with the T2 message
|
.split(",")
|
||||||
// There is nore we could do to ensure we are processing correctly,
|
.find((_) => _.match(/ *NTLM/))
|
||||||
// but this is the easiest option for now
|
?.trim() || "";
|
||||||
if (ntlmheader.length < 50) {
|
if (
|
||||||
t1Msg = ntlm.createType1Message(credentials.workstation, credentials.domain);
|
!(
|
||||||
error.config.headers["Authorization"] = t1Msg;
|
error &&
|
||||||
|
error.status === 401 &&
|
||||||
|
error.headers["www-authenticate"] &&
|
||||||
|
error.headers["www-authenticate"].includes("NTLM")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return [3 /*break*/, 3];
|
||||||
|
// This length check is a hack because SharePoint is awkward and will
|
||||||
|
// include the Negotiate option when responding with the T2 message
|
||||||
|
// There is nore we could do to ensure we are processing correctly,
|
||||||
|
// but this is the easiest option for now
|
||||||
|
if (ntlmheader.length < 50) {
|
||||||
|
t1Msg = ntlm.createType1Message(credentials.workstation, credentials.domain);
|
||||||
|
error.config.headers["Authorization"] = t1Msg;
|
||||||
|
} else {
|
||||||
|
t2Msg = ntlm.decodeType2Message((ntlmheader.match(/^NTLM\s+(.+?)(,|\s+|$)/) || [])[1]);
|
||||||
|
t3Msg = ntlm.createType3Message(
|
||||||
|
t2Msg,
|
||||||
|
credentials.username,
|
||||||
|
credentials.password,
|
||||||
|
credentials.workstation,
|
||||||
|
credentials.domain
|
||||||
|
);
|
||||||
|
error.config.headers["X-retry"] = "false";
|
||||||
|
error.config.headers["Authorization"] = t3Msg;
|
||||||
|
}
|
||||||
|
if (!(error.config.responseType === "stream")) return [3 /*break*/, 2];
|
||||||
|
stream_1 = (_a = err.response) === null || _a === void 0 ? void 0 : _a.data;
|
||||||
|
if (!(stream_1 && !stream_1.readableEnded)) return [3 /*break*/, 2];
|
||||||
|
return [
|
||||||
|
4 /*yield*/,
|
||||||
|
new Promise(function (resolve) {
|
||||||
|
stream_1.pipe((0, dev_null_1.default)());
|
||||||
|
stream_1.once("close", resolve);
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
case 1:
|
||||||
|
_b.sent();
|
||||||
|
_b.label = 2;
|
||||||
|
case 2:
|
||||||
|
return [2 /*return*/, client(error.config)];
|
||||||
|
case 3:
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
else {
|
});
|
||||||
t2Msg = ntlm.decodeType2Message((ntlmheader.match(/^NTLM\s+(.+?)(,|\s+|$)/) || [])[1]);
|
});
|
||||||
t3Msg = ntlm.createType3Message(t2Msg, credentials.username, credentials.password, credentials.workstation, credentials.domain);
|
}
|
||||||
error.config.headers["X-retry"] = "false";
|
);
|
||||||
error.config.headers["Authorization"] = t3Msg;
|
|
||||||
}
|
|
||||||
if (!(error.config.responseType === "stream")) return [3 /*break*/, 2];
|
|
||||||
stream_1 = (_a = err.response) === null || _a === void 0 ? void 0 : _a.data;
|
|
||||||
if (!(stream_1 && !stream_1.readableEnded)) return [3 /*break*/, 2];
|
|
||||||
return [4 /*yield*/, new Promise(function (resolve) {
|
|
||||||
stream_1.pipe((0, dev_null_1.default)());
|
|
||||||
stream_1.once('close', resolve);
|
|
||||||
})];
|
|
||||||
case 1:
|
|
||||||
_b.sent();
|
|
||||||
_b.label = 2;
|
|
||||||
case 2: return [2 /*return*/, client(error.config)];
|
|
||||||
case 3: throw err;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}); });
|
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
exports.NtlmClient = NtlmClient;
|
exports.NtlmClient = NtlmClient;
|
||||||
//# sourceMappingURL=ntlmClient.js.map
|
//# sourceMappingURL=ntlmClient.js.map
|
||||||
|
|||||||
30
server/modules/dayjs/plugin/timezone.d.ts
vendored
30
server/modules/dayjs/plugin/timezone.d.ts
vendored
@ -1,20 +1,20 @@
|
|||||||
import { PluginFunc, ConfigType } from 'dayjs'
|
import { PluginFunc, ConfigType } from "dayjs";
|
||||||
|
|
||||||
declare const plugin: PluginFunc
|
declare const plugin: PluginFunc;
|
||||||
export = plugin
|
export = plugin;
|
||||||
|
|
||||||
declare module 'dayjs' {
|
declare module "dayjs" {
|
||||||
interface Dayjs {
|
interface Dayjs {
|
||||||
tz(timezone?: string, keepLocalTime?: boolean): Dayjs
|
tz(timezone?: string, keepLocalTime?: boolean): Dayjs;
|
||||||
offsetName(type?: 'short' | 'long'): string | undefined
|
offsetName(type?: "short" | "long"): string | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DayjsTimezone {
|
interface DayjsTimezone {
|
||||||
(date: ConfigType, timezone?: string): Dayjs
|
(date: ConfigType, timezone?: string): Dayjs;
|
||||||
(date: ConfigType, format: string, timezone?: string): Dayjs
|
(date: ConfigType, format: string, timezone?: string): Dayjs;
|
||||||
guess(): string
|
guess(): string;
|
||||||
setDefault(timezone?: string): void
|
setDefault(timezone?: string): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tz: DayjsTimezone
|
const tz: DayjsTimezone;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,10 +4,14 @@
|
|||||||
* Source: https://github.com/iamkun/dayjs/tree/dev/src/plugin/utc
|
* Source: https://github.com/iamkun/dayjs/tree/dev/src/plugin/utc
|
||||||
* License: MIT
|
* License: MIT
|
||||||
*/
|
*/
|
||||||
!function (t, e) {
|
!(function (t, e) {
|
||||||
// eslint-disable-next-line no-undef
|
// eslint-disable-next-line no-undef
|
||||||
typeof exports == "object" && typeof module != "undefined" ? module.exports = e() : typeof define == "function" && define.amd ? define(e) : (t = typeof globalThis != "undefined" ? globalThis : t || self).dayjs_plugin_timezone = e();
|
typeof exports == "object" && typeof module != "undefined"
|
||||||
}(this, (function () {
|
? (module.exports = e())
|
||||||
|
: typeof define == "function" && define.amd
|
||||||
|
? define(e)
|
||||||
|
: ((t = typeof globalThis != "undefined" ? globalThis : t || self).dayjs_plugin_timezone = e());
|
||||||
|
})(this, function () {
|
||||||
"use strict";
|
"use strict";
|
||||||
let t = {
|
let t = {
|
||||||
year: 0,
|
year: 0,
|
||||||
@ -15,7 +19,7 @@
|
|||||||
day: 2,
|
day: 2,
|
||||||
hour: 3,
|
hour: 3,
|
||||||
minute: 4,
|
minute: 4,
|
||||||
second: 5
|
second: 5,
|
||||||
};
|
};
|
||||||
let e = {};
|
let e = {};
|
||||||
return function (n, i, o) {
|
return function (n, i, o) {
|
||||||
@ -23,23 +27,28 @@
|
|||||||
let a = function (t, n, i) {
|
let a = function (t, n, i) {
|
||||||
void 0 === i && (i = {});
|
void 0 === i && (i = {});
|
||||||
let o = new Date(t);
|
let o = new Date(t);
|
||||||
let r = function (t, n) {
|
let r = (function (t, n) {
|
||||||
void 0 === n && (n = {});
|
void 0 === n && (n = {});
|
||||||
let i = n.timeZoneName || "short";
|
let i = n.timeZoneName || "short";
|
||||||
let o = t + "|" + i;
|
let o = t + "|" + i;
|
||||||
let r = e[o];
|
let r = e[o];
|
||||||
return r || (r = new Intl.DateTimeFormat("en-US", {
|
return (
|
||||||
hour12: !1,
|
r ||
|
||||||
timeZone: t,
|
((r = new Intl.DateTimeFormat("en-US", {
|
||||||
year: "numeric",
|
hour12: !1,
|
||||||
month: "2-digit",
|
timeZone: t,
|
||||||
day: "2-digit",
|
year: "numeric",
|
||||||
hour: "2-digit",
|
month: "2-digit",
|
||||||
minute: "2-digit",
|
day: "2-digit",
|
||||||
second: "2-digit",
|
hour: "2-digit",
|
||||||
timeZoneName: i
|
minute: "2-digit",
|
||||||
}), e[o] = r), r;
|
second: "2-digit",
|
||||||
}(n, i);
|
timeZoneName: i,
|
||||||
|
})),
|
||||||
|
(e[o] = r)),
|
||||||
|
r
|
||||||
|
);
|
||||||
|
})(n, i);
|
||||||
return r.formatToParts(o);
|
return r.formatToParts(o);
|
||||||
};
|
};
|
||||||
let u = function (e, n) {
|
let u = function (e, n) {
|
||||||
@ -60,56 +69,62 @@
|
|||||||
return (o.utc(v).valueOf() - (h -= h % 1e3)) / 6e4;
|
return (o.utc(v).valueOf() - (h -= h % 1e3)) / 6e4;
|
||||||
};
|
};
|
||||||
let f = i.prototype;
|
let f = i.prototype;
|
||||||
f.tz = function (t, e) {
|
((f.tz = function (t, e) {
|
||||||
void 0 === t && (t = r);
|
void 0 === t && (t = r);
|
||||||
let n = this.utcOffset();
|
let n = this.utcOffset();
|
||||||
let i = this.toDate();
|
let i = this.toDate();
|
||||||
let a = i.toLocaleString("en-US", { timeZone: t }).replace("\u202f", " ");
|
let a = i.toLocaleString("en-US", { timeZone: t }).replace("\u202f", " ");
|
||||||
let u = Math.round((i - new Date(a)) / 1e3 / 60);
|
let u = Math.round((i - new Date(a)) / 1e3 / 60);
|
||||||
let f = o(a).$set("millisecond", this.$ms).utcOffset(15 * -Math.round(i.getTimezoneOffset() / 15) - u, !0);
|
let f = o(a)
|
||||||
|
.$set("millisecond", this.$ms)
|
||||||
|
.utcOffset(15 * -Math.round(i.getTimezoneOffset() / 15) - u, !0);
|
||||||
if (e) {
|
if (e) {
|
||||||
let s = f.utcOffset();
|
let s = f.utcOffset();
|
||||||
f = f.add(n - s, "minute");
|
f = f.add(n - s, "minute");
|
||||||
}
|
}
|
||||||
return f.$x.$timezone = t, f;
|
return ((f.$x.$timezone = t), f);
|
||||||
}, f.offsetName = function (t) {
|
}),
|
||||||
let e = this.$x.$timezone || o.tz.guess();
|
(f.offsetName = function (t) {
|
||||||
let n = a(this.valueOf(), e, { timeZoneName: t }).find((function (t) {
|
let e = this.$x.$timezone || o.tz.guess();
|
||||||
return t.type.toLowerCase() === "timezonename";
|
let n = a(this.valueOf(), e, { timeZoneName: t }).find(function (t) {
|
||||||
|
return t.type.toLowerCase() === "timezonename";
|
||||||
|
});
|
||||||
|
return n && n.value;
|
||||||
}));
|
}));
|
||||||
return n && n.value;
|
|
||||||
};
|
|
||||||
let s = f.startOf;
|
let s = f.startOf;
|
||||||
f.startOf = function (t, e) {
|
((f.startOf = function (t, e) {
|
||||||
if (!this.$x || !this.$x.$timezone) {
|
if (!this.$x || !this.$x.$timezone) {
|
||||||
return s.call(this, t, e);
|
return s.call(this, t, e);
|
||||||
}
|
}
|
||||||
let n = o(this.format("YYYY-MM-DD HH:mm:ss:SSS"));
|
let n = o(this.format("YYYY-MM-DD HH:mm:ss:SSS"));
|
||||||
return s.call(n, t, e).tz(this.$x.$timezone, !0);
|
return s.call(n, t, e).tz(this.$x.$timezone, !0);
|
||||||
}, o.tz = function (t, e, n) {
|
}),
|
||||||
let i = n && e;
|
(o.tz = function (t, e, n) {
|
||||||
let a = n || e || r;
|
let i = n && e;
|
||||||
let f = u(+o(), a);
|
let a = n || e || r;
|
||||||
if (typeof t != "string") {
|
let f = u(+o(), a);
|
||||||
return o(t).tz(a);
|
if (typeof t != "string") {
|
||||||
}
|
return o(t).tz(a);
|
||||||
let s = function (t, e, n) {
|
|
||||||
let i = t - 60 * e * 1e3;
|
|
||||||
let o = u(i, n);
|
|
||||||
if (e === o) {
|
|
||||||
return [ i, e ];
|
|
||||||
}
|
}
|
||||||
let r = u(i -= 60 * (o - e) * 1e3, n);
|
let s = (function (t, e, n) {
|
||||||
return o === r ? [ i, o ] : [ t - 60 * Math.min(o, r) * 1e3, Math.max(o, r) ];
|
let i = t - 60 * e * 1e3;
|
||||||
}(o.utc(t, i).valueOf(), f, a);
|
let o = u(i, n);
|
||||||
let m = s[0];
|
if (e === o) {
|
||||||
let c = s[1];
|
return [i, e];
|
||||||
let d = o(m).utcOffset(c);
|
}
|
||||||
return d.$x.$timezone = a, d;
|
let r = u((i -= 60 * (o - e) * 1e3), n);
|
||||||
}, o.tz.guess = function () {
|
return o === r ? [i, o] : [t - 60 * Math.min(o, r) * 1e3, Math.max(o, r)];
|
||||||
return Intl.DateTimeFormat().resolvedOptions().timeZone;
|
})(o.utc(t, i).valueOf(), f, a);
|
||||||
}, o.tz.setDefault = function (t) {
|
let m = s[0];
|
||||||
r = t;
|
let c = s[1];
|
||||||
};
|
let d = o(m).utcOffset(c);
|
||||||
|
return ((d.$x.$timezone = a), d);
|
||||||
|
}),
|
||||||
|
(o.tz.guess = function () {
|
||||||
|
return Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||||
|
}),
|
||||||
|
(o.tz.setDefault = function (t) {
|
||||||
|
r = t;
|
||||||
|
}));
|
||||||
};
|
};
|
||||||
}));
|
});
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user