Compare commits
93 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48e6b1bb7c | ||
|
|
8949fbe245 | ||
|
|
d8e6bd7f4a | ||
|
|
4edfeb22c6 | ||
|
|
2d5d0d16ca | ||
|
|
16f8ee485a | ||
|
|
2d28f8bf35 | ||
|
|
8af3665ae2 | ||
|
|
0fa1d4bf7c | ||
|
|
8139416323 | ||
|
|
be5cd7f148 | ||
|
|
fa068b6d4a | ||
|
|
a805a49662 | ||
|
|
296e4ff5ce | ||
|
|
20749d2eae | ||
|
|
ff4e959d11 | ||
|
|
37195fefa8 | ||
|
|
13ef83cee4 | ||
|
|
b89b2d0c6a | ||
|
|
edf687fd8a | ||
|
|
cb60eba373 | ||
|
|
c49a7bbe3c | ||
|
|
3bb317535c | ||
|
|
989e6f3471 | ||
|
|
35d575e7ac | ||
|
|
92a8aab07d | ||
|
|
c5b2419191 | ||
|
|
732e0ef683 | ||
|
|
e8491d80cb | ||
|
|
35c3b53a23 | ||
|
|
6fef30f29d | ||
|
|
acf480fd25 | ||
|
|
8bbc4f0192 | ||
|
|
48e7991f11 | ||
|
|
5e9b0652b0 | ||
|
|
438211199d | ||
|
|
0f77a32656 | ||
|
|
9f3e99ede8 | ||
|
|
a8c07c0969 | ||
|
|
cf8472b04c | ||
|
|
317a7ebbd3 | ||
|
|
63f4150232 | ||
|
|
3bfc2556fc | ||
|
|
511cc47d2b | ||
|
|
9660650f41 | ||
|
|
9ac754d4de | ||
|
|
646318e1f6 | ||
|
|
beb1ac7d04 | ||
|
|
f3a9311374 | ||
|
|
44d8e9b975 | ||
|
|
f3d7e61ddb | ||
|
|
526c0f4796 | ||
|
|
fe1acaa4b6 | ||
|
|
8e9bd8728a | ||
|
|
9df9309c66 | ||
|
|
b85712e29e | ||
|
|
c32df86c76 | ||
|
|
0f52136fd2 | ||
|
|
605b80037a | ||
|
|
63b430e354 | ||
|
|
d9c212fe2f | ||
|
|
5fa0a0fca8 | ||
|
|
068ac281ea | ||
|
|
0bcf88eb7c | ||
|
|
5c137a8678 | ||
|
|
540ff31784 | ||
|
|
82ea3c1ac4 | ||
|
|
e1f177257a | ||
|
|
0211827c74 | ||
|
|
ac5732970c | ||
|
|
1b1ed55252 | ||
|
|
5c5e84b289 | ||
|
|
5755b98b66 | ||
|
|
86ee1eea6d | ||
|
|
adcbf61049 | ||
|
|
e197399441 | ||
|
|
ff2438a877 | ||
|
|
c85067dfba | ||
|
|
b1df170d80 | ||
|
|
9566f6e579 | ||
|
|
12a682e9f6 | ||
|
|
e0bb098e47 | ||
|
|
b390ce309a | ||
|
|
3dac86d3ce | ||
|
|
2001ab6dae | ||
|
|
31f0655ff6 | ||
|
|
775874cf86 | ||
|
|
9ca4daa906 | ||
|
|
2318a8a82b | ||
|
|
69ed6f5ca4 | ||
|
|
3a96e6d7e7 | ||
|
|
9a2b10476c | ||
|
|
c8938dc131 |
@@ -3,3 +3,4 @@ dist/
|
||||
target/
|
||||
mcs
|
||||
!mcs/
|
||||
portal-ui/node_modules/
|
||||
|
||||
12
.github/workflows/go.yml
vendored
@@ -14,25 +14,23 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.14.x]
|
||||
go-version: [1.13.x, 1.14.x]
|
||||
os: [ubuntu-latest]
|
||||
steps:
|
||||
- name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }}
|
||||
uses: actions/setup-go@v1
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v1
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Build on ${{ matrix.os }}
|
||||
env:
|
||||
GO111MODULE: on
|
||||
GOOS: linux
|
||||
run: |
|
||||
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.21.0
|
||||
$(go env GOPATH)/bin/golangci-lint run --timeout=5m --config ./.golangci.yml
|
||||
go mod vendor
|
||||
go test -v -race ./...
|
||||
make verifiers
|
||||
make test
|
||||
make mcs
|
||||
|
||||
48
.github/workflows/release.yml
vendored
@@ -1,48 +0,0 @@
|
||||
name: goreleaser
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
|
||||
jobs:
|
||||
goreleaser:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
-
|
||||
name: Unshallow
|
||||
run: git fetch --prune --unshallow
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.14.x
|
||||
-
|
||||
name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@53acad1befee355d46f71cccf6ab4d885eb4f77f
|
||||
with:
|
||||
version: latest
|
||||
args: release --skip-publish --rm-dist --snapshot
|
||||
-
|
||||
name: Upload Win64 Binaries
|
||||
uses: actions/upload-artifact@v1
|
||||
if: success()
|
||||
with:
|
||||
name: MCS-Snapshot-Build-Win64
|
||||
path: dist/mcs_windows_amd64
|
||||
-
|
||||
name: Upload Linux Binaries
|
||||
uses: actions/upload-artifact@v1
|
||||
if: success()
|
||||
with:
|
||||
name: MCS-Snapshot-Build-Linux-amd64
|
||||
path: dist/mcs_linux_amd64
|
||||
-
|
||||
name: Upload MacOS Binaries
|
||||
uses: actions/upload-artifact@v1
|
||||
if: success()
|
||||
with:
|
||||
name: MCS-Snapshot-Build-MacOSX-amd64
|
||||
path: dist/mcs_darwin_amd64
|
||||
10
.gitignore
vendored
@@ -6,6 +6,7 @@
|
||||
*.dylib
|
||||
.DS_Store
|
||||
*.swp
|
||||
*.orig
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
@@ -22,3 +23,12 @@ mcs
|
||||
!mcs/
|
||||
|
||||
dist/
|
||||
|
||||
# Ignore tls cert and key
|
||||
private.key
|
||||
public.crt
|
||||
|
||||
# Ignore VsCode files
|
||||
.vscode/
|
||||
*.code-workspace
|
||||
*~
|
||||
@@ -1,4 +1,7 @@
|
||||
linters-settings:
|
||||
golint:
|
||||
min-confidence: 0
|
||||
|
||||
misspell:
|
||||
locale: US
|
||||
|
||||
@@ -14,4 +17,8 @@ linters:
|
||||
- gosimple
|
||||
- deadcode
|
||||
- unparam
|
||||
- unused
|
||||
- structcheck
|
||||
|
||||
service:
|
||||
golangci-lint-version: 1.21.0 # use the fixed version to not introduce new linters unexpectedly
|
||||
|
||||
@@ -23,7 +23,7 @@ builds:
|
||||
- -trimpath
|
||||
- --tags=kqueue
|
||||
ldflags:
|
||||
- -s -w -X github.com/minio/mcs/pkg.ReleaseTag={{.Tag}} -X github.com/minio/warp/pkg.CommitID={{.FullCommit}} -X github.com/minio/warp/pkg.Version={{.Version}} -X github.com/minio/warp/pkg.ShortCommitID={{.ShortCommit}} -X github.com/minio/warp/pkg.ReleaseTime={{.Date}}
|
||||
- -s -w -X github.com/minio/mcs/pkg.ReleaseTag={{.Tag}} -X github.com/minio/mcs/pkg.CommitID={{.FullCommit}} -X github.com/minio/mcs/pkg.Version={{.Version}} -X github.com/minio/mcs/pkg.ShortCommitID={{.ShortCommit}} -X github.com/minio/mcs/pkg.ReleaseTime={{.Date}}
|
||||
archives:
|
||||
-
|
||||
replacements:
|
||||
|
||||
59
CONTRIBUTING.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# MinIO Console Server Contribution Guide [](https://slack.min.io)
|
||||
|
||||
This is a REST portal server created using [go-swagger](https://github.com/go-swagger/go-swagger)
|
||||
|
||||
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.
|
||||
|
||||
## 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_mcs.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.
|
||||
|
||||
To run tests:
|
||||
```
|
||||
go test ./restapi
|
||||
```
|
||||
|
||||
## 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
|
||||
|
||||
```
|
||||
$ 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.
|
||||
|
||||
## FAQs
|
||||
### How does ``mcs`` 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 mcs?
|
||||
``mcs`` 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).
|
||||
127
DEVELOPMENT.md
Normal file
@@ -0,0 +1,127 @@
|
||||
# LDAP authentication with MCS
|
||||
|
||||
## Setup
|
||||
|
||||
Run openLDAP with docker.
|
||||
|
||||
```
|
||||
$ docker run --rm -p 389:389 -p 636:636 --name my-openldap-container --detach osixia/openldap:1.3.0
|
||||
```
|
||||
|
||||
Run the `billy.ldif` file using `ldapadd` command to create a new user and assign it to a group.
|
||||
|
||||
```
|
||||
$ cat > billy.ldif << EOF
|
||||
# LDIF fragment to create group branch under root
|
||||
dn: uid=billy,dc=example,dc=org
|
||||
uid: billy
|
||||
cn: billy
|
||||
sn: 3
|
||||
objectClass: top
|
||||
objectClass: posixAccount
|
||||
objectClass: inetOrgPerson
|
||||
loginShell: /bin/bash
|
||||
homeDirectory: /home/billy
|
||||
uidNumber: 14583102
|
||||
gidNumber: 14564100
|
||||
userPassword: {SSHA}j3lBh1Seqe4rqF1+NuWmjhvtAni1JC5A
|
||||
mail: billy@example.org
|
||||
gecos: Billy User
|
||||
# Create base group
|
||||
dn: ou=groups,dc=example,dc=org
|
||||
objectclass:organizationalunit
|
||||
ou: groups
|
||||
description: generic groups branch
|
||||
# create mcsAdmin group (this already exists on minio and have a policy of s3::*)
|
||||
dn: cn=mcsAdmin,ou=groups,dc=example,dc=org
|
||||
objectClass: top
|
||||
objectClass: posixGroup
|
||||
gidNumber: 678
|
||||
# Assing group to new user
|
||||
dn: cn=mcsAdmin,ou=groups,dc=example,dc=org
|
||||
changetype: modify
|
||||
add: memberuid
|
||||
memberuid: billy
|
||||
EOF
|
||||
|
||||
$ docker cp billy.ldif my-openldap-container:/container/service/slapd/assets/test/billy.ldif
|
||||
$ docker exec my-openldap-container ldapadd -x -D "cn=admin,dc=example,dc=org" -w admin -f /container/service/slapd/assets/test/billy.ldif -H ldap://localhost -ZZ
|
||||
```
|
||||
|
||||
Query the ldap server to check the user billy was created correctly and got assigned to the mcsAdmin group, you should get a list
|
||||
containing ldap users and groups.
|
||||
|
||||
```
|
||||
$ docker exec my-openldap-container ldapsearch -x -H ldap://localhost -b dc=example,dc=org -D "cn=admin,dc=example,dc=org" -w admin
|
||||
```
|
||||
|
||||
Query the ldap server again, this time filtering only for the user `billy`, you should see only 1 record.
|
||||
|
||||
```
|
||||
$ docker exec my-openldap-container ldapsearch -x -H ldap://localhost -b uid=billy,dc=example,dc=org -D "cn=admin,dc=example,dc=org" -w admin
|
||||
```
|
||||
|
||||
### Change the password for user billy
|
||||
|
||||
Set the new password for `billy` to `minio123` and enter `admin` as the default `LDAP Password`
|
||||
|
||||
```
|
||||
$ docker exec -it my-openldap-container /bin/bash
|
||||
# ldappasswd -H ldap://localhost -x -D "cn=admin,dc=example,dc=org" -W -S "uid=billy,dc=example,dc=org"
|
||||
New password:
|
||||
Re-enter new password:
|
||||
Enter LDAP Password:
|
||||
```
|
||||
|
||||
### Add the mcsAdmin policy to user billy on MinIO
|
||||
```
|
||||
$ cat > mcsAdmin.json << EOF
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Action": [
|
||||
"admin:*"
|
||||
],
|
||||
"Effect": "Allow",
|
||||
"Sid": ""
|
||||
},
|
||||
{
|
||||
"Action": [
|
||||
"s3:*"
|
||||
],
|
||||
"Effect": "Allow",
|
||||
"Resource": [
|
||||
"arn:aws:s3:::*"
|
||||
],
|
||||
"Sid": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
$ mc admin policy add myminio mcsAdmin mcsAdmin.json
|
||||
$ mc admin policy set myminio mcsAdmin user=billy
|
||||
```
|
||||
|
||||
## Run MinIO
|
||||
|
||||
```
|
||||
export MINIO_ACCESS_KEY=minio
|
||||
export MINIO_SECRET_KEY=minio123
|
||||
export MINIO_IDENTITY_LDAP_SERVER_ADDR='localhost:389'
|
||||
export MINIO_IDENTITY_LDAP_USERNAME_FORMAT='uid=%s,dc=example,dc=org'
|
||||
export MINIO_IDENTITY_LDAP_USERNAME_SEARCH_FILTER='(|(objectclass=posixAccount)(uid=%s))'
|
||||
export MINIO_IDENTITY_LDAP_TLS_SKIP_VERIFY=on
|
||||
export MINIO_IDENTITY_LDAP_SERVER_INSECURE=on
|
||||
./minio server ~/Data
|
||||
```
|
||||
|
||||
## Run MCS
|
||||
|
||||
```
|
||||
export MCS_ACCESS_KEY=minio
|
||||
export MCS_SECRET_KEY=minio123
|
||||
...
|
||||
export MCS_LDAP_ENABLED=on
|
||||
./mcs server
|
||||
```
|
||||
@@ -1,8 +1,9 @@
|
||||
FROM golang:1.14.1
|
||||
FROM golang:1.13
|
||||
|
||||
ADD go.mod /go/src/github.com/minio/mcs/go.mod
|
||||
ADD go.sum /go/src/github.com/minio/mcs/go.sum
|
||||
WORKDIR /go/src/github.com/minio/mcs/
|
||||
|
||||
# Get dependencies - will also be cached if we won't change mod/sum
|
||||
RUN go mod download
|
||||
|
||||
|
||||
37
Makefile
@@ -1,23 +1,50 @@
|
||||
PWD := $(shell pwd)
|
||||
GOPATH := $(shell go env GOPATH)
|
||||
|
||||
default: mcs
|
||||
|
||||
.PHONY: mcs
|
||||
mcs:
|
||||
@echo "Building mcs binary to './mcs'"
|
||||
@(CGO_ENABLED=0 go build --tags=kqueue --ldflags "-s -w" -o mcs ./cmd/mcs)
|
||||
@(GO111MODULE=on CGO_ENABLED=0 go build -trimpath --tags=kqueue --ldflags "-s -w" -o mcs ./cmd/mcs)
|
||||
|
||||
getdeps:
|
||||
@mkdir -p ${GOPATH}/bin
|
||||
@which golangci-lint 1>/dev/null || (echo "Installing golangci-lint" && curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOPATH)/bin v1.27.0)
|
||||
|
||||
verifiers: getdeps fmt lint
|
||||
|
||||
fmt:
|
||||
@echo "Running $@ check"
|
||||
@GO111MODULE=on gofmt -d cmd/
|
||||
@GO111MODULE=on gofmt -d pkg/
|
||||
|
||||
lint:
|
||||
@echo "Running $@ check"
|
||||
@GO111MODULE=on ${GOPATH}/bin/golangci-lint cache clean
|
||||
@GO111MODULE=on ${GOPATH}/bin/golangci-lint run --timeout=5m --config ./.golangci.yml
|
||||
|
||||
install: mcs
|
||||
@echo "Installing mcs binary to '$(GOPATH)/bin/mcs'"
|
||||
@mkdir -p $(GOPATH)/bin && cp -f $(PWD)/mcs $(GOPATH)/bin/mcs
|
||||
@echo "Installation successful. To learn more, try \"mcs --help\"."
|
||||
|
||||
swagger-gen:
|
||||
@echo "Generating swagger server code from yaml"
|
||||
@swagger generate server -A mcs --main-package=mcs --exclude-main -P models.Principal -f ./swagger.yml -r NOTICE
|
||||
|
||||
build:
|
||||
assets:
|
||||
@(cd portal-ui; yarn install; make build-static; cd ..)
|
||||
@(CGO_ENABLED=0 go build --tags kqueue --ldflags "-s -w" -o mcs ./cmd/mcs)
|
||||
|
||||
test:
|
||||
@(go test ./restapi -v)
|
||||
@(GO111MODULE=on go test -race -v github.com/minio/mcs/restapi/...)
|
||||
@(GO111MODULE=on go test -race -v github.com/minio/mcs/pkg/...)
|
||||
|
||||
coverage:
|
||||
@(go test ./restapi -v -coverprofile=coverage.out && go tool cover -html=coverage.out && open coverage.html)
|
||||
@(GO111MODULE=on go test -v -coverprofile=coverage.out github.com/minio/mcs/restapi/... && go tool cover -html=coverage.out && open coverage.html)
|
||||
|
||||
clean:
|
||||
@echo "Cleaning up all the generated files"
|
||||
@find . -name '*.test' | xargs rm -fv
|
||||
@find . -name '*~' | xargs rm -fv
|
||||
@rm -vf mcs
|
||||
|
||||
143
README.md
@@ -1,6 +1,11 @@
|
||||
# MCS Minio Console Service
|
||||
# Minio Console Server
|
||||
|
||||
This is a REST portal server created using [go-swagger](https://github.com/go-swagger/go-swagger)
|
||||
A graphical user interface for [MinIO](https://github.com/minio/minio)
|
||||
|
||||
|
||||
| Dashboard | Adding A User |
|
||||
| ------------- | ------------- |
|
||||
|  |  |
|
||||
|
||||
## Setup
|
||||
|
||||
@@ -14,31 +19,30 @@ $ mc admin user add myminio mcs YOURMCSSECRET
|
||||
$ set -o history
|
||||
```
|
||||
|
||||
2. Create a policy for `mcs`
|
||||
2. Create a policy for `mcs` with access to everything (for testing and debugging)
|
||||
|
||||
```
|
||||
$ cat > mcsAdmin.json << EOF
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Action": [
|
||||
"admin:*"
|
||||
],
|
||||
"Effect": "Allow",
|
||||
"Sid": ""
|
||||
},
|
||||
{
|
||||
"Action": [
|
||||
"s3:*"
|
||||
],
|
||||
"Effect": "Allow",
|
||||
"Resource": [
|
||||
"arn:aws:s3:::*"
|
||||
],
|
||||
"Sid": ""
|
||||
}
|
||||
]
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [{
|
||||
"Action": [
|
||||
"admin:*"
|
||||
],
|
||||
"Effect": "Allow",
|
||||
"Sid": ""
|
||||
},
|
||||
{
|
||||
"Action": [
|
||||
"s3:*"
|
||||
],
|
||||
"Effect": "Allow",
|
||||
"Resource": [
|
||||
"arn:aws:s3:::*"
|
||||
],
|
||||
"Sid": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
$ mc admin policy add myminio mcsAdmin mcsAdmin.json
|
||||
@@ -50,44 +54,77 @@ $ mc admin policy add myminio mcsAdmin mcsAdmin.json
|
||||
$ mc admin policy set myminio mcsAdmin user=mcs
|
||||
```
|
||||
|
||||
|
||||
### Note
|
||||
Additionally, you can create policies to limit the privileges for `mcs` users, for example, if you want the user to only have access to dashboard, buckets, notifications and watch page, the policy should look like this:
|
||||
```
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [{
|
||||
"Action": [
|
||||
"admin:ServerInfo",
|
||||
],
|
||||
"Effect": "Allow",
|
||||
"Sid": ""
|
||||
},
|
||||
{
|
||||
"Action": [
|
||||
"s3:ListenBucketNotification",
|
||||
"s3:PutBucketNotification",
|
||||
"s3:GetBucketNotification",
|
||||
"s3:ListMultipartUploadParts",
|
||||
"s3:ListBucketMultipartUploads",
|
||||
"s3:ListBucket",
|
||||
"s3:HeadBucket",
|
||||
"s3:GetObject",
|
||||
"s3:GetBucketLocation",
|
||||
"s3:AbortMultipartUpload",
|
||||
"s3:CreateBucket",
|
||||
"s3:PutObject",
|
||||
"s3:DeleteObject",
|
||||
"s3:DeleteBucket",
|
||||
"s3:PutBucketPolicy",
|
||||
"s3:DeleteBucketPolicy",
|
||||
"s3:GetBucketPolicy"
|
||||
],
|
||||
"Effect": "Allow",
|
||||
"Resource": [
|
||||
"arn:aws:s3:::*"
|
||||
],
|
||||
"Sid": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Run MCS server
|
||||
To run the server:
|
||||
|
||||
```
|
||||
export MCS_HMAC_JWT_SECRET=YOURJWTSIGNINGSECRET
|
||||
|
||||
#required to encrypt jwet payload
|
||||
export MCS_PBKDF_PASSPHRASE=SECRET
|
||||
|
||||
#required to encrypt jwet payload
|
||||
export MCS_PBKDF_SALT=SECRET
|
||||
|
||||
export MCS_ACCESS_KEY=mcs
|
||||
export MCS_SECRET_KEY=YOURMCSSECRET
|
||||
export MCS_MINIO_SERVER=http://localhost:9000
|
||||
./mcs
|
||||
./mcs server
|
||||
```
|
||||
|
||||
## Connect MCS to a Minio using TLS and a self-signed certificate
|
||||
|
||||
```
|
||||
...
|
||||
export MCS_MINIO_SERVER_TLS_SKIP_VERIFICATION=on
|
||||
export MCS_MINIO_SERVER=https://localhost:9000
|
||||
./mcs server
|
||||
```
|
||||
|
||||
You can verify that the apis work by doing the request on `localhost:9090/api/v1/...`
|
||||
|
||||
# Development
|
||||
|
||||
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.
|
||||
|
||||
## 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_mcs.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.
|
||||
|
||||
To run tests:
|
||||
```
|
||||
go test ./restapi
|
||||
```
|
||||
# Contribute to mcs Project
|
||||
Please follow mcs [Contributor's Guide](https://github.com/minio/mcs/blob/master/CONTRIBUTING.md)
|
||||
|
||||
41
SECURITY.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
We always provide security updates for the [latest release](https://github.com/minio/mcs/releases/latest).
|
||||
Whenever there is a security update you just need to upgrade to the latest version.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
All security bugs in [minio/mcs](https://github,com/minio/mcs) (or other minio/* repositories)
|
||||
should be reported by email to security@min.io. Your email will be acknowledged within 48 hours,
|
||||
and you'll receive a more detailed response to your email within 72 hours indicating the next steps
|
||||
in handling your report.
|
||||
|
||||
Please, provide a detailed explanation of the issue. In particular, outline the type of the security
|
||||
issue (DoS, authentication bypass, information disclose, ...) and the assumptions you're making (e.g. do
|
||||
you need access credentials for a successful exploit).
|
||||
|
||||
If you have not received a reply to your email within 48 hours or you have not heard from the security team
|
||||
for the past five days please contact the security team directly:
|
||||
- Primary security coordinator: lenin@min.io
|
||||
- Secondary coordinator: daniel@min.io, cesar@min.io
|
||||
- If you receive no response: dev@min.io
|
||||
|
||||
### Disclosure Process
|
||||
|
||||
MinIO uses the following disclosure process:
|
||||
|
||||
1. Once the security report is received one member of the security team tries to verify and reproduce
|
||||
the issue and determines the impact it has.
|
||||
2. A member of the security team will respond and either confirm or reject the security report.
|
||||
If the report is rejected the response explains why.
|
||||
3. Code is audited to find any potential similar problems.
|
||||
4. Fixes are prepared for the latest release.
|
||||
5. On the date that the fixes are applied a security advisory will be published on https://blog.min.io.
|
||||
Please inform us in your report email whether MinIO should mention your contribution w.r.t. fixing
|
||||
the security issue. By default MinIO will **not** publish this information to protect your privacy.
|
||||
|
||||
This process can take some time, especially when coordination is required with maintainers of other projects.
|
||||
Every effort will be made to handle the bug in as timely a manner as possible, however it's important that we
|
||||
follow the process described above to ensure that disclosures are handled consistently.
|
||||
@@ -21,8 +21,9 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/minio/m3/mcs/pkg"
|
||||
"github.com/minio/mcs/pkg"
|
||||
|
||||
"github.com/minio/minio/pkg/console"
|
||||
"github.com/minio/minio/pkg/trie"
|
||||
@@ -31,7 +32,7 @@ import (
|
||||
"github.com/minio/cli"
|
||||
)
|
||||
|
||||
// Help template for m3.
|
||||
// Help template for mcs.
|
||||
var mcsHelpTemplate = `NAME:
|
||||
{{.Name}} - {{.Usage}}
|
||||
|
||||
@@ -53,14 +54,13 @@ VERSION:
|
||||
|
||||
var appCmds = []cli.Command{
|
||||
serverCmd,
|
||||
versionCmd,
|
||||
}
|
||||
|
||||
func newApp(name string) *cli.App {
|
||||
// Collection of m3 commands currently supported are.
|
||||
commands := []cli.Command{}
|
||||
// Collection of mcs commands currently supported are.
|
||||
var commands []cli.Command
|
||||
|
||||
// Collection of m3 commands currently supported in a trie tree.
|
||||
// Collection of mcs commands currently supported in a trie tree.
|
||||
commandsTree := trie.NewTrie()
|
||||
|
||||
// registerCommand registers a cli command.
|
||||
@@ -104,10 +104,12 @@ func newApp(name string) *cli.App {
|
||||
|
||||
app := cli.NewApp()
|
||||
app.Name = name
|
||||
app.Version = pkg.Version
|
||||
app.Version = pkg.Version + " - " + pkg.ShortCommitID
|
||||
app.Author = "MinIO, Inc."
|
||||
app.Usage = "mcs COMMAND"
|
||||
app.Usage = "MinIO Console Server"
|
||||
app.Description = `MinIO Console Server`
|
||||
app.Copyright = "(c) 2020 MinIO, Inc."
|
||||
app.Compiled, _ = time.Parse(time.RFC3339, pkg.ReleaseTime)
|
||||
app.Commands = commands
|
||||
app.HideHelpCommand = true // Hide `help, h` command, we already have `minio --help`.
|
||||
app.CustomAppHelpTemplate = mcsHelpTemplate
|
||||
|
||||
@@ -17,15 +17,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/go-openapi/loads"
|
||||
"github.com/jessevdk/go-flags"
|
||||
"github.com/minio/cli"
|
||||
"github.com/minio/m3/mcs/restapi"
|
||||
"github.com/minio/m3/mcs/restapi/operations"
|
||||
"github.com/minio/mcs/restapi"
|
||||
"github.com/minio/mcs/restapi/operations"
|
||||
)
|
||||
|
||||
// starts the server
|
||||
@@ -35,10 +35,35 @@ var serverCmd = cli.Command{
|
||||
Usage: "starts mcs server",
|
||||
Action: startServer,
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "host",
|
||||
Value: restapi.GetHostname(),
|
||||
Usage: "HTTP server hostname",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "port",
|
||||
Value: 9090,
|
||||
Usage: "Server port",
|
||||
Value: restapi.GetPort(),
|
||||
Usage: "HTTP Server port",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "tls-host",
|
||||
Value: restapi.GetSSLHostname(),
|
||||
Usage: "HTTPS server hostname",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "tls-port",
|
||||
Value: restapi.GetSSLPort(),
|
||||
Usage: "HTTPS server port",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "tls-certificate",
|
||||
Value: "",
|
||||
Usage: "filename of public cert",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "tls-key",
|
||||
Value: "",
|
||||
Usage: "filename of private key",
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -74,11 +99,32 @@ func startServer(ctx *cli.Context) error {
|
||||
}
|
||||
os.Exit(code)
|
||||
}
|
||||
// Parse flags
|
||||
flag.Parse()
|
||||
server.ConfigureAPI()
|
||||
|
||||
server.Host = ctx.String("host")
|
||||
server.Port = ctx.Int("port")
|
||||
|
||||
restapi.Hostname = ctx.String("host")
|
||||
restapi.Port = fmt.Sprintf("%v", ctx.Int("port"))
|
||||
|
||||
tlsCertificatePath := ctx.String("tls-certificate")
|
||||
tlsCertificateKeyPath := ctx.String("tls-key")
|
||||
|
||||
if tlsCertificatePath != "" && tlsCertificateKeyPath != "" {
|
||||
server.TLSCertificate = flags.Filename(tlsCertificatePath)
|
||||
server.TLSCertificateKey = flags.Filename(tlsCertificateKeyPath)
|
||||
// If TLS certificates are provided enforce the HTTPS schema, meaning mcs will redirect
|
||||
// plain HTTP connections to HTTPS server
|
||||
server.EnabledListeners = []string{"http", "https"}
|
||||
server.TLSPort = ctx.Int("tls-port")
|
||||
server.TLSHost = ctx.String("tls-host")
|
||||
// Need to store tls-port, tls-host un config variables so secure.middleware can read from there
|
||||
restapi.TLSPort = fmt.Sprintf("%v", ctx.Int("tls-port"))
|
||||
restapi.TLSHostname = ctx.String("tls-host")
|
||||
restapi.TLSRedirect = "on"
|
||||
}
|
||||
|
||||
server.ConfigureAPI()
|
||||
|
||||
if err := server.Serve(); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
80
code_of_conduct.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, gender identity and expression, level of experience,
|
||||
nationality, personal appearance, race, religion, or sexual identity and
|
||||
orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior, in compliance with the
|
||||
licensing terms applying to the Project developments.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful. However, these actions shall respect the
|
||||
licensing terms of the Project Developments that will always supersede such
|
||||
Code of Conduct.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at dev@min.io. The project team
|
||||
will review and investigate all complaints, and will respond in a way that it deems
|
||||
appropriate to the circumstances. The project team is obligated to maintain
|
||||
confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
This version includes a clarification to ensure that the code of conduct is in
|
||||
compliance with the free software licensing terms of the project.
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
||||
21
go.mod
@@ -1,8 +1,10 @@
|
||||
module github.com/minio/m3/mcs
|
||||
module github.com/minio/mcs
|
||||
|
||||
go 1.14
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.0
|
||||
github.com/go-openapi/errors v0.19.4
|
||||
github.com/go-openapi/loads v0.19.5
|
||||
@@ -11,11 +13,18 @@ require (
|
||||
github.com/go-openapi/strfmt v0.19.5
|
||||
github.com/go-openapi/swag v0.19.8
|
||||
github.com/go-openapi/validate v0.19.7
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/jessevdk/go-flags v1.4.0
|
||||
github.com/json-iterator/go v1.1.9
|
||||
github.com/minio/cli v1.22.0
|
||||
github.com/minio/mc v0.0.0-20200403024131-4d36c1f8b856
|
||||
github.com/minio/minio v0.0.0-20200327214830-6f992134a25f
|
||||
github.com/minio/minio-go/v6 v6.0.51-0.20200401083717-eadbcae2a0e6
|
||||
github.com/minio/mc v0.0.0-20200515235434-3b479cf92ed6
|
||||
github.com/minio/minio v0.0.0-20200516011754-9cac385aecdb
|
||||
github.com/minio/minio-go/v6 v6.0.56-0.20200502013257-a81c8c13cc3f
|
||||
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
|
||||
github.com/satori/go.uuid v1.2.0
|
||||
github.com/stretchr/testify v1.5.1
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a
|
||||
github.com/unrolled/secure v1.0.7
|
||||
golang.org/x/crypto v0.0.0-20200214034016-1d94cc7ab1c6
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e
|
||||
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a
|
||||
)
|
||||
|
||||
121
go.sum
@@ -2,6 +2,7 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.39.0 h1:UgQP9na6OTfp4dsAiz/eFpFA1C6tPdH5wiRdi19tuMw=
|
||||
cloud.google.com/go v0.39.0/go.mod h1:rVLT6fkc8chs9sfPtFc1SBH6em7n+ZoXaG+87tDISts=
|
||||
contrib.go.opencensus.io/exporter/ocagent v0.5.0 h1:TKXjQSRS0/cCDrP7KvkgU6SmILtF/yV2TOs/02K/WZQ=
|
||||
contrib.go.opencensus.io/exporter/ocagent v0.5.0/go.mod h1:ImxhfLRpxoYiSq891pBrLVhN+qmP8BTVvdH2YLs7Gl0=
|
||||
git.apache.org/thrift.git v0.13.0 h1:/3bz5WZ+sqYArk7MBBBbDufMxKKOA56/6JO6psDpUDY=
|
||||
git.apache.org/thrift.git v0.13.0/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
|
||||
@@ -9,7 +10,9 @@ github.com/Azure/azure-pipeline-go v0.2.1 h1:OLBdZJ3yvOn2MezlWvbrBMTEUQC72zAftRZ
|
||||
github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4=
|
||||
github.com/Azure/azure-storage-blob-go v0.8.0 h1:53qhf0Oxa0nOjgbDeeYPUeyiNmafAFEY95rZLK0Tj6o=
|
||||
github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0=
|
||||
github.com/Azure/go-autorest v11.7.1+incompatible h1:M2YZIajBBVekV86x0rr1443Lc1F/Ylxb9w+5EtSyX3Q=
|
||||
github.com/Azure/go-autorest v11.7.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
@@ -19,6 +22,7 @@ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/Shopify/sarama v1.24.1 h1:svn9vfN3R1Hz21WR2Gj0VW9ehaDGkiOS+VqlIcZOkMI=
|
||||
github.com/Shopify/sarama v1.24.1/go.mod h1:fGP8eQ6PugKEI0iUETYYtnP6d1pH/bdDMTel1X5ajsU=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk=
|
||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
||||
@@ -27,10 +31,9 @@ github.com/alecthomas/participle v0.2.1 h1:4AVLj1viSGa4LG5HDXKXrm5xRx19SB/rS/skP
|
||||
github.com/alecthomas/participle v0.2.1/go.mod h1:SW6HZGeZgSIpcUWX3fXpfZhuaWHnmoD5KCVaqSaNTkk=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5 h1:nWDRPCyCltiTsANwC/n3QZH7Vww33Npq9MKqlwRzI/c=
|
||||
github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878 h1:EFSB7Zo9Eg91v7MJPVsifUysc/wPdN+NOnVe6bWbdBM=
|
||||
github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQhVx52RsWOnlkpikZr01T/yAVN2gn0861vByNg=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
@@ -38,7 +41,6 @@ github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:l
|
||||
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496 h1:zV3ejI06GQ59hwDQAvmK1qxOQGB3WuVTRoY0okPTAv0=
|
||||
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
|
||||
github.com/aws/aws-sdk-go v1.20.21/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
|
||||
github.com/bcicen/jstream v0.0.0-20190220045926-16c1f8af81c2 h1:M+TYzBcNIRyzPRg66ndEqUMd7oWDmhvdQmaPC6EZNwM=
|
||||
github.com/bcicen/jstream v0.0.0-20190220045926-16c1f8af81c2/go.mod h1:RDu/qcrnpEdJC/p8tx34+YBFqqX71lB7dOX9QE+ZC4M=
|
||||
github.com/beevik/ntp v0.2.0 h1:sGsd+kAXzT0bfVfzJfce04g+dSRfrs+tbQW8lweuYgw=
|
||||
@@ -47,6 +49,7 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLM
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.0 h1:LzQXZOgg4CQfE6bFvXGM30YZL1WW/M337pXml+GrcZ4=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
@@ -55,12 +58,16 @@ github.com/cheggaaa/pb v1.0.28/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXH
|
||||
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
|
||||
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/codegangsta/negroni v1.0.0 h1:+aYywywx4bnKXWvoWtRfJ91vC59NbEhEY03sZjQhbVY=
|
||||
github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0=
|
||||
github.com/coredns/coredns v1.4.0 h1:RubBkYmkByUqZWWkjRHvNLnUHgkRVqAWgSMmRFvpE1A=
|
||||
github.com/coredns/coredns v1.4.0/go.mod h1:zASH/MVDgR6XZTbxvOnsZfffS+31vg6Ackf/wo1+AM0=
|
||||
github.com/coreos/bbolt v1.3.3 h1:n6AiVyVRKQFNb6mJlwESEvvLoDyiTzXX7ORAUlkeBdY=
|
||||
github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.12+incompatible h1:pAWNwdf7QiT1zfaWyqCtNZQWCLByQyA3JrSQyuYAqnQ=
|
||||
github.com/coreos/etcd v3.3.12+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk=
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
|
||||
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
|
||||
@@ -95,8 +102,10 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv
|
||||
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
|
||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||
github.com/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
||||
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
|
||||
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
||||
github.com/frankban/quicktest v1.4.1/go.mod h1:36zfPVQyHxymz4cH7wlDmVwDrJuljRB60qkgn7rorfQ=
|
||||
github.com/frankban/quicktest v1.7.2 h1:2QxQoC1TS09S7fhCPsrvqYdvP1H5M1P1ih5ABm3BTYk=
|
||||
github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 h1:Mn26/9ZMNWSw9C9ERFA1PUxfmGpolnw2v0bKOREu5ew=
|
||||
@@ -104,6 +113,7 @@ github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32/go.mod h1:GIjDIg/heH
|
||||
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-ldap/ldap v3.0.2+incompatible h1:kD5HQcAzlQ7yrhfn+h+MSABeAy/jAJhvIJ/QDllP44g=
|
||||
github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
|
||||
@@ -229,6 +239,7 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
@@ -245,6 +256,8 @@ github.com/gorilla/rpc v1.2.0 h1:WvvdC2lNeT1SP32zrIce5l0ECBfbAlmrmSBsuc57wfk=
|
||||
github.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ=
|
||||
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.1.0 h1:THDBEeQ9xZ8JEaCLyLQqXMMdRqNr0QAUJTIkQAUtFjg=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE=
|
||||
@@ -262,8 +275,11 @@ github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng
|
||||
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
|
||||
github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||
github.com/hashicorp/go-hclog v0.9.1/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
|
||||
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI=
|
||||
github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
@@ -284,6 +300,7 @@ github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/raft v1.1.1-0.20190703171940-f639636d18e0 h1:msEDtkZC3STZq6Pthlju+jKruuNHXCZAWhghDK47HcM=
|
||||
github.com/hashicorp/raft v1.1.1-0.20190703171940-f639636d18e0/go.mod h1:vPAJM8Asw6u8LxC3eJCUZmRP/E4QmUGE1R7g7k8sG/8=
|
||||
github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea/go.mod h1:pNv7Wc3ycL6F5oOWn+tPGo2gWD4a5X+yp/ntwdKLjRk=
|
||||
github.com/hashicorp/vault/api v1.0.4 h1:j08Or/wryXT4AcHj1oCbMd7IijXcKzYUGw59LGu9onU=
|
||||
@@ -322,12 +339,16 @@ github.com/klauspost/compress v1.10.3 h1:OP96hzwJVBIHYU52pVTI6CczrxPvrGfgqF9N5eT
|
||||
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/cpuid v1.2.2 h1:1xAgYebNnsb9LKCdLOvFWtAxGU/33mjJtyOVbmUa0Us=
|
||||
github.com/klauspost/cpuid v1.2.2/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/cpuid v1.2.4 h1:EBfaK0SWSwk+fgk6efYFWdzl8MwRWoOO1gkmiaTXPW4=
|
||||
github.com/klauspost/cpuid v1.2.4/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/pgzip v1.2.1 h1:oIPZROsWuPHpOdMVWLuJZXwgjhrW8r1yEX8UqMyeNHM=
|
||||
github.com/klauspost/pgzip v1.2.1/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
github.com/klauspost/readahead v1.3.1 h1:QqXNYvm+VvqYcbrRT4LojUciM0XrznFRIDrbHiJtu/0=
|
||||
github.com/klauspost/readahead v1.3.1/go.mod h1:AH9juHzNH7xqdqFHrMRSHeH2Ps+vFf+kblDqzPFiLJg=
|
||||
github.com/klauspost/reedsolomon v1.9.3 h1:N/VzgeMfHmLc+KHMD1UL/tNkfXAt8FnUqlgXGIduwAY=
|
||||
github.com/klauspost/reedsolomon v1.9.3/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4=
|
||||
github.com/klauspost/reedsolomon v1.9.7 h1:+azeqnT4iNG9UEcWC+7utJ4xXQ9S8pSlkZor0DOArEQ=
|
||||
github.com/klauspost/reedsolomon v1.9.7/go.mod h1:+8WD025Xpby8/kG5h/HDPIFhiiuGEtZOKw+5Y4drAD8=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
@@ -338,8 +359,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kurin/blazer v0.5.4-0.20190613185654-cf2f27cc0be3 h1:1sl2HmNtqGnDuydLgCJwZIpDLGqZOdwOkcY8WtUl8Cw=
|
||||
github.com/kurin/blazer v0.5.4-0.20190613185654-cf2f27cc0be3/go.mod h1:4FCXMUWo9DllR2Do4TtBd377ezyAJ51vB5uTBjt0pGU=
|
||||
github.com/kurin/blazer v0.5.4-0.20200327014341-8f90a40f8af7 h1:smZXPopqRVVywwzou4WYWvUbJvSAzIDFizfWElpmAqY=
|
||||
github.com/kurin/blazer v0.5.4-0.20200327014341-8f90a40f8af7/go.mod h1:4FCXMUWo9DllR2Do4TtBd377ezyAJ51vB5uTBjt0pGU=
|
||||
github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
|
||||
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/mailru/easyjson v0.0.0-20180730094502-03f2033d19d5/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
@@ -383,17 +404,18 @@ github.com/minio/highwayhash v1.0.0 h1:iMSDhgUILCr0TNm8LWlSjF8N0ZIj2qbO8WHp6Q/J2
|
||||
github.com/minio/highwayhash v1.0.0/go.mod h1:xQboMTeM9nY9v/LlAOxFctujiv5+Aq2hR5dxBpaMbdc=
|
||||
github.com/minio/lsync v1.0.1 h1:AVvILxA976xc27hstd1oR+X9PQG0sPSom1MNb1ImfUs=
|
||||
github.com/minio/lsync v1.0.1/go.mod h1:tCFzfo0dlvdGl70IT4IAK/5Wtgb0/BrTmo/jE8pArKA=
|
||||
github.com/minio/mc v0.0.0-20200403024131-4d36c1f8b856 h1:4uIc5fw4tVr5glh2Mc8GFuiY04pTGEhmihPxJPUvCoU=
|
||||
github.com/minio/mc v0.0.0-20200403024131-4d36c1f8b856/go.mod h1:IDy4dA4aFY6zFFNkYgdUztl0jcYuev/Ubg3NadoaMKc=
|
||||
github.com/minio/minio v0.0.0-20200327214830-6f992134a25f h1:RoOBi0vhXkZqe2b6RTROOsVJUwMqLMoet9r7eL01euo=
|
||||
github.com/minio/minio v0.0.0-20200327214830-6f992134a25f/go.mod h1:BzbIyKUJPp+4f03i2XF7+GsijXnxMakUe5x+lm2WNc8=
|
||||
github.com/minio/minio-go/v6 v6.0.45/go.mod h1:qD0lajrGW49lKZLtXKtCB4X/qkMf0a5tBvN2PaZg7Gg=
|
||||
github.com/minio/minio-go/v6 v6.0.51-0.20200319192131-097caa7760c7 h1:WQmYVUDRGdcEWhJeb42/Fn1IO7SBLem173DTE4+jp/E=
|
||||
github.com/minio/minio-go/v6 v6.0.51-0.20200319192131-097caa7760c7/go.mod h1:qD0lajrGW49lKZLtXKtCB4X/qkMf0a5tBvN2PaZg7Gg=
|
||||
github.com/minio/minio-go/v6 v6.0.51-0.20200401083717-eadbcae2a0e6 h1:7JhqKjmt1Tv6co7eP/40/xtDLrzzWu1UwUNwQzSvcb0=
|
||||
github.com/minio/minio-go/v6 v6.0.51-0.20200401083717-eadbcae2a0e6/go.mod h1:qD0lajrGW49lKZLtXKtCB4X/qkMf0a5tBvN2PaZg7Gg=
|
||||
github.com/minio/parquet-go v0.0.0-20200125064549-a1e49702e174 h1:WYFHZIJ5LTWd4C3CW26jguaBLLDdX7l1/Xa3QSKGkIc=
|
||||
github.com/minio/parquet-go v0.0.0-20200125064549-a1e49702e174/go.mod h1:PXYM9yI2l0YPmxHUXe6mFTmkQcyaVasDshAPTbGpDoo=
|
||||
github.com/minio/mc v0.0.0-20200515235434-3b479cf92ed6 h1:2SrKe2vLDLwvnYkYrJelrzyGW8t/8HCbr9yDsw+8XSI=
|
||||
github.com/minio/mc v0.0.0-20200515235434-3b479cf92ed6/go.mod h1:U3Jgk0bcSjn+QPUMisrS6nxCWOoQ6rYWSvLCB30apuU=
|
||||
github.com/minio/minio v0.0.0-20200421050159-282c9f790a03/go.mod h1:zBua5AiljGs1Irdl2XEyiJjvZVCVDIG8gjozzRBcVlw=
|
||||
github.com/minio/minio v0.0.0-20200516011754-9cac385aecdb h1:CQC7D3UDnUycuxhwImcVhMSLet/RbShosAnYcvMtEB8=
|
||||
github.com/minio/minio v0.0.0-20200516011754-9cac385aecdb/go.mod h1:wymaytM/HELuwdz7BGZHmQ3XKq2SxPsLeGxyOCaCLiA=
|
||||
github.com/minio/minio-go/v6 v6.0.53 h1:8jzpwiOzZ5Iz7/goFWqNZRICbyWYShbb5rARjrnSCNI=
|
||||
github.com/minio/minio-go/v6 v6.0.53/go.mod h1:DIvC/IApeHX8q1BAMVCXSXwpmrmM+I+iBvhvztQorfI=
|
||||
github.com/minio/minio-go/v6 v6.0.55-0.20200425081427-89eebdef2af0/go.mod h1:KQMM+/44DSlSGSQWSfRrAZ12FVMmpWNuX37i2AX0jfI=
|
||||
github.com/minio/minio-go/v6 v6.0.56-0.20200502013257-a81c8c13cc3f h1:ifHrI8+exqLi5RztIWWKS5k+Wu+W7DJisVXwNaCH2zs=
|
||||
github.com/minio/minio-go/v6 v6.0.56-0.20200502013257-a81c8c13cc3f/go.mod h1:KQMM+/44DSlSGSQWSfRrAZ12FVMmpWNuX37i2AX0jfI=
|
||||
github.com/minio/parquet-go v0.0.0-20200414234858-838cfa8aae61 h1:pUSI/WKPdd77gcuoJkSzhJ4wdS8OMDOsOu99MtpXEQA=
|
||||
github.com/minio/parquet-go v0.0.0-20200414234858-838cfa8aae61/go.mod h1:4trzEJ7N1nBTd5Tt7OCZT5SEin+WiAXpdJ/WgPkESA8=
|
||||
github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=
|
||||
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
|
||||
github.com/minio/simdjson-go v0.1.5-0.20200303142138-b17fe061ea37 h1:pDeao6M5AEd8hwTtGmE0pVKomlL56JFRa5SiXDZAuJE=
|
||||
@@ -422,14 +444,20 @@ github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJ
|
||||
github.com/montanaflynn/stats v0.5.0 h1:2EkzeTSqBB4V4bJwWrt5gIIrZmpJBcoIRGS2kWLgzmk=
|
||||
github.com/montanaflynn/stats v0.5.0/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nats-io/gnatsd v1.4.1 h1:RconcfDeWpKCD6QIIwiVFcvForlXpWeJP7i5/lDLy44=
|
||||
github.com/nats-io/gnatsd v1.4.1/go.mod h1:nqco77VO78hLCJpIcVfygDP2rPGfsEHkGTUk94uh5DQ=
|
||||
github.com/nats-io/go-nats v1.7.2 h1:cJujlwCYR8iMz5ofZSD/p2WLW8FabhkQ2lIEVbSvNSA=
|
||||
github.com/nats-io/go-nats v1.7.2/go.mod h1:+t7RHT5ApZebkrQdnn6AhQJmhJJiKAvJUio1PiiCtj0=
|
||||
github.com/nats-io/go-nats-streaming v0.4.4 h1:1I3lkZDRdQYXb+holjdqZ2J6xyekrD06o9Fd8rWlgP4=
|
||||
github.com/nats-io/go-nats-streaming v0.4.4/go.mod h1:gfq4R3c9sKAINOpelo0gn/b9QDMBZnmrttcsNF+lqyo=
|
||||
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
|
||||
github.com/nats-io/jwt v0.3.2 h1:+RB5hMpXUUA2dfxuhBTEkMOrYmM+gKIZYS1KjSostMI=
|
||||
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
|
||||
github.com/nats-io/nats-server v1.4.1 h1:Ul1oSOGNV/L8kjr4v6l2f9Yet6WY+LevH1/7cRZ/qyA=
|
||||
github.com/nats-io/nats-server v1.4.1/go.mod h1:c8f/fHd2B6Hgms3LtCaI7y6pC4WD1f4SUxcCud5vhBc=
|
||||
github.com/nats-io/nats-server/v2 v2.1.2 h1:i2Ly0B+1+rzNZHHWtD4ZwKi+OU5l+uQo1iDHZ2PmiIc=
|
||||
github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
|
||||
github.com/nats-io/nats-streaming-server v0.14.2 h1:WjQMDqVOwsI0Nb0E+XmEs1LY17CwHRbTCSTWKhw9fXs=
|
||||
github.com/nats-io/nats-streaming-server v0.14.2/go.mod h1:RyqtDJZvMZO66YmyjIYdIvS69zu/wDAkyNWa8PIUa5c=
|
||||
github.com/nats-io/nats.go v1.9.1 h1:ik3HbLhZ0YABLto7iX80pZLPw/6dx3T+++MZJwLnMrQ=
|
||||
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
|
||||
@@ -446,6 +474,7 @@ github.com/nsqio/go-nsq v1.0.7 h1:O0pIZJYTf+x7cZBA0UMY8WxFG79lYTURmWzAAh48ljY=
|
||||
github.com/nsqio/go-nsq v1.0.7/go.mod h1:XP5zaUs3pqf+Q71EqUJs3HYfBIqfK6G83WQMdNN+Ito=
|
||||
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
|
||||
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pborman/getopt v0.0.0-20180729010549-6fdd0a2c7117/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
|
||||
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||
@@ -468,6 +497,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/posener/complete v1.2.2-0.20190702141536-6ffe496ea953 h1:oBvgW8IvwF278gJ3R4hH0gD3ZeJxjwBXVIScRR0dRc8=
|
||||
github.com/posener/complete v1.2.2-0.20190702141536-6ffe496ea953/go.mod h1:6gapUrK/U1TAN7ciCoNRIdVC5sbdBTUh1DKN0g6uH7E=
|
||||
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 h1:J9b7z+QKAmPf4YLrFg6oQUotqHQeUNWwkvo7jZp1GLU=
|
||||
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
|
||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829 h1:D+CiwcpGTW6pL6bv6KI3KbyEyCKyS+1JWS2h8PNDnGA=
|
||||
@@ -497,6 +528,7 @@ github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
||||
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
|
||||
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
|
||||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/secure-io/sio-go v0.3.0 h1:QKGb6rGJeiExac9wSWxnWPYo8O8OFN7lxXQvHshX6vo=
|
||||
github.com/secure-io/sio-go v0.3.0/go.mod h1:D3KmXgKETffyYxBdFRN+Hpd2WzhzqS0EQwT3XWsAcBU=
|
||||
@@ -508,8 +540,8 @@ github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/skyrings/skyring-common v0.0.0-20160929130248-d1c0bb1cbd5e h1:jrZSSgPUDtBeJbGXqgGUeupQH8I+ZvGXfhpIahye2Bc=
|
||||
github.com/skyrings/skyring-common v0.0.0-20160929130248-d1c0bb1cbd5e/go.mod h1:d8hQseuYt4rJoOo21lFzYJdhMjmDqLY++ayArbgYjWI=
|
||||
github.com/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q=
|
||||
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/assertions v0.0.0-20190401211740-f487f9de1cd3 h1:hBSHahWMEgzwRyS6dRpxY0XyjZsHyQ61s084wo5PJe0=
|
||||
github.com/smartystreets/assertions v0.0.0-20190401211740-f487f9de1cd3/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
@@ -518,12 +550,15 @@ github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2
|
||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94 h1:0ngsPmuP6XIjiFRNFYlvKwSr5zff2v+uPHaffZ6/M4k=
|
||||
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
@@ -549,9 +584,15 @@ github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVM
|
||||
github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2tfCQDUqRd8fI=
|
||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/unrolled/secure v1.0.7 h1:BcQHp3iKZyZCKj5gRqwQG+5urnGBF00wGgoPPwtheVQ=
|
||||
github.com/unrolled/secure v1.0.7/go.mod h1:uGc1OcRF8gCVBA+ANksKmvM85Hka6SZtQIbrKc3sHS4=
|
||||
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a h1:0R4NLDRDZX6JcmhJgXi5E4b8Wg84ihbmUKp/GvSPEzc=
|
||||
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
|
||||
github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
|
||||
github.com/willf/bitset v1.1.10 h1:NotGKqX0KwQ72NUzqrjZq5ipPNDQex9lo3WpaS8L2sc=
|
||||
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||
github.com/willf/bloom v2.0.3+incompatible h1:QDacWdqcAUI1MPOwIQZRy9kOR7yxfyEmxX8Wdm2/JPA=
|
||||
github.com/willf/bloom v2.0.3+incompatible/go.mod h1:MmAltL9pDMNTrvUkxdg0k0q5I0suxmuwp3KbyrZLOZ8=
|
||||
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk=
|
||||
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
|
||||
github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
|
||||
@@ -559,6 +600,7 @@ github.com/xdg/stringprep v1.0.0 h1:d9X0esnoa3dFsV0FG35rAT0RIhYFlPq7MiP+DW89La0=
|
||||
github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk=
|
||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
|
||||
@@ -571,11 +613,19 @@ go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
|
||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
|
||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.11.0 h1:gSmpCfs+R47a4yQPAI4xJ0IPDLTRGXskm6UelqNXpqE=
|
||||
go.uber.org/zap v1.11.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM=
|
||||
go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
||||
golang.org/x/arch v0.0.0-20190909030613-46d78d1859ac/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181106171534-e4dc69e5b2fd/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
@@ -584,11 +634,13 @@ golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACk
|
||||
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f h1:kz4KIr+xcPUsI3VMoqWfPMvtnJ6MGfiVwsWSVzphMO4=
|
||||
golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200214034016-1d94cc7ab1c6 h1:Sy5bstxEqwwbYs6n0/pBuxKENqOeZUgD45Gp3Q3pqLg=
|
||||
@@ -598,6 +650,11 @@ golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTk
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -614,11 +671,9 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA=
|
||||
@@ -628,7 +683,10 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -649,8 +707,8 @@ golang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200320181252-af34d8274f85 h1:fD99hd4ciR6T3oPhr2EkmuKe9oHixHx9Hj/hND89j3g=
|
||||
golang.org/x/sys v0.0.0-20200320181252-af34d8274f85/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
@@ -675,9 +733,18 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn
|
||||
golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190914235951-31e00f45c22e h1:nOOVVcLC+/3MeovP40q5lCiWmP1Z1DaN8yn8ngU63hw=
|
||||
golang.org/x/tools v0.0.0-20190914235951-31e00f45c22e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200428211428-0c9eba77bc32 h1:Xvf3ZQTm5bjXPxhI7g+dwqsCqadK1rcNtwtszuatetk=
|
||||
golang.org/x/tools v0.0.0-20200428211428-0c9eba77bc32/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.5.0 h1:lj9SyhMzyoa38fgFF0oO2T6pjs5IzkLPKfVtxpyCRMM=
|
||||
google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
@@ -711,8 +778,8 @@ gopkg.in/h2non/filetype.v1 v1.0.5/go.mod h1:M0yem4rwSX5lLVrkEuRRp2/NinFMD5vgJ4Dl
|
||||
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.48.0 h1:URjZc+8ugRY5mL5uUeQH/a63JcHwdX9xZaWvmNWD7z8=
|
||||
gopkg.in/ini.v1 v1.48.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.52.0 h1:j+Lt/M1oPPejkniCg1TkWE2J3Eh1oZTsHSXzMTzUXn4=
|
||||
gopkg.in/ini.v1 v1.52.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.55.0 h1:E8yzL5unfpW3M6fz/eB7Cb5MQAYSZ7GKo4Qth+N2sgQ=
|
||||
gopkg.in/ini.v1 v1.55.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/jcmturner/aescts.v1 v1.0.1 h1:cVVZBK2b1zY26haWB4vbBiZrfFQnfbTVrE3xZq6hrEw=
|
||||
gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo=
|
||||
gopkg.in/jcmturner/dnsutils.v1 v1.0.1 h1:cIuC1OLRGZrld+16ZJvvZxVJeKPsvd5eUIvxfoN5hSM=
|
||||
@@ -740,4 +807,6 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
|
||||
BIN
images/pic1.png
Normal file
|
After Width: | Height: | Size: 635 KiB |
BIN
images/pic2.png
Normal file
|
After Width: | Height: | Size: 688 KiB |
147
models/add_notification_endpoint.go
Normal file
@@ -0,0 +1,147 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 models
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// AddNotificationEndpoint add notification endpoint
|
||||
//
|
||||
// swagger:model addNotificationEndpoint
|
||||
type AddNotificationEndpoint struct {
|
||||
|
||||
// account
|
||||
Account string `json:"account,omitempty"`
|
||||
|
||||
// properties
|
||||
Properties map[string]string `json:"properties,omitempty"`
|
||||
|
||||
// service
|
||||
// Enum: [webhook amqp kafka mqtt nats nsq mysql postgres elasticsearch redis]
|
||||
Service string `json:"service,omitempty"`
|
||||
}
|
||||
|
||||
// Validate validates this add notification endpoint
|
||||
func (m *AddNotificationEndpoint) Validate(formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.validateService(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var addNotificationEndpointTypeServicePropEnum []interface{}
|
||||
|
||||
func init() {
|
||||
var res []string
|
||||
if err := json.Unmarshal([]byte(`["webhook","amqp","kafka","mqtt","nats","nsq","mysql","postgres","elasticsearch","redis"]`), &res); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for _, v := range res {
|
||||
addNotificationEndpointTypeServicePropEnum = append(addNotificationEndpointTypeServicePropEnum, v)
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
|
||||
// AddNotificationEndpointServiceWebhook captures enum value "webhook"
|
||||
AddNotificationEndpointServiceWebhook string = "webhook"
|
||||
|
||||
// AddNotificationEndpointServiceAmqp captures enum value "amqp"
|
||||
AddNotificationEndpointServiceAmqp string = "amqp"
|
||||
|
||||
// AddNotificationEndpointServiceKafka captures enum value "kafka"
|
||||
AddNotificationEndpointServiceKafka string = "kafka"
|
||||
|
||||
// AddNotificationEndpointServiceMqtt captures enum value "mqtt"
|
||||
AddNotificationEndpointServiceMqtt string = "mqtt"
|
||||
|
||||
// AddNotificationEndpointServiceNats captures enum value "nats"
|
||||
AddNotificationEndpointServiceNats string = "nats"
|
||||
|
||||
// AddNotificationEndpointServiceNsq captures enum value "nsq"
|
||||
AddNotificationEndpointServiceNsq string = "nsq"
|
||||
|
||||
// AddNotificationEndpointServiceMysql captures enum value "mysql"
|
||||
AddNotificationEndpointServiceMysql string = "mysql"
|
||||
|
||||
// AddNotificationEndpointServicePostgres captures enum value "postgres"
|
||||
AddNotificationEndpointServicePostgres string = "postgres"
|
||||
|
||||
// AddNotificationEndpointServiceElasticsearch captures enum value "elasticsearch"
|
||||
AddNotificationEndpointServiceElasticsearch string = "elasticsearch"
|
||||
|
||||
// AddNotificationEndpointServiceRedis captures enum value "redis"
|
||||
AddNotificationEndpointServiceRedis string = "redis"
|
||||
)
|
||||
|
||||
// prop value enum
|
||||
func (m *AddNotificationEndpoint) validateServiceEnum(path, location string, value string) error {
|
||||
if err := validate.Enum(path, location, value, addNotificationEndpointTypeServicePropEnum); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *AddNotificationEndpoint) validateService(formats strfmt.Registry) error {
|
||||
|
||||
if swag.IsZero(m.Service) { // not required
|
||||
return nil
|
||||
}
|
||||
|
||||
// value enum
|
||||
if err := m.validateServiceEnum("service", "body", m.Service); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *AddNotificationEndpoint) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return swag.WriteJSON(m)
|
||||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *AddNotificationEndpoint) UnmarshalBinary(b []byte) error {
|
||||
var res AddNotificationEndpoint
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = res
|
||||
return nil
|
||||
}
|
||||
@@ -34,12 +34,13 @@ import (
|
||||
// swagger:model addPolicyRequest
|
||||
type AddPolicyRequest struct {
|
||||
|
||||
// definition
|
||||
Definition string `json:"definition,omitempty"`
|
||||
|
||||
// name
|
||||
// Required: true
|
||||
Name *string `json:"name"`
|
||||
|
||||
// policy
|
||||
// Required: true
|
||||
Policy *string `json:"policy"`
|
||||
}
|
||||
|
||||
// Validate validates this add policy request
|
||||
@@ -50,6 +51,10 @@ func (m *AddPolicyRequest) Validate(formats strfmt.Registry) error {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.validatePolicy(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
@@ -65,6 +70,15 @@ func (m *AddPolicyRequest) validateName(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *AddPolicyRequest) validatePolicy(formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.Required("policy", "body", m.Policy); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *AddPolicyRequest) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
|
||||
@@ -38,6 +38,10 @@ type AddUserRequest struct {
|
||||
// Required: true
|
||||
AccessKey *string `json:"accessKey"`
|
||||
|
||||
// groups
|
||||
// Required: true
|
||||
Groups []string `json:"groups"`
|
||||
|
||||
// secret key
|
||||
// Required: true
|
||||
SecretKey *string `json:"secretKey"`
|
||||
@@ -51,6 +55,10 @@ func (m *AddUserRequest) Validate(formats strfmt.Registry) error {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.validateGroups(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.validateSecretKey(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
@@ -70,6 +78,15 @@ func (m *AddUserRequest) validateAccessKey(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *AddUserRequest) validateGroups(formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.Required("groups", "body", m.Groups); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *AddUserRequest) validateSecretKey(formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.Required("secretKey", "body", m.SecretKey); err != nil {
|
||||
|
||||
98
models/bulk_user_groups.go
Normal file
@@ -0,0 +1,98 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 models
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// BulkUserGroups bulk user groups
|
||||
//
|
||||
// swagger:model bulkUserGroups
|
||||
type BulkUserGroups struct {
|
||||
|
||||
// groups
|
||||
// Required: true
|
||||
Groups []string `json:"groups"`
|
||||
|
||||
// users
|
||||
// Required: true
|
||||
Users []string `json:"users"`
|
||||
}
|
||||
|
||||
// Validate validates this bulk user groups
|
||||
func (m *BulkUserGroups) Validate(formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.validateGroups(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.validateUsers(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *BulkUserGroups) validateGroups(formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.Required("groups", "body", m.Groups); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *BulkUserGroups) validateUsers(formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.Required("users", "body", m.Users); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *BulkUserGroups) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return swag.WriteJSON(m)
|
||||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *BulkUserGroups) UnmarshalBinary(b []byte) error {
|
||||
var res BulkUserGroups
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = res
|
||||
return nil
|
||||
}
|
||||
98
models/login_oauth2_auth_request.go
Normal file
@@ -0,0 +1,98 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 models
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// LoginOauth2AuthRequest login oauth2 auth request
|
||||
//
|
||||
// swagger:model loginOauth2AuthRequest
|
||||
type LoginOauth2AuthRequest struct {
|
||||
|
||||
// code
|
||||
// Required: true
|
||||
Code *string `json:"code"`
|
||||
|
||||
// state
|
||||
// Required: true
|
||||
State *string `json:"state"`
|
||||
}
|
||||
|
||||
// Validate validates this login oauth2 auth request
|
||||
func (m *LoginOauth2AuthRequest) Validate(formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.validateCode(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.validateState(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *LoginOauth2AuthRequest) validateCode(formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.Required("code", "body", m.Code); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *LoginOauth2AuthRequest) validateState(formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.Required("state", "body", m.State); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *LoginOauth2AuthRequest) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return swag.WriteJSON(m)
|
||||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *LoginOauth2AuthRequest) UnmarshalBinary(b []byte) error {
|
||||
var res LoginOauth2AuthRequest
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = res
|
||||
return nil
|
||||
}
|
||||
104
models/nofitication_service.go
Normal file
@@ -0,0 +1,104 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 models
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// NofiticationService nofitication service
|
||||
//
|
||||
// swagger:model nofiticationService
|
||||
type NofiticationService string
|
||||
|
||||
const (
|
||||
|
||||
// NofiticationServiceWebhook captures enum value "webhook"
|
||||
NofiticationServiceWebhook NofiticationService = "webhook"
|
||||
|
||||
// NofiticationServiceAmqp captures enum value "amqp"
|
||||
NofiticationServiceAmqp NofiticationService = "amqp"
|
||||
|
||||
// NofiticationServiceKafka captures enum value "kafka"
|
||||
NofiticationServiceKafka NofiticationService = "kafka"
|
||||
|
||||
// NofiticationServiceMqtt captures enum value "mqtt"
|
||||
NofiticationServiceMqtt NofiticationService = "mqtt"
|
||||
|
||||
// NofiticationServiceNats captures enum value "nats"
|
||||
NofiticationServiceNats NofiticationService = "nats"
|
||||
|
||||
// NofiticationServiceNsq captures enum value "nsq"
|
||||
NofiticationServiceNsq NofiticationService = "nsq"
|
||||
|
||||
// NofiticationServiceMysql captures enum value "mysql"
|
||||
NofiticationServiceMysql NofiticationService = "mysql"
|
||||
|
||||
// NofiticationServicePostgres captures enum value "postgres"
|
||||
NofiticationServicePostgres NofiticationService = "postgres"
|
||||
|
||||
// NofiticationServiceElasticsearch captures enum value "elasticsearch"
|
||||
NofiticationServiceElasticsearch NofiticationService = "elasticsearch"
|
||||
|
||||
// NofiticationServiceRedis captures enum value "redis"
|
||||
NofiticationServiceRedis NofiticationService = "redis"
|
||||
)
|
||||
|
||||
// for schema
|
||||
var nofiticationServiceEnum []interface{}
|
||||
|
||||
func init() {
|
||||
var res []NofiticationService
|
||||
if err := json.Unmarshal([]byte(`["webhook","amqp","kafka","mqtt","nats","nsq","mysql","postgres","elasticsearch","redis"]`), &res); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for _, v := range res {
|
||||
nofiticationServiceEnum = append(nofiticationServiceEnum, v)
|
||||
}
|
||||
}
|
||||
|
||||
func (m NofiticationService) validateNofiticationServiceEnum(path, location string, value NofiticationService) error {
|
||||
if err := validate.Enum(path, location, value, nofiticationServiceEnum); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate validates this nofitication service
|
||||
func (m NofiticationService) Validate(formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
// value enum
|
||||
if err := m.validateNofiticationServiceEnum("", "body", m); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
97
models/notif_endpoint_response.go
Normal file
@@ -0,0 +1,97 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 models
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// NotifEndpointResponse notif endpoint response
|
||||
//
|
||||
// swagger:model notifEndpointResponse
|
||||
type NotifEndpointResponse struct {
|
||||
|
||||
// notification endpoints
|
||||
NotificationEndpoints []*NotificationEndpointItem `json:"notification_endpoints"`
|
||||
}
|
||||
|
||||
// Validate validates this notif endpoint response
|
||||
func (m *NotifEndpointResponse) Validate(formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.validateNotificationEndpoints(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *NotifEndpointResponse) validateNotificationEndpoints(formats strfmt.Registry) error {
|
||||
|
||||
if swag.IsZero(m.NotificationEndpoints) { // not required
|
||||
return nil
|
||||
}
|
||||
|
||||
for i := 0; i < len(m.NotificationEndpoints); i++ {
|
||||
if swag.IsZero(m.NotificationEndpoints[i]) { // not required
|
||||
continue
|
||||
}
|
||||
|
||||
if m.NotificationEndpoints[i] != nil {
|
||||
if err := m.NotificationEndpoints[i].Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("notification_endpoints" + "." + strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *NotifEndpointResponse) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return swag.WriteJSON(m)
|
||||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *NotifEndpointResponse) UnmarshalBinary(b []byte) error {
|
||||
var res NotifEndpointResponse
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = res
|
||||
return nil
|
||||
}
|
||||
129
models/notification_delete_request.go
Normal file
@@ -0,0 +1,129 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 models
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// NotificationDeleteRequest notification delete request
|
||||
//
|
||||
// swagger:model notificationDeleteRequest
|
||||
type NotificationDeleteRequest struct {
|
||||
|
||||
// filter specific type of event. Defaults to all event (default: '[put,delete,get]')
|
||||
// Required: true
|
||||
// Min Length: 1
|
||||
Events []NotificationEventType `json:"events"`
|
||||
|
||||
// filter event associated to the specified prefix
|
||||
// Required: true
|
||||
Prefix *string `json:"prefix"`
|
||||
|
||||
// filter event associated to the specified suffix
|
||||
// Required: true
|
||||
Suffix *string `json:"suffix"`
|
||||
}
|
||||
|
||||
// Validate validates this notification delete request
|
||||
func (m *NotificationDeleteRequest) Validate(formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.validateEvents(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.validatePrefix(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.validateSuffix(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *NotificationDeleteRequest) validateEvents(formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.Required("events", "body", m.Events); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < len(m.Events); i++ {
|
||||
|
||||
if err := m.Events[i].Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("events" + "." + strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *NotificationDeleteRequest) validatePrefix(formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.Required("prefix", "body", m.Prefix); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *NotificationDeleteRequest) validateSuffix(formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.Required("suffix", "body", m.Suffix); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *NotificationDeleteRequest) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return swag.WriteJSON(m)
|
||||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *NotificationDeleteRequest) UnmarshalBinary(b []byte) error {
|
||||
var res NotificationDeleteRequest
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = res
|
||||
return nil
|
||||
}
|
||||
114
models/notification_endpoint.go
Normal file
@@ -0,0 +1,114 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 models
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// NotificationEndpoint notification endpoint
|
||||
//
|
||||
// swagger:model notificationEndpoint
|
||||
type NotificationEndpoint struct {
|
||||
|
||||
// account id
|
||||
// Required: true
|
||||
AccountID *string `json:"account_id"`
|
||||
|
||||
// properties
|
||||
// Required: true
|
||||
Properties map[string]string `json:"properties"`
|
||||
|
||||
// service
|
||||
// Required: true
|
||||
Service NofiticationService `json:"service"`
|
||||
}
|
||||
|
||||
// Validate validates this notification endpoint
|
||||
func (m *NotificationEndpoint) Validate(formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.validateAccountID(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.validateProperties(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.validateService(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *NotificationEndpoint) validateAccountID(formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.Required("account_id", "body", m.AccountID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *NotificationEndpoint) validateProperties(formats strfmt.Registry) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *NotificationEndpoint) validateService(formats strfmt.Registry) error {
|
||||
|
||||
if err := m.Service.Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("service")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *NotificationEndpoint) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return swag.WriteJSON(m)
|
||||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *NotificationEndpoint) UnmarshalBinary(b []byte) error {
|
||||
var res NotificationEndpoint
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = res
|
||||
return nil
|
||||
}
|
||||
92
models/notification_endpoint_item.go
Normal file
@@ -0,0 +1,92 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 models
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// NotificationEndpointItem notification endpoint item
|
||||
//
|
||||
// swagger:model notificationEndpointItem
|
||||
type NotificationEndpointItem struct {
|
||||
|
||||
// account id
|
||||
AccountID string `json:"account_id,omitempty"`
|
||||
|
||||
// service
|
||||
Service NofiticationService `json:"service,omitempty"`
|
||||
|
||||
// status
|
||||
Status string `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// Validate validates this notification endpoint item
|
||||
func (m *NotificationEndpointItem) Validate(formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.validateService(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *NotificationEndpointItem) validateService(formats strfmt.Registry) error {
|
||||
|
||||
if swag.IsZero(m.Service) { // not required
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := m.Service.Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("service")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *NotificationEndpointItem) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return swag.WriteJSON(m)
|
||||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *NotificationEndpointItem) UnmarshalBinary(b []byte) error {
|
||||
var res NotificationEndpointItem
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = res
|
||||
return nil
|
||||
}
|
||||
@@ -23,9 +23,6 @@ package models
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
@@ -38,49 +35,12 @@ type Policy struct {
|
||||
// name
|
||||
Name string `json:"name,omitempty"`
|
||||
|
||||
// statements
|
||||
Statements []*Statement `json:"statements"`
|
||||
|
||||
// version
|
||||
Version string `json:"version,omitempty"`
|
||||
// policy
|
||||
Policy string `json:"policy,omitempty"`
|
||||
}
|
||||
|
||||
// Validate validates this policy
|
||||
func (m *Policy) Validate(formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.validateStatements(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Policy) validateStatements(formats strfmt.Registry) error {
|
||||
|
||||
if swag.IsZero(m.Statements) { // not required
|
||||
return nil
|
||||
}
|
||||
|
||||
for i := 0; i < len(m.Statements); i++ {
|
||||
if swag.IsZero(m.Statements[i]) { // not required
|
||||
continue
|
||||
}
|
||||
|
||||
if m.Statements[i] != nil {
|
||||
if err := m.Statements[i].Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("statements" + "." + strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
72
models/policy_statement.go
Normal file
@@ -0,0 +1,72 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 models
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// PolicyStatement policy statement
|
||||
//
|
||||
// swagger:model policyStatement
|
||||
type PolicyStatement struct {
|
||||
|
||||
// action
|
||||
Action []string `json:"Action"`
|
||||
|
||||
// condition
|
||||
Condition string `json:"Condition,omitempty"`
|
||||
|
||||
// effect
|
||||
Effect string `json:"Effect,omitempty"`
|
||||
|
||||
// resource
|
||||
Resource string `json:"Resource,omitempty"`
|
||||
|
||||
// sid
|
||||
Sid string `json:"Sid,omitempty"`
|
||||
}
|
||||
|
||||
// Validate validates this policy statement
|
||||
func (m *PolicyStatement) Validate(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *PolicyStatement) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return swag.WriteJSON(m)
|
||||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *PolicyStatement) UnmarshalBinary(b []byte) error {
|
||||
var res PolicyStatement
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = res
|
||||
return nil
|
||||
}
|
||||
62
models/policy_statements.go
Normal file
@@ -0,0 +1,62 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 models
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// PolicyStatements policy statements
|
||||
//
|
||||
// swagger:model policyStatements
|
||||
type PolicyStatements []*PolicyStatement
|
||||
|
||||
// Validate validates this policy statements
|
||||
func (m PolicyStatements) Validate(formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
for i := 0; i < len(m); i++ {
|
||||
if swag.IsZero(m[i]) { // not required
|
||||
continue
|
||||
}
|
||||
|
||||
if m[i] != nil {
|
||||
if err := m[i].Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName(strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
63
models/service_account_creds.go
Normal file
@@ -0,0 +1,63 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 models
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// ServiceAccountCreds service account creds
|
||||
//
|
||||
// swagger:model serviceAccountCreds
|
||||
type ServiceAccountCreds struct {
|
||||
|
||||
// access key
|
||||
AccessKey string `json:"accessKey,omitempty"`
|
||||
|
||||
// secret key
|
||||
SecretKey string `json:"secretKey,omitempty"`
|
||||
}
|
||||
|
||||
// Validate validates this service account creds
|
||||
func (m *ServiceAccountCreds) Validate(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *ServiceAccountCreds) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return swag.WriteJSON(m)
|
||||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *ServiceAccountCreds) UnmarshalBinary(b []byte) error {
|
||||
var res ServiceAccountCreds
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = res
|
||||
return nil
|
||||
}
|
||||
@@ -27,28 +27,22 @@ import (
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// Statement statement
|
||||
// ServiceAccountRequest service account request
|
||||
//
|
||||
// swagger:model statement
|
||||
type Statement struct {
|
||||
// swagger:model serviceAccountRequest
|
||||
type ServiceAccountRequest struct {
|
||||
|
||||
// actions
|
||||
Actions []string `json:"actions"`
|
||||
|
||||
// effect
|
||||
Effect string `json:"effect,omitempty"`
|
||||
|
||||
// resources
|
||||
Resources []string `json:"resources"`
|
||||
// policy to be applied to the Service Account if any
|
||||
Policy string `json:"policy,omitempty"`
|
||||
}
|
||||
|
||||
// Validate validates this statement
|
||||
func (m *Statement) Validate(formats strfmt.Registry) error {
|
||||
// Validate validates this service account request
|
||||
func (m *ServiceAccountRequest) Validate(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *Statement) MarshalBinary() ([]byte, error) {
|
||||
func (m *ServiceAccountRequest) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -56,8 +50,8 @@ func (m *Statement) MarshalBinary() ([]byte, error) {
|
||||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *Statement) UnmarshalBinary(b []byte) error {
|
||||
var res Statement
|
||||
func (m *ServiceAccountRequest) UnmarshalBinary(b []byte) error {
|
||||
var res ServiceAccountRequest
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
37
models/service_accounts.go
Normal file
@@ -0,0 +1,37 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 models
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
// ServiceAccounts service accounts
|
||||
//
|
||||
// swagger:model serviceAccounts
|
||||
type ServiceAccounts []string
|
||||
|
||||
// Validate validates this service accounts
|
||||
func (m ServiceAccounts) Validate(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
@@ -36,6 +36,9 @@ import (
|
||||
// swagger:model sessionResponse
|
||||
type SessionResponse struct {
|
||||
|
||||
// pages
|
||||
Pages []string `json:"pages"`
|
||||
|
||||
// status
|
||||
// Enum: [ok]
|
||||
Status string `json:"status,omitempty"`
|
||||
|
||||
98
models/update_user.go
Normal file
@@ -0,0 +1,98 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 models
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// UpdateUser update user
|
||||
//
|
||||
// swagger:model updateUser
|
||||
type UpdateUser struct {
|
||||
|
||||
// groups
|
||||
// Required: true
|
||||
Groups []string `json:"groups"`
|
||||
|
||||
// status
|
||||
// Required: true
|
||||
Status *string `json:"status"`
|
||||
}
|
||||
|
||||
// Validate validates this update user
|
||||
func (m *UpdateUser) Validate(formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.validateGroups(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.validateStatus(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *UpdateUser) validateGroups(formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.Required("groups", "body", m.Groups); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *UpdateUser) validateStatus(formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.Required("status", "body", m.Status); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *UpdateUser) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return swag.WriteJSON(m)
|
||||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *UpdateUser) UnmarshalBinary(b []byte) error {
|
||||
var res UpdateUser
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = res
|
||||
return nil
|
||||
}
|
||||
81
models/update_user_groups.go
Normal file
@@ -0,0 +1,81 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 models
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// UpdateUserGroups update user groups
|
||||
//
|
||||
// swagger:model updateUserGroups
|
||||
type UpdateUserGroups struct {
|
||||
|
||||
// groups
|
||||
// Required: true
|
||||
Groups []string `json:"groups"`
|
||||
}
|
||||
|
||||
// Validate validates this update user groups
|
||||
func (m *UpdateUserGroups) Validate(formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.validateGroups(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *UpdateUserGroups) validateGroups(formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.Required("groups", "body", m.Groups); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *UpdateUserGroups) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return swag.WriteJSON(m)
|
||||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *UpdateUserGroups) UnmarshalBinary(b []byte) error {
|
||||
var res UpdateUserGroups
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = res
|
||||
return nil
|
||||
}
|
||||
@@ -14,24 +14,16 @@
|
||||
// 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 main
|
||||
package acl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/minio/cli"
|
||||
"github.com/minio/m3/mcs/pkg"
|
||||
"github.com/minio/minio/pkg/env"
|
||||
)
|
||||
|
||||
// starts the server
|
||||
var versionCmd = cli.Command{
|
||||
Name: "version",
|
||||
Usage: "shows mcs version",
|
||||
Action: version,
|
||||
}
|
||||
|
||||
// starts the controller
|
||||
func version(ctx *cli.Context) error {
|
||||
fmt.Printf("MCS version %s (%s - %s. Commit %s)", pkg.Version, pkg.ReleaseTag, pkg.ReleaseTime, pkg.CommitID)
|
||||
return nil
|
||||
// GetOperatorOnly gets mcs operator mode status set on env variable
|
||||
//or default one
|
||||
func GetOperatorOnly() string {
|
||||
return strings.ToLower(env.Get(McsOperatorOnly, "off"))
|
||||
}
|
||||
21
pkg/acl/const.go
Normal file
@@ -0,0 +1,21 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 acl
|
||||
|
||||
const (
|
||||
McsOperatorOnly = "MCS_OPERATOR_ONLY"
|
||||
)
|
||||
315
pkg/acl/endpoints.go
Normal file
@@ -0,0 +1,315 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 acl
|
||||
|
||||
import (
|
||||
iampolicy "github.com/minio/minio/pkg/iam/policy"
|
||||
)
|
||||
|
||||
// endpoints definition
|
||||
var (
|
||||
configuration = "/configurations-list"
|
||||
users = "/users"
|
||||
groups = "/groups"
|
||||
iamPolicies = "/policies"
|
||||
dashboard = "/dashboard"
|
||||
profiling = "/profiling"
|
||||
trace = "/trace"
|
||||
logs = "/logs"
|
||||
watch = "/watch"
|
||||
notifications = "/notification-endpoints"
|
||||
buckets = "/buckets"
|
||||
bucketsDetail = "/buckets/:bucketName"
|
||||
serviceAccounts = "/service-accounts"
|
||||
tenants = "/tenants"
|
||||
tenantsDetail = "/tenants/:tenantName"
|
||||
heal = "/heal"
|
||||
)
|
||||
|
||||
type ConfigurationActionSet struct {
|
||||
actionTypes iampolicy.ActionSet
|
||||
actions iampolicy.ActionSet
|
||||
}
|
||||
|
||||
// configurationActionSet contains the list of admin actions required for this endpoint to work
|
||||
var configurationActionSet = ConfigurationActionSet{
|
||||
actionTypes: iampolicy.NewActionSet(
|
||||
iampolicy.AllAdminActions,
|
||||
),
|
||||
actions: iampolicy.NewActionSet(
|
||||
iampolicy.ConfigUpdateAdminAction,
|
||||
),
|
||||
}
|
||||
|
||||
// logsActionSet contains the list of admin actions required for this endpoint to work
|
||||
var logsActionSet = ConfigurationActionSet{
|
||||
actionTypes: iampolicy.NewActionSet(
|
||||
iampolicy.AllAdminActions,
|
||||
),
|
||||
actions: iampolicy.NewActionSet(
|
||||
iampolicy.ConsoleLogAdminAction,
|
||||
),
|
||||
}
|
||||
|
||||
// dashboardActionSet contains the list of admin actions required for this endpoint to work
|
||||
var dashboardActionSet = ConfigurationActionSet{
|
||||
actionTypes: iampolicy.NewActionSet(
|
||||
iampolicy.AllAdminActions,
|
||||
),
|
||||
actions: iampolicy.NewActionSet(
|
||||
iampolicy.ServerInfoAdminAction,
|
||||
),
|
||||
}
|
||||
|
||||
// groupsActionSet contains the list of admin actions required for this endpoint to work
|
||||
var groupsActionSet = ConfigurationActionSet{
|
||||
actionTypes: iampolicy.NewActionSet(
|
||||
iampolicy.AllAdminActions,
|
||||
),
|
||||
actions: iampolicy.NewActionSet(
|
||||
iampolicy.ListGroupsAdminAction,
|
||||
iampolicy.AddUserToGroupAdminAction,
|
||||
//iampolicy.GetGroupAdminAction,
|
||||
iampolicy.EnableGroupAdminAction,
|
||||
iampolicy.DisableGroupAdminAction,
|
||||
),
|
||||
}
|
||||
|
||||
// iamPoliciesActionSet contains the list of admin actions required for this endpoint to work
|
||||
var iamPoliciesActionSet = ConfigurationActionSet{
|
||||
actionTypes: iampolicy.NewActionSet(
|
||||
iampolicy.AllAdminActions,
|
||||
),
|
||||
actions: iampolicy.NewActionSet(
|
||||
iampolicy.GetPolicyAdminAction,
|
||||
iampolicy.DeletePolicyAdminAction,
|
||||
iampolicy.CreatePolicyAdminAction,
|
||||
iampolicy.AttachPolicyAdminAction,
|
||||
iampolicy.ListUserPoliciesAdminAction,
|
||||
),
|
||||
}
|
||||
|
||||
// profilingActionSet contains the list of admin actions required for this endpoint to work
|
||||
var profilingActionSet = ConfigurationActionSet{
|
||||
actionTypes: iampolicy.NewActionSet(
|
||||
iampolicy.AllAdminActions,
|
||||
),
|
||||
actions: iampolicy.NewActionSet(
|
||||
iampolicy.ProfilingAdminAction,
|
||||
),
|
||||
}
|
||||
|
||||
// traceActionSet contains the list of admin actions required for this endpoint to work
|
||||
var traceActionSet = ConfigurationActionSet{
|
||||
actionTypes: iampolicy.NewActionSet(
|
||||
iampolicy.AllAdminActions,
|
||||
),
|
||||
actions: iampolicy.NewActionSet(
|
||||
iampolicy.TraceAdminAction,
|
||||
),
|
||||
}
|
||||
|
||||
// usersActionSet contains the list of admin actions required for this endpoint to work
|
||||
var usersActionSet = ConfigurationActionSet{
|
||||
actionTypes: iampolicy.NewActionSet(
|
||||
iampolicy.AllAdminActions,
|
||||
),
|
||||
actions: iampolicy.NewActionSet(
|
||||
iampolicy.ListUsersAdminAction,
|
||||
iampolicy.CreateUserAdminAction,
|
||||
iampolicy.DeleteUserAdminAction,
|
||||
iampolicy.GetUserAdminAction,
|
||||
iampolicy.EnableUserAdminAction,
|
||||
iampolicy.DisableUserAdminAction,
|
||||
),
|
||||
}
|
||||
|
||||
// watchActionSet contains the list of admin actions required for this endpoint to work
|
||||
var watchActionSet = ConfigurationActionSet{
|
||||
actionTypes: iampolicy.NewActionSet(
|
||||
iampolicy.AllAdminActions,
|
||||
),
|
||||
actions: iampolicy.NewActionSet(
|
||||
iampolicy.ListenBucketNotificationAction,
|
||||
),
|
||||
}
|
||||
|
||||
// notificationsActionSet contains the list of admin actions required for this endpoint to work
|
||||
var notificationsActionSet = ConfigurationActionSet{
|
||||
actionTypes: iampolicy.NewActionSet(
|
||||
iampolicy.AllActions,
|
||||
),
|
||||
actions: iampolicy.NewActionSet(
|
||||
iampolicy.ListenBucketNotificationAction,
|
||||
iampolicy.PutBucketNotificationAction,
|
||||
iampolicy.GetBucketNotificationAction,
|
||||
),
|
||||
}
|
||||
|
||||
// bucketsActionSet contains the list of admin actions required for this endpoint to work
|
||||
var bucketsActionSet = ConfigurationActionSet{
|
||||
actionTypes: iampolicy.NewActionSet(
|
||||
iampolicy.AllActions,
|
||||
),
|
||||
actions: iampolicy.NewActionSet(
|
||||
// Read access to buckets
|
||||
iampolicy.ListMultipartUploadPartsAction,
|
||||
iampolicy.ListBucketMultipartUploadsAction,
|
||||
iampolicy.ListBucketAction,
|
||||
iampolicy.HeadBucketAction,
|
||||
iampolicy.GetObjectAction,
|
||||
iampolicy.GetBucketLocationAction,
|
||||
// Write access to buckets
|
||||
iampolicy.AbortMultipartUploadAction,
|
||||
iampolicy.CreateBucketAction,
|
||||
iampolicy.PutObjectAction,
|
||||
iampolicy.DeleteObjectAction,
|
||||
iampolicy.DeleteBucketAction,
|
||||
// Assign bucket policies
|
||||
iampolicy.PutBucketPolicyAction,
|
||||
iampolicy.DeleteBucketPolicyAction,
|
||||
iampolicy.GetBucketPolicyAction,
|
||||
),
|
||||
}
|
||||
|
||||
// serviceAccountsActionSet no actions needed for this module to work
|
||||
var serviceAccountsActionSet = ConfigurationActionSet{
|
||||
actionTypes: iampolicy.NewActionSet(),
|
||||
actions: iampolicy.NewActionSet(),
|
||||
}
|
||||
|
||||
// tenantsActionSet temporally no actions needed for tenants sections to work
|
||||
var tenantsActionSet = ConfigurationActionSet{
|
||||
actionTypes: iampolicy.NewActionSet(),
|
||||
actions: iampolicy.NewActionSet(),
|
||||
}
|
||||
|
||||
// healActionSet contains the list of admin actions required for this endpoint to work
|
||||
var healActionSet = ConfigurationActionSet{
|
||||
actionTypes: iampolicy.NewActionSet(
|
||||
iampolicy.AllAdminActions,
|
||||
),
|
||||
actions: iampolicy.NewActionSet(
|
||||
iampolicy.HealAdminAction,
|
||||
),
|
||||
}
|
||||
|
||||
// endpointRules contains the mapping between endpoints and ActionSets, additional rules can be added here
|
||||
var endpointRules = map[string]ConfigurationActionSet{
|
||||
configuration: configurationActionSet,
|
||||
users: usersActionSet,
|
||||
groups: groupsActionSet,
|
||||
iamPolicies: iamPoliciesActionSet,
|
||||
dashboard: dashboardActionSet,
|
||||
profiling: profilingActionSet,
|
||||
trace: traceActionSet,
|
||||
logs: logsActionSet,
|
||||
watch: watchActionSet,
|
||||
notifications: notificationsActionSet,
|
||||
buckets: bucketsActionSet,
|
||||
bucketsDetail: bucketsActionSet,
|
||||
serviceAccounts: serviceAccountsActionSet,
|
||||
heal: healActionSet,
|
||||
}
|
||||
|
||||
// operatorRules contains the mapping between endpoints and ActionSets for operator only mode
|
||||
var operatorRules = map[string]ConfigurationActionSet{
|
||||
tenants: tenantsActionSet,
|
||||
tenantsDetail: tenantsActionSet,
|
||||
}
|
||||
|
||||
// operatorOnly ENV variable
|
||||
var operatorOnly = GetOperatorOnly()
|
||||
|
||||
// GetActionsStringFromPolicy extract the admin/s3 actions from a given policy and return them in []string format
|
||||
//
|
||||
// ie:
|
||||
// {
|
||||
// "Version": "2012-10-17",
|
||||
// "Statement": [{
|
||||
// "Action": [
|
||||
// "admin:ServerInfo",
|
||||
// "admin:CreatePolicy",
|
||||
// "admin:GetUser"
|
||||
// ],
|
||||
// ...
|
||||
// },
|
||||
// {
|
||||
// "Action": [
|
||||
// "s3:ListenBucketNotification",
|
||||
// "s3:PutBucketNotification"
|
||||
// ],
|
||||
// ...
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// Will produce an array like: ["admin:ServerInfo", "admin:CreatePolicy", "admin:GetUser", "s3:ListenBucketNotification", "s3:PutBucketNotification"]\
|
||||
func GetActionsStringFromPolicy(policy *iampolicy.Policy) []string {
|
||||
var actions []string
|
||||
for _, statement := range policy.Statements {
|
||||
// We only care about allowed actions
|
||||
if statement.Effect.IsAllowed(true) {
|
||||
for _, action := range statement.Actions.ToSlice() {
|
||||
actions = append(actions, string(action))
|
||||
}
|
||||
}
|
||||
}
|
||||
return actions
|
||||
}
|
||||
|
||||
// actionsStringToActionSet convert a given string array to iampolicy.ActionSet structure
|
||||
// this avoids ending with duplicate actions
|
||||
func actionsStringToActionSet(actions []string) iampolicy.ActionSet {
|
||||
actionsSet := iampolicy.ActionSet{}
|
||||
for _, action := range actions {
|
||||
actionsSet.Add(iampolicy.Action(action))
|
||||
}
|
||||
return actionsSet
|
||||
}
|
||||
|
||||
// GetAuthorizedEndpoints return a list of allowed endpoint based on a provided *iampolicy.Policy
|
||||
// ie: pages the user should have access based on his current privileges
|
||||
func GetAuthorizedEndpoints(actions []string) []string {
|
||||
rangeTake := endpointRules
|
||||
|
||||
if operatorOnly == "on" {
|
||||
rangeTake = operatorRules
|
||||
}
|
||||
|
||||
if len(actions) == 0 {
|
||||
return []string{}
|
||||
}
|
||||
// Prepare new ActionSet structure that will hold all the user actions
|
||||
userAllowedAction := actionsStringToActionSet(actions)
|
||||
allowedEndpoints := []string{}
|
||||
for endpoint, rules := range rangeTake {
|
||||
// check if user policy matches s3:* or admin:* typesIntersection
|
||||
endpointActionTypes := rules.actionTypes
|
||||
typesIntersection := endpointActionTypes.Intersection(userAllowedAction)
|
||||
if len(typesIntersection) == len(endpointActionTypes.ToSlice()) {
|
||||
allowedEndpoints = append(allowedEndpoints, endpoint)
|
||||
continue
|
||||
}
|
||||
// check if user policy matches explicitly defined endpoint required actions
|
||||
endpointRequiredActions := rules.actions
|
||||
actionsIntersection := endpointRequiredActions.Intersection(userAllowedAction)
|
||||
if len(actionsIntersection) == len(endpointRequiredActions.ToSlice()) {
|
||||
allowedEndpoints = append(allowedEndpoints, endpoint)
|
||||
}
|
||||
}
|
||||
return allowedEndpoints
|
||||
}
|
||||
190
pkg/acl/endpoints_test.go
Normal file
@@ -0,0 +1,190 @@
|
||||
// This file is part of MinIO Orchestrator
|
||||
// Copyright (c) 2020 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 acl
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
iampolicy "github.com/minio/minio/pkg/iam/policy"
|
||||
)
|
||||
|
||||
type args struct {
|
||||
actions []string
|
||||
}
|
||||
|
||||
type endpoint struct {
|
||||
name string
|
||||
args args
|
||||
want int
|
||||
}
|
||||
|
||||
func validateEndpoints(t *testing.T, configs []endpoint) {
|
||||
for _, tt := range configs {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := GetAuthorizedEndpoints(tt.args.actions); !reflect.DeepEqual(len(got), tt.want) {
|
||||
t.Errorf("GetAuthorizedEndpoints() = %v, want %v", len(got), tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAuthorizedEndpoints(t *testing.T) {
|
||||
tests := []endpoint{
|
||||
{
|
||||
name: "dashboard endpoint",
|
||||
args: args{
|
||||
[]string{"admin:ServerInfo"},
|
||||
},
|
||||
want: 2,
|
||||
},
|
||||
{
|
||||
name: "policies endpoint",
|
||||
args: args{
|
||||
[]string{
|
||||
"admin:CreatePolicy",
|
||||
"admin:DeletePolicy",
|
||||
"admin:GetPolicy",
|
||||
"admin:AttachUserOrGroupPolicy",
|
||||
"admin:ListUserPolicies",
|
||||
},
|
||||
},
|
||||
want: 2,
|
||||
},
|
||||
{
|
||||
name: "all admin endpoints",
|
||||
args: args{
|
||||
[]string{
|
||||
"admin:*",
|
||||
},
|
||||
},
|
||||
want: 11,
|
||||
},
|
||||
{
|
||||
name: "all s3 endpoints",
|
||||
args: args{
|
||||
[]string{
|
||||
"s3:*",
|
||||
},
|
||||
},
|
||||
want: 4,
|
||||
},
|
||||
{
|
||||
name: "all admin and s3 endpoints",
|
||||
args: args{
|
||||
[]string{
|
||||
"admin:*",
|
||||
"s3:*",
|
||||
},
|
||||
},
|
||||
want: 14,
|
||||
},
|
||||
{
|
||||
name: "no endpoints",
|
||||
args: args{
|
||||
[]string{},
|
||||
},
|
||||
want: 0,
|
||||
},
|
||||
}
|
||||
|
||||
validateEndpoints(t, tests)
|
||||
}
|
||||
|
||||
func TestOperatorOnlyEndpoints(t *testing.T) {
|
||||
operatorOnly = "on"
|
||||
|
||||
tests := []endpoint{
|
||||
{
|
||||
name: "Operator Only - all admin endpoints",
|
||||
args: args{
|
||||
[]string{
|
||||
"admin:*",
|
||||
},
|
||||
},
|
||||
want: 2,
|
||||
},
|
||||
{
|
||||
name: "Operator Only - all s3 endpoints",
|
||||
args: args{
|
||||
[]string{
|
||||
"s3:*",
|
||||
},
|
||||
},
|
||||
want: 2,
|
||||
},
|
||||
{
|
||||
name: "Operator Only - all admin and s3 endpoints",
|
||||
args: args{
|
||||
[]string{
|
||||
"admin:*",
|
||||
"s3:*",
|
||||
},
|
||||
},
|
||||
want: 2,
|
||||
},
|
||||
{
|
||||
name: "Operator Only - no endpoints",
|
||||
args: args{
|
||||
[]string{},
|
||||
},
|
||||
want: 0,
|
||||
},
|
||||
}
|
||||
|
||||
validateEndpoints(t, tests)
|
||||
}
|
||||
|
||||
func TestGetActionsStringFromPolicy(t *testing.T) {
|
||||
type args struct {
|
||||
policy *iampolicy.Policy
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want int
|
||||
}{
|
||||
{
|
||||
name: "parse ReadOnly policy",
|
||||
args: args{
|
||||
policy: &iampolicy.ReadOnly,
|
||||
},
|
||||
want: 2,
|
||||
},
|
||||
{
|
||||
name: "parse WriteOnly policy",
|
||||
args: args{
|
||||
policy: &iampolicy.WriteOnly,
|
||||
},
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
name: "parse AdminDiagnostics policy",
|
||||
args: args{
|
||||
policy: &iampolicy.AdminDiagnostics,
|
||||
},
|
||||
want: 6,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := GetActionsStringFromPolicy(tt.args.policy); !reflect.DeepEqual(len(got), tt.want) {
|
||||
t.Errorf("GetActionsStringFromPolicy() = %v, want %v", len(got), tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
49
pkg/auth/idp.go
Normal file
@@ -0,0 +1,49 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/minio/mcs/pkg/auth/idp/oauth2"
|
||||
)
|
||||
|
||||
// IdentityProviderClient interface with all functions to be implemented
|
||||
// by mock when testing, it should include all IdentityProviderClient respective api calls
|
||||
// that are used within this project.
|
||||
type IdentityProviderClient interface {
|
||||
VerifyIdentity(ctx context.Context, code, state string) (*oauth2.User, error)
|
||||
GenerateLoginURL() string
|
||||
}
|
||||
|
||||
// Interface implementation
|
||||
//
|
||||
// Define the structure of a IdentityProvider Client and define the functions that are actually used
|
||||
// during the authentication flow.
|
||||
type IdentityProvider struct {
|
||||
Client IdentityProviderClient
|
||||
}
|
||||
|
||||
// VerifyIdentity will verify the user identity against the idp using the authorization code flow
|
||||
func (c IdentityProvider) VerifyIdentity(ctx context.Context, code, state string) (*oauth2.User, error) {
|
||||
return c.Client.VerifyIdentity(ctx, code, state)
|
||||
}
|
||||
|
||||
// GenerateLoginURL returns a new URL used by the user to login against the idp
|
||||
func (c IdentityProvider) GenerateLoginURL() string {
|
||||
return c.Client.GenerateLoginURL()
|
||||
}
|
||||
71
pkg/auth/idp/oauth2/config.go
Normal file
@@ -0,0 +1,71 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 oauth2 contains all the necessary configurations to initialize the
|
||||
// idp communication using oauth2 protocol
|
||||
package oauth2
|
||||
|
||||
import (
|
||||
"github.com/minio/mcs/pkg/auth/utils"
|
||||
"github.com/minio/minio/pkg/env"
|
||||
)
|
||||
|
||||
func GetIdpURL() string {
|
||||
return env.Get(McsIdpURL, "")
|
||||
}
|
||||
|
||||
func GetIdpClientID() string {
|
||||
return env.Get(McsIdpClientID, "")
|
||||
}
|
||||
|
||||
func GetIdpSecret() string {
|
||||
return env.Get(McsIdpSecret, "")
|
||||
}
|
||||
|
||||
// Public endpoint used by the identity oidcProvider when redirecting the user after identity verification
|
||||
func GetIdpCallbackURL() string {
|
||||
return env.Get(McsIdpCallbackURL, "")
|
||||
}
|
||||
|
||||
func GetIdpAdminRoles() string {
|
||||
return env.Get(McsIdpAdminRoles, "")
|
||||
}
|
||||
|
||||
func IsIdpEnabled() bool {
|
||||
return GetIdpURL() != "" &&
|
||||
GetIdpClientID() != "" &&
|
||||
GetIdpSecret() != "" &&
|
||||
GetIdpCallbackURL() != ""
|
||||
}
|
||||
|
||||
var defaultPassphraseForIdpHmac = utils.RandomCharString(64)
|
||||
|
||||
// GetPassphraseForIdpHmac returns passphrase for the pbkdf2 function used to sign the oauth2 state parameter
|
||||
func getPassphraseForIdpHmac() string {
|
||||
return env.Get(McsIdpHmacPassphrase, defaultPassphraseForIdpHmac)
|
||||
}
|
||||
|
||||
var defaultSaltForIdpHmac = utils.RandomCharString(64)
|
||||
|
||||
// GetSaltForIdpHmac returns salt for the pbkdf2 function used to sign the oauth2 state parameter
|
||||
func getSaltForIdpHmac() string {
|
||||
return env.Get(McsIdpHmacSalt, defaultSaltForIdpHmac)
|
||||
}
|
||||
|
||||
// GetSaltForIdpHmac returns the policy to be assigned to the users authenticating via an IDP
|
||||
func GetIDPPolicyForUser() string {
|
||||
return env.Get(McsIdpPolicyUser, "mcsAdmin")
|
||||
}
|
||||
29
pkg/auth/idp/oauth2/const.go
Normal file
@@ -0,0 +1,29 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 oauth2
|
||||
|
||||
const (
|
||||
// const for idp configuration
|
||||
McsIdpURL = "MCS_IDP_URL"
|
||||
McsIdpClientID = "MCS_IDP_CLIENT_ID"
|
||||
McsIdpSecret = "MCS_IDP_SECRET"
|
||||
McsIdpCallbackURL = "MCS_IDP_CALLBACK"
|
||||
McsIdpAdminRoles = "MCS_IDP_ADMIN_ROLES"
|
||||
McsIdpHmacPassphrase = "MCS_IDP_HMAC_PASSPHRASE"
|
||||
McsIdpHmacSalt = "MCS_IDP_HMAC_SALT"
|
||||
McsIdpPolicyUser = "MCS_IDP_POLICY_USER"
|
||||
)
|
||||
229
pkg/auth/idp/oauth2/provider.go
Normal file
@@ -0,0 +1,229 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 oauth2
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha1"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/coreos/go-oidc"
|
||||
"github.com/minio/mcs/pkg/auth/utils"
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
xoauth2 "golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
var (
|
||||
errGeneric = errors.New("an error occurred, please try again")
|
||||
)
|
||||
|
||||
type Configuration interface {
|
||||
Exchange(ctx context.Context, code string, opts ...xoauth2.AuthCodeOption) (*xoauth2.Token, error)
|
||||
AuthCodeURL(state string, opts ...xoauth2.AuthCodeOption) string
|
||||
PasswordCredentialsToken(ctx context.Context, username string, password string) (*xoauth2.Token, error)
|
||||
Client(ctx context.Context, t *xoauth2.Token) *http.Client
|
||||
TokenSource(ctx context.Context, t *xoauth2.Token) xoauth2.TokenSource
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
xoauth2.Config
|
||||
}
|
||||
|
||||
func (ac Config) Exchange(ctx context.Context, code string, opts ...xoauth2.AuthCodeOption) (*xoauth2.Token, error) {
|
||||
return ac.Exchange(ctx, code, opts...)
|
||||
}
|
||||
|
||||
func (ac Config) AuthCodeURL(state string, opts ...xoauth2.AuthCodeOption) string {
|
||||
return ac.AuthCodeURL(state, opts...)
|
||||
}
|
||||
|
||||
func (ac Config) PasswordCredentialsToken(ctx context.Context, username string, password string) (*xoauth2.Token, error) {
|
||||
return ac.PasswordCredentialsToken(ctx, username, password)
|
||||
}
|
||||
|
||||
func (ac Config) Client(ctx context.Context, t *xoauth2.Token) *http.Client {
|
||||
return ac.Client(ctx, t)
|
||||
}
|
||||
|
||||
func (ac Config) TokenSource(ctx context.Context, t *xoauth2.Token) xoauth2.TokenSource {
|
||||
return ac.TokenSource(ctx, t)
|
||||
}
|
||||
|
||||
// Provider is a wrapper of the oauth2 configuration and the oidc provider
|
||||
type Provider struct {
|
||||
// oauth2Config is an interface configuration that contains the following fields
|
||||
// Config{
|
||||
// ClientID string
|
||||
// ClientSecret string
|
||||
// RedirectURL string
|
||||
// Endpoint oauth2.Endpoint
|
||||
// Scopes []string
|
||||
// }
|
||||
// - ClientID is the public identifier for this application
|
||||
// - ClientSecret is a shared secret between this application and the authorization server
|
||||
// - RedirectURL is the URL to redirect users going through
|
||||
// the OAuth flow, after the resource owner's URLs.
|
||||
// - Endpoint contains the resource server's token endpoint
|
||||
// URLs. These are constants specific to each server and are
|
||||
// often available via site-specific packages, such as
|
||||
// google.Endpoint or github.Endpoint.
|
||||
// - Scopes specifies optional requested permissions.
|
||||
ClientID string
|
||||
oauth2Config Configuration
|
||||
oidcProvider *oidc.Provider
|
||||
}
|
||||
|
||||
// derivedKey is the key used to compute the HMAC for signing the oauth state parameter
|
||||
// its derived using pbkdf on MCS_IDP_HMAC_PASSPHRASE with MCS_IDP_HMAC_SALT
|
||||
var derivedKey = pbkdf2.Key([]byte(getPassphraseForIdpHmac()), []byte(getSaltForIdpHmac()), 4096, 32, sha1.New)
|
||||
|
||||
// NewOauth2ProviderClient instantiates a new oauth2 client using the configured credentials
|
||||
// it returns a *Provider object that contains the necessary configuration to initiate an
|
||||
// oauth2 authentication flow
|
||||
func NewOauth2ProviderClient(ctx context.Context, scopes []string) (*Provider, error) {
|
||||
provider, err := oidc.NewProvider(ctx, GetIdpURL())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// If provided scopes are empty we use a default list
|
||||
if len(scopes) == 0 {
|
||||
scopes = []string{oidc.ScopeOpenID, "profile", "app_metadata", "user_metadata", "email"}
|
||||
}
|
||||
client := new(Provider)
|
||||
config := xoauth2.Config{
|
||||
ClientID: GetIdpClientID(),
|
||||
ClientSecret: GetIdpSecret(),
|
||||
RedirectURL: GetIdpCallbackURL(),
|
||||
Endpoint: provider.Endpoint(),
|
||||
Scopes: scopes,
|
||||
}
|
||||
client.oauth2Config = &config
|
||||
client.oidcProvider = provider
|
||||
client.ClientID = GetIdpClientID()
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
type User struct {
|
||||
AppMetadata map[string]interface{} `json:"app_metadata"`
|
||||
Blocked bool `json:"blocked"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
Email string `json:"email"`
|
||||
EmailVerified bool `json:"email_verified"`
|
||||
FamilyName string `json:"family_name"`
|
||||
GivenName string `json:"given_name"`
|
||||
Identities []interface{} `json:"identities"`
|
||||
LastIP string `json:"last_ip"`
|
||||
LastLogin string `json:"last_login"`
|
||||
LastPasswordReset string `json:"last_password_reset"`
|
||||
LoginsCount int `json:"logins_count"`
|
||||
Mltifactor string `json:"multifactor"`
|
||||
Name string `json:"name"`
|
||||
Nickname string `json:"nickname"`
|
||||
PhoneNumber string `json:"phone_number"`
|
||||
PhoneVerified bool `json:"phone_verified"`
|
||||
Picture string `json:"picture"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
UserID string `json:"user_id"`
|
||||
UserMetadata map[string]interface{} `json:"user_metadata"`
|
||||
Username string `json:"username"`
|
||||
}
|
||||
|
||||
// VerifyIdentity will contact the configured IDP and validate the user identity based on the authorization code
|
||||
func (client *Provider) VerifyIdentity(ctx context.Context, code, state string) (*User, error) {
|
||||
// verify the provided state is valid (prevents CSRF attacks)
|
||||
if !validateOauth2State(state) {
|
||||
return nil, errGeneric
|
||||
}
|
||||
// verify the authorization code against the identity oidcProvider
|
||||
// idp will return a token in exchange
|
||||
token, err := client.oauth2Config.Exchange(ctx, code)
|
||||
if err != nil {
|
||||
log.Println("Failed to verify authorization code", err)
|
||||
return nil, errGeneric
|
||||
}
|
||||
// extract and check id_token field is provided in the response
|
||||
rawIDToken, ok := token.Extra("id_token").(string)
|
||||
if !ok {
|
||||
log.Println("No id_token field in oauth2 token")
|
||||
return nil, errGeneric
|
||||
}
|
||||
config := &oidc.Config{
|
||||
ClientID: client.ClientID,
|
||||
}
|
||||
idToken, err := client.oidcProvider.Verifier(config).Verify(ctx, rawIDToken)
|
||||
if err != nil {
|
||||
log.Println("Failed to verify ID token", err)
|
||||
return nil, errGeneric
|
||||
}
|
||||
var profile User
|
||||
// Populate the profile object using the claims included in the token
|
||||
if err := idToken.Claims(&profile); err != nil {
|
||||
log.Println("Failed to read profile information", err)
|
||||
return nil, errGeneric
|
||||
}
|
||||
return &profile, nil
|
||||
}
|
||||
|
||||
// validateOauth2State validates the provided state was originated using the same
|
||||
// instance (or one configured using the same secrets) of MCS, this is basically used to prevent CSRF attacks
|
||||
// https://security.stackexchange.com/questions/20187/oauth2-cross-site-request-forgery-and-state-parameter
|
||||
func validateOauth2State(state string) bool {
|
||||
// state contains a base64 encoded string that may ends with "==", the browser encodes that to "%3D%3D"
|
||||
// query unescape is need it before trying to decode the base64 string
|
||||
encodedMessage, err := url.QueryUnescape(state)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return false
|
||||
}
|
||||
// decode the state parameter value
|
||||
message, err := base64.StdEncoding.DecodeString(encodedMessage)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return false
|
||||
}
|
||||
s := strings.Split(string(message), ":")
|
||||
// Validate that the decoded message has the right format "message:hmac"
|
||||
if len(s) != 2 {
|
||||
return false
|
||||
}
|
||||
// extract the state and hmac
|
||||
incomingState, incomingHmac := s[0], s[1]
|
||||
// validate that hmac(incomingState + pbkdf2(secret, salt)) == incomingHmac
|
||||
return utils.ComputeHmac256(incomingState, derivedKey) == incomingHmac
|
||||
}
|
||||
|
||||
// GetRandomStateWithHMAC computes message + hmac(message, pbkdf2(key, salt)) to be used as state during the oauth authorization
|
||||
func GetRandomStateWithHMAC(length int) string {
|
||||
state := utils.RandomCharString(length)
|
||||
hmac := utils.ComputeHmac256(state, derivedKey)
|
||||
return base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", state, hmac)))
|
||||
}
|
||||
|
||||
// GenerateLoginURL returns a new login URL based on the configured IDP
|
||||
func (client *Provider) GenerateLoginURL() string {
|
||||
// generates random state and sign it using HMAC256
|
||||
state := GetRandomStateWithHMAC(25)
|
||||
loginURL := client.oauth2Config.AuthCodeURL(state)
|
||||
return strings.TrimSpace(loginURL)
|
||||
}
|
||||
98
pkg/auth/idp/oauth2/provider_test.go
Normal file
@@ -0,0 +1,98 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 oauth2
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/coreos/go-oidc"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
type Oauth2configMock struct{}
|
||||
|
||||
var oauth2ConfigExchangeMock func(ctx context.Context, code string, opts ...oauth2.AuthCodeOption) (*oauth2.Token, error)
|
||||
var oauth2ConfigAuthCodeURLMock func(state string, opts ...oauth2.AuthCodeOption) string
|
||||
var oauth2ConfigPasswordCredentialsTokenMock func(ctx context.Context, username string, password string) (*oauth2.Token, error)
|
||||
var oauth2ConfigClientMock func(ctx context.Context, t *oauth2.Token) *http.Client
|
||||
var oauth2ConfigokenSourceMock func(ctx context.Context, t *oauth2.Token) oauth2.TokenSource
|
||||
|
||||
func (ac Oauth2configMock) Exchange(ctx context.Context, code string, opts ...oauth2.AuthCodeOption) (*oauth2.Token, error) {
|
||||
return oauth2ConfigExchangeMock(ctx, code, opts...)
|
||||
}
|
||||
|
||||
func (ac Oauth2configMock) AuthCodeURL(state string, opts ...oauth2.AuthCodeOption) string {
|
||||
return oauth2ConfigAuthCodeURLMock(state, opts...)
|
||||
}
|
||||
|
||||
func (ac Oauth2configMock) PasswordCredentialsToken(ctx context.Context, username string, password string) (*oauth2.Token, error) {
|
||||
return oauth2ConfigPasswordCredentialsTokenMock(ctx, username, password)
|
||||
}
|
||||
|
||||
func (ac Oauth2configMock) Client(ctx context.Context, t *oauth2.Token) *http.Client {
|
||||
return oauth2ConfigClientMock(ctx, t)
|
||||
}
|
||||
|
||||
func (ac Oauth2configMock) TokenSource(ctx context.Context, t *oauth2.Token) oauth2.TokenSource {
|
||||
return oauth2ConfigokenSourceMock(ctx, t)
|
||||
}
|
||||
|
||||
func TestGenerateLoginURL(t *testing.T) {
|
||||
funcAssert := assert.New(t)
|
||||
oauth2Provider := Provider{
|
||||
oauth2Config: Oauth2configMock{},
|
||||
oidcProvider: &oidc.Provider{},
|
||||
}
|
||||
// Test-1 : GenerateLoginURL() generates URL correctly with provided state
|
||||
oauth2ConfigAuthCodeURLMock = func(state string, opts ...oauth2.AuthCodeOption) string {
|
||||
// Internally we are testing the private method getRandomStateWithHMAC, this function should always returns
|
||||
// a non-empty string
|
||||
return state
|
||||
}
|
||||
url := oauth2Provider.GenerateLoginURL()
|
||||
funcAssert.NotEqual("", url)
|
||||
}
|
||||
|
||||
func TestVerifyIdentity(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
funcAssert := assert.New(t)
|
||||
// mock data
|
||||
oauth2Provider := Provider{
|
||||
oauth2Config: Oauth2configMock{},
|
||||
oidcProvider: &oidc.Provider{},
|
||||
}
|
||||
// Test-1 : VerifyIdentity() should fail because of bad state token
|
||||
_, err := oauth2Provider.VerifyIdentity(ctx, "AAABBBCCCDDDEEEFFF", "badtoken")
|
||||
funcAssert.NotNil(err)
|
||||
// Test-2 : VerifyIdentity() should fail because no id_token is provided by the idp
|
||||
oauth2ConfigExchangeMock = func(ctx context.Context, code string, opts ...oauth2.AuthCodeOption) (*oauth2.Token, error) {
|
||||
return &oauth2.Token{}, nil
|
||||
}
|
||||
state := GetRandomStateWithHMAC(32)
|
||||
code := "AAABBBCCCDDDEEEFFF"
|
||||
_, err = oauth2Provider.VerifyIdentity(ctx, code, state)
|
||||
funcAssert.NotNil(err)
|
||||
// Test-3 : VerifyIdentity() should fail because no id_token is provided by the idp
|
||||
// TODO
|
||||
// Test-4 : VerifyIdentity() should fail because oidcProvider.Verifier returned an error
|
||||
// TODO
|
||||
// Test-5 : VerifyIdentity() should fail because idToken.Claims contains invalid fields
|
||||
// TODO
|
||||
}
|
||||
184
pkg/auth/jwt.go
Normal file
@@ -0,0 +1,184 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 auth
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"crypto/sha1"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
jwtgo "github.com/dgrijalva/jwt-go"
|
||||
xjwt "github.com/minio/mcs/pkg/auth/jwt"
|
||||
"github.com/minio/minio-go/v6/pkg/credentials"
|
||||
"github.com/minio/minio/cmd"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
)
|
||||
|
||||
var (
|
||||
errAuthentication = errors.New("authentication failed, check your access credentials")
|
||||
errNoAuthToken = errors.New("JWT token missing")
|
||||
errReadingToken = errors.New("JWT internal data is malformed")
|
||||
errClaimsFormat = errors.New("encrypted jwt claims not in the right format")
|
||||
)
|
||||
|
||||
// derivedKey is the key used to encrypt the JWT claims, its derived using pbkdf on MCS_PBKDF_PASSPHRASE with MCS_PBKDF_SALT
|
||||
var derivedKey = pbkdf2.Key([]byte(xjwt.GetPBKDFPassphrase()), []byte(xjwt.GetPBKDFSalt()), 4096, 32, sha1.New)
|
||||
|
||||
// IsJWTValid returns true or false depending if the provided jwt is valid or not
|
||||
func IsJWTValid(token string) bool {
|
||||
_, err := JWTAuthenticate(token)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// DecryptedClaims claims struct for decrypted credentials
|
||||
type DecryptedClaims struct {
|
||||
AccessKeyID string
|
||||
SecretAccessKey string
|
||||
SessionToken string
|
||||
Actions []string
|
||||
}
|
||||
|
||||
// JWTAuthenticate takes a jwt, decode it, extract claims and validate the signature
|
||||
// if the jwt claims.Data is valid we proceed to decrypt the information inside
|
||||
//
|
||||
// returns claims after validation in the following format:
|
||||
//
|
||||
// type DecryptedClaims struct {
|
||||
// AccessKeyID
|
||||
// SecretAccessKey
|
||||
// SessionToken
|
||||
// }
|
||||
func JWTAuthenticate(token string) (*DecryptedClaims, error) {
|
||||
if token == "" {
|
||||
return nil, errNoAuthToken
|
||||
}
|
||||
// initialize claims object
|
||||
claims := xjwt.NewMapClaims()
|
||||
// populate the claims object
|
||||
if err := xjwt.ParseWithClaims(token, claims); err != nil {
|
||||
return nil, errAuthentication
|
||||
}
|
||||
// decrypt the claims.Data field
|
||||
claimTokens, err := decryptClaims(claims.Data)
|
||||
if err != nil {
|
||||
// we print decryption token error information for debugging purposes
|
||||
log.Println(err)
|
||||
// we return a generic error that doesn't give any information to attackers
|
||||
return nil, errReadingToken
|
||||
}
|
||||
// claimsTokens contains the decrypted STS claims
|
||||
return claimTokens, nil
|
||||
}
|
||||
|
||||
// NewJWTWithClaimsForClient generates a new jwt with claims based on the provided STS credentials, first
|
||||
// encrypts the claims and the sign them
|
||||
func NewJWTWithClaimsForClient(credentials *credentials.Value, actions []string, audience string) (string, error) {
|
||||
if credentials != nil {
|
||||
encryptedClaims, err := encryptClaims(credentials.AccessKeyID, credentials.SecretAccessKey, credentials.SessionToken, actions)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
claims := xjwt.NewStandardClaims()
|
||||
claims.SetExpiry(cmd.UTCNow().Add(xjwt.GetMcsSTSAndJWTDurationTime()))
|
||||
claims.SetSubject(uuid.NewV4().String())
|
||||
claims.SetData(encryptedClaims)
|
||||
claims.SetAudience(audience)
|
||||
jwt := jwtgo.NewWithClaims(jwtgo.SigningMethodHS512, claims)
|
||||
return jwt.SignedString([]byte(xjwt.GetHmacJWTSecret()))
|
||||
}
|
||||
return "", errors.New("provided credentials are empty")
|
||||
}
|
||||
|
||||
// encryptClaims() receives the 3 STS claims, concatenate them and encrypt them using AES-GCM
|
||||
// returns a base64 encoded ciphertext
|
||||
func encryptClaims(accessKeyID, secretAccessKey, sessionToken string, actions []string) (string, error) {
|
||||
payload := []byte(fmt.Sprintf("%s#%s#%s#%s", accessKeyID, secretAccessKey, sessionToken, strings.Join(actions, ",")))
|
||||
ciphertext, err := encrypt(payload)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(ciphertext), nil
|
||||
}
|
||||
|
||||
// decryptClaims() receives base64 encoded ciphertext, decode it, decrypt it (AES-GCM) and produces a *DecryptedClaims object
|
||||
func decryptClaims(ciphertext string) (*DecryptedClaims, error) {
|
||||
decoded, err := base64.StdEncoding.DecodeString(ciphertext)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return nil, errClaimsFormat
|
||||
}
|
||||
plaintext, err := decrypt(decoded)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return nil, errClaimsFormat
|
||||
}
|
||||
s := strings.Split(string(plaintext), "#")
|
||||
// Validate that the decrypted string has the right format "accessKeyID:secretAccessKey:sessionToken"
|
||||
if len(s) != 4 {
|
||||
return nil, errClaimsFormat
|
||||
}
|
||||
accessKeyID, secretAccessKey, sessionToken, actions := s[0], s[1], s[2], s[3]
|
||||
actionsList := strings.Split(actions, ",")
|
||||
return &DecryptedClaims{
|
||||
AccessKeyID: accessKeyID,
|
||||
SecretAccessKey: secretAccessKey,
|
||||
SessionToken: sessionToken,
|
||||
Actions: actionsList,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Encrypt a blob of data using AEAD (AES-GCM) with a pbkdf2 derived key
|
||||
func encrypt(plaintext []byte) ([]byte, error) {
|
||||
block, _ := aes.NewCipher(derivedKey)
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nonce := make([]byte, gcm.NonceSize())
|
||||
if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cipherText := gcm.Seal(nonce, nonce, plaintext, nil)
|
||||
return cipherText, nil
|
||||
}
|
||||
|
||||
// Decrypts a blob of data using AEAD (AES-GCM) with a pbkdf2 derived key
|
||||
func decrypt(data []byte) ([]byte, error) {
|
||||
block, err := aes.NewCipher(derivedKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nonceSize := gcm.NonceSize()
|
||||
nonce, cipherText := data[:nonceSize], data[nonceSize:]
|
||||
plaintext, err := gcm.Open(nil, nonce, cipherText, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return plaintext, nil
|
||||
}
|
||||
63
pkg/auth/jwt/config.go
Normal file
@@ -0,0 +1,63 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 jwt
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/minio/mcs/pkg/auth/utils"
|
||||
"github.com/minio/minio/pkg/env"
|
||||
)
|
||||
|
||||
// defaultHmacJWTPassphrase will be used by default if application is not configured with a custom MCS_HMAC_JWT_SECRET secret
|
||||
var defaultHmacJWTPassphrase = utils.RandomCharString(64)
|
||||
|
||||
// GetHmacJWTSecret returns the 64 bytes secret used for signing the generated JWT for the application
|
||||
func GetHmacJWTSecret() string {
|
||||
return env.Get(McsHmacJWTSecret, defaultHmacJWTPassphrase)
|
||||
}
|
||||
|
||||
// McsSTSAndJWTDurationSeconds returns the default session duration for the STS requested tokens and the generated JWTs.
|
||||
// Ideally both values should match so jwt and Minio sts sessions expires at the same time.
|
||||
func GetMcsSTSAndJWTDurationInSeconds() int {
|
||||
duration, err := strconv.Atoi(env.Get(McsSTSAndJWTDurationSeconds, "3600"))
|
||||
if err != nil {
|
||||
duration = 3600
|
||||
}
|
||||
return duration
|
||||
}
|
||||
|
||||
// GetMcsSTSAndJWTDurationTime returns GetMcsSTSAndJWTDurationInSeconds in duration format
|
||||
func GetMcsSTSAndJWTDurationTime() time.Duration {
|
||||
duration := GetMcsSTSAndJWTDurationInSeconds()
|
||||
return time.Duration(duration) * time.Second
|
||||
}
|
||||
|
||||
var defaultPBKDFPassphrase = utils.RandomCharString(64)
|
||||
|
||||
// GetPBKDFPassphrase returns passphrase for the pbkdf2 function used to encrypt JWT payload
|
||||
func GetPBKDFPassphrase() string {
|
||||
return env.Get(McsPBKDFPassphrase, defaultPBKDFPassphrase)
|
||||
}
|
||||
|
||||
var defaultPBKDFSalt = utils.RandomCharString(64)
|
||||
|
||||
// GetPBKDFSalt returns salt for the pbkdf2 function used to encrypt JWT payload
|
||||
func GetPBKDFSalt() string {
|
||||
return env.Get(McsPBKDFSalt, defaultPBKDFSalt)
|
||||
}
|
||||
24
pkg/auth/jwt/const.go
Normal file
@@ -0,0 +1,24 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 jwt
|
||||
|
||||
const (
|
||||
McsHmacJWTSecret = "MCS_HMAC_JWT_SECRET"
|
||||
McsSTSAndJWTDurationSeconds = "MCS_STS_AND_JWT_DURATION_SECONDS"
|
||||
McsPBKDFPassphrase = "MCS_PBKDF_PASSPHRASE"
|
||||
McsPBKDFSalt = "MCS_PBKDF_SALT"
|
||||
)
|
||||
281
pkg/auth/jwt/parser.go
Normal file
@@ -0,0 +1,281 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 jwt
|
||||
|
||||
// This file is a re-implementation of the original code here with some
|
||||
// additional allocation tweaks reproduced using GODEBUG=allocfreetrace=1
|
||||
// original file https://github.com/dgrijalva/jwt-go/blob/master/parser.go
|
||||
// borrowed under MIT License https://github.com/dgrijalva/jwt-go/blob/master/LICENSE
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/hmac"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
jwtgo "github.com/dgrijalva/jwt-go"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
)
|
||||
|
||||
const (
|
||||
claimData = "data"
|
||||
claimSub = "sub"
|
||||
)
|
||||
|
||||
// SigningMethodHMAC - Implements the HMAC-SHA family of signing methods signing methods
|
||||
// Expects key type of []byte for both signing and validation
|
||||
type SigningMethodHMAC struct {
|
||||
Name string
|
||||
Hash crypto.Hash
|
||||
}
|
||||
|
||||
// Specific instances for HS256, HS384, HS512
|
||||
var (
|
||||
SigningMethodHS256 *SigningMethodHMAC
|
||||
SigningMethodHS384 *SigningMethodHMAC
|
||||
SigningMethodHS512 *SigningMethodHMAC
|
||||
)
|
||||
|
||||
var (
|
||||
base64BufPool sync.Pool
|
||||
hmacSigners []*SigningMethodHMAC
|
||||
)
|
||||
|
||||
func init() {
|
||||
base64BufPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
buf := make([]byte, 8192)
|
||||
return &buf
|
||||
},
|
||||
}
|
||||
|
||||
hmacSigners = []*SigningMethodHMAC{
|
||||
{"HS256", crypto.SHA256},
|
||||
{"HS384", crypto.SHA384},
|
||||
{"HS512", crypto.SHA512},
|
||||
}
|
||||
}
|
||||
|
||||
// StandardClaims are basically standard claims with "Data"
|
||||
type StandardClaims struct {
|
||||
Data string `json:"data,omitempty"`
|
||||
jwtgo.StandardClaims
|
||||
}
|
||||
|
||||
// MapClaims - implements custom unmarshaller
|
||||
type MapClaims struct {
|
||||
Data string `json:"data,omitempty"`
|
||||
Subject string `json:"sub,omitempty"`
|
||||
jwtgo.MapClaims
|
||||
}
|
||||
|
||||
// NewStandardClaims - initializes standard claims
|
||||
func NewStandardClaims() *StandardClaims {
|
||||
return &StandardClaims{}
|
||||
}
|
||||
|
||||
// SetIssuer sets issuer for these claims
|
||||
func (c *StandardClaims) SetIssuer(issuer string) {
|
||||
c.Issuer = issuer
|
||||
}
|
||||
|
||||
// SetAudience sets audience for these claims
|
||||
func (c *StandardClaims) SetAudience(aud string) {
|
||||
c.Audience = aud
|
||||
}
|
||||
|
||||
// SetExpiry sets expiry in unix epoch secs
|
||||
func (c *StandardClaims) SetExpiry(t time.Time) {
|
||||
c.ExpiresAt = t.Unix()
|
||||
}
|
||||
|
||||
// SetSubject sets unique identifier for the jwt
|
||||
func (c *StandardClaims) SetSubject(subject string) {
|
||||
c.Subject = subject
|
||||
}
|
||||
|
||||
// SetData sets the "Data" custom field.
|
||||
func (c *StandardClaims) SetData(data string) {
|
||||
c.Data = data
|
||||
}
|
||||
|
||||
// Valid - implements https://godoc.org/github.com/dgrijalva/jwt-go#Claims compatible
|
||||
// claims interface, additionally validates "Data" field.
|
||||
func (c *StandardClaims) Valid() error {
|
||||
if err := c.StandardClaims.Valid(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.Data == "" || c.Subject == "" {
|
||||
return jwtgo.NewValidationError("data/sub",
|
||||
jwtgo.ValidationErrorClaimsInvalid)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewMapClaims - Initializes a new map claims
|
||||
func NewMapClaims() *MapClaims {
|
||||
return &MapClaims{MapClaims: jwtgo.MapClaims{}}
|
||||
}
|
||||
|
||||
// Lookup returns the value and if the key is found.
|
||||
func (c *MapClaims) Lookup(key string) (value string, ok bool) {
|
||||
var vinterface interface{}
|
||||
vinterface, ok = c.MapClaims[key]
|
||||
if ok {
|
||||
value, ok = vinterface.(string)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// SetExpiry sets expiry in unix epoch secs
|
||||
func (c *MapClaims) SetExpiry(t time.Time) {
|
||||
c.MapClaims["exp"] = t.Unix()
|
||||
}
|
||||
|
||||
// SetData sets the "Data" custom field.
|
||||
func (c *MapClaims) SetData(data string) {
|
||||
c.MapClaims[claimData] = data
|
||||
}
|
||||
|
||||
// Valid - implements https://godoc.org/github.com/dgrijalva/jwt-go#Claims compatible
|
||||
// claims interface, additionally validates "Data" field.
|
||||
func (c *MapClaims) Valid() error {
|
||||
if err := c.MapClaims.Valid(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.Data == "" || c.Subject == "" {
|
||||
return jwtgo.NewValidationError("data/subject",
|
||||
jwtgo.ValidationErrorClaimsInvalid)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Map returns underlying low-level map claims.
|
||||
func (c *MapClaims) Map() map[string]interface{} {
|
||||
return c.MapClaims
|
||||
}
|
||||
|
||||
// MarshalJSON marshals the MapClaims struct
|
||||
func (c *MapClaims) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(c.MapClaims)
|
||||
}
|
||||
|
||||
// https://tools.ietf.org/html/rfc7519#page-11
|
||||
type jwtHeader struct {
|
||||
Algorithm string `json:"alg"`
|
||||
Type string `json:"typ"`
|
||||
}
|
||||
|
||||
// ParseWithClaims - parse the token string, valid methods.
|
||||
func ParseWithClaims(tokenStr string, claims *MapClaims) error {
|
||||
bufp := base64BufPool.Get().(*[]byte)
|
||||
defer base64BufPool.Put(bufp)
|
||||
|
||||
signer, err := parseUnverifiedMapClaims(tokenStr, claims, *bufp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
i := strings.LastIndex(tokenStr, ".")
|
||||
if i < 0 {
|
||||
return jwtgo.ErrSignatureInvalid
|
||||
}
|
||||
|
||||
n, err := base64Decode(tokenStr[i+1:], *bufp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var ok bool
|
||||
|
||||
claims.Data, ok = claims.Lookup(claimData)
|
||||
if !ok {
|
||||
return jwtgo.NewValidationError("data missing",
|
||||
jwtgo.ValidationErrorClaimsInvalid)
|
||||
}
|
||||
|
||||
claims.Subject, ok = claims.Lookup(claimSub)
|
||||
if !ok {
|
||||
return jwtgo.NewValidationError("sub missing",
|
||||
jwtgo.ValidationErrorClaimsInvalid)
|
||||
}
|
||||
|
||||
hasher := hmac.New(signer.Hash.New, []byte(GetHmacJWTSecret()))
|
||||
hasher.Write([]byte(tokenStr[:i]))
|
||||
if !hmac.Equal((*bufp)[:n], hasher.Sum(nil)) {
|
||||
return jwtgo.ErrSignatureInvalid
|
||||
}
|
||||
|
||||
// Signature is valid, lets validate the claims for
|
||||
// other fields such as expiry etc.
|
||||
return claims.Valid()
|
||||
}
|
||||
|
||||
// base64Decode returns the bytes represented by the base64 string s.
|
||||
func base64Decode(s string, buf []byte) (int, error) {
|
||||
return base64.RawURLEncoding.Decode(buf, []byte(s))
|
||||
}
|
||||
|
||||
// ParseUnverifiedMapClaims - WARNING: Don't use this method unless you know what you're doing
|
||||
//
|
||||
// This method parses the token but doesn't validate the signature. It's only
|
||||
// ever useful in cases where you know the signature is valid (because it has
|
||||
// been checked previously in the stack) and you want to extract values from
|
||||
// it.
|
||||
func parseUnverifiedMapClaims(tokenString string, claims *MapClaims, buf []byte) (*SigningMethodHMAC, error) {
|
||||
if strings.Count(tokenString, ".") != 2 {
|
||||
return nil, jwtgo.ErrSignatureInvalid
|
||||
}
|
||||
|
||||
i := strings.Index(tokenString, ".")
|
||||
j := strings.LastIndex(tokenString, ".")
|
||||
|
||||
n, err := base64Decode(tokenString[:i], buf)
|
||||
if err != nil {
|
||||
return nil, &jwtgo.ValidationError{Inner: err, Errors: jwtgo.ValidationErrorMalformed}
|
||||
}
|
||||
|
||||
var header = jwtHeader{}
|
||||
var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
if err = json.Unmarshal(buf[:n], &header); err != nil {
|
||||
return nil, &jwtgo.ValidationError{Inner: err, Errors: jwtgo.ValidationErrorMalformed}
|
||||
}
|
||||
|
||||
n, err = base64Decode(tokenString[i+1:j], buf)
|
||||
if err != nil {
|
||||
return nil, &jwtgo.ValidationError{Inner: err, Errors: jwtgo.ValidationErrorMalformed}
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(buf[:n], &claims.MapClaims); err != nil {
|
||||
return nil, &jwtgo.ValidationError{Inner: err, Errors: jwtgo.ValidationErrorMalformed}
|
||||
}
|
||||
|
||||
for _, signer := range hmacSigners {
|
||||
if header.Algorithm == signer.Name {
|
||||
return signer, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, jwtgo.NewValidationError(fmt.Sprintf("signing method (%s) is unavailable.", header.Algorithm),
|
||||
jwtgo.ValidationErrorUnverifiable)
|
||||
}
|
||||
80
pkg/auth/jwt_test.go
Normal file
@@ -0,0 +1,80 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 auth
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/minio/minio-go/v6/pkg/credentials"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var audience = ""
|
||||
var creds = &credentials.Value{
|
||||
AccessKeyID: "fakeAccessKeyID",
|
||||
SecretAccessKey: "fakeSecretAccessKey",
|
||||
SessionToken: "fakeSessionToken",
|
||||
SignerType: 0,
|
||||
}
|
||||
var goodToken = ""
|
||||
var badToken = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjoiRDMwYWE0ekQ1bWtFaFRyWm5yOWM3NWh0Yko0MkROOWNDZVQ5RHVHUkg1U25SR3RyTXZNOXBMdnlFSVJAAAE5eWxxekhYMXllck8xUXpzMlZzRVFKeUF2ZmpOaDkrTVdoUURWZ2FhK2R5emxzSjNpK0k1dUdoeW5DNWswUW83WEY0UWszY0RtUTdUQUVROVFEbWRKdjBkdVB5L25hQk5vM3dIdlRDZHFNRDJZN3kycktJbmVUbUlFNmVveW9EWmprcW5tckVoYmMrTlhTRU81WjZqa1kwZ1E2eXZLaWhUZGxBRS9zS1lBNlc4Q1R1cm1MU0E0b0dIcGtldFZWU0VXMHEzNU9TU1VaczRXNkxHdGMxSTFWVFZLWUo3ZTlHR2REQ3hMWGtiZHQwcjl0RDNMWUhWRndra0dSZit5ZHBzS1Y3L1Jtbkp3SHNqNVVGV0w5WGVHUkZVUjJQclJTN2plVzFXeGZuYitVeXoxNVpOMzZsZ01GNnBlWFd1LzJGcEtrb2Z2QzNpY2x5Rmp0SE45ZkxYTVpVSFhnV2lsQWVSa3oiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjkwMDAiLCJleHAiOjE1ODc1MTY1NzEsInN1YiI6ImZmYmY4YzljLTJlMjYtNGMwYS1iMmI0LTYyMmVhM2I1YjZhYiJ9.P392RUwzsrBeJOO3fS1xMZcF-lWiDvWZ5hM7LZOyFMmoG5QLccDU5eAPSm8obzPoznX1b7eCFLeEmKK-vKgjiQ"
|
||||
|
||||
func TestNewJWTWithClaimsForClient(t *testing.T) {
|
||||
funcAssert := assert.New(t)
|
||||
// Test-1 : NewJWTWithClaimsForClient() is generated correctly without errors
|
||||
function := "NewJWTWithClaimsForClient()"
|
||||
jwt, err := NewJWTWithClaimsForClient(creds, []string{""}, audience)
|
||||
if err != nil || jwt == "" {
|
||||
t.Errorf("Failed on %s:, error occurred: %s", function, err)
|
||||
}
|
||||
// saving jwt for future tests
|
||||
goodToken = jwt
|
||||
// Test-2 : NewJWTWithClaimsForClient() throws error because of empty credentials
|
||||
if _, err = NewJWTWithClaimsForClient(nil, []string{""}, audience); err != nil {
|
||||
funcAssert.Equal("provided credentials are empty", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestJWTAuthenticate(t *testing.T) {
|
||||
funcAssert := assert.New(t)
|
||||
// Test-1 : JWTAuthenticate() should correctly return the claims
|
||||
function := "JWTAuthenticate()"
|
||||
claims, err := JWTAuthenticate(goodToken)
|
||||
if err != nil || claims == nil {
|
||||
t.Errorf("Failed on %s:, error occurred: %s", function, err)
|
||||
} else {
|
||||
funcAssert.Equal(claims.AccessKeyID, creds.AccessKeyID)
|
||||
funcAssert.Equal(claims.SecretAccessKey, creds.SecretAccessKey)
|
||||
funcAssert.Equal(claims.SessionToken, creds.SessionToken)
|
||||
}
|
||||
// Test-2 : JWTAuthenticate() return an error because of a tampered jwt
|
||||
if _, err := JWTAuthenticate(badToken); err != nil {
|
||||
funcAssert.Equal("authentication failed, check your access credentials", err.Error())
|
||||
}
|
||||
// Test-3 : JWTAuthenticate() return an error because of an empty jwt
|
||||
if _, err := JWTAuthenticate(""); err != nil {
|
||||
funcAssert.Equal("JWT token missing", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsJWTValid(t *testing.T) {
|
||||
funcAssert := assert.New(t)
|
||||
// Test-1 : JWTAuthenticate() provided token is valid
|
||||
funcAssert.Equal(true, IsJWTValid(goodToken))
|
||||
// Test-2 : JWTAuthenticate() provided token is invalid
|
||||
funcAssert.Equal(false, IsJWTValid(badToken))
|
||||
}
|
||||
39
pkg/auth/ldap.go
Normal file
@@ -0,0 +1,39 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 auth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
|
||||
"github.com/minio/minio-go/v6/pkg/credentials"
|
||||
)
|
||||
|
||||
var (
|
||||
errInvalidCredentials = errors.New("invalid Credentials")
|
||||
)
|
||||
|
||||
// GetMcsCredentialsFromLDAP authenticates the user against MinIO when the LDAP integration is enabled
|
||||
// if the authentication succeed *credentials.Credentials object is returned and we continue with the normal STSAssumeRole flow
|
||||
func GetMcsCredentialsFromLDAP(endpoint, ldapUser, ldapPassword string) (*credentials.Credentials, error) {
|
||||
creds, err := credentials.NewLDAPIdentity(endpoint, ldapUser, ldapPassword)
|
||||
if err != nil {
|
||||
log.Println("LDAP authentication error: ", err)
|
||||
return nil, errInvalidCredentials
|
||||
}
|
||||
return creds, nil
|
||||
}
|
||||
27
pkg/auth/ldap/config.go
Normal file
@@ -0,0 +1,27 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 ldap
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/minio/minio/pkg/env"
|
||||
)
|
||||
|
||||
func GetLDAPEnabled() bool {
|
||||
return strings.ToLower(env.Get(MCSLDAPEnabled, "off")) == "on"
|
||||
}
|
||||
22
pkg/auth/ldap/const.go
Normal file
@@ -0,0 +1,22 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 ldap
|
||||
|
||||
const (
|
||||
// const for ldap configuration
|
||||
MCSLDAPEnabled = "MCS_LDAP_ENABLED"
|
||||
)
|
||||
@@ -14,52 +14,17 @@
|
||||
// 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 sessions
|
||||
package utils
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"io"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
mcCmd "github.com/minio/mc/cmd"
|
||||
)
|
||||
|
||||
type Singleton struct {
|
||||
sessions map[string]*mcCmd.Config
|
||||
}
|
||||
|
||||
var instance *Singleton
|
||||
var once sync.Once
|
||||
|
||||
// Returns a Singleton instance that keeps the sessions
|
||||
func GetInstance() *Singleton {
|
||||
once.Do(func() {
|
||||
//build sessions hash
|
||||
sessions := make(map[string]*mcCmd.Config)
|
||||
|
||||
instance = &Singleton{
|
||||
sessions: sessions,
|
||||
}
|
||||
})
|
||||
return instance
|
||||
}
|
||||
|
||||
func (s *Singleton) NewSession(cfg *mcCmd.Config) string {
|
||||
// genereate random session id
|
||||
sessionID := RandomCharString(64)
|
||||
// store the cfg under that session id
|
||||
s.sessions[sessionID] = cfg
|
||||
return sessionID
|
||||
}
|
||||
|
||||
func (s *Singleton) ValidSession(sessionID string) bool {
|
||||
if _, ok := s.sessions[sessionID]; ok {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Do not use:
|
||||
// https://stackoverflow.com/questions/22892120/how-to-generate-a-random-string-of-a-fixed-length-in-go
|
||||
// It relies on math/rand and therefore not on a cryptographically secure RNG => It must not be used
|
||||
@@ -87,3 +52,9 @@ func RandomCharString(n int) string {
|
||||
}
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func ComputeHmac256(message string, key []byte) string {
|
||||
h := hmac.New(sha256.New, key)
|
||||
h.Write([]byte(message))
|
||||
return base64.StdEncoding.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
46
pkg/auth/utils/utils_test.go
Normal file
@@ -0,0 +1,46 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 utils
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
)
|
||||
|
||||
func TestRandomCharString(t *testing.T) {
|
||||
funcAssert := assert.New(t)
|
||||
// Test-1 : RandomCharString() should return string with expected length
|
||||
length := 32
|
||||
token := RandomCharString(length)
|
||||
funcAssert.Equal(length, len(token))
|
||||
// Test-2 : RandomCharString() should output random string, new generated string should not be equal to the previous one
|
||||
newToken := RandomCharString(length)
|
||||
funcAssert.NotEqual(token, newToken)
|
||||
}
|
||||
|
||||
func TestComputeHmac256(t *testing.T) {
|
||||
funcAssert := assert.New(t)
|
||||
// Test-1 : ComputeHmac256() should return the right Hmac256 string based on a derived key
|
||||
var derivedKey = pbkdf2.Key([]byte("secret"), []byte("salt"), 4096, 32, sha1.New)
|
||||
var message = "hello world"
|
||||
var expectedHmac = "5r32q7W+0hcBnqzQwJJUDzVGoVivXGSodTcHSqG/9Q8="
|
||||
hmac := ComputeHmac256(message, derivedKey)
|
||||
funcAssert.Equal(hmac, expectedHmac)
|
||||
}
|
||||
51
pkg/ws/websocket.go
Normal file
@@ -0,0 +1,51 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 ws contains websocket utils for mcs project
|
||||
package ws
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// GetTokenFromRequest returns a token from a http Request
|
||||
// either defined on a cookie `token` or on Authorization header.
|
||||
//
|
||||
// Authorization Header needs to be like "Authorization Bearer <jwt_token>"
|
||||
func GetTokenFromRequest(r *http.Request) (*string, error) {
|
||||
// Get Auth token
|
||||
var reqToken string
|
||||
|
||||
// Token might come either as a Cookie or as a Header
|
||||
// if not set in cookie, check if it is set on Header.
|
||||
tokenCookie, err := r.Cookie("token")
|
||||
if err != nil {
|
||||
headerToken := r.Header.Get("Authorization")
|
||||
// reqToken should come as "Bearer <token>"
|
||||
splitHeaderToken := strings.Split(headerToken, "Bearer")
|
||||
if len(splitHeaderToken) <= 1 {
|
||||
return nil, errors.New(http.StatusBadRequest, "Authentication not valid")
|
||||
}
|
||||
reqToken = strings.TrimSpace(splitHeaderToken[1])
|
||||
} else {
|
||||
reqToken = strings.TrimSpace(tokenCookie.Value)
|
||||
}
|
||||
return swag.String(reqToken), nil
|
||||
}
|
||||
5976
portal-ui/package-lock.json
generated
@@ -5,7 +5,7 @@
|
||||
"dependencies": {
|
||||
"@babel/helper-create-regexp-features-plugin": "^7.7.4",
|
||||
"@babel/plugin-transform-react-jsx-development": "^7.9.0",
|
||||
"@material-ui/core": "^4.9.8",
|
||||
"@material-ui/core": "^4.9.12",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@types/history": "^4.7.3",
|
||||
"@types/jest": "24.0.23",
|
||||
@@ -19,6 +19,9 @@
|
||||
"@types/recharts": "^1.8.9",
|
||||
"@types/superagent": "^4.1.4",
|
||||
"@types/webpack-env": "^1.14.1",
|
||||
"@types/websocket": "^1.0.0",
|
||||
"ansi-to-react": "^6.0.5",
|
||||
"chart.js": "^2.9.3",
|
||||
"codemirror": "^5.52.2",
|
||||
"history": "^4.10.1",
|
||||
"local-storage-fallback": "^4.1.1",
|
||||
@@ -26,6 +29,7 @@
|
||||
"moment": "^2.24.0",
|
||||
"npm": "^6.14.4",
|
||||
"react": "^16.13.1",
|
||||
"react-chartjs-2": "^2.9.0",
|
||||
"react-codemirror2": "^7.1.0",
|
||||
"react-dom": "^16.12.0",
|
||||
"react-moment": "^0.9.7",
|
||||
@@ -37,7 +41,8 @@
|
||||
"redux-thunk": "^2.3.0",
|
||||
"superagent": "^5.1.0",
|
||||
"typeface-roboto": "^0.0.75",
|
||||
"typescript": "3.6.4"
|
||||
"typescript": "3.6.4",
|
||||
"websocket": "^1.0.31"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "PORT=5000 react-scripts start",
|
||||
@@ -60,7 +65,7 @@
|
||||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"proxy": "http://localhost:9090",
|
||||
"proxy": "http://localhost:9090/",
|
||||
"devDependencies": {
|
||||
"prettier": "^1.19.1"
|
||||
}
|
||||
|
||||
BIN
portal-ui/public/amqp.png
Normal file
|
After Width: | Height: | Size: 107 KiB |
BIN
portal-ui/public/elasticsearch.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
@@ -6,13 +6,13 @@
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Acme cloud storage"
|
||||
content="MinIO Console"
|
||||
/>
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link href="https://fonts.googleapis.com/css?family=Questrial&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Lato:wght@400;500;700;900&display=swap" rel="stylesheet">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="%PUBLIC_URL%/apple-icon-180x180.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="%PUBLIC_URL%/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="96x96" href="%PUBLIC_URL%/favicon-96x96.png">
|
||||
|
||||
BIN
portal-ui/public/kafka.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
portal-ui/public/mqtt.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
portal-ui/public/mysql.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
BIN
portal-ui/public/nats.png
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
portal-ui/public/postgres.png
Normal file
|
After Width: | Height: | Size: 301 KiB |
BIN
portal-ui/public/redis.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
@@ -15,15 +15,16 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
import { Route, Router, Switch } from "react-router-dom";
|
||||
import { Redirect, Route, Router, Switch } from "react-router-dom";
|
||||
import history from "./history";
|
||||
import Login from "./screens/LoginPage";
|
||||
import Login from "./screens/LoginPage/LoginPage";
|
||||
import Console from "./screens/Console/Console";
|
||||
import NotFoundPage from "./screens/NotFoundPage";
|
||||
import storage from "local-storage-fallback";
|
||||
import { connect } from "react-redux";
|
||||
import { AppState } from "./store";
|
||||
import { userLoggedIn } from "./actions";
|
||||
import LoginCallback from "./screens/LoginPage/LoginCallback";
|
||||
|
||||
const isLoggedIn = () => {
|
||||
return (
|
||||
@@ -34,7 +35,7 @@ const isLoggedIn = () => {
|
||||
};
|
||||
|
||||
const mapState = (state: AppState) => ({
|
||||
loggedIn: state.system.loggedIn
|
||||
loggedIn: state.system.loggedIn,
|
||||
});
|
||||
|
||||
const connector = connect(mapState, { userLoggedIn });
|
||||
@@ -55,6 +56,7 @@ class Routes extends React.Component<RoutesProps> {
|
||||
return (
|
||||
<Router history={history}>
|
||||
<Switch>
|
||||
<Route exact path="/oauth_callback" component={LoginCallback} />
|
||||
<Route exact path="/login" component={Login} />
|
||||
{this.props.loggedIn ? (
|
||||
<Switch>
|
||||
@@ -64,7 +66,7 @@ class Routes extends React.Component<RoutesProps> {
|
||||
) : (
|
||||
<Switch>
|
||||
<Route exact path="/" component={Login} />
|
||||
<Route component={NotFoundPage} />
|
||||
<Redirect to="/" />
|
||||
</Switch>
|
||||
)}
|
||||
</Switch>
|
||||
|
||||
@@ -14,7 +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/>.
|
||||
|
||||
import { MENU_OPEN, USER_LOGGED } from "./types";
|
||||
import {
|
||||
MENU_OPEN,
|
||||
SERVER_IS_LOADING,
|
||||
SERVER_NEEDS_RESTART,
|
||||
USER_LOGGED
|
||||
} from "./types";
|
||||
|
||||
export function userLoggedIn(loggedIn: boolean) {
|
||||
return {
|
||||
@@ -29,3 +34,17 @@ export function setMenuOpen(open: boolean) {
|
||||
open: open
|
||||
};
|
||||
}
|
||||
|
||||
export function serverNeedsRestart(needsRestart: boolean) {
|
||||
return {
|
||||
type: SERVER_NEEDS_RESTART,
|
||||
needsRestart: needsRestart
|
||||
};
|
||||
}
|
||||
|
||||
export function serverIsLoading(isLoading: boolean) {
|
||||
return {
|
||||
type: SERVER_IS_LOADING,
|
||||
isLoading: isLoading
|
||||
};
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
import storage from "local-storage-fallback";
|
||||
import request from "superagent";
|
||||
import get from "lodash/get";
|
||||
|
||||
export class API {
|
||||
invoke(method: string, url: string, data?: object) {
|
||||
@@ -23,20 +24,34 @@ export class API {
|
||||
return request(method, url)
|
||||
.set("Authorization", `Bearer ${token}`)
|
||||
.send(data)
|
||||
.then(res => res.body)
|
||||
.catch(err => this.onError(err));
|
||||
.then((res) => res.body)
|
||||
.catch((err) => {
|
||||
// if we get unauthorized, kick out the user
|
||||
if (err.status === 401) {
|
||||
storage.removeItem("token");
|
||||
window.location.href = "/";
|
||||
}
|
||||
return this.onError(err);
|
||||
});
|
||||
}
|
||||
|
||||
onError(err: any) {
|
||||
if (err.status) {
|
||||
const errMessage: string =
|
||||
(err.response.body && err.response.body.error) ||
|
||||
err.status.toString(10);
|
||||
return Promise.reject(errMessage);
|
||||
const errMessage = get(
|
||||
err.response,
|
||||
"body.message",
|
||||
err.status.toString()
|
||||
);
|
||||
|
||||
const throwMessage =
|
||||
errMessage.charAt(0).toUpperCase() + errMessage.slice(1);
|
||||
|
||||
return Promise.reject(throwMessage);
|
||||
} else {
|
||||
return Promise.reject("Unknown error");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const api = new API();
|
||||
export default api;
|
||||
|
||||
94
portal-ui/src/common/utils.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
export const units = [
|
||||
"B",
|
||||
"KiB",
|
||||
"MiB",
|
||||
"GiB",
|
||||
"TiB",
|
||||
"PiB",
|
||||
"EiB",
|
||||
"ZiB",
|
||||
"YiB",
|
||||
];
|
||||
export const k8sUnits = ["Ki", "Mi", "Gi", "Ti", "Pi", "Ei"];
|
||||
export const niceBytes = (x: string) => {
|
||||
let l = 0,
|
||||
n = parseInt(x, 10) || 0;
|
||||
|
||||
while (n >= 1024 && ++l) {
|
||||
n = n / 1024;
|
||||
}
|
||||
//include a decimal point and a tenths-place digit if presenting
|
||||
//less than ten of KB or greater units
|
||||
return n.toFixed(n < 10 && l > 0 ? 1 : 0) + " " + units[l];
|
||||
};
|
||||
|
||||
export const setCookie = (name: string, val: string) => {
|
||||
const date = new Date();
|
||||
const value = val;
|
||||
|
||||
// Set it expire in 45 minutes
|
||||
date.setTime(date.getTime() + 45 * 60 * 1000);
|
||||
|
||||
// Set it
|
||||
document.cookie =
|
||||
name + "=" + value + "; expires=" + date.toUTCString() + "; path=/";
|
||||
};
|
||||
|
||||
// timeFromdate gets time string from date input
|
||||
export const timeFromDate = (d: Date) => {
|
||||
let h = d.getHours() < 10 ? `0${d.getHours()}` : `${d.getHours()}`;
|
||||
let m = d.getMinutes() < 10 ? `0${d.getMinutes()}` : `${d.getMinutes()}`;
|
||||
let s = d.getSeconds() < 10 ? `0${d.getSeconds()}` : `${d.getSeconds()}`;
|
||||
|
||||
return `${h}:${m}:${s}:${d.getMilliseconds()}`;
|
||||
};
|
||||
|
||||
// units to be used in a dropdown
|
||||
export const factorForDropdown = () => {
|
||||
return units.map((unit) => {
|
||||
return { label: unit, value: unit };
|
||||
});
|
||||
};
|
||||
|
||||
// units to be used in a dropdown
|
||||
export const k8sfactorForDropdown = () => {
|
||||
return k8sUnits.map((unit) => {
|
||||
return { label: unit, value: unit };
|
||||
});
|
||||
};
|
||||
|
||||
//getBytes, converts from a value and a unit from units array to bytes
|
||||
export const getBytes = (value: string, unit: string) => {
|
||||
const vl: number = parseFloat(value);
|
||||
const powFactor = units.findIndex((element) => element === unit);
|
||||
|
||||
if (powFactor == -1) {
|
||||
return 0;
|
||||
}
|
||||
const factor = Math.pow(1024, powFactor);
|
||||
const total = vl * factor;
|
||||
|
||||
return total.toString(10);
|
||||
};
|
||||
|
||||
//getTotalSize gets the total size of a value & unit
|
||||
export const getTotalSize = (value: string, unit: string) => {
|
||||
const bytes = getBytes(value, unit).toString(10);
|
||||
return niceBytes(bytes);
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2019 MinIO, Inc.
|
||||
// Copyright (c) 2020 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,22 +14,18 @@
|
||||
// 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/>.
|
||||
|
||||
|
||||
import React from "react";
|
||||
import {SvgIcon} from "@material-ui/core";
|
||||
import { SvgIcon } from "@material-ui/core";
|
||||
class BucketsIcon extends React.Component {
|
||||
render() {
|
||||
return (<SvgIcon>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||
<title>ic_h_buckets</title>
|
||||
<g id="Layer_2" data-name="Layer 2">
|
||||
<g id="Layer_1-2" data-name="Layer 1">
|
||||
<polygon className="cls-1" points="13.428 16 2.572 16 0 0 16 0 13.428 16"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</SvgIcon>)
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<SvgIcon>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10">
|
||||
<path d="M8.392,10H1.608L0,0H10Z" />
|
||||
</svg>
|
||||
</SvgIcon>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default BucketsIcon;
|
||||
|
||||
123
portal-ui/src/icons/ClustersIcon.tsx
Normal file
@@ -0,0 +1,123 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
import React from "react";
|
||||
import { SvgIcon } from "@material-ui/core";
|
||||
class ClustersIcon extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<SvgIcon>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 9">
|
||||
<g transform="translate(79 438.479)">
|
||||
<g>
|
||||
<g>
|
||||
<rect x="-77.9" y="-434.5" width="7.8" height="1" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<rect
|
||||
x="-77.9"
|
||||
y="-434.5"
|
||||
transform="matrix(0.4999 -0.8661 0.8661 0.4999 338.8698 -281.1237)"
|
||||
width="7.8"
|
||||
height="1"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<rect
|
||||
x="-74.5"
|
||||
y="-437.9"
|
||||
transform="matrix(0.866 -0.5001 0.5001 0.866 207.1129 -95.1668)"
|
||||
width="1"
|
||||
height="7.8"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path
|
||||
d="M-71.8-430.1h-4.5l-2.2-3.9l2.2-3.9h4.5l2.2,3.9L-71.8-430.1z M-75.7-431.1h3.3l1.7-2.9l-1.7-2.9h-3.3
|
||||
l-1.7,2.9L-75.7-431.1z"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path
|
||||
d="M-72.3-434c0,0.9-0.7,1.7-1.7,1.7c-0.9,0-1.7-0.7-1.7-1.7c0-0.9,0.7-1.7,1.7-1.7
|
||||
C-73.1-435.7-72.3-434.9-72.3-434z"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path
|
||||
d="M-76.8-434c0,0.6-0.5,1.1-1.1,1.1c0,0,0,0,0,0c-0.6,0-1.1-0.5-1.1-1.1c0,0,0,0,0,0c0-0.6,0.5-1.1,1.1-1.1
|
||||
c0,0,0,0,0,0C-77.3-435.1-76.8-434.6-76.8-434C-76.8-434-76.8-434-76.8-434z"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path
|
||||
d="M-69-434c0,0.6-0.5,1.1-1.1,1.1c0,0,0,0,0,0c-0.6,0-1.1-0.5-1.1-1.1c0,0,0,0,0,0c0-0.6,0.5-1.1,1.1-1.1
|
||||
c0,0,0,0,0,0C-69.5-435.1-69-434.6-69-434C-69-434-69-434-69-434z"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path
|
||||
d="M-75.4-431.6c0.5,0.3,0.7,1,0.4,1.5c-0.3,0.5-1,0.7-1.5,0.4c0,0,0,0,0,0c-0.5-0.3-0.7-1-0.4-1.5
|
||||
C-76.6-431.7-75.9-431.9-75.4-431.6C-75.4-431.6-75.4-431.6-75.4-431.6z"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path
|
||||
d="M-71.5-438.3c0.5,0.3,0.7,1,0.4,1.5c-0.3,0.5-1,0.7-1.5,0.4c0,0,0,0,0,0c-0.5-0.3-0.7-1-0.4-1.5
|
||||
C-72.7-438.5-72-438.6-71.5-438.3C-71.5-438.3-71.5-438.3-71.5-438.3z"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path
|
||||
d="M-72.6-431.6c0.5-0.3,1.2-0.1,1.5,0.4c0,0,0,0,0,0c0.3,0.5,0.1,1.2-0.4,1.5c-0.5,0.3-1.2,0.1-1.5-0.4
|
||||
c0,0,0,0,0,0C-73.3-430.6-73.1-431.3-72.6-431.6z"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path
|
||||
d="M-76.5-438.3c0.5-0.3,1.2-0.1,1.5,0.4c0,0,0,0,0,0c0.3,0.5,0.1,1.2-0.4,1.5c-0.5,0.3-1.2,0.1-1.5-0.4
|
||||
c0,0,0,0,0,0C-77.2-437.3-77-438-76.5-438.3z"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</SvgIcon>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ClustersIcon;
|
||||
42
portal-ui/src/icons/ConfigurationsListIcon.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
import React from "react";
|
||||
import { SvgIcon } from "@material-ui/core";
|
||||
class ConfigurationsListIcon extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<SvgIcon>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10">
|
||||
<rect width="1.433" height="1" />
|
||||
<rect width="7.828" height="1" transform="translate(2.172)" />
|
||||
<rect width="1.433" height="1" transform="translate(0 6)" />
|
||||
<rect width="1.433" height="1" transform="translate(0 3)" />
|
||||
<rect width="1.433" height="1" transform="translate(0 9)" />
|
||||
<rect width="1.368" height="0.569" transform="translate(6.316 9)" />
|
||||
<path d="M5.566,9.569v-.31l-.238-.138-.269.155-.65.375L4.034,9V9H2.172v1H5.566Z" />
|
||||
<path d="M9.966,9l-.375.65-.65-.375-.269-.155-.238.138V10H10V9H9.967Z" />
|
||||
<path d="M3.625,6.793l.269-.155V6.362l-.269-.155L3.266,6H2.172V7H3.266Z" />
|
||||
<path d="M8.434,3.431v.31l.238.138.269-.155.649-.375L9.966,4V4H10V3H8.434Z" />
|
||||
<path d="M4.034,4l.375-.65.65.375.269.155.238-.138V3H2.172V4H4.033Z" />
|
||||
<path d="M9.356,5.929,10,5.558,9.316,4.373l-.644.372-.988-.571V3.431H6.316v.743l-.988.571-.644-.372L4,5.558l.644.371V7.071L4,7.442l.684,1.185.644-.372.988.571v.743H7.684V8.826l.988-.571.644.372L10,7.442l-.644-.371ZM7,7.278A.778.778,0,1,1,7.778,6.5.779.779,0,0,1,7,7.278Z" />
|
||||
</svg>
|
||||
</SvgIcon>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ConfigurationsListIcon;
|
||||
@@ -1,5 +1,5 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2019 MinIO, Inc.
|
||||
// Copyright (c) 2020 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
|
||||
@@ -20,15 +20,24 @@ class DashboardIcon extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<SvgIcon>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||
<title>ic_h_dashboard</title>
|
||||
<g id="Layer_2" data-name="Layer 2">
|
||||
<g id="Layer_1-2" data-name="Layer 1">
|
||||
<rect className="cls-1" x="9" width="7" height="7" />
|
||||
<rect className="cls-1" width="7" height="7" />
|
||||
<rect className="cls-1" x="9" y="9" width="7" height="7" />
|
||||
<rect className="cls-1" y="9" width="7" height="7" />
|
||||
</g>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10">
|
||||
<g transform="translate(249 720)">
|
||||
<rect
|
||||
width="6"
|
||||
height="5"
|
||||
transform="translate(-244 -720) rotate(90)"
|
||||
/>
|
||||
<rect width="4" height="4" transform="translate(-243 -720)" />
|
||||
<rect
|
||||
width="5"
|
||||
height="4"
|
||||
transform="translate(-239 -715) rotate(90)"
|
||||
/>
|
||||
<rect
|
||||
width="5"
|
||||
height="3"
|
||||
transform="translate(-244 -710) rotate(180)"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</SvgIcon>
|
||||
|
||||
41
portal-ui/src/icons/GroupsIcon.tsx
Normal file
@@ -0,0 +1,41 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
import React from "react";
|
||||
import { SvgIcon } from "@material-ui/core";
|
||||
class GroupsIcon extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<SvgIcon>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 9.787">
|
||||
<g transform="translate(177 719.787)">
|
||||
<g transform="translate(-105 -720)">
|
||||
<path d="M-65,5a3,3,0,0,0-1.131.224A3.981,3.981,0,0,1-65,8v2h3V8A3,3,0,0,0-65,5Z" />
|
||||
<path d="M-72,10h6V8a3,3,0,0,0-3-3,3,3,0,0,0-3,3Z" />
|
||||
<path
|
||||
className="a"
|
||||
d="M-65,.213a1.993,1.993,0,0,0-1.384.561A2.967,2.967,0,0,1-66,2.213a2.964,2.964,0,0,1-.384,1.439A1.989,1.989,0,0,0-65,4.213a2,2,0,0,0,2-2A2,2,0,0,0-65,.213Z"
|
||||
/>
|
||||
<circle cx="2" cy="2" r="2" transform="translate(-71 0.213)" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</SvgIcon>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default GroupsIcon;
|
||||
34
portal-ui/src/icons/IAMPoliciesIcon.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
import React from "react";
|
||||
import { SvgIcon } from "@material-ui/core";
|
||||
class BucketsIcon extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<SvgIcon>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 8.75 10">
|
||||
<path
|
||||
d="M-44.625,10l-4.353-2.419L-53.375,10V0h8.75Z"
|
||||
transform="translate(53.375)"
|
||||
/>
|
||||
</svg>
|
||||
</SvgIcon>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default BucketsIcon;
|
||||
34
portal-ui/src/icons/LambdaNotificationsIcon.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
import React from "react";
|
||||
import { SvgIcon } from "@material-ui/core";
|
||||
class LambdaNotificationsIcon extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<SvgIcon>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10">
|
||||
<path
|
||||
d="M0,0v10l2.8-2.2H10V0H0z M6.6,6L5.6,6.4l-0.8-2l-1.5,2L2.5,5.9l1.9-2.6L4.1,2.4H3.2v-1h1.5l1.4,3.7l0.9-0.4
|
||||
l0.4,0.9L6.6,6z"
|
||||
/>
|
||||
</svg>
|
||||
</SvgIcon>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default LambdaNotificationsIcon;
|
||||
35
portal-ui/src/icons/MirroringIcon.tsx
Normal file
@@ -0,0 +1,35 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
import React from "react";
|
||||
import { SvgIcon } from "@material-ui/core";
|
||||
class MirroringIcon extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<SvgIcon>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10">
|
||||
<g transform="translate(61 439)">
|
||||
<rect width="1.5" height="10" transform="translate(-56.75 -439)" />
|
||||
<path d="M6.5,10V0h.572L10,10Z" transform="translate(-61 -439)" />
|
||||
<path d="M3.5,10V0H2.928L0,10Z" transform="translate(-61 -439)" />
|
||||
</g>
|
||||
</svg>
|
||||
</SvgIcon>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default MirroringIcon;
|
||||
41
portal-ui/src/icons/ServiceAccountsIcon.tsx
Normal file
@@ -0,0 +1,41 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
import React from "react";
|
||||
import { SvgIcon } from "@material-ui/core";
|
||||
class ServiceAccountsIcon extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<SvgIcon>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 9.5">
|
||||
<g transform="translate(231 719.516)">
|
||||
<path
|
||||
d="M-125.5,7.984a4.5,4.5,0,0,1,4.5-4.5,4.5,4.5,0,0,1,4.5,4.5Z"
|
||||
transform="translate(-105 -720)"
|
||||
/>
|
||||
<rect width="10" height="1" transform="translate(-231 -711.016)" />
|
||||
<path
|
||||
d="M-119.5.484h-3v1h1v1h1v-1h1Z"
|
||||
transform="translate(-105 -720)"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</SvgIcon>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ServiceAccountsIcon;
|
||||
62
portal-ui/src/icons/TraceIcon.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
import React from "react";
|
||||
import { SvgIcon } from "@material-ui/core";
|
||||
class TraceIcon extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<SvgIcon>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 9.998 10">
|
||||
<g transform="translate(140.999 720)">
|
||||
<g transform="translate(-105 -720)">
|
||||
<rect
|
||||
width="1.114"
|
||||
height="1.667"
|
||||
transform="translate(-27.116 8.333)"
|
||||
/>
|
||||
<path d="M-28.184,10H-29.3V8.154l2.182-3.037V3.147H-26V5.476l-2.182,3.037Z" />
|
||||
<rect
|
||||
width="1.114"
|
||||
height="2.963"
|
||||
transform="translate(-31.531)"
|
||||
/>
|
||||
<rect
|
||||
width="1.114"
|
||||
height="2.132"
|
||||
transform="translate(-27.115 0)"
|
||||
/>
|
||||
<rect
|
||||
width="1.114"
|
||||
height="5.389"
|
||||
transform="translate(-29.298)"
|
||||
/>
|
||||
<path d="M-30.417,10h-1.114V5.722l-2.233-3V0h1.114V2.353l2.233,3Z" />
|
||||
<path d="M-32.65,10h-1.114V6.185l-2.234-3V0h1.114V2.815l2.234,3Z" />
|
||||
<rect
|
||||
width="1.114"
|
||||
height="4.463"
|
||||
transform="translate(-35.999 5.537)"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</SvgIcon>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default TraceIcon;
|
||||
@@ -1,5 +1,5 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2019 MinIO, Inc.
|
||||
// Copyright (c) 2020 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,27 +14,32 @@
|
||||
// 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/>.
|
||||
|
||||
|
||||
import React from "react";
|
||||
import {SvgIcon} from "@material-ui/core";
|
||||
import { SvgIcon } from "@material-ui/core";
|
||||
class UsersIcon extends React.Component {
|
||||
render() {
|
||||
return (<SvgIcon>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 14.874">
|
||||
<title>ic_users</title>
|
||||
<g id="Layer_2" data-name="Layer 2">
|
||||
<g id="Layer_1-2" data-name="Layer 1">
|
||||
<path className="cls-1"
|
||||
d="M3.5,6.875h0a3.5,3.5,0,0,1,3.5,3.5v4.5a0,0,0,0,1,0,0H0a0,0,0,0,1,0,0v-4.5A3.5,3.5,0,0,1,3.5,6.875Z"/>
|
||||
<path className="cls-1"
|
||||
d="M12.5,6.875h0a3.5,3.5,0,0,1,3.5,3.5v4.5a0,0,0,0,1,0,0H9a0,0,0,0,1,0,0v-4.5A3.5,3.5,0,0,1,12.5,6.875Z"/>
|
||||
<circle className="cls-1" cx="3.498" cy="2.859" r="2.859"/>
|
||||
<circle className="cls-1" cx="12.502" cy="2.859" r="2.859"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</SvgIcon>)
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<SvgIcon>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 6.131 10">
|
||||
<g transform="translate(193 719.787)">
|
||||
<g transform="translate(-193 -719.787)">
|
||||
<path
|
||||
d="M3,0h.131a3,3,0,0,1,3,3V5a0,0,0,0,1,0,0H0A0,0,0,0,1,0,5V3A3,3,0,0,1,3,0Z"
|
||||
transform="translate(0 5)"
|
||||
/>
|
||||
<ellipse
|
||||
cx="2.065"
|
||||
cy="2"
|
||||
rx="2.065"
|
||||
ry="2"
|
||||
transform="translate(1 0)"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</SvgIcon>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default UsersIcon;
|
||||
|
||||
39
portal-ui/src/icons/WarpIcon.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
import React from "react";
|
||||
import { SvgIcon } from "@material-ui/core";
|
||||
class WarpIcon extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<SvgIcon>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10">
|
||||
<g transform="translate(43 439)">
|
||||
<path d="M27.5,10" transform="translate(-61 -439)" />
|
||||
<rect width="1.5" height="2" transform="translate(-43 -431)" />
|
||||
<rect width="1.5" height="6" transform="translate(-38.75 -435)" />
|
||||
<rect width="1.5" height="8" transform="translate(-36.625 -437)" />
|
||||
<rect width="1.5" height="4" transform="translate(-40.875 -433)" />
|
||||
<rect width="1.5" height="10" transform="translate(-34.5 -439)" />
|
||||
<path d="M18.5,10" transform="translate(-61 -439)" />
|
||||
</g>
|
||||
</svg>
|
||||
</SvgIcon>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default WarpIcon;
|
||||
59
portal-ui/src/icons/WatchIcon.tsx
Normal file
@@ -0,0 +1,59 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
import React from "react";
|
||||
import { SvgIcon } from "@material-ui/core";
|
||||
class WatchIcon extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<SvgIcon>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10">
|
||||
<g transform="translate(213 720)">
|
||||
<g transform="translate(-105 -720)">
|
||||
<rect width="1.5" height="4" transform="translate(-108)" />
|
||||
<rect width="1.5" height="4" transform="translate(-108 6)" />
|
||||
<rect width="1.5" height="4" transform="translate(-99.5 6)" />
|
||||
<rect width="1.5" height="4" transform="translate(-99.5)" />
|
||||
<rect
|
||||
width="1.5"
|
||||
height="4"
|
||||
transform="translate(-98) rotate(90)"
|
||||
/>
|
||||
<rect
|
||||
width="1.5"
|
||||
height="4"
|
||||
transform="translate(-104) rotate(90)"
|
||||
/>
|
||||
<rect
|
||||
width="1.5"
|
||||
height="4"
|
||||
transform="translate(-104 8.5) rotate(90)"
|
||||
/>
|
||||
<rect
|
||||
width="1.5"
|
||||
height="4"
|
||||
transform="translate(-98 8.5) rotate(90)"
|
||||
/>
|
||||
<circle cx="2" cy="2" r="2" transform="translate(-105 3)" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</SvgIcon>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default WatchIcon;
|
||||
@@ -1,5 +1,5 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2019 MinIO, Inc.
|
||||
// Copyright (c) 2020 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,10 +14,20 @@
|
||||
// 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 { default as PermissionIcon } from './PermissionIcon';
|
||||
export { default as CreateIcon } from './CreateIcon';
|
||||
export { default as DeleteIcon } from './DeleteIcon';
|
||||
export { default as ServiceAccountIcon } from './ServiceAccountIcon';
|
||||
export { default as DashboardIcon } from './DashboardIcon';
|
||||
export { default as BucketsIcon } from './BucketsIcon';
|
||||
export { default as UsersIcon } from './UsersIcon';
|
||||
export { default as PermissionIcon } from "./PermissionIcon";
|
||||
export { default as CreateIcon } from "./CreateIcon";
|
||||
export { default as DeleteIcon } from "./DeleteIcon";
|
||||
export { default as ServiceAccountIcon } from "./ServiceAccountIcon";
|
||||
export { default as DashboardIcon } from "./DashboardIcon";
|
||||
export { default as BucketsIcon } from "./BucketsIcon";
|
||||
export { default as UsersIcon } from "./UsersIcon";
|
||||
export { default as ServiceAccountsIcon } from "./ServiceAccountsIcon";
|
||||
export { default as GroupsIcon } from "./GroupsIcon";
|
||||
export { default as IAMPoliciesIcon } from "./IAMPoliciesIcon";
|
||||
export { default as TraceIcon } from "./TraceIcon";
|
||||
export { default as LambdaNotificationsIcon } from "./LambdaNotificationsIcon";
|
||||
export { default as ConfigurationsListIcon } from "./ConfigurationsListIcon";
|
||||
export { default as ClustersIcon } from "./ClustersIcon";
|
||||
export { default as MirroringIcon } from "./MirroringIcon";
|
||||
export { default as WarpIcon } from "./WarpIcon";
|
||||
export { default as WatchIcon } from "./WatchIcon";
|
||||
|
||||
1
portal-ui/src/icons/minio_console_logo.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 81.879 23.119"><defs><style>.cls-1{fill:#1b1556;}</style></defs><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path class="cls-1" d="M10.086,13.4,8.969,14.573a4.2,4.2,0,0,0-3.01-1.279,3.886,3.886,0,0,0-3.884,4.093,3.888,3.888,0,0,0,3.884,4.1A4.4,4.4,0,0,0,9,20.2l1.082,1.186A5.344,5.344,0,0,1,6,23.119a5.512,5.512,0,0,1-5.7-5.732A5.509,5.509,0,0,1,6,11.667,5.328,5.328,0,0,1,10.086,13.4Z"/><path class="cls-1" d="M23.608,17.387a5.637,5.637,0,0,1-5.8,5.732,5.628,5.628,0,0,1-5.791-5.732,5.626,5.626,0,0,1,5.791-5.72A5.635,5.635,0,0,1,23.608,17.387Zm-9.825,0a4.024,4.024,0,1,0,8.046,0,4.024,4.024,0,1,0-8.046,0Z"/><path class="cls-1" d="M36.862,16.073V22.9H35.129V16.643c0-2.093-1.163-3.325-3.174-3.325a3.24,3.24,0,0,0-3.371,3.372V22.9H26.839V11.888H28.56v1.569a4.354,4.354,0,0,1,3.709-1.79A4.261,4.261,0,0,1,36.862,16.073Z"/><path class="cls-1" d="M48.2,14.225a6.872,6.872,0,0,0-3.605-1.035c-1.569,0-2.6.663-2.6,1.732,0,.919.8,1.372,2.244,1.547l1.3.163c2.338.3,3.7,1.267,3.7,3.069,0,2.093-1.884,3.407-4.849,3.407A7.725,7.725,0,0,1,39.791,21.7l.8-1.3a5.8,5.8,0,0,0,3.815,1.2c1.86,0,3.034-.616,3.034-1.778,0-.884-.744-1.419-2.3-1.605l-1.314-.151c-2.477-.3-3.639-1.408-3.639-3.046,0-2.082,1.755-3.338,4.4-3.338a8.067,8.067,0,0,1,4.372,1.2Z"/><path class="cls-1" d="M63.033,17.387a5.8,5.8,0,0,1-11.593,0,5.8,5.8,0,0,1,11.593,0Zm-9.825,0a4.023,4.023,0,1,0,8.045,0,4.023,4.023,0,1,0-8.045,0Z"/><path class="cls-1" d="M68.008,22.9H66.264V6.155h1.744Z"/><path class="cls-1" d="M81.879,17.353a5.606,5.606,0,0,1-.035.65H73.019a3.743,3.743,0,0,0,3.9,3.593A5.1,5.1,0,0,0,80.4,20.213l.931,1.186a6.179,6.179,0,0,1-4.524,1.72A5.394,5.394,0,0,1,71.24,17.4a5.406,5.406,0,0,1,5.465-5.732C79.693,11.667,81.856,14,81.879,17.353ZM73.043,16.6h7.069a3.446,3.446,0,0,0-3.442-3.384A3.59,3.59,0,0,0,73.043,16.6Z"/><rect class="cls-1" x="13.484" y="0.12" width="2.328" height="6.875"/><path class="cls-1" d="M10.662.215,5.936,3.1a.21.21,0,0,1-.219,0L.992.215A.651.651,0,0,0,.654.12H.648A.648.648,0,0,0,0,.768v6.22H2.327V4.028a.233.233,0,0,1,.354-.2l2.648,1.62a.829.829,0,0,0,.853.008l2.8-1.639a.232.232,0,0,1,.35.2V6.988h2.327V.768A.648.648,0,0,0,11.006.12H11A.651.651,0,0,0,10.662.215Z"/><path class="cls-1" d="M27.422.12H25.061V3.25a.233.233,0,0,1-.342.205L18.6.2A.662.662,0,0,0,18.3.12h0a.648.648,0,0,0-.648.648v6.22h2.342V3.863a.233.233,0,0,1,.342-.206L26.47,6.915a.646.646,0,0,0,.3.076h0a.648.648,0,0,0,.648-.648Z"/><path class="cls-1" d="M29.252,7V.12h1.072V7Z"/><path class="cls-1" d="M36.629,7.119c-2.882,0-4.927-1.368-4.927-3.56S33.759,0,36.629,0s4.938,1.367,4.938,3.559S39.547,7.119,36.629,7.119Zm0-6.208c-2.143,0-3.794.936-3.794,2.648s1.651,2.648,3.794,2.648,3.805-.923,3.805-2.648S38.772.911,36.629.911Z"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 2.7 KiB |
BIN
portal-ui/src/icons/postgres.png
Normal file
|
After Width: | Height: | Size: 301 KiB |
@@ -1,8 +1,6 @@
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||
sans-serif;
|
||||
font-family: 'Lato', sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
@@ -14,13 +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/>.
|
||||
|
||||
import {MENU_OPEN, SystemActionTypes, SystemState, USER_LOGGED} from "./types";
|
||||
import {
|
||||
MENU_OPEN,
|
||||
SERVER_IS_LOADING,
|
||||
SERVER_NEEDS_RESTART,
|
||||
SystemActionTypes,
|
||||
SystemState,
|
||||
USER_LOGGED
|
||||
} from "./types";
|
||||
|
||||
const initialState: SystemState = {
|
||||
loggedIn: false,
|
||||
session: "",
|
||||
userName: "",
|
||||
sidebarOpen:true,
|
||||
sidebarOpen: true,
|
||||
serverNeedsRestart: false,
|
||||
serverIsLoading: false
|
||||
};
|
||||
|
||||
export function systemReducer(
|
||||
@@ -38,6 +47,17 @@ export function systemReducer(
|
||||
...state,
|
||||
sidebarOpen: action.open
|
||||
};
|
||||
case SERVER_NEEDS_RESTART:
|
||||
return {
|
||||
...state,
|
||||
serverNeedsRestart: action.needsRestart
|
||||
};
|
||||
|
||||
case SERVER_IS_LOADING:
|
||||
return {
|
||||
...state,
|
||||
serverIsLoading: action.isLoading
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -35,9 +35,8 @@ import { AppState } from "../../../store";
|
||||
import { setMenuOpen } from "../../../actions";
|
||||
import { ThemedComponentProps } from "@material-ui/core/styles/withTheme";
|
||||
import NotFoundPage from "../../NotFoundPage";
|
||||
import BucketList from "./ListBuckets/ListBuckets";
|
||||
import ViewBucket from "./ViewBucket/ViewBucket";
|
||||
import ListBuckets from "./ListBuckets/ListBuckets";
|
||||
import ViewBucket from "./ViewBucket/ViewBucket";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
|
||||
@@ -16,28 +16,23 @@
|
||||
|
||||
import React from "react";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import Title from "../../../../common/Title";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
FormControl,
|
||||
InputLabel,
|
||||
LinearProgress,
|
||||
MenuItem,
|
||||
Select,
|
||||
TextField
|
||||
} from "@material-ui/core";
|
||||
import { Button, LinearProgress } from "@material-ui/core";
|
||||
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
|
||||
import { modalBasic } from "../../Common/FormComponents/common/styleLibrary";
|
||||
import api from "../../../../common/api";
|
||||
import ModalWrapper from "../../Common/ModalWrapper/ModalWrapper";
|
||||
import InputBoxWrapper from "../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
errorBlock: {
|
||||
color: "red"
|
||||
}
|
||||
color: "red",
|
||||
},
|
||||
buttonContainer: {
|
||||
textAlign: "right",
|
||||
},
|
||||
...modalBasic,
|
||||
});
|
||||
|
||||
interface IAddBucketProps {
|
||||
@@ -50,7 +45,6 @@ interface IAddBucketState {
|
||||
addLoading: boolean;
|
||||
addError: string;
|
||||
bucketName: string;
|
||||
accessPolicy: string;
|
||||
}
|
||||
|
||||
class AddBucket extends React.Component<IAddBucketProps, IAddBucketState> {
|
||||
@@ -58,12 +52,11 @@ class AddBucket extends React.Component<IAddBucketProps, IAddBucketState> {
|
||||
addLoading: false,
|
||||
addError: "",
|
||||
bucketName: "",
|
||||
accessPolicy: ""
|
||||
};
|
||||
|
||||
addRecord(event: React.FormEvent) {
|
||||
event.preventDefault();
|
||||
const { bucketName, addLoading, accessPolicy } = this.state;
|
||||
const { bucketName, addLoading } = this.state;
|
||||
if (addLoading) {
|
||||
return;
|
||||
}
|
||||
@@ -71,23 +64,22 @@ class AddBucket extends React.Component<IAddBucketProps, IAddBucketState> {
|
||||
api
|
||||
.invoke("POST", "/api/v1/buckets", {
|
||||
name: bucketName,
|
||||
access: accessPolicy
|
||||
})
|
||||
.then(res => {
|
||||
.then((res) => {
|
||||
this.setState(
|
||||
{
|
||||
addLoading: false,
|
||||
addError: ""
|
||||
addError: "",
|
||||
},
|
||||
() => {
|
||||
this.props.closeModalAndRefresh();
|
||||
}
|
||||
);
|
||||
})
|
||||
.catch(err => {
|
||||
.catch((err) => {
|
||||
this.setState({
|
||||
addLoading: false,
|
||||
addError: err
|
||||
addError: err,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -95,10 +87,11 @@ class AddBucket extends React.Component<IAddBucketProps, IAddBucketState> {
|
||||
|
||||
render() {
|
||||
const { classes, open } = this.props;
|
||||
const { addLoading, addError, accessPolicy } = this.state;
|
||||
const { addLoading, addError, bucketName } = this.state;
|
||||
return (
|
||||
<Dialog
|
||||
open={open}
|
||||
<ModalWrapper
|
||||
title="Create Bucket"
|
||||
modalOpen={open}
|
||||
onClose={() => {
|
||||
this.setState({ addError: "" }, () => {
|
||||
this.props.closeModalAndRefresh();
|
||||
@@ -107,18 +100,15 @@ class AddBucket extends React.Component<IAddBucketProps, IAddBucketState> {
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">
|
||||
<Title>Create Bucket</Title>
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<form
|
||||
noValidate
|
||||
autoComplete="off"
|
||||
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
|
||||
this.addRecord(e);
|
||||
}}
|
||||
>
|
||||
<Grid container>
|
||||
<form
|
||||
noValidate
|
||||
autoComplete="off"
|
||||
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
|
||||
this.addRecord(e);
|
||||
}}
|
||||
>
|
||||
<Grid container>
|
||||
<Grid item xs={12} className={classes.formScrollable}>
|
||||
{addError !== "" && (
|
||||
<Grid item xs={12}>
|
||||
<Typography
|
||||
@@ -131,57 +121,35 @@ class AddBucket extends React.Component<IAddBucketProps, IAddBucketState> {
|
||||
</Grid>
|
||||
)}
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
id="standard-basic"
|
||||
fullWidth
|
||||
label="Bucket Name"
|
||||
<InputBoxWrapper
|
||||
id="bucket-name"
|
||||
name="bucket-name"
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({ bucketName: e.target.value });
|
||||
}}
|
||||
label="Bucket Name"
|
||||
value={bucketName}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<FormControl className={classes.formControl} fullWidth>
|
||||
<InputLabel id="select-access-policy">
|
||||
Access Policy
|
||||
</InputLabel>
|
||||
<Select
|
||||
labelId="select-access-policy"
|
||||
id="select-access-policy"
|
||||
value={accessPolicy}
|
||||
onChange={(e: React.ChangeEvent<{ value: unknown }>) => {
|
||||
this.setState({ accessPolicy: e.target.value as string });
|
||||
}}
|
||||
>
|
||||
<MenuItem value="PRIVATE">Private</MenuItem>
|
||||
<MenuItem value="PUBLIC">Public</MenuItem>
|
||||
<MenuItem value="CUSTOM">Custom</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<br />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
fullWidth
|
||||
disabled={addLoading}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</Grid>
|
||||
{addLoading && (
|
||||
<Grid item xs={12}>
|
||||
<LinearProgress />
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
</form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
<Grid item xs={12} className={classes.buttonContainer}>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={addLoading}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</Grid>
|
||||
{addLoading && (
|
||||
<Grid item xs={12}>
|
||||
<LinearProgress />
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
</form>
|
||||
</ModalWrapper>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,77 +16,64 @@
|
||||
|
||||
import React from "react";
|
||||
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
|
||||
import Table from "@material-ui/core/Table";
|
||||
import TableBody from "@material-ui/core/TableBody";
|
||||
import TableCell from "@material-ui/core/TableCell";
|
||||
import TableHead from "@material-ui/core/TableHead";
|
||||
import TableRow from "@material-ui/core/TableRow";
|
||||
import Paper from "@material-ui/core/Paper";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import api from "../../../../common/api";
|
||||
import { Bucket, BucketList } from "../types";
|
||||
import {
|
||||
Button,
|
||||
IconButton,
|
||||
LinearProgress,
|
||||
TableFooter,
|
||||
TablePagination
|
||||
} from "@material-ui/core";
|
||||
import { Button } from "@material-ui/core";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import DeleteIcon from "@material-ui/icons/Delete";
|
||||
import AddBucket from "./AddBucket";
|
||||
import DeleteBucket from "./DeleteBucket";
|
||||
import { MinTablePaginationActions } from "../../../../common/MinTablePaginationActions";
|
||||
import { CreateIcon } from "../../../../icons";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import InputAdornment from "@material-ui/core/InputAdornment";
|
||||
import SearchIcon from "@material-ui/icons/Search";
|
||||
import Moment from "react-moment";
|
||||
import { Link } from "react-router-dom";
|
||||
import ViewIcon from "@material-ui/icons/Visibility";
|
||||
import api from "../../../../common/api";
|
||||
import { Bucket, BucketList } from "../types";
|
||||
import TableWrapper from "../../Common/TableWrapper/TableWrapper";
|
||||
import AddBucket from "./AddBucket";
|
||||
import DeleteBucket from "./DeleteBucket";
|
||||
import { MinTablePaginationActions } from "../../../../common/MinTablePaginationActions";
|
||||
import { CreateIcon } from "../../../../icons";
|
||||
import { niceBytes } from "../../../../common/utils";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
seeMore: {
|
||||
marginTop: theme.spacing(3)
|
||||
marginTop: theme.spacing(3),
|
||||
},
|
||||
paper: {
|
||||
display: "flex",
|
||||
overflow: "auto",
|
||||
flexDirection: "column"
|
||||
flexDirection: "column",
|
||||
},
|
||||
|
||||
addSideBar: {
|
||||
width: "320px",
|
||||
padding: "20px"
|
||||
padding: "20px",
|
||||
},
|
||||
errorBlock: {
|
||||
color: "red"
|
||||
color: "red",
|
||||
},
|
||||
tableToolbar: {
|
||||
paddingLeft: theme.spacing(2),
|
||||
paddingRight: theme.spacing(0)
|
||||
paddingRight: theme.spacing(0),
|
||||
},
|
||||
minTableHeader: {
|
||||
color: "#393939",
|
||||
"& tr": {
|
||||
"& th": {
|
||||
fontWeight: "bold"
|
||||
}
|
||||
}
|
||||
fontWeight: "bold",
|
||||
},
|
||||
},
|
||||
},
|
||||
actionsTray: {
|
||||
textAlign: "right",
|
||||
"& button": {
|
||||
marginLeft: 10
|
||||
}
|
||||
marginLeft: 10,
|
||||
},
|
||||
},
|
||||
searchField: {
|
||||
background: "#FFFFFF",
|
||||
padding: 12,
|
||||
borderRadius: 5,
|
||||
boxShadow: "0px 3px 6px #00000012"
|
||||
}
|
||||
boxShadow: "0px 3px 6px #00000012",
|
||||
},
|
||||
});
|
||||
|
||||
interface IListBucketsProps {
|
||||
@@ -122,7 +109,7 @@ class ListBuckets extends React.Component<
|
||||
rowsPerPage: 10,
|
||||
deleteOpen: false,
|
||||
selectedBucket: "",
|
||||
filterBuckets: ""
|
||||
filterBuckets: "",
|
||||
};
|
||||
|
||||
fetchRecords() {
|
||||
@@ -134,9 +121,9 @@ class ListBuckets extends React.Component<
|
||||
.then((res: BucketList) => {
|
||||
this.setState({
|
||||
loading: false,
|
||||
records: res.buckets,
|
||||
totalRecords: res.total,
|
||||
error: ""
|
||||
records: res.buckets || [],
|
||||
totalRecords: !res.buckets ? 0 : res.total,
|
||||
error: "",
|
||||
});
|
||||
// if we get 0 results, and page > 0 , go down 1 page
|
||||
if (
|
||||
@@ -188,7 +175,7 @@ class ListBuckets extends React.Component<
|
||||
rowsPerPage,
|
||||
deleteOpen,
|
||||
selectedBucket,
|
||||
filterBuckets
|
||||
filterBuckets,
|
||||
} = this.state;
|
||||
|
||||
const offset = page * rowsPerPage;
|
||||
@@ -208,14 +195,48 @@ class ListBuckets extends React.Component<
|
||||
this.setState({ deleteOpen: true, selectedBucket: bucket });
|
||||
};
|
||||
|
||||
const tableActions = [
|
||||
{ type: "view", to: `/buckets`, sendOnlyId: true },
|
||||
{ type: "delete", onClick: confirmDeleteBucket, sendOnlyId: true },
|
||||
];
|
||||
|
||||
const displayParsedDate = (date: string) => {
|
||||
return <Moment>{date}</Moment>;
|
||||
};
|
||||
|
||||
const filteredRecords = records
|
||||
.slice(offset, offset + rowsPerPage)
|
||||
.filter((b: Bucket) => {
|
||||
if (filterBuckets === "") {
|
||||
return true;
|
||||
} else {
|
||||
if (b.name.indexOf(filterBuckets) >= 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<AddBucket
|
||||
open={addScreenOpen}
|
||||
closeModalAndRefresh={() => {
|
||||
this.closeAddModalAndRefresh();
|
||||
}}
|
||||
/>
|
||||
{addScreenOpen && (
|
||||
<AddBucket
|
||||
open={addScreenOpen}
|
||||
closeModalAndRefresh={() => {
|
||||
this.closeAddModalAndRefresh();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{deleteOpen && (
|
||||
<DeleteBucket
|
||||
deleteOpen={deleteOpen}
|
||||
selectedBucket={selectedBucket}
|
||||
closeDeleteModalAndRefresh={(refresh: boolean) => {
|
||||
this.closeDeleteModalAndRefresh(refresh);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="h6">Buckets</Typography>
|
||||
@@ -229,9 +250,9 @@ class ListBuckets extends React.Component<
|
||||
className={classes.searchField}
|
||||
id="search-resource"
|
||||
label=""
|
||||
onChange={val => {
|
||||
onChange={(val) => {
|
||||
this.setState({
|
||||
filterBuckets: val.target.value
|
||||
filterBuckets: val.target.value,
|
||||
});
|
||||
}}
|
||||
InputProps={{
|
||||
@@ -240,7 +261,7 @@ class ListBuckets extends React.Component<
|
||||
<InputAdornment position="start">
|
||||
<SearchIcon />
|
||||
</InputAdornment>
|
||||
)
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
@@ -249,7 +270,7 @@ class ListBuckets extends React.Component<
|
||||
startIcon={<CreateIcon />}
|
||||
onClick={() => {
|
||||
this.setState({
|
||||
addScreenOpen: true
|
||||
addScreenOpen: true,
|
||||
});
|
||||
}}
|
||||
>
|
||||
@@ -260,88 +281,42 @@ class ListBuckets extends React.Component<
|
||||
<br />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Paper className={classes.paper}>
|
||||
{loading && <LinearProgress />}
|
||||
{records != null && records.length > 0 ? (
|
||||
<Table size="medium">
|
||||
<TableHead className={classes.minTableHeader}>
|
||||
<TableRow>
|
||||
<TableCell>Name</TableCell>
|
||||
<TableCell>Creation Date</TableCell>
|
||||
<TableCell align="right">Actions</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{records
|
||||
.slice(offset, offset + rowsPerPage)
|
||||
.filter((b: Bucket) => {
|
||||
if (filterBuckets === "") {
|
||||
return true;
|
||||
} else {
|
||||
if (b.name.indexOf(filterBuckets) >= 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
})
|
||||
.map(row => (
|
||||
<TableRow key={row.name}>
|
||||
<TableCell>{row.name}</TableCell>
|
||||
<TableCell>
|
||||
<Moment>{row.creation_date}</Moment>
|
||||
</TableCell>
|
||||
<TableCell align="right">
|
||||
<Link to={`/buckets/${row.name}`}>
|
||||
<IconButton aria-label="delete">
|
||||
<ViewIcon />
|
||||
</IconButton>
|
||||
</Link>
|
||||
<IconButton
|
||||
aria-label="delete"
|
||||
onClick={() => {
|
||||
confirmDeleteBucket(row.name);
|
||||
}}
|
||||
>
|
||||
<DeleteIcon />
|
||||
</IconButton>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
<TableFooter>
|
||||
<TableRow>
|
||||
<TablePagination
|
||||
rowsPerPageOptions={[5, 10, 25]}
|
||||
colSpan={3}
|
||||
count={totalRecords}
|
||||
rowsPerPage={rowsPerPage}
|
||||
page={page}
|
||||
SelectProps={{
|
||||
inputProps: { "aria-label": "rows per page" },
|
||||
native: true
|
||||
}}
|
||||
onChangePage={handleChangePage}
|
||||
onChangeRowsPerPage={handleChangeRowsPerPage}
|
||||
ActionsComponent={MinTablePaginationActions}
|
||||
/>
|
||||
</TableRow>
|
||||
</TableFooter>
|
||||
</Table>
|
||||
) : (
|
||||
<div>No Buckets</div>
|
||||
)}
|
||||
</Paper>
|
||||
<TableWrapper
|
||||
itemActions={tableActions}
|
||||
columns={[
|
||||
{ label: "Name", elementKey: "name" },
|
||||
{
|
||||
label: "Creation Date",
|
||||
elementKey: "creation_date",
|
||||
renderFunction: displayParsedDate,
|
||||
},
|
||||
{
|
||||
label: "Size",
|
||||
elementKey: "size",
|
||||
renderFunction: niceBytes,
|
||||
},
|
||||
]}
|
||||
isLoading={loading}
|
||||
records={filteredRecords}
|
||||
entityName="Buckets"
|
||||
idField="name"
|
||||
paginatorConfig={{
|
||||
rowsPerPageOptions: [5, 10, 25],
|
||||
colSpan: 3,
|
||||
count: totalRecords,
|
||||
rowsPerPage: rowsPerPage,
|
||||
page: page,
|
||||
SelectProps: {
|
||||
inputProps: { "aria-label": "rows per page" },
|
||||
native: true,
|
||||
},
|
||||
onChangePage: handleChangePage,
|
||||
onChangeRowsPerPage: handleChangeRowsPerPage,
|
||||
ActionsComponent: MinTablePaginationActions,
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<DeleteBucket
|
||||
deleteOpen={deleteOpen}
|
||||
selectedBucket={selectedBucket}
|
||||
closeDeleteModalAndRefresh={(refresh: boolean) => {
|
||||
this.closeDeleteModalAndRefresh(refresh);
|
||||
}}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -16,20 +16,8 @@
|
||||
|
||||
import React, { ChangeEvent } from "react";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import Title from "../../../../common/Title";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
FormControl,
|
||||
InputLabel,
|
||||
LinearProgress,
|
||||
MenuItem,
|
||||
Select,
|
||||
TextField
|
||||
} from "@material-ui/core";
|
||||
import { Button, LinearProgress } from "@material-ui/core";
|
||||
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
|
||||
import api from "../../../../common/api";
|
||||
import TableHead from "@material-ui/core/TableHead";
|
||||
@@ -38,21 +26,29 @@ import TableCell from "@material-ui/core/TableCell";
|
||||
import TableBody from "@material-ui/core/TableBody";
|
||||
import Checkbox from "@material-ui/core/Checkbox";
|
||||
import Table from "@material-ui/core/Table";
|
||||
import { ArnList, BucketEventList } from "../types";
|
||||
import { ArnList } from "../types";
|
||||
import { modalBasic } from "../../Common/FormComponents/common/styleLibrary";
|
||||
import ModalWrapper from "../../Common/ModalWrapper/ModalWrapper";
|
||||
import InputBoxWrapper from "../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
||||
import SelectWrapper from "../../Common/FormComponents/SelectWrapper/SelectWrapper";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
errorBlock: {
|
||||
color: "red"
|
||||
color: "red",
|
||||
},
|
||||
minTableHeader: {
|
||||
color: "#393939",
|
||||
"& tr": {
|
||||
"& th": {
|
||||
fontWeight: "bold"
|
||||
}
|
||||
}
|
||||
}
|
||||
fontWeight: "bold",
|
||||
},
|
||||
},
|
||||
},
|
||||
buttonContainer: {
|
||||
textAlign: "right",
|
||||
},
|
||||
...modalBasic,
|
||||
});
|
||||
|
||||
interface IAddEventProps {
|
||||
@@ -80,7 +76,7 @@ class AddEvent extends React.Component<IAddEventProps, IAddEventState> {
|
||||
suffix: "",
|
||||
arn: "",
|
||||
selectedEvents: [],
|
||||
arnList: []
|
||||
arnList: [],
|
||||
};
|
||||
|
||||
addRecord(event: React.FormEvent) {
|
||||
@@ -97,25 +93,25 @@ class AddEvent extends React.Component<IAddEventProps, IAddEventState> {
|
||||
arn: arn,
|
||||
events: selectedEvents,
|
||||
prefix: prefix,
|
||||
sufix: suffix
|
||||
suffix: suffix,
|
||||
},
|
||||
ignoreExisting: true
|
||||
ignoreExisting: true,
|
||||
})
|
||||
.then(res => {
|
||||
.then((res) => {
|
||||
this.setState(
|
||||
{
|
||||
addLoading: false,
|
||||
addError: ""
|
||||
addError: "",
|
||||
},
|
||||
() => {
|
||||
this.props.closeModalAndRefresh();
|
||||
}
|
||||
);
|
||||
})
|
||||
.catch(err => {
|
||||
.catch((err) => {
|
||||
this.setState({
|
||||
addLoading: false,
|
||||
addError: err
|
||||
addError: err,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -133,7 +129,7 @@ class AddEvent extends React.Component<IAddEventProps, IAddEventState> {
|
||||
this.setState({
|
||||
addLoading: false,
|
||||
arnList: arns,
|
||||
addError: ""
|
||||
addError: "",
|
||||
});
|
||||
})
|
||||
.catch((err: any) => {
|
||||
@@ -148,34 +144,22 @@ class AddEvent extends React.Component<IAddEventProps, IAddEventState> {
|
||||
|
||||
render() {
|
||||
const { classes, open } = this.props;
|
||||
const { addLoading, addError, arn, selectedEvents, arnList } = this.state;
|
||||
const {
|
||||
addLoading,
|
||||
addError,
|
||||
arn,
|
||||
selectedEvents,
|
||||
arnList,
|
||||
prefix,
|
||||
suffix,
|
||||
} = this.state;
|
||||
|
||||
const events = [
|
||||
{ label: "PUT - Object Uploaded", value: "put" },
|
||||
{ label: "GET - Object accessed", value: "get" },
|
||||
{ label: "DELETE - Object Deleted", value: "delete" }
|
||||
{ label: "DELETE - Object Deleted", value: "delete" },
|
||||
];
|
||||
|
||||
const selectionChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const targetD = e.target;
|
||||
const value = targetD.value;
|
||||
const checked = targetD.checked;
|
||||
|
||||
let elements: string[] = [...selectedEvents]; // We clone the selectedGroups array
|
||||
|
||||
if (checked) {
|
||||
// If the user has checked this field we need to push this to selectedGroupsList
|
||||
elements.push(value);
|
||||
} else {
|
||||
// User has unchecked this field, we need to remove it from the list
|
||||
elements = elements.filter(element => element !== value);
|
||||
}
|
||||
|
||||
this.setState({ selectedEvents: selectedEvents });
|
||||
|
||||
return elements;
|
||||
};
|
||||
|
||||
const handleClick = (
|
||||
event: React.MouseEvent<unknown> | ChangeEvent<unknown>,
|
||||
name: string
|
||||
@@ -199,29 +183,30 @@ class AddEvent extends React.Component<IAddEventProps, IAddEventState> {
|
||||
this.setState({ selectedEvents: newSelected });
|
||||
};
|
||||
|
||||
const arnValues = arnList.map((arnConstant) => ({
|
||||
label: arnConstant,
|
||||
value: arnConstant,
|
||||
}));
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={open}
|
||||
<ModalWrapper
|
||||
modalOpen={open}
|
||||
onClose={() => {
|
||||
this.setState({ addError: "" }, () => {
|
||||
this.props.closeModalAndRefresh();
|
||||
});
|
||||
}}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
title="Subscribe To Event"
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">
|
||||
<Title>Subscribe To Event</Title>
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<form
|
||||
noValidate
|
||||
autoComplete="off"
|
||||
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
|
||||
this.addRecord(e);
|
||||
}}
|
||||
>
|
||||
<Grid container>
|
||||
<form
|
||||
noValidate
|
||||
autoComplete="off"
|
||||
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
|
||||
this.addRecord(e);
|
||||
}}
|
||||
>
|
||||
<Grid container>
|
||||
<Grid item xs={12} className={classes.formScrollable}>
|
||||
{addError !== "" && (
|
||||
<Grid item xs={12}>
|
||||
<Typography
|
||||
@@ -234,23 +219,17 @@ class AddEvent extends React.Component<IAddEventProps, IAddEventState> {
|
||||
</Grid>
|
||||
)}
|
||||
<Grid item xs={12}>
|
||||
<FormControl className={classes.formControl} fullWidth>
|
||||
<InputLabel id="select-access-policy">ARN</InputLabel>
|
||||
<Select
|
||||
labelId="select-access-policy"
|
||||
id="select-access-policy"
|
||||
value={arn}
|
||||
onChange={(e: React.ChangeEvent<{ value: unknown }>) => {
|
||||
this.setState({ arn: e.target.value as string });
|
||||
}}
|
||||
>
|
||||
{arnList.map(arn => (
|
||||
<MenuItem value={arn}>{arn}</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<SelectWrapper
|
||||
onChange={(e: React.ChangeEvent<{ value: unknown }>) => {
|
||||
this.setState({ arn: e.target.value as string });
|
||||
}}
|
||||
id="select-access-policy"
|
||||
name="select-access-policy"
|
||||
label={"ARN"}
|
||||
value={arn}
|
||||
options={arnValues}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<Table size="medium">
|
||||
<TableHead className={classes.minTableHeader}>
|
||||
@@ -260,19 +239,19 @@ class AddEvent extends React.Component<IAddEventProps, IAddEventState> {
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{events.map(row => (
|
||||
{events.map((row) => (
|
||||
<TableRow
|
||||
key={`group-${row.value}`}
|
||||
onClick={event => handleClick(event, row.value)}
|
||||
onClick={(event) => handleClick(event, row.value)}
|
||||
>
|
||||
<TableCell padding="checkbox">
|
||||
<Checkbox
|
||||
value={row.value}
|
||||
color="primary"
|
||||
inputProps={{
|
||||
"aria-label": "secondary checkbox"
|
||||
"aria-label": "secondary checkbox",
|
||||
}}
|
||||
onChange={event => handleClick(event, row.value)}
|
||||
onChange={(event) => handleClick(event, row.value)}
|
||||
checked={selectedEvents.includes(row.value)}
|
||||
/>
|
||||
</TableCell>
|
||||
@@ -285,20 +264,25 @@ class AddEvent extends React.Component<IAddEventProps, IAddEventState> {
|
||||
</Table>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
id="standard-basic"
|
||||
fullWidth
|
||||
<br />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
id="prefix-input"
|
||||
name="prefix-input"
|
||||
label="Prefix"
|
||||
value={prefix}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({ prefix: e.target.value });
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
id="standard-basic"
|
||||
fullWidth
|
||||
<InputBoxWrapper
|
||||
id="suffix-input"
|
||||
name="suffix-input"
|
||||
label="Suffix"
|
||||
value={suffix}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({ suffix: e.target.value });
|
||||
}}
|
||||
@@ -307,26 +291,25 @@ class AddEvent extends React.Component<IAddEventProps, IAddEventState> {
|
||||
<Grid item xs={12}>
|
||||
<br />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
fullWidth
|
||||
disabled={addLoading}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</Grid>
|
||||
{addLoading && (
|
||||
<Grid item xs={12}>
|
||||
<LinearProgress />
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
</form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
<Grid item xs={12} className={classes.buttonContainer}>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={addLoading}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</Grid>
|
||||
{addLoading && (
|
||||
<Grid item xs={12}>
|
||||
<LinearProgress />
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
</form>
|
||||
</ModalWrapper>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,9 @@
|
||||
// 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/>.
|
||||
|
||||
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
|
||||
import React from "react";
|
||||
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
|
||||
import get from "lodash/get";
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
@@ -23,7 +24,7 @@ import {
|
||||
DialogContent,
|
||||
DialogContentText,
|
||||
DialogTitle,
|
||||
LinearProgress
|
||||
LinearProgress,
|
||||
} from "@material-ui/core";
|
||||
import api from "../../../../common/api";
|
||||
import { BucketEvent, BucketList } from "../types";
|
||||
@@ -32,8 +33,8 @@ import Typography from "@material-ui/core/Typography";
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
errorBlock: {
|
||||
color: "red"
|
||||
}
|
||||
color: "red",
|
||||
},
|
||||
});
|
||||
|
||||
interface IDeleteEventProps {
|
||||
@@ -55,7 +56,7 @@ class DeleteEvent extends React.Component<
|
||||
> {
|
||||
state: IDeleteEventState = {
|
||||
deleteLoading: false,
|
||||
deleteError: ""
|
||||
deleteError: "",
|
||||
};
|
||||
|
||||
removeRecord() {
|
||||
@@ -67,37 +68,43 @@ class DeleteEvent extends React.Component<
|
||||
if (bucketEvent == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({ deleteLoading: true }, () => {
|
||||
const events = get(bucketEvent, "events", []);
|
||||
const prefix = get(bucketEvent, "prefix", "");
|
||||
const suffix = get(bucketEvent, "suffix", "");
|
||||
api
|
||||
.invoke(
|
||||
"DELETE",
|
||||
`/api/v1/buckets/${selectedBucket}/events/${bucketEvent.id}`,
|
||||
`/api/v1/buckets/${selectedBucket}/events/${bucketEvent.arn}`,
|
||||
{
|
||||
name: selectedBucket
|
||||
events,
|
||||
prefix,
|
||||
suffix,
|
||||
}
|
||||
)
|
||||
.then((res: BucketList) => {
|
||||
this.setState(
|
||||
{
|
||||
deleteLoading: false,
|
||||
deleteError: ""
|
||||
deleteError: "",
|
||||
},
|
||||
() => {
|
||||
this.props.closeDeleteModalAndRefresh(true);
|
||||
}
|
||||
);
|
||||
})
|
||||
.catch(err => {
|
||||
.catch((err) => {
|
||||
this.setState({
|
||||
deleteLoading: false,
|
||||
deleteError: err
|
||||
deleteError: err,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { classes, deleteOpen, selectedBucket } = this.props;
|
||||
const { classes, deleteOpen } = this.props;
|
||||
const { deleteLoading, deleteError } = this.state;
|
||||
|
||||
return (
|
||||
|
||||
@@ -15,34 +15,27 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import React from "react";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import Title from "../../../../common/Title";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
FormControl,
|
||||
InputLabel,
|
||||
LinearProgress,
|
||||
MenuItem,
|
||||
Select,
|
||||
TextField
|
||||
} from "@material-ui/core";
|
||||
import { Button, LinearProgress } from "@material-ui/core";
|
||||
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
|
||||
import { modalBasic } from "../../Common/FormComponents/common/styleLibrary";
|
||||
import api from "../../../../common/api";
|
||||
import ModalWrapper from "../../Common/ModalWrapper/ModalWrapper";
|
||||
import SelectWrapper from "../../Common/FormComponents/SelectWrapper/SelectWrapper";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
errorBlock: {
|
||||
color: "red"
|
||||
}
|
||||
color: "red",
|
||||
},
|
||||
...modalBasic,
|
||||
});
|
||||
|
||||
interface ISetAccessPolicyProps {
|
||||
classes: any;
|
||||
open: boolean;
|
||||
bucketName: string;
|
||||
actualPolicy: string;
|
||||
closeModalAndRefresh: () => void;
|
||||
}
|
||||
|
||||
@@ -59,7 +52,7 @@ class SetAccessPolicy extends React.Component<
|
||||
state: ISetAccessPolicyState = {
|
||||
addLoading: false,
|
||||
addError: "",
|
||||
accessPolicy: ""
|
||||
accessPolicy: "",
|
||||
};
|
||||
|
||||
addRecord(event: React.FormEvent) {
|
||||
@@ -72,54 +65,56 @@ class SetAccessPolicy extends React.Component<
|
||||
this.setState({ addLoading: true }, () => {
|
||||
api
|
||||
.invoke("PUT", `/api/v1/buckets/${bucketName}/set-policy`, {
|
||||
access: accessPolicy
|
||||
access: accessPolicy,
|
||||
})
|
||||
.then(res => {
|
||||
.then((res) => {
|
||||
this.setState(
|
||||
{
|
||||
addLoading: false,
|
||||
addError: ""
|
||||
addError: "",
|
||||
},
|
||||
() => {
|
||||
this.props.closeModalAndRefresh();
|
||||
}
|
||||
);
|
||||
})
|
||||
.catch(err => {
|
||||
.catch((err) => {
|
||||
this.setState({
|
||||
addLoading: false,
|
||||
addError: err
|
||||
addError: err,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { actualPolicy } = this.props;
|
||||
|
||||
this.setState({ accessPolicy: actualPolicy });
|
||||
}
|
||||
|
||||
render() {
|
||||
const { classes, open } = this.props;
|
||||
const { classes, open, actualPolicy } = this.props;
|
||||
const { addLoading, addError, accessPolicy } = this.state;
|
||||
return (
|
||||
<Dialog
|
||||
open={open}
|
||||
<ModalWrapper
|
||||
title="Change Access Policy"
|
||||
modalOpen={open}
|
||||
onClose={() => {
|
||||
this.setState({ addError: "" }, () => {
|
||||
this.props.closeModalAndRefresh();
|
||||
});
|
||||
}}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">
|
||||
<Title>Change Access Policy</Title>
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<form
|
||||
noValidate
|
||||
autoComplete="off"
|
||||
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
|
||||
this.addRecord(e);
|
||||
}}
|
||||
>
|
||||
<Grid container>
|
||||
<form
|
||||
noValidate
|
||||
autoComplete="off"
|
||||
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
|
||||
this.addRecord(e);
|
||||
}}
|
||||
>
|
||||
<Grid container>
|
||||
<Grid item xs={12} className={classes.formScrollable}>
|
||||
{addError !== "" && (
|
||||
<Grid item xs={12}>
|
||||
<Typography
|
||||
@@ -132,47 +127,40 @@ class SetAccessPolicy extends React.Component<
|
||||
</Grid>
|
||||
)}
|
||||
<Grid item xs={12}>
|
||||
<FormControl className={classes.formControl} fullWidth>
|
||||
<InputLabel id="select-access-policy">
|
||||
Access Policy
|
||||
</InputLabel>
|
||||
<Select
|
||||
labelId="select-access-policy"
|
||||
id="select-access-policy"
|
||||
value={accessPolicy}
|
||||
onChange={(e: React.ChangeEvent<{ value: unknown }>) => {
|
||||
this.setState({ accessPolicy: e.target.value as string });
|
||||
}}
|
||||
>
|
||||
<MenuItem value="PRIVATE">Private</MenuItem>
|
||||
<MenuItem value="PUBLIC">Public</MenuItem>
|
||||
<MenuItem value="CUSTOM">Custom</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
<SelectWrapper
|
||||
value={accessPolicy}
|
||||
label="Access Policy"
|
||||
id="select-access-policy"
|
||||
name="select-access-policy"
|
||||
onChange={(e: React.ChangeEvent<{ value: unknown }>) => {
|
||||
this.setState({ accessPolicy: e.target.value as string });
|
||||
}}
|
||||
options={[
|
||||
{ value: "PRIVATE", label: "Private" },
|
||||
{ value: "PUBLIC", label: "Public" },
|
||||
]}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<br />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
fullWidth
|
||||
disabled={addLoading}
|
||||
>
|
||||
Set
|
||||
</Button>
|
||||
</Grid>
|
||||
{addLoading && (
|
||||
<Grid item xs={12}>
|
||||
<LinearProgress />
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
</form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
<Grid item xs={12}>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
fullWidth
|
||||
disabled={addLoading}
|
||||
>
|
||||
Set
|
||||
</Button>
|
||||
</Grid>
|
||||
{addLoading && (
|
||||
<Grid item xs={12}>
|
||||
<LinearProgress />
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
</form>
|
||||
</ModalWrapper>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||