Compare commits
436 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5553e7e34d | ||
|
|
220a55500c | ||
|
|
a4281edbc4 | ||
|
|
0398c69c7f | ||
|
|
7871f6bc27 | ||
|
|
3dc0fdc039 | ||
|
|
e2bbf91e8a | ||
|
|
ee974a5961 | ||
|
|
40c4ce76c5 | ||
|
|
28b080122a | ||
|
|
6df2db82af | ||
|
|
ff2b72f869 | ||
|
|
f5ad4defc9 | ||
|
|
6499469487 | ||
|
|
71b1b708b7 | ||
|
|
63c6d8952b | ||
|
|
33a7fbb205 | ||
|
|
36d0e78834 | ||
|
|
9e0416f1ab | ||
|
|
f4a08fc0af | ||
|
|
115de8ee25 | ||
|
|
27cb17dbfd | ||
|
|
31a5d640eb | ||
|
|
b45e11ce7f | ||
|
|
4388ecc4eb | ||
|
|
656d8075b2 | ||
|
|
8b209a202f | ||
|
|
2e66a13f48 | ||
|
|
d54ed26c71 | ||
|
|
5cf02ffae9 | ||
|
|
6afd0b16dc | ||
|
|
0b8af385f1 | ||
|
|
9a3063b7da | ||
|
|
71541029e7 | ||
|
|
076b803a5c | ||
|
|
97ef82f831 | ||
|
|
2ca484c691 | ||
|
|
4e5dcf0fc3 | ||
|
|
18e50975d4 | ||
|
|
d425af3c85 | ||
|
|
fce84d1de0 | ||
|
|
dc19984f23 | ||
|
|
8c1ecae68a | ||
|
|
862d692444 | ||
|
|
854a0c16b3 | ||
|
|
3d74e9762c | ||
|
|
3d8b98f563 | ||
|
|
06af416642 | ||
|
|
01920841d2 | ||
|
|
78aceb2b53 | ||
|
|
dce9bbd046 | ||
|
|
9f4573ade8 | ||
|
|
24af63da42 | ||
|
|
52c77fd388 | ||
|
|
19e6cc87c2 | ||
|
|
9bfed73b03 | ||
|
|
095241517b | ||
|
|
339885b2a0 | ||
|
|
6cfc985337 | ||
|
|
1c47685aea | ||
|
|
efa74a5f50 | ||
|
|
4c432cd356 | ||
|
|
0b07cb3885 | ||
|
|
8d13be5e87 | ||
|
|
3c34602f9e | ||
|
|
adfc96074f | ||
|
|
7cc7b874d1 | ||
|
|
4d12a5061d | ||
|
|
b274add4da | ||
|
|
fd51c9dc4c | ||
|
|
51f8794aa6 | ||
|
|
3db998f9c4 | ||
|
|
0a2a7087a7 | ||
|
|
8f0eb11ced | ||
|
|
e3e3599095 | ||
|
|
aa74e31453 | ||
|
|
e1f6e729fd | ||
|
|
13d83a6d1c | ||
|
|
6075387654 | ||
|
|
69fad3f55f | ||
|
|
e3864b62a4 | ||
|
|
22176f4e0f | ||
|
|
a89d7ec0ea | ||
|
|
8262049e20 | ||
|
|
c61e1e0a2a | ||
|
|
b376cf6c65 | ||
|
|
16bae25ce6 | ||
|
|
57ba17a12e | ||
|
|
f4d98a4910 | ||
|
|
fa32d78ff1 | ||
|
|
56f22a4479 | ||
|
|
7b88d3a1bc | ||
|
|
c8a39f9544 | ||
|
|
e77d1be53e | ||
|
|
6765bd0624 | ||
|
|
5f7b563a01 | ||
|
|
3885875149 | ||
|
|
cf05d5026f | ||
|
|
3e83a30739 | ||
|
|
49c5f5a8f0 | ||
|
|
72939e0cd7 | ||
|
|
271560894a | ||
|
|
6a591c1bcd | ||
|
|
3fdcfef1b4 | ||
|
|
7b8cfa2062 | ||
|
|
cc5921fd74 | ||
|
|
d027b7f759 | ||
|
|
f1524b0120 | ||
|
|
9985892751 | ||
|
|
cfd60bdd91 | ||
|
|
779f2a86e5 | ||
|
|
f47c4445bd | ||
|
|
1aeb4cc3d5 | ||
|
|
9e0a0205cc | ||
|
|
1058efb17a | ||
|
|
d0f744ebef | ||
|
|
a8c043cb16 | ||
|
|
978e02b5dc | ||
|
|
b39dbfff96 | ||
|
|
bd89cfde79 | ||
|
|
0bd563b2e5 | ||
|
|
22fe915629 | ||
|
|
aa161a5365 | ||
|
|
0557514cb4 | ||
|
|
298203253c | ||
|
|
cbeef2b248 | ||
|
|
e68a74ba48 | ||
|
|
02a0db1408 | ||
|
|
348376c672 | ||
|
|
037b02e268 | ||
|
|
fe534ab4e6 | ||
|
|
6625d54d67 | ||
|
|
ee6d1ed586 | ||
|
|
6de1d88e11 | ||
|
|
de19b6f17b | ||
|
|
226a90be1d | ||
|
|
6cfb6ff06a | ||
|
|
649c3d74b8 | ||
|
|
662ce3b2f5 | ||
|
|
0292bc154d | ||
|
|
ceee83f03a | ||
|
|
144904f0f6 | ||
|
|
963c8f1221 | ||
|
|
6c50c38f83 | ||
|
|
3aac62cc81 | ||
|
|
78a05d39c4 | ||
|
|
79bec3880e | ||
|
|
bdf7bd6309 | ||
|
|
4ce1ba999b | ||
|
|
d01501703b | ||
|
|
6a38a09462 | ||
|
|
78990e354f | ||
|
|
3189ebdfef | ||
|
|
39bf627b0a | ||
|
|
a838c763ea | ||
|
|
0afea63994 | ||
|
|
0df9487527 | ||
|
|
9274ee72ad | ||
|
|
2b6c3debb4 | ||
|
|
8dd6dd4e7f | ||
|
|
5e64c96497 | ||
|
|
54c0b4b8a2 | ||
|
|
31056e12ba | ||
|
|
151c8117a3 | ||
|
|
9b5c17c2db | ||
|
|
23e01b257e | ||
|
|
ecc8c7a86e | ||
|
|
ee4d7b9b69 | ||
|
|
80c03839a4 | ||
|
|
f394cb69ce | ||
|
|
52137ba9e5 | ||
|
|
942b8101cc | ||
|
|
a0a6b33ecd | ||
|
|
d4c5e1b51c | ||
|
|
96923aed75 | ||
|
|
a04f833e3f | ||
|
|
3b52cc9bd4 | ||
|
|
df2e92e451 | ||
|
|
8836fe043b | ||
|
|
7ce6a58099 | ||
|
|
57d6aca716 | ||
|
|
8d99637455 | ||
|
|
abd66780f4 | ||
|
|
a5175a35ec | ||
|
|
d9f945b5df | ||
|
|
0c55e39e8c | ||
|
|
b5443952da | ||
|
|
b9f0ccfaba | ||
|
|
24742325b7 | ||
|
|
c87ebe447f | ||
|
|
462cf16db9 | ||
|
|
edaa4e8754 | ||
|
|
76c596c574 | ||
|
|
b5554f6dcf | ||
|
|
fc65f1afd1 | ||
|
|
b066b6a920 | ||
|
|
bc0e63aac8 | ||
|
|
343ff575e6 | ||
|
|
08c922dca6 | ||
|
|
4dd6519cc6 | ||
|
|
cdffdae289 | ||
|
|
27e3b82223 | ||
|
|
239b31748a | ||
|
|
b465b74326 | ||
|
|
616f262d09 | ||
|
|
8aa0ec17c5 | ||
|
|
a8c5b53a2c | ||
|
|
e96dbd444e | ||
|
|
939e2acb0b | ||
|
|
a04955dc70 | ||
|
|
ba04a22492 | ||
|
|
a281fe129f | ||
|
|
a655cc8d3b | ||
|
|
63b584c83d | ||
|
|
7dffd5f079 | ||
|
|
044e5702df | ||
|
|
3c3b9546d9 | ||
|
|
5bc0e74b53 | ||
|
|
f0d4dddacd | ||
|
|
f4a3f46bcf | ||
|
|
38472e4cd2 | ||
|
|
9db5d1e4f4 | ||
|
|
4cadaf7d49 | ||
|
|
748486160f | ||
|
|
2c0a0b2bc4 | ||
|
|
7e51d4bebb | ||
|
|
c011e67122 | ||
|
|
394b4c403d | ||
|
|
74030aa067 | ||
|
|
07b8c745e6 | ||
|
|
6767bfa2d2 | ||
|
|
607d94fef4 | ||
|
|
83b060ef94 | ||
|
|
cb14cb94ce | ||
|
|
2b9de49fbe | ||
|
|
290f273bdf | ||
|
|
7b43779fb0 | ||
|
|
924c38faa6 | ||
|
|
e4d5f9610e | ||
|
|
04e9cb0ac8 | ||
|
|
da53daff37 | ||
|
|
8c26eff2c1 | ||
|
|
044c265423 | ||
|
|
0053658d5d | ||
|
|
99cf3b378f | ||
|
|
78293eab62 | ||
|
|
1a84be5782 | ||
|
|
178f82b675 | ||
|
|
ec5fbbcd1e | ||
|
|
78164054d4 | ||
|
|
6d5d11d5b4 | ||
|
|
9e3b93d385 | ||
|
|
d77cf93193 | ||
|
|
2cca3f3722 | ||
|
|
36d96a1791 | ||
|
|
82e34a5df2 | ||
|
|
7b83f4b1dc | ||
|
|
7d9910d1ca | ||
|
|
7a63f6da56 | ||
|
|
0043833f36 | ||
|
|
3ad3bccadb | ||
|
|
39e94c890e | ||
|
|
701039454a | ||
|
|
ec77a03d7c | ||
|
|
8dbad84a58 | ||
|
|
1767a37162 | ||
|
|
622c3a067a | ||
|
|
4389548b64 | ||
|
|
8cb0f1e558 | ||
|
|
faafb77c73 | ||
|
|
0ecd1c73c1 | ||
|
|
88bf40f9a6 | ||
|
|
a025163b34 | ||
|
|
07c80462b7 | ||
|
|
79ac2277d4 | ||
|
|
1c27bee9d0 | ||
|
|
56dc58b0b8 | ||
|
|
4018addd79 | ||
|
|
429dfb4314 | ||
|
|
1d7bb0bb2b | ||
|
|
476eb673bb | ||
|
|
71681b710c | ||
|
|
fb02a7da06 | ||
|
|
5fdc341138 | ||
|
|
15de6caf75 | ||
|
|
77bc2d5006 | ||
|
|
972f5fca9d | ||
|
|
083314ee2d | ||
|
|
078ce0e546 | ||
|
|
9beca2c226 | ||
|
|
451f23ae24 | ||
|
|
300ebfa19f | ||
|
|
1ce2846c95 | ||
|
|
7fb8c11a9d | ||
|
|
e7993c2d1b | ||
|
|
3e93f7ff88 | ||
|
|
f0580956db | ||
|
|
65b0bab26d | ||
|
|
a559421293 | ||
|
|
6ef35c26a4 | ||
|
|
8a918324aa | ||
|
|
d30c0c8cbb | ||
|
|
1697c826c0 | ||
|
|
b378b8c8ef | ||
|
|
2c42d7ff81 | ||
|
|
e1f36ee54a | ||
|
|
698f72f828 | ||
|
|
8dd94f5336 | ||
|
|
1dc21b9a21 | ||
|
|
248215cc77 | ||
|
|
a6eee73c11 | ||
|
|
50d6a39312 | ||
|
|
467b6b9bcb | ||
|
|
6e6246797c | ||
|
|
f8e4f747f5 | ||
|
|
9acd49fcc6 | ||
|
|
636d12d43f | ||
|
|
5e9383de95 | ||
|
|
4863af863e | ||
|
|
b6d4c62edd | ||
|
|
bf733f3822 | ||
|
|
bbf4027418 | ||
|
|
dbffc5fc22 | ||
|
|
f4a9420002 | ||
|
|
657854bd29 | ||
|
|
cdc9e7d921 | ||
|
|
b125121ac8 | ||
|
|
0c480dd5ec | ||
|
|
c07b8dcf73 | ||
|
|
912a4b216f | ||
|
|
e7fb205c31 | ||
|
|
a2ba20e12f | ||
|
|
f515dd82fe | ||
|
|
61d3193c41 | ||
|
|
430ae66955 | ||
|
|
3abbbc82b2 | ||
|
|
854181f63e | ||
|
|
df996794ed | ||
|
|
2d94018e3c | ||
|
|
72bb9d0ca1 | ||
|
|
93bd0d65e2 | ||
|
|
495b0f0068 | ||
|
|
3275b6a6d8 | ||
|
|
fed5aa1599 | ||
|
|
6bc4efbac1 | ||
|
|
cc0164a67b | ||
|
|
b968cc25ad | ||
|
|
d116a35a6d | ||
|
|
49f856bdd5 | ||
|
|
0d628f589a | ||
|
|
4387b2149f | ||
|
|
8cc602434e | ||
|
|
6411dc9504 | ||
|
|
32c34b0a11 | ||
|
|
6e8f5e0fc2 | ||
|
|
3ce377dbd1 | ||
|
|
ad502b9f18 | ||
|
|
fde186a5a3 | ||
|
|
0823f623c8 | ||
|
|
6cec113304 | ||
|
|
cd42d77a46 | ||
|
|
35907beaca | ||
|
|
a062a59288 | ||
|
|
842c2decd0 | ||
|
|
d1069ed359 | ||
|
|
6d81a1b1f8 | ||
|
|
b2fe478dae | ||
|
|
02ed6a6e8b | ||
|
|
1b271ab467 | ||
|
|
bacb5f8901 | ||
|
|
ae7371da95 | ||
|
|
60f5eb603b | ||
|
|
420ed00f55 | ||
|
|
b975871e9d | ||
|
|
803ffe2960 | ||
|
|
c96c95924c | ||
|
|
f02786001c | ||
|
|
542b7192c3 | ||
|
|
b31aa10b52 | ||
|
|
1eba59954d | ||
|
|
b71d9f05c5 | ||
|
|
fc5e94d55f | ||
|
|
3875fb3eaa | ||
|
|
b3d4132fe6 | ||
|
|
21f20bb9ea | ||
|
|
df937467a0 | ||
|
|
d1ae271111 | ||
|
|
e7fb3e0e45 | ||
|
|
b7b0271ec7 | ||
|
|
9935b839b7 | ||
|
|
0e11098c31 | ||
|
|
c55e0a069b | ||
|
|
c3da876b04 | ||
|
|
643a9c6c7c | ||
|
|
0c3a94172d | ||
|
|
527eb16700 | ||
|
|
e3aec3f094 | ||
|
|
eac2734df4 | ||
|
|
a411e7c977 | ||
|
|
28c4abe2d0 | ||
|
|
a9ef6ebf5f | ||
|
|
c12415c12d | ||
|
|
1f481e690b | ||
|
|
58aad859e1 | ||
|
|
b9ebfe09ee | ||
|
|
864cf7af99 | ||
|
|
b76f460979 | ||
|
|
cbd2c4682d | ||
|
|
d49bdf7d49 | ||
|
|
559a7278a0 | ||
|
|
4a172fae97 | ||
|
|
fc4263e2f9 | ||
|
|
c1b9b4c81b | ||
|
|
aa9b73522e | ||
|
|
0904f83627 | ||
|
|
253053cc23 | ||
|
|
08a3ff65c7 | ||
|
|
ee8fac8be8 | ||
|
|
9fa49b40b3 | ||
|
|
de13119e02 | ||
|
|
bf9acd7691 | ||
|
|
a5066fecc8 | ||
|
|
6432681440 | ||
|
|
b3b6df9d82 | ||
|
|
fe7be4ef62 | ||
|
|
b4603547f6 | ||
|
|
b33b9315ea | ||
|
|
6ae03fa028 | ||
|
|
e1bb1e0472 | ||
|
|
411670e4f5 | ||
|
|
1c55932f84 | ||
|
|
5a77054d6b | ||
|
|
84c5fd58f9 | ||
|
|
98979911ee | ||
|
|
c0cf7358c7 | ||
|
|
9053e64dff |
@@ -1,7 +0,0 @@
|
||||
node_modules/
|
||||
dist/
|
||||
target/
|
||||
console
|
||||
!console/
|
||||
portal-ui/node_modules/
|
||||
.git/
|
||||
49
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
49
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: community, triage
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
## NOTE
|
||||
|
||||
Please subscribe to our [paid subscription plans](https://min.io/pricing) for 24x7 support from our Engineering team.
|
||||
|
||||
<!--- Provide a general summary of the issue in the title above -->
|
||||
|
||||
## Expected Behavior
|
||||
<!--- If you're describing a bug, tell us what should happen -->
|
||||
<!--- If you're suggesting a change/improvement, tell us how it should work -->
|
||||
|
||||
## Current Behavior
|
||||
<!--- If describing a bug, tell us what happens instead of the expected behavior -->
|
||||
<!--- If suggesting a change/improvement, explain the difference from current behavior -->
|
||||
|
||||
## Possible Solution
|
||||
<!--- Not obligatory, but suggest a fix/reason for the bug, -->
|
||||
<!--- or ideas how to implement the addition or change -->
|
||||
|
||||
## Steps to Reproduce (for bugs)
|
||||
<!--- Provide a link to a live example, or an unambiguous set of steps to -->
|
||||
<!--- reproduce this bug. Include code to reproduce, if relevant -->
|
||||
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
4.
|
||||
|
||||
## Context
|
||||
<!--- How has this issue affected you? What are you trying to accomplish? -->
|
||||
<!--- Providing context helps us come up with a solution that is most useful in the real world -->
|
||||
|
||||
## Regression
|
||||
<!-- Is this issue a regression? (Yes / No) -->
|
||||
<!-- If Yes, optionally please include the MinIO version or commit id or PR# that caused this regression, if you have these details. -->
|
||||
|
||||
## Your Environment
|
||||
<!--- Include as many relevant details about the environment you experienced the bug in -->
|
||||
* MinIO version used (`minio --version`):
|
||||
* Server setup and configuration:
|
||||
* Operating System and version (`uname -a`):
|
||||
18
.github/workflows/issues.yaml
vendored
Normal file
18
.github/workflows/issues.yaml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
# @format
|
||||
|
||||
name: Issue Workflow
|
||||
|
||||
on:
|
||||
issues:
|
||||
types:
|
||||
- opened
|
||||
|
||||
jobs:
|
||||
add-to-project:
|
||||
name: Add issue to project
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/add-to-project@v0.5.0
|
||||
with:
|
||||
project-url: https://github.com/orgs/miniohq/projects/2
|
||||
github-token: ${{ secrets.BOT_PAT }}
|
||||
1172
.github/workflows/jobs.yaml
vendored
1172
.github/workflows/jobs.yaml
vendored
File diff suppressed because it is too large
Load Diff
53
.github/workflows/vulncheck.yaml
vendored
Normal file
53
.github/workflows/vulncheck.yaml
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
# @format
|
||||
|
||||
name: Vulnerability Check
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
permissions:
|
||||
contents: read # to fetch code (actions/checkout)
|
||||
|
||||
jobs:
|
||||
vulncheck:
|
||||
name: Analysis
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: 1.23.8
|
||||
check-latest: true
|
||||
- name: Get official govulncheck
|
||||
run: go install golang.org/x/vuln/cmd/govulncheck@latest
|
||||
shell: bash
|
||||
- name: Run govulncheck
|
||||
run: govulncheck ./...
|
||||
shell: bash
|
||||
|
||||
react-code-known-vulnerabilities:
|
||||
name: "React Code Has No Known Vulnerable Deps"
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [ 1.23.x ]
|
||||
os: [ ubuntu-latest ]
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
- name: Read .nvmrc
|
||||
id: node_version
|
||||
run: echo "$(cat .nvmrc)" && echo "NVMRC=$(cat .nvmrc)" >> $GITHUB_ENV
|
||||
- name: Enable Corepack
|
||||
run: corepack enable
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ env.NVMRC }}
|
||||
- name: Checks for known security issues with the installed packages
|
||||
working-directory: ./web-app
|
||||
continue-on-error: false
|
||||
run: |
|
||||
yarn npm audit --recursive --environment production --no-deprecations
|
||||
13
.gitignore
vendored
13
.gitignore
vendored
@@ -1,12 +1,12 @@
|
||||
# Playwright Data
|
||||
portal-ui/storage/
|
||||
portal-ui/playwright/.auth/admin.json
|
||||
web-app/storage/
|
||||
web-app/playwright/.auth/admin.json
|
||||
|
||||
# Report from Playwright
|
||||
portal-ui/playwright-report/
|
||||
web-app/playwright-report/
|
||||
|
||||
# Coverage from Playwright
|
||||
portal-ui/.nyc_output/
|
||||
web-app/.nyc_output/
|
||||
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
@@ -37,7 +37,7 @@ dist/
|
||||
|
||||
# Ignore node_modules
|
||||
|
||||
portal-ui/node_modules/
|
||||
web-app/node_modules/
|
||||
|
||||
# Ignore tls cert and key
|
||||
private.key
|
||||
@@ -48,3 +48,6 @@ public.crt
|
||||
*.code-workspace
|
||||
*~
|
||||
.eslintcache
|
||||
|
||||
# Ignore Bin files
|
||||
bin/
|
||||
|
||||
55
.golangci.bck.yml
Normal file
55
.golangci.bck.yml
Normal file
@@ -0,0 +1,55 @@
|
||||
linters-settings:
|
||||
misspell:
|
||||
locale: US
|
||||
testifylint:
|
||||
disable:
|
||||
- go-require
|
||||
staticcheck:
|
||||
checks:
|
||||
[
|
||||
"all",
|
||||
"-ST1005",
|
||||
"-ST1000",
|
||||
"-SA4000",
|
||||
"-SA9004",
|
||||
"-SA1019",
|
||||
"-SA1008",
|
||||
"-U1000",
|
||||
"-ST1016",
|
||||
]
|
||||
goheader:
|
||||
values:
|
||||
regexp:
|
||||
copyright-holder: Copyright \(c\) (20\d\d\-20\d\d)|2021|({{year}})
|
||||
template-path: .license.tmpl
|
||||
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
- goimports
|
||||
- misspell
|
||||
- govet
|
||||
- revive
|
||||
- ineffassign
|
||||
- gosimple
|
||||
- gomodguard
|
||||
- gofmt
|
||||
- unused
|
||||
- staticcheck
|
||||
- unconvert
|
||||
- gocritic
|
||||
- gofumpt
|
||||
- durationcheck
|
||||
|
||||
issues:
|
||||
exclude-use-default: false
|
||||
exclude:
|
||||
- should have a package comment
|
||||
# TODO(y4m4): Remove once all exported ident. have comments!
|
||||
- comment on exported function
|
||||
- comment on exported type
|
||||
- should have comment
|
||||
- use leading k in Go names
|
||||
- comment on exported const
|
||||
exclude-dirs:
|
||||
- api/operations
|
||||
116
.golangci.yml
116
.golangci.yml
@@ -1,49 +1,73 @@
|
||||
linters-settings:
|
||||
golint:
|
||||
min-confidence: 0
|
||||
|
||||
misspell:
|
||||
locale: US
|
||||
|
||||
goheader:
|
||||
values:
|
||||
regexp:
|
||||
copyright-holder: Copyright \(c\) (20\d\d\-20\d\d)|2021|({{year}})
|
||||
template-path: .license.tmpl
|
||||
|
||||
version: "2"
|
||||
linters:
|
||||
disable-all: true
|
||||
default: none
|
||||
enable:
|
||||
- goimports
|
||||
- misspell
|
||||
- govet
|
||||
- revive
|
||||
- ineffassign
|
||||
- gosimple
|
||||
- gomodguard
|
||||
- gofmt
|
||||
- unused
|
||||
- unconvert
|
||||
- varcheck
|
||||
- gocritic
|
||||
- gofumpt
|
||||
- durationcheck
|
||||
|
||||
service:
|
||||
golangci-lint-version: 1.43.0 # use the fixed version to not introduce new linters unexpectedly
|
||||
|
||||
issues:
|
||||
exclude-use-default: false
|
||||
exclude:
|
||||
- should have a package comment
|
||||
# TODO(y4m4): Remove once all exported ident. have comments!
|
||||
- comment on exported function
|
||||
- comment on exported type
|
||||
- should have comment
|
||||
- use leading k in Go names
|
||||
- comment on exported const
|
||||
run:
|
||||
skip-dirs:
|
||||
- pkg/clientgen
|
||||
- pkg/apis/networking.gke.io
|
||||
- restapi/operations
|
||||
- gocritic
|
||||
- gomodguard
|
||||
- govet
|
||||
- ineffassign
|
||||
- misspell
|
||||
- revive
|
||||
- staticcheck
|
||||
- unconvert
|
||||
- unused
|
||||
settings:
|
||||
goheader:
|
||||
values:
|
||||
regexp:
|
||||
copyright-holder: Copyright \(c\) (20\d\d\-20\d\d)|2021|({{year}})
|
||||
template-path: .license.tmpl
|
||||
misspell:
|
||||
locale: US
|
||||
staticcheck:
|
||||
checks:
|
||||
- all
|
||||
- -QF1001
|
||||
- -QF1008
|
||||
- -QF1010
|
||||
- -QF1012
|
||||
- -SA1008
|
||||
- -SA1019
|
||||
- -SA4000
|
||||
- -SA9004
|
||||
- -ST1000
|
||||
- -ST1005
|
||||
- -ST1016
|
||||
- -ST1019
|
||||
- -U1000
|
||||
testifylint:
|
||||
disable:
|
||||
- go-require
|
||||
exclusions:
|
||||
generated: lax
|
||||
rules:
|
||||
- path: (.+)\.go$
|
||||
text: should have a package comment
|
||||
- path: (.+)\.go$
|
||||
text: comment on exported function
|
||||
- path: (.+)\.go$
|
||||
text: comment on exported type
|
||||
- path: (.+)\.go$
|
||||
text: should have comment
|
||||
- path: (.+)\.go$
|
||||
text: use leading k in Go names
|
||||
- path: (.+)\.go$
|
||||
text: comment on exported const
|
||||
paths:
|
||||
- api/operations
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
formatters:
|
||||
enable:
|
||||
- gofmt
|
||||
- gofumpt
|
||||
- goimports
|
||||
exclusions:
|
||||
generated: lax
|
||||
paths:
|
||||
- api/operations
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
|
||||
191
.goreleaser.yml
191
.goreleaser.yml
@@ -1,191 +0,0 @@
|
||||
# This is an example goreleaser.yaml file with some sane defaults.
|
||||
# Make sure to check the documentation at http://goreleaser.com
|
||||
project_name: console
|
||||
|
||||
release:
|
||||
name_template: "Release version {{.Tag}}"
|
||||
github:
|
||||
owner: minio
|
||||
name: console
|
||||
extra_files:
|
||||
- glob: "*.minisig"
|
||||
|
||||
before:
|
||||
hooks:
|
||||
# you may remove this if you don't use vgo
|
||||
- go mod tidy -compat=1.19
|
||||
|
||||
builds:
|
||||
- goos:
|
||||
- linux
|
||||
- darwin
|
||||
- windows
|
||||
goarch:
|
||||
- amd64
|
||||
- ppc64le
|
||||
- s390x
|
||||
- arm64
|
||||
ignore:
|
||||
- goos: darwin
|
||||
goarch: arm
|
||||
- goos: windows
|
||||
goarch: arm64
|
||||
- goos: windows
|
||||
goarch: arm
|
||||
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
|
||||
main: ./cmd/console/
|
||||
|
||||
flags:
|
||||
- -trimpath
|
||||
- --tags=kqueue,operator
|
||||
|
||||
ldflags:
|
||||
- -s -w -X github.com/minio/console/pkg.ReleaseTag={{.Tag}} -X github.com/minio/console/pkg.CommitID={{.FullCommit}} -X github.com/minio/console/pkg.Version={{.Version}} -X github.com/minio/console/pkg.ShortCommitID={{.ShortCommit}} -X github.com/minio/console/pkg.ReleaseTime={{.Date}}
|
||||
|
||||
archives:
|
||||
- name_template: "{{ .ProjectName }}-{{ .Os }}-{{ .Arch }}"
|
||||
format: binary
|
||||
replacements:
|
||||
arm: arm
|
||||
|
||||
signs:
|
||||
- signature: "${artifact}.minisig"
|
||||
cmd: "sh"
|
||||
args:
|
||||
- '-c'
|
||||
- 'minisign -s /media/${USER}/minio/minisign.key -Sm ${artifact} < /media/${USER}/minio/minisign-passphrase'
|
||||
artifacts: all
|
||||
|
||||
snapshot:
|
||||
name_template: v0.0.0@{{.ShortCommit}}
|
||||
|
||||
changelog:
|
||||
sort: asc
|
||||
|
||||
nfpms:
|
||||
- vendor: MinIO, Inc.
|
||||
homepage: https://github.com/minio/console
|
||||
maintainer: MinIO Development <dev@min.io>
|
||||
description: MinIO Console Server
|
||||
license: GNU Affero General Public License v3.0
|
||||
formats:
|
||||
- deb
|
||||
- rpm
|
||||
contents:
|
||||
# Basic file that applies to all packagers
|
||||
- src: systemd/console.service
|
||||
dst: /etc/systemd/system/minio-console.service
|
||||
|
||||
dockers:
|
||||
- image_templates:
|
||||
- "minio/console:{{ .Tag }}-amd64"
|
||||
use: buildx
|
||||
goarch: amd64
|
||||
dockerfile: Dockerfile.release
|
||||
extra_files:
|
||||
- LICENSE
|
||||
- CREDITS
|
||||
build_flag_templates:
|
||||
- "--platform=linux/amd64"
|
||||
- "--build-arg=TAG={{ .Tag }}"
|
||||
- image_templates:
|
||||
- "minio/console:{{ .Tag }}-ppc64le"
|
||||
use: buildx
|
||||
goarch: ppc64le
|
||||
dockerfile: Dockerfile.release
|
||||
extra_files:
|
||||
- LICENSE
|
||||
- CREDITS
|
||||
build_flag_templates:
|
||||
- "--platform=linux/ppc64le"
|
||||
- "--build-arg=TAG={{ .Tag }}"
|
||||
- image_templates:
|
||||
- "minio/console:{{ .Tag }}-s390x"
|
||||
use: buildx
|
||||
goarch: s390x
|
||||
dockerfile: Dockerfile.release
|
||||
extra_files:
|
||||
- LICENSE
|
||||
- CREDITS
|
||||
build_flag_templates:
|
||||
- "--platform=linux/s390x"
|
||||
- "--build-arg=TAG={{ .Tag }}"
|
||||
- image_templates:
|
||||
- "minio/console:{{ .Tag }}-arm64"
|
||||
use: buildx
|
||||
goarch: arm64
|
||||
goos: linux
|
||||
dockerfile: Dockerfile.release
|
||||
extra_files:
|
||||
- LICENSE
|
||||
- CREDITS
|
||||
build_flag_templates:
|
||||
- "--platform=linux/arm64"
|
||||
- "--build-arg=TAG={{ .Tag }}"
|
||||
- image_templates:
|
||||
- "quay.io/minio/console:{{ .Tag }}-amd64"
|
||||
use: buildx
|
||||
goarch: amd64
|
||||
dockerfile: Dockerfile.release
|
||||
extra_files:
|
||||
- LICENSE
|
||||
- CREDITS
|
||||
build_flag_templates:
|
||||
- "--platform=linux/amd64"
|
||||
- "--build-arg=TAG={{ .Tag }}"
|
||||
- image_templates:
|
||||
- "quay.io/minio/console:{{ .Tag }}-ppc64le"
|
||||
use: buildx
|
||||
goarch: ppc64le
|
||||
dockerfile: Dockerfile.release
|
||||
extra_files:
|
||||
- LICENSE
|
||||
- CREDITS
|
||||
build_flag_templates:
|
||||
- "--platform=linux/ppc64le"
|
||||
- "--build-arg=TAG={{ .Tag }}"
|
||||
- image_templates:
|
||||
- "quay.io/minio/console:{{ .Tag }}-s390x"
|
||||
use: buildx
|
||||
goarch: s390x
|
||||
dockerfile: Dockerfile.release
|
||||
extra_files:
|
||||
- LICENSE
|
||||
- CREDITS
|
||||
build_flag_templates:
|
||||
- "--platform=linux/s390x"
|
||||
- "--build-arg=TAG={{ .Tag }}"
|
||||
- image_templates:
|
||||
- "quay.io/minio/console:{{ .Tag }}-arm64"
|
||||
use: buildx
|
||||
goarch: arm64
|
||||
goos: linux
|
||||
dockerfile: Dockerfile.release
|
||||
extra_files:
|
||||
- LICENSE
|
||||
- CREDITS
|
||||
build_flag_templates:
|
||||
- "--platform=linux/arm64"
|
||||
- "--build-arg=TAG={{ .Tag }}"
|
||||
docker_manifests:
|
||||
- name_template: minio/console:{{ .Tag }}
|
||||
image_templates:
|
||||
- minio/console:{{ .Tag }}-amd64
|
||||
- minio/console:{{ .Tag }}-arm64
|
||||
- minio/console:{{ .Tag }}-ppc64le
|
||||
- minio/console:{{ .Tag }}-s390x
|
||||
- name_template: quay.io/minio/console:{{ .Tag }}
|
||||
image_templates:
|
||||
- quay.io/minio/console:{{ .Tag }}-amd64
|
||||
- quay.io/minio/console:{{ .Tag }}-arm64
|
||||
- quay.io/minio/console:{{ .Tag }}-ppc64le
|
||||
- quay.io/minio/console:{{ .Tag }}-s390x
|
||||
- name_template: minio/console:latest
|
||||
image_templates:
|
||||
- minio/console:{{ .Tag }}-amd64
|
||||
- minio/console:{{ .Tag }}-arm64
|
||||
- minio/console:{{ .Tag }}-ppc64le
|
||||
- minio/console:{{ .Tag }}-s390x
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
# Common large paths
|
||||
node_modules/
|
||||
portal-ui/node_modules/
|
||||
web-app/node_modules/
|
||||
build/
|
||||
dist/
|
||||
.idea/
|
||||
|
||||
476
CHANGELOG.md
Normal file
476
CHANGELOG.md
Normal file
@@ -0,0 +1,476 @@
|
||||
# Changelog
|
||||
|
||||
## Release v2.0.1
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Updated project dependencies for vulnerabilities
|
||||
|
||||
Changes:
|
||||
|
||||
- Updated Object Browser console logos
|
||||
- Updated License page information
|
||||
|
||||
|
||||
|
||||
## Release v2.0.0
|
||||
|
||||
Community version is going back to be an object browser only.
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Fixed Dependencies vulnerabilities
|
||||
|
||||
Deprecations:
|
||||
|
||||
- Deprecated support of accounts & policies management, this can be managed by using mc admin commands. Please refer to the [MinIO Console User Management page](https://min.io/docs/minio/kubernetes/upstream/administration/identity-access-management/minio-user-management.html#id1) for more information.
|
||||
- Deprecated support of bucket management, this can be managed by using mc commands. Please refer to the [MinIO Client](https://min.io/docs/minio/linux/reference/minio-mc.html) for more information.
|
||||
- Deprecated support of configuration management, this can be managed by using mc admin config commands. Please refer to the [MinIO Client](https://min.io/docs/minio/linux/reference/minio-mc.html) for more information.
|
||||
|
||||
|
||||
## Release v1.7.6
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Fix null pointer exception in Admin Info
|
||||
- Ignore leading or trailing spaces in login request
|
||||
- Fix file path on drag and drop
|
||||
- Fix typo in User DN Search Filter example
|
||||
|
||||
## Release v1.7.5
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Fixed leaks during ZIP multiobject downloads
|
||||
- Allow spaces in Policy names
|
||||
|
||||
## Release v1.7.4
|
||||
|
||||
Deprecations:
|
||||
|
||||
- Deprecated support tools User Interface in favor of mc admin commands. Please refer to the [MinIO SUBNET Registration page](https://min.io/docs/minio/linux/administration/console/subnet-registration.html#subnet) for more information.
|
||||
- Deprecated Site replication User Interface in favor of mc admin commands. Please refer to the [MinIO Site Replication page](https://min.io/docs/minio/linux/operations/install-deploy-manage/multi-site-replication.html) for more information.
|
||||
- Deprecated Lifecycle & Tiers User Interface in favor of mc admin commands. Please refer to the [MinIO Tiers page](https://min.io/docs/minio/linux/reference/minio-mc/mc-ilm-tier.html) for more information.
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Avoid loading unpkg.com call when login animation is off
|
||||
|
||||
## Release v1.7.3
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Use a fixed public license verification key
|
||||
- Show non-expiring access keys as `no-expiry` instead of Jan 1, 1970
|
||||
- Use "join Slack" button for non-commercial edition instead of "Signup"
|
||||
- Fix setting policies on groups that have spaces
|
||||
|
||||
## Release v1.7.2
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Fixed issue in Server Health Info
|
||||
- Fixed Security vulnerability in dependencies
|
||||
- Fixed client string in trace message
|
||||
|
||||
Additional Changes:
|
||||
|
||||
- Remove live logs in Call Home Page
|
||||
- Update License page
|
||||
|
||||
## Release v1.7.1
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Fixed issue that could cause a failure when attempting to view deleted files in the object browser
|
||||
- Return network error when logging in and the network connection fails
|
||||
|
||||
Additional Changes:
|
||||
|
||||
- Added debug logging for console HTTP request (see [PR #3440](https://github.com/minio/console/pull/3440) for more detailed information)
|
||||
|
||||
## Release v1.7.0
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Fixed directory listing
|
||||
- Fix MinIO videos link
|
||||
|
||||
Additional Changes:
|
||||
|
||||
- Removed deprecated KES functionality
|
||||
|
||||
## Release v1.6.3
|
||||
|
||||
Additional Changes:
|
||||
|
||||
- Updated go.mod version
|
||||
|
||||
## Release v1.6.2
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Fixed minor user session issues
|
||||
- Updated project dependencies
|
||||
|
||||
Additional Changes:
|
||||
|
||||
- Improved Drives List visualization
|
||||
- Improved WS request logic
|
||||
- Updated License page with current MinIO plans.
|
||||
|
||||
## Release v1.6.1
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Fixed objectManager issues under certain conditions
|
||||
- Fixed Security vulnerability in dependencies
|
||||
|
||||
Additional Changes:
|
||||
|
||||
- Improved Share Link behavior
|
||||
|
||||
## Release v1.6.0
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Fixed share link encoding
|
||||
- Fixed Edit Lifecycle Storage Class
|
||||
- Added Tiers Improvements for Bucket Lifecycle management
|
||||
|
||||
Additional Changes:
|
||||
|
||||
- Vulnerability updates
|
||||
- Update Logo logic
|
||||
|
||||
## Release v1.5.0
|
||||
|
||||
Features:
|
||||
|
||||
- Added remove Tier functionality
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Fixed ILM rule tags not being shown
|
||||
- Fixed race condition Object Browser websocket
|
||||
- Fixed Encryption page crashing on empty response
|
||||
- Fixed Replication Delete Marker comparisons
|
||||
|
||||
Additional Changes:
|
||||
|
||||
- Use automatic URI encoding for APIs
|
||||
- Vulnerability updates
|
||||
|
||||
## Release v1.4.0
|
||||
|
||||
Features:
|
||||
|
||||
- Added VersionID support to metadata details
|
||||
- Improved Websockets handlers
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Fixed vulnerabilities and updated dependencies
|
||||
- Fixed an issue with Download URL decoding
|
||||
- Fixed leak in Object Browser Websocket
|
||||
- Minor UX fixes
|
||||
|
||||
## Release v1.3.0
|
||||
|
||||
Features:
|
||||
|
||||
- Adds ExpireDeleteMarker status to BucketLifecycleRule UI
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Fixed vulnerability
|
||||
- Used URL-safe base64 enconding for Share API
|
||||
- Made Prefix field optional when Adding Tier
|
||||
- Added Console user agent in MinIO Admin Client
|
||||
|
||||
## Release v1.2.0
|
||||
|
||||
Features:
|
||||
|
||||
- Updated file share logic to work as Proxy
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Updated project dependencies
|
||||
- Fixed Key Permissions UX
|
||||
- Added permissions validation to rewind button
|
||||
- Fixed Health report upload to SUBNET
|
||||
- Misc Cosmetic fixes
|
||||
|
||||
## Release v1.1.1
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Fixed folder download issue
|
||||
|
||||
## Release v1.1.0
|
||||
|
||||
Features:
|
||||
|
||||
- Added Set Expired object all versions selector
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Updated Go Dependencies
|
||||
|
||||
## Release v1.0.0
|
||||
|
||||
Features:
|
||||
|
||||
- Updated Preview message alert
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Updated Websocket API
|
||||
- Fixed issues with download manager
|
||||
- Fixed policies issues
|
||||
|
||||
## Release v0.46.0
|
||||
|
||||
Features:
|
||||
|
||||
- Added latest help content to forms
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Disabled Create User button in certain policy cases
|
||||
- Fixed an issue with Logout request
|
||||
- Upgraded project dependencies
|
||||
|
||||
## Release v0.45.0
|
||||
|
||||
Deprecated:
|
||||
|
||||
- Deprecated Heal / Drives page
|
||||
|
||||
Features:
|
||||
|
||||
- Updated tines on menus & pages
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Upgraded project dependencies
|
||||
|
||||
## Release v0.44.0
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Upgraded project dependencies
|
||||
- Fixed events icons not loading in subpaths
|
||||
|
||||
## Release v0.43.1
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Update Share Object UI to reflect maximum expiration time in UI
|
||||
|
||||
## Release v0.43.0
|
||||
|
||||
Features:
|
||||
|
||||
- Updated PDF preview method
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Fixed vulnerabilities
|
||||
- Prevented non-necessary metadata calls in object browser
|
||||
|
||||
## Release v0.42.2
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Hidden Prometheus metrics if URL is empty
|
||||
|
||||
## Release v0.42.1
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Reset go version to 1.19
|
||||
|
||||
## Release v0.42.0
|
||||
|
||||
Features:
|
||||
|
||||
- Introducing Dark Mode
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Fixed vulnerabilities
|
||||
- Changes on Upload and Delete object urls
|
||||
- Fixed blocking subpath creation if not enough permissions
|
||||
- Removed share object option at prefix level
|
||||
- Updated allowed actions for a deleted object
|
||||
|
||||
## Release v0.41.0
|
||||
|
||||
Features:
|
||||
|
||||
- Updated pages to use mds components
|
||||
- support for resolving IPv4/IPv6
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Remove cache for ClientIP
|
||||
- Fixed override environment variables display in settings page
|
||||
- Fixed daylight savings time support in share modal
|
||||
|
||||
## Release v0.40.0
|
||||
|
||||
Features:
|
||||
|
||||
- Updated OpenID page
|
||||
- Added New bucket event types support
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Fixed crash in access keys page
|
||||
- Fixed AuditLog filters issue
|
||||
- Fixed multiple issues with Object Browser
|
||||
|
||||
## Release v0.39.0
|
||||
|
||||
Features:
|
||||
|
||||
- Migrated metrics page to mds
|
||||
- Migrated Register page to mds
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Fixed LDAP configuration page issues
|
||||
- Load available certificates in logout
|
||||
- Updated dependencies & go version
|
||||
- Fixed delete objects functionality
|
||||
|
||||
## Release v0.38.0
|
||||
|
||||
Features:
|
||||
|
||||
- Added extra information to Service Accounts page
|
||||
- Updated Tiers, Site Replication, Speedtest, Heal & Watch pages components
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Fixed IDP expiry time errors
|
||||
- Updated project Dependencies
|
||||
|
||||
## Release v0.37.0
|
||||
|
||||
Features:
|
||||
|
||||
- Updated Trace and Logs page components
|
||||
- Updated Prometheus metrics
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Disabled input fields for Subscription features if MinIO is not registered
|
||||
|
||||
## Release v0.36.0
|
||||
|
||||
Features:
|
||||
|
||||
- Updated Settings page components
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Show LDAP Enabled value LDAP configuration
|
||||
- Download multiple objects in same path as they were selected
|
||||
|
||||
## Release v0.35.1
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Change timestamp format for zip creation
|
||||
|
||||
## Release v0.35.0
|
||||
|
||||
Features:
|
||||
|
||||
- Add Exclude Folders and Exclude Prefixes during bucket creation
|
||||
- Download multiple selected objects as zip and ignore deleted objects
|
||||
- Updated Call Home, Inspet, Profile and Health components
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Remove extra white spaces for configuration strings
|
||||
- Allow Create New Path in bucket view when having right permissions
|
||||
|
||||
## Release v0.34.0
|
||||
|
||||
Features:
|
||||
|
||||
- Updated Buckets components
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Fixed SUBNET Health report upload
|
||||
- Updated Download Handler
|
||||
- Fixes issue with rewind
|
||||
- Avoid 1 hour expiration for IDP credentials
|
||||
|
||||
---
|
||||
|
||||
## Release v0.33.0
|
||||
|
||||
Features:
|
||||
|
||||
- Updated OpenID, LDAP components
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Fixed security issues
|
||||
- Fixed navigation issues in Object Browser
|
||||
- Fixed Dashboard metrics
|
||||
|
||||
---
|
||||
|
||||
## Release v0.32.0
|
||||
|
||||
Features:
|
||||
|
||||
- Updated Users and Groups components
|
||||
- Added placeholder image for Help Menu
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Fixed memory leak in WebSocket API for Object Browser
|
||||
|
||||
---
|
||||
|
||||
## Release v0.31.0
|
||||
|
||||
**Breaking Changes:**
|
||||
|
||||
- **Removed support for Standalone Deployments**
|
||||
|
||||
Features:
|
||||
|
||||
- Updated way files are displayed in uploading component
|
||||
- Updated Audit Logs and Policies components
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Fixed Download folders issue in Object Browser
|
||||
- Added missing Notification Events (ILM & REPLICA) in Events Notification Page
|
||||
- Fixed Security Vulnerability for `semver` dependency
|
||||
|
||||
---
|
||||
|
||||
## Release v0.30.0
|
||||
|
||||
Features:
|
||||
|
||||
- Added MinIO Console Help Menu
|
||||
- Updated UI Menu components
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Disable the Upload button on Object Browser if the user is not allowed
|
||||
- Fixed security vulnerability for `lestrrat-go/jwx` and `fast-xml-parser`
|
||||
- Fixed bug on sub-paths for Object Browser
|
||||
- Reduce the number of calls to `/session` API endpoint to improve performance
|
||||
- Rolled back the previous change for the Share File feature to no longer ask for Service Account access keys
|
||||
@@ -4,56 +4,80 @@ This is a REST portal server created using [go-swagger](https://github.com/go-sw
|
||||
|
||||
The API handlers are created using a YAML definition located in `swagger.YAML`.
|
||||
|
||||
To add new api, the YAML file needs to be updated with all the desired apis using the [Swagger Basic Structure](https://swagger.io/docs/specification/2-0/basic-structure/), this includes paths, parameters, definitions, tags, etc.
|
||||
To add new api, the YAML file needs to be updated with all the desired apis using
|
||||
the [Swagger Basic Structure](https://swagger.io/docs/specification/2-0/basic-structure/), this includes paths,
|
||||
parameters, definitions, tags, etc.
|
||||
|
||||
## Generate server from YAML
|
||||
|
||||
Once the YAML file is ready we can autogenerate the code needed for the new api by just running:
|
||||
|
||||
Validate it:
|
||||
|
||||
```
|
||||
swagger validate ./swagger.yml
|
||||
```
|
||||
|
||||
Update server code:
|
||||
|
||||
```
|
||||
make swagger-gen
|
||||
```
|
||||
|
||||
This will update all the necessary code.
|
||||
|
||||
`./restapi/configure_console.go` is a file that contains the handlers to be used by the application, here is the only place where we need to update our code to support the new apis. This file is not affected when running the swagger generator and it is safe to edit.
|
||||
`./api/configure_console.go` is a file that contains the handlers to be used by the application, here is the only place
|
||||
where we need to update our code to support the new apis. This file is not affected when running the swagger generator
|
||||
and it is safe to edit.
|
||||
|
||||
## Unit Tests
|
||||
`./restapi/handlers_test.go` needs to be updated with the proper tests for the new api.
|
||||
|
||||
`./api/handlers_test.go` needs to be updated with the proper tests for the new api.
|
||||
|
||||
To run tests:
|
||||
|
||||
```
|
||||
go test ./restapi
|
||||
go test ./api
|
||||
```
|
||||
|
||||
## Commit changes
|
||||
After verification, commit your changes. This is a [great post](https://chris.beams.io/posts/git-commit/) on how to write useful commit messages
|
||||
|
||||
After verification, commit your changes. This is a [great post](https://chris.beams.io/posts/git-commit/) on how to
|
||||
write useful commit messages
|
||||
|
||||
```
|
||||
$ git commit -am 'Add some feature'
|
||||
```
|
||||
|
||||
### Push to the branch
|
||||
|
||||
Push your locally committed changes to the remote origin (your fork)
|
||||
|
||||
```
|
||||
$ git push origin my-new-feature
|
||||
```
|
||||
|
||||
### Create a Pull Request
|
||||
Pull requests can be created via GitHub. Refer to [this document](https://help.github.com/articles/creating-a-pull-request/) for detailed steps on how to create a pull request. After a Pull Request gets peer reviewed and approved, it will be merged.
|
||||
|
||||
Pull requests can be created via GitHub. Refer
|
||||
to [this document](https://help.github.com/articles/creating-a-pull-request/) for detailed steps on how to create a pull
|
||||
request. After a Pull Request gets peer reviewed and approved, it will be merged.
|
||||
|
||||
## FAQs
|
||||
|
||||
### How does ``console`` manages dependencies?
|
||||
|
||||
``MinIO`` uses `go mod` to manage its dependencies.
|
||||
|
||||
- Run `go get foo/bar` in the source folder to add the dependency to `go.mod` file.
|
||||
|
||||
To remove a dependency
|
||||
|
||||
- Edit your code and remove the import reference.
|
||||
- Run `go mod tidy` in the source folder to remove dependency from `go.mod` file.
|
||||
|
||||
### What are the coding guidelines for console?
|
||||
``console`` is fully conformant with Golang style. Refer: [Effective Go](https://github.com/golang/go/wiki/CodeReviewComments) article from Golang project. If you observe offending code, please feel free to send a pull request or ping us on [Slack](https://slack.min.io).
|
||||
|
||||
``console`` is fully conformant with Golang style.
|
||||
Refer: [Effective Go](https://github.com/golang/go/wiki/CodeReviewComments) article from Golang project. If you observe
|
||||
offending code, please feel free to send a pull request or ping us on [Slack](https://slack.min.io).
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
# Developing MinIO Console
|
||||
|
||||
The MinIO Console requires the [MinIO Server](https://github.com/minio/minio). For development purposes, you also need to run both the MinIO Console web app and the MinIO Console server.
|
||||
The MinIO Console requires the [MinIO Server](https://github.com/minio/minio). For development purposes, you also need
|
||||
to run both the MinIO Console web app and the MinIO Console server.
|
||||
|
||||
## Running MinIO Console server
|
||||
|
||||
Build the server in the main folder by running:
|
||||
|
||||
```
|
||||
make
|
||||
```
|
||||
> Note: If it's the first time running the server, you might need to run `go mod tidy` to ensure you have all modules required.
|
||||
To start the server run:
|
||||
|
||||
> Note: If it's the first time running the server, you might need to run `go mod tidy` to ensure you have all modules
|
||||
> required.
|
||||
> To start the server run:
|
||||
|
||||
```
|
||||
CONSOLE_ACCESS_KEY=<your-access-key>
|
||||
CONSOLE_SECRET_KEY=<your-secret-key>
|
||||
@@ -19,8 +24,8 @@ CONSOLE_DEV_MODE=on
|
||||
```
|
||||
|
||||
## Running MinIO Console web app
|
||||
Refer to `/portal-ui` [instructions](/portal-ui/README.md) to run the web app locally.
|
||||
|
||||
Refer to `/web-app` [instructions](/web-app/README.md) to run the web app locally.
|
||||
|
||||
# Building with MinIO
|
||||
|
||||
@@ -72,25 +77,6 @@ Still in the MinIO folder, run
|
||||
make build
|
||||
```
|
||||
|
||||
# Testing on Kubernetes
|
||||
|
||||
If you want to test console on kubernetes, you can perform all the steps from `Building with MinIO`, but change `Step 3`
|
||||
to the following:
|
||||
|
||||
```shell
|
||||
TAG=miniodev/console:dev make docker
|
||||
```
|
||||
|
||||
This will build a docker container image that can be used to test with your local kubernetes environment.
|
||||
|
||||
For example, if you are using kind:
|
||||
|
||||
```shell
|
||||
kind load docker-image miniodev/console:dev
|
||||
```
|
||||
|
||||
and then deploy any `Tenant` that uses this image
|
||||
|
||||
# LDAP authentication with Console
|
||||
|
||||
## Setup
|
||||
|
||||
43
Dockerfile
43
Dockerfile
@@ -1,43 +0,0 @@
|
||||
ARG NODE_VERSION
|
||||
FROM node:$NODE_VERSION as uilayer
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY ./portal-ui/package.json ./
|
||||
COPY ./portal-ui/yarn.lock ./
|
||||
RUN yarn install
|
||||
|
||||
COPY ./portal-ui .
|
||||
|
||||
RUN make build-static
|
||||
|
||||
USER node
|
||||
|
||||
FROM golang:1.19 as golayer
|
||||
|
||||
RUN apt-get update -y && apt-get install -y ca-certificates
|
||||
|
||||
ADD go.mod /go/src/github.com/minio/console/go.mod
|
||||
ADD go.sum /go/src/github.com/minio/console/go.sum
|
||||
WORKDIR /go/src/github.com/minio/console/
|
||||
|
||||
# Get dependencies - will also be cached if we won't change mod/sum
|
||||
RUN go mod download
|
||||
|
||||
ADD . /go/src/github.com/minio/console/
|
||||
WORKDIR /go/src/github.com/minio/console/
|
||||
|
||||
ENV CGO_ENABLED=0
|
||||
|
||||
COPY --from=uilayer /app/build /go/src/github.com/minio/console/portal-ui/build
|
||||
RUN go build --tags=kqueue,operator -ldflags "-w -s" -a -o console ./cmd/console
|
||||
|
||||
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.7
|
||||
MAINTAINER MinIO Development "dev@min.io"
|
||||
EXPOSE 9090
|
||||
|
||||
|
||||
COPY --from=golayer /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||
COPY --from=golayer /go/src/github.com/minio/console/console .
|
||||
|
||||
ENTRYPOINT ["/console"]
|
||||
@@ -1,14 +0,0 @@
|
||||
ARG NODE_VERSION
|
||||
FROM node:$NODE_VERSION as uilayer
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY ./portal-ui/package.json ./
|
||||
COPY ./portal-ui/yarn.lock ./
|
||||
RUN yarn install
|
||||
|
||||
COPY ./portal-ui .
|
||||
|
||||
RUN yarn install && make build-static
|
||||
|
||||
USER node
|
||||
@@ -1,27 +0,0 @@
|
||||
FROM --platform=linux/amd64 registry.access.redhat.com/ubi8/ubi-minimal:8.7 as build
|
||||
|
||||
RUN microdnf update --nodocs && microdnf install ca-certificates --nodocs
|
||||
RUN curl -s -q https://raw.githubusercontent.com/minio/kes/master/LICENSE -o LICENSE
|
||||
RUN curl -s -q https://raw.githubusercontent.com/minio/kes/master/CREDITS -o CREDITS
|
||||
|
||||
FROM registry.access.redhat.com/ubi8/ubi-micro:8.7
|
||||
|
||||
# On RHEL the certificate bundle is located at:
|
||||
# - /etc/pki/tls/certs/ca-bundle.crt (RHEL 6)
|
||||
# - /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem (RHEL 7)
|
||||
COPY --from=build /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem /etc/pki/ca-trust/extracted/pem/
|
||||
COPY --from=build LICENSE /LICENSE
|
||||
COPY --from=build CREDITS /CREDITS
|
||||
|
||||
LABEL name="MinIO" \
|
||||
vendor="MinIO Inc <dev@min.io>" \
|
||||
maintainer="MinIO Inc <dev@min.io>" \
|
||||
version="${TAG}" \
|
||||
release="${TAG}" \
|
||||
summary="A graphical user interface for MinIO" \
|
||||
description="MinIO object storage is fundamentally different. Designed for performance and the S3 API, it is 100% open-source. MinIO is ideal for large, private cloud environments with stringent security requirements and delivers mission-critical availability across a diverse range of workloads."
|
||||
|
||||
EXPOSE 9090
|
||||
COPY console /console
|
||||
|
||||
ENTRYPOINT ["/console"]
|
||||
133
Makefile
133
Makefile
@@ -33,6 +33,10 @@ lint:
|
||||
@GO111MODULE=on ${GOPATH}/bin/golangci-lint cache clean
|
||||
@GO111MODULE=on ${GOPATH}/bin/golangci-lint run --timeout=5m --config ./.golangci.yml
|
||||
|
||||
lint-fix: getdeps ## runs golangci-lint suite of linters with automatic fixes
|
||||
@echo "Running $@ check"
|
||||
@GO111MODULE=on ${GOPATH}/bin/golangci-lint run --timeout=5m --config ./.golangci.yml --fix
|
||||
|
||||
install: console
|
||||
@echo "Installing console binary to '$(GOPATH)/bin/console'"
|
||||
@mkdir -p $(GOPATH)/bin && cp -f $(PWD)/console $(GOPATH)/bin/console
|
||||
@@ -48,18 +52,23 @@ apply-gofmt:
|
||||
clean-swagger:
|
||||
@echo "cleaning"
|
||||
@rm -rf models
|
||||
@rm -rf restapi/operations
|
||||
@rm -rf api/operations
|
||||
|
||||
swagger-console:
|
||||
@echo "Generating swagger server code from yaml"
|
||||
@swagger generate server -A console --main-package=management --server-package=restapi --exclude-main -P models.Principal -f ./swagger.yml -r NOTICE
|
||||
@swagger generate server -A console --main-package=management --server-package=api --exclude-main -P models.Principal -f ./swagger.yml -r NOTICE
|
||||
@echo "Ensure basic install"
|
||||
@(cd web-app; yarn; cd ..)
|
||||
@echo "Generating typescript api"
|
||||
@npx swagger-typescript-api -p ./swagger.yml -o ./portal-ui/src/api -n consoleApi.ts
|
||||
@make swagger-typescript-api path="../swagger.yml" output="./src/api" name="consoleApi.ts"
|
||||
@git restore api/server.go
|
||||
|
||||
swagger-typescript-api:
|
||||
@(cd web-app; yarn swagger-typescript-api -p $(path) -o $(output) -n $(name) --custom-config ../generator.config.js; cd ..)
|
||||
|
||||
assets:
|
||||
@(if [ -f "${NVM_DIR}/nvm.sh" ]; then \. "${NVM_DIR}/nvm.sh" && nvm install && nvm use && npm install -g yarn ; fi &&\
|
||||
cd portal-ui; yarn install --prefer-offline; make build-static; yarn prettier --write . --loglevel warn; cd ..)
|
||||
cd web-app; corepack enable; yarn install --prefer-offline; make build-static; yarn prettier --write . --log-level warn; cd ..)
|
||||
|
||||
test-integration:
|
||||
@(docker stop pgsqlcontainer || true)
|
||||
@@ -77,7 +86,7 @@ test-integration:
|
||||
@echo "Postgres"
|
||||
@(docker run --net=mynet123 --ip=173.18.0.4 --name pgsqlcontainer --rm -p 5432:5432 -e POSTGRES_PASSWORD=password -d postgres && sleep 5)
|
||||
@echo "execute test and get coverage for test-integration:"
|
||||
@(cd integration && go test -coverpkg=../restapi -c -tags testrunmain . && mkdir -p coverage && ./integration.test -test.v -test.run "^Test*" -test.coverprofile=coverage/system.out)
|
||||
@(cd integration && go test -coverpkg=../api -c -tags testrunmain . && mkdir -p coverage && ./integration.test -test.v -test.run "^Test*" -test.coverprofile=coverage/system.out)
|
||||
@(docker stop pgsqlcontainer)
|
||||
@(docker stop minio)
|
||||
@(docker stop minio2)
|
||||
@@ -125,99 +134,39 @@ test-replication:
|
||||
$(MINIO_VERSION) server /data{1...4} \
|
||||
--address :9002 \
|
||||
--console-address :6002)
|
||||
@(cd replication && go test -coverpkg=../restapi -c -tags testrunmain . && mkdir -p coverage && ./replication.test -test.v -test.run "^Test*" -test.coverprofile=coverage/replication.out)
|
||||
@(cd replication && go test -coverpkg=../api -c -tags testrunmain . && mkdir -p coverage && ./replication.test -test.v -test.run "^Test*" -test.coverprofile=coverage/replication.out)
|
||||
@(docker stop minio || true)
|
||||
@(docker stop minio1 || true)
|
||||
@(docker stop minio2 || true)
|
||||
@(docker network rm mynet123 || true)
|
||||
|
||||
test-sso-integration:
|
||||
@echo "create the network in bridge mode to communicate all containers"
|
||||
@(docker network create my-net)
|
||||
@echo "run openldap container using MinIO Image: quay.io/minio/openldap:latest"
|
||||
@(docker run \
|
||||
-e LDAP_ORGANIZATION="MinIO Inc" \
|
||||
-e LDAP_DOMAIN="min.io" \
|
||||
-e LDAP_ADMIN_PASSWORD="admin" \
|
||||
--network my-net \
|
||||
-p 389:389 \
|
||||
-p 636:636 \
|
||||
--name openldap \
|
||||
--detach quay.io/minio/openldap:latest)
|
||||
@echo "Run Dex container using MinIO Image: quay.io/minio/dex:latest"
|
||||
@(docker run \
|
||||
-e DEX_ISSUER=http://dex:5556/dex \
|
||||
-e DEX_CLIENT_REDIRECT_URI=http://127.0.0.1:9090/oauth_callback \
|
||||
-e DEX_LDAP_SERVER=openldap:389 \
|
||||
--network my-net \
|
||||
-p 5556:5556 \
|
||||
--name dex \
|
||||
--detach quay.io/minio/dex:latest)
|
||||
@echo "running minio server"
|
||||
@(docker run \
|
||||
-v /data1 -v /data2 -v /data3 -v /data4 \
|
||||
--network my-net \
|
||||
-d \
|
||||
--name minio \
|
||||
--rm \
|
||||
-p 9000:9000 \
|
||||
-p 9001:9001 \
|
||||
-e MINIO_IDENTITY_OPENID_CLIENT_ID="minio-client-app" \
|
||||
-e MINIO_IDENTITY_OPENID_CLIENT_SECRET="minio-client-app-secret" \
|
||||
-e MINIO_IDENTITY_OPENID_CLAIM_NAME=name \
|
||||
-e MINIO_IDENTITY_OPENID_CONFIG_URL=http://dex:5556/dex/.well-known/openid-configuration \
|
||||
-e MINIO_IDENTITY_OPENID_REDIRECT_URI=http://127.0.0.1:9090/oauth_callback \
|
||||
-e MINIO_ROOT_USER=minio \
|
||||
-e MINIO_ROOT_PASSWORD=minio123 $(MINIO_VERSION) server /data{1...4} --address :9000 --console-address :9001)
|
||||
@echo "run mc commands to set the policy"
|
||||
@(docker run --name minio-client --network my-net -dit --entrypoint=/bin/sh minio/mc)
|
||||
@(docker exec minio-client mc alias set myminio/ http://minio:9000 minio minio123)
|
||||
@echo "adding policy to Dillon Harper to be able to login:"
|
||||
@(cd sso-integration && docker cp allaccess.json minio-client:/ && docker exec minio-client mc admin policy create myminio "Dillon Harper" allaccess.json)
|
||||
@echo "starting bash script"
|
||||
@(env bash $(PWD)/sso-integration/set-sso.sh)
|
||||
@echo "add python module"
|
||||
@(pip3 install bs4)
|
||||
@echo "Executing the test:"
|
||||
@(cd sso-integration && go test -coverpkg=../restapi -c -tags testrunmain . && mkdir -p coverage && ./sso-integration.test -test.v -test.run "^Test*" -test.coverprofile=coverage/sso-system.out)
|
||||
|
||||
test-permissions-1:
|
||||
@(docker run -v /data1 -v /data2 -v /data3 -v /data4 -d --name minio --rm -p 9000:9000 quay.io/minio/minio:latest server /data{1...4})
|
||||
@(env bash $(PWD)/portal-ui/tests/scripts/permissions.sh "portal-ui/tests/permissions-1/")
|
||||
@(env bash $(PWD)/web-app/tests/scripts/permissions.sh "web-app/tests/permissions-1/")
|
||||
@(docker stop minio)
|
||||
|
||||
test-permissions-2:
|
||||
@(docker run -v /data1 -v /data2 -v /data3 -v /data4 -d --name minio --rm -p 9000:9000 quay.io/minio/minio:latest server /data{1...4})
|
||||
@(env bash $(PWD)/portal-ui/tests/scripts/permissions.sh "portal-ui/tests/permissions-2/")
|
||||
@(env bash $(PWD)/web-app/tests/scripts/permissions.sh "web-app/tests/permissions-2/")
|
||||
@(docker stop minio)
|
||||
|
||||
test-permissions-3:
|
||||
@(docker run -v /data1 -v /data2 -v /data3 -v /data4 -d --name minio --rm -p 9000:9000 quay.io/minio/minio:latest server /data{1...4})
|
||||
@(env bash $(PWD)/portal-ui/tests/scripts/permissions.sh "portal-ui/tests/permissions-3/")
|
||||
@(env bash $(PWD)/web-app/tests/scripts/permissions.sh "web-app/tests/permissions-3/")
|
||||
@(docker stop minio)
|
||||
|
||||
test-permissions-4:
|
||||
@(docker run -v /data1 -v /data2 -v /data3 -v /data4 -d --name minio --rm -p 9000:9000 quay.io/minio/minio:latest server /data{1...4})
|
||||
@(env bash $(PWD)/portal-ui/tests/scripts/permissions.sh "portal-ui/tests/permissions-4/")
|
||||
@(docker stop minio)
|
||||
|
||||
test-permissions-5:
|
||||
@(docker run -v /data1 -v /data2 -v /data3 -v /data4 -d --name minio --rm -p 9000:9000 quay.io/minio/minio:latest server /data{1...4})
|
||||
@(env bash $(PWD)/portal-ui/tests/scripts/permissions.sh "portal-ui/tests/permissions-5/")
|
||||
@(env bash $(PWD)/web-app/tests/scripts/permissions.sh "web-app/tests/permissions-4/")
|
||||
@(docker stop minio)
|
||||
|
||||
test-permissions-6:
|
||||
@(docker run -v /data1 -v /data2 -v /data3 -v /data4 -d --name minio --rm -p 9000:9000 quay.io/minio/minio:latest server /data{1...4})
|
||||
@(env bash $(PWD)/portal-ui/tests/scripts/permissions.sh "portal-ui/tests/permissions-6/")
|
||||
@(docker stop minio)
|
||||
|
||||
test-permissions-7:
|
||||
@(docker run -v /data1 -v /data2 -v /data3 -v /data4 -d --name minio --rm -p 9000:9000 quay.io/minio/minio:latest server /data{1...4})
|
||||
@(env bash $(PWD)/portal-ui/tests/scripts/permissions.sh "portal-ui/tests/permissions-7/")
|
||||
@(env bash $(PWD)/web-app/tests/scripts/permissions.sh "web-app/tests/permissions-6/")
|
||||
@(docker stop minio)
|
||||
|
||||
test-apply-permissions:
|
||||
@(env bash $(PWD)/portal-ui/tests/scripts/initialize-env.sh)
|
||||
@(env bash $(PWD)/web-app/tests/scripts/initialize-env.sh)
|
||||
|
||||
test-start-docker-minio:
|
||||
@(docker run -v /data1 -v /data2 -v /data3 -v /data4 -d --name minio --rm -p 9000:9000 quay.io/minio/minio:latest server /data{1...4})
|
||||
@@ -226,20 +175,50 @@ initialize-permissions: test-start-docker-minio test-apply-permissions
|
||||
@echo "Done initializing permissions test"
|
||||
|
||||
cleanup-permissions:
|
||||
@(env bash $(PWD)/portal-ui/tests/scripts/cleanup-env.sh)
|
||||
@(env bash $(PWD)/web-app/tests/scripts/cleanup-env.sh)
|
||||
@(docker stop minio)
|
||||
|
||||
initialize-docker-network:
|
||||
@(docker network create test-network)
|
||||
|
||||
test-start-docker-minio-w-redirect-url: initialize-docker-network
|
||||
@(docker run \
|
||||
-e MINIO_BROWSER_REDIRECT_URL='http://localhost:8000/console/subpath/' \
|
||||
-e MINIO_SERVER_URL='http://localhost:9000' \
|
||||
-v /data1 -v /data2 -v /data3 -v /data4 \
|
||||
-d --network host --name minio --rm\
|
||||
quay.io/minio/minio:latest server /data{1...4})
|
||||
|
||||
test-start-docker-nginx-w-subpath:
|
||||
@(docker run \
|
||||
--network host \
|
||||
-d --rm \
|
||||
--add-host=host.docker.internal:host-gateway \
|
||||
-v ./web-app/tests/subpath-nginx/nginx.conf:/etc/nginx/nginx.conf \
|
||||
--name test-nginx nginx)
|
||||
|
||||
test-initialize-minio-nginx: test-start-docker-minio-w-redirect-url test-start-docker-nginx-w-subpath
|
||||
|
||||
cleanup-minio-nginx:
|
||||
@(docker stop minio test-nginx & docker network rm test-network)
|
||||
|
||||
# https://stackoverflow.com/questions/19200235/golang-tests-in-sub-directory
|
||||
# Note: go test ./... will run tests on the current folder and all subfolders.
|
||||
# This is needed because tests can be in the folder or sub-folder(s), let's include them all please!.
|
||||
test:
|
||||
@echo "execute test and get coverage"
|
||||
@(cd restapi && mkdir coverage && GO111MODULE=on go test -test.v -coverprofile=coverage/coverage.out)
|
||||
@(cd api && mkdir -p coverage && GO111MODULE=on go test ./... -test.v -coverprofile=coverage/coverage.out)
|
||||
|
||||
|
||||
# https://stackoverflow.com/questions/19200235/golang-tests-in-sub-directory
|
||||
# Note: go test ./... will run tests on the current folder and all subfolders.
|
||||
# This is since tests in pkg folder are in subfolders and were not executed.
|
||||
test-pkg:
|
||||
@echo "execute test and get coverage"
|
||||
@(cd pkg && mkdir coverage && GO111MODULE=on go test -test.v -coverprofile=coverage/coverage-pkg.out)
|
||||
@(cd pkg && mkdir -p coverage && GO111MODULE=on go test ./... -test.v -coverprofile=coverage/coverage-pkg.out)
|
||||
|
||||
coverage:
|
||||
@(GO111MODULE=on go test -v -coverprofile=coverage.out github.com/minio/console/restapi/... && go tool cover -html=coverage.out && open coverage.html)
|
||||
@(GO111MODULE=on go test -v -coverprofile=coverage.out github.com/minio/console/api/... && go tool cover -html=coverage.out && open coverage.html)
|
||||
|
||||
clean:
|
||||
@echo "Cleaning up all the generated files"
|
||||
@@ -254,4 +233,4 @@ release: swagger-gen
|
||||
@echo "Generating Release: $(RELEASE)"
|
||||
@make assets
|
||||
@git add -u .
|
||||
@git add portal-ui/build/
|
||||
@git add web-app/build/
|
||||
|
||||
85
README.md
85
README.md
@@ -4,65 +4,29 @@
|
||||
|
||||
A graphical user interface for [MinIO](https://github.com/minio/minio)
|
||||
|
||||
| Object Browser | Dashboard | Creating a bucket |
|
||||
|------------------------------------|-------------------------------|-------------------------------|
|
||||
|  |  |  |
|
||||
| Object Browser | Creating a bucket | Object Details |
|
||||
|--------------------------------------|-------------------------------|---------------------------------|
|
||||
|  |  |  |
|
||||
|  |  |  |
|
||||
|
||||
<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc -->
|
||||
**Table of Contents**
|
||||
|
||||
- [MinIO Console](#minio-console)
|
||||
- [Install](#install)
|
||||
- [Binary Releases](#binary-releases)
|
||||
- [Docker](#docker)
|
||||
- [Build from source](#build-from-source)
|
||||
- [Setup](#setup)
|
||||
- [1. Create a user `console` using `mc`](#1-create-a-user-console-using-mc)
|
||||
- [2. Create a policy for `console` with admin access to all resources (for testing)](#2-create-a-policy-for-console-with-admin-access-to-all-resources-for-testing)
|
||||
- [3. Set the policy for the new `console` user](#3-set-the-policy-for-the-new-console-user)
|
||||
- [Start Console service:](#start-console-service)
|
||||
- [Start Console service with TLS:](#start-console-service-with-tls)
|
||||
- [Connect Console to a Minio using TLS and a self-signed certificate](#connect-console-to-a-minio-using-tls-and-a-self-signed-certificate)
|
||||
- [Install](#install)
|
||||
- [Build from source](#build-from-source)
|
||||
- [Setup](#setup)
|
||||
- [1. Create a user `console` using `mc`](#1-create-a-user-console-using-mc)
|
||||
- [2. Create a policy for `console` with admin access to all resources (for testing)](#2-create-a-policy-for-console-with-admin-access-to-all-resources-for-testing)
|
||||
- [3. Set the policy for the new `console` user](#3-set-the-policy-for-the-new-console-user)
|
||||
- [Start Console service:](#start-console-service)
|
||||
- [Start Console service with TLS:](#start-console-service-with-tls)
|
||||
- [Connect Console to a Minio using TLS and a self-signed certificate](#connect-console-to-a-minio-using-tls-and-a-self-signed-certificate)
|
||||
- [Contribute to console Project](#contribute-to-console-project)
|
||||
|
||||
<!-- markdown-toc end -->
|
||||
|
||||
## Install
|
||||
|
||||
### Binary Releases
|
||||
|
||||
| OS | ARCH | Binary |
|
||||
|:-------:|:-------:|:----------------------------------------------------------------------------------------------------:|
|
||||
| Linux | amd64 | [linux-amd64](https://github.com/minio/console/releases/latest/download/console-linux-amd64) |
|
||||
| Linux | arm64 | [linux-arm64](https://github.com/minio/console/releases/latest/download/console-linux-arm64) |
|
||||
| Linux | ppc64le | [linux-ppc64le](https://github.com/minio/console/releases/latest/download/console-linux-ppc64le) |
|
||||
| Linux | s390x | [linux-s390x](https://github.com/minio/console/releases/latest/download/console-linux-s390x) |
|
||||
| Apple | amd64 | [darwin-amd64](https://github.com/minio/console/releases/latest/download/console-darwin-amd64) |
|
||||
| Windows | amd64 | [windows-amd64](https://github.com/minio/console/releases/latest/download/console-windows-amd64.exe) |
|
||||
|
||||
You can also verify the binary with [minisign](https://jedisct1.github.io/minisign/) by downloading the
|
||||
corresponding [`.minisig`](https://github.com/minio/console/releases/latest) signature file. Then run:
|
||||
|
||||
```
|
||||
minisign -Vm console-<OS>-<ARCH> -P RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav
|
||||
```
|
||||
|
||||
### Docker
|
||||
|
||||
Pull the latest release via:
|
||||
|
||||
```
|
||||
docker pull minio/console
|
||||
```
|
||||
|
||||
### Build from source
|
||||
|
||||
> You will need a working Go environment. Therefore, please follow [How to install Go](https://golang.org/doc/install).
|
||||
> Minimum version required is go1.19
|
||||
|
||||
```
|
||||
go install github.com/minio/console/cmd/console@latest
|
||||
```
|
||||
MinIO Console is a library that provides a management and browser UI overlay for the MinIO Server.
|
||||
|
||||
## Setup
|
||||
|
||||
@@ -228,6 +192,27 @@ export CONSOLE_MINIO_SERVER=https://localhost:9000
|
||||
|
||||
You can verify that the apis work by doing the request on `localhost:9090/api/v1/...`
|
||||
|
||||
## Debug logging
|
||||
|
||||
In some cases it may be convenient to log all HTTP requests. This can be enabled by setting
|
||||
the `CONSOLE_DEBUG_LOGLEVEL` environment variable to one of the following values:
|
||||
|
||||
- `0` (default) uses no logging.
|
||||
- `1` log single line per request for server-side errors (status-code 5xx).
|
||||
- `2` log single line per request for client-side and server-side errors (status-code 4xx/5xx).
|
||||
- `3` log single line per request for all requests (status-code 4xx/5xx).
|
||||
- `4` log details per request for server-side errors (status-code 5xx).
|
||||
- `5` log details per request for client-side and server-side errors (status-code 4xx/5xx).
|
||||
- `6` log details per request for all requests (status-code 4xx/5xx).
|
||||
|
||||
A single line logging has the following information:
|
||||
- Remote endpoint (IP + port) of the request. Note that reverse proxies may hide the actual remote endpoint of the client's browser.
|
||||
- HTTP method and URL
|
||||
- Status code of the response (websocket connections are hijacked, so no response is shown)
|
||||
- Duration of the request
|
||||
|
||||
The detailed logging also includes all request and response headers (if any).
|
||||
|
||||
# Contribute to console Project
|
||||
|
||||
Please follow console [Contributor's Guide](https://github.com/minio/console/blob/master/CONTRIBUTING.md)
|
||||
|
||||
@@ -14,31 +14,22 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
export interface LDAPEntitiesRequest {
|
||||
users?: string[];
|
||||
groups?: string[];
|
||||
policies?: string[];
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/minio/madmin-go/v3"
|
||||
)
|
||||
|
||||
type AdminClientMock struct {
|
||||
minioAccountInfoMock func(ctx context.Context) (madmin.AccountInfo, error)
|
||||
}
|
||||
|
||||
export interface LDAPEntitiesResponse {
|
||||
timestamp: string;
|
||||
users?: LDAPUsersResponse[];
|
||||
groups?: LDAPGroupsResponse[];
|
||||
policies?: LDAPPoliciesResponse[];
|
||||
func (ac AdminClientMock) kmsStatus(_ context.Context) (madmin.KMSStatus, error) {
|
||||
return madmin.KMSStatus{Name: "name", DefaultKeyID: "key", Endpoints: map[string]madmin.ItemState{"localhost": madmin.ItemState("online")}}, nil
|
||||
}
|
||||
|
||||
export interface LDAPUsersResponse {
|
||||
user: string;
|
||||
policies: string[];
|
||||
}
|
||||
|
||||
export interface LDAPGroupsResponse {
|
||||
group: string;
|
||||
policies: string[];
|
||||
}
|
||||
|
||||
export interface LDAPPoliciesResponse {
|
||||
policy: string;
|
||||
users: string[];
|
||||
groups: string[];
|
||||
func (ac AdminClientMock) AccountInfo(ctx context.Context) (madmin.AccountInfo, error) {
|
||||
return ac.minioAccountInfoMock(ctx)
|
||||
}
|
||||
@@ -14,11 +14,10 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package restapi
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"time"
|
||||
|
||||
"github.com/minio/mc/cmd"
|
||||
@@ -32,7 +31,7 @@ type objectsListOpts struct {
|
||||
}
|
||||
|
||||
type ObjectsRequest struct {
|
||||
Mode string `json:"mode,nonempty"`
|
||||
Mode string `json:"mode,omitempty"`
|
||||
BucketName string `json:"bucket_name"`
|
||||
Prefix string `json:"prefix"`
|
||||
Date string `json:"date"`
|
||||
@@ -40,18 +39,19 @@ type ObjectsRequest struct {
|
||||
}
|
||||
|
||||
type WSResponse struct {
|
||||
RequestID int64 `json:"request_id,nonempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
RequestID int64 `json:"request_id,omitempty"`
|
||||
Error *CodedAPIError `json:"error,omitempty"`
|
||||
RequestEnd bool `json:"request_end,omitempty"`
|
||||
Prefix string `json:"prefix,omitempty"`
|
||||
BucketName string `json:"bucketName,omitempty"`
|
||||
Data []ObjectResponse `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
type ObjectResponse struct {
|
||||
Name string `json:"name,nonempty"`
|
||||
LastModified string `json:"last_modified,nonempty"`
|
||||
Size int64 `json:"size,nonempty"`
|
||||
VersionID string `json:"version_id,nonempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
LastModified string `json:"last_modified,omitempty"`
|
||||
Size int64 `json:"size,omitempty"`
|
||||
VersionID string `json:"version_id,omitempty"`
|
||||
DeleteMarker bool `json:"delete_flag,omitempty"`
|
||||
IsLatest bool `json:"is_latest,omitempty"`
|
||||
}
|
||||
@@ -59,20 +59,7 @@ type ObjectResponse struct {
|
||||
func getObjectsOptionsFromReq(request ObjectsRequest) (*objectsListOpts, error) {
|
||||
pOptions := objectsListOpts{
|
||||
BucketName: request.BucketName,
|
||||
Prefix: "",
|
||||
}
|
||||
|
||||
prefix := request.Prefix
|
||||
|
||||
if prefix != "" {
|
||||
encodedPrefix := SanitizeEncodedPrefix(prefix)
|
||||
decodedPrefix, err := base64.StdEncoding.DecodeString(encodedPrefix)
|
||||
if err != nil {
|
||||
LogError("error decoding prefix: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pOptions.Prefix = string(decodedPrefix)
|
||||
Prefix: request.Prefix,
|
||||
}
|
||||
|
||||
if request.Mode == "rewind" {
|
||||
@@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package restapi
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -97,11 +97,11 @@ func TestWSRewindObjects(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Run(tt.name, func(_ *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
mcListMock = func(ctx context.Context, opts mc.ListOptions) <-chan *mc.ClientContent {
|
||||
mcListMock = func(_ context.Context, _ mc.ListOptions) <-chan *mc.ClientContent {
|
||||
ch := make(chan *mc.ClientContent)
|
||||
go func() {
|
||||
defer close(ch)
|
||||
@@ -206,11 +206,11 @@ func TestWSListObjects(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Run(tt.name, func(_ *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
minioListObjectsMock = func(ctx context.Context, bucket string, opts minio.ListObjectsOptions) <-chan minio.ObjectInfo {
|
||||
minioListObjectsMock = func(_ context.Context, _ string, _ minio.ListObjectsOptions) <-chan minio.ObjectInfo {
|
||||
ch := make(chan minio.ObjectInfo)
|
||||
go func() {
|
||||
defer close(ch)
|
||||
190
api/client-admin.go
Normal file
190
api/client-admin.go
Normal file
@@ -0,0 +1,190 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2021 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/minio/console/pkg"
|
||||
|
||||
"github.com/minio/console/pkg/utils"
|
||||
|
||||
"github.com/minio/console/models"
|
||||
"github.com/minio/madmin-go/v3"
|
||||
"github.com/minio/minio-go/v7/pkg/credentials"
|
||||
)
|
||||
|
||||
const globalAppName = "MinIO Console"
|
||||
|
||||
// MinioAdmin interface with all functions to be implemented
|
||||
// by mock when testing, it should include all MinioAdmin respective api calls
|
||||
// that are used within this project.
|
||||
type MinioAdmin interface {
|
||||
AccountInfo(ctx context.Context) (madmin.AccountInfo, error)
|
||||
// KMS
|
||||
kmsStatus(ctx context.Context) (madmin.KMSStatus, error)
|
||||
}
|
||||
|
||||
// Interface implementation
|
||||
//
|
||||
// Define the structure of a minIO Client and define the functions that are actually used
|
||||
// from minIO api.
|
||||
type AdminClient struct {
|
||||
Client *madmin.AdminClient
|
||||
}
|
||||
|
||||
// AccountInfo implements madmin.AccountInfo()
|
||||
func (ac AdminClient) AccountInfo(ctx context.Context) (madmin.AccountInfo, error) {
|
||||
return ac.Client.AccountInfo(ctx, madmin.AccountOpts{})
|
||||
}
|
||||
|
||||
func (ac AdminClient) getBucketQuota(ctx context.Context, bucket string) (madmin.BucketQuota, error) {
|
||||
return ac.Client.GetBucketQuota(ctx, bucket)
|
||||
}
|
||||
|
||||
func (ac AdminClient) kmsStatus(ctx context.Context) (madmin.KMSStatus, error) {
|
||||
return ac.Client.KMSStatus(ctx)
|
||||
}
|
||||
|
||||
func NewMinioAdminClient(ctx context.Context, sessionClaims *models.Principal) (*madmin.AdminClient, error) {
|
||||
clientIP := utils.ClientIPFromContext(ctx)
|
||||
adminClient, err := newAdminFromClaims(sessionClaims, clientIP)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
adminClient.SetAppInfo(globalAppName, pkg.Version)
|
||||
return adminClient, nil
|
||||
}
|
||||
|
||||
// newAdminFromClaims creates a minio admin from Decrypted claims using Assume role credentials
|
||||
func newAdminFromClaims(claims *models.Principal, clientIP string) (*madmin.AdminClient, error) {
|
||||
tlsEnabled := getMinIOEndpointIsSecure()
|
||||
endpoint := getMinIOEndpoint()
|
||||
|
||||
adminClient, err := madmin.NewWithOptions(endpoint, &madmin.Options{
|
||||
Creds: credentials.NewStaticV4(claims.STSAccessKeyID, claims.STSSecretAccessKey, claims.STSSessionToken),
|
||||
Secure: tlsEnabled,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
adminClient.SetAppInfo(globalAppName, pkg.Version)
|
||||
adminClient.SetCustomTransport(PrepareSTSClientTransport(clientIP))
|
||||
return adminClient, nil
|
||||
}
|
||||
|
||||
// isLocalAddress returns true if the url contains an IPv4/IPv6 hostname
|
||||
// that points to the local machine - FQDN are not supported
|
||||
func isLocalIPEndpoint(endpoint string) bool {
|
||||
u, err := url.Parse(endpoint)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return isLocalIPAddress(u.Hostname())
|
||||
}
|
||||
|
||||
// isLocalAddress returns true if the url contains an IPv4/IPv6 hostname
|
||||
// that points to the local machine - FQDN are not supported
|
||||
func isLocalIPAddress(ipAddr string) bool {
|
||||
if ipAddr == "" {
|
||||
return false
|
||||
}
|
||||
if ipAddr == "localhost" {
|
||||
return true
|
||||
}
|
||||
ip := net.ParseIP(ipAddr)
|
||||
return ip != nil && ip.IsLoopback()
|
||||
}
|
||||
|
||||
// GetConsoleHTTPClient caches different http clients depending on the target endpoint while taking
|
||||
// in consideration CA certs stored in ${HOME}/.console/certs/CAs and ${HOME}/.minio/certs/CAs
|
||||
// If the target endpoint points to a loopback device, skip the TLS verification.
|
||||
func GetConsoleHTTPClient(clientIP string) *http.Client {
|
||||
return PrepareConsoleHTTPClient(clientIP)
|
||||
}
|
||||
|
||||
var (
|
||||
// De-facto standard header keys.
|
||||
xForwardedFor = http.CanonicalHeaderKey("X-Forwarded-For")
|
||||
xRealIP = http.CanonicalHeaderKey("X-Real-IP")
|
||||
)
|
||||
|
||||
var (
|
||||
// RFC7239 defines a new "Forwarded: " header designed to replace the
|
||||
// existing use of X-Forwarded-* headers.
|
||||
// e.g. Forwarded: for=192.0.2.60;proto=https;by=203.0.113.43
|
||||
forwarded = http.CanonicalHeaderKey("Forwarded")
|
||||
// Allows for a sub-match of the first value after 'for=' to the next
|
||||
// comma, semi-colon or space. The match is case-insensitive.
|
||||
forRegex = regexp.MustCompile(`(?i)(?:for=)([^(;|,| )]+)(.*)`)
|
||||
)
|
||||
|
||||
// getSourceIPFromHeaders retrieves the IP from the X-Forwarded-For, X-Real-IP
|
||||
// and RFC7239 Forwarded headers (in that order)
|
||||
func getSourceIPFromHeaders(r *http.Request) string {
|
||||
var addr string
|
||||
|
||||
if fwd := r.Header.Get(xForwardedFor); fwd != "" {
|
||||
// Only grab the first (client) address. Note that '192.168.0.1,
|
||||
// 10.1.1.1' is a valid key for X-Forwarded-For where addresses after
|
||||
// the first may represent forwarding proxies earlier in the chain.
|
||||
s := strings.Index(fwd, ", ")
|
||||
if s == -1 {
|
||||
s = len(fwd)
|
||||
}
|
||||
addr = fwd[:s]
|
||||
} else if fwd := r.Header.Get(xRealIP); fwd != "" {
|
||||
// X-Real-IP should only contain one IP address (the client making the
|
||||
// request).
|
||||
addr = fwd
|
||||
} else if fwd := r.Header.Get(forwarded); fwd != "" {
|
||||
// match should contain at least two elements if the protocol was
|
||||
// specified in the Forwarded header. The first element will always be
|
||||
// the 'for=' capture, which we ignore. In the case of multiple IP
|
||||
// addresses (for=8.8.8.8, 8.8.4.4, 172.16.1.20 is valid) we only
|
||||
// extract the first, which should be the client IP.
|
||||
if match := forRegex.FindStringSubmatch(fwd); len(match) > 1 {
|
||||
// IPv6 addresses in Forwarded headers are quoted-strings. We strip
|
||||
// these quotes.
|
||||
addr = strings.Trim(match[1], `"`)
|
||||
}
|
||||
}
|
||||
|
||||
return addr
|
||||
}
|
||||
|
||||
// getClientIP retrieves the IP from the request headers
|
||||
// and falls back to r.RemoteAddr when necessary.
|
||||
// however returns without bracketing.
|
||||
func getClientIP(r *http.Request) string {
|
||||
addr := getSourceIPFromHeaders(r)
|
||||
if addr == "" {
|
||||
addr = r.RemoteAddr
|
||||
}
|
||||
|
||||
// Default to remote address if headers not set.
|
||||
raddr, _, _ := net.SplitHostPort(addr)
|
||||
if raddr == "" {
|
||||
return addr
|
||||
}
|
||||
return raddr
|
||||
}
|
||||
@@ -14,32 +14,28 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package restapi
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"net/http"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/minio/minio-go/v7/pkg/replication"
|
||||
"github.com/minio/minio-go/v7/pkg/sse"
|
||||
xnet "github.com/minio/pkg/net"
|
||||
xnet "github.com/minio/pkg/v3/net"
|
||||
|
||||
"github.com/minio/console/models"
|
||||
"github.com/minio/console/pkg"
|
||||
"github.com/minio/console/pkg/auth"
|
||||
"github.com/minio/console/pkg/auth/ldap"
|
||||
xjwt "github.com/minio/console/pkg/auth/token"
|
||||
mc "github.com/minio/mc/cmd"
|
||||
"github.com/minio/mc/pkg/probe"
|
||||
"github.com/minio/minio-go/v7"
|
||||
"github.com/minio/minio-go/v7/pkg/credentials"
|
||||
"github.com/minio/minio-go/v7/pkg/lifecycle"
|
||||
"github.com/minio/minio-go/v7/pkg/notification"
|
||||
"github.com/minio/minio-go/v7/pkg/tags"
|
||||
)
|
||||
@@ -75,8 +71,6 @@ type MinioClient interface {
|
||||
setObjectLockConfig(ctx context.Context, bucketName string, mode *minio.RetentionMode, validity *uint, unit *minio.ValidityUnit) error
|
||||
getBucketObjectLockConfig(ctx context.Context, bucketName string) (mode *minio.RetentionMode, validity *uint, unit *minio.ValidityUnit, err error)
|
||||
getObjectLockConfig(ctx context.Context, bucketName string) (lock string, mode *minio.RetentionMode, validity *uint, unit *minio.ValidityUnit, err error)
|
||||
getLifecycleRules(ctx context.Context, bucketName string) (lifecycle *lifecycle.Configuration, err error)
|
||||
setBucketLifecycle(ctx context.Context, bucketName string, config *lifecycle.Configuration) error
|
||||
copyObject(ctx context.Context, dst minio.CopyDestOptions, src minio.CopySrcOptions) (minio.UploadInfo, error)
|
||||
GetBucketTagging(ctx context.Context, bucketName string) (*tags.Tags, error)
|
||||
SetBucketTagging(ctx context.Context, bucketName string, tags *tags.Tags) error
|
||||
@@ -141,11 +135,6 @@ func (c minioClient) getBucketVersioning(ctx context.Context, bucketName string)
|
||||
return c.client.GetBucketVersioning(ctx, bucketName)
|
||||
}
|
||||
|
||||
// implements minio.getBucketVersioning(ctx, bucketName)
|
||||
func (c minioClient) getBucketReplication(ctx context.Context, bucketName string) (replication.Config, error) {
|
||||
return c.client.GetBucketReplication(ctx, bucketName)
|
||||
}
|
||||
|
||||
// implements minio.listObjects(ctx)
|
||||
func (c minioClient) listObjects(ctx context.Context, bucket string, opts minio.ListObjectsOptions) <-chan minio.ObjectInfo {
|
||||
return c.client.ListObjects(ctx, bucket, opts)
|
||||
@@ -210,22 +199,10 @@ func (c minioClient) getObjectLockConfig(ctx context.Context, bucketName string)
|
||||
return c.client.GetObjectLockConfig(ctx, bucketName)
|
||||
}
|
||||
|
||||
func (c minioClient) getLifecycleRules(ctx context.Context, bucketName string) (lifecycle *lifecycle.Configuration, err error) {
|
||||
return c.client.GetBucketLifecycle(ctx, bucketName)
|
||||
}
|
||||
|
||||
func (c minioClient) setBucketLifecycle(ctx context.Context, bucketName string, config *lifecycle.Configuration) error {
|
||||
return c.client.SetBucketLifecycle(ctx, bucketName, config)
|
||||
}
|
||||
|
||||
func (c minioClient) copyObject(ctx context.Context, dst minio.CopyDestOptions, src minio.CopySrcOptions) (minio.UploadInfo, error) {
|
||||
return c.client.CopyObject(ctx, dst, src)
|
||||
}
|
||||
|
||||
func (c minioClient) presignedGetObject(ctx context.Context, bucketName, objectName string, expiry time.Duration, reqParams url.Values) (*url.URL, error) {
|
||||
return c.client.PresignedGetObject(ctx, bucketName, objectName, expiry, reqParams)
|
||||
}
|
||||
|
||||
// MCClient interface with all functions to be implemented
|
||||
// by mock when testing, it should include all mc/S3Client respective api calls
|
||||
// that are used within this project.
|
||||
@@ -237,7 +214,7 @@ type MCClient interface {
|
||||
list(ctx context.Context, opts mc.ListOptions) <-chan *mc.ClientContent
|
||||
get(ctx context.Context, opts mc.GetOptions) (io.ReadCloser, *probe.Error)
|
||||
shareDownload(ctx context.Context, versionID string, expires time.Duration) (string, *probe.Error)
|
||||
setVersioning(ctx context.Context, status string) *probe.Error
|
||||
setVersioning(ctx context.Context, status string, excludePrefix []string, excludeFolders bool) *probe.Error
|
||||
}
|
||||
|
||||
// Interface implementation
|
||||
@@ -262,16 +239,8 @@ func (c mcClient) watch(ctx context.Context, options mc.WatchOptions) (*mc.Watch
|
||||
return c.client.Watch(ctx, options)
|
||||
}
|
||||
|
||||
func (c mcClient) setReplication(ctx context.Context, cfg *replication.Config, opts replication.Options) *probe.Error {
|
||||
return c.client.SetReplication(ctx, cfg, opts)
|
||||
}
|
||||
|
||||
func (c mcClient) deleteAllReplicationRules(ctx context.Context) *probe.Error {
|
||||
return c.client.RemoveReplication(ctx)
|
||||
}
|
||||
|
||||
func (c mcClient) setVersioning(ctx context.Context, status string) *probe.Error {
|
||||
return c.client.SetVersion(ctx, status, []string{}, false)
|
||||
func (c mcClient) setVersioning(ctx context.Context, status string, excludePrefix []string, excludeFolders bool) *probe.Error {
|
||||
return c.client.SetVersion(ctx, status, excludePrefix, excludeFolders)
|
||||
}
|
||||
|
||||
func (c mcClient) remove(ctx context.Context, isIncomplete, isRemoveBucket, isBypass, forceDelete bool, contentCh <-chan *mc.ClientContent) <-chan mc.RemoveResult {
|
||||
@@ -283,7 +252,8 @@ func (c mcClient) list(ctx context.Context, opts mc.ListOptions) <-chan *mc.Clie
|
||||
}
|
||||
|
||||
func (c mcClient) get(ctx context.Context, opts mc.GetOptions) (io.ReadCloser, *probe.Error) {
|
||||
return c.client.Get(ctx, opts)
|
||||
rd, _, err := c.client.Get(ctx, opts)
|
||||
return rd, err
|
||||
}
|
||||
|
||||
func (c mcClient) shareDownload(ctx context.Context, versionID string, expires time.Duration) (string, *probe.Error) {
|
||||
@@ -303,6 +273,7 @@ type ConsoleCredentialsI interface {
|
||||
type ConsoleCredentials struct {
|
||||
ConsoleCredentials *credentials.Credentials
|
||||
AccountAccessKey string
|
||||
CredContext *credentials.CredContext
|
||||
}
|
||||
|
||||
func (c ConsoleCredentials) GetAccountAccessKey() string {
|
||||
@@ -311,7 +282,7 @@ func (c ConsoleCredentials) GetAccountAccessKey() string {
|
||||
|
||||
// Get implements *Login.Get()
|
||||
func (c ConsoleCredentials) Get() (credentials.Value, error) {
|
||||
return c.ConsoleCredentials.Get()
|
||||
return c.ConsoleCredentials.GetWithContext(c.CredContext)
|
||||
}
|
||||
|
||||
// Expire implements *Login.Expire()
|
||||
@@ -326,6 +297,10 @@ type consoleSTSAssumeRole struct {
|
||||
stsAssumeRole *credentials.STSAssumeRole
|
||||
}
|
||||
|
||||
func (s consoleSTSAssumeRole) RetrieveWithCredContext(cc *credentials.CredContext) (credentials.Value, error) {
|
||||
return s.stsAssumeRole.RetrieveWithCredContext(cc)
|
||||
}
|
||||
|
||||
func (s consoleSTSAssumeRole) Retrieve() (credentials.Value, error) {
|
||||
return s.stsAssumeRole.Retrieve()
|
||||
}
|
||||
@@ -334,7 +309,7 @@ func (s consoleSTSAssumeRole) IsExpired() bool {
|
||||
return s.stsAssumeRole.IsExpired()
|
||||
}
|
||||
|
||||
func stsCredentials(minioURL, accessKey, secretKey, location string) (*credentials.Credentials, error) {
|
||||
func stsCredentials(minioURL, accessKey, secretKey, location string, client *http.Client) (*credentials.Credentials, error) {
|
||||
if accessKey == "" || secretKey == "" {
|
||||
return nil, errors.New("credentials endpoint, access and secret key are mandatory for AssumeRoleSTS")
|
||||
}
|
||||
@@ -345,7 +320,7 @@ func stsCredentials(minioURL, accessKey, secretKey, location string) (*credentia
|
||||
DurationSeconds: int(xjwt.GetConsoleSTSDuration().Seconds()),
|
||||
}
|
||||
stsAssumeRole := &credentials.STSAssumeRole{
|
||||
Client: GetConsoleHTTPClient(minioURL),
|
||||
Client: client,
|
||||
STSEndpoint: minioURL,
|
||||
Options: opts,
|
||||
}
|
||||
@@ -353,51 +328,10 @@ func stsCredentials(minioURL, accessKey, secretKey, location string) (*credentia
|
||||
return credentials.New(consoleSTSWrapper), nil
|
||||
}
|
||||
|
||||
func NewConsoleCredentials(accessKey, secretKey, location string) (*credentials.Credentials, error) {
|
||||
func NewConsoleCredentials(accessKey, secretKey, location string, client *http.Client) (*credentials.Credentials, error) {
|
||||
minioURL := getMinIOServer()
|
||||
|
||||
// Future authentication methods can be added under this switch statement
|
||||
switch {
|
||||
// LDAP authentication for Console
|
||||
case ldap.GetLDAPEnabled():
|
||||
{
|
||||
creds, err := auth.GetCredentialsFromLDAP(GetConsoleHTTPClient(minioURL), minioURL, accessKey, secretKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// We verify if LDAP credentials are correct and no error is returned
|
||||
_, err = creds.Get()
|
||||
|
||||
if err != nil && strings.Contains(strings.ToLower(err.Error()), "not found") {
|
||||
// We try to use STS Credentials in case LDAP credentials are incorrect.
|
||||
stsCreds, errSTS := stsCredentials(minioURL, accessKey, secretKey, location)
|
||||
|
||||
// If there is an error with STS too, then we return the original LDAP error
|
||||
if errSTS != nil {
|
||||
LogError("error in STS credentials for LDAP case: %v ", errSTS)
|
||||
|
||||
// We return LDAP result
|
||||
return creds, nil
|
||||
}
|
||||
|
||||
_, err := stsCreds.Get()
|
||||
// There is an error with STS credentials, We return the result of LDAP as STS is not a priority in this case.
|
||||
if err != nil {
|
||||
return creds, nil
|
||||
}
|
||||
|
||||
return stsCreds, nil
|
||||
}
|
||||
|
||||
return creds, nil
|
||||
}
|
||||
// default authentication for Console is via STS (Security Token Service) against MinIO
|
||||
default:
|
||||
{
|
||||
return stsCredentials(minioURL, accessKey, secretKey, location)
|
||||
}
|
||||
}
|
||||
return stsCredentials(minioURL, accessKey, secretKey, location, client)
|
||||
}
|
||||
|
||||
// getConsoleCredentialsFromSession returns the *consoleCredentials.Login associated to the
|
||||
@@ -411,14 +345,14 @@ func getConsoleCredentialsFromSession(claims *models.Principal) *credentials.Cre
|
||||
|
||||
// newMinioClient creates a new MinIO client based on the ConsoleCredentials extracted
|
||||
// from the provided session token
|
||||
func newMinioClient(claims *models.Principal) (*minio.Client, error) {
|
||||
func newMinioClient(claims *models.Principal, clientIP string) (*minio.Client, error) {
|
||||
creds := getConsoleCredentialsFromSession(claims)
|
||||
endpoint := getMinIOEndpoint()
|
||||
secure := getMinIOEndpointIsSecure()
|
||||
minioClient, err := minio.New(endpoint, &minio.Options{
|
||||
Creds: creds,
|
||||
Secure: secure,
|
||||
Transport: GetConsoleHTTPClient(getMinIOServer()).Transport,
|
||||
Transport: GetConsoleHTTPClient(clientIP).Transport,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -430,10 +364,9 @@ func newMinioClient(claims *models.Principal) (*minio.Client, error) {
|
||||
|
||||
// computeObjectURLWithoutEncode returns a MinIO url containing the object filename without encoding
|
||||
func computeObjectURLWithoutEncode(bucketName, prefix string) (string, error) {
|
||||
endpoint := getMinIOServer()
|
||||
u, err := xnet.ParseHTTPURL(endpoint)
|
||||
u, err := xnet.ParseHTTPURL(getMinIOServer())
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("the provided endpoint is invalid")
|
||||
return "", fmt.Errorf("the provided endpoint: '%s' is invalid", getMinIOServer())
|
||||
}
|
||||
var p string
|
||||
if strings.TrimSpace(bucketName) != "" {
|
||||
@@ -442,11 +375,11 @@ func computeObjectURLWithoutEncode(bucketName, prefix string) (string, error) {
|
||||
if strings.TrimSpace(prefix) != "" {
|
||||
p = pathJoinFinalSlash(p, prefix)
|
||||
}
|
||||
return fmt.Sprintf("%s://%s/%s", u.Scheme, u.Host, p), nil
|
||||
return u.String() + "/" + p, nil
|
||||
}
|
||||
|
||||
// newS3BucketClient creates a new mc S3Client to talk to the server based on a bucket
|
||||
func newS3BucketClient(claims *models.Principal, bucketName string, prefix string) (*mc.S3Client, error) {
|
||||
func newS3BucketClient(claims *models.Principal, bucketName string, prefix string, clientIP string) (*mc.S3Client, error) {
|
||||
if claims == nil {
|
||||
return nil, fmt.Errorf("the provided credentials are invalid")
|
||||
}
|
||||
@@ -455,7 +388,7 @@ func newS3BucketClient(claims *models.Principal, bucketName string, prefix strin
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("the provided endpoint is invalid")
|
||||
}
|
||||
s3Config := newS3Config(objectURL, claims.STSAccessKeyID, claims.STSSecretAccessKey, claims.STSSessionToken)
|
||||
s3Config := newS3Config(objectURL, claims.STSAccessKeyID, claims.STSSecretAccessKey, claims.STSSessionToken, clientIP)
|
||||
client, pErr := mc.S3New(s3Config)
|
||||
if pErr != nil {
|
||||
return nil, pErr.Cause
|
||||
@@ -477,27 +410,24 @@ func pathJoinFinalSlash(elem ...string) string {
|
||||
return path.Join(elem...)
|
||||
}
|
||||
|
||||
// Deprecated
|
||||
// newS3Config simply creates a new Config struct using the passed
|
||||
// parameters.
|
||||
func newS3Config(endpoint, accessKey, secretKey, sessionToken string) *mc.Config {
|
||||
func newS3Config(endpoint, accessKey, secretKey, sessionToken string, clientIP string) *mc.Config {
|
||||
// We have a valid alias and hostConfig. We populate the/
|
||||
// consoleCredentials from the match found in the config file.
|
||||
s3Config := new(mc.Config)
|
||||
|
||||
s3Config.AppName = globalAppName
|
||||
s3Config.AppVersion = pkg.Version
|
||||
s3Config.Debug = false
|
||||
|
||||
s3Config.HostURL = endpoint
|
||||
s3Config.AccessKey = accessKey
|
||||
s3Config.SecretKey = secretKey
|
||||
s3Config.SessionToken = sessionToken
|
||||
s3Config.Signature = "S3v4"
|
||||
|
||||
insecure := isLocalIPEndpoint(endpoint)
|
||||
|
||||
s3Config.Insecure = insecure
|
||||
s3Config.Transport = PrepareSTSClientTransport(insecure)
|
||||
|
||||
return s3Config
|
||||
return &mc.Config{
|
||||
HostURL: endpoint,
|
||||
AccessKey: accessKey,
|
||||
SecretKey: secretKey,
|
||||
SessionToken: sessionToken,
|
||||
Signature: "S3v4",
|
||||
AppName: globalAppName,
|
||||
AppVersion: pkg.Version,
|
||||
Insecure: isLocalIPEndpoint(endpoint),
|
||||
Transport: &ConsoleTransport{
|
||||
ClientIP: clientIP,
|
||||
Transport: GlobalTransport,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2021 MinIO, Inc.
|
||||
// Copyright (c) 2024 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
@@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package restapi
|
||||
package api
|
||||
|
||||
import "testing"
|
||||
|
||||
@@ -76,14 +76,15 @@ func Test_computeObjectURLWithoutEncode(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Run(tt.name, func(_ *testing.T) {
|
||||
got, err := computeObjectURLWithoutEncode(tt.args.bucketName, tt.args.prefix)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("computeObjectURLWithoutEncode() errors = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("computeObjectURLWithoutEncode() got = %v, want %v", got, tt.want)
|
||||
if err == nil {
|
||||
if got != tt.want {
|
||||
t.Errorf("computeObjectURLWithoutEncode() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -14,18 +14,21 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package restapi
|
||||
package api
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/minio/console/pkg/auth/idp/oauth2"
|
||||
xcerts "github.com/minio/pkg/certs"
|
||||
"github.com/minio/pkg/env"
|
||||
xnet "github.com/minio/pkg/net"
|
||||
xcerts "github.com/minio/pkg/v3/certs"
|
||||
"github.com/minio/pkg/v3/env"
|
||||
xnet "github.com/minio/pkg/v3/net"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -54,6 +57,31 @@ var (
|
||||
GlobalPublicCerts []*x509.Certificate
|
||||
// GlobalTLSCertsManager custom TLS Manager for SNI support
|
||||
GlobalTLSCertsManager *xcerts.Manager
|
||||
// GlobalTransport is common transport used for all HTTP calls, this is set via
|
||||
// MinIO server to be the correct transport, however we still define some defaults
|
||||
// here just in case.
|
||||
GlobalTransport = &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
DialContext: (&net.Dialer{
|
||||
Timeout: 10 * time.Second,
|
||||
KeepAlive: 15 * time.Second,
|
||||
}).DialContext,
|
||||
MaxIdleConns: 1024,
|
||||
MaxIdleConnsPerHost: 1024,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
ExpectContinueTimeout: 10 * time.Second,
|
||||
DisableCompression: true, // Set to avoid auto-decompression
|
||||
TLSClientConfig: &tls.Config{
|
||||
// Can't use SSLv3 because of POODLE and BEAST
|
||||
// Can't use TLSv1.0 because of POODLE and BEAST using CBC cipher
|
||||
// Can't use TLSv1.1 because of RC4 cipher usage
|
||||
MinVersion: tls.VersionTLS12,
|
||||
// Console runs in the same pod/node as MinIO this is acceptable.
|
||||
InsecureSkipVerify: true,
|
||||
RootCAs: GlobalRootCAs,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// MinIOConfig represents application configuration passed in from the MinIO
|
||||
@@ -70,10 +98,6 @@ func getMinIOServer() string {
|
||||
return strings.TrimSpace(env.Get(ConsoleMinIOServer, "http://localhost:9000"))
|
||||
}
|
||||
|
||||
func getSubnetProxy() string {
|
||||
return strings.TrimSpace(env.Get(ConsoleSubnetProxy, ""))
|
||||
}
|
||||
|
||||
func GetMinIORegion() string {
|
||||
return strings.TrimSpace(env.Get(ConsoleMinIORegion, ""))
|
||||
}
|
||||
@@ -203,21 +227,11 @@ func GetSecureSTSPreload() bool {
|
||||
return strings.ToLower(env.Get(ConsoleSecureSTSPreload, "off")) == "on"
|
||||
}
|
||||
|
||||
// If TLSTemporaryRedirect is true, the a 302 will be used while redirecting. Default is false (301).
|
||||
func GetSecureTLSTemporaryRedirect() bool {
|
||||
return strings.ToLower(env.Get(ConsoleSecureTLSTemporaryRedirect, "off")) == "on"
|
||||
}
|
||||
|
||||
// STS header is only included when the connection is HTTPS.
|
||||
func GetSecureForceSTSHeader() bool {
|
||||
return strings.ToLower(env.Get(ConsoleSecureForceSTSHeader, "off")) == "on"
|
||||
}
|
||||
|
||||
// PublicKey implements HPKP to prevent MITM attacks with forged certificates. Default is "".
|
||||
func GetSecurePublicKey() string {
|
||||
return env.Get(ConsoleSecurePublicKey, "")
|
||||
}
|
||||
|
||||
// ReferrerPolicy allows the Referrer-Policy header with the value to be set with a custom value. Default is "".
|
||||
func GetSecureReferrerPolicy() string {
|
||||
return env.Get(ConsoleSecureReferrerPolicy, "")
|
||||
@@ -228,10 +242,6 @@ func GetSecureFeaturePolicy() string {
|
||||
return env.Get(ConsoleSecureFeaturePolicy, "")
|
||||
}
|
||||
|
||||
func GetSecureExpectCTHeader() string {
|
||||
return env.Get(ConsoleSecureExpectCTHeader, "")
|
||||
}
|
||||
|
||||
func getLogSearchAPIToken() string {
|
||||
if v := env.Get(ConsoleLogQueryAuthToken, ""); v != "" {
|
||||
return v
|
||||
@@ -239,22 +249,6 @@ func getLogSearchAPIToken() string {
|
||||
return env.Get(LogSearchQueryAuthToken, "")
|
||||
}
|
||||
|
||||
func getLogSearchURL() string {
|
||||
return env.Get(ConsoleLogQueryURL, "")
|
||||
}
|
||||
|
||||
func getPrometheusURL() string {
|
||||
return env.Get(PrometheusURL, "")
|
||||
}
|
||||
|
||||
func getPrometheusJobID() string {
|
||||
return env.Get(PrometheusJobID, "minio-job")
|
||||
}
|
||||
|
||||
func getPrometheusExtraLabels() string {
|
||||
return env.Get(PrometheusExtraLabels, "")
|
||||
}
|
||||
|
||||
func getMaxConcurrentUploadsLimit() int64 {
|
||||
cu, err := strconv.ParseInt(env.Get(ConsoleMaxConcurrentUploads, "10"), 10, 64)
|
||||
if err != nil {
|
||||
@@ -280,3 +274,7 @@ func getConsoleDevMode() bool {
|
||||
func getConsoleAnimatedLogin() bool {
|
||||
return strings.ToLower(env.Get(ConsoleAnimatedLogin, "on")) == "on"
|
||||
}
|
||||
|
||||
func getConsoleBrowserRedirectURL() string {
|
||||
return env.Get(ConsoleBrowserRedirectURL, "")
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package restapi
|
||||
package api
|
||||
|
||||
import (
|
||||
"os"
|
||||
@@ -54,7 +54,7 @@ func TestGetPort(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Run(tt.name, func(_ *testing.T) {
|
||||
os.Setenv(ConsolePort, tt.args.env)
|
||||
assert.Equalf(t, tt.want, GetPort(), "GetPort()")
|
||||
os.Unsetenv(ConsolePort)
|
||||
@@ -87,7 +87,7 @@ func TestGetTLSPort(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Run(tt.name, func(_ *testing.T) {
|
||||
os.Setenv(ConsoleTLSPort, tt.args.env)
|
||||
assert.Equalf(t, tt.want, GetTLSPort(), "GetTLSPort()")
|
||||
os.Unsetenv(ConsoleTLSPort)
|
||||
@@ -120,7 +120,7 @@ func TestGetSecureAllowedHosts(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Run(tt.name, func(_ *testing.T) {
|
||||
os.Setenv(ConsoleSecureAllowedHosts, tt.args.env)
|
||||
assert.Equalf(t, tt.want, GetSecureAllowedHosts(), "GetSecureAllowedHosts()")
|
||||
os.Unsetenv(ConsoleSecureAllowedHosts)
|
||||
@@ -153,7 +153,7 @@ func TestGetSecureHostsProxyHeaders(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Run(tt.name, func(_ *testing.T) {
|
||||
os.Setenv(ConsoleSecureHostsProxyHeaders, tt.args.env)
|
||||
assert.Equalf(t, tt.want, GetSecureHostsProxyHeaders(), "GetSecureHostsProxyHeaders()")
|
||||
os.Unsetenv(ConsoleSecureHostsProxyHeaders)
|
||||
@@ -186,7 +186,7 @@ func TestGetSecureSTSSeconds(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Run(tt.name, func(_ *testing.T) {
|
||||
os.Setenv(ConsoleSecureSTSSeconds, tt.args.env)
|
||||
assert.Equalf(t, tt.want, GetSecureSTSSeconds(), "GetSecureSTSSeconds()")
|
||||
os.Unsetenv(ConsoleSecureSTSSeconds)
|
||||
@@ -219,7 +219,7 @@ func Test_getLogSearchAPIToken(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Run(tt.name, func(_ *testing.T) {
|
||||
os.Setenv(ConsoleLogQueryAuthToken, tt.args.env)
|
||||
assert.Equalf(t, tt.want, getLogSearchAPIToken(), "getLogSearchAPIToken()")
|
||||
os.Setenv(ConsoleLogQueryAuthToken, tt.args.env)
|
||||
@@ -227,72 +227,6 @@ func Test_getLogSearchAPIToken(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func Test_getPrometheusURL(t *testing.T) {
|
||||
type args struct {
|
||||
env string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "env set",
|
||||
args: args{
|
||||
env: "value",
|
||||
},
|
||||
want: "value",
|
||||
},
|
||||
{
|
||||
name: "env not set",
|
||||
args: args{
|
||||
env: "",
|
||||
},
|
||||
want: "",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
os.Setenv(PrometheusURL, tt.args.env)
|
||||
assert.Equalf(t, tt.want, getPrometheusURL(), "getPrometheusURL()")
|
||||
os.Setenv(PrometheusURL, tt.args.env)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_getPrometheusJobID(t *testing.T) {
|
||||
type args struct {
|
||||
env string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "env set",
|
||||
args: args{
|
||||
env: "value",
|
||||
},
|
||||
want: "value",
|
||||
},
|
||||
{
|
||||
name: "env not set",
|
||||
args: args{
|
||||
env: "",
|
||||
},
|
||||
want: "minio-job",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
os.Setenv(PrometheusJobID, tt.args.env)
|
||||
assert.Equalf(t, tt.want, getPrometheusJobID(), "getPrometheusJobID()")
|
||||
os.Setenv(PrometheusJobID, tt.args.env)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_getMaxConcurrentUploadsLimit(t *testing.T) {
|
||||
type args struct {
|
||||
env string
|
||||
@@ -318,7 +252,7 @@ func Test_getMaxConcurrentUploadsLimit(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Run(tt.name, func(_ *testing.T) {
|
||||
os.Setenv(ConsoleMaxConcurrentUploads, tt.args.env)
|
||||
assert.Equalf(t, tt.want, getMaxConcurrentUploadsLimit(), "getMaxConcurrentUploadsLimit()")
|
||||
os.Unsetenv(ConsoleMaxConcurrentUploads)
|
||||
@@ -351,7 +285,7 @@ func Test_getMaxConcurrentDownloadsLimit(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Run(tt.name, func(_ *testing.T) {
|
||||
os.Setenv(ConsoleMaxConcurrentDownloads, tt.args.env)
|
||||
assert.Equalf(t, tt.want, getMaxConcurrentDownloadsLimit(), "getMaxConcurrentDownloadsLimit()")
|
||||
os.Unsetenv(ConsoleMaxConcurrentDownloads)
|
||||
@@ -384,7 +318,7 @@ func Test_getConsoleDevMode(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Run(tt.name, func(_ *testing.T) {
|
||||
os.Setenv(ConsoleDevMode, tt.args.env)
|
||||
assert.Equalf(t, tt.want, getConsoleDevMode(), "getConsoleDevMode()")
|
||||
os.Unsetenv(ConsoleDevMode)
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
// This file is safe to edit. Once it exists it will not be overwritten
|
||||
|
||||
package restapi
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -31,26 +31,30 @@ import (
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/minio/console/pkg/logger"
|
||||
"github.com/minio/console/pkg/utils"
|
||||
"github.com/minio/minio-go/v7/pkg/credentials"
|
||||
|
||||
"github.com/klauspost/compress/gzhttp"
|
||||
|
||||
portal_ui "github.com/minio/console/portal-ui"
|
||||
"github.com/minio/pkg/env"
|
||||
"github.com/minio/pkg/mimedb"
|
||||
xnet "github.com/minio/pkg/net"
|
||||
portal_ui "github.com/minio/console/web-app"
|
||||
"github.com/minio/pkg/v3/env"
|
||||
"github.com/minio/pkg/v3/mimedb"
|
||||
xnet "github.com/minio/pkg/v3/net"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/minio/console/api/operations"
|
||||
"github.com/minio/console/models"
|
||||
"github.com/minio/console/pkg/auth"
|
||||
"github.com/minio/console/restapi/operations"
|
||||
"github.com/unrolled/secure"
|
||||
)
|
||||
|
||||
@@ -65,7 +69,7 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
subPath = "/"
|
||||
cfgSubPath = "/"
|
||||
subPathOnce sync.Once
|
||||
)
|
||||
|
||||
@@ -80,7 +84,7 @@ func configureFlags(api *operations.ConsoleAPI) {
|
||||
|
||||
func configureAPI(api *operations.ConsoleAPI) http.Handler {
|
||||
// Applies when the "x-token" header is set
|
||||
api.KeyAuth = func(token string, scopes []string) (*models.Principal, error) {
|
||||
api.KeyAuth = func(token string, _ []string) (*models.Principal, error) {
|
||||
// we are validating the session token by decrypting the claims inside, if the operation succeed that means the jwt
|
||||
// was generated and signed by us in the first place
|
||||
if token == "Anonymous" {
|
||||
@@ -101,7 +105,7 @@ func configureAPI(api *operations.ConsoleAPI) http.Handler {
|
||||
CustomStyleOb: claims.CustomStyleOB,
|
||||
}, nil
|
||||
}
|
||||
api.AnonymousAuth = func(s string) (*models.Principal, error) {
|
||||
api.AnonymousAuth = func(_ string) (*models.Principal, error) {
|
||||
return &models.Principal{}, nil
|
||||
}
|
||||
|
||||
@@ -111,72 +115,19 @@ func configureAPI(api *operations.ConsoleAPI) http.Handler {
|
||||
registerLogoutHandlers(api)
|
||||
// Register bucket handlers
|
||||
registerBucketsHandlers(api)
|
||||
// Register all users handlers
|
||||
registerUsersHandlers(api)
|
||||
// Register groups handlers
|
||||
registerGroupsHandlers(api)
|
||||
// Register policies handlers
|
||||
registersPoliciesHandler(api)
|
||||
// Register configurations handlers
|
||||
registerConfigHandlers(api)
|
||||
// Register bucket events handlers
|
||||
registerBucketEventsHandlers(api)
|
||||
// Register bucket lifecycle handlers
|
||||
registerBucketsLifecycleHandlers(api)
|
||||
// Register service handlers
|
||||
registerServiceHandlers(api)
|
||||
// Register session handlers
|
||||
registerSessionHandlers(api)
|
||||
// Register version handlers
|
||||
registerVersionHandlers(api)
|
||||
// Register admin info handlers
|
||||
registerAdminInfoHandlers(api)
|
||||
// Register admin arns handlers
|
||||
registerAdminArnsHandlers(api)
|
||||
// Register admin notification endpoints handlers
|
||||
registerAdminNotificationEndpointsHandlers(api)
|
||||
// Register admin Service Account Handlers
|
||||
registerServiceAccountsHandlers(api)
|
||||
// Register admin remote buckets
|
||||
registerAdminBucketRemoteHandlers(api)
|
||||
// Register admin log search
|
||||
registerLogSearchHandlers(api)
|
||||
// Register admin subnet handlers
|
||||
registerSubnetHandlers(api)
|
||||
// Register admin KMS handlers
|
||||
registerKMSHandlers(api)
|
||||
// Register admin IDP handlers
|
||||
registerIDPHandlers(api)
|
||||
// Register Account handlers
|
||||
registerAdminTiersHandlers(api)
|
||||
// Register Inspect Handler
|
||||
registerInspectHandler(api)
|
||||
// Register nodes handlers
|
||||
registerNodesHandler(api)
|
||||
|
||||
registerSiteReplicationHandler(api)
|
||||
registerSiteReplicationStatusHandler(api)
|
||||
// Register Support Handler
|
||||
registerSupportHandlers(api)
|
||||
|
||||
// Operator Console
|
||||
|
||||
// Register Object's Handlers
|
||||
registerObjectsHandlers(api)
|
||||
// Register Bucket Quota's Handlers
|
||||
registerBucketQuotaHandlers(api)
|
||||
// Register Account handlers
|
||||
registerAccountHandlers(api)
|
||||
|
||||
registerReleasesHandlers(api)
|
||||
// Register Bucket Policy's Handlers
|
||||
registerPublicObjectsHandlers(api)
|
||||
|
||||
api.PreServerShutdown = func() {}
|
||||
|
||||
api.ServerShutdown = func() {}
|
||||
|
||||
// do an initial subnet plan caching
|
||||
fetchLicensePlan()
|
||||
|
||||
return setupGlobalMiddleware(api.Serve(setupMiddlewares))
|
||||
}
|
||||
|
||||
@@ -194,15 +145,12 @@ func setupMiddlewares(handler http.Handler) http.Handler {
|
||||
|
||||
func ContextMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
requestID, err := utils.NewUUID()
|
||||
if err != nil && err != auth.ErrNoAuthToken {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
requestID := uuid.NewString()
|
||||
ctx := context.WithValue(r.Context(), utils.ContextRequestID, requestID)
|
||||
ctx = context.WithValue(ctx, utils.ContextRequestUserAgent, r.UserAgent())
|
||||
ctx = context.WithValue(ctx, utils.ContextRequestHost, r.Host)
|
||||
ctx = context.WithValue(ctx, utils.ContextRequestRemoteAddr, r.RemoteAddr)
|
||||
ctx = context.WithValue(ctx, utils.ContextClientIP, getClientIP(r))
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
@@ -217,6 +165,97 @@ func AuditLogMiddleware(next http.Handler) http.Handler {
|
||||
})
|
||||
}
|
||||
|
||||
func DebugLogMiddleware(next http.Handler) http.Handler {
|
||||
debugLogLevel, _ := env.GetInt("CONSOLE_DEBUG_LOGLEVEL", 0)
|
||||
if debugLogLevel == 0 {
|
||||
return next
|
||||
}
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
rw := logger.NewResponseWriter(w)
|
||||
next.ServeHTTP(rw, r)
|
||||
debugLog(debugLogLevel, r, rw)
|
||||
})
|
||||
}
|
||||
|
||||
func debugLog(debugLogLevel int, r *http.Request, rw *logger.ResponseWriter) {
|
||||
switch debugLogLevel {
|
||||
case 1:
|
||||
// Log server errors only (summary)
|
||||
if rw.StatusCode >= 500 {
|
||||
debugLogSummary(r, rw)
|
||||
}
|
||||
case 2:
|
||||
// Log server and client errors (summary)
|
||||
if rw.StatusCode >= 400 {
|
||||
debugLogSummary(r, rw)
|
||||
}
|
||||
case 3:
|
||||
// Log all requests (summary)
|
||||
debugLogSummary(r, rw)
|
||||
case 4:
|
||||
// Log server errors only (including headers)
|
||||
if rw.StatusCode >= 500 {
|
||||
debugLogDetails(r, rw)
|
||||
}
|
||||
case 5:
|
||||
// Log server and client errors (including headers)
|
||||
if rw.StatusCode >= 400 {
|
||||
debugLogDetails(r, rw)
|
||||
}
|
||||
case 6:
|
||||
// Log all requests (including headers)
|
||||
debugLogDetails(r, rw)
|
||||
}
|
||||
}
|
||||
|
||||
func debugLogSummary(r *http.Request, rw *logger.ResponseWriter) {
|
||||
statusCode := strconv.Itoa(rw.StatusCode)
|
||||
if rw.Hijacked {
|
||||
statusCode = "hijacked"
|
||||
}
|
||||
logger.Info(fmt.Sprintf("%s %s %s %s %dms", r.RemoteAddr, r.Method, r.URL, statusCode, time.Since(rw.StartTime).Milliseconds()))
|
||||
}
|
||||
|
||||
func debugLogDetails(r *http.Request, rw *logger.ResponseWriter) {
|
||||
var sb strings.Builder
|
||||
sb.WriteString(fmt.Sprintf("- Method/URL: %s %s\n", r.Method, r.URL))
|
||||
sb.WriteString(fmt.Sprintf(" Remote endpoint: %s\n", r.RemoteAddr))
|
||||
if rw.Hijacked {
|
||||
sb.WriteString(" Status code: <hijacked, probably a websocket>\n")
|
||||
} else {
|
||||
sb.WriteString(fmt.Sprintf(" Status code: %d\n", rw.StatusCode))
|
||||
}
|
||||
sb.WriteString(fmt.Sprintf(" Duration (ms): %d\n", time.Since(rw.StartTime).Milliseconds()))
|
||||
sb.WriteString(" Request headers: ")
|
||||
debugLogHeaders(&sb, r.Header)
|
||||
sb.WriteString(" Response headers: ")
|
||||
debugLogHeaders(&sb, rw.Header())
|
||||
logger.Info(sb.String())
|
||||
}
|
||||
|
||||
func debugLogHeaders(sb *strings.Builder, h http.Header) {
|
||||
keys := make([]string, 0, len(h))
|
||||
for key := range h {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
first := true
|
||||
for _, key := range keys {
|
||||
values := h[key]
|
||||
for _, value := range values {
|
||||
if !first {
|
||||
sb.WriteString(" ")
|
||||
} else {
|
||||
first = false
|
||||
}
|
||||
sb.WriteString(fmt.Sprintf("%s: %s\n", key, value))
|
||||
}
|
||||
}
|
||||
if first {
|
||||
sb.WriteRune('\n')
|
||||
}
|
||||
}
|
||||
|
||||
// The middleware configuration happens before anything, this middleware also applies to serving the swagger.json document.
|
||||
// So this is a good place to plug in a panic handling middleware, logger and metrics
|
||||
func setupGlobalMiddleware(handler http.Handler) http.Handler {
|
||||
@@ -229,6 +268,8 @@ func setupGlobalMiddleware(handler http.Handler) http.Handler {
|
||||
next = ContextMiddleware(next)
|
||||
// handle cookie or authorization header for session
|
||||
next = AuthenticationMiddleware(next)
|
||||
// handle debug logging
|
||||
next = DebugLogMiddleware(next)
|
||||
|
||||
sslHostFn := secure.SSLHostFunc(func(host string) string {
|
||||
xhost, err := xnet.ParseHost(host)
|
||||
@@ -257,10 +298,8 @@ func setupGlobalMiddleware(handler http.Handler) http.Handler {
|
||||
BrowserXssFilter: GetSecureBrowserXSSFilter(),
|
||||
ContentSecurityPolicy: GetSecureContentSecurityPolicy(),
|
||||
ContentSecurityPolicyReportOnly: GetSecureContentSecurityPolicyReportOnly(),
|
||||
PublicKey: GetSecurePublicKey(),
|
||||
ReferrerPolicy: GetSecureReferrerPolicy(),
|
||||
FeaturePolicy: GetSecureFeaturePolicy(),
|
||||
ExpectCTHeader: GetSecureExpectCTHeader(),
|
||||
IsDevelopment: false,
|
||||
}
|
||||
secureMiddleware := secure.New(secureOptions)
|
||||
@@ -316,6 +355,12 @@ func AuthenticationMiddleware(next http.Handler) http.Handler {
|
||||
|
||||
// FileServerMiddleware serves files from the static folder
|
||||
func FileServerMiddleware(next http.Handler) http.Handler {
|
||||
buildFs, err := fs.Sub(portal_ui.GetStaticAssets(), "build")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
spaFileHandler := wrapHandlerSinglePageApplication(requestBounce(http.FileServer(http.FS(buildFs))))
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Server", globalAppName) // do not add version information
|
||||
switch {
|
||||
@@ -324,11 +369,7 @@ func FileServerMiddleware(next http.Handler) http.Handler {
|
||||
case strings.HasPrefix(r.URL.Path, "/api"):
|
||||
next.ServeHTTP(w, r)
|
||||
default:
|
||||
buildFs, err := fs.Sub(portal_ui.GetStaticAssets(), "build")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
wrapHandlerSinglePageApplication(requestBounce(http.FileServer(http.FS(buildFs)))).ServeHTTP(w, r)
|
||||
spaFileHandler.ServeHTTP(w, r)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -427,13 +468,10 @@ func handleSPA(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
indexPageBytes = replaceLicense(indexPageBytes)
|
||||
|
||||
mimeType := mimedb.TypeByExtension(filepath.Ext(r.URL.Path))
|
||||
|
||||
if mimeType == "application/octet-stream" {
|
||||
mimeType = "text/html"
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", mimeType)
|
||||
// it's important to force "Content-Type: text/html", because a previous
|
||||
// handler may have already set the content-type to a different value.
|
||||
// (i.e. the FileServer when it detected that it couldn't find the file)
|
||||
w.Header().Set("Content-Type", "text/html")
|
||||
http.ServeContent(w, r, "index.html", time.Now(), bytes.NewReader(indexPageBytes))
|
||||
}
|
||||
|
||||
@@ -471,9 +509,9 @@ func configureServer(s *http.Server, _, _ string) {
|
||||
|
||||
func getSubPath() string {
|
||||
subPathOnce.Do(func() {
|
||||
subPath = parseSubPath(env.Get(SubPath, ""))
|
||||
cfgSubPath = parseSubPath(env.Get(SubPath, ""))
|
||||
})
|
||||
return subPath
|
||||
return cfgSubPath
|
||||
}
|
||||
|
||||
func parseSubPath(v string) string {
|
||||
@@ -483,7 +521,7 @@ func parseSubPath(v string) string {
|
||||
}
|
||||
// Replace all unnecessary `\` to `/`
|
||||
// also add pro-actively at the end.
|
||||
subPath = path.Clean(filepath.ToSlash(v))
|
||||
subPath := path.Clean(filepath.ToSlash(v))
|
||||
if !strings.HasPrefix(subPath, SlashSeparator) {
|
||||
subPath = SlashSeparator + subPath
|
||||
}
|
||||
@@ -510,8 +548,6 @@ func replaceBaseInIndex(indexPageBytes []byte, basePath string) []byte {
|
||||
|
||||
func replaceLicense(indexPageBytes []byte) []byte {
|
||||
indexPageStr := string(indexPageBytes)
|
||||
newPlan := fmt.Sprintf("<meta name=\"minio-license\" content=\"%s\" />", InstanceLicensePlan.String())
|
||||
indexPageStr = strings.Replace(indexPageStr, "<meta name=\"minio-license\" content=\"apgl\"/>", newPlan, 1)
|
||||
indexPageBytes = []byte(indexPageStr)
|
||||
return indexPageBytes
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package restapi
|
||||
package api
|
||||
|
||||
import (
|
||||
"os"
|
||||
@@ -70,7 +70,7 @@ func Test_parseSubPath(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Run(tt.name, func(_ *testing.T) {
|
||||
assert.Equalf(t, tt.want, parseSubPath(tt.args.v), "parseSubPath(%v)", tt.args.v)
|
||||
})
|
||||
}
|
||||
@@ -115,7 +115,7 @@ func Test_getSubPath(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Run(tt.name, func(_ *testing.T) {
|
||||
t.Setenv(SubPath, tt.args.envValue)
|
||||
defer os.Unsetenv(SubPath)
|
||||
subPathOnce = sync.Once{}
|
||||
@@ -14,13 +14,12 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package restapi
|
||||
package api
|
||||
|
||||
// list of all console environment constants
|
||||
const (
|
||||
// Constants for common configuration
|
||||
ConsoleMinIOServer = "CONSOLE_MINIO_SERVER"
|
||||
ConsoleSubnetProxy = "CONSOLE_SUBNET_PROXY"
|
||||
ConsoleMinIORegion = "CONSOLE_MINIO_REGION"
|
||||
ConsoleHostname = "CONSOLE_HOSTNAME"
|
||||
ConsolePort = "CONSOLE_PORT"
|
||||
@@ -40,21 +39,17 @@ const (
|
||||
ConsoleSecureSTSPreload = "CONSOLE_SECURE_STS_PRELOAD"
|
||||
ConsoleSecureTLSRedirect = "CONSOLE_SECURE_TLS_REDIRECT"
|
||||
ConsoleSecureTLSHost = "CONSOLE_SECURE_TLS_HOST"
|
||||
ConsoleSecureTLSTemporaryRedirect = "CONSOLE_SECURE_TLS_TEMPORARY_REDIRECT"
|
||||
ConsoleSecureForceSTSHeader = "CONSOLE_SECURE_FORCE_STS_HEADER"
|
||||
ConsoleSecurePublicKey = "CONSOLE_SECURE_PUBLIC_KEY"
|
||||
ConsoleSecureReferrerPolicy = "CONSOLE_SECURE_REFERRER_POLICY"
|
||||
ConsoleSecureFeaturePolicy = "CONSOLE_SECURE_FEATURE_POLICY"
|
||||
ConsoleSecureExpectCTHeader = "CONSOLE_SECURE_EXPECT_CT_HEADER"
|
||||
PrometheusURL = "CONSOLE_PROMETHEUS_URL"
|
||||
PrometheusJobID = "CONSOLE_PROMETHEUS_JOB_ID"
|
||||
PrometheusExtraLabels = "CONSOLE_PROMETHEUS_EXTRA_LABELS"
|
||||
ConsoleLogQueryURL = "CONSOLE_LOG_QUERY_URL"
|
||||
ConsoleLogQueryAuthToken = "CONSOLE_LOG_QUERY_AUTH_TOKEN"
|
||||
ConsoleMaxConcurrentUploads = "CONSOLE_MAX_CONCURRENT_UPLOADS"
|
||||
ConsoleMaxConcurrentDownloads = "CONSOLE_MAX_CONCURRENT_DOWNLOADS"
|
||||
ConsoleDevMode = "CONSOLE_DEV_MODE"
|
||||
ConsoleAnimatedLogin = "CONSOLE_ANIMATED_LOGIN"
|
||||
ConsoleBrowserRedirectURL = "CONSOLE_BROWSER_REDIRECT_URL"
|
||||
LogSearchQueryAuthToken = "LOGSEARCH_QUERY_AUTH_TOKEN"
|
||||
SlashSeparator = "/"
|
||||
LocalAddress = "127.0.0.1"
|
||||
)
|
||||
556
api/custom-server.go
Normal file
556
api/custom-server.go
Normal file
@@ -0,0 +1,556 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2023 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/go-openapi/runtime/flagext"
|
||||
"github.com/go-openapi/swag"
|
||||
flags "github.com/jessevdk/go-flags"
|
||||
"golang.org/x/net/netutil"
|
||||
|
||||
"github.com/minio/console/api/operations"
|
||||
)
|
||||
|
||||
const (
|
||||
schemeHTTP = "http"
|
||||
schemeHTTPS = "https"
|
||||
schemeUnix = "unix"
|
||||
)
|
||||
|
||||
var defaultSchemes []string
|
||||
|
||||
func init() {
|
||||
defaultSchemes = []string{
|
||||
schemeHTTP,
|
||||
}
|
||||
}
|
||||
|
||||
// NewServer creates a new api console server but does not configure it
|
||||
func NewServer(api *operations.ConsoleAPI) *Server {
|
||||
s := new(Server)
|
||||
|
||||
s.shutdown = make(chan struct{})
|
||||
s.api = api
|
||||
s.interrupt = make(chan os.Signal, 1)
|
||||
return s
|
||||
}
|
||||
|
||||
// ConfigureAPI configures the API and handlers.
|
||||
func (s *Server) ConfigureAPI() {
|
||||
if s.api != nil {
|
||||
s.handler = configureAPI(s.api)
|
||||
}
|
||||
}
|
||||
|
||||
// ConfigureFlags configures the additional flags defined by the handlers. Needs to be called before the parser.Parse
|
||||
func (s *Server) ConfigureFlags() {
|
||||
if s.api != nil {
|
||||
configureFlags(s.api)
|
||||
}
|
||||
}
|
||||
|
||||
// Server for the console API
|
||||
type Server struct {
|
||||
EnabledListeners []string `long:"scheme" description:"the listeners to enable, this can be repeated and defaults to the schemes in the swagger spec"`
|
||||
CleanupTimeout time.Duration `long:"cleanup-timeout" description:"grace period for which to wait before killing idle connections" default:"10s"`
|
||||
GracefulTimeout time.Duration `long:"graceful-timeout" description:"grace period for which to wait before shutting down the server" default:"15s"`
|
||||
MaxHeaderSize flagext.ByteSize `long:"max-header-size" description:"controls the maximum number of bytes the server will read parsing the request header's keys and values, including the request line. It does not limit the size of the request body." default:"1MiB"`
|
||||
|
||||
SocketPath flags.Filename `long:"socket-path" description:"the unix socket to listen on" default:"/var/run/console.sock"`
|
||||
domainSocketL net.Listener
|
||||
|
||||
Host string `long:"host" description:"the IP to listen on" default:"localhost" env:"HOST"`
|
||||
Port int `long:"port" description:"the port to listen on for insecure connections, defaults to a random value" env:"PORT"`
|
||||
ListenLimit int `long:"listen-limit" description:"limit the number of outstanding requests"`
|
||||
KeepAlive time.Duration `long:"keep-alive" description:"sets the TCP keep-alive timeouts on accepted connections. It prunes dead TCP connections ( e.g. closing laptop mid-download)" default:"3m"`
|
||||
ReadTimeout time.Duration `long:"read-timeout" description:"maximum duration before timing out read of the request" default:"30s"`
|
||||
WriteTimeout time.Duration `long:"write-timeout" description:"maximum duration before timing out write of the response" default:"60s"`
|
||||
httpServerL []net.Listener
|
||||
|
||||
TLSHost string `long:"tls-host" description:"the IP to listen on for tls, when not specified it's the same as --host" env:"TLS_HOST"`
|
||||
TLSPort int `long:"tls-port" description:"the port to listen on for secure connections, defaults to a random value" env:"TLS_PORT"`
|
||||
TLSCertificate flags.Filename `long:"tls-certificate" description:"the certificate to use for secure connections" env:"TLS_CERTIFICATE"`
|
||||
TLSCertificateKey flags.Filename `long:"tls-key" description:"the private key to use for secure connections" env:"TLS_PRIVATE_KEY"`
|
||||
TLSCACertificate flags.Filename `long:"tls-ca" description:"the certificate authority file to be used with mutual tls auth" env:"TLS_CA_CERTIFICATE"`
|
||||
TLSListenLimit int `long:"tls-listen-limit" description:"limit the number of outstanding requests"`
|
||||
TLSKeepAlive time.Duration `long:"tls-keep-alive" description:"sets the TCP keep-alive timeouts on accepted connections. It prunes dead TCP connections ( e.g. closing laptop mid-download)"`
|
||||
TLSReadTimeout time.Duration `long:"tls-read-timeout" description:"maximum duration before timing out read of the request"`
|
||||
TLSWriteTimeout time.Duration `long:"tls-write-timeout" description:"maximum duration before timing out write of the response"`
|
||||
httpsServerL []net.Listener
|
||||
|
||||
api *operations.ConsoleAPI
|
||||
handler http.Handler
|
||||
hasListeners bool
|
||||
shutdown chan struct{}
|
||||
shuttingDown int32
|
||||
interrupted bool
|
||||
interrupt chan os.Signal
|
||||
}
|
||||
|
||||
// Logf logs message either via defined user logger or via system one if no user logger is defined.
|
||||
func (s *Server) Logf(f string, args ...interface{}) {
|
||||
if s.api != nil && s.api.Logger != nil {
|
||||
s.api.Logger(f, args...)
|
||||
} else {
|
||||
log.Printf(f, args...)
|
||||
}
|
||||
}
|
||||
|
||||
// Fatalf logs message either via defined user logger or via system one if no user logger is defined.
|
||||
// Exits with non-zero status after printing
|
||||
func (s *Server) Fatalf(f string, args ...interface{}) {
|
||||
if s.api != nil && s.api.Logger != nil {
|
||||
s.api.Logger(f, args...)
|
||||
os.Exit(1)
|
||||
}
|
||||
log.Fatalf(f, args...)
|
||||
}
|
||||
|
||||
// SetAPI configures the server with the specified API. Needs to be called before Serve
|
||||
func (s *Server) SetAPI(api *operations.ConsoleAPI) {
|
||||
if api == nil {
|
||||
s.api = nil
|
||||
s.handler = nil
|
||||
return
|
||||
}
|
||||
|
||||
s.api = api
|
||||
s.handler = configureAPI(api)
|
||||
}
|
||||
|
||||
func (s *Server) hasScheme(scheme string) bool {
|
||||
schemes := s.EnabledListeners
|
||||
if len(schemes) == 0 {
|
||||
schemes = defaultSchemes
|
||||
}
|
||||
|
||||
for _, v := range schemes {
|
||||
if v == scheme {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Serve the api
|
||||
func (s *Server) Serve() (err error) {
|
||||
if !s.hasListeners {
|
||||
if err = s.Listen(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// set default handler, if none is set
|
||||
if s.handler == nil {
|
||||
if s.api == nil {
|
||||
return errors.New("can't create the default handler, as no api is set")
|
||||
}
|
||||
|
||||
s.SetHandler(s.api.Serve(nil))
|
||||
}
|
||||
|
||||
wg := new(sync.WaitGroup)
|
||||
once := new(sync.Once)
|
||||
signalNotify(s.interrupt)
|
||||
go handleInterrupt(once, s)
|
||||
|
||||
servers := []*http.Server{}
|
||||
|
||||
if s.hasScheme(schemeUnix) {
|
||||
domainSocket := new(http.Server)
|
||||
domainSocket.MaxHeaderBytes = int(s.MaxHeaderSize)
|
||||
domainSocket.Handler = s.handler
|
||||
if int64(s.CleanupTimeout) > 0 {
|
||||
domainSocket.IdleTimeout = s.CleanupTimeout
|
||||
}
|
||||
|
||||
configureServer(domainSocket, "unix", string(s.SocketPath))
|
||||
|
||||
servers = append(servers, domainSocket)
|
||||
wg.Add(1)
|
||||
s.Logf("Serving console at unix://%s", s.SocketPath)
|
||||
go func(l net.Listener) {
|
||||
defer wg.Done()
|
||||
if err := domainSocket.Serve(l); err != nil && err != http.ErrServerClosed {
|
||||
s.Fatalf("%v", err)
|
||||
}
|
||||
s.Logf("Stopped serving console at unix://%s", s.SocketPath)
|
||||
}(s.domainSocketL)
|
||||
}
|
||||
|
||||
if s.hasScheme(schemeHTTP) {
|
||||
httpServer := new(http.Server)
|
||||
httpServer.MaxHeaderBytes = int(s.MaxHeaderSize)
|
||||
httpServer.ReadTimeout = s.ReadTimeout
|
||||
httpServer.WriteTimeout = s.WriteTimeout
|
||||
httpServer.SetKeepAlivesEnabled(int64(s.KeepAlive) > 0)
|
||||
if s.ListenLimit > 0 {
|
||||
for i := range s.httpServerL {
|
||||
s.httpServerL[i] = netutil.LimitListener(s.httpServerL[i], s.ListenLimit)
|
||||
}
|
||||
}
|
||||
|
||||
if int64(s.CleanupTimeout) > 0 {
|
||||
httpServer.IdleTimeout = s.CleanupTimeout
|
||||
}
|
||||
|
||||
httpServer.Handler = s.handler
|
||||
|
||||
configureServer(httpServer, "http", s.httpServerL[0].Addr().String())
|
||||
|
||||
servers = append(servers, httpServer)
|
||||
s.Logf("Serving console at http://%s", s.httpServerL[0].Addr())
|
||||
for i := range s.httpServerL {
|
||||
wg.Add(1)
|
||||
go func(l net.Listener) {
|
||||
defer wg.Done()
|
||||
if err := httpServer.Serve(l); err != nil && err != http.ErrServerClosed {
|
||||
s.Fatalf("%v", err)
|
||||
}
|
||||
s.Logf("Stopped serving console at http://%s", l.Addr())
|
||||
}(s.httpServerL[i])
|
||||
}
|
||||
}
|
||||
|
||||
if s.hasScheme(schemeHTTPS) {
|
||||
httpsServer := new(http.Server)
|
||||
httpsServer.MaxHeaderBytes = int(s.MaxHeaderSize)
|
||||
httpsServer.ReadTimeout = s.TLSReadTimeout
|
||||
httpsServer.WriteTimeout = s.TLSWriteTimeout
|
||||
httpsServer.SetKeepAlivesEnabled(int64(s.TLSKeepAlive) > 0)
|
||||
if s.TLSListenLimit > 0 {
|
||||
for i := range s.httpsServerL {
|
||||
s.httpsServerL[i] = netutil.LimitListener(s.httpsServerL[i], s.TLSListenLimit)
|
||||
}
|
||||
}
|
||||
if int64(s.CleanupTimeout) > 0 {
|
||||
httpsServer.IdleTimeout = s.CleanupTimeout
|
||||
}
|
||||
httpsServer.Handler = s.handler
|
||||
|
||||
// Inspired by https://blog.bracebin.com/achieving-perfect-ssl-labs-score-with-go
|
||||
httpsServer.TLSConfig = &tls.Config{
|
||||
// Causes servers to use Go's default ciphersuite preferences,
|
||||
// which are tuned to avoid attacks. Does nothing on clients.
|
||||
PreferServerCipherSuites: true,
|
||||
// Only use curves which have assembly implementations
|
||||
// https://github.com/golang/go/tree/master/src/crypto/elliptic
|
||||
CurvePreferences: []tls.CurveID{tls.CurveP256},
|
||||
// Use modern tls mode https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility
|
||||
NextProtos: []string{"h2", "http/1.1"},
|
||||
// https://www.owasp.org/index.php/Transport_Layer_Protection_Cheat_Sheet#Rule_-_Only_Support_Strong_Protocols
|
||||
MinVersion: tls.VersionTLS12,
|
||||
// These ciphersuites support Forward Secrecy: https://en.wikipedia.org/wiki/Forward_secrecy
|
||||
CipherSuites: []uint16{
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
|
||||
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
|
||||
},
|
||||
}
|
||||
|
||||
// build standard config from server options
|
||||
if s.TLSCertificate != "" && s.TLSCertificateKey != "" {
|
||||
httpsServer.TLSConfig.Certificates = make([]tls.Certificate, 1)
|
||||
httpsServer.TLSConfig.Certificates[0], err = tls.LoadX509KeyPair(string(s.TLSCertificate), string(s.TLSCertificateKey))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if s.TLSCACertificate != "" {
|
||||
// include specified CA certificate
|
||||
caCert, caCertErr := os.ReadFile(string(s.TLSCACertificate))
|
||||
if caCertErr != nil {
|
||||
return caCertErr
|
||||
}
|
||||
caCertPool := x509.NewCertPool()
|
||||
ok := caCertPool.AppendCertsFromPEM(caCert)
|
||||
if !ok {
|
||||
return fmt.Errorf("cannot parse CA certificate")
|
||||
}
|
||||
httpsServer.TLSConfig.ClientCAs = caCertPool
|
||||
httpsServer.TLSConfig.ClientAuth = tls.RequireAndVerifyClientCert
|
||||
}
|
||||
|
||||
// call custom TLS configurator
|
||||
configureTLS(httpsServer.TLSConfig)
|
||||
|
||||
if len(httpsServer.TLSConfig.Certificates) == 0 && httpsServer.TLSConfig.GetCertificate == nil {
|
||||
// after standard and custom config are passed, this ends up with no certificate
|
||||
if s.TLSCertificate == "" {
|
||||
if s.TLSCertificateKey == "" {
|
||||
s.Fatalf("the required flags `--tls-certificate` and `--tls-key` were not specified")
|
||||
}
|
||||
s.Fatalf("the required flag `--tls-certificate` was not specified")
|
||||
}
|
||||
if s.TLSCertificateKey == "" {
|
||||
s.Fatalf("the required flag `--tls-key` was not specified")
|
||||
}
|
||||
// this happens with a wrong custom TLS configurator
|
||||
s.Fatalf("no certificate was configured for TLS")
|
||||
}
|
||||
|
||||
configureServer(httpsServer, "https", s.httpsServerL[0].Addr().String())
|
||||
|
||||
servers = append(servers, httpsServer)
|
||||
s.Logf("Serving console at https://%s", s.httpsServerL[0].Addr())
|
||||
for i := range s.httpsServerL {
|
||||
wg.Add(1)
|
||||
go func(l net.Listener) {
|
||||
defer wg.Done()
|
||||
if err := httpsServer.Serve(l); err != nil && err != http.ErrServerClosed {
|
||||
s.Fatalf("%v", err)
|
||||
}
|
||||
s.Logf("Stopped serving console at https://%s", l.Addr())
|
||||
}(tls.NewListener(s.httpsServerL[i], httpsServer.TLSConfig))
|
||||
}
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
go s.handleShutdown(wg, &servers)
|
||||
|
||||
wg.Wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Listen creates the listeners for the server
|
||||
func (s *Server) Listen() error {
|
||||
if s.hasListeners { // already done this
|
||||
return nil
|
||||
}
|
||||
|
||||
if s.hasScheme(schemeHTTPS) {
|
||||
// Use http host if https host wasn't defined
|
||||
if s.TLSHost == "" {
|
||||
s.TLSHost = s.Host
|
||||
}
|
||||
// Use http listen limit if https listen limit wasn't defined
|
||||
if s.TLSListenLimit == 0 {
|
||||
s.TLSListenLimit = s.ListenLimit
|
||||
}
|
||||
// Use http tcp keep alive if https tcp keep alive wasn't defined
|
||||
if int64(s.TLSKeepAlive) == 0 {
|
||||
s.TLSKeepAlive = s.KeepAlive
|
||||
}
|
||||
// Use http read timeout if https read timeout wasn't defined
|
||||
if int64(s.TLSReadTimeout) == 0 {
|
||||
s.TLSReadTimeout = s.ReadTimeout
|
||||
}
|
||||
// Use http write timeout if https write timeout wasn't defined
|
||||
if int64(s.TLSWriteTimeout) == 0 {
|
||||
s.TLSWriteTimeout = s.WriteTimeout
|
||||
}
|
||||
}
|
||||
|
||||
if s.hasScheme(schemeUnix) {
|
||||
domSockListener, err := net.Listen("unix", string(s.SocketPath))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.domainSocketL = domSockListener
|
||||
}
|
||||
|
||||
lookup := func(addr string) []net.IP {
|
||||
ips, err := net.LookupIP(addr)
|
||||
if err == nil {
|
||||
return ips
|
||||
}
|
||||
return []net.IP{net.ParseIP(addr)}
|
||||
}
|
||||
|
||||
convert := func(ip net.IP) (string, string) {
|
||||
if ip == nil {
|
||||
return "", "tcp"
|
||||
}
|
||||
proto := "tcp4"
|
||||
if ip.To4() == nil {
|
||||
proto = "tcp6"
|
||||
}
|
||||
return ip.String(), proto
|
||||
}
|
||||
|
||||
if s.hasScheme(schemeHTTP) {
|
||||
for _, ip := range lookup(s.Host) {
|
||||
host, proto := convert(ip)
|
||||
listener, err := net.Listen(proto, net.JoinHostPort(host, strconv.Itoa(s.Port)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if s.Host == "" || s.Port == 0 {
|
||||
h, p, err := swag.SplitHostPort(listener.Addr().String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.Host = h
|
||||
s.Port = p
|
||||
}
|
||||
s.httpServerL = append(s.httpServerL, listener)
|
||||
}
|
||||
}
|
||||
|
||||
if s.hasScheme(schemeHTTPS) {
|
||||
for _, ip := range lookup(s.TLSHost) {
|
||||
host, proto := convert(ip)
|
||||
tlsListener, err := net.Listen(proto, net.JoinHostPort(host, strconv.Itoa(s.TLSPort)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if s.TLSHost == "" || s.TLSPort == 0 {
|
||||
sh, sp, err := swag.SplitHostPort(tlsListener.Addr().String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.TLSHost = sh
|
||||
s.TLSPort = sp
|
||||
}
|
||||
s.httpsServerL = append(s.httpsServerL, tlsListener)
|
||||
}
|
||||
}
|
||||
|
||||
s.hasListeners = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// Shutdown server and clean up resources
|
||||
func (s *Server) Shutdown() error {
|
||||
if atomic.CompareAndSwapInt32(&s.shuttingDown, 0, 1) {
|
||||
close(s.shutdown)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) handleShutdown(wg *sync.WaitGroup, serversPtr *[]*http.Server) {
|
||||
// wg.Done must occur last, after s.api.ServerShutdown()
|
||||
// (to preserve old behavior)
|
||||
defer wg.Done()
|
||||
|
||||
<-s.shutdown
|
||||
|
||||
servers := *serversPtr
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.TODO(), s.GracefulTimeout)
|
||||
defer cancel()
|
||||
|
||||
// first execute the pre-shutdown hook
|
||||
s.api.PreServerShutdown()
|
||||
|
||||
shutdownChan := make(chan bool)
|
||||
for i := range servers {
|
||||
server := servers[i]
|
||||
go func() {
|
||||
var success bool
|
||||
defer func() {
|
||||
shutdownChan <- success
|
||||
}()
|
||||
if err := server.Shutdown(ctx); err != nil {
|
||||
// Error from closing listeners, or context timeout:
|
||||
s.Logf("HTTP server Shutdown: %v", err)
|
||||
} else {
|
||||
success = true
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Wait until all listeners have successfully shut down before calling ServerShutdown
|
||||
success := true
|
||||
for range servers {
|
||||
success = success && <-shutdownChan
|
||||
}
|
||||
if success {
|
||||
s.api.ServerShutdown()
|
||||
}
|
||||
}
|
||||
|
||||
// GetHandler returns a handler useful for testing
|
||||
func (s *Server) GetHandler() http.Handler {
|
||||
return s.handler
|
||||
}
|
||||
|
||||
// SetHandler allows for setting a http handler on this server
|
||||
func (s *Server) SetHandler(handler http.Handler) {
|
||||
s.handler = handler
|
||||
}
|
||||
|
||||
// UnixListener returns the domain socket listener
|
||||
func (s *Server) UnixListener() (net.Listener, error) {
|
||||
if !s.hasListeners {
|
||||
if err := s.Listen(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return s.domainSocketL, nil
|
||||
}
|
||||
|
||||
// HTTPListener returns the http listener
|
||||
func (s *Server) HTTPListener() ([]net.Listener, error) {
|
||||
if !s.hasListeners {
|
||||
if err := s.Listen(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return s.httpServerL, nil
|
||||
}
|
||||
|
||||
// TLSListener returns the https listener
|
||||
func (s *Server) TLSListener() ([]net.Listener, error) {
|
||||
if !s.hasListeners {
|
||||
if err := s.Listen(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return s.httpsServerL, nil
|
||||
}
|
||||
|
||||
func handleInterrupt(once *sync.Once, s *Server) {
|
||||
once.Do(func() {
|
||||
for range s.interrupt {
|
||||
if s.interrupted {
|
||||
s.Logf("Server already shutting down")
|
||||
continue
|
||||
}
|
||||
s.interrupted = true
|
||||
s.Logf("Shutting down... ")
|
||||
if err := s.Shutdown(); err != nil {
|
||||
s.Logf("HTTP server Shutdown: %v", err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func signalNotify(interrupt chan<- os.Signal) {
|
||||
signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM)
|
||||
}
|
||||
@@ -16,7 +16,7 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
// Package restapi MinIO Console Server
|
||||
// Package api MinIO Console Server
|
||||
//
|
||||
// Schemes:
|
||||
// http
|
||||
@@ -30,9 +30,8 @@
|
||||
// - multipart/form-data
|
||||
//
|
||||
// Produces:
|
||||
// - application/zip
|
||||
// - application/octet-stream
|
||||
// - application/json
|
||||
//
|
||||
// swagger:meta
|
||||
package restapi
|
||||
package api
|
||||
3677
api/embedded_spec.go
Normal file
3677
api/embedded_spec.go
Normal file
File diff suppressed because it is too large
Load Diff
@@ -14,22 +14,22 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package restapi
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/minio/console/models"
|
||||
"github.com/minio/madmin-go/v2"
|
||||
"github.com/minio/minio-go/v7"
|
||||
|
||||
"github.com/minio/console/models"
|
||||
"github.com/minio/madmin-go/v3"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrDefault = errors.New("an error occurred, please try again")
|
||||
ErrInvalidLogin = errors.New("invalid Login")
|
||||
ErrInvalidLogin = errors.New("invalid login")
|
||||
ErrForbidden = errors.New("403 Forbidden")
|
||||
ErrBadRequest = errors.New("400 Bad Request")
|
||||
ErrFileTooLarge = errors.New("413 File too Large")
|
||||
@@ -43,7 +43,6 @@ var (
|
||||
ErrGroupNameNotInRequest = errors.New("error group name not in request")
|
||||
ErrPolicyNameNotInRequest = errors.New("error policy name not in request")
|
||||
ErrPolicyBodyNotInRequest = errors.New("error policy body not in request")
|
||||
ErrPolicyNameContainsSpace = errors.New("error policy name cannot contain spaces")
|
||||
ErrInvalidEncryptionAlgorithm = errors.New("error invalid encryption algorithm")
|
||||
ErrSSENotConfigured = errors.New("error server side encryption configuration not found")
|
||||
ErrBucketLifeCycleNotConfigured = errors.New("error bucket life cycle configuration not found")
|
||||
@@ -53,6 +52,7 @@ var (
|
||||
ErrAvoidSelfAccountDelete = errors.New("logged in user cannot be deleted by itself")
|
||||
ErrAccessDenied = errors.New("access denied")
|
||||
ErrOauth2Provider = errors.New("unable to contact configured identity provider")
|
||||
ErrOauth2Login = errors.New("unable to login using configured identity provider")
|
||||
ErrNonUniqueAccessKey = errors.New("access key already in use")
|
||||
ErrRemoteTierExists = errors.New("specified remote tier already exists")
|
||||
ErrRemoteTierNotFound = errors.New("specified remote tier was not found")
|
||||
@@ -71,17 +71,25 @@ var (
|
||||
ErrEncryptionConfigNotFound = errors.New("encryption configuration not found")
|
||||
ErrPolicyNotFound = errors.New("policy does not exist")
|
||||
ErrLoginNotAllowed = errors.New("login not allowed")
|
||||
ErrSubnetUploadFail = errors.New("Subnet upload failed")
|
||||
ErrHealthReportFail = errors.New("failure to generate Health report")
|
||||
ErrNetworkError = errors.New("unable to login due to network error")
|
||||
)
|
||||
|
||||
type CodedAPIError struct {
|
||||
Code int
|
||||
APIError *models.APIError
|
||||
}
|
||||
|
||||
// ErrorWithContext :
|
||||
func ErrorWithContext(ctx context.Context, err ...interface{}) *models.Error {
|
||||
errorCode := int32(500)
|
||||
func ErrorWithContext(ctx context.Context, err ...interface{}) *CodedAPIError {
|
||||
errorCode := 500
|
||||
errorMessage := ErrDefault.Error()
|
||||
var detailedMessage string
|
||||
var err1 error
|
||||
var exists bool
|
||||
if len(err) > 0 {
|
||||
if err1, exists = err[0].(error); exists {
|
||||
detailedMessage = err1.Error()
|
||||
var lastError error
|
||||
if len(err) > 1 {
|
||||
if err2, lastExists := err[1].(error); lastExists {
|
||||
@@ -99,15 +107,27 @@ func ErrorWithContext(ctx context.Context, err ...interface{}) *models.Error {
|
||||
errorMessage = ErrNotFound.Error()
|
||||
}
|
||||
if errors.Is(err1, ErrInvalidLogin) {
|
||||
detailedMessage = ""
|
||||
errorCode = 401
|
||||
errorMessage = ErrInvalidLogin.Error()
|
||||
}
|
||||
if errors.Is(err1, ErrNetworkError) {
|
||||
detailedMessage = ""
|
||||
errorCode = 503
|
||||
errorMessage = ErrNetworkError.Error()
|
||||
}
|
||||
if strings.Contains(strings.ToLower(err1.Error()), ErrAccessDenied.Error()) {
|
||||
errorCode = 403
|
||||
errorMessage = err1.Error()
|
||||
}
|
||||
// If the last error is ErrInvalidLogin, this is a login failure
|
||||
if errors.Is(lastError, ErrInvalidLogin) {
|
||||
detailedMessage = ""
|
||||
errorCode = 401
|
||||
errorMessage = err1.Error()
|
||||
}
|
||||
if strings.Contains(err1.Error(), ErrLoginNotAllowed.Error()) {
|
||||
detailedMessage = ""
|
||||
errorCode = 400
|
||||
errorMessage = ErrLoginNotAllowed.Error()
|
||||
}
|
||||
@@ -140,10 +160,6 @@ func ErrorWithContext(ctx context.Context, err ...interface{}) *models.Error {
|
||||
errorCode = 400
|
||||
errorMessage = ErrPolicyBodyNotInRequest.Error()
|
||||
}
|
||||
if errors.Is(err1, ErrPolicyNameContainsSpace) {
|
||||
errorCode = 400
|
||||
errorMessage = ErrPolicyNameContainsSpace.Error()
|
||||
}
|
||||
// console invalid session errors
|
||||
if errors.Is(err1, ErrInvalidSession) {
|
||||
errorCode = 401
|
||||
@@ -201,6 +217,7 @@ func ErrorWithContext(ctx context.Context, err ...interface{}) *models.Error {
|
||||
errorMessage = ErrAccessDenied.Error()
|
||||
}
|
||||
if madmin.ToErrorResponse(err1).Code == "InvalidAccessKeyId" {
|
||||
|
||||
errorCode = 401
|
||||
errorMessage = ErrInvalidSession.Error()
|
||||
}
|
||||
@@ -240,6 +257,7 @@ func ErrorWithContext(ctx context.Context, err ...interface{}) *models.Error {
|
||||
errorCode = 400
|
||||
errorMessage = "Bucket already exists"
|
||||
}
|
||||
|
||||
LogError("ErrorWithContext:%v", err...)
|
||||
LogIf(ctx, err1, err...)
|
||||
}
|
||||
@@ -250,11 +268,11 @@ func ErrorWithContext(ctx context.Context, err ...interface{}) *models.Error {
|
||||
}
|
||||
}
|
||||
}
|
||||
return &models.Error{Code: errorCode, Message: swag.String(errorMessage), DetailedMessage: swag.String(err1.Error())}
|
||||
return &CodedAPIError{Code: errorCode, APIError: &models.APIError{Message: errorMessage, DetailedMessage: detailedMessage}}
|
||||
}
|
||||
|
||||
// Error receives an errors object and parse it against k8sErrors, returns the right errors code paired with a generic errors message
|
||||
func Error(err ...interface{}) *models.Error {
|
||||
func Error(err ...interface{}) *CodedAPIError {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
return ErrorWithContext(ctx, err...)
|
||||
@@ -14,14 +14,13 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package restapi
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/minio/console/models"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@@ -34,7 +33,7 @@ func TestError(t *testing.T) {
|
||||
type testError struct {
|
||||
name string
|
||||
args args
|
||||
want *models.Error
|
||||
want *CodedAPIError
|
||||
}
|
||||
|
||||
var tests []testError
|
||||
@@ -45,37 +44,37 @@ func TestError(t *testing.T) {
|
||||
}
|
||||
|
||||
appErrors := map[string]expectedError{
|
||||
"ErrDefault": {code: 500, err: ErrDefault},
|
||||
"ErrInvalidLogin": {code: 401, err: ErrInvalidLogin},
|
||||
"ErrForbidden": {code: 403, err: ErrForbidden},
|
||||
"ErrFileTooLarge": {code: 413, err: ErrFileTooLarge},
|
||||
"ErrInvalidSession": {code: 401, err: ErrInvalidSession},
|
||||
"ErrNotFound": {code: 404, err: ErrNotFound},
|
||||
"ErrGroupAlreadyExists": {code: 400, err: ErrGroupAlreadyExists},
|
||||
"ErrInvalidErasureCodingValue": {code: 400, err: ErrInvalidErasureCodingValue},
|
||||
"ErrBucketBodyNotInRequest": {code: 400, err: ErrBucketBodyNotInRequest},
|
||||
"ErrBucketNameNotInRequest": {code: 400, err: ErrBucketNameNotInRequest},
|
||||
"ErrGroupBodyNotInRequest": {code: 400, err: ErrGroupBodyNotInRequest},
|
||||
"ErrGroupNameNotInRequest": {code: 400, err: ErrGroupNameNotInRequest},
|
||||
"ErrPolicyNameNotInRequest": {code: 400, err: ErrPolicyNameNotInRequest},
|
||||
"ErrPolicyBodyNotInRequest": {code: 400, err: ErrPolicyBodyNotInRequest},
|
||||
"ErrInvalidEncryptionAlgorithm": {code: 500, err: ErrInvalidEncryptionAlgorithm},
|
||||
"ErrSSENotConfigured": {code: 404, err: ErrSSENotConfigured},
|
||||
"ErrBucketLifeCycleNotConfigured": {code: 404, err: ErrBucketLifeCycleNotConfigured},
|
||||
"ErrChangePassword": {code: 403, err: ErrChangePassword},
|
||||
"ErrInvalidLicense": {code: 404, err: ErrInvalidLicense},
|
||||
"ErrLicenseNotFound": {code: 404, err: ErrLicenseNotFound},
|
||||
"ErrAvoidSelfAccountDelete": {code: 403, err: ErrAvoidSelfAccountDelete},
|
||||
"ErrAccessDenied": {code: 403, err: ErrAccessDenied},
|
||||
"ErrDefault": {code: 500, err: ErrDefault},
|
||||
|
||||
"ErrForbidden": {code: 403, err: ErrForbidden},
|
||||
"ErrFileTooLarge": {code: 413, err: ErrFileTooLarge},
|
||||
"ErrInvalidSession": {code: 401, err: ErrInvalidSession},
|
||||
"ErrNotFound": {code: 404, err: ErrNotFound},
|
||||
"ErrGroupAlreadyExists": {code: 400, err: ErrGroupAlreadyExists},
|
||||
"ErrInvalidErasureCodingValue": {code: 400, err: ErrInvalidErasureCodingValue},
|
||||
"ErrBucketBodyNotInRequest": {code: 400, err: ErrBucketBodyNotInRequest},
|
||||
"ErrBucketNameNotInRequest": {code: 400, err: ErrBucketNameNotInRequest},
|
||||
"ErrGroupBodyNotInRequest": {code: 400, err: ErrGroupBodyNotInRequest},
|
||||
"ErrGroupNameNotInRequest": {code: 400, err: ErrGroupNameNotInRequest},
|
||||
"ErrPolicyNameNotInRequest": {code: 400, err: ErrPolicyNameNotInRequest},
|
||||
"ErrPolicyBodyNotInRequest": {code: 400, err: ErrPolicyBodyNotInRequest},
|
||||
"ErrInvalidEncryptionAlgorithm": {code: 500, err: ErrInvalidEncryptionAlgorithm},
|
||||
"ErrSSENotConfigured": {code: 404, err: ErrSSENotConfigured},
|
||||
"ErrChangePassword": {code: 403, err: ErrChangePassword},
|
||||
"ErrInvalidLicense": {code: 404, err: ErrInvalidLicense},
|
||||
"ErrLicenseNotFound": {code: 404, err: ErrLicenseNotFound},
|
||||
"ErrAvoidSelfAccountDelete": {code: 403, err: ErrAvoidSelfAccountDelete},
|
||||
|
||||
"ErrNonUniqueAccessKey": {code: 500, err: ErrNonUniqueAccessKey},
|
||||
"ErrRemoteTierExists": {code: 400, err: ErrRemoteTierExists},
|
||||
"ErrRemoteTierNotFound": {code: 400, err: ErrRemoteTierNotFound},
|
||||
"ErrRemoteTierUppercase": {code: 400, err: ErrRemoteTierUppercase},
|
||||
"ErrRemoteTierBucketNotFound": {code: 400, err: ErrRemoteTierBucketNotFound},
|
||||
"ErrRemoteInvalidCredentials": {code: 403, err: ErrRemoteInvalidCredentials},
|
||||
"ErrTooFewNodes": {code: 500, err: ErrTooFewNodes},
|
||||
"ErrUnableToGetTenantUsage": {code: 500, err: ErrUnableToGetTenantUsage},
|
||||
"ErrTooManyNodes": {code: 500, err: ErrTooManyNodes},
|
||||
"ErrTooFewNodes": {code: 500, err: ErrTooFewNodes},
|
||||
"ErrAccessDenied": {code: 403, err: ErrAccessDenied},
|
||||
"ErrTooFewAvailableNodes": {code: 500, err: ErrTooFewAvailableNodes},
|
||||
"ErrFewerThanFourNodes": {code: 500, err: ErrFewerThanFourNodes},
|
||||
"ErrUnableToGetTenantLogs": {code: 500, err: ErrUnableToGetTenantLogs},
|
||||
@@ -91,22 +90,41 @@ func TestError(t *testing.T) {
|
||||
args: args{
|
||||
err: []interface{}{e.err},
|
||||
},
|
||||
want: &models.Error{Code: int32(e.code), Message: swag.String(e.err.Error()), DetailedMessage: swag.String(e.err.Error())},
|
||||
want: &CodedAPIError{
|
||||
Code: e.code,
|
||||
APIError: &models.APIError{Message: e.err.Error(), DetailedMessage: e.err.Error()},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
tests = append(tests,
|
||||
testError{
|
||||
name: "passing multiple errors but ErrInvalidLogin is last",
|
||||
args: args{
|
||||
err: []interface{}{ErrDefault, ErrInvalidLogin},
|
||||
},
|
||||
want: &models.Error{Code: int32(401), Message: swag.String(ErrDefault.Error()), DetailedMessage: swag.String(ErrDefault.Error())},
|
||||
want: &CodedAPIError{
|
||||
Code: int(401),
|
||||
APIError: &models.APIError{Message: ErrDefault.Error(), DetailedMessage: ""},
|
||||
},
|
||||
})
|
||||
tests = append(tests,
|
||||
testError{
|
||||
name: "login error omits detailedMessage",
|
||||
args: args{
|
||||
err: []interface{}{ErrInvalidLogin},
|
||||
},
|
||||
want: &CodedAPIError{
|
||||
Code: int(401),
|
||||
APIError: &models.APIError{Message: ErrInvalidLogin.Error(), DetailedMessage: ""},
|
||||
},
|
||||
})
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Run(tt.name, func(_ *testing.T) {
|
||||
got := Error(tt.args.err...)
|
||||
assert.Equalf(t, tt.want.Code, got.Code, "Error(%v) Got (%v)", tt.want.Code, got.Code)
|
||||
assert.Equalf(t, *tt.want.DetailedMessage, *got.DetailedMessage, "Error(%s) Got (%s)", *tt.want.DetailedMessage, *got.DetailedMessage)
|
||||
assert.Equalf(t, tt.want.APIError.DetailedMessage, got.APIError.DetailedMessage, "Error(%s) Got (%s)", tt.want.APIError.DetailedMessage, got.APIError.DetailedMessage)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -119,7 +137,7 @@ func TestErrorWithContext(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *models.Error
|
||||
want *CodedAPIError
|
||||
}{
|
||||
{
|
||||
name: "default error",
|
||||
@@ -127,11 +145,13 @@ func TestErrorWithContext(t *testing.T) {
|
||||
ctx: context.Background(),
|
||||
err: []interface{}{ErrDefault},
|
||||
},
|
||||
want: &models.Error{Code: 500, Message: swag.String(ErrDefault.Error()), DetailedMessage: swag.String(ErrDefault.Error())},
|
||||
want: &CodedAPIError{
|
||||
Code: 500, APIError: &models.APIError{Message: ErrDefault.Error(), DetailedMessage: ErrDefault.Error()},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Run(tt.name, func(_ *testing.T) {
|
||||
assert.Equalf(t, tt.want, ErrorWithContext(tt.args.ctx, tt.args.err...), "ErrorWithContext(%v, %v)", tt.args.ctx, tt.args.err)
|
||||
})
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
package restapi
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -58,7 +58,7 @@ type Context struct {
|
||||
TLSCertificate, TLSKey, TLSca string
|
||||
}
|
||||
|
||||
// Load loads restapi Context from command line context.
|
||||
// Load loads api Context from command line context.
|
||||
func (c *Context) Load(ctx *cli.Context) error {
|
||||
*c = Context{
|
||||
Host: ctx.String("host"),
|
||||
@@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package restapi
|
||||
package api
|
||||
|
||||
import (
|
||||
"flag"
|
||||
@@ -85,7 +85,7 @@ func TestContext_Load(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Run(tt.name, func(_ *testing.T) {
|
||||
c := &Context{}
|
||||
|
||||
fs := flag.NewFlagSet("flags", flag.ContinueOnError)
|
||||
@@ -86,7 +86,7 @@ type LoginDetailDefault struct {
|
||||
/*
|
||||
In: Body
|
||||
*/
|
||||
Payload *models.Error `json:"body,omitempty"`
|
||||
Payload *models.APIError `json:"body,omitempty"`
|
||||
}
|
||||
|
||||
// NewLoginDetailDefault creates LoginDetailDefault with default headers values
|
||||
@@ -112,13 +112,13 @@ func (o *LoginDetailDefault) SetStatusCode(code int) {
|
||||
}
|
||||
|
||||
// WithPayload adds the payload to the login detail default response
|
||||
func (o *LoginDetailDefault) WithPayload(payload *models.Error) *LoginDetailDefault {
|
||||
func (o *LoginDetailDefault) WithPayload(payload *models.APIError) *LoginDetailDefault {
|
||||
o.Payload = payload
|
||||
return o
|
||||
}
|
||||
|
||||
// SetPayload sets the payload to the login detail default response
|
||||
func (o *LoginDetailDefault) SetPayload(payload *models.Error) {
|
||||
func (o *LoginDetailDefault) SetPayload(payload *models.APIError) {
|
||||
o.Payload = payload
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ type LoginDefault struct {
|
||||
/*
|
||||
In: Body
|
||||
*/
|
||||
Payload *models.Error `json:"body,omitempty"`
|
||||
Payload *models.APIError `json:"body,omitempty"`
|
||||
}
|
||||
|
||||
// NewLoginDefault creates LoginDefault with default headers values
|
||||
@@ -92,13 +92,13 @@ func (o *LoginDefault) SetStatusCode(code int) {
|
||||
}
|
||||
|
||||
// WithPayload adds the payload to the login default response
|
||||
func (o *LoginDefault) WithPayload(payload *models.Error) *LoginDefault {
|
||||
func (o *LoginDefault) WithPayload(payload *models.APIError) *LoginDefault {
|
||||
o.Payload = payload
|
||||
return o
|
||||
}
|
||||
|
||||
// SetPayload sets the payload to the login default response
|
||||
func (o *LoginDefault) SetPayload(payload *models.Error) {
|
||||
func (o *LoginDefault) SetPayload(payload *models.APIError) {
|
||||
o.Payload = payload
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ type LogoutDefault struct {
|
||||
/*
|
||||
In: Body
|
||||
*/
|
||||
Payload *models.Error `json:"body,omitempty"`
|
||||
Payload *models.APIError `json:"body,omitempty"`
|
||||
}
|
||||
|
||||
// NewLogoutDefault creates LogoutDefault with default headers values
|
||||
@@ -92,13 +92,13 @@ func (o *LogoutDefault) SetStatusCode(code int) {
|
||||
}
|
||||
|
||||
// WithPayload adds the payload to the logout default response
|
||||
func (o *LogoutDefault) WithPayload(payload *models.Error) *LogoutDefault {
|
||||
func (o *LogoutDefault) WithPayload(payload *models.APIError) *LogoutDefault {
|
||||
o.Payload = payload
|
||||
return o
|
||||
}
|
||||
|
||||
// SetPayload sets the payload to the logout default response
|
||||
func (o *LogoutDefault) SetPayload(payload *models.Error) {
|
||||
func (o *LogoutDefault) SetPayload(payload *models.APIError) {
|
||||
o.Payload = payload
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ type SessionCheckDefault struct {
|
||||
/*
|
||||
In: Body
|
||||
*/
|
||||
Payload *models.Error `json:"body,omitempty"`
|
||||
Payload *models.APIError `json:"body,omitempty"`
|
||||
}
|
||||
|
||||
// NewSessionCheckDefault creates SessionCheckDefault with default headers values
|
||||
@@ -112,13 +112,13 @@ func (o *SessionCheckDefault) SetStatusCode(code int) {
|
||||
}
|
||||
|
||||
// WithPayload adds the payload to the session check default response
|
||||
func (o *SessionCheckDefault) WithPayload(payload *models.Error) *SessionCheckDefault {
|
||||
func (o *SessionCheckDefault) WithPayload(payload *models.APIError) *SessionCheckDefault {
|
||||
o.Payload = payload
|
||||
return o
|
||||
}
|
||||
|
||||
// SetPayload sets the payload to the session check default response
|
||||
func (o *SessionCheckDefault) SetPayload(payload *models.Error) {
|
||||
func (o *SessionCheckDefault) SetPayload(payload *models.APIError) {
|
||||
o.Payload = payload
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ type BucketInfoDefault struct {
|
||||
/*
|
||||
In: Body
|
||||
*/
|
||||
Payload *models.Error `json:"body,omitempty"`
|
||||
Payload *models.APIError `json:"body,omitempty"`
|
||||
}
|
||||
|
||||
// NewBucketInfoDefault creates BucketInfoDefault with default headers values
|
||||
@@ -112,13 +112,13 @@ func (o *BucketInfoDefault) SetStatusCode(code int) {
|
||||
}
|
||||
|
||||
// WithPayload adds the payload to the bucket info default response
|
||||
func (o *BucketInfoDefault) WithPayload(payload *models.Error) *BucketInfoDefault {
|
||||
func (o *BucketInfoDefault) WithPayload(payload *models.APIError) *BucketInfoDefault {
|
||||
o.Payload = payload
|
||||
return o
|
||||
}
|
||||
|
||||
// SetPayload sets the payload to the bucket info default response
|
||||
func (o *BucketInfoDefault) SetPayload(payload *models.Error) {
|
||||
func (o *BucketInfoDefault) SetPayload(payload *models.APIError) {
|
||||
o.Payload = payload
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ type GetBucketQuotaDefault struct {
|
||||
/*
|
||||
In: Body
|
||||
*/
|
||||
Payload *models.Error `json:"body,omitempty"`
|
||||
Payload *models.APIError `json:"body,omitempty"`
|
||||
}
|
||||
|
||||
// NewGetBucketQuotaDefault creates GetBucketQuotaDefault with default headers values
|
||||
@@ -112,13 +112,13 @@ func (o *GetBucketQuotaDefault) SetStatusCode(code int) {
|
||||
}
|
||||
|
||||
// WithPayload adds the payload to the get bucket quota default response
|
||||
func (o *GetBucketQuotaDefault) WithPayload(payload *models.Error) *GetBucketQuotaDefault {
|
||||
func (o *GetBucketQuotaDefault) WithPayload(payload *models.APIError) *GetBucketQuotaDefault {
|
||||
o.Payload = payload
|
||||
return o
|
||||
}
|
||||
|
||||
// SetPayload sets the payload to the get bucket quota default response
|
||||
func (o *GetBucketQuotaDefault) SetPayload(payload *models.Error) {
|
||||
func (o *GetBucketQuotaDefault) SetPayload(payload *models.APIError) {
|
||||
o.Payload = payload
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ type GetBucketRewindDefault struct {
|
||||
/*
|
||||
In: Body
|
||||
*/
|
||||
Payload *models.Error `json:"body,omitempty"`
|
||||
Payload *models.APIError `json:"body,omitempty"`
|
||||
}
|
||||
|
||||
// NewGetBucketRewindDefault creates GetBucketRewindDefault with default headers values
|
||||
@@ -112,13 +112,13 @@ func (o *GetBucketRewindDefault) SetStatusCode(code int) {
|
||||
}
|
||||
|
||||
// WithPayload adds the payload to the get bucket rewind default response
|
||||
func (o *GetBucketRewindDefault) WithPayload(payload *models.Error) *GetBucketRewindDefault {
|
||||
func (o *GetBucketRewindDefault) WithPayload(payload *models.APIError) *GetBucketRewindDefault {
|
||||
o.Payload = payload
|
||||
return o
|
||||
}
|
||||
|
||||
// SetPayload sets the payload to the get bucket rewind default response
|
||||
func (o *GetBucketRewindDefault) SetPayload(payload *models.Error) {
|
||||
func (o *GetBucketRewindDefault) SetPayload(payload *models.APIError) {
|
||||
o.Payload = payload
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ type GetBucketVersioningDefault struct {
|
||||
/*
|
||||
In: Body
|
||||
*/
|
||||
Payload *models.Error `json:"body,omitempty"`
|
||||
Payload *models.APIError `json:"body,omitempty"`
|
||||
}
|
||||
|
||||
// NewGetBucketVersioningDefault creates GetBucketVersioningDefault with default headers values
|
||||
@@ -112,13 +112,13 @@ func (o *GetBucketVersioningDefault) SetStatusCode(code int) {
|
||||
}
|
||||
|
||||
// WithPayload adds the payload to the get bucket versioning default response
|
||||
func (o *GetBucketVersioningDefault) WithPayload(payload *models.Error) *GetBucketVersioningDefault {
|
||||
func (o *GetBucketVersioningDefault) WithPayload(payload *models.APIError) *GetBucketVersioningDefault {
|
||||
o.Payload = payload
|
||||
return o
|
||||
}
|
||||
|
||||
// SetPayload sets the payload to the get bucket versioning default response
|
||||
func (o *GetBucketVersioningDefault) SetPayload(payload *models.Error) {
|
||||
func (o *GetBucketVersioningDefault) SetPayload(payload *models.APIError) {
|
||||
o.Payload = payload
|
||||
}
|
||||
|
||||
@@ -30,40 +30,40 @@ import (
|
||||
"github.com/minio/console/models"
|
||||
)
|
||||
|
||||
// DeleteRemoteBucketHandlerFunc turns a function with the right signature into a delete remote bucket handler
|
||||
type DeleteRemoteBucketHandlerFunc func(DeleteRemoteBucketParams, *models.Principal) middleware.Responder
|
||||
// GetMaxShareLinkExpHandlerFunc turns a function with the right signature into a get max share link exp handler
|
||||
type GetMaxShareLinkExpHandlerFunc func(GetMaxShareLinkExpParams, *models.Principal) middleware.Responder
|
||||
|
||||
// Handle executing the request and returning a response
|
||||
func (fn DeleteRemoteBucketHandlerFunc) Handle(params DeleteRemoteBucketParams, principal *models.Principal) middleware.Responder {
|
||||
func (fn GetMaxShareLinkExpHandlerFunc) Handle(params GetMaxShareLinkExpParams, principal *models.Principal) middleware.Responder {
|
||||
return fn(params, principal)
|
||||
}
|
||||
|
||||
// DeleteRemoteBucketHandler interface for that can handle valid delete remote bucket params
|
||||
type DeleteRemoteBucketHandler interface {
|
||||
Handle(DeleteRemoteBucketParams, *models.Principal) middleware.Responder
|
||||
// GetMaxShareLinkExpHandler interface for that can handle valid get max share link exp params
|
||||
type GetMaxShareLinkExpHandler interface {
|
||||
Handle(GetMaxShareLinkExpParams, *models.Principal) middleware.Responder
|
||||
}
|
||||
|
||||
// NewDeleteRemoteBucket creates a new http.Handler for the delete remote bucket operation
|
||||
func NewDeleteRemoteBucket(ctx *middleware.Context, handler DeleteRemoteBucketHandler) *DeleteRemoteBucket {
|
||||
return &DeleteRemoteBucket{Context: ctx, Handler: handler}
|
||||
// NewGetMaxShareLinkExp creates a new http.Handler for the get max share link exp operation
|
||||
func NewGetMaxShareLinkExp(ctx *middleware.Context, handler GetMaxShareLinkExpHandler) *GetMaxShareLinkExp {
|
||||
return &GetMaxShareLinkExp{Context: ctx, Handler: handler}
|
||||
}
|
||||
|
||||
/*
|
||||
DeleteRemoteBucket swagger:route DELETE /remote-buckets/{source-bucket-name}/{arn} Bucket deleteRemoteBucket
|
||||
GetMaxShareLinkExp swagger:route GET /buckets/max-share-exp Bucket getMaxShareLinkExp
|
||||
|
||||
Delete Remote Bucket
|
||||
Get max expiration time for share link in seconds
|
||||
*/
|
||||
type DeleteRemoteBucket struct {
|
||||
type GetMaxShareLinkExp struct {
|
||||
Context *middleware.Context
|
||||
Handler DeleteRemoteBucketHandler
|
||||
Handler GetMaxShareLinkExpHandler
|
||||
}
|
||||
|
||||
func (o *DeleteRemoteBucket) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||
func (o *GetMaxShareLinkExp) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||
route, rCtx, _ := o.Context.RouteInfo(r)
|
||||
if rCtx != nil {
|
||||
*r = *rCtx
|
||||
}
|
||||
var Params = NewDeleteRemoteBucketParams()
|
||||
var Params = NewGetMaxShareLinkExpParams()
|
||||
uprinc, aCtx, err := o.Context.Authorize(r, route)
|
||||
if err != nil {
|
||||
o.Context.Respond(rw, r, route.Produces, route, err)
|
||||
@@ -29,19 +29,19 @@ import (
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
)
|
||||
|
||||
// NewListRemoteBucketsParams creates a new ListRemoteBucketsParams object
|
||||
// NewGetMaxShareLinkExpParams creates a new GetMaxShareLinkExpParams object
|
||||
//
|
||||
// There are no default values defined in the spec.
|
||||
func NewListRemoteBucketsParams() ListRemoteBucketsParams {
|
||||
func NewGetMaxShareLinkExpParams() GetMaxShareLinkExpParams {
|
||||
|
||||
return ListRemoteBucketsParams{}
|
||||
return GetMaxShareLinkExpParams{}
|
||||
}
|
||||
|
||||
// ListRemoteBucketsParams contains all the bound params for the list remote buckets operation
|
||||
// GetMaxShareLinkExpParams contains all the bound params for the get max share link exp operation
|
||||
// typically these are obtained from a http.Request
|
||||
//
|
||||
// swagger:parameters ListRemoteBuckets
|
||||
type ListRemoteBucketsParams struct {
|
||||
// swagger:parameters GetMaxShareLinkExp
|
||||
type GetMaxShareLinkExpParams struct {
|
||||
|
||||
// HTTP Request Object
|
||||
HTTPRequest *http.Request `json:"-"`
|
||||
@@ -50,8 +50,8 @@ type ListRemoteBucketsParams struct {
|
||||
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
|
||||
// for simple values it will use straight method calls.
|
||||
//
|
||||
// To ensure default values, the struct must have been initialized with NewListRemoteBucketsParams() beforehand.
|
||||
func (o *ListRemoteBucketsParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
|
||||
// To ensure default values, the struct must have been initialized with NewGetMaxShareLinkExpParams() beforehand.
|
||||
func (o *GetMaxShareLinkExpParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
|
||||
var res []error
|
||||
|
||||
o.HTTPRequest = r
|
||||
@@ -30,41 +30,41 @@ import (
|
||||
"github.com/minio/console/models"
|
||||
)
|
||||
|
||||
// GetBucketLifecycleOKCode is the HTTP code returned for type GetBucketLifecycleOK
|
||||
const GetBucketLifecycleOKCode int = 200
|
||||
// GetMaxShareLinkExpOKCode is the HTTP code returned for type GetMaxShareLinkExpOK
|
||||
const GetMaxShareLinkExpOKCode int = 200
|
||||
|
||||
/*
|
||||
GetBucketLifecycleOK A successful response.
|
||||
GetMaxShareLinkExpOK A successful response.
|
||||
|
||||
swagger:response getBucketLifecycleOK
|
||||
swagger:response getMaxShareLinkExpOK
|
||||
*/
|
||||
type GetBucketLifecycleOK struct {
|
||||
type GetMaxShareLinkExpOK struct {
|
||||
|
||||
/*
|
||||
In: Body
|
||||
*/
|
||||
Payload *models.BucketLifecycleResponse `json:"body,omitempty"`
|
||||
Payload *models.MaxShareLinkExpResponse `json:"body,omitempty"`
|
||||
}
|
||||
|
||||
// NewGetBucketLifecycleOK creates GetBucketLifecycleOK with default headers values
|
||||
func NewGetBucketLifecycleOK() *GetBucketLifecycleOK {
|
||||
// NewGetMaxShareLinkExpOK creates GetMaxShareLinkExpOK with default headers values
|
||||
func NewGetMaxShareLinkExpOK() *GetMaxShareLinkExpOK {
|
||||
|
||||
return &GetBucketLifecycleOK{}
|
||||
return &GetMaxShareLinkExpOK{}
|
||||
}
|
||||
|
||||
// WithPayload adds the payload to the get bucket lifecycle o k response
|
||||
func (o *GetBucketLifecycleOK) WithPayload(payload *models.BucketLifecycleResponse) *GetBucketLifecycleOK {
|
||||
// WithPayload adds the payload to the get max share link exp o k response
|
||||
func (o *GetMaxShareLinkExpOK) WithPayload(payload *models.MaxShareLinkExpResponse) *GetMaxShareLinkExpOK {
|
||||
o.Payload = payload
|
||||
return o
|
||||
}
|
||||
|
||||
// SetPayload sets the payload to the get bucket lifecycle o k response
|
||||
func (o *GetBucketLifecycleOK) SetPayload(payload *models.BucketLifecycleResponse) {
|
||||
// SetPayload sets the payload to the get max share link exp o k response
|
||||
func (o *GetMaxShareLinkExpOK) SetPayload(payload *models.MaxShareLinkExpResponse) {
|
||||
o.Payload = payload
|
||||
}
|
||||
|
||||
// WriteResponse to the client
|
||||
func (o *GetBucketLifecycleOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
|
||||
func (o *GetMaxShareLinkExpOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
|
||||
|
||||
rw.WriteHeader(200)
|
||||
if o.Payload != nil {
|
||||
@@ -76,54 +76,54 @@ func (o *GetBucketLifecycleOK) WriteResponse(rw http.ResponseWriter, producer ru
|
||||
}
|
||||
|
||||
/*
|
||||
GetBucketLifecycleDefault Generic error response.
|
||||
GetMaxShareLinkExpDefault Generic error response.
|
||||
|
||||
swagger:response getBucketLifecycleDefault
|
||||
swagger:response getMaxShareLinkExpDefault
|
||||
*/
|
||||
type GetBucketLifecycleDefault struct {
|
||||
type GetMaxShareLinkExpDefault struct {
|
||||
_statusCode int
|
||||
|
||||
/*
|
||||
In: Body
|
||||
*/
|
||||
Payload *models.Error `json:"body,omitempty"`
|
||||
Payload *models.APIError `json:"body,omitempty"`
|
||||
}
|
||||
|
||||
// NewGetBucketLifecycleDefault creates GetBucketLifecycleDefault with default headers values
|
||||
func NewGetBucketLifecycleDefault(code int) *GetBucketLifecycleDefault {
|
||||
// NewGetMaxShareLinkExpDefault creates GetMaxShareLinkExpDefault with default headers values
|
||||
func NewGetMaxShareLinkExpDefault(code int) *GetMaxShareLinkExpDefault {
|
||||
if code <= 0 {
|
||||
code = 500
|
||||
}
|
||||
|
||||
return &GetBucketLifecycleDefault{
|
||||
return &GetMaxShareLinkExpDefault{
|
||||
_statusCode: code,
|
||||
}
|
||||
}
|
||||
|
||||
// WithStatusCode adds the status to the get bucket lifecycle default response
|
||||
func (o *GetBucketLifecycleDefault) WithStatusCode(code int) *GetBucketLifecycleDefault {
|
||||
// WithStatusCode adds the status to the get max share link exp default response
|
||||
func (o *GetMaxShareLinkExpDefault) WithStatusCode(code int) *GetMaxShareLinkExpDefault {
|
||||
o._statusCode = code
|
||||
return o
|
||||
}
|
||||
|
||||
// SetStatusCode sets the status to the get bucket lifecycle default response
|
||||
func (o *GetBucketLifecycleDefault) SetStatusCode(code int) {
|
||||
// SetStatusCode sets the status to the get max share link exp default response
|
||||
func (o *GetMaxShareLinkExpDefault) SetStatusCode(code int) {
|
||||
o._statusCode = code
|
||||
}
|
||||
|
||||
// WithPayload adds the payload to the get bucket lifecycle default response
|
||||
func (o *GetBucketLifecycleDefault) WithPayload(payload *models.Error) *GetBucketLifecycleDefault {
|
||||
// WithPayload adds the payload to the get max share link exp default response
|
||||
func (o *GetMaxShareLinkExpDefault) WithPayload(payload *models.APIError) *GetMaxShareLinkExpDefault {
|
||||
o.Payload = payload
|
||||
return o
|
||||
}
|
||||
|
||||
// SetPayload sets the payload to the get bucket lifecycle default response
|
||||
func (o *GetBucketLifecycleDefault) SetPayload(payload *models.Error) {
|
||||
// SetPayload sets the payload to the get max share link exp default response
|
||||
func (o *GetMaxShareLinkExpDefault) SetPayload(payload *models.APIError) {
|
||||
o.Payload = payload
|
||||
}
|
||||
|
||||
// WriteResponse to the client
|
||||
func (o *GetBucketLifecycleDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
|
||||
func (o *GetMaxShareLinkExpDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
|
||||
|
||||
rw.WriteHeader(o._statusCode)
|
||||
if o.Payload != nil {
|
||||
@@ -17,7 +17,7 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
package policy
|
||||
package bucket
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the generate command
|
||||
@@ -28,15 +28,15 @@ import (
|
||||
golangswaggerpaths "path"
|
||||
)
|
||||
|
||||
// GetUserPolicyURL generates an URL for the get user policy operation
|
||||
type GetUserPolicyURL struct {
|
||||
// GetMaxShareLinkExpURL generates an URL for the get max share link exp operation
|
||||
type GetMaxShareLinkExpURL struct {
|
||||
_basePath string
|
||||
}
|
||||
|
||||
// WithBasePath sets the base path for this url builder, only required when it's different from the
|
||||
// base path specified in the swagger spec.
|
||||
// When the value of the base path is an empty string
|
||||
func (o *GetUserPolicyURL) WithBasePath(bp string) *GetUserPolicyURL {
|
||||
func (o *GetMaxShareLinkExpURL) WithBasePath(bp string) *GetMaxShareLinkExpURL {
|
||||
o.SetBasePath(bp)
|
||||
return o
|
||||
}
|
||||
@@ -44,15 +44,15 @@ func (o *GetUserPolicyURL) WithBasePath(bp string) *GetUserPolicyURL {
|
||||
// SetBasePath sets the base path for this url builder, only required when it's different from the
|
||||
// base path specified in the swagger spec.
|
||||
// When the value of the base path is an empty string
|
||||
func (o *GetUserPolicyURL) SetBasePath(bp string) {
|
||||
func (o *GetMaxShareLinkExpURL) SetBasePath(bp string) {
|
||||
o._basePath = bp
|
||||
}
|
||||
|
||||
// Build a url path and query string
|
||||
func (o *GetUserPolicyURL) Build() (*url.URL, error) {
|
||||
func (o *GetMaxShareLinkExpURL) Build() (*url.URL, error) {
|
||||
var _result url.URL
|
||||
|
||||
var _path = "/user/policy"
|
||||
var _path = "/buckets/max-share-exp"
|
||||
|
||||
_basePath := o._basePath
|
||||
if _basePath == "" {
|
||||
@@ -64,7 +64,7 @@ func (o *GetUserPolicyURL) Build() (*url.URL, error) {
|
||||
}
|
||||
|
||||
// Must is a helper function to panic when the url builder returns an error
|
||||
func (o *GetUserPolicyURL) Must(u *url.URL, err error) *url.URL {
|
||||
func (o *GetMaxShareLinkExpURL) Must(u *url.URL, err error) *url.URL {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -75,17 +75,17 @@ func (o *GetUserPolicyURL) Must(u *url.URL, err error) *url.URL {
|
||||
}
|
||||
|
||||
// String returns the string representation of the path with query string
|
||||
func (o *GetUserPolicyURL) String() string {
|
||||
func (o *GetMaxShareLinkExpURL) String() string {
|
||||
return o.Must(o.Build()).String()
|
||||
}
|
||||
|
||||
// BuildFull builds a full url with scheme, host, path and query string
|
||||
func (o *GetUserPolicyURL) BuildFull(scheme, host string) (*url.URL, error) {
|
||||
func (o *GetMaxShareLinkExpURL) BuildFull(scheme, host string) (*url.URL, error) {
|
||||
if scheme == "" {
|
||||
return nil, errors.New("scheme is required for a full url on GetUserPolicyURL")
|
||||
return nil, errors.New("scheme is required for a full url on GetMaxShareLinkExpURL")
|
||||
}
|
||||
if host == "" {
|
||||
return nil, errors.New("host is required for a full url on GetUserPolicyURL")
|
||||
return nil, errors.New("host is required for a full url on GetMaxShareLinkExpURL")
|
||||
}
|
||||
|
||||
base, err := o.Build()
|
||||
@@ -99,6 +99,6 @@ func (o *GetUserPolicyURL) BuildFull(scheme, host string) (*url.URL, error) {
|
||||
}
|
||||
|
||||
// StringFull returns the string representation of a complete url
|
||||
func (o *GetUserPolicyURL) StringFull(scheme, host string) string {
|
||||
func (o *GetMaxShareLinkExpURL) StringFull(scheme, host string) string {
|
||||
return o.Must(o.BuildFull(scheme, host)).String()
|
||||
}
|
||||
@@ -86,7 +86,7 @@ type ListBucketsDefault struct {
|
||||
/*
|
||||
In: Body
|
||||
*/
|
||||
Payload *models.Error `json:"body,omitempty"`
|
||||
Payload *models.APIError `json:"body,omitempty"`
|
||||
}
|
||||
|
||||
// NewListBucketsDefault creates ListBucketsDefault with default headers values
|
||||
@@ -112,13 +112,13 @@ func (o *ListBucketsDefault) SetStatusCode(code int) {
|
||||
}
|
||||
|
||||
// WithPayload adds the payload to the list buckets default response
|
||||
func (o *ListBucketsDefault) WithPayload(payload *models.Error) *ListBucketsDefault {
|
||||
func (o *ListBucketsDefault) WithPayload(payload *models.APIError) *ListBucketsDefault {
|
||||
o.Payload = payload
|
||||
return o
|
||||
}
|
||||
|
||||
// SetPayload sets the payload to the list buckets default response
|
||||
func (o *ListBucketsDefault) SetPayload(payload *models.Error) {
|
||||
func (o *ListBucketsDefault) SetPayload(payload *models.APIError) {
|
||||
o.Payload = payload
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ type MakeBucketDefault struct {
|
||||
/*
|
||||
In: Body
|
||||
*/
|
||||
Payload *models.Error `json:"body,omitempty"`
|
||||
Payload *models.APIError `json:"body,omitempty"`
|
||||
}
|
||||
|
||||
// NewMakeBucketDefault creates MakeBucketDefault with default headers values
|
||||
@@ -112,13 +112,13 @@ func (o *MakeBucketDefault) SetStatusCode(code int) {
|
||||
}
|
||||
|
||||
// WithPayload adds the payload to the make bucket default response
|
||||
func (o *MakeBucketDefault) WithPayload(payload *models.Error) *MakeBucketDefault {
|
||||
func (o *MakeBucketDefault) WithPayload(payload *models.APIError) *MakeBucketDefault {
|
||||
o.Payload = payload
|
||||
return o
|
||||
}
|
||||
|
||||
// SetPayload sets the payload to the make bucket default response
|
||||
func (o *MakeBucketDefault) SetPayload(payload *models.Error) {
|
||||
func (o *MakeBucketDefault) SetPayload(payload *models.APIError) {
|
||||
o.Payload = payload
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ type SetBucketVersioningDefault struct {
|
||||
/*
|
||||
In: Body
|
||||
*/
|
||||
Payload *models.Error `json:"body,omitempty"`
|
||||
Payload *models.APIError `json:"body,omitempty"`
|
||||
}
|
||||
|
||||
// NewSetBucketVersioningDefault creates SetBucketVersioningDefault with default headers values
|
||||
@@ -92,13 +92,13 @@ func (o *SetBucketVersioningDefault) SetStatusCode(code int) {
|
||||
}
|
||||
|
||||
// WithPayload adds the payload to the set bucket versioning default response
|
||||
func (o *SetBucketVersioningDefault) WithPayload(payload *models.Error) *SetBucketVersioningDefault {
|
||||
func (o *SetBucketVersioningDefault) WithPayload(payload *models.APIError) *SetBucketVersioningDefault {
|
||||
o.Payload = payload
|
||||
return o
|
||||
}
|
||||
|
||||
// SetPayload sets the payload to the set bucket versioning default response
|
||||
func (o *SetBucketVersioningDefault) SetPayload(payload *models.Error) {
|
||||
func (o *SetBucketVersioningDefault) SetPayload(payload *models.APIError) {
|
||||
o.Payload = payload
|
||||
}
|
||||
|
||||
676
api/operations/console_api.go
Normal file
676
api/operations/console_api.go
Normal file
@@ -0,0 +1,676 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2023 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
package operations
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/loads"
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
"github.com/go-openapi/runtime/security"
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
|
||||
"github.com/minio/console/api/operations/auth"
|
||||
"github.com/minio/console/api/operations/bucket"
|
||||
"github.com/minio/console/api/operations/license"
|
||||
"github.com/minio/console/api/operations/object"
|
||||
"github.com/minio/console/api/operations/public"
|
||||
"github.com/minio/console/api/operations/system"
|
||||
"github.com/minio/console/models"
|
||||
)
|
||||
|
||||
// NewConsoleAPI creates a new Console instance
|
||||
func NewConsoleAPI(spec *loads.Document) *ConsoleAPI {
|
||||
return &ConsoleAPI{
|
||||
handlers: make(map[string]map[string]http.Handler),
|
||||
formats: strfmt.Default,
|
||||
defaultConsumes: "application/json",
|
||||
defaultProduces: "application/json",
|
||||
customConsumers: make(map[string]runtime.Consumer),
|
||||
customProducers: make(map[string]runtime.Producer),
|
||||
PreServerShutdown: func() {},
|
||||
ServerShutdown: func() {},
|
||||
spec: spec,
|
||||
useSwaggerUI: false,
|
||||
ServeError: errors.ServeError,
|
||||
BasicAuthenticator: security.BasicAuth,
|
||||
APIKeyAuthenticator: security.APIKeyAuth,
|
||||
BearerAuthenticator: security.BearerAuth,
|
||||
|
||||
JSONConsumer: runtime.JSONConsumer(),
|
||||
MultipartformConsumer: runtime.DiscardConsumer,
|
||||
|
||||
BinProducer: runtime.ByteStreamProducer(),
|
||||
JSONProducer: runtime.JSONProducer(),
|
||||
|
||||
SystemAdminInfoHandler: system.AdminInfoHandlerFunc(func(params system.AdminInfoParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation system.AdminInfo has not yet been implemented")
|
||||
}),
|
||||
BucketBucketInfoHandler: bucket.BucketInfoHandlerFunc(func(params bucket.BucketInfoParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation bucket.BucketInfo has not yet been implemented")
|
||||
}),
|
||||
ObjectDeleteMultipleObjectsHandler: object.DeleteMultipleObjectsHandlerFunc(func(params object.DeleteMultipleObjectsParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation object.DeleteMultipleObjects has not yet been implemented")
|
||||
}),
|
||||
ObjectDeleteObjectHandler: object.DeleteObjectHandlerFunc(func(params object.DeleteObjectParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation object.DeleteObject has not yet been implemented")
|
||||
}),
|
||||
ObjectDownloadObjectHandler: object.DownloadObjectHandlerFunc(func(params object.DownloadObjectParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation object.DownloadObject has not yet been implemented")
|
||||
}),
|
||||
ObjectDownloadMultipleObjectsHandler: object.DownloadMultipleObjectsHandlerFunc(func(params object.DownloadMultipleObjectsParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation object.DownloadMultipleObjects has not yet been implemented")
|
||||
}),
|
||||
PublicDownloadSharedObjectHandler: public.DownloadSharedObjectHandlerFunc(func(params public.DownloadSharedObjectParams) middleware.Responder {
|
||||
return middleware.NotImplemented("operation public.DownloadSharedObject has not yet been implemented")
|
||||
}),
|
||||
BucketGetBucketQuotaHandler: bucket.GetBucketQuotaHandlerFunc(func(params bucket.GetBucketQuotaParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation bucket.GetBucketQuota has not yet been implemented")
|
||||
}),
|
||||
BucketGetBucketRewindHandler: bucket.GetBucketRewindHandlerFunc(func(params bucket.GetBucketRewindParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation bucket.GetBucketRewind has not yet been implemented")
|
||||
}),
|
||||
BucketGetBucketVersioningHandler: bucket.GetBucketVersioningHandlerFunc(func(params bucket.GetBucketVersioningParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation bucket.GetBucketVersioning has not yet been implemented")
|
||||
}),
|
||||
BucketGetMaxShareLinkExpHandler: bucket.GetMaxShareLinkExpHandlerFunc(func(params bucket.GetMaxShareLinkExpParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation bucket.GetMaxShareLinkExp has not yet been implemented")
|
||||
}),
|
||||
ObjectGetObjectMetadataHandler: object.GetObjectMetadataHandlerFunc(func(params object.GetObjectMetadataParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation object.GetObjectMetadata has not yet been implemented")
|
||||
}),
|
||||
LicenseLicenseAcknowledgeHandler: license.LicenseAcknowledgeHandlerFunc(func(params license.LicenseAcknowledgeParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation license.LicenseAcknowledge has not yet been implemented")
|
||||
}),
|
||||
BucketListBucketsHandler: bucket.ListBucketsHandlerFunc(func(params bucket.ListBucketsParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation bucket.ListBuckets has not yet been implemented")
|
||||
}),
|
||||
ObjectListObjectsHandler: object.ListObjectsHandlerFunc(func(params object.ListObjectsParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation object.ListObjects has not yet been implemented")
|
||||
}),
|
||||
AuthLoginHandler: auth.LoginHandlerFunc(func(params auth.LoginParams) middleware.Responder {
|
||||
return middleware.NotImplemented("operation auth.Login has not yet been implemented")
|
||||
}),
|
||||
AuthLoginDetailHandler: auth.LoginDetailHandlerFunc(func(params auth.LoginDetailParams) middleware.Responder {
|
||||
return middleware.NotImplemented("operation auth.LoginDetail has not yet been implemented")
|
||||
}),
|
||||
AuthLogoutHandler: auth.LogoutHandlerFunc(func(params auth.LogoutParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation auth.Logout has not yet been implemented")
|
||||
}),
|
||||
BucketMakeBucketHandler: bucket.MakeBucketHandlerFunc(func(params bucket.MakeBucketParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation bucket.MakeBucket has not yet been implemented")
|
||||
}),
|
||||
ObjectPostBucketsBucketNameObjectsUploadHandler: object.PostBucketsBucketNameObjectsUploadHandlerFunc(func(params object.PostBucketsBucketNameObjectsUploadParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation object.PostBucketsBucketNameObjectsUpload has not yet been implemented")
|
||||
}),
|
||||
ObjectPutObjectRestoreHandler: object.PutObjectRestoreHandlerFunc(func(params object.PutObjectRestoreParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation object.PutObjectRestore has not yet been implemented")
|
||||
}),
|
||||
ObjectPutObjectTagsHandler: object.PutObjectTagsHandlerFunc(func(params object.PutObjectTagsParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation object.PutObjectTags has not yet been implemented")
|
||||
}),
|
||||
AuthSessionCheckHandler: auth.SessionCheckHandlerFunc(func(params auth.SessionCheckParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation auth.SessionCheck has not yet been implemented")
|
||||
}),
|
||||
BucketSetBucketVersioningHandler: bucket.SetBucketVersioningHandlerFunc(func(params bucket.SetBucketVersioningParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation bucket.SetBucketVersioning has not yet been implemented")
|
||||
}),
|
||||
ObjectShareObjectHandler: object.ShareObjectHandlerFunc(func(params object.ShareObjectParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation object.ShareObject has not yet been implemented")
|
||||
}),
|
||||
|
||||
// Applies when the "X-Anonymous" header is set
|
||||
AnonymousAuth: func(token string) (*models.Principal, error) {
|
||||
return nil, errors.NotImplemented("api key auth (anonymous) X-Anonymous from header param [X-Anonymous] has not yet been implemented")
|
||||
},
|
||||
KeyAuth: func(token string, scopes []string) (*models.Principal, error) {
|
||||
return nil, errors.NotImplemented("oauth2 bearer auth (key) has not yet been implemented")
|
||||
},
|
||||
// default authorizer is authorized meaning no requests are blocked
|
||||
APIAuthorizer: security.Authorized(),
|
||||
}
|
||||
}
|
||||
|
||||
/*ConsoleAPI the console API */
|
||||
type ConsoleAPI struct {
|
||||
spec *loads.Document
|
||||
context *middleware.Context
|
||||
handlers map[string]map[string]http.Handler
|
||||
formats strfmt.Registry
|
||||
customConsumers map[string]runtime.Consumer
|
||||
customProducers map[string]runtime.Producer
|
||||
defaultConsumes string
|
||||
defaultProduces string
|
||||
Middleware func(middleware.Builder) http.Handler
|
||||
useSwaggerUI bool
|
||||
|
||||
// BasicAuthenticator generates a runtime.Authenticator from the supplied basic auth function.
|
||||
// It has a default implementation in the security package, however you can replace it for your particular usage.
|
||||
BasicAuthenticator func(security.UserPassAuthentication) runtime.Authenticator
|
||||
|
||||
// APIKeyAuthenticator generates a runtime.Authenticator from the supplied token auth function.
|
||||
// It has a default implementation in the security package, however you can replace it for your particular usage.
|
||||
APIKeyAuthenticator func(string, string, security.TokenAuthentication) runtime.Authenticator
|
||||
|
||||
// BearerAuthenticator generates a runtime.Authenticator from the supplied bearer token auth function.
|
||||
// It has a default implementation in the security package, however you can replace it for your particular usage.
|
||||
BearerAuthenticator func(string, security.ScopedTokenAuthentication) runtime.Authenticator
|
||||
|
||||
// JSONConsumer registers a consumer for the following mime types:
|
||||
// - application/json
|
||||
JSONConsumer runtime.Consumer
|
||||
// MultipartformConsumer registers a consumer for the following mime types:
|
||||
// - multipart/form-data
|
||||
MultipartformConsumer runtime.Consumer
|
||||
|
||||
// BinProducer registers a producer for the following mime types:
|
||||
// - application/octet-stream
|
||||
BinProducer runtime.Producer
|
||||
// JSONProducer registers a producer for the following mime types:
|
||||
// - application/json
|
||||
JSONProducer runtime.Producer
|
||||
|
||||
// AnonymousAuth registers a function that takes a token and returns a principal
|
||||
// it performs authentication based on an api key X-Anonymous provided in the header
|
||||
AnonymousAuth func(string) (*models.Principal, error)
|
||||
|
||||
// KeyAuth registers a function that takes an access token and a collection of required scopes and returns a principal
|
||||
// it performs authentication based on an oauth2 bearer token provided in the request
|
||||
KeyAuth func(string, []string) (*models.Principal, error)
|
||||
|
||||
// APIAuthorizer provides access control (ACL/RBAC/ABAC) by providing access to the request and authenticated principal
|
||||
APIAuthorizer runtime.Authorizer
|
||||
|
||||
// SystemAdminInfoHandler sets the operation handler for the admin info operation
|
||||
SystemAdminInfoHandler system.AdminInfoHandler
|
||||
// BucketBucketInfoHandler sets the operation handler for the bucket info operation
|
||||
BucketBucketInfoHandler bucket.BucketInfoHandler
|
||||
// ObjectDeleteMultipleObjectsHandler sets the operation handler for the delete multiple objects operation
|
||||
ObjectDeleteMultipleObjectsHandler object.DeleteMultipleObjectsHandler
|
||||
// ObjectDeleteObjectHandler sets the operation handler for the delete object operation
|
||||
ObjectDeleteObjectHandler object.DeleteObjectHandler
|
||||
// ObjectDownloadObjectHandler sets the operation handler for the download object operation
|
||||
ObjectDownloadObjectHandler object.DownloadObjectHandler
|
||||
// ObjectDownloadMultipleObjectsHandler sets the operation handler for the download multiple objects operation
|
||||
ObjectDownloadMultipleObjectsHandler object.DownloadMultipleObjectsHandler
|
||||
// PublicDownloadSharedObjectHandler sets the operation handler for the download shared object operation
|
||||
PublicDownloadSharedObjectHandler public.DownloadSharedObjectHandler
|
||||
// BucketGetBucketQuotaHandler sets the operation handler for the get bucket quota operation
|
||||
BucketGetBucketQuotaHandler bucket.GetBucketQuotaHandler
|
||||
// BucketGetBucketRewindHandler sets the operation handler for the get bucket rewind operation
|
||||
BucketGetBucketRewindHandler bucket.GetBucketRewindHandler
|
||||
// BucketGetBucketVersioningHandler sets the operation handler for the get bucket versioning operation
|
||||
BucketGetBucketVersioningHandler bucket.GetBucketVersioningHandler
|
||||
// BucketGetMaxShareLinkExpHandler sets the operation handler for the get max share link exp operation
|
||||
BucketGetMaxShareLinkExpHandler bucket.GetMaxShareLinkExpHandler
|
||||
// ObjectGetObjectMetadataHandler sets the operation handler for the get object metadata operation
|
||||
ObjectGetObjectMetadataHandler object.GetObjectMetadataHandler
|
||||
// LicenseLicenseAcknowledgeHandler sets the operation handler for the license acknowledge operation
|
||||
LicenseLicenseAcknowledgeHandler license.LicenseAcknowledgeHandler
|
||||
// BucketListBucketsHandler sets the operation handler for the list buckets operation
|
||||
BucketListBucketsHandler bucket.ListBucketsHandler
|
||||
// ObjectListObjectsHandler sets the operation handler for the list objects operation
|
||||
ObjectListObjectsHandler object.ListObjectsHandler
|
||||
// AuthLoginHandler sets the operation handler for the login operation
|
||||
AuthLoginHandler auth.LoginHandler
|
||||
// AuthLoginDetailHandler sets the operation handler for the login detail operation
|
||||
AuthLoginDetailHandler auth.LoginDetailHandler
|
||||
// AuthLogoutHandler sets the operation handler for the logout operation
|
||||
AuthLogoutHandler auth.LogoutHandler
|
||||
// BucketMakeBucketHandler sets the operation handler for the make bucket operation
|
||||
BucketMakeBucketHandler bucket.MakeBucketHandler
|
||||
// ObjectPostBucketsBucketNameObjectsUploadHandler sets the operation handler for the post buckets bucket name objects upload operation
|
||||
ObjectPostBucketsBucketNameObjectsUploadHandler object.PostBucketsBucketNameObjectsUploadHandler
|
||||
// ObjectPutObjectRestoreHandler sets the operation handler for the put object restore operation
|
||||
ObjectPutObjectRestoreHandler object.PutObjectRestoreHandler
|
||||
// ObjectPutObjectTagsHandler sets the operation handler for the put object tags operation
|
||||
ObjectPutObjectTagsHandler object.PutObjectTagsHandler
|
||||
// AuthSessionCheckHandler sets the operation handler for the session check operation
|
||||
AuthSessionCheckHandler auth.SessionCheckHandler
|
||||
// BucketSetBucketVersioningHandler sets the operation handler for the set bucket versioning operation
|
||||
BucketSetBucketVersioningHandler bucket.SetBucketVersioningHandler
|
||||
// ObjectShareObjectHandler sets the operation handler for the share object operation
|
||||
ObjectShareObjectHandler object.ShareObjectHandler
|
||||
|
||||
// ServeError is called when an error is received, there is a default handler
|
||||
// but you can set your own with this
|
||||
ServeError func(http.ResponseWriter, *http.Request, error)
|
||||
|
||||
// PreServerShutdown is called before the HTTP(S) server is shutdown
|
||||
// This allows for custom functions to get executed before the HTTP(S) server stops accepting traffic
|
||||
PreServerShutdown func()
|
||||
|
||||
// ServerShutdown is called when the HTTP(S) server is shut down and done
|
||||
// handling all active connections and does not accept connections any more
|
||||
ServerShutdown func()
|
||||
|
||||
// Custom command line argument groups with their descriptions
|
||||
CommandLineOptionsGroups []swag.CommandLineOptionsGroup
|
||||
|
||||
// User defined logger function.
|
||||
Logger func(string, ...interface{})
|
||||
}
|
||||
|
||||
// UseRedoc for documentation at /docs
|
||||
func (o *ConsoleAPI) UseRedoc() {
|
||||
o.useSwaggerUI = false
|
||||
}
|
||||
|
||||
// UseSwaggerUI for documentation at /docs
|
||||
func (o *ConsoleAPI) UseSwaggerUI() {
|
||||
o.useSwaggerUI = true
|
||||
}
|
||||
|
||||
// SetDefaultProduces sets the default produces media type
|
||||
func (o *ConsoleAPI) SetDefaultProduces(mediaType string) {
|
||||
o.defaultProduces = mediaType
|
||||
}
|
||||
|
||||
// SetDefaultConsumes returns the default consumes media type
|
||||
func (o *ConsoleAPI) SetDefaultConsumes(mediaType string) {
|
||||
o.defaultConsumes = mediaType
|
||||
}
|
||||
|
||||
// SetSpec sets a spec that will be served for the clients.
|
||||
func (o *ConsoleAPI) SetSpec(spec *loads.Document) {
|
||||
o.spec = spec
|
||||
}
|
||||
|
||||
// DefaultProduces returns the default produces media type
|
||||
func (o *ConsoleAPI) DefaultProduces() string {
|
||||
return o.defaultProduces
|
||||
}
|
||||
|
||||
// DefaultConsumes returns the default consumes media type
|
||||
func (o *ConsoleAPI) DefaultConsumes() string {
|
||||
return o.defaultConsumes
|
||||
}
|
||||
|
||||
// Formats returns the registered string formats
|
||||
func (o *ConsoleAPI) Formats() strfmt.Registry {
|
||||
return o.formats
|
||||
}
|
||||
|
||||
// RegisterFormat registers a custom format validator
|
||||
func (o *ConsoleAPI) RegisterFormat(name string, format strfmt.Format, validator strfmt.Validator) {
|
||||
o.formats.Add(name, format, validator)
|
||||
}
|
||||
|
||||
// Validate validates the registrations in the ConsoleAPI
|
||||
func (o *ConsoleAPI) Validate() error {
|
||||
var unregistered []string
|
||||
|
||||
if o.JSONConsumer == nil {
|
||||
unregistered = append(unregistered, "JSONConsumer")
|
||||
}
|
||||
if o.MultipartformConsumer == nil {
|
||||
unregistered = append(unregistered, "MultipartformConsumer")
|
||||
}
|
||||
|
||||
if o.BinProducer == nil {
|
||||
unregistered = append(unregistered, "BinProducer")
|
||||
}
|
||||
if o.JSONProducer == nil {
|
||||
unregistered = append(unregistered, "JSONProducer")
|
||||
}
|
||||
|
||||
if o.AnonymousAuth == nil {
|
||||
unregistered = append(unregistered, "XAnonymousAuth")
|
||||
}
|
||||
if o.KeyAuth == nil {
|
||||
unregistered = append(unregistered, "KeyAuth")
|
||||
}
|
||||
|
||||
if o.SystemAdminInfoHandler == nil {
|
||||
unregistered = append(unregistered, "system.AdminInfoHandler")
|
||||
}
|
||||
if o.BucketBucketInfoHandler == nil {
|
||||
unregistered = append(unregistered, "bucket.BucketInfoHandler")
|
||||
}
|
||||
if o.ObjectDeleteMultipleObjectsHandler == nil {
|
||||
unregistered = append(unregistered, "object.DeleteMultipleObjectsHandler")
|
||||
}
|
||||
if o.ObjectDeleteObjectHandler == nil {
|
||||
unregistered = append(unregistered, "object.DeleteObjectHandler")
|
||||
}
|
||||
if o.ObjectDownloadObjectHandler == nil {
|
||||
unregistered = append(unregistered, "object.DownloadObjectHandler")
|
||||
}
|
||||
if o.ObjectDownloadMultipleObjectsHandler == nil {
|
||||
unregistered = append(unregistered, "object.DownloadMultipleObjectsHandler")
|
||||
}
|
||||
if o.PublicDownloadSharedObjectHandler == nil {
|
||||
unregistered = append(unregistered, "public.DownloadSharedObjectHandler")
|
||||
}
|
||||
if o.BucketGetBucketQuotaHandler == nil {
|
||||
unregistered = append(unregistered, "bucket.GetBucketQuotaHandler")
|
||||
}
|
||||
if o.BucketGetBucketRewindHandler == nil {
|
||||
unregistered = append(unregistered, "bucket.GetBucketRewindHandler")
|
||||
}
|
||||
if o.BucketGetBucketVersioningHandler == nil {
|
||||
unregistered = append(unregistered, "bucket.GetBucketVersioningHandler")
|
||||
}
|
||||
if o.BucketGetMaxShareLinkExpHandler == nil {
|
||||
unregistered = append(unregistered, "bucket.GetMaxShareLinkExpHandler")
|
||||
}
|
||||
if o.ObjectGetObjectMetadataHandler == nil {
|
||||
unregistered = append(unregistered, "object.GetObjectMetadataHandler")
|
||||
}
|
||||
if o.LicenseLicenseAcknowledgeHandler == nil {
|
||||
unregistered = append(unregistered, "license.LicenseAcknowledgeHandler")
|
||||
}
|
||||
if o.BucketListBucketsHandler == nil {
|
||||
unregistered = append(unregistered, "bucket.ListBucketsHandler")
|
||||
}
|
||||
if o.ObjectListObjectsHandler == nil {
|
||||
unregistered = append(unregistered, "object.ListObjectsHandler")
|
||||
}
|
||||
if o.AuthLoginHandler == nil {
|
||||
unregistered = append(unregistered, "auth.LoginHandler")
|
||||
}
|
||||
if o.AuthLoginDetailHandler == nil {
|
||||
unregistered = append(unregistered, "auth.LoginDetailHandler")
|
||||
}
|
||||
if o.AuthLogoutHandler == nil {
|
||||
unregistered = append(unregistered, "auth.LogoutHandler")
|
||||
}
|
||||
if o.BucketMakeBucketHandler == nil {
|
||||
unregistered = append(unregistered, "bucket.MakeBucketHandler")
|
||||
}
|
||||
if o.ObjectPostBucketsBucketNameObjectsUploadHandler == nil {
|
||||
unregistered = append(unregistered, "object.PostBucketsBucketNameObjectsUploadHandler")
|
||||
}
|
||||
if o.ObjectPutObjectRestoreHandler == nil {
|
||||
unregistered = append(unregistered, "object.PutObjectRestoreHandler")
|
||||
}
|
||||
if o.ObjectPutObjectTagsHandler == nil {
|
||||
unregistered = append(unregistered, "object.PutObjectTagsHandler")
|
||||
}
|
||||
if o.AuthSessionCheckHandler == nil {
|
||||
unregistered = append(unregistered, "auth.SessionCheckHandler")
|
||||
}
|
||||
if o.BucketSetBucketVersioningHandler == nil {
|
||||
unregistered = append(unregistered, "bucket.SetBucketVersioningHandler")
|
||||
}
|
||||
if o.ObjectShareObjectHandler == nil {
|
||||
unregistered = append(unregistered, "object.ShareObjectHandler")
|
||||
}
|
||||
|
||||
if len(unregistered) > 0 {
|
||||
return fmt.Errorf("missing registration: %s", strings.Join(unregistered, ", "))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ServeErrorFor gets a error handler for a given operation id
|
||||
func (o *ConsoleAPI) ServeErrorFor(operationID string) func(http.ResponseWriter, *http.Request, error) {
|
||||
return o.ServeError
|
||||
}
|
||||
|
||||
// AuthenticatorsFor gets the authenticators for the specified security schemes
|
||||
func (o *ConsoleAPI) AuthenticatorsFor(schemes map[string]spec.SecurityScheme) map[string]runtime.Authenticator {
|
||||
result := make(map[string]runtime.Authenticator)
|
||||
for name := range schemes {
|
||||
switch name {
|
||||
case "anonymous":
|
||||
scheme := schemes[name]
|
||||
result[name] = o.APIKeyAuthenticator(scheme.Name, scheme.In, func(token string) (interface{}, error) {
|
||||
return o.AnonymousAuth(token)
|
||||
})
|
||||
|
||||
case "key":
|
||||
result[name] = o.BearerAuthenticator(name, func(token string, scopes []string) (interface{}, error) {
|
||||
return o.KeyAuth(token, scopes)
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Authorizer returns the registered authorizer
|
||||
func (o *ConsoleAPI) Authorizer() runtime.Authorizer {
|
||||
return o.APIAuthorizer
|
||||
}
|
||||
|
||||
// ConsumersFor gets the consumers for the specified media types.
|
||||
// MIME type parameters are ignored here.
|
||||
func (o *ConsoleAPI) ConsumersFor(mediaTypes []string) map[string]runtime.Consumer {
|
||||
result := make(map[string]runtime.Consumer, len(mediaTypes))
|
||||
for _, mt := range mediaTypes {
|
||||
switch mt {
|
||||
case "application/json":
|
||||
result["application/json"] = o.JSONConsumer
|
||||
case "multipart/form-data":
|
||||
result["multipart/form-data"] = o.MultipartformConsumer
|
||||
}
|
||||
|
||||
if c, ok := o.customConsumers[mt]; ok {
|
||||
result[mt] = c
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// ProducersFor gets the producers for the specified media types.
|
||||
// MIME type parameters are ignored here.
|
||||
func (o *ConsoleAPI) ProducersFor(mediaTypes []string) map[string]runtime.Producer {
|
||||
result := make(map[string]runtime.Producer, len(mediaTypes))
|
||||
for _, mt := range mediaTypes {
|
||||
switch mt {
|
||||
case "application/octet-stream":
|
||||
result["application/octet-stream"] = o.BinProducer
|
||||
case "application/json":
|
||||
result["application/json"] = o.JSONProducer
|
||||
}
|
||||
|
||||
if p, ok := o.customProducers[mt]; ok {
|
||||
result[mt] = p
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// HandlerFor gets a http.Handler for the provided operation method and path
|
||||
func (o *ConsoleAPI) HandlerFor(method, path string) (http.Handler, bool) {
|
||||
if o.handlers == nil {
|
||||
return nil, false
|
||||
}
|
||||
um := strings.ToUpper(method)
|
||||
if _, ok := o.handlers[um]; !ok {
|
||||
return nil, false
|
||||
}
|
||||
if path == "/" {
|
||||
path = ""
|
||||
}
|
||||
h, ok := o.handlers[um][path]
|
||||
return h, ok
|
||||
}
|
||||
|
||||
// Context returns the middleware context for the console API
|
||||
func (o *ConsoleAPI) Context() *middleware.Context {
|
||||
if o.context == nil {
|
||||
o.context = middleware.NewRoutableContext(o.spec, o, nil)
|
||||
}
|
||||
|
||||
return o.context
|
||||
}
|
||||
|
||||
func (o *ConsoleAPI) initHandlerCache() {
|
||||
o.Context() // don't care about the result, just that the initialization happened
|
||||
if o.handlers == nil {
|
||||
o.handlers = make(map[string]map[string]http.Handler)
|
||||
}
|
||||
|
||||
if o.handlers["GET"] == nil {
|
||||
o.handlers["GET"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["GET"]["/admin/info"] = system.NewAdminInfo(o.context, o.SystemAdminInfoHandler)
|
||||
if o.handlers["GET"] == nil {
|
||||
o.handlers["GET"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["GET"]["/buckets/{name}"] = bucket.NewBucketInfo(o.context, o.BucketBucketInfoHandler)
|
||||
if o.handlers["POST"] == nil {
|
||||
o.handlers["POST"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["POST"]["/buckets/{bucket_name}/delete-objects"] = object.NewDeleteMultipleObjects(o.context, o.ObjectDeleteMultipleObjectsHandler)
|
||||
if o.handlers["DELETE"] == nil {
|
||||
o.handlers["DELETE"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["DELETE"]["/buckets/{bucket_name}/objects"] = object.NewDeleteObject(o.context, o.ObjectDeleteObjectHandler)
|
||||
if o.handlers["GET"] == nil {
|
||||
o.handlers["GET"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["GET"]["/buckets/{bucket_name}/objects/download"] = object.NewDownloadObject(o.context, o.ObjectDownloadObjectHandler)
|
||||
if o.handlers["POST"] == nil {
|
||||
o.handlers["POST"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["POST"]["/buckets/{bucket_name}/objects/download-multiple"] = object.NewDownloadMultipleObjects(o.context, o.ObjectDownloadMultipleObjectsHandler)
|
||||
if o.handlers["GET"] == nil {
|
||||
o.handlers["GET"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["GET"]["/download-shared-object/{url}"] = public.NewDownloadSharedObject(o.context, o.PublicDownloadSharedObjectHandler)
|
||||
if o.handlers["GET"] == nil {
|
||||
o.handlers["GET"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["GET"]["/buckets/{name}/quota"] = bucket.NewGetBucketQuota(o.context, o.BucketGetBucketQuotaHandler)
|
||||
if o.handlers["GET"] == nil {
|
||||
o.handlers["GET"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["GET"]["/buckets/{bucket_name}/rewind/{date}"] = bucket.NewGetBucketRewind(o.context, o.BucketGetBucketRewindHandler)
|
||||
if o.handlers["GET"] == nil {
|
||||
o.handlers["GET"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["GET"]["/buckets/{bucket_name}/versioning"] = bucket.NewGetBucketVersioning(o.context, o.BucketGetBucketVersioningHandler)
|
||||
if o.handlers["GET"] == nil {
|
||||
o.handlers["GET"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["GET"]["/buckets/max-share-exp"] = bucket.NewGetMaxShareLinkExp(o.context, o.BucketGetMaxShareLinkExpHandler)
|
||||
if o.handlers["GET"] == nil {
|
||||
o.handlers["GET"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["GET"]["/buckets/{bucket_name}/objects/metadata"] = object.NewGetObjectMetadata(o.context, o.ObjectGetObjectMetadataHandler)
|
||||
if o.handlers["GET"] == nil {
|
||||
o.handlers["GET"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["GET"]["/license/acknowledge"] = license.NewLicenseAcknowledge(o.context, o.LicenseLicenseAcknowledgeHandler)
|
||||
if o.handlers["GET"] == nil {
|
||||
o.handlers["GET"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["GET"]["/buckets"] = bucket.NewListBuckets(o.context, o.BucketListBucketsHandler)
|
||||
if o.handlers["GET"] == nil {
|
||||
o.handlers["GET"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["GET"]["/buckets/{bucket_name}/objects"] = object.NewListObjects(o.context, o.ObjectListObjectsHandler)
|
||||
if o.handlers["POST"] == nil {
|
||||
o.handlers["POST"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["POST"]["/login"] = auth.NewLogin(o.context, o.AuthLoginHandler)
|
||||
if o.handlers["GET"] == nil {
|
||||
o.handlers["GET"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["GET"]["/login"] = auth.NewLoginDetail(o.context, o.AuthLoginDetailHandler)
|
||||
if o.handlers["POST"] == nil {
|
||||
o.handlers["POST"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["POST"]["/logout"] = auth.NewLogout(o.context, o.AuthLogoutHandler)
|
||||
if o.handlers["POST"] == nil {
|
||||
o.handlers["POST"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["POST"]["/buckets"] = bucket.NewMakeBucket(o.context, o.BucketMakeBucketHandler)
|
||||
if o.handlers["POST"] == nil {
|
||||
o.handlers["POST"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["POST"]["/buckets/{bucket_name}/objects/upload"] = object.NewPostBucketsBucketNameObjectsUpload(o.context, o.ObjectPostBucketsBucketNameObjectsUploadHandler)
|
||||
if o.handlers["PUT"] == nil {
|
||||
o.handlers["PUT"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["PUT"]["/buckets/{bucket_name}/objects/restore"] = object.NewPutObjectRestore(o.context, o.ObjectPutObjectRestoreHandler)
|
||||
if o.handlers["PUT"] == nil {
|
||||
o.handlers["PUT"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["PUT"]["/buckets/{bucket_name}/objects/tags"] = object.NewPutObjectTags(o.context, o.ObjectPutObjectTagsHandler)
|
||||
if o.handlers["GET"] == nil {
|
||||
o.handlers["GET"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["GET"]["/session"] = auth.NewSessionCheck(o.context, o.AuthSessionCheckHandler)
|
||||
if o.handlers["PUT"] == nil {
|
||||
o.handlers["PUT"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["PUT"]["/buckets/{bucket_name}/versioning"] = bucket.NewSetBucketVersioning(o.context, o.BucketSetBucketVersioningHandler)
|
||||
if o.handlers["GET"] == nil {
|
||||
o.handlers["GET"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["GET"]["/buckets/{bucket_name}/objects/share"] = object.NewShareObject(o.context, o.ObjectShareObjectHandler)
|
||||
}
|
||||
|
||||
// Serve creates a http handler to serve the API over HTTP
|
||||
// can be used directly in http.ListenAndServe(":8000", api.Serve(nil))
|
||||
func (o *ConsoleAPI) Serve(builder middleware.Builder) http.Handler {
|
||||
o.Init()
|
||||
|
||||
if o.Middleware != nil {
|
||||
return o.Middleware(builder)
|
||||
}
|
||||
if o.useSwaggerUI {
|
||||
return o.context.APIHandlerSwaggerUI(builder)
|
||||
}
|
||||
return o.context.APIHandler(builder)
|
||||
}
|
||||
|
||||
// Init allows you to just initialize the handler cache, you can then recompose the middleware as you see fit
|
||||
func (o *ConsoleAPI) Init() {
|
||||
if len(o.handlers) == 0 {
|
||||
o.initHandlerCache()
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterConsumer allows you to add (or override) a consumer for a media type.
|
||||
func (o *ConsoleAPI) RegisterConsumer(mediaType string, consumer runtime.Consumer) {
|
||||
o.customConsumers[mediaType] = consumer
|
||||
}
|
||||
|
||||
// RegisterProducer allows you to add (or override) a producer for a media type.
|
||||
func (o *ConsoleAPI) RegisterProducer(mediaType string, producer runtime.Producer) {
|
||||
o.customProducers[mediaType] = producer
|
||||
}
|
||||
|
||||
// AddMiddlewareFor adds a http middleware to existing handler
|
||||
func (o *ConsoleAPI) AddMiddlewareFor(method, path string, builder middleware.Builder) {
|
||||
um := strings.ToUpper(method)
|
||||
if path == "/" {
|
||||
path = ""
|
||||
}
|
||||
o.Init()
|
||||
if h, ok := o.handlers[um][path]; ok {
|
||||
o.handlers[um][path] = builder(h)
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
package idp
|
||||
package license
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the generate command
|
||||
@@ -30,40 +30,40 @@ import (
|
||||
"github.com/minio/console/models"
|
||||
)
|
||||
|
||||
// ListConfigurationsHandlerFunc turns a function with the right signature into a list configurations handler
|
||||
type ListConfigurationsHandlerFunc func(ListConfigurationsParams, *models.Principal) middleware.Responder
|
||||
// LicenseAcknowledgeHandlerFunc turns a function with the right signature into a license acknowledge handler
|
||||
type LicenseAcknowledgeHandlerFunc func(LicenseAcknowledgeParams, *models.Principal) middleware.Responder
|
||||
|
||||
// Handle executing the request and returning a response
|
||||
func (fn ListConfigurationsHandlerFunc) Handle(params ListConfigurationsParams, principal *models.Principal) middleware.Responder {
|
||||
func (fn LicenseAcknowledgeHandlerFunc) Handle(params LicenseAcknowledgeParams, principal *models.Principal) middleware.Responder {
|
||||
return fn(params, principal)
|
||||
}
|
||||
|
||||
// ListConfigurationsHandler interface for that can handle valid list configurations params
|
||||
type ListConfigurationsHandler interface {
|
||||
Handle(ListConfigurationsParams, *models.Principal) middleware.Responder
|
||||
// LicenseAcknowledgeHandler interface for that can handle valid license acknowledge params
|
||||
type LicenseAcknowledgeHandler interface {
|
||||
Handle(LicenseAcknowledgeParams, *models.Principal) middleware.Responder
|
||||
}
|
||||
|
||||
// NewListConfigurations creates a new http.Handler for the list configurations operation
|
||||
func NewListConfigurations(ctx *middleware.Context, handler ListConfigurationsHandler) *ListConfigurations {
|
||||
return &ListConfigurations{Context: ctx, Handler: handler}
|
||||
// NewLicenseAcknowledge creates a new http.Handler for the license acknowledge operation
|
||||
func NewLicenseAcknowledge(ctx *middleware.Context, handler LicenseAcknowledgeHandler) *LicenseAcknowledge {
|
||||
return &LicenseAcknowledge{Context: ctx, Handler: handler}
|
||||
}
|
||||
|
||||
/*
|
||||
ListConfigurations swagger:route GET /idp/{type} idp listConfigurations
|
||||
LicenseAcknowledge swagger:route GET /license/acknowledge License licenseAcknowledge
|
||||
|
||||
List IDP Configurations
|
||||
Acknowledge the license
|
||||
*/
|
||||
type ListConfigurations struct {
|
||||
type LicenseAcknowledge struct {
|
||||
Context *middleware.Context
|
||||
Handler ListConfigurationsHandler
|
||||
Handler LicenseAcknowledgeHandler
|
||||
}
|
||||
|
||||
func (o *ListConfigurations) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||
func (o *LicenseAcknowledge) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||
route, rCtx, _ := o.Context.RouteInfo(r)
|
||||
if rCtx != nil {
|
||||
*r = *rCtx
|
||||
}
|
||||
var Params = NewListConfigurationsParams()
|
||||
var Params = NewLicenseAcknowledgeParams()
|
||||
uprinc, aCtx, err := o.Context.Authorize(r, route)
|
||||
if err != nil {
|
||||
o.Context.Respond(rw, r, route.Produces, route, err)
|
||||
@@ -17,7 +17,7 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
package configuration
|
||||
package license
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
@@ -29,19 +29,19 @@ import (
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
)
|
||||
|
||||
// NewExportConfigParams creates a new ExportConfigParams object
|
||||
// NewLicenseAcknowledgeParams creates a new LicenseAcknowledgeParams object
|
||||
//
|
||||
// There are no default values defined in the spec.
|
||||
func NewExportConfigParams() ExportConfigParams {
|
||||
func NewLicenseAcknowledgeParams() LicenseAcknowledgeParams {
|
||||
|
||||
return ExportConfigParams{}
|
||||
return LicenseAcknowledgeParams{}
|
||||
}
|
||||
|
||||
// ExportConfigParams contains all the bound params for the export config operation
|
||||
// LicenseAcknowledgeParams contains all the bound params for the license acknowledge operation
|
||||
// typically these are obtained from a http.Request
|
||||
//
|
||||
// swagger:parameters ExportConfig
|
||||
type ExportConfigParams struct {
|
||||
// swagger:parameters LicenseAcknowledge
|
||||
type LicenseAcknowledgeParams struct {
|
||||
|
||||
// HTTP Request Object
|
||||
HTTPRequest *http.Request `json:"-"`
|
||||
@@ -50,8 +50,8 @@ type ExportConfigParams struct {
|
||||
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
|
||||
// for simple values it will use straight method calls.
|
||||
//
|
||||
// To ensure default values, the struct must have been initialized with NewExportConfigParams() beforehand.
|
||||
func (o *ExportConfigParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
|
||||
// To ensure default values, the struct must have been initialized with NewLicenseAcknowledgeParams() beforehand.
|
||||
func (o *LicenseAcknowledgeParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
|
||||
var res []error
|
||||
|
||||
o.HTTPRequest = r
|
||||
@@ -17,7 +17,7 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
package object
|
||||
package license
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
@@ -30,25 +30,25 @@ import (
|
||||
"github.com/minio/console/models"
|
||||
)
|
||||
|
||||
// PutObjectRetentionOKCode is the HTTP code returned for type PutObjectRetentionOK
|
||||
const PutObjectRetentionOKCode int = 200
|
||||
// LicenseAcknowledgeOKCode is the HTTP code returned for type LicenseAcknowledgeOK
|
||||
const LicenseAcknowledgeOKCode int = 200
|
||||
|
||||
/*
|
||||
PutObjectRetentionOK A successful response.
|
||||
LicenseAcknowledgeOK A successful response.
|
||||
|
||||
swagger:response putObjectRetentionOK
|
||||
swagger:response licenseAcknowledgeOK
|
||||
*/
|
||||
type PutObjectRetentionOK struct {
|
||||
type LicenseAcknowledgeOK struct {
|
||||
}
|
||||
|
||||
// NewPutObjectRetentionOK creates PutObjectRetentionOK with default headers values
|
||||
func NewPutObjectRetentionOK() *PutObjectRetentionOK {
|
||||
// NewLicenseAcknowledgeOK creates LicenseAcknowledgeOK with default headers values
|
||||
func NewLicenseAcknowledgeOK() *LicenseAcknowledgeOK {
|
||||
|
||||
return &PutObjectRetentionOK{}
|
||||
return &LicenseAcknowledgeOK{}
|
||||
}
|
||||
|
||||
// WriteResponse to the client
|
||||
func (o *PutObjectRetentionOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
|
||||
func (o *LicenseAcknowledgeOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
|
||||
|
||||
rw.Header().Del(runtime.HeaderContentType) //Remove Content-Type on empty responses
|
||||
|
||||
@@ -56,54 +56,54 @@ func (o *PutObjectRetentionOK) WriteResponse(rw http.ResponseWriter, producer ru
|
||||
}
|
||||
|
||||
/*
|
||||
PutObjectRetentionDefault Generic error response.
|
||||
LicenseAcknowledgeDefault Generic error response.
|
||||
|
||||
swagger:response putObjectRetentionDefault
|
||||
swagger:response licenseAcknowledgeDefault
|
||||
*/
|
||||
type PutObjectRetentionDefault struct {
|
||||
type LicenseAcknowledgeDefault struct {
|
||||
_statusCode int
|
||||
|
||||
/*
|
||||
In: Body
|
||||
*/
|
||||
Payload *models.Error `json:"body,omitempty"`
|
||||
Payload *models.APIError `json:"body,omitempty"`
|
||||
}
|
||||
|
||||
// NewPutObjectRetentionDefault creates PutObjectRetentionDefault with default headers values
|
||||
func NewPutObjectRetentionDefault(code int) *PutObjectRetentionDefault {
|
||||
// NewLicenseAcknowledgeDefault creates LicenseAcknowledgeDefault with default headers values
|
||||
func NewLicenseAcknowledgeDefault(code int) *LicenseAcknowledgeDefault {
|
||||
if code <= 0 {
|
||||
code = 500
|
||||
}
|
||||
|
||||
return &PutObjectRetentionDefault{
|
||||
return &LicenseAcknowledgeDefault{
|
||||
_statusCode: code,
|
||||
}
|
||||
}
|
||||
|
||||
// WithStatusCode adds the status to the put object retention default response
|
||||
func (o *PutObjectRetentionDefault) WithStatusCode(code int) *PutObjectRetentionDefault {
|
||||
// WithStatusCode adds the status to the license acknowledge default response
|
||||
func (o *LicenseAcknowledgeDefault) WithStatusCode(code int) *LicenseAcknowledgeDefault {
|
||||
o._statusCode = code
|
||||
return o
|
||||
}
|
||||
|
||||
// SetStatusCode sets the status to the put object retention default response
|
||||
func (o *PutObjectRetentionDefault) SetStatusCode(code int) {
|
||||
// SetStatusCode sets the status to the license acknowledge default response
|
||||
func (o *LicenseAcknowledgeDefault) SetStatusCode(code int) {
|
||||
o._statusCode = code
|
||||
}
|
||||
|
||||
// WithPayload adds the payload to the put object retention default response
|
||||
func (o *PutObjectRetentionDefault) WithPayload(payload *models.Error) *PutObjectRetentionDefault {
|
||||
// WithPayload adds the payload to the license acknowledge default response
|
||||
func (o *LicenseAcknowledgeDefault) WithPayload(payload *models.APIError) *LicenseAcknowledgeDefault {
|
||||
o.Payload = payload
|
||||
return o
|
||||
}
|
||||
|
||||
// SetPayload sets the payload to the put object retention default response
|
||||
func (o *PutObjectRetentionDefault) SetPayload(payload *models.Error) {
|
||||
// SetPayload sets the payload to the license acknowledge default response
|
||||
func (o *LicenseAcknowledgeDefault) SetPayload(payload *models.APIError) {
|
||||
o.Payload = payload
|
||||
}
|
||||
|
||||
// WriteResponse to the client
|
||||
func (o *PutObjectRetentionDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
|
||||
func (o *LicenseAcknowledgeDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
|
||||
|
||||
rw.WriteHeader(o._statusCode)
|
||||
if o.Payload != nil {
|
||||
@@ -17,7 +17,7 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
package auth
|
||||
package license
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the generate command
|
||||
@@ -28,15 +28,15 @@ import (
|
||||
golangswaggerpaths "path"
|
||||
)
|
||||
|
||||
// LoginOauth2AuthURL generates an URL for the login oauth2 auth operation
|
||||
type LoginOauth2AuthURL struct {
|
||||
// LicenseAcknowledgeURL generates an URL for the license acknowledge operation
|
||||
type LicenseAcknowledgeURL struct {
|
||||
_basePath string
|
||||
}
|
||||
|
||||
// WithBasePath sets the base path for this url builder, only required when it's different from the
|
||||
// base path specified in the swagger spec.
|
||||
// When the value of the base path is an empty string
|
||||
func (o *LoginOauth2AuthURL) WithBasePath(bp string) *LoginOauth2AuthURL {
|
||||
func (o *LicenseAcknowledgeURL) WithBasePath(bp string) *LicenseAcknowledgeURL {
|
||||
o.SetBasePath(bp)
|
||||
return o
|
||||
}
|
||||
@@ -44,15 +44,15 @@ func (o *LoginOauth2AuthURL) WithBasePath(bp string) *LoginOauth2AuthURL {
|
||||
// SetBasePath sets the base path for this url builder, only required when it's different from the
|
||||
// base path specified in the swagger spec.
|
||||
// When the value of the base path is an empty string
|
||||
func (o *LoginOauth2AuthURL) SetBasePath(bp string) {
|
||||
func (o *LicenseAcknowledgeURL) SetBasePath(bp string) {
|
||||
o._basePath = bp
|
||||
}
|
||||
|
||||
// Build a url path and query string
|
||||
func (o *LoginOauth2AuthURL) Build() (*url.URL, error) {
|
||||
func (o *LicenseAcknowledgeURL) Build() (*url.URL, error) {
|
||||
var _result url.URL
|
||||
|
||||
var _path = "/login/oauth2/auth"
|
||||
var _path = "/license/acknowledge"
|
||||
|
||||
_basePath := o._basePath
|
||||
if _basePath == "" {
|
||||
@@ -64,7 +64,7 @@ func (o *LoginOauth2AuthURL) Build() (*url.URL, error) {
|
||||
}
|
||||
|
||||
// Must is a helper function to panic when the url builder returns an error
|
||||
func (o *LoginOauth2AuthURL) Must(u *url.URL, err error) *url.URL {
|
||||
func (o *LicenseAcknowledgeURL) Must(u *url.URL, err error) *url.URL {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -75,17 +75,17 @@ func (o *LoginOauth2AuthURL) Must(u *url.URL, err error) *url.URL {
|
||||
}
|
||||
|
||||
// String returns the string representation of the path with query string
|
||||
func (o *LoginOauth2AuthURL) String() string {
|
||||
func (o *LicenseAcknowledgeURL) String() string {
|
||||
return o.Must(o.Build()).String()
|
||||
}
|
||||
|
||||
// BuildFull builds a full url with scheme, host, path and query string
|
||||
func (o *LoginOauth2AuthURL) BuildFull(scheme, host string) (*url.URL, error) {
|
||||
func (o *LicenseAcknowledgeURL) BuildFull(scheme, host string) (*url.URL, error) {
|
||||
if scheme == "" {
|
||||
return nil, errors.New("scheme is required for a full url on LoginOauth2AuthURL")
|
||||
return nil, errors.New("scheme is required for a full url on LicenseAcknowledgeURL")
|
||||
}
|
||||
if host == "" {
|
||||
return nil, errors.New("host is required for a full url on LoginOauth2AuthURL")
|
||||
return nil, errors.New("host is required for a full url on LicenseAcknowledgeURL")
|
||||
}
|
||||
|
||||
base, err := o.Build()
|
||||
@@ -99,6 +99,6 @@ func (o *LoginOauth2AuthURL) BuildFull(scheme, host string) (*url.URL, error) {
|
||||
}
|
||||
|
||||
// StringFull returns the string representation of a complete url
|
||||
func (o *LoginOauth2AuthURL) StringFull(scheme, host string) string {
|
||||
func (o *LicenseAcknowledgeURL) StringFull(scheme, host string) string {
|
||||
return o.Must(o.BuildFull(scheme, host)).String()
|
||||
}
|
||||
@@ -66,7 +66,7 @@ type DeleteMultipleObjectsDefault struct {
|
||||
/*
|
||||
In: Body
|
||||
*/
|
||||
Payload *models.Error `json:"body,omitempty"`
|
||||
Payload *models.APIError `json:"body,omitempty"`
|
||||
}
|
||||
|
||||
// NewDeleteMultipleObjectsDefault creates DeleteMultipleObjectsDefault with default headers values
|
||||
@@ -92,13 +92,13 @@ func (o *DeleteMultipleObjectsDefault) SetStatusCode(code int) {
|
||||
}
|
||||
|
||||
// WithPayload adds the payload to the delete multiple objects default response
|
||||
func (o *DeleteMultipleObjectsDefault) WithPayload(payload *models.Error) *DeleteMultipleObjectsDefault {
|
||||
func (o *DeleteMultipleObjectsDefault) WithPayload(payload *models.APIError) *DeleteMultipleObjectsDefault {
|
||||
o.Payload = payload
|
||||
return o
|
||||
}
|
||||
|
||||
// SetPayload sets the payload to the delete multiple objects default response
|
||||
func (o *DeleteMultipleObjectsDefault) SetPayload(payload *models.Error) {
|
||||
func (o *DeleteMultipleObjectsDefault) SetPayload(payload *models.APIError) {
|
||||
o.Payload = payload
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ type DeleteObjectParams struct {
|
||||
Required: true
|
||||
In: query
|
||||
*/
|
||||
Path string
|
||||
Prefix string
|
||||
/*
|
||||
In: query
|
||||
*/
|
||||
@@ -113,8 +113,8 @@ func (o *DeleteObjectParams) BindRequest(r *http.Request, route *middleware.Matc
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
qPath, qhkPath, _ := qs.GetOK("path")
|
||||
if err := o.bindPath(qPath, qhkPath, route.Formats); err != nil {
|
||||
qPrefix, qhkPrefix, _ := qs.GetOK("prefix")
|
||||
if err := o.bindPrefix(qPrefix, qhkPrefix, route.Formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
@@ -216,10 +216,10 @@ func (o *DeleteObjectParams) bindNonCurrentVersions(rawData []string, hasKey boo
|
||||
return nil
|
||||
}
|
||||
|
||||
// bindPath binds and validates parameter Path from query.
|
||||
func (o *DeleteObjectParams) bindPath(rawData []string, hasKey bool, formats strfmt.Registry) error {
|
||||
// bindPrefix binds and validates parameter Prefix from query.
|
||||
func (o *DeleteObjectParams) bindPrefix(rawData []string, hasKey bool, formats strfmt.Registry) error {
|
||||
if !hasKey {
|
||||
return errors.Required("path", "query", rawData)
|
||||
return errors.Required("prefix", "query", rawData)
|
||||
}
|
||||
var raw string
|
||||
if len(rawData) > 0 {
|
||||
@@ -229,10 +229,10 @@ func (o *DeleteObjectParams) bindPath(rawData []string, hasKey bool, formats str
|
||||
// Required: true
|
||||
// AllowEmptyValue: false
|
||||
|
||||
if err := validate.RequiredString("path", "query", raw); err != nil {
|
||||
if err := validate.RequiredString("prefix", "query", raw); err != nil {
|
||||
return err
|
||||
}
|
||||
o.Path = raw
|
||||
o.Prefix = raw
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -66,7 +66,7 @@ type DeleteObjectDefault struct {
|
||||
/*
|
||||
In: Body
|
||||
*/
|
||||
Payload *models.Error `json:"body,omitempty"`
|
||||
Payload *models.APIError `json:"body,omitempty"`
|
||||
}
|
||||
|
||||
// NewDeleteObjectDefault creates DeleteObjectDefault with default headers values
|
||||
@@ -92,13 +92,13 @@ func (o *DeleteObjectDefault) SetStatusCode(code int) {
|
||||
}
|
||||
|
||||
// WithPayload adds the payload to the delete object default response
|
||||
func (o *DeleteObjectDefault) WithPayload(payload *models.Error) *DeleteObjectDefault {
|
||||
func (o *DeleteObjectDefault) WithPayload(payload *models.APIError) *DeleteObjectDefault {
|
||||
o.Payload = payload
|
||||
return o
|
||||
}
|
||||
|
||||
// SetPayload sets the payload to the delete object default response
|
||||
func (o *DeleteObjectDefault) SetPayload(payload *models.Error) {
|
||||
func (o *DeleteObjectDefault) SetPayload(payload *models.APIError) {
|
||||
o.Payload = payload
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ type DeleteObjectURL struct {
|
||||
AllVersions *bool
|
||||
Bypass *bool
|
||||
NonCurrentVersions *bool
|
||||
Path string
|
||||
Prefix string
|
||||
Recursive *bool
|
||||
VersionID *string
|
||||
|
||||
@@ -107,9 +107,9 @@ func (o *DeleteObjectURL) Build() (*url.URL, error) {
|
||||
qs.Set("non_current_versions", nonCurrentVersionsQ)
|
||||
}
|
||||
|
||||
pathQ := o.Path
|
||||
if pathQ != "" {
|
||||
qs.Set("path", pathQ)
|
||||
prefixQ := o.Prefix
|
||||
if prefixQ != "" {
|
||||
qs.Set("prefix", prefixQ)
|
||||
}
|
||||
|
||||
var recursiveQ string
|
||||
@@ -17,7 +17,7 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
package bucket
|
||||
package object
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the generate command
|
||||
@@ -30,40 +30,40 @@ import (
|
||||
"github.com/minio/console/models"
|
||||
)
|
||||
|
||||
// DisableBucketEncryptionHandlerFunc turns a function with the right signature into a disable bucket encryption handler
|
||||
type DisableBucketEncryptionHandlerFunc func(DisableBucketEncryptionParams, *models.Principal) middleware.Responder
|
||||
// DownloadMultipleObjectsHandlerFunc turns a function with the right signature into a download multiple objects handler
|
||||
type DownloadMultipleObjectsHandlerFunc func(DownloadMultipleObjectsParams, *models.Principal) middleware.Responder
|
||||
|
||||
// Handle executing the request and returning a response
|
||||
func (fn DisableBucketEncryptionHandlerFunc) Handle(params DisableBucketEncryptionParams, principal *models.Principal) middleware.Responder {
|
||||
func (fn DownloadMultipleObjectsHandlerFunc) Handle(params DownloadMultipleObjectsParams, principal *models.Principal) middleware.Responder {
|
||||
return fn(params, principal)
|
||||
}
|
||||
|
||||
// DisableBucketEncryptionHandler interface for that can handle valid disable bucket encryption params
|
||||
type DisableBucketEncryptionHandler interface {
|
||||
Handle(DisableBucketEncryptionParams, *models.Principal) middleware.Responder
|
||||
// DownloadMultipleObjectsHandler interface for that can handle valid download multiple objects params
|
||||
type DownloadMultipleObjectsHandler interface {
|
||||
Handle(DownloadMultipleObjectsParams, *models.Principal) middleware.Responder
|
||||
}
|
||||
|
||||
// NewDisableBucketEncryption creates a new http.Handler for the disable bucket encryption operation
|
||||
func NewDisableBucketEncryption(ctx *middleware.Context, handler DisableBucketEncryptionHandler) *DisableBucketEncryption {
|
||||
return &DisableBucketEncryption{Context: ctx, Handler: handler}
|
||||
// NewDownloadMultipleObjects creates a new http.Handler for the download multiple objects operation
|
||||
func NewDownloadMultipleObjects(ctx *middleware.Context, handler DownloadMultipleObjectsHandler) *DownloadMultipleObjects {
|
||||
return &DownloadMultipleObjects{Context: ctx, Handler: handler}
|
||||
}
|
||||
|
||||
/*
|
||||
DisableBucketEncryption swagger:route POST /buckets/{bucket_name}/encryption/disable Bucket disableBucketEncryption
|
||||
DownloadMultipleObjects swagger:route POST /buckets/{bucket_name}/objects/download-multiple Object downloadMultipleObjects
|
||||
|
||||
Disable bucket encryption.
|
||||
Download Multiple Objects
|
||||
*/
|
||||
type DisableBucketEncryption struct {
|
||||
type DownloadMultipleObjects struct {
|
||||
Context *middleware.Context
|
||||
Handler DisableBucketEncryptionHandler
|
||||
Handler DownloadMultipleObjectsHandler
|
||||
}
|
||||
|
||||
func (o *DisableBucketEncryption) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||
func (o *DownloadMultipleObjects) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||
route, rCtx, _ := o.Context.RouteInfo(r)
|
||||
if rCtx != nil {
|
||||
*r = *rCtx
|
||||
}
|
||||
var Params = NewDisableBucketEncryptionParams()
|
||||
var Params = NewDownloadMultipleObjectsParams()
|
||||
uprinc, aCtx, err := o.Context.Authorize(r, route)
|
||||
if err != nil {
|
||||
o.Context.Respond(rw, r, route.Produces, route, err)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user