Merge branch 'next' into dependabot/npm_and_yarn/integration-tests/next/selenium-webdriver-4.41.0
This commit is contained in:
commit
a8c6366bdd
|
|
@ -7,14 +7,20 @@ updates:
|
|||
interval: "weekly"
|
||||
target-branch: "next"
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- "3k"
|
||||
- "dependencies"
|
||||
|
||||
# npm updates for frontend - targeting "release/2k" branch
|
||||
# npm updates for frontend - targeting "release/2k" branch (security updates only)
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/frontend"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
target-branch: "release/2k"
|
||||
open-pull-requests-limit: 10
|
||||
open-pull-requests-limit: 0
|
||||
labels:
|
||||
- "2k"
|
||||
- "dependencies"
|
||||
|
||||
# npm updates for integration-tests - targeting "next" branch
|
||||
- package-ecosystem: "npm"
|
||||
|
|
@ -23,14 +29,20 @@ updates:
|
|||
interval: "weekly"
|
||||
target-branch: "next"
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- "3k"
|
||||
- "dependencies"
|
||||
|
||||
# npm updates for integration-tests - targeting "release/2k" branch
|
||||
# npm updates for integration-tests - targeting "release/2k" branch (security updates only)
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/integration-tests"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
target-branch: "release/2k"
|
||||
open-pull-requests-limit: 10
|
||||
open-pull-requests-limit: 0
|
||||
labels:
|
||||
- "2k"
|
||||
- "dependencies"
|
||||
|
||||
# Go modules updates for service - targeting "next" branch
|
||||
- package-ecosystem: "gomod"
|
||||
|
|
@ -39,14 +51,20 @@ updates:
|
|||
interval: "weekly"
|
||||
target-branch: "next"
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- "3k"
|
||||
- "dependencies"
|
||||
|
||||
# Go modules updates for service - targeting "release/2k" branch
|
||||
# Go modules updates for service - targeting "release/2k" branch (security updates only)
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "/service"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
target-branch: "release/2k"
|
||||
open-pull-requests-limit: 10
|
||||
open-pull-requests-limit: 0
|
||||
labels:
|
||||
- "2k"
|
||||
- "dependencies"
|
||||
|
||||
# Go modules updates for lang - targeting "next" branch
|
||||
- package-ecosystem: "gomod"
|
||||
|
|
@ -55,14 +73,20 @@ updates:
|
|||
interval: "weekly"
|
||||
target-branch: "next"
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- "3k"
|
||||
- "dependencies"
|
||||
|
||||
# Go modules updates for lang - targeting "release/2k" branch
|
||||
# Go modules updates for lang - targeting "release/2k" branch (security updates only)
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "/lang"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
target-branch: "release/2k"
|
||||
open-pull-requests-limit: 10
|
||||
open-pull-requests-limit: 0
|
||||
labels:
|
||||
- "2k"
|
||||
- "dependencies"
|
||||
|
||||
# Docker updates - targeting "next" branch
|
||||
- package-ecosystem: "docker"
|
||||
|
|
@ -71,12 +95,18 @@ updates:
|
|||
interval: "weekly"
|
||||
target-branch: "next"
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- "3k"
|
||||
- "dependencies"
|
||||
|
||||
# Docker updates - targeting "release/2k" branch
|
||||
# Docker updates - targeting "release/2k" branch (security updates only)
|
||||
- package-ecosystem: "docker"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
target-branch: "release/2k"
|
||||
open-pull-requests-limit: 10
|
||||
open-pull-requests-limit: 0
|
||||
labels:
|
||||
- "2k"
|
||||
- "dependencies"
|
||||
|
||||
|
|
|
|||
|
|
@ -87,6 +87,9 @@ jobs:
|
|||
with:
|
||||
install-only: true
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: release
|
||||
if: github.ref_type != 'tag'
|
||||
uses: cycjimmy/semantic-release-action@v4
|
||||
|
|
|
|||
|
|
@ -9,6 +9,19 @@ repos:
|
|||
- id: end-of-file-fixer
|
||||
- id: check-yaml
|
||||
- id: check-added-large-files
|
||||
- id: check-merge-conflict
|
||||
- id: detect-private-key
|
||||
- id: mixed-line-ending
|
||||
args: ['--fix', 'lf']
|
||||
- id: check-json
|
||||
exclude: |
|
||||
(?x)^(
|
||||
service/internal/entities/testdata/.*\.json|
|
||||
integration-tests/tests/.*/entities/.*\.json|
|
||||
var/entities/.*\.json
|
||||
)$
|
||||
- id: check-case-conflict
|
||||
- id: detect-aws-credentials
|
||||
|
||||
# Alternative semantic commit checker
|
||||
- repo: https://github.com/compilerla/conventional-pre-commit
|
||||
|
|
@ -34,9 +47,23 @@ repos:
|
|||
pass_filenames: false
|
||||
always_run: true
|
||||
|
||||
- id: it
|
||||
name: it
|
||||
entry: make service-codestyle frontend-codestyle
|
||||
- id: service-unittests
|
||||
name: service-unittests
|
||||
entry: make service-unittests
|
||||
language: system
|
||||
pass_filenames: false
|
||||
always_run: true
|
||||
|
||||
- id: service-build
|
||||
name: service-build
|
||||
entry: make service
|
||||
language: system
|
||||
pass_filenames: false
|
||||
always_run: true
|
||||
|
||||
- id: it
|
||||
name: integration-tests
|
||||
entry: make it
|
||||
language: system
|
||||
pass_filenames: false
|
||||
always_run: true
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ If you are looking for OliveTin's AI policy, you can find it in `AI.md`.
|
|||
- From repo root: `go run ./service`
|
||||
- Unit tests (Go):
|
||||
- From repo root: `cd service && make unittests`
|
||||
- Code style (after editing code in `service/`):
|
||||
- From repo root: `cd service && make codestyle`
|
||||
- Integration tests (Mocha + Selenium):
|
||||
- Single test: `cd integration-tests && npx --yes mocha test/general.mjs`
|
||||
- All tests: `cd integration-tests && npx --yes mocha`
|
||||
|
|
@ -41,6 +43,7 @@ If you are looking for OliveTin's AI policy, you can find it in `AI.md`.
|
|||
- Do not swallow errors; propagate or log meaningfully.
|
||||
- Match existing formatting; avoid unrelated reformatting.
|
||||
- Be safe around nils in executor steps (e.g., guard `req.Binding` and `req.Binding.Action`).
|
||||
- Cyclomatic complexity over 4 is not permitted.
|
||||
|
||||
### API and Execution Flow (High-level)
|
||||
1. Client calls Connect RPC (e.g., `Init`, `GetDashboard`, `StartAction`).
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
[](https://bestpractices.coreinfrastructure.org/projects/5050)
|
||||
|
||||
[](https://goreportcard.com/report/github.com/OliveTin/OliveTin)
|
||||
[-blue)](https://blog.jread.com/posts/ai-levels-of-autonomy-in-software-engineering/)
|
||||
|
||||
[OliveTin 2k to 3k upgrade guide](https://docs.olivetin.app/upgrade/2k3k.html)
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@ To understand more about 2k vs 3k, see the following docs; https://docs.olivetin
|
|||
|
||||
The very purpose of OliveTin is to allow users to execute commands remotely on a machine.
|
||||
|
||||
This means that, by design, OliveTin has might higher potential to be used for remote code execution (RCE), and any security vulnerabilities that do occour have the potential to be much more severe than in other types of software.
|
||||
This means that, by design, OliveTin has much higher potential to be used for remote code execution (RCE), and any security vulnerabilities that do occur have the potential to be much more severe than in other types of software.
|
||||
|
||||
We hope that you understand that while the project goes to great aims to be safe, and mitigate, that security vulnerabilities are inevitable, as they are with all software of all sizes - like Kubernetes, the Kernel, etc - and OliveTin has substancially less resources than those projects.
|
||||
We hope that you understand that while the project goes to great aims to be safe, and mitigate, that security vulnerabilities are inevitable, as they are with all software of all sizes - like Kubernetes, the Kernel, etc - and OliveTin has substantially less resources than those projects.
|
||||
|
||||
With that being said, OliveTin tries to follow examples of best practice, so judge the project not on if/when it has security issues, but how security issues are responded to as the measure of quality.
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ This is why we take security very seriously, and why we encourage responsible di
|
|||
|
||||
Please use responsible disclosure practices when reporting a vulnerability. **You will receive full credit for your discovery**, and we will work with you to ensure that the issue is resolved as quickly as **possible**. Please note that only James Read has access to security issues at the moment, so please be patient and understanding if you do not receive an immediate response.
|
||||
|
||||
* **Option A (preferred)**: GitHub Security Advisories, which allows you to report a vulnerability privately and securely. You can find the option to report a security issue in the "Issues" tab of this repository, and then select "Report a security vulnerability". This will allow you to provide details about the vulnerability without making it public.
|
||||
* **Option A (preferred)**: GitHub Security Advisories, which allows you to report a vulnerability privately and securely. Use this direct link to report privately: `https://github.com/OliveTin/OliveTin/security/advisories/new`. This allows you to provide details without making them public.
|
||||
|
||||
* **Option B**: Please email `contact@jread.com` for responsible disclosure.
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
"dependencies": {
|
||||
"@connectrpc/connect": "^2.1.1",
|
||||
"@connectrpc/connect-web": "^2.1.1",
|
||||
"@hugeicons/core-free-icons": "^3.1.1",
|
||||
"@hugeicons/core-free-icons": "^3.3.0",
|
||||
"@hugeicons/vue": "^1.0.4",
|
||||
"@vitejs/plugin-vue": "^6.0.4",
|
||||
"@xterm/addon-fit": "^0.11.0",
|
||||
|
|
@ -21,13 +21,13 @@
|
|||
"standard": "^17.1.2",
|
||||
"unplugin-vue-components": "^31.0.0",
|
||||
"vite": "^7.3.1",
|
||||
"vue": "^3.5.28",
|
||||
"vue": "^3.5.29",
|
||||
"vue-i18n": "^11.2.8",
|
||||
"vue-router": "^5.0.2"
|
||||
"vue-router": "^5.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"process": "^0.11.10",
|
||||
"stylelint": "^17.3.0",
|
||||
"stylelint": "^17.4.0",
|
||||
"stylelint-config-standard": "^40.0.0"
|
||||
}
|
||||
},
|
||||
|
|
@ -905,9 +905,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@hugeicons/core-free-icons": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@hugeicons/core-free-icons/-/core-free-icons-3.1.1.tgz",
|
||||
"integrity": "sha512-UpS2lUQFi5sKyJSWwM6rO+BnPLvVz1gsyCpPHeZyVuZqi89YH8ksliza4cwaODqKOZyeXmG8juo1ty4QtQofkg==",
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@hugeicons/core-free-icons/-/core-free-icons-3.3.0.tgz",
|
||||
"integrity": "sha512-qYyr4JQ2eQIHTSTbITvnJvs6ERNK64D9gpwZnf2IyuG0exzqfyABLO/oTB71FB3RZPfu1GbwycdiGSo46apjMQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@hugeicons/vue": {
|
||||
|
|
@ -1435,39 +1435,39 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-core": {
|
||||
"version": "3.5.28",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.28.tgz",
|
||||
"integrity": "sha512-kviccYxTgoE8n6OCw96BNdYlBg2GOWfBuOW4Vqwrt7mSKWKwFVvI8egdTltqRgITGPsTFYtKYfxIG8ptX2PJHQ==",
|
||||
"version": "3.5.29",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.29.tgz",
|
||||
"integrity": "sha512-cuzPhD8fwRHk8IGfmYaR4eEe4cAyJEL66Ove/WZL7yWNL134nqLddSLwNRIsFlnnW1kK+p8Ck3viFnC0chXCXw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.29.0",
|
||||
"@vue/shared": "3.5.28",
|
||||
"@vue/shared": "3.5.29",
|
||||
"entities": "^7.0.1",
|
||||
"estree-walker": "^2.0.2",
|
||||
"source-map-js": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-dom": {
|
||||
"version": "3.5.28",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.28.tgz",
|
||||
"integrity": "sha512-/1ZepxAb159jKR1btkefDP+J2xuWL5V3WtleRmxaT+K2Aqiek/Ab/+Ebrw2pPj0sdHO8ViAyyJWfhXXOP/+LQA==",
|
||||
"version": "3.5.29",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.29.tgz",
|
||||
"integrity": "sha512-n0G5o7R3uBVmVxjTIYcz7ovr8sy7QObFG8OQJ3xGCDNhbG60biP/P5KnyY8NLd81OuT1WJflG7N4KWYHaeeaIg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/compiler-core": "3.5.28",
|
||||
"@vue/shared": "3.5.28"
|
||||
"@vue/compiler-core": "3.5.29",
|
||||
"@vue/shared": "3.5.29"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-sfc": {
|
||||
"version": "3.5.28",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.28.tgz",
|
||||
"integrity": "sha512-6TnKMiNkd6u6VeVDhZn/07KhEZuBSn43Wd2No5zaP5s3xm8IqFTHBj84HJah4UepSUJTro5SoqqlOY22FKY96g==",
|
||||
"version": "3.5.29",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.29.tgz",
|
||||
"integrity": "sha512-oJZhN5XJs35Gzr50E82jg2cYdZQ78wEwvRO6Y63TvLVTc+6xICzJHP1UIecdSPPYIbkautNBanDiWYa64QSFIA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.29.0",
|
||||
"@vue/compiler-core": "3.5.28",
|
||||
"@vue/compiler-dom": "3.5.28",
|
||||
"@vue/compiler-ssr": "3.5.28",
|
||||
"@vue/shared": "3.5.28",
|
||||
"@vue/compiler-core": "3.5.29",
|
||||
"@vue/compiler-dom": "3.5.29",
|
||||
"@vue/compiler-ssr": "3.5.29",
|
||||
"@vue/shared": "3.5.29",
|
||||
"estree-walker": "^2.0.2",
|
||||
"magic-string": "^0.30.21",
|
||||
"postcss": "^8.5.6",
|
||||
|
|
@ -1475,13 +1475,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-ssr": {
|
||||
"version": "3.5.28",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.28.tgz",
|
||||
"integrity": "sha512-JCq//9w1qmC6UGLWJX7RXzrGpKkroubey/ZFqTpvEIDJEKGgntuDMqkuWiZvzTzTA5h2qZvFBFHY7fAAa9475g==",
|
||||
"version": "3.5.29",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.29.tgz",
|
||||
"integrity": "sha512-Y/ARJZE6fpjzL5GH/phJmsFwx3g6t2KmHKHx5q+MLl2kencADKIrhH5MLF6HHpRMmlRAYBRSvv347Mepf1zVNw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.5.28",
|
||||
"@vue/shared": "3.5.28"
|
||||
"@vue/compiler-dom": "3.5.29",
|
||||
"@vue/shared": "3.5.29"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/devtools-api": {
|
||||
|
|
@ -1491,12 +1491,12 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@vue/devtools-kit": {
|
||||
"version": "8.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-8.0.5.tgz",
|
||||
"integrity": "sha512-q2VV6x1U3KJMTQPUlRMyWEKVbcHuxhqJdSr6Jtjz5uAThAIrfJ6WVZdGZm5cuO63ZnSUz0RCsVwiUUb0mDV0Yg==",
|
||||
"version": "8.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-8.0.6.tgz",
|
||||
"integrity": "sha512-9zXZPTJW72OteDXeSa5RVML3zWDCRcO5t77aJqSs228mdopYj5AiTpihozbsfFJ0IodfNs7pSgOGO3qfCuxDtw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/devtools-shared": "^8.0.5",
|
||||
"@vue/devtools-shared": "^8.0.6",
|
||||
"birpc": "^2.6.1",
|
||||
"hookable": "^5.5.3",
|
||||
"mitt": "^3.0.1",
|
||||
|
|
@ -1506,62 +1506,62 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@vue/devtools-shared": {
|
||||
"version": "8.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-8.0.5.tgz",
|
||||
"integrity": "sha512-bRLn6/spxpmgLk+iwOrR29KrYnJjG9DGpHGkDFG82UM21ZpJ39ztUT9OXX3g+usW7/b2z+h46I9ZiYyB07XMXg==",
|
||||
"version": "8.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-8.0.6.tgz",
|
||||
"integrity": "sha512-Pp1JylTqlgMJvxW6MGyfTF8vGvlBSCAvMFaDCYa82Mgw7TT5eE5kkHgDvmOGHWeJE4zIDfCpCxHapsK2LtIAJg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"rfdc": "^1.4.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/reactivity": {
|
||||
"version": "3.5.28",
|
||||
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.28.tgz",
|
||||
"integrity": "sha512-gr5hEsxvn+RNyu9/9o1WtdYdwDjg5FgjUSBEkZWqgTKlo/fvwZ2+8W6AfKsc9YN2k/+iHYdS9vZYAhpi10kNaw==",
|
||||
"version": "3.5.29",
|
||||
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.29.tgz",
|
||||
"integrity": "sha512-zcrANcrRdcLtmGZETBxWqIkoQei8HaFpZWx/GHKxx79JZsiZ8j1du0VUJtu4eJjgFvU/iKL5lRXFXksVmI+5DA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/shared": "3.5.28"
|
||||
"@vue/shared": "3.5.29"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/runtime-core": {
|
||||
"version": "3.5.28",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.28.tgz",
|
||||
"integrity": "sha512-POVHTdbgnrBBIpnbYU4y7pOMNlPn2QVxVzkvEA2pEgvzbelQq4ZOUxbp2oiyo+BOtiYlm8Q44wShHJoBvDPAjQ==",
|
||||
"version": "3.5.29",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.29.tgz",
|
||||
"integrity": "sha512-8DpW2QfdwIWOLqtsNcds4s+QgwSaHSJY/SUe04LptianUQ/0xi6KVsu/pYVh+HO3NTVvVJjIPL2t6GdeKbS4Lg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/reactivity": "3.5.28",
|
||||
"@vue/shared": "3.5.28"
|
||||
"@vue/reactivity": "3.5.29",
|
||||
"@vue/shared": "3.5.29"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/runtime-dom": {
|
||||
"version": "3.5.28",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.28.tgz",
|
||||
"integrity": "sha512-4SXxSF8SXYMuhAIkT+eBRqOkWEfPu6nhccrzrkioA6l0boiq7sp18HCOov9qWJA5HML61kW8p/cB4MmBiG9dSA==",
|
||||
"version": "3.5.29",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.29.tgz",
|
||||
"integrity": "sha512-AHvvJEtcY9tw/uk+s/YRLSlxxQnqnAkjqvK25ZiM4CllCZWzElRAoQnCM42m9AHRLNJ6oe2kC5DCgD4AUdlvXg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/reactivity": "3.5.28",
|
||||
"@vue/runtime-core": "3.5.28",
|
||||
"@vue/shared": "3.5.28",
|
||||
"@vue/reactivity": "3.5.29",
|
||||
"@vue/runtime-core": "3.5.29",
|
||||
"@vue/shared": "3.5.29",
|
||||
"csstype": "^3.2.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/server-renderer": {
|
||||
"version": "3.5.28",
|
||||
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.28.tgz",
|
||||
"integrity": "sha512-pf+5ECKGj8fX95bNincbzJ6yp6nyzuLDhYZCeFxUNp8EBrQpPpQaLX3nNCp49+UbgbPun3CeVE+5CXVV1Xydfg==",
|
||||
"version": "3.5.29",
|
||||
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.29.tgz",
|
||||
"integrity": "sha512-G/1k6WK5MusLlbxSE2YTcqAAezS+VuwHhOvLx2KnQU7G2zCH6KIb+5Wyt6UjMq7a3qPzNEjJXs1hvAxDclQH+g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/compiler-ssr": "3.5.28",
|
||||
"@vue/shared": "3.5.28"
|
||||
"@vue/compiler-ssr": "3.5.29",
|
||||
"@vue/shared": "3.5.29"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "3.5.28"
|
||||
"vue": "3.5.29"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/shared": {
|
||||
"version": "3.5.28",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.28.tgz",
|
||||
"integrity": "sha512-cfWa1fCGBxrvaHRhvV3Is0MgmrbSCxYTXCSCau2I0a1Xw1N1pHAvkWCiXPRAqjvToILvguNyEwjevUqAuBQWvQ==",
|
||||
"version": "3.5.29",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.29.tgz",
|
||||
"integrity": "sha512-w7SR0A5zyRByL9XUkCfdLs7t9XOHUyJ67qPGQjOou3p6GvBeBW+AVjUUmlxtZ4PIYaRvE+1LmK44O4uajlZwcg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@xterm/addon-fit": {
|
||||
|
|
@ -2121,13 +2121,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/css-functions-list": {
|
||||
"version": "3.2.3",
|
||||
"resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.3.tgz",
|
||||
"integrity": "sha512-IQOkD3hbR5KrN93MtcYuad6YPuTSUhntLHDuLEbFWE+ff2/XSZNdZG+LcbbIW5AXKg/WFIfYItIzVoHngHXZzA==",
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.3.3.tgz",
|
||||
"integrity": "sha512-8HFEBPKhOpJPEPu70wJJetjKta86Gw9+CCyCnB3sui2qQfOvRyqBy4IKLKKAwdMpWb2lHXWk9Wb4Z6AmaUT1Pg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12 || >=16"
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/css-tree": {
|
||||
|
|
@ -4276,13 +4276,6 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/known-css-properties": {
|
||||
"version": "0.37.0",
|
||||
"resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.37.0.tgz",
|
||||
"integrity": "sha512-JCDrsP4Z1Sb9JwG0aJ8Eo2r7k4Ou5MwmThS/6lcIe1ICyb7UBJKGRIUUdqc2ASdE/42lgz6zFUnzAIhtXnBVrQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/levn": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
|
||||
|
|
@ -5854,9 +5847,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/stylelint": {
|
||||
"version": "17.3.0",
|
||||
"resolved": "https://registry.npmjs.org/stylelint/-/stylelint-17.3.0.tgz",
|
||||
"integrity": "sha512-1POV91lcEMhj6SLVaOeA0KlS9yattS+qq+cyWqP/nYzWco7K5jznpGH1ExngvPlTM9QF1Kjd2bmuzJu9TH2OcA==",
|
||||
"version": "17.4.0",
|
||||
"resolved": "https://registry.npmjs.org/stylelint/-/stylelint-17.4.0.tgz",
|
||||
"integrity": "sha512-3kQ2/cHv3Zt8OBg+h2B8XCx9evEABQIrv4hh3uXahGz/ZEHrTR80zxBiK2NfXNaSoyBzxO1pjsz1Vhdzwn5XSw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -5872,15 +5865,14 @@
|
|||
"dependencies": {
|
||||
"@csstools/css-calc": "^3.1.1",
|
||||
"@csstools/css-parser-algorithms": "^4.0.0",
|
||||
"@csstools/css-syntax-patches-for-csstree": "^1.0.26",
|
||||
"@csstools/css-syntax-patches-for-csstree": "^1.0.27",
|
||||
"@csstools/css-tokenizer": "^4.0.0",
|
||||
"@csstools/media-query-list-parser": "^5.0.0",
|
||||
"@csstools/selector-resolve-nested": "^4.0.0",
|
||||
"@csstools/selector-specificity": "^6.0.0",
|
||||
"balanced-match": "^3.0.1",
|
||||
"colord": "^2.9.3",
|
||||
"cosmiconfig": "^9.0.0",
|
||||
"css-functions-list": "^3.2.3",
|
||||
"css-functions-list": "^3.3.3",
|
||||
"css-tree": "^3.1.0",
|
||||
"debug": "^4.4.3",
|
||||
"fast-glob": "^3.3.3",
|
||||
|
|
@ -5894,7 +5886,6 @@
|
|||
"import-meta-resolve": "^4.2.0",
|
||||
"imurmurhash": "^0.1.4",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"known-css-properties": "^0.37.0",
|
||||
"mathml-tag-names": "^4.0.0",
|
||||
"meow": "^14.0.0",
|
||||
"micromatch": "^4.0.8",
|
||||
|
|
@ -5979,16 +5970,6 @@
|
|||
"url": "https://github.com/chalk/ansi-regex?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/stylelint/node_modules/balanced-match": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-3.0.1.tgz",
|
||||
"integrity": "sha512-vjtV3hiLqYDNRoiAv0zC4QaGAMPomEoq83PRmYIofPswwZurCeWR5LByXm7SyoL0Zh5+2z0+HC7jG8gSZJUh0w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 16"
|
||||
}
|
||||
},
|
||||
"node_modules/stylelint/node_modules/file-entry-cache": {
|
||||
"version": "11.1.2",
|
||||
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-11.1.2.tgz",
|
||||
|
|
@ -6615,16 +6596,16 @@
|
|||
}
|
||||
},
|
||||
"node_modules/vue": {
|
||||
"version": "3.5.28",
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.28.tgz",
|
||||
"integrity": "sha512-BRdrNfeoccSoIZeIhyPBfvWSLFP4q8J3u8Ju8Ug5vu3LdD+yTM13Sg4sKtljxozbnuMu1NB1X5HBHRYUzFocKg==",
|
||||
"version": "3.5.29",
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.29.tgz",
|
||||
"integrity": "sha512-BZqN4Ze6mDQVNAni0IHeMJ5mwr8VAJ3MQC9FmprRhcBYENw+wOAAjRj8jfmN6FLl0j96OXbR+CjWhmAmM+QGnA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.5.28",
|
||||
"@vue/compiler-sfc": "3.5.28",
|
||||
"@vue/runtime-dom": "3.5.28",
|
||||
"@vue/server-renderer": "3.5.28",
|
||||
"@vue/shared": "3.5.28"
|
||||
"@vue/compiler-dom": "3.5.29",
|
||||
"@vue/compiler-sfc": "3.5.29",
|
||||
"@vue/runtime-dom": "3.5.29",
|
||||
"@vue/server-renderer": "3.5.29",
|
||||
"@vue/shared": "3.5.29"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "*"
|
||||
|
|
@ -6656,14 +6637,14 @@
|
|||
}
|
||||
},
|
||||
"node_modules/vue-router": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-5.0.2.tgz",
|
||||
"integrity": "sha512-YFhwaE5c5JcJpNB1arpkl4/GnO32wiUWRB+OEj1T0DlDxEZoOfbltl2xEwktNU/9o1sGcGburIXSpbLpPFe/6w==",
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-5.0.3.tgz",
|
||||
"integrity": "sha512-nG1c7aAFac7NYj8Hluo68WyWfc41xkEjaR0ViLHCa3oDvTQ/nIuLJlXJX1NUPw/DXzx/8+OKMng045HHQKQKWw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/generator": "^7.28.6",
|
||||
"@vue-macros/common": "^3.1.1",
|
||||
"@vue/devtools-api": "^8.0.0",
|
||||
"@vue/devtools-api": "^8.0.6",
|
||||
"ast-walker-scope": "^0.8.3",
|
||||
"chokidar": "^5.0.0",
|
||||
"json5": "^2.2.3",
|
||||
|
|
@ -6701,12 +6682,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/vue-router/node_modules/@vue/devtools-api": {
|
||||
"version": "8.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-8.0.5.tgz",
|
||||
"integrity": "sha512-DgVcW8H/Nral7LgZEecYFFYXnAvGuN9C3L3DtWekAncFBedBczpNW8iHKExfaM559Zm8wQWrwtYZ9lXthEHtDw==",
|
||||
"version": "8.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-8.0.6.tgz",
|
||||
"integrity": "sha512-+lGBI+WTvJmnU2FZqHhEB8J1DXcvNlDeEalz77iYgOdY1jTj1ipSBaKj3sRhYcy+kqA8v/BSuvOz1XJucfQmUA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/devtools-kit": "^8.0.5"
|
||||
"@vue/devtools-kit": "^8.0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-router/node_modules/json5": {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
"source": "index.html",
|
||||
"devDependencies": {
|
||||
"process": "^0.11.10",
|
||||
"stylelint": "^17.3.0",
|
||||
"stylelint": "^17.4.0",
|
||||
"stylelint-config-standard": "^40.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
"dependencies": {
|
||||
"@connectrpc/connect": "^2.1.1",
|
||||
"@connectrpc/connect-web": "^2.1.1",
|
||||
"@hugeicons/core-free-icons": "^3.1.1",
|
||||
"@hugeicons/core-free-icons": "^3.3.0",
|
||||
"@hugeicons/vue": "^1.0.4",
|
||||
"@vitejs/plugin-vue": "^6.0.4",
|
||||
"@xterm/addon-fit": "^0.11.0",
|
||||
|
|
@ -34,8 +34,8 @@
|
|||
"standard": "^17.1.2",
|
||||
"unplugin-vue-components": "^31.0.0",
|
||||
"vite": "^7.3.1",
|
||||
"vue": "^3.5.28",
|
||||
"vue": "^3.5.29",
|
||||
"vue-i18n": "^11.2.8",
|
||||
"vue-router": "^5.0.2"
|
||||
"vue-router": "^5.0.3"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -210,6 +210,11 @@ export declare type EffectivePolicy = Message<"olivetin.api.v1.EffectivePolicy">
|
|||
* @generated from field: bool show_log_list = 2;
|
||||
*/
|
||||
showLogList: boolean;
|
||||
|
||||
/**
|
||||
* @generated from field: bool show_version_number = 3;
|
||||
*/
|
||||
showVersionNumber: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -495,6 +500,13 @@ export declare type GetLogsRequest = Message<"olivetin.api.v1.GetLogsRequest"> &
|
|||
* @generated from field: string date_filter = 2;
|
||||
*/
|
||||
dateFilter: string;
|
||||
|
||||
/**
|
||||
* Number of logs per page (optional; server default used if 0 or unset)
|
||||
*
|
||||
* @generated from field: int64 page_size = 3;
|
||||
*/
|
||||
pageSize: bigint;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -31,7 +31,7 @@
|
|||
<footer title="footer" v-if="showFooter">
|
||||
<p>
|
||||
<img title="application icon" :src="logoUrl" alt="OliveTin logo" style="height: 1em;" class="logo" />
|
||||
OliveTin {{ currentVersion }}
|
||||
OliveTin <span v-if="showVersionNumber">{{ currentVersion }}</span>
|
||||
</p>
|
||||
<p>
|
||||
<span>
|
||||
|
|
@ -52,7 +52,7 @@
|
|||
|
||||
<span>{{ t('connected') }}</span>
|
||||
</p>
|
||||
<p>
|
||||
<p v-if="showVersionNumber">
|
||||
<a id="available-version" href="http://olivetin.app" target="_blank" hidden>?</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
|
@ -126,6 +126,7 @@ const showFooter = ref(true)
|
|||
const showNavigation = ref(true)
|
||||
const showLogs = ref(true)
|
||||
const showDiagnostics = ref(true)
|
||||
const showVersionNumber = ref(true)
|
||||
const showLoginLink = ref(true)
|
||||
const sectionNavigationStyle = ref('sidebar')
|
||||
|
||||
|
|
@ -223,6 +224,7 @@ function updateHeaderFromInit() {
|
|||
showNavigation.value = window.initResponse.showNavigation
|
||||
showLogs.value = window.initResponse.showLogList
|
||||
showDiagnostics.value = window.initResponse.showDiagnostics
|
||||
showVersionNumber.value = window.initResponse.effectivePolicy?.showVersionNumber ?? true
|
||||
sectionNavigationStyle.value = window.initResponse.sectionNavigationStyle || 'sidebar'
|
||||
availableThemes.value = window.initResponse.availableThemes || []
|
||||
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@
|
|||
</tbody>
|
||||
</table>
|
||||
|
||||
<Pagination :pageSize="pageSize" :total="totalCount" :currentPage="currentPage" @page-change="handlePageChange" class="padding"
|
||||
<Pagination :pageSize="pageSize" :total="totalCount" :currentPage="currentPage" :page="currentPage" @page-change="handlePageChange" class="padding"
|
||||
@page-size-change="handlePageSizeChange" itemTitle="execution logs" />
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -162,7 +162,10 @@ async function generateBrowserInfo() {
|
|||
userAgentData: userAgentData
|
||||
}
|
||||
|
||||
const olivetinVersion = window.initResponse?.currentVersion || t('diagnostics.unknown')
|
||||
const showVersionNumber = window.initResponse?.effectivePolicy?.showVersionNumber ?? true
|
||||
const olivetinVersion = showVersionNumber
|
||||
? (window.initResponse?.currentVersion || t('diagnostics.unknown'))
|
||||
: '[hidden]'
|
||||
const currentLanguage = locale.value || t('diagnostics.unknown')
|
||||
|
||||
let output = '';
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@
|
|||
</tbody>
|
||||
</table>
|
||||
|
||||
<Pagination :pageSize="pageSize" :total="totalCount" :currentPage="currentPage" @page-change="handlePageChange" class = "padding"
|
||||
<Pagination :pageSize="pageSize" :total="totalCount" :currentPage="currentPage" :page="currentPage" @page-change="handlePageChange" class = "padding"
|
||||
@page-size-change="handlePageSizeChange" itemTitle="execution logs" />
|
||||
</div>
|
||||
|
||||
|
|
@ -150,6 +150,7 @@ async function fetchLogs() {
|
|||
|
||||
const args = {
|
||||
"startOffset": BigInt(startOffset),
|
||||
"pageSize": BigInt(pageSize.value),
|
||||
}
|
||||
|
||||
// Add date filter if selected
|
||||
|
|
@ -160,7 +161,6 @@ async function fetchLogs() {
|
|||
const response = await window.client.getLogs(args)
|
||||
|
||||
logs.value = response.logs
|
||||
pageSize.value = Number(response.pageSize) || 0
|
||||
totalCount.value = Number(response.totalCount) || 0
|
||||
} catch (err) {
|
||||
console.error('Failed to fetch logs:', err)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"chai": "^6.2.2",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint": "^10.0.2",
|
||||
"mocha": "^11.7.5",
|
||||
"selenium-webdriver": "^4.41.0"
|
||||
}
|
||||
|
|
@ -67,9 +67,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@eslint-community/regexpp": {
|
||||
"version": "4.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz",
|
||||
"integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==",
|
||||
"version": "4.12.2",
|
||||
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz",
|
||||
"integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
|
|
@ -77,105 +77,68 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@eslint/config-array": {
|
||||
"version": "0.21.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz",
|
||||
"integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==",
|
||||
"version": "0.23.2",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.2.tgz",
|
||||
"integrity": "sha512-YF+fE6LV4v5MGWRGj7G404/OZzGNepVF8fxk7jqmqo3lrza7a0uUcDnROGRBG1WFC1omYUS/Wp1f42i0M+3Q3A==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@eslint/object-schema": "^2.1.7",
|
||||
"@eslint/object-schema": "^3.0.2",
|
||||
"debug": "^4.3.1",
|
||||
"minimatch": "^3.1.2"
|
||||
"minimatch": "^10.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
"node": "^20.19.0 || ^22.13.0 || >=24"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/config-helpers": {
|
||||
"version": "0.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz",
|
||||
"integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==",
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.2.tgz",
|
||||
"integrity": "sha512-a5MxrdDXEvqnIq+LisyCX6tQMPF/dSJpCfBgBauY+pNZ28yCtSsTvyTYrMhaI+LK26bVyCJfJkT0u8KIj2i1dQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@eslint/core": "^0.17.0"
|
||||
"@eslint/core": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
"node": "^20.19.0 || ^22.13.0 || >=24"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/core": {
|
||||
"version": "0.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz",
|
||||
"integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==",
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.1.0.tgz",
|
||||
"integrity": "sha512-/nr9K9wkr3P1EzFTdFdMoLuo1PmIxjmwvPozwoSodjNBdefGujXQUF93u1DDZpEaTuDvMsIQddsd35BwtrW9Xw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.15"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/eslintrc": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz",
|
||||
"integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ajv": "^6.12.4",
|
||||
"debug": "^4.3.2",
|
||||
"espree": "^10.0.1",
|
||||
"globals": "^14.0.0",
|
||||
"ignore": "^5.2.0",
|
||||
"import-fresh": "^3.2.1",
|
||||
"js-yaml": "^4.1.0",
|
||||
"minimatch": "^3.1.2",
|
||||
"strip-json-comments": "^3.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/js": {
|
||||
"version": "9.39.2",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz",
|
||||
"integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://eslint.org/donate"
|
||||
"node": "^20.19.0 || ^22.13.0 || >=24"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/object-schema": {
|
||||
"version": "2.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz",
|
||||
"integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==",
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.2.tgz",
|
||||
"integrity": "sha512-HOy56KJt48Bx8KmJ+XGQNSUMT/6dZee/M54XyUyuvTvPXJmsERRvBchsUVx1UMe1WwIH49XLAczNC7V2INsuUw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
"node": "^20.19.0 || ^22.13.0 || >=24"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/plugin-kit": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz",
|
||||
"integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==",
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.6.0.tgz",
|
||||
"integrity": "sha512-bIZEUzOI1jkhviX2cp5vNyXQc6olzb2ohewQubuYlMXZ2Q/XjBO0x0XhGPvc9fjSIiUN0vw+0hq53BJ4eQSJKQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@eslint/core": "^0.17.0",
|
||||
"@eslint/core": "^1.1.0",
|
||||
"levn": "^0.4.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
"node": "^20.19.0 || ^22.13.0 || >=24"
|
||||
}
|
||||
},
|
||||
"node_modules/@hapi/address": {
|
||||
|
|
@ -326,10 +289,17 @@
|
|||
"integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/esrecurse": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz",
|
||||
"integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
|
||||
"integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
||||
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
|
|
@ -341,9 +311,9 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.15.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"version": "8.16.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
|
||||
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
|
|
@ -364,9 +334,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/ajv": {
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"version": "6.14.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz",
|
||||
"integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
|
@ -438,14 +408,26 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz",
|
||||
"integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
"balanced-match": "^4.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "18 || 20 || >=22"
|
||||
}
|
||||
},
|
||||
"node_modules/brace-expansion/node_modules/balanced-match": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
|
||||
"integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "18 || 20 || >=22"
|
||||
}
|
||||
},
|
||||
"node_modules/browser-stdout": {
|
||||
|
|
@ -467,16 +449,6 @@
|
|||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/callsites": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
|
||||
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/camelcase": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
|
||||
|
|
@ -639,13 +611,6 @@
|
|||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/core-util-is": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
||||
|
|
@ -818,33 +783,30 @@
|
|||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "9.39.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz",
|
||||
"integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==",
|
||||
"version": "10.0.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-10.0.2.tgz",
|
||||
"integrity": "sha512-uYixubwmqJZH+KLVYIVKY1JQt7tysXhtj21WSvjcSmU5SVNzMus1bgLe+pAt816yQ8opKfheVVoPLqvVMGejYw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.8.0",
|
||||
"@eslint-community/regexpp": "^4.12.1",
|
||||
"@eslint/config-array": "^0.21.1",
|
||||
"@eslint/config-helpers": "^0.4.2",
|
||||
"@eslint/core": "^0.17.0",
|
||||
"@eslint/eslintrc": "^3.3.1",
|
||||
"@eslint/js": "9.39.2",
|
||||
"@eslint/plugin-kit": "^0.4.1",
|
||||
"@eslint-community/regexpp": "^4.12.2",
|
||||
"@eslint/config-array": "^0.23.2",
|
||||
"@eslint/config-helpers": "^0.5.2",
|
||||
"@eslint/core": "^1.1.0",
|
||||
"@eslint/plugin-kit": "^0.6.0",
|
||||
"@humanfs/node": "^0.16.6",
|
||||
"@humanwhocodes/module-importer": "^1.0.1",
|
||||
"@humanwhocodes/retry": "^0.4.2",
|
||||
"@types/estree": "^1.0.6",
|
||||
"ajv": "^6.12.4",
|
||||
"chalk": "^4.0.0",
|
||||
"ajv": "^6.14.0",
|
||||
"cross-spawn": "^7.0.6",
|
||||
"debug": "^4.3.2",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"eslint-scope": "^8.4.0",
|
||||
"eslint-visitor-keys": "^4.2.1",
|
||||
"espree": "^10.4.0",
|
||||
"esquery": "^1.5.0",
|
||||
"eslint-scope": "^9.1.1",
|
||||
"eslint-visitor-keys": "^5.0.1",
|
||||
"espree": "^11.1.1",
|
||||
"esquery": "^1.7.0",
|
||||
"esutils": "^2.0.2",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"file-entry-cache": "^8.0.0",
|
||||
|
|
@ -854,8 +816,7 @@
|
|||
"imurmurhash": "^0.1.4",
|
||||
"is-glob": "^4.0.0",
|
||||
"json-stable-stringify-without-jsonify": "^1.0.1",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"minimatch": "^3.1.2",
|
||||
"minimatch": "^10.2.1",
|
||||
"natural-compare": "^1.4.0",
|
||||
"optionator": "^0.9.3"
|
||||
},
|
||||
|
|
@ -863,7 +824,7 @@
|
|||
"eslint": "bin/eslint.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
"node": "^20.19.0 || ^22.13.0 || >=24"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://eslint.org/donate"
|
||||
|
|
@ -878,58 +839,61 @@
|
|||
}
|
||||
},
|
||||
"node_modules/eslint-scope": {
|
||||
"version": "8.4.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
|
||||
"integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
|
||||
"version": "9.1.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.1.tgz",
|
||||
"integrity": "sha512-GaUN0sWim5qc8KVErfPBWmc31LEsOkrUJbvJZV+xuL3u2phMUK4HIvXlWAakfC8W4nzlK+chPEAkYOYb5ZScIw==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"@types/esrecurse": "^4.3.1",
|
||||
"@types/estree": "^1.0.8",
|
||||
"esrecurse": "^4.3.0",
|
||||
"estraverse": "^5.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
"node": "^20.19.0 || ^22.13.0 || >=24"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-visitor-keys": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
|
||||
"integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
|
||||
"integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
"node": "^20.19.0 || ^22.13.0 || >=24"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/espree": {
|
||||
"version": "10.4.0",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
|
||||
"integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
|
||||
"version": "11.1.1",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-11.1.1.tgz",
|
||||
"integrity": "sha512-AVHPqQoZYc+RUM4/3Ly5udlZY/U4LS8pIG05jEjWM2lQMU/oaZ7qshzAl2YP1tfNmXfftH3ohurfwNAug+MnsQ==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"acorn": "^8.15.0",
|
||||
"acorn": "^8.16.0",
|
||||
"acorn-jsx": "^5.3.2",
|
||||
"eslint-visitor-keys": "^4.2.1"
|
||||
"eslint-visitor-keys": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
"node": "^20.19.0 || ^22.13.0 || >=24"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/esquery": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz",
|
||||
"integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==",
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
|
||||
"integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"estraverse": "^5.1.0"
|
||||
},
|
||||
|
|
@ -955,6 +919,7 @@
|
|||
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
|
||||
"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
}
|
||||
|
|
@ -1216,19 +1181,6 @@
|
|||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/globals": {
|
||||
"version": "14.0.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
|
||||
"integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/gopd": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||
|
|
@ -1314,23 +1266,6 @@
|
|||
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/import-fresh": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
|
||||
"integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"parent-module": "^1.0.0",
|
||||
"resolve-from": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/imurmurhash": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
|
||||
|
|
@ -1552,12 +1487,6 @@
|
|||
"integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.merge": {
|
||||
"version": "4.6.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/log-symbols": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
|
||||
|
|
@ -1612,16 +1541,19 @@
|
|||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"version": "10.2.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz",
|
||||
"integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"license": "BlueOak-1.0.0",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
"brace-expansion": "^5.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
"node": "18 || 20 || >=22"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/minimist": {
|
||||
|
|
@ -1793,19 +1725,6 @@
|
|||
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/parent-module": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||
"integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"callsites": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/path-exists": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||
|
|
@ -1928,16 +1847,6 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve-from": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
|
||||
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/rxjs": {
|
||||
"version": "7.8.2",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
"license": "AGPL-3.0-only",
|
||||
"devDependencies": {
|
||||
"chai": "^6.2.2",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint": "^10.0.2",
|
||||
"mocha": "^11.7.5",
|
||||
"selenium-webdriver": "^4.41.0"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ listenAddressSingleHTTPFrontend: 0.0.0.0:1337
|
|||
|
||||
logLevel: "DEBUG"
|
||||
checkForUpdates: false
|
||||
popupOnStart: execution-dialog
|
||||
defaultPopupOnStart: execution-dialog
|
||||
|
||||
actions:
|
||||
- title: Test checkbox argument
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ listenAddressSingleHTTPFrontend: 0.0.0.0:1337
|
|||
|
||||
logLevel: "DEBUG"
|
||||
checkForUpdates: false
|
||||
popupOnStart: execution-dialog
|
||||
defaultPopupOnStart: execution-dialog
|
||||
|
||||
actions:
|
||||
- title: Test datetime argument
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ listenAddressSingleHTTPFrontend: 0.0.0.0:1337
|
|||
|
||||
logLevel: "DEBUG"
|
||||
checkForUpdates: false
|
||||
popupOnStart: execution-dialog
|
||||
defaultPopupOnStart: execution-dialog
|
||||
|
||||
actions:
|
||||
- title: Test suggestionsBrowserKey
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ message GetDashboardResponse {
|
|||
message EffectivePolicy {
|
||||
bool show_diagnostics = 1;
|
||||
bool show_log_list = 2;
|
||||
bool show_version_number = 3;
|
||||
}
|
||||
|
||||
message GetDashboardRequest {
|
||||
|
|
@ -121,6 +122,7 @@ message StartActionByGetAndWaitResponse {
|
|||
message GetLogsRequest{
|
||||
int64 start_offset = 1;
|
||||
string date_filter = 2; // Optional date filter in YYYY-MM-DD format
|
||||
int64 page_size = 3; // Number of logs per page (optional; server default used if 0 or unset)
|
||||
};
|
||||
|
||||
message LogEntry {
|
||||
|
|
|
|||
|
|
@ -413,6 +413,7 @@ type EffectivePolicy struct {
|
|||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
ShowDiagnostics bool `protobuf:"varint,1,opt,name=show_diagnostics,json=showDiagnostics,proto3" json:"show_diagnostics,omitempty"`
|
||||
ShowLogList bool `protobuf:"varint,2,opt,name=show_log_list,json=showLogList,proto3" json:"show_log_list,omitempty"`
|
||||
ShowVersionNumber bool `protobuf:"varint,3,opt,name=show_version_number,json=showVersionNumber,proto3" json:"show_version_number,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
|
@ -461,6 +462,13 @@ func (x *EffectivePolicy) GetShowLogList() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (x *EffectivePolicy) GetShowVersionNumber() bool {
|
||||
if x != nil {
|
||||
return x.ShowVersionNumber
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type GetDashboardRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"`
|
||||
|
|
@ -1105,6 +1113,7 @@ type GetLogsRequest struct {
|
|||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
StartOffset int64 `protobuf:"varint,1,opt,name=start_offset,json=startOffset,proto3" json:"start_offset,omitempty"`
|
||||
DateFilter string `protobuf:"bytes,2,opt,name=date_filter,json=dateFilter,proto3" json:"date_filter,omitempty"` // Optional date filter in YYYY-MM-DD format
|
||||
PageSize int64 `protobuf:"varint,3,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` // Number of logs per page (optional; server default used if 0 or unset)
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
|
@ -1153,6 +1162,13 @@ func (x *GetLogsRequest) GetDateFilter() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func (x *GetLogsRequest) GetPageSize() int64 {
|
||||
if x != nil {
|
||||
return x.PageSize
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type LogEntry struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
DatetimeStarted string `protobuf:"bytes,1,opt,name=datetime_started,json=datetimeStarted,proto3" json:"datetime_started,omitempty"`
|
||||
|
|
@ -3926,10 +3942,11 @@ const file_olivetin_api_v1_olivetin_proto_rawDesc = "" +
|
|||
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"f\n" +
|
||||
"\x14GetDashboardResponse\x12\x14\n" +
|
||||
"\x05title\x18\x01 \x01(\tR\x05title\x128\n" +
|
||||
"\tdashboard\x18\x04 \x01(\v2\x1a.olivetin.api.v1.DashboardR\tdashboard\"`\n" +
|
||||
"\tdashboard\x18\x04 \x01(\v2\x1a.olivetin.api.v1.DashboardR\tdashboard\"\x90\x01\n" +
|
||||
"\x0fEffectivePolicy\x12)\n" +
|
||||
"\x10show_diagnostics\x18\x01 \x01(\bR\x0fshowDiagnostics\x12\"\n" +
|
||||
"\rshow_log_list\x18\x02 \x01(\bR\vshowLogList\"k\n" +
|
||||
"\rshow_log_list\x18\x02 \x01(\bR\vshowLogList\x12.\n" +
|
||||
"\x13show_version_number\x18\x03 \x01(\bR\x11showVersionNumber\"k\n" +
|
||||
"\x13GetDashboardRequest\x12\x14\n" +
|
||||
"\x05title\x18\x01 \x01(\tR\x05title\x12\x1f\n" +
|
||||
"\ventity_type\x18\x02 \x01(\tR\n" +
|
||||
|
|
@ -3972,11 +3989,12 @@ const file_olivetin_api_v1_olivetin_proto_rawDesc = "" +
|
|||
"\x1eStartActionByGetAndWaitRequest\x12\x1b\n" +
|
||||
"\taction_id\x18\x01 \x01(\tR\bactionId\"Y\n" +
|
||||
"\x1fStartActionByGetAndWaitResponse\x126\n" +
|
||||
"\tlog_entry\x18\x01 \x01(\v2\x19.olivetin.api.v1.LogEntryR\blogEntry\"T\n" +
|
||||
"\tlog_entry\x18\x01 \x01(\v2\x19.olivetin.api.v1.LogEntryR\blogEntry\"q\n" +
|
||||
"\x0eGetLogsRequest\x12!\n" +
|
||||
"\fstart_offset\x18\x01 \x01(\x03R\vstartOffset\x12\x1f\n" +
|
||||
"\vdate_filter\x18\x02 \x01(\tR\n" +
|
||||
"dateFilter\"\x89\x05\n" +
|
||||
"dateFilter\x12\x1b\n" +
|
||||
"\tpage_size\x18\x03 \x01(\x03R\bpageSize\"\x89\x05\n" +
|
||||
"\bLogEntry\x12)\n" +
|
||||
"\x10datetime_started\x18\x01 \x01(\tR\x0fdatetimeStarted\x12!\n" +
|
||||
"\faction_title\x18\x02 \x01(\tR\vactionTitle\x12\x16\n" +
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package api
|
|||
import (
|
||||
ctx "context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"os"
|
||||
"path"
|
||||
"sort"
|
||||
|
|
@ -144,6 +145,9 @@ func (api *oliveTinAPI) PasswordHash(ctx ctx.Context, req *connect.Request[apiv1
|
|||
hash, err := createHash(req.Msg.Password)
|
||||
|
||||
if err != nil {
|
||||
if errors.Is(err, ErrArgon2Busy) {
|
||||
return nil, connect.NewError(connect.CodeResourceExhausted, err)
|
||||
}
|
||||
return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("error creating hash: %w", err))
|
||||
}
|
||||
|
||||
|
|
@ -154,52 +158,50 @@ func (api *oliveTinAPI) PasswordHash(ctx ctx.Context, req *connect.Request[apiv1
|
|||
return connect.NewResponse(ret), nil
|
||||
}
|
||||
|
||||
func (api *oliveTinAPI) LocalUserLogin(ctx ctx.Context, req *connect.Request[apiv1.LocalUserLoginRequest]) (*connect.Response[apiv1.LocalUserLoginResponse], error) {
|
||||
// Check if local user authentication is enabled
|
||||
if !api.cfg.AuthLocalUsers.Enabled {
|
||||
return connect.NewResponse(&apiv1.LocalUserLoginResponse{
|
||||
Success: false,
|
||||
}), nil
|
||||
}
|
||||
|
||||
match := checkUserPassword(api.cfg, req.Msg.Username, req.Msg.Password)
|
||||
|
||||
response := connect.NewResponse(&apiv1.LocalUserLoginResponse{
|
||||
Success: match,
|
||||
})
|
||||
func (api *oliveTinAPI) cookieSecure(header http.Header) bool {
|
||||
useTLS := header.Get("X-Forwarded-Proto") == "https"
|
||||
return useTLS || api.cfg.Security.ForceSecureCookies
|
||||
}
|
||||
|
||||
func (api *oliveTinAPI) applyLocalLoginResult(req *apiv1.LocalUserLoginRequest, response *connect.Response[apiv1.LocalUserLoginResponse], match bool, secure bool) {
|
||||
if match {
|
||||
// Set authentication cookie for successful login
|
||||
user := api.cfg.FindUserByUsername(req.Msg.Username)
|
||||
user := api.cfg.FindUserByUsername(req.Username)
|
||||
if user != nil {
|
||||
sid := uuid.NewString()
|
||||
// Register the session in the session storage
|
||||
auth.RegisterUserSession(api.cfg, "local", sid, user.Username)
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"username": user.Username,
|
||||
}).Info("LocalUserLogin: Session created and registered")
|
||||
|
||||
// Set the authentication cookie in the response headers
|
||||
log.WithFields(log.Fields{"username": user.Username}).Info("LocalUserLogin: Session created and registered")
|
||||
cookie := &http.Cookie{
|
||||
Name: "olivetin-sid-local",
|
||||
Value: sid,
|
||||
MaxAge: 31556952, // 1 year
|
||||
MaxAge: 31556952,
|
||||
HttpOnly: true,
|
||||
Path: "/",
|
||||
Secure: secure,
|
||||
SameSite: http.SameSiteLaxMode,
|
||||
}
|
||||
response.Header().Set("Set-Cookie", cookie.String())
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"username": req.Msg.Username,
|
||||
}).Info("LocalUserLogin: User logged in successfully.")
|
||||
log.WithFields(log.Fields{"username": user.Username}).Info("LocalUserLogin: User logged in successfully.")
|
||||
} else {
|
||||
log.WithFields(log.Fields{
|
||||
"username": req.Msg.Username,
|
||||
}).Warn("LocalUserLogin: User login failed.")
|
||||
log.WithFields(log.Fields{"username": req.Username}).Warn("LocalUserLogin: Password matched but user lookup failed.")
|
||||
}
|
||||
} else {
|
||||
log.WithFields(log.Fields{"username": req.Username}).Warn("LocalUserLogin: User login failed.")
|
||||
}
|
||||
}
|
||||
|
||||
func (api *oliveTinAPI) LocalUserLogin(ctx ctx.Context, req *connect.Request[apiv1.LocalUserLoginRequest]) (*connect.Response[apiv1.LocalUserLoginResponse], error) {
|
||||
if !api.cfg.AuthLocalUsers.Enabled {
|
||||
return connect.NewResponse(&apiv1.LocalUserLoginResponse{Success: false}), nil
|
||||
}
|
||||
match, err := checkUserPassword(api.cfg, req.Msg.Username, req.Msg.Password)
|
||||
if err != nil {
|
||||
if errors.Is(err, ErrArgon2Busy) {
|
||||
return nil, connect.NewError(connect.CodeResourceExhausted, err)
|
||||
}
|
||||
return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("checking password: %w", err))
|
||||
}
|
||||
response := connect.NewResponse(&apiv1.LocalUserLoginResponse{Success: match})
|
||||
api.applyLocalLoginResult(req.Msg, response, match, api.cookieSecure(req.Header()))
|
||||
return response, nil
|
||||
}
|
||||
|
||||
|
|
@ -354,30 +356,36 @@ func getMostRecentExecutionStatusByActionId(api *oliveTinAPI, actionId string) *
|
|||
return ile
|
||||
}
|
||||
|
||||
func (api *oliveTinAPI) resolveExecutionStatusForView(msg *apiv1.ExecutionStatusRequest, user *authpublic.AuthenticatedUser) (*executor.InternalLogEntry, error) {
|
||||
ile := api.getExecutionStatusByRequest(msg)
|
||||
if ile == nil {
|
||||
return nil, connect.NewError(connect.CodeNotFound, fmt.Errorf("execution not found for tracking ID %s or action ID %s", msg.ExecutionTrackingId, msg.ActionId))
|
||||
}
|
||||
if !isValidLogEntry(ile) || !api.isLogEntryAllowed(ile, user) {
|
||||
return nil, connect.NewError(connect.CodePermissionDenied, fmt.Errorf("permission denied to view this execution"))
|
||||
}
|
||||
return ile, nil
|
||||
}
|
||||
|
||||
func (api *oliveTinAPI) getExecutionStatusByRequest(msg *apiv1.ExecutionStatusRequest) *executor.InternalLogEntry {
|
||||
if msg.ExecutionTrackingId != "" {
|
||||
return getExecutionStatusByTrackingID(api, msg.ExecutionTrackingId)
|
||||
}
|
||||
return getMostRecentExecutionStatusByActionId(api, msg.ActionId)
|
||||
}
|
||||
|
||||
func (api *oliveTinAPI) ExecutionStatus(ctx ctx.Context, req *connect.Request[apiv1.ExecutionStatusRequest]) (*connect.Response[apiv1.ExecutionStatusResponse], error) {
|
||||
res := &apiv1.ExecutionStatusResponse{}
|
||||
|
||||
user := auth.UserFromApiCall(ctx, req, api.cfg)
|
||||
|
||||
if err := api.checkDashboardAccess(user); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ile *executor.InternalLogEntry
|
||||
|
||||
if req.Msg.ExecutionTrackingId != "" {
|
||||
ile = getExecutionStatusByTrackingID(api, req.Msg.ExecutionTrackingId)
|
||||
|
||||
} else {
|
||||
ile = getMostRecentExecutionStatusByActionId(api, req.Msg.ActionId)
|
||||
ile, err := api.resolveExecutionStatusForView(req.Msg, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ile == nil {
|
||||
return nil, connect.NewError(connect.CodeNotFound, fmt.Errorf("execution not found for tracking ID %s or action ID %s", req.Msg.ExecutionTrackingId, req.Msg.ActionId))
|
||||
} else {
|
||||
res.LogEntry = api.internalLogEntryToPb(ile, user)
|
||||
res := &apiv1.ExecutionStatusResponse{
|
||||
LogEntry: api.internalLogEntryToPb(ile, user),
|
||||
}
|
||||
|
||||
return connect.NewResponse(res), nil
|
||||
}
|
||||
|
||||
|
|
@ -390,6 +398,7 @@ func (api *oliveTinAPI) Logout(ctx ctx.Context, req *connect.Request[apiv1.Logou
|
|||
}).Info("Logout: User logged out")
|
||||
|
||||
response := connect.NewResponse(&apiv1.LogoutResponse{})
|
||||
secure := api.cookieSecure(req.Header())
|
||||
|
||||
// Clear the local authentication cookie by setting it to expire
|
||||
localCookie := &http.Cookie{
|
||||
|
|
@ -398,6 +407,8 @@ func (api *oliveTinAPI) Logout(ctx ctx.Context, req *connect.Request[apiv1.Logou
|
|||
MaxAge: -1, // This tells the browser to delete the cookie
|
||||
HttpOnly: true,
|
||||
Path: "/",
|
||||
Secure: secure,
|
||||
SameSite: http.SameSiteLaxMode,
|
||||
}
|
||||
response.Header().Set("Set-Cookie", localCookie.String())
|
||||
|
||||
|
|
@ -408,6 +419,8 @@ func (api *oliveTinAPI) Logout(ctx ctx.Context, req *connect.Request[apiv1.Logou
|
|||
MaxAge: -1, // This tells the browser to delete the cookie
|
||||
HttpOnly: true,
|
||||
Path: "/",
|
||||
Secure: secure,
|
||||
SameSite: http.SameSiteLaxMode,
|
||||
}
|
||||
response.Header().Add("Set-Cookie", oauth2Cookie.String())
|
||||
|
||||
|
|
@ -494,6 +507,19 @@ func (api *oliveTinAPI) buildCustomDashboardResponse(rr *DashboardRenderRequest,
|
|||
return connect.NewResponse(res), nil
|
||||
}
|
||||
|
||||
func resolveLogsPageSize(requestPageSize, defaultPageSize int64) int64 {
|
||||
if requestPageSize == 0 {
|
||||
return defaultPageSize
|
||||
}
|
||||
if requestPageSize < 10 {
|
||||
return 10
|
||||
}
|
||||
if requestPageSize > 100 {
|
||||
return 100
|
||||
}
|
||||
return requestPageSize
|
||||
}
|
||||
|
||||
func (api *oliveTinAPI) GetLogs(ctx ctx.Context, req *connect.Request[apiv1.GetLogsRequest]) (*connect.Response[apiv1.GetLogsResponse], error) {
|
||||
user := auth.UserFromApiCall(ctx, req, api.cfg)
|
||||
|
||||
|
|
@ -501,12 +527,9 @@ func (api *oliveTinAPI) GetLogs(ctx ctx.Context, req *connect.Request[apiv1.GetL
|
|||
return nil, err
|
||||
}
|
||||
|
||||
pageSize := resolveLogsPageSize(req.Msg.GetPageSize(), api.cfg.LogHistoryPageSize)
|
||||
logEntries, paging := api.executor.GetLogTrackingIdsACL(api.cfg, user, req.Msg.StartOffset, pageSize, req.Msg.DateFilter)
|
||||
ret := &apiv1.GetLogsResponse{}
|
||||
dateFilter := ""
|
||||
if req.Msg.DateFilter != "" {
|
||||
dateFilter = req.Msg.DateFilter
|
||||
}
|
||||
logEntries, paging := api.executor.GetLogTrackingIdsACL(api.cfg, user, req.Msg.StartOffset, api.cfg.LogHistoryPageSize, dateFilter)
|
||||
for _, le := range logEntries {
|
||||
ret.Logs = append(ret.Logs, api.internalLogEntryToPb(le, user))
|
||||
}
|
||||
|
|
@ -687,7 +710,9 @@ func (api *oliveTinAPI) WhoAmI(ctx ctx.Context, req *connect.Request[apiv1.WhoAm
|
|||
}
|
||||
|
||||
func (api *oliveTinAPI) SosReport(ctx ctx.Context, req *connect.Request[apiv1.SosReportRequest]) (*connect.Response[apiv1.SosReportResponse], error) {
|
||||
sos := installationinfo.GetSosReport()
|
||||
user := auth.UserFromApiCall(ctx, req, api.cfg)
|
||||
redactVersion := !user.EffectivePolicy.ShowVersionNumber
|
||||
sos := installationinfo.GetSosReport(redactVersion)
|
||||
|
||||
if !api.cfg.InsecureAllowDumpSos {
|
||||
log.Info(sos)
|
||||
|
|
@ -872,11 +897,17 @@ func (api *oliveTinAPI) OnExecutionFinished(ile *executor.InternalLogEntry) {
|
|||
}
|
||||
|
||||
func (api *oliveTinAPI) GetDiagnostics(ctx ctx.Context, req *connect.Request[apiv1.GetDiagnosticsRequest]) (*connect.Response[apiv1.GetDiagnosticsResponse], error) {
|
||||
user := auth.UserFromApiCall(ctx, req, api.cfg)
|
||||
if err := api.checkDashboardAccess(user); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !user.EffectivePolicy.ShowDiagnostics {
|
||||
return nil, connect.NewError(connect.CodePermissionDenied, fmt.Errorf("diagnostics are not available for your account"))
|
||||
}
|
||||
res := &apiv1.GetDiagnosticsResponse{
|
||||
SshFoundKey: installationinfo.Runtime.SshFoundKey,
|
||||
SshFoundConfig: installationinfo.Runtime.SshFoundConfig,
|
||||
}
|
||||
|
||||
return connect.NewResponse(res), nil
|
||||
}
|
||||
|
||||
|
|
@ -885,12 +916,19 @@ func (api *oliveTinAPI) Init(ctx ctx.Context, req *connect.Request[apiv1.InitReq
|
|||
|
||||
loginRequired := user.IsGuest() && api.cfg.AuthRequireGuestsToLogin
|
||||
|
||||
showVersion := user.EffectivePolicy.ShowVersionNumber
|
||||
currentVersion := ""
|
||||
availableVersion := ""
|
||||
if showVersion {
|
||||
currentVersion = installationinfo.Build.Version
|
||||
availableVersion = installationinfo.Runtime.AvailableVersion
|
||||
}
|
||||
res := &apiv1.InitResponse{
|
||||
ShowFooter: api.cfg.ShowFooter,
|
||||
ShowNavigation: api.cfg.ShowNavigation,
|
||||
ShowNewVersions: api.cfg.ShowNewVersions,
|
||||
AvailableVersion: installationinfo.Runtime.AvailableVersion,
|
||||
CurrentVersion: installationinfo.Build.Version,
|
||||
ShowNewVersions: showVersion && api.cfg.ShowNewVersions,
|
||||
AvailableVersion: availableVersion,
|
||||
CurrentVersion: currentVersion,
|
||||
PageTitle: api.cfg.PageTitle,
|
||||
SectionNavigationStyle: api.cfg.SectionNavigationStyle,
|
||||
DefaultIconForBack: api.cfg.DefaultIconForBack,
|
||||
|
|
@ -1253,7 +1291,7 @@ func (api *oliveTinAPI) RestartAction(ctx ctx.Context, req *connect.Request[apiv
|
|||
|
||||
return api.StartAction(ctx, &connect.Request[apiv1.StartActionRequest]{
|
||||
Msg: &apiv1.StartActionRequest{
|
||||
// FIXME
|
||||
BindingId: execReqLogEntry.GetBindingId(),
|
||||
UniqueTrackingId: req.Msg.ExecutionTrackingId,
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ func buildEffectivePolicy(policy *config.ConfigurationPolicy) *apiv1.EffectivePo
|
|||
ret := &apiv1.EffectivePolicy{
|
||||
ShowDiagnostics: policy.ShowDiagnostics,
|
||||
ShowLogList: policy.ShowLogList,
|
||||
ShowVersionNumber: policy.ShowVersionNumber,
|
||||
}
|
||||
|
||||
return ret
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ func buildEntityFieldsetContents(contents []*config.DashboardComponent, ent *ent
|
|||
for _, subitem := range contents {
|
||||
c := cloneItem(subitem, ent, entityType, rr)
|
||||
|
||||
log.Infof("cloneItem: %+v", c)
|
||||
log.Tracef("cloneItem: %+v", c)
|
||||
|
||||
if c != nil {
|
||||
ret = append(ret, c)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"runtime"
|
||||
|
||||
config "github.com/OliveTin/OliveTin/internal/config"
|
||||
|
|
@ -8,6 +9,12 @@ import (
|
|||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var ErrArgon2Busy = errors.New("too many concurrent password operations")
|
||||
|
||||
const argon2MaxConcurrent = 10
|
||||
|
||||
var argon2Sem = make(chan struct{}, argon2MaxConcurrent)
|
||||
|
||||
var defaultParams = argon2id.Params{
|
||||
Memory: 64 * 1024,
|
||||
Iterations: 4,
|
||||
|
|
@ -17,10 +24,16 @@ var defaultParams = argon2id.Params{
|
|||
}
|
||||
|
||||
func CreateHash(password string) (string, error) {
|
||||
select {
|
||||
case argon2Sem <- struct{}{}:
|
||||
defer func() { <-argon2Sem }()
|
||||
default:
|
||||
return "", ErrArgon2Busy
|
||||
}
|
||||
hash, err := argon2id.CreateHash(password, &defaultParams)
|
||||
|
||||
if err != nil {
|
||||
log.Fatal("Error creating hash: ", err)
|
||||
log.Warnf("Error creating hash: %v", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
|
|
@ -31,37 +44,40 @@ func createHash(password string) (string, error) {
|
|||
return CreateHash(password)
|
||||
}
|
||||
|
||||
func comparePasswordAndHash(password, hash string) bool {
|
||||
func comparePasswordAndHash(password, hash string) (bool, error) {
|
||||
select {
|
||||
case argon2Sem <- struct{}{}:
|
||||
defer func() { <-argon2Sem }()
|
||||
default:
|
||||
return false, ErrArgon2Busy
|
||||
}
|
||||
match, err := argon2id.ComparePasswordAndHash(password, hash)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("Error comparing password and hash: %v", err)
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return match
|
||||
return match, nil
|
||||
}
|
||||
|
||||
func checkUserPassword(cfg *config.Config, username, password string) bool {
|
||||
for _, user := range cfg.AuthLocalUsers.Users {
|
||||
if user.Username == username {
|
||||
match := comparePasswordAndHash(password, user.Password)
|
||||
|
||||
if match {
|
||||
return true
|
||||
} else {
|
||||
log.WithFields(log.Fields{
|
||||
"username": username,
|
||||
}).Warn("Password does not match for user")
|
||||
|
||||
return false
|
||||
func checkUserPassword(cfg *config.Config, username, password string) (bool, error) {
|
||||
user := cfg.FindUserByUsername(username)
|
||||
if user == nil {
|
||||
log.WithFields(log.Fields{"username": username}).Warn("Failed to check password for user, as username was not found")
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"username": username,
|
||||
}).Warn("Failed to check password for user, as username was not found")
|
||||
|
||||
return false
|
||||
return comparePasswordAndLogResult(password, user.Password, username)
|
||||
}
|
||||
|
||||
func comparePasswordAndLogResult(password, hash, username string) (bool, error) {
|
||||
match, err := comparePasswordAndHash(password, hash)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !match {
|
||||
log.WithFields(log.Fields{"username": username}).Warn("Password does not match for user")
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ func getEffectivePolicy(cfg *config.Config, u *AuthenticatedUser) *config.Config
|
|||
ret := &config.ConfigurationPolicy{
|
||||
ShowDiagnostics: cfg.DefaultPolicy.ShowDiagnostics,
|
||||
ShowLogList: cfg.DefaultPolicy.ShowLogList,
|
||||
ShowVersionNumber: cfg.DefaultPolicy.ShowVersionNumber,
|
||||
}
|
||||
|
||||
for _, acl := range cfg.AccessControlLists {
|
||||
|
|
@ -98,5 +99,9 @@ func buildConfigurationPolicy(ret *config.ConfigurationPolicy, policy config.Con
|
|||
ret.ShowLogList = policy.ShowLogList
|
||||
}
|
||||
|
||||
if policy.ShowVersionNumber {
|
||||
ret.ShowVersionNumber = policy.ShowVersionNumber
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,14 +108,20 @@ func randString(nByte int) (string, error) {
|
|||
return base64.URLEncoding.EncodeToString(b), nil
|
||||
}
|
||||
|
||||
func (h *OAuth2Handler) cookieSecure(r *http.Request) bool {
|
||||
useTLS := r.TLS != nil || r.Header.Get("X-Forwarded-Proto") == "https"
|
||||
return useTLS || h.cfg.Security.ForceSecureCookies
|
||||
}
|
||||
|
||||
func (h *OAuth2Handler) setOAuthCallbackCookie(w http.ResponseWriter, r *http.Request, name, value string) {
|
||||
cookie := &http.Cookie{
|
||||
Name: name,
|
||||
Value: value,
|
||||
MaxAge: 900, // 15 minutes
|
||||
Secure: r.TLS != nil,
|
||||
Secure: h.cookieSecure(r),
|
||||
HttpOnly: true,
|
||||
Path: "/",
|
||||
SameSite: http.SameSiteLaxMode,
|
||||
}
|
||||
|
||||
http.SetCookie(w, cookie)
|
||||
|
|
|
|||
|
|
@ -100,6 +100,7 @@ type AccessControlList struct {
|
|||
type ConfigurationPolicy struct {
|
||||
ShowDiagnostics bool `koanf:"showDiagnostics"`
|
||||
ShowLogList bool `koanf:"showLogList"`
|
||||
ShowVersionNumber bool `koanf:"showVersionNumber"`
|
||||
}
|
||||
|
||||
type PrometheusConfig struct {
|
||||
|
|
@ -107,6 +108,16 @@ type PrometheusConfig struct {
|
|||
DefaultGoMetrics bool `koanf:"defaultGoMetrics"`
|
||||
}
|
||||
|
||||
// SecurityConfig allows users to fine tune the security related HTTP headers and cookie options.
|
||||
type SecurityConfig struct {
|
||||
HeaderContentSecurityPolicy bool `koanf:"headerContentSecurityPolicy"`
|
||||
ContentSecurityPolicy string `koanf:"contentSecurityPolicy"`
|
||||
HeaderXContentTypeOptions bool `koanf:"headerXContentTypeOptions"`
|
||||
HeaderXFrameOptions bool `koanf:"headerXFrameOptions"`
|
||||
XFrameOptions string `koanf:"xFrameOptions"`
|
||||
ForceSecureCookies bool `koanf:"forceSecureCookies"`
|
||||
}
|
||||
|
||||
// Config is the global config used through the whole app.
|
||||
type Config struct {
|
||||
UseSingleHTTPFrontend bool `koanf:"useSingleHTTPFrontend"`
|
||||
|
|
@ -160,6 +171,7 @@ type Config struct {
|
|||
InsecureAllowDumpActionMap bool `koanf:"insecureAllowDumpActionMap"`
|
||||
InsecureAllowDumpJwtClaims bool `koanf:"insecureAllowDumpJwtClaims"`
|
||||
Prometheus PrometheusConfig `koanf:"prometheus"`
|
||||
Security SecurityConfig `koanf:"security"`
|
||||
SaveLogs SaveLogsConfig `koanf:"saveLogs"`
|
||||
DefaultIconForActions string `koanf:"defaultIconForActions"`
|
||||
DefaultIconForDirectories string `koanf:"defaultIconForDirectories"`
|
||||
|
|
@ -268,6 +280,11 @@ func DefaultConfigWithBasePort(basePort int) *Config {
|
|||
config.InsecureAllowDumpJwtClaims = false
|
||||
config.Prometheus.Enabled = false
|
||||
config.Prometheus.DefaultGoMetrics = false
|
||||
config.Security.HeaderContentSecurityPolicy = true
|
||||
config.Security.ContentSecurityPolicy = "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; frame-ancestors 'none'; base-uri 'self'"
|
||||
config.Security.HeaderXContentTypeOptions = true
|
||||
config.Security.HeaderXFrameOptions = true
|
||||
config.Security.XFrameOptions = "DENY"
|
||||
config.DefaultIconForActions = "😀"
|
||||
config.DefaultIconForDirectories = "📁"
|
||||
config.DefaultIconForBack = "«"
|
||||
|
|
@ -281,6 +298,7 @@ func DefaultConfigWithBasePort(basePort int) *Config {
|
|||
|
||||
config.DefaultPolicy.ShowDiagnostics = true
|
||||
config.DefaultPolicy.ShowLogList = true
|
||||
config.DefaultPolicy.ShowVersionNumber = true
|
||||
|
||||
return &config
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ func (cfg *Config) Sanitize() {
|
|||
cfg.sanitizeAuthRequireGuestsToLogin()
|
||||
cfg.sanitizeLogHistoryPageSize()
|
||||
cfg.sanitizeLocalUserPasswords()
|
||||
cfg.sanitizeSecurityHeaders()
|
||||
|
||||
// log.Infof("cfg %p", cfg)
|
||||
|
||||
|
|
@ -183,6 +184,25 @@ func (cfg *Config) sanitizeLocalUserPasswords() {
|
|||
}
|
||||
}
|
||||
|
||||
func (cfg *Config) sanitizeSecurityHeaders() {
|
||||
cfg.sanitizeSecurityHeadersCSP()
|
||||
cfg.sanitizeSecurityHeadersXFrameOptions()
|
||||
}
|
||||
|
||||
func (cfg *Config) sanitizeSecurityHeadersCSP() {
|
||||
if !cfg.Security.HeaderContentSecurityPolicy || cfg.Security.ContentSecurityPolicy != "" {
|
||||
return
|
||||
}
|
||||
cfg.Security.ContentSecurityPolicy = "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; frame-ancestors 'none'; base-uri 'self'"
|
||||
}
|
||||
|
||||
func (cfg *Config) sanitizeSecurityHeadersXFrameOptions() {
|
||||
if !cfg.Security.HeaderXFrameOptions || cfg.Security.XFrameOptions != "" {
|
||||
return
|
||||
}
|
||||
cfg.Security.XFrameOptions = "DENY"
|
||||
}
|
||||
|
||||
// parsePasswordTemplate expands {{ .Env.VAR }} in local user password fields using the process environment.
|
||||
func parsePasswordTemplate(source string) string {
|
||||
t, err := template.New("password").Option("missingkey=error").Parse(source)
|
||||
|
|
@ -239,8 +259,7 @@ func (arg *ActionArgument) sanitize() {
|
|||
|
||||
arg.sanitizeNoType()
|
||||
|
||||
// TODO Validate the default against the type checker, but this creates a
|
||||
// import loop
|
||||
// Default value validation runs in executor at config load (validateArgumentDefaults).
|
||||
}
|
||||
|
||||
func (arg *ActionArgument) sanitizeNoType() {
|
||||
|
|
|
|||
|
|
@ -1,23 +0,0 @@
|
|||
package cors
|
||||
|
||||
import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// AllowCors takes a HTTP handler and adds Access-Control-Allow-Origin headers to
|
||||
// responses.
|
||||
//
|
||||
// Note: HTTP OPTIONS requests (which need to be preflighted" for CORS) are not
|
||||
// handled because this app does not use HTTP PUT/PATCH/etc.
|
||||
func AllowCors(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if origin := r.Header.Get("Origin"); origin != "" {
|
||||
log.Debugf("Adding CORS header origin: %q", origin)
|
||||
|
||||
w.Header().Set("Access-Control-Allow-Origin", origin)
|
||||
}
|
||||
|
||||
h.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
package cors
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCors(t *testing.T) {
|
||||
req, _ := http.NewRequest("GET", "/health-check", nil)
|
||||
req.Header.Add("Origin", "1.2.3.4")
|
||||
|
||||
blat := AllowCors(http.FileServer(http.Dir(".")))
|
||||
|
||||
rr := httptest.NewRecorder()
|
||||
|
||||
blat.ServeHTTP(rr, req)
|
||||
|
||||
assert.Equal(t, http.StatusNotFound, rr.Code, "HTTP 404 on CORS")
|
||||
assert.Equal(t, "1.2.3.4", rr.Header().Get("Access-Control-Allow-Origin"), "CORS Header set")
|
||||
}
|
||||
|
|
@ -603,14 +603,14 @@ func getExecutionsCount(rate config.RateSpec, req *ExecutionRequest) int {
|
|||
|
||||
then := time.Now().Add(-duration)
|
||||
|
||||
currentEntityPrefix := ""
|
||||
if req.Binding != nil && req.Binding.Entity != nil {
|
||||
currentEntityPrefix = req.Binding.Entity.UniqueKey
|
||||
}
|
||||
for _, logEntry := range req.executor.GetLogsByBindingId(req.Binding.ID) {
|
||||
// FIXME
|
||||
/*
|
||||
if logEntry.EntityPrefix != req.EntityPrefix {
|
||||
if logEntry.EntityPrefix != currentEntityPrefix {
|
||||
continue
|
||||
}
|
||||
*/
|
||||
|
||||
if logEntry.DatetimeStarted.After(then) && !logEntry.Blocked {
|
||||
|
||||
executions += 1
|
||||
|
|
@ -761,28 +761,12 @@ func fail(req *ExecutionRequest, err error) bool {
|
|||
func stepRequestAction(req *ExecutionRequest) bool {
|
||||
metricActionsRequested.Inc()
|
||||
|
||||
// If there is no binding or action, do not proceed. Leave default
|
||||
// log entry values (icon/title/id) and stop execution gracefully.
|
||||
if req.Binding == nil || req.Binding.Action == nil {
|
||||
log.Warnf("Action request has no binding/action; skipping execution")
|
||||
if !stepRequestActionHasBinding(req) {
|
||||
return false
|
||||
}
|
||||
|
||||
req.logEntry.Binding = req.Binding
|
||||
req.logEntry.ActionConfigTitle = req.Binding.Action.Title
|
||||
req.logEntry.ActionTitle = tpl.ParseTemplateOfActionBeforeExec(req.Binding.Action.Title, req.Binding.Entity)
|
||||
req.logEntry.ActionIcon = req.Binding.Action.Icon
|
||||
req.logEntry.Tags = req.Tags
|
||||
|
||||
req.executor.logmutex.Lock()
|
||||
|
||||
if _, containsKey := req.executor.LogsByBindingId[req.Binding.ID]; !containsKey {
|
||||
req.executor.LogsByBindingId[req.Binding.ID] = make([]*InternalLogEntry, 0)
|
||||
}
|
||||
|
||||
req.executor.LogsByBindingId[req.Binding.ID] = append(req.executor.LogsByBindingId[req.Binding.ID], req.logEntry)
|
||||
|
||||
req.executor.logmutex.Unlock()
|
||||
stepRequestActionPopulateLogEntry(req)
|
||||
stepRequestActionRegisterLog(req)
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"actionTitle": req.logEntry.ActionTitle,
|
||||
|
|
@ -794,6 +778,35 @@ func stepRequestAction(req *ExecutionRequest) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func stepRequestActionHasBinding(req *ExecutionRequest) bool {
|
||||
if req.Binding == nil || req.Binding.Action == nil {
|
||||
log.Warnf("Action request has no binding/action; skipping execution")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func stepRequestActionPopulateLogEntry(req *ExecutionRequest) {
|
||||
req.logEntry.Binding = req.Binding
|
||||
req.logEntry.ActionConfigTitle = req.Binding.Action.Title
|
||||
req.logEntry.ActionTitle = tpl.ParseTemplateOfActionBeforeExec(req.Binding.Action.Title, req.Binding.Entity)
|
||||
req.logEntry.ActionIcon = req.Binding.Action.Icon
|
||||
req.logEntry.Tags = req.Tags
|
||||
if req.Binding.Entity != nil {
|
||||
req.logEntry.EntityPrefix = req.Binding.Entity.UniqueKey
|
||||
}
|
||||
}
|
||||
|
||||
func stepRequestActionRegisterLog(req *ExecutionRequest) {
|
||||
req.executor.logmutex.Lock()
|
||||
defer req.executor.logmutex.Unlock()
|
||||
|
||||
if _, containsKey := req.executor.LogsByBindingId[req.Binding.ID]; !containsKey {
|
||||
req.executor.LogsByBindingId[req.Binding.ID] = make([]*InternalLogEntry, 0)
|
||||
}
|
||||
req.executor.LogsByBindingId[req.Binding.ID] = append(req.executor.LogsByBindingId[req.Binding.ID], req.logEntry)
|
||||
}
|
||||
|
||||
func stepLogStart(req *ExecutionRequest) bool {
|
||||
log.WithFields(log.Fields{
|
||||
"actionTitle": req.logEntry.ActionTitle,
|
||||
|
|
|
|||
|
|
@ -41,7 +41,41 @@ type RebuildActionMapRequest struct {
|
|||
DashboardActionTitles []string
|
||||
}
|
||||
|
||||
func validateArgumentDefaults(cfg *config.Config) {
|
||||
if cfg == nil {
|
||||
return
|
||||
}
|
||||
for _, action := range cfg.Actions {
|
||||
validateActionArgumentDefaults(action)
|
||||
}
|
||||
}
|
||||
|
||||
func validateActionArgumentDefaults(action *config.Action) {
|
||||
if action == nil {
|
||||
return
|
||||
}
|
||||
for i := range action.Arguments {
|
||||
validateArgumentDefault(action, &action.Arguments[i])
|
||||
}
|
||||
}
|
||||
|
||||
func validateArgumentDefault(action *config.Action, arg *config.ActionArgument) {
|
||||
if arg.Default == "" {
|
||||
return
|
||||
}
|
||||
if err := ValidateArgument(arg, arg.Default, action); err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"actionTitle": action.Title,
|
||||
"argName": arg.Name,
|
||||
"default": arg.Default,
|
||||
"error": err,
|
||||
}).Warn("Argument default value failed validation")
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Executor) RebuildActionMap() {
|
||||
validateArgumentDefaults(e.Cfg)
|
||||
|
||||
e.MapActionBindingsLock.Lock()
|
||||
|
||||
clear(e.MapActionBindings)
|
||||
|
|
|
|||
|
|
@ -23,6 +23,40 @@ import (
|
|||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func applySecurityHeaders(cfg *config.Config, w http.ResponseWriter) {
|
||||
applyCSP(cfg, w)
|
||||
applyXContentTypeOptions(cfg, w)
|
||||
applyXFrameOptions(cfg, w)
|
||||
}
|
||||
|
||||
func applyCSP(cfg *config.Config, w http.ResponseWriter) {
|
||||
if !cfg.Security.HeaderContentSecurityPolicy || cfg.Security.ContentSecurityPolicy == "" {
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Security-Policy", cfg.Security.ContentSecurityPolicy)
|
||||
}
|
||||
|
||||
func applyXContentTypeOptions(cfg *config.Config, w http.ResponseWriter) {
|
||||
if !cfg.Security.HeaderXContentTypeOptions {
|
||||
return
|
||||
}
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
}
|
||||
|
||||
func applyXFrameOptions(cfg *config.Config, w http.ResponseWriter) {
|
||||
if !cfg.Security.HeaderXFrameOptions || cfg.Security.XFrameOptions == "" {
|
||||
return
|
||||
}
|
||||
w.Header().Set("X-Frame-Options", cfg.Security.XFrameOptions)
|
||||
}
|
||||
|
||||
func securityHeadersMiddleware(cfg *config.Config, next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
applySecurityHeaders(cfg, w)
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func logDebugRequest(cfg *config.Config, source string, r *http.Request) {
|
||||
if cfg.LogDebugOptions.SingleFrontendRequests {
|
||||
log.Debugf("SingleFrontend HTTP Req URL %v: %q", source, r.URL)
|
||||
|
|
@ -96,7 +130,7 @@ func StartFrontendMux(cfg *config.Config, ex *executor.Executor) {
|
|||
|
||||
srv := &http.Server{
|
||||
Addr: cfg.ListenAddressSingleHTTPFrontend,
|
||||
Handler: mux,
|
||||
Handler: securityHeadersMiddleware(cfg, mux),
|
||||
}
|
||||
|
||||
log.Fatal(srv.ListenAndServe())
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
package httpservers
|
||||
|
||||
import (
|
||||
|
||||
// cors "github.com/OliveTin/OliveTin/internal/cors"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
|
|
|
|||
|
|
@ -40,15 +40,23 @@ func configToSosreport(cfg *config.Config) *sosReportConfig {
|
|||
}
|
||||
}
|
||||
|
||||
func GetSosReport() string {
|
||||
func GetSosReport(redactVersion bool) string {
|
||||
ret := ""
|
||||
|
||||
ret += "### SOSREPORT START (copy all text to SOSREPORT END)\n"
|
||||
|
||||
out, _ := yaml.Marshal(Build)
|
||||
buildForReport := *Build
|
||||
if redactVersion {
|
||||
buildForReport.Version = "[redacted]"
|
||||
}
|
||||
out, _ := yaml.Marshal(&buildForReport)
|
||||
ret += fmt.Sprintf("# Build: \n%+v\n", string(out))
|
||||
|
||||
out, _ = yaml.Marshal(Runtime)
|
||||
runtimeForReport := *Runtime
|
||||
if redactVersion {
|
||||
runtimeForReport.AvailableVersion = "[redacted]"
|
||||
}
|
||||
out, _ = yaml.Marshal(&runtimeForReport)
|
||||
ret += fmt.Sprintf("# Runtime:\n%+v\n", string(out))
|
||||
|
||||
out, _ = yaml.Marshal(configToSosreport(Config))
|
||||
|
|
|
|||
Loading…
Reference in New Issue