Compare commits

...

65 Commits

Author SHA1 Message Date
Minio Trusted
901358e8d4 update to release v0.6.5 2021-03-27 13:26:58 -07:00
Lenin Alevski
5155aef802 Add support to load certificates from swagger tls flags (#672)
- Add support to load certificates via `--tls-certificate`, `--tls-key`
  and `--tls-ca` flags (standard TLS flags for the swagger server)
- Certificate keypair will be added to the certificate pool used by the
  Console server
2021-03-27 12:21:59 -07:00
adfost
23b3283014 Adding Bucket Policies UI to ViewBucket.tsx (#669)
* Adding ViewBucket.tsx

* Update ViewBucket.tsx

Co-authored-by: Adam Stafford <adam@minio.io>
2021-03-26 10:06:38 -07:00
Daniel Valdivia
53eb59f5ad Disable Bucket/Replication (feature) if not enough permissions (#662)
* Bucket/Replication (feature) if not enough permissions

* Address comments

* Remove Consts fetchPerms
2021-03-25 10:10:54 -07:00
Minio Trusted
e088431c62 update to v0.6.4 2021-03-23 17:45:51 -07:00
Lenin Alevski
8bb982b39f update ldap development example (#664) 2021-03-23 15:09:44 -06:00
Daniel Valdivia
744ccea842 Add Bucket Locking option and fix versioning configuration. (#661)
* Add Bucket Locking option and fix versioning configuration.

* Addres comments

* Rework the View Bucket options

* Remove extra padding
2021-03-22 16:28:07 -07:00
Daniel Valdivia
19195e0cd0 Interactive Feedback when list objects take a long time (#655)
* Interactive Feedback when list objects take a long time

* Remove cancel button

Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>
2021-03-22 11:36:46 -07:00
Lenin Alevski
7ce36bac42 console license page improvements and fixes (#647)
- fixed issue when deploying tenant with tls disabled
- applied new design for tenant details and license screens
- added license refresh job to operator console
- added new refresh license endpoint
- console operator not longer store CONSOLE_ACCESS_KEY and
  CONSOLE_SECRET_KEY values in the tenant-console-secret

Co-authored-by: Daniel Valdivia <hola@danielvaldivia.com>
2021-03-22 11:08:31 -07:00
Daniel Valdivia
2a704d3d59 Allow to assign multiple policies to to a user or group (#646)
* Allow to assign multiple policies to to a user or group

* Latest assets
2021-03-22 10:45:31 -07:00
dependabot[bot]
897b5b8be5 Bump react-dev-utils from 11.0.1 to 11.0.4 in /portal-ui (#644)
Bumps [react-dev-utils](https://github.com/facebook/create-react-app/tree/HEAD/packages/react-dev-utils) from 11.0.1 to 11.0.4.
- [Release notes](https://github.com/facebook/create-react-app/releases)
- [Changelog](https://github.com/facebook/create-react-app/blob/master/CHANGELOG-1.x.md)
- [Commits](https://github.com/facebook/create-react-app/commits/HEAD/packages/react-dev-utils)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Daniel Valdivia <hola@danielvaldivia.com>
2021-03-19 22:18:24 -07:00
Alex
03dc83af3a Added versioning edit in console (#645) 2021-03-19 17:48:58 -07:00
adfost
26f7982323 api for listing policies attatched to a bucket (#660)
api for listing policies attatched to a bucket
2021-03-19 16:00:56 -07:00
dependabot[bot]
934e8c9f4c Bump elliptic from 6.5.3 to 6.5.4 in /portal-ui (#640)
Bumps [elliptic](https://github.com/indutny/elliptic) from 6.5.3 to 6.5.4.
- [Release notes](https://github.com/indutny/elliptic/releases)
- [Commits](https://github.com/indutny/elliptic/compare/v6.5.3...v6.5.4)

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-18 18:05:15 -07:00
Cesar N
e780f24fb9 Add list direct-csi drives api (#643)
Add direct-csi volumes list api

Co-authored-by: Daniel Valdivia <hola@danielvaldivia.com>
2021-03-18 12:10:05 -07:00
Lenin Alevski
c48a024310 Remove user secret key from encrypted session token (#652)
User secret key is not really need it to be stored inside the encrypted
session key, since the `change-password` endpoint requires the user to
provide the current `secret key` that password will be used to
initialize a new minio client then we will leverage on the
`SetUser` operation, this api only works with actual user credentials
and not sts credentials
2021-03-18 10:27:27 -07:00
Minio Trusted
3fcf278460 rename Readme.md as README.md github friendly name 2021-03-11 21:26:28 -08:00
Nitish Tiwari
8b6202296e Add Docker compose file for quick deployment on non k8s envs (#639) 2021-03-11 21:24:38 -08:00
Alex
7030e80ac8 Allowed edit in policies create form (#642) 2021-03-11 16:48:01 -06:00
Alex
6bed9f8f97 Fixed issue with routes (#641) 2021-03-10 13:39:07 -06:00
Cesar N
e7263c9a89 Show object versions on UI only when bucket has versioning enabled (#637) 2021-03-10 12:37:43 -06:00
Lenin Alevski
9c1e87b1be Improvements on change-password errors page (#635)
- Returning correct error when user is unable to change password
- Added support for enable/disable UI elements based on allowed apis
2021-03-09 19:32:09 -06:00
Alex
6f98ecc59f Revert "Tiers & lifecycle implementation (#615)" (#636)
This reverts commit ac77b8b441.

Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2021-03-09 14:07:53 -08:00
Alex
ac77b8b441 Tiers & lifecycle implementation (#615)
* Tiers & lifecycle implementation

* Add a feature flag for ILM

* Update pkg/auth/idp/oauth2/provider.go

Co-authored-by: Lenin Alevski <alevsk.8772@gmail.com>

Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
Co-authored-by: Daniel Valdivia <hola@danielvaldivia.com>
Co-authored-by: Lenin Alevski <alevsk.8772@gmail.com>
2021-03-09 12:36:48 -08:00
Alex
d4a69978fc Added loader & notification for files download (#634)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2021-03-09 09:29:54 -08:00
Alex
81087ae910 Added validation for users to not delete their own account (#633)
Also Implemented an option to show / hide actions in table wrapper

Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2021-03-08 21:38:19 -08:00
Cesar N
ebab2e1648 Update docs for go version required (#632) 2021-03-05 17:59:55 -06:00
Harshavardhana
9a875a6f14 add console systemd service (#627)
Co-authored-by: Daniel Valdivia <hola@danielvaldivia.com>
2021-03-05 15:20:22 -08:00
Alex
abc9f2b428 Limited input width size for forms in wide screens (#628)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2021-03-05 12:30:01 -08:00
Daniel Valdivia
a2a09b8db1 Upgrade to Go 1.16. Remove Go-Bind-assets in favor of embed. (#630)
* Upgrade to Go 1.16. Remove Go-Bind-assets in favor of embed. Checking Portal-UI Build folder.

* lint

* Remove assets references

* Fixes for sub fs

* Fix lint
2021-03-05 10:39:17 -08:00
Alex
716aabe782 Fixed max size for widgets (#624)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2021-03-04 16:09:22 -08:00
Alex
07a23ab374 Fixes issue in settings page with CSV multiselector scroll (#622)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
Co-authored-by: Daniel Valdivia <hola@danielvaldivia.com>
2021-03-04 14:53:47 -08:00
Cesar N
e7838ebc47 Add right image for logsearchapi (#626) 2021-03-03 16:26:44 -08:00
Minio Trusted
e6705b685c update to v0.6.3 2021-03-02 20:46:04 -08:00
Alex
6b11d403a6 Add Tenant page refactor (#617)
Refactored add tenant page to be working with reducers & settings styles
2021-03-02 20:18:53 -08:00
Daniel Valdivia
8958cbec69 Fix container image for log search (#619) 2021-03-02 11:07:31 -06:00
Lenin Alevski
5ef66c3cfc Fixes for license page (#620) 2021-03-01 22:25:08 -08:00
Harshavardhana
d4395e1409 add update command to self-update console (#618) 2021-03-01 16:30:53 -08:00
Minio Trusted
8a4139c8e7 update to v0.6.2 2021-02-26 13:01:28 -08:00
Lenin Alevski
34bcd25c9f Disable Users and Groups Menu options when LDAP is enabled on MinIO (#614) 2021-02-26 11:20:17 -08:00
Minio Trusted
7853aa6bb9 update to v0.6.1 2021-02-25 10:20:32 -08:00
Lenin Alevski
9c1f0c47b0 Custom HTTP Client TLS transport for STSWebIdentity (#612)
Co-authored-by: Daniel Valdivia <hola@danielvaldivia.com>
2021-02-25 09:09:55 -08:00
Daniel Valdivia
6ac95e40a4 Get Tenants endpoints check hostname (#609) 2021-02-23 12:49:46 -08:00
Joshua Hoblitt
70fb7291f5 fix docker "dev" tag string (#611) 2021-02-23 10:28:05 -08:00
Lenin Alevski
4b28bf5921 New design for License Page (#608) 2021-02-22 16:41:17 -08:00
jinapurapu
99d5e71512 Added refresh tenant functionality (#604)
* Added refresh tenant functionality

* Delete bindata.go

Co-authored-by: Daniel Valdivia <hola@danielvaldivia.com>
Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>
2021-02-18 17:33:00 -08:00
Minio Trusted
2a5c1afbdf release console version v0.6.0 2021-02-18 12:23:47 -08:00
Lenin Alevski
51a9482e91 Fixes issue that prevents LDAP users to authenticate (#605) 2021-02-18 13:06:02 -06:00
Harshavardhana
d01eeb43a7 update minio dependency to latest release (#603)
iam/policies now support wildcard actions for
all actions such as 's3:Get*', 's3:Put*'

new policies such as CreateBucket now honors
LocationConstraint set but rejecting calls
that do not honor region.
2021-02-16 12:53:18 -08:00
Alex
7121dbfcea Replaced help icon in console (#602) 2021-02-12 20:22:05 -08:00
Lenin Alevski
e5fc6e3125 AWS KMS Operator-UI fix (#601)
- Operator UI was not passing AWS KMS configuration on create tenant
  request
2021-02-12 18:15:03 -06:00
Lenin Alevski
396d8fbcfc GCP KMS many fixes (#600)
- Operator-UI didnt correctly append gcp kms configuration
2021-02-12 09:20:36 -08:00
Daniel Valdivia
f958b73e48 Show Credentials after adding tenant (#599)
* Show Credentials after adding tenant

* assets

* Change order of routing
2021-02-10 21:09:35 -08:00
Lenin Alevski
940c7dc5bc Support for GCP KMS configuration (#592) 2021-02-10 18:09:50 -08:00
Daniel Valdivia
cdadb05551 Move Tenant from Modal to Page (#596)
* Move Tenant from Modal to Page

* Address comments

* Small margin tweak
2021-02-10 15:41:07 -08:00
Daniel Valdivia
1dcdc61ce8 Fix Tenant Details Bugs (#589)
This fixes #584 by making the expand set a name for the pool
This fixes #585 by making the expand set an affinity for the pool
This fixes #586 by generating a pool name if it's not indicated only
2021-02-05 14:27:29 -08:00
Lenin Alevski
7174892231 New design for subscription page (#568)
Co-authored-by: Daniel Valdivia <hola@danielvaldivia.com>
2021-02-05 12:49:31 -08:00
Minio Trusted
3262212bd0 update README.md to link the binaries 2021-02-04 23:49:56 -08:00
Alex
ee1a6718d7 Changed policy API to receive name param in query instead or URL (#591)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2021-02-04 15:57:10 -08:00
Lenin Alevski
1c6a29bc20 Support for adding ExternalCaCert secrets (#576) 2021-02-02 16:49:40 -08:00
Daniel Valdivia
6b02f472e6 Upgrade console to use operator v4.0.0 (#581)
* Upgrade console to use operator v4.0.0

* Use latest Operator
2021-02-01 12:13:51 -08:00
Harshavardhana
eddb6a810b update console deps (#582)
- github.com/minio/minio/pkg/licverifier
- github.com/minio/minio/pkg/madmin
- github.com/minio/operator/

Co-authored-by: Minio Trusted <trusted@minio.io>
2021-01-27 19:55:56 -08:00
Lenin Alevski
3b1449c029 Default TLS redirect if Console runs with HTTPS (#580)
TLS redirect default behavior is `TRUE` only if Console is running with
HTTPS
2021-01-26 20:08:21 -08:00
Harshavardhana
365778eecb fix: turn-off TLS redirects if configured (#574)
fixes #573
2021-01-25 23:15:34 -08:00
Alex
52fac7f542 Fixed some issues with dashboard (#570)
-Added padding to the bottom of dashboard

-Added calculations for linear chart tick interval

-Added default min width configurations to panels.

- Fixed crash on clean tenant

Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2021-01-25 10:12:50 -08:00
239 changed files with 16277 additions and 5843 deletions

View File

@@ -14,7 +14,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
go-version: [1.15.x]
go-version: [1.16.x]
os: [ubuntu-latest]
steps:
- name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }}

1
.gitignore vendored
View File

@@ -27,7 +27,6 @@ dist/
# Ignore node_modules
portal-ui/node_modules/
portal-ui/build/
# Ignore tls cert and key
private.key

View File

@@ -3,7 +3,7 @@
project_name: console
release:
name_template: "Release version {{.Version}}"
name_template: "Release version {{.Tag}}"
github:
owner: minio
name: console
@@ -27,8 +27,6 @@ builds:
- s390x
- arm64
ignore:
- goos: darwin
goarch: arm64
- goos: darwin
goarch: arm
- goos: windows
@@ -85,6 +83,7 @@ dockers:
- image_templates:
- "minio/console:{{ .Tag }}-amd64"
use_buildx: true
goarch: amd64
dockerfile: Dockerfile.release
extra_files:
- LICENSE
@@ -94,6 +93,7 @@ dockers:
- image_templates:
- "minio/console:{{ .Tag }}-ppc64le"
use_buildx: true
goarch: ppc64le
dockerfile: Dockerfile.release
extra_files:
- LICENSE
@@ -103,6 +103,7 @@ dockers:
- image_templates:
- "minio/console:{{ .Tag }}-s390x"
use_buildx: true
goarch: s390x
dockerfile: Dockerfile.release
extra_files:
- LICENSE
@@ -113,6 +114,7 @@ dockers:
- "minio/console:{{ .Tag }}-arm64"
use_buildx: true
goarch: arm64
goos: linux
dockerfile: Dockerfile.release
extra_files:
- LICENSE

73
CREDITS
View File

@@ -2836,35 +2836,6 @@ Everyone is permitted to copy and distribute copies of this Agreement, but in or
This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation.
================================================================
github.com/elazarl/go-bindata-assetfs
https://github.com/elazarl/go-bindata-assetfs
----------------------------------------------------------------
Copyright (c) 2014, Elazar Leibovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================================
github.com/evanphx/json-patch
https://github.com/evanphx/json-patch
----------------------------------------------------------------
@@ -13173,28 +13144,28 @@ SOFTWARE.
github.com/klauspost/readahead
https://github.com/klauspost/readahead
----------------------------------------------------------------
The MIT License (MIT)
Copyright (c) 2015 Klaus Post
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
The MIT License (MIT)
Copyright (c) 2015 Klaus Post
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================================

View File

@@ -12,7 +12,7 @@ Run the `billy.ldif` file using `ldapadd` command to create a new user and assig
```
$ docker cp console/docs/ldap/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
$ 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
```
Query the ldap server to check the user billy was created correctly and got assigned to the consoleAdmin group, you should get a list
@@ -67,7 +67,7 @@ $ cat > consoleAdmin.json << EOF
}
EOF
$ mc admin policy add myminio consoleAdmin consoleAdmin.json
$ mc admin policy set myminio consoleAdmin user=billy
$ mc admin policy set myminio consoleAdmin user="uid=billy,dc=example,dc=org"
```
## Run MinIO

View File

@@ -1,14 +1,7 @@
FROM golang:1.15 as binlayer
RUN go get github.com/go-bindata/go-bindata/... && go get github.com/elazarl/go-bindata-assetfs/...
FROM node:10 as uilayer
WORKDIR /app
COPY --from=binlayer /go/bin/go-bindata-assetfs /bin/
COPY --from=binlayer /go/bin/go-bindata /bin/
COPY ./portal-ui/package.json ./
COPY ./portal-ui/yarn.lock ./
RUN yarn install
@@ -19,7 +12,7 @@ RUN yarn install && make build-static
USER node
FROM golang:1.15 as golayer
FROM golang:1.16 as golayer
RUN apt-get update -y && apt-get install -y ca-certificates
@@ -33,8 +26,6 @@ RUN go mod download
ADD . /go/src/github.com/minio/console/
WORKDIR /go/src/github.com/minio/console/
COPY --from=uilayer /app/bindata_assetfs.go /go/src/github.com/minio/console/portal-ui/bindata_assetfs.go
ENV CGO_ENABLED=0
RUN go build -ldflags "-w -s" -a -o console ./cmd/console

View File

@@ -1,14 +1,7 @@
FROM golang:1.15 as binlayer
RUN go get github.com/go-bindata/go-bindata/... && go get github.com/elazarl/go-bindata-assetfs/...
FROM node:10 as uilayer
WORKDIR /app
COPY --from=binlayer /go/bin/go-bindata-assetfs /bin/
COPY --from=binlayer /go/bin/go-bindata /bin/
COPY ./portal-ui/package.json ./
COPY ./portal-ui/yarn.lock ./
RUN yarn install

View File

@@ -6,8 +6,8 @@ COPY LICENSE /licenses/LICENSE
LABEL name="MinIO" \
vendor="MinIO Inc <dev@min.io>" \
maintainer="MinIO Inc <dev@min.io>" \
version="v0.5.2" \
release="v0.5.2" \
version="v0.6.5" \
release="v0.6.5" \
summary="A graphical user interface for MinIO" \
description="MinIO object storage is fundamentally different. Designed for performance and the S3 API, it is 100% open-source. MinIO is ideal for large, private cloud environments with stringent security requirements and delivers mission-critical availability across a diverse range of workloads."

View File

@@ -3,7 +3,7 @@ GOPATH := $(shell go env GOPATH)
# Sets the build version based on the output of the following command, if we are building for a tag, that's the build else it uses the current git branch as the build
BUILD_VERSION:=$(shell git describe --exact-match --tags $(git log -n1 --pretty='%h') 2>/dev/null || git rev-parse --abbrev-ref HEAD 2>/dev/null)
BUILD_TIME:=$(shell date 2>/dev/null)
TAG ?= "minio/console:$(VERSION)-dev"
TAG ?= "minio/console:$(BUILD_VERSION)-dev"
default: console

View File

@@ -12,25 +12,61 @@ A graphical user interface for [MinIO](https://github.com/minio/minio)
**Table of Contents**
- [MinIO Console](#minio-console)
- [-](#-)
- [Install](#install)
- [Binary Releases](#binary-releases)
- [Docker](#docker)
- [Build from source](#build-from-source)
- [Setup](#setup)
- [1. Create a user `console` using `mc`](#1-create-a-user-console-using-mc)
- [2. Create a policy for `console` with admin access to all resources (for testing)](#2-create-a-policy-for-console-with-admin-access-to-all-resources-for-testing)
- [3. Set the policy for the new `console` user](#3-set-the-policy-for-the-new-console-user)
- [Start Console service:](#start-console-service)
- [Salt to encrypt JWT payload](#salt-to-encrypt-jwt-payload)
- [Start Console service with TLS:](#start-console-service-with-tls)
- [Connect Console to a Minio using TLS and a self-signed certificate](#connect-console-to-a-minio-using-tls-and-a-self-signed-certificate)
- [Contribute to console Project](#contribute-to-console-project)
<!-- markdown-toc end -->
### Setup
## Install
### Binary Releases
| OS | ARCH | Binary |
|:-------:|:-------:|:----------------------------------------------------------------------------------------------------:|
| Linux | amd64 | [linux-amd64](https://github.com/minio/console/releases/latest/download/console-linux-amd64) |
| Linux | arm64 | [linux-arm64](https://github.com/minio/console/releases/latest/download/console-linux-arm64) |
| Linux | ppc64le | [linux-ppc64le](https://github.com/minio/console/releases/latest/download/console-linux-ppc64le) |
| Linux | s390x | [linux-s390x](https://github.com/minio/console/releases/latest/download/console-linux-s390x) |
| Apple | amd64 | [darwin-amd64](https://github.com/minio/console/releases/latest/download/console-darwin-amd64) |
| Windows | amd64 | [windows-amd64](https://github.com/minio/console/releases/latest/download/console-windows-amd64.exe) |
You can also verify the binary with [minisign](https://jedisct1.github.io/minisign/) by downloading the corresponding [`.minisig`](https://github.com/minio/console/releases/latest) signature file. Then run:
```
minisign -Vm console-<OS>-<ARCH> -P RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav
```
### Docker
Pull the latest release via:
```
docker pull minio/console
```
### Build from source
```
GO111MODULE=on go get github.com/minio/console/cmd/console
```
> You will need a working Go environment. Therefore, please follow [How to install Go](https://golang.org/doc/install).
> Minimum version required is go1.16
## Setup
All `console` needs is a MinIO user with admin privileges and URL pointing to your MinIO deployment.
> Note: We don't recommend using MinIO's Operator Credentials
#### 1. Create a user `console` using `mc`
### 1. Create a user `console` using `mc`
```bash
mc admin user add myminio/
@@ -38,7 +74,7 @@ Enter Access Key: console
Enter Secret Key: xxxxxxxx
```
#### 2. Create a policy for `console` with admin access to all resources (for testing)
### 2. Create a policy for `console` with admin access to all resources (for testing)
```sh
cat > admin.json << EOF
@@ -70,7 +106,7 @@ EOF
mc admin policy add myminio/ consoleAdmin admin.json
```
#### 3. Set the policy for the new `console` user
### 3. Set the policy for the new `console` user
```sh
mc admin policy set myminio consoleAdmin user=console
@@ -173,7 +209,8 @@ Following tree structure is expected for supporting multiple domains:
## Connect Console to a Minio using TLS and a self-signed certificate
Copy the MinIO `ca.crt` under `~/.console/certs/CAs`, then:
```
```sh
export CONSOLE_MINIO_SERVER=https://localhost:9000
./console server
```

View File

@@ -18,13 +18,13 @@ 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
- Primary security coordinator: lenin@min.io
- Secondary coordinator: security@min.io
- If you receive no response: dev@min.io
### Disclosure Process
MinIO uses the following disclosure process:
MinIO Console 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.
@@ -33,8 +33,8 @@ MinIO uses the following disclosure process:
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.
Please inform us in your report email whether MinIO Console should mention your contribution w.r.t. fixing
the security issue. By default MinIO Console 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

38
VULNERABILITY_REPORT.md Normal file
View File

@@ -0,0 +1,38 @@
## Vulnerability Management Policy
This document formally describes the process of addressing and managing a
reported vulnerability that has been found in the MinIO Console server code base,
any directly connected ecosystem component or a direct / indirect dependency
of the code base.
### Scope
The vulnerability management policy described in this document covers the
process of investigating, assessing and resolving a vulnerability report
opened by a MinIO Console employee or an external third party.
Therefore, it lists pre-conditions and actions that should be performed to
resolve and fix a reported vulnerability.
### Vulnerability Management Process
The vulnerability management process requires that the vulnerability report
contains the following information:
- The project / component that contains the reported vulnerability.
- A description of the vulnerability. In particular, the type of the
reported vulnerability and how it might be exploited. Alternatively,
a well-established vulnerability identifier, e.g. CVE number, can be
used instead.
Based on the description mentioned above, a MinIO Console engineer or security team
member investigates:
- Whether the reported vulnerability exists.
- The conditions that are required such that the vulnerability can be exploited.
- The steps required to fix the vulnerability.
In general, if the vulnerability exists in one of the MinIO Console code bases
itself - not in a code dependency - then MinIO Console will, if possible, fix
the vulnerability or implement reasonable countermeasures such that the
vulnerability cannot be exploited anymore.

View File

@@ -17,6 +17,7 @@
package cluster
import (
direct "github.com/minio/direct-csi/pkg/clientset"
operator "github.com/minio/operator/pkg/client/clientset/versioned"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
@@ -63,3 +64,8 @@ func OperatorClient(token string) (*operator.Clientset, error) {
func K8sClient(token string) (*kubernetes.Clientset, error) {
return kubernetes.NewForConfig(GetK8sConfig(token))
}
// DirectCSIClient returns Direct CSI client using GetK8sConfig for its config
func DirectCSIClient(token string) (*direct.Clientset, error) {
return direct.NewForConfig(GetK8sConfig(token))
}

View File

@@ -54,6 +54,7 @@ VERSION:
var appCmds = []cli.Command{
serverCmd,
updateCmd,
}
func newApp(name string) *cli.App {

View File

@@ -18,9 +18,13 @@ package main
import (
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
"time"
"github.com/minio/minio/cmd/config"
"github.com/go-openapi/loads"
"github.com/jessevdk/go-flags"
@@ -57,11 +61,31 @@ var serverCmd = cli.Command{
Value: restapi.GetTLSPort(),
Usage: "HTTPS server port",
},
cli.StringFlag{
Name: "tls-redirect",
Value: restapi.GetTLSRedirect(),
Usage: "HTTPS redirect by default",
},
cli.StringFlag{
Name: "certs-dir",
Value: certs.GlobalCertsCADir.Get(),
Usage: "path to certs directory",
},
cli.StringFlag{
Name: "tls-certificate",
Value: "",
Usage: "path tls certificate",
},
cli.StringFlag{
Name: "tls-key",
Value: "",
Usage: "path tls key",
},
cli.StringFlag{
Name: "tls-ca",
Value: "",
Usage: "path tls ca",
},
},
}
@@ -116,6 +140,30 @@ func startServer(ctx *cli.Context) error {
// load the certificates and the CAs
restapi.GlobalRootCAs, restapi.GlobalPublicCerts, restapi.GlobalTLSCertsManager = certs.GetAllCertificatesAndCAs()
// TLS flags from swagger server, used to support older versions of minio-operator
swaggerServerCertificate := ctx.String("tls-certificate")
swaggerServerCertificateKey := ctx.String("tls-key")
SwaggerServerCACertificate := ctx.String("tls-ca")
// load tls cert and key from swagger server tls-certificate and tls-key flags
if swaggerServerCertificate != "" && swaggerServerCertificateKey != "" {
if errAddCert := restapi.GlobalTLSCertsManager.AddCertificate(swaggerServerCertificate, swaggerServerCertificateKey); errAddCert == nil {
if x509Certs, errParseCert := config.ParsePublicCertFile(swaggerServerCertificate); errParseCert == nil && len(x509Certs) > 0 {
restapi.GlobalPublicCerts = append(restapi.GlobalPublicCerts, x509Certs[0])
} else {
log.Println(errParseCert)
}
} else {
log.Println(errAddCert)
}
}
// load ca cert from swagger server tls-ca flag
if SwaggerServerCACertificate != "" {
caCert, caCertErr := ioutil.ReadFile(SwaggerServerCACertificate)
if caCertErr == nil {
restapi.GlobalRootCAs.AppendCertsFromPEM(caCert)
}
}
if len(restapi.GlobalPublicCerts) > 0 {
// If TLS certificates are provided enforce the HTTPS schema, meaning console will redirect
// plain HTTP connections to HTTPS server
@@ -125,11 +173,33 @@ func startServer(ctx *cli.Context) error {
// 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"
restapi.TLSRedirect = ctx.String("tls-redirect")
}
server.ConfigureAPI()
// subnet license refresh process
go func() {
failedAttempts := 0
for {
if err := restapi.RefreshLicense(); err != nil {
log.Println(err)
failedAttempts++
// end license refresh after 3 consecutive failed attempts
if failedAttempts >= 3 {
return
}
// wait 5 minutes and retry again
time.Sleep(time.Minute * 5)
continue
}
// if license refreshed successfully reset the counter
failedAttempts = 0
// try to refresh license every 24 hrs
time.Sleep(time.Hour * 24)
}
}()
if err := server.Serve(); err != nil {
log.Fatalln(err)
}

154
cmd/console/update.go Normal file
View File

@@ -0,0 +1,154 @@
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package main
import (
"encoding/json"
"errors"
"fmt"
"io"
"net"
"net/http"
"os"
"runtime"
"strings"
"time"
"github.com/blang/semver/v4"
"github.com/cheggaaa/pb/v3"
"github.com/minio/cli"
"github.com/minio/console/pkg"
"github.com/minio/selfupdate"
)
func getUpdateTransport(timeout time.Duration) http.RoundTripper {
var updateTransport http.RoundTripper = &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: timeout,
KeepAlive: timeout,
DualStack: true,
}).DialContext,
IdleConnTimeout: timeout,
TLSHandshakeTimeout: timeout,
ExpectContinueTimeout: timeout,
DisableCompression: true,
}
return updateTransport
}
func getUpdateReaderFromURL(u string, transport http.RoundTripper) (io.ReadCloser, int64, error) {
clnt := &http.Client{
Transport: transport,
}
req, err := http.NewRequest(http.MethodGet, u, nil)
if err != nil {
return nil, -1, err
}
resp, err := clnt.Do(req)
if err != nil {
return nil, -1, err
}
return resp.Body, resp.ContentLength, nil
}
const defaultPubKey = "RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav"
func getLatestRelease(tr http.RoundTripper) (string, error) {
releaseURL := "https://api.github.com/repos/minio/console/releases/latest"
body, _, err := getUpdateReaderFromURL(releaseURL, tr)
if err != nil {
return "", fmt.Errorf("unable to access github release URL %w", err)
}
defer body.Close()
lm := make(map[string]interface{})
if err = json.NewDecoder(body).Decode(&lm); err != nil {
return "", err
}
rel, ok := lm["tag_name"].(string)
if !ok {
return "", errors.New("unable to find latest release tag")
}
return rel, nil
}
// update console in-place
var updateCmd = cli.Command{
Name: "update",
Usage: "update console to latest release",
Action: updateInplace,
}
func updateInplace(ctx *cli.Context) error {
transport := getUpdateTransport(30 * time.Second)
rel, err := getLatestRelease(transport)
if err != nil {
return err
}
latest, err := semver.Make(strings.TrimPrefix(rel, "v"))
if err != nil {
return err
}
current, err := semver.Make(pkg.Version)
if err != nil {
return err
}
if current.GTE(latest) {
fmt.Printf("You are already running the latest version v%v.\n", pkg.Version)
return nil
}
consoleBin := fmt.Sprintf("https://github.com/minio/console/releases/download/%s/console-%s-%s", rel, runtime.GOOS, runtime.GOARCH)
reader, length, err := getUpdateReaderFromURL(consoleBin, transport)
if err != nil {
return fmt.Errorf("unable to fetch binary from %s: %w", consoleBin, err)
}
minisignPubkey := os.Getenv("CONSOLE_MINISIGN_PUBKEY")
if minisignPubkey == "" {
minisignPubkey = defaultPubKey
}
v := selfupdate.NewVerifier()
if err = v.LoadFromURL(consoleBin+".minisig", minisignPubkey, transport); err != nil {
return fmt.Errorf("unable to fetch binary signature for %s: %w", consoleBin, err)
}
opts := selfupdate.Options{
Verifier: v,
}
tmpl := `{{ red "Downloading:" }} {{bar . (red "[") (green "=") (red "]")}} {{speed . | rndcolor }}`
bar := pb.ProgressBarTemplate(tmpl).Start64(length)
barReader := bar.NewProxyReader(reader)
if err = selfupdate.Apply(barReader, opts); err != nil {
bar.Finish()
if rerr := selfupdate.RollbackError(err); rerr != nil {
return rerr
}
return err
}
bar.Finish()
fmt.Printf("Updated 'console' to latest release %s\n", rel)
return nil
}

61
compose/.env Normal file
View File

@@ -0,0 +1,61 @@
## PostgreSQL related variables
# Postgres Docker image
POSTGRES_IMAGE=library/postgres
# Postgres user
POSTGRES_USER=postgres
# Postgres password
POSTGRES_PASSWORD=magical_password
# Postgres port number
POSTGRES_PORT=5432
# Postgres data directory
PGDATA=/data/postgres
## Logsearch related variables
# Logsearch Docker image
LOGSEARCH_IMAGE=minio/logsearchapi:v4.0.2
# Logsearch storage max
LOGSEARCH_DISK_CAPACITY_GB=5
# Logsearch port number
LOGSEARCH_PORT=8080
# Log retention duration
LOGSEARCH_MAX_RETENTION_MONTHS=1
# Logsearch audit authentication token
LOGSEARCH_AUDIT_AUTH_TOKEN=c6rkqjZ03ElEUKQ7MtSeYBJ8q_p3GDFPBQAQJlcbBLA=
# Logsearch query authentication token
LOGSEARCH_QUERY_AUTH_TOKEN=c6rkqjZ03ElEUKQ7MtSeYBJ8q_p3GDFPBQAQJlcbBLA=
## Console related variables
# Console Docker image
CONSOLE_IMAGE=minio/console:v0.6.2
# Salt to encrypt JWT payload
CONSOLE_PBKDF_PASSPHRASE=top_secret
# Required to encrypt JWT payload
CONSOLE_PBKDF_SALT=top_secret1
# MinIO Server URL
CONSOLE_MINIO_SERVER=http://localhost:9000
## Prometheus related variables
# Prometheus Docker image
PROMETHEUS_IMAGE=prom/prometheus:latest
# Prometheus port number
PROMETHEUS_PORT=9999

64
compose/README.md Normal file
View File

@@ -0,0 +1,64 @@
## Console Docker Compose
This compose file allows users to quickly deploy MinIO Console, LogSearch & Prometheus in a baremetal (non Kubernetes) environment.
### Pre-requisites
1. [MinIO](https://docs.minio.io/docs/distributed-minio-quickstart-guide.html) cluster up and running.
2. [mc](https://docs.minio.io/docs/minio-client-quickstart-guide.html) configured for this MinIO cluster.
3. [Docker-Compose](https://docs.docker.com/compose/) installed on the server.
### Getting Started
- Download the contents of `compose` directory on your machine.
- Edit the `prometheus.yaml` file and fill in the correct target (MinIO Endpoint). Optionally setup the `bearer_token` as explained [here](https://github.com/minio/minio/tree/master/docs/metrics/prometheus#31-authenticated-prometheus-config).
- Setup a console admin policy.
```sh
cat > admin.json << EOF
{
"Version": "2012-10-17",
"Statement": [{
"Action": [
"admin:*"
],
"Effect": "Allow",
"Sid": ""
},
{
"Action": [
"s3:*"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::*"
],
"Sid": ""
}
]
}
EOF
```
Then create this policy on MinIO server: `mc admin policy add myminio consoleAdmin admin.json`.
- Setup user and policy for Console
```
mc admin user add myminio console console123
mc admin policy set myminio consoleAdmin user=console
```
- Configure Webhook target on the MinIO server. Remember to change the `token` value in below URL to the actual token value as set in the `.env` file.
```
mc admin config set myminio audit_webhook:1 endpoint=http://localhost:8080/api/ingest?token=c6rkqjZ03ElEUKQ7MtSeYBJ8q_p3GDFPBQAQJlcbBLA=
mc admin service restart myminio
```
### Configuration
To configure the Console Compose file to custom setup, please take a look at the [`.env`](./.env) file.

View File

@@ -0,0 +1,62 @@
version: '3.4'
services:
pg_database:
image: ${POSTGRES_IMAGE}
network_mode: host
environment:
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- PGDATA=${PGDATA}
- POSTGRES_DB=minio_logs
volumes:
- database:${PGDATA}
ports:
- ${POSTGRES_PORT}:${POSTGRES_PORT}
log_search:
image: ${LOGSEARCH_IMAGE}
network_mode: host
environment:
- LOGSEARCH_AUDIT_AUTH_TOKEN=${LOGSEARCH_AUDIT_AUTH_TOKEN}
- LOGSEARCH_QUERY_AUTH_TOKEN=${LOGSEARCH_QUERY_AUTH_TOKEN}
- LOGSEARCH_DISK_CAPACITY_GB=${LOGSEARCH_DISK_CAPACITY_GB}
- LOGSEARCH_MAX_RETENTION_MONTHS=${LOGSEARCH_MAX_RETENTION_MONTHS}
- LOGSEARCH_PG_CONN_STR=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:${POSTGRES_PORT}/minio_logs?sslmode=disable
ports:
- ${LOGSEARCH_PORT}:${LOGSEARCH_PORT}
command: ["/usr/bin/wait-for-it.sh", "localhost:${POSTGRES_PORT}", "--", "/logsearchapi"]
volumes:
- ./wait-for-it.sh:/usr/bin/wait-for-it.sh
depends_on:
- pg_database
console:
image: ${CONSOLE_IMAGE}
network_mode: host
environment:
- CONSOLE_PBKDF_PASSPHRASE=${CONSOLE_PBKDF_PASSPHRASE}
- CONSOLE_PBKDF_SALT=${CONSOLE_PBKDF_SALT}
- LOGSEARCH_QUERY_AUTH_TOKEN=${LOGSEARCH_QUERY_AUTH_TOKEN}
- CONSOLE_MINIO_SERVER=${CONSOLE_MINIO_SERVER}
- CONSOLE_LOG_QUERY_URL=http://localhost:${LOGSEARCH_PORT}
- CONSOLE_PROMETHEUS_URL=http://localhost:${PROMETHEUS_PORT}
ports:
- "9090:9090"
command: server
depends_on:
- log_search
- prometheus
prometheus:
image: ${PROMETHEUS_IMAGE}
network_mode: host
ports:
- ${PROMETHEUS_PORT}:${PROMETHEUS_PORT}
command:
- --config.file=/etc/prometheus/prometheus.yml
- --web.listen-address=:${PROMETHEUS_PORT}
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
volumes:
database:

15
compose/prometheus.yml Normal file
View File

@@ -0,0 +1,15 @@
global:
scrape_interval: 10s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
evaluation_interval: 30s # Evaluate rules every 15 seconds. The default is every 1 minute.
# scrape_timeout is set to the global default (10s).
# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
# The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
- job_name: minio-node1
metrics_path: /minio/v2/metrics/cluster
scheme: http
static_configs:
- targets:
- 'localhost:9000'

182
compose/wait-for-it.sh Executable file
View File

@@ -0,0 +1,182 @@
#!/usr/bin/env bash
# Use this script to test if a given TCP host/port are available
WAITFORIT_cmdname=${0##*/}
echoerr() { if [[ $WAITFORIT_QUIET -ne 1 ]]; then echo "$@" 1>&2; fi }
usage()
{
cat << USAGE >&2
Usage:
$WAITFORIT_cmdname host:port [-s] [-t timeout] [-- command args]
-h HOST | --host=HOST Host or IP under test
-p PORT | --port=PORT TCP port under test
Alternatively, you specify the host and port as host:port
-s | --strict Only execute subcommand if the test succeeds
-q | --quiet Don't output any status messages
-t TIMEOUT | --timeout=TIMEOUT
Timeout in seconds, zero for no timeout
-- COMMAND ARGS Execute command with args after the test finishes
USAGE
exit 1
}
wait_for()
{
if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then
echoerr "$WAITFORIT_cmdname: waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
else
echoerr "$WAITFORIT_cmdname: waiting for $WAITFORIT_HOST:$WAITFORIT_PORT without a timeout"
fi
WAITFORIT_start_ts=$(date +%s)
while :
do
if [[ $WAITFORIT_ISBUSY -eq 1 ]]; then
nc -z $WAITFORIT_HOST $WAITFORIT_PORT
WAITFORIT_result=$?
else
(echo -n > /dev/tcp/$WAITFORIT_HOST/$WAITFORIT_PORT) >/dev/null 2>&1
WAITFORIT_result=$?
fi
if [[ $WAITFORIT_result -eq 0 ]]; then
WAITFORIT_end_ts=$(date +%s)
echoerr "$WAITFORIT_cmdname: $WAITFORIT_HOST:$WAITFORIT_PORT is available after $((WAITFORIT_end_ts - WAITFORIT_start_ts)) seconds"
break
fi
sleep 1
done
return $WAITFORIT_result
}
wait_for_wrapper()
{
# In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692
if [[ $WAITFORIT_QUIET -eq 1 ]]; then
timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --quiet --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
else
timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
fi
WAITFORIT_PID=$!
trap "kill -INT -$WAITFORIT_PID" INT
wait $WAITFORIT_PID
WAITFORIT_RESULT=$?
if [[ $WAITFORIT_RESULT -ne 0 ]]; then
echoerr "$WAITFORIT_cmdname: timeout occurred after waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
fi
return $WAITFORIT_RESULT
}
# process arguments
while [[ $# -gt 0 ]]
do
case "$1" in
*:* )
WAITFORIT_hostport=(${1//:/ })
WAITFORIT_HOST=${WAITFORIT_hostport[0]}
WAITFORIT_PORT=${WAITFORIT_hostport[1]}
shift 1
;;
--child)
WAITFORIT_CHILD=1
shift 1
;;
-q | --quiet)
WAITFORIT_QUIET=1
shift 1
;;
-s | --strict)
WAITFORIT_STRICT=1
shift 1
;;
-h)
WAITFORIT_HOST="$2"
if [[ $WAITFORIT_HOST == "" ]]; then break; fi
shift 2
;;
--host=*)
WAITFORIT_HOST="${1#*=}"
shift 1
;;
-p)
WAITFORIT_PORT="$2"
if [[ $WAITFORIT_PORT == "" ]]; then break; fi
shift 2
;;
--port=*)
WAITFORIT_PORT="${1#*=}"
shift 1
;;
-t)
WAITFORIT_TIMEOUT="$2"
if [[ $WAITFORIT_TIMEOUT == "" ]]; then break; fi
shift 2
;;
--timeout=*)
WAITFORIT_TIMEOUT="${1#*=}"
shift 1
;;
--)
shift
WAITFORIT_CLI=("$@")
break
;;
--help)
usage
;;
*)
echoerr "Unknown argument: $1"
usage
;;
esac
done
if [[ "$WAITFORIT_HOST" == "" || "$WAITFORIT_PORT" == "" ]]; then
echoerr "Error: you need to provide a host and port to test."
usage
fi
WAITFORIT_TIMEOUT=${WAITFORIT_TIMEOUT:-15}
WAITFORIT_STRICT=${WAITFORIT_STRICT:-0}
WAITFORIT_CHILD=${WAITFORIT_CHILD:-0}
WAITFORIT_QUIET=${WAITFORIT_QUIET:-0}
# Check to see if timeout is from busybox?
WAITFORIT_TIMEOUT_PATH=$(type -p timeout)
WAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH)
WAITFORIT_BUSYTIMEFLAG=""
if [[ $WAITFORIT_TIMEOUT_PATH =~ "busybox" ]]; then
WAITFORIT_ISBUSY=1
# Check if busybox timeout uses -t flag
# (recent Alpine versions don't support -t anymore)
if timeout &>/dev/stdout | grep -q -e '-t '; then
WAITFORIT_BUSYTIMEFLAG="-t"
fi
else
WAITFORIT_ISBUSY=0
fi
if [[ $WAITFORIT_CHILD -gt 0 ]]; then
wait_for
WAITFORIT_RESULT=$?
exit $WAITFORIT_RESULT
else
if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then
wait_for_wrapper
WAITFORIT_RESULT=$?
else
wait_for
WAITFORIT_RESULT=$?
fi
fi
if [[ $WAITFORIT_CLI != "" ]]; then
if [[ $WAITFORIT_RESULT -ne 0 && $WAITFORIT_STRICT -eq 1 ]]; then
echoerr "$WAITFORIT_cmdname: strict mode, refusing to execute subprocess"
exit $WAITFORIT_RESULT
fi
exec "${WAITFORIT_CLI[@]}"
else
exit $WAITFORIT_RESULT
fi

27
go.mod
View File

@@ -1,10 +1,11 @@
module github.com/minio/console
go 1.15
go 1.16
require (
github.com/blang/semver/v4 v4.0.0
github.com/cheggaaa/pb/v3 v3.0.6
github.com/coreos/go-oidc v2.2.1+incompatible
github.com/elazarl/go-bindata-assetfs v1.0.0
github.com/go-openapi/errors v0.19.6
github.com/go-openapi/loads v0.19.5
github.com/go-openapi/runtime v0.19.19
@@ -15,24 +16,24 @@ require (
github.com/gorilla/websocket v1.4.2
github.com/jessevdk/go-flags v1.4.0
github.com/minio/cli v1.22.0
github.com/minio/direct-csi v1.2.8
github.com/minio/kes v0.11.0
github.com/minio/mc v0.0.0-20201220181029-41c804b179de
github.com/minio/minio v0.0.0-20201221162327-6df6ac0f3410
github.com/minio/minio-go/v7 v7.0.7-0.20201217170524-3baf9ea06f7c
github.com/minio/operator v0.0.0-20201204220226-9901d1d0766c
github.com/minio/operator/logsearchapi v0.0.0-20201217190212-bf6546b09012
github.com/minio/mc v0.0.0-20210301162250-f9d36f9b5243
github.com/minio/minio v0.0.0-20210301203133-e8d8dfa3ae8f
github.com/minio/minio-go/v7 v7.0.10
github.com/minio/operator v0.0.0-20210317030027-207337abe7fd
github.com/minio/operator/logsearchapi v0.0.0-20210201110528-753019b838b4
github.com/minio/selfupdate v0.3.1
github.com/mitchellh/go-homedir v1.1.0
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
github.com/secure-io/sio-go v0.3.1
github.com/stretchr/testify v1.6.1
github.com/unrolled/secure v1.0.7
golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb
golang.org/x/net v0.0.0-20201216054612-986b41b23924
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
gopkg.in/yaml.v2 v2.3.0
k8s.io/api v0.18.6
k8s.io/apimachinery v0.18.8
k8s.io/client-go v0.18.6
k8s.io/api v0.20.2
k8s.io/apimachinery v0.20.2
k8s.io/client-go v0.20.2
)
replace github.com/minio/operator v0.0.0-20201204220226-9901d1d0766c => github.com/dvaldivia/operator v0.0.0-20201230052356-04efc0ea5890

407
go.sum

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

After

Width:  |  Height:  |  Size: 1.7 MiB

View File

@@ -3,20 +3,6 @@ kind: ClusterRole
metadata:
name: console-sa-role
rules:
- apiGroups:
- ""
resources:
- namespaces
- pods
- services
- events
- resourcequotas
verbs:
- get
- watch
- create
- list
- patch
- apiGroups:
- ""
resources:
@@ -27,8 +13,33 @@ rules:
- create
- list
- patch
- update
- deletecollection
- delete
- apiGroups:
- ""
resources:
- namespaces
- pods
- services
- events
- resourcequotas
- nodes
verbs:
- get
- watch
- create
- list
- patch
- apiGroups:
- ""
resources:
- persistentvolumeclaims
verbs:
- deletecollection
- list
- get
- watch
- update
- apiGroups:
- "storage.k8s.io"
resources:
@@ -86,3 +97,126 @@ rules:
- "*"
verbs:
- "*"
- apiGroups:
- ""
resources:
- persistentvolumes
verbs:
- get
- list
- watch
- create
- delete
- apiGroups:
- ""
resources:
- persistentvolumeclaims
verbs:
- get
- list
- watch
- update
- apiGroups:
- ""
resources:
- events
verbs:
- create
- list
- watch
- update
- patch
- apiGroups:
- snapshot.storage.k8s.io
resources:
- volumesnapshots
verbs:
- get
- list
- apiGroups:
- snapshot.storage.k8s.io
resources:
- volumesnapshotcontents
verbs:
- get
- list
- apiGroups:
- storage.k8s.io
resources:
- csinodes
verbs:
- get
- list
- watch
- apiGroups:
- storage.k8s.io
resources:
- volumeattachments
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- endpoints
verbs:
- get
- list
- watch
- create
- update
- delete
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- get
- list
- watch
- create
- update
- delete
- apiGroups:
- direct.csi.min.io
resources:
- volumes
verbs:
- get
- list
- watch
- create
- update
- delete
- apiGroups:
- apiextensions.k8s.io
resources:
- customresourcedefinitions
verbs:
- get
- list
- watch
- create
- update
- delete
- apiGroups:
- direct.csi.min.io
resources:
- directcsidrives
- directcsivolumes
verbs:
- get
- list
- watch
- create
- update
- delete
- apiGroups:
- ""
resources:
- pod
verbs:
- get
- list
- watch

View File

@@ -15,7 +15,7 @@ spec:
serviceAccountName: console-sa
containers:
- name: console
image: minio/console:v0.5.2
image: minio/console:v0.6.5
imagePullPolicy: "IfNotPresent"
args:
- server

View File

@@ -38,6 +38,8 @@ rules:
- deletecollection
- list
- get
- watch
- update
- apiGroups:
- "storage.k8s.io"
resources:
@@ -95,3 +97,126 @@ rules:
- "*"
verbs:
- "*"
- apiGroups:
- ""
resources:
- persistentvolumes
verbs:
- get
- list
- watch
- create
- delete
- apiGroups:
- ""
resources:
- persistentvolumeclaims
verbs:
- get
- list
- watch
- update
- apiGroups:
- ""
resources:
- events
verbs:
- create
- list
- watch
- update
- patch
- apiGroups:
- snapshot.storage.k8s.io
resources:
- volumesnapshots
verbs:
- get
- list
- apiGroups:
- snapshot.storage.k8s.io
resources:
- volumesnapshotcontents
verbs:
- get
- list
- apiGroups:
- storage.k8s.io
resources:
- csinodes
verbs:
- get
- list
- watch
- apiGroups:
- storage.k8s.io
resources:
- volumeattachments
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- endpoints
verbs:
- get
- list
- watch
- create
- update
- delete
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- get
- list
- watch
- create
- update
- delete
- apiGroups:
- direct.csi.min.io
resources:
- volumes
verbs:
- get
- list
- watch
- create
- update
- delete
- apiGroups:
- apiextensions.k8s.io
resources:
- customresourcedefinitions
verbs:
- get
- list
- watch
- create
- update
- delete
- apiGroups:
- direct.csi.min.io
resources:
- directcsidrives
- directcsivolumes
verbs:
- get
- list
- watch
- create
- update
- delete
- apiGroups:
- ""
resources:
- pod
verbs:
- get
- list
- watch

View File

@@ -15,7 +15,7 @@ spec:
serviceAccountName: console-sa
containers:
- name: console
image: minio/console:v0.5.2
image: minio/console:v0.6.5
imagePullPolicy: "IfNotPresent"
env:
- name: CONSOLE_OPERATOR_MODE

View File

@@ -0,0 +1,60 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package 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"
)
// BucketObLockingResponse bucket ob locking response
//
// swagger:model bucketObLockingResponse
type BucketObLockingResponse struct {
// object locking enabled
ObjectLockingEnabled bool `json:"object_locking_enabled,omitempty"`
}
// Validate validates this bucket ob locking response
func (m *BucketObLockingResponse) Validate(formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *BucketObLockingResponse) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *BucketObLockingResponse) UnmarshalBinary(b []byte) error {
var res BucketObLockingResponse
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -0,0 +1,78 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package 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"
)
// DirectCSIDriveInfo direct c s i drive info
//
// swagger:model directCSIDriveInfo
type DirectCSIDriveInfo struct {
// allocated
Allocated int64 `json:"allocated,omitempty"`
// capacity
Capacity int64 `json:"capacity,omitempty"`
// drive
Drive string `json:"drive,omitempty"`
// message
Message string `json:"message,omitempty"`
// node
Node string `json:"node,omitempty"`
// status
Status string `json:"status,omitempty"`
// volumes
Volumes int64 `json:"volumes,omitempty"`
}
// Validate validates this direct c s i drive info
func (m *DirectCSIDriveInfo) Validate(formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *DirectCSIDriveInfo) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *DirectCSIDriveInfo) UnmarshalBinary(b []byte) error {
var res DirectCSIDriveInfo
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -0,0 +1,69 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package 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"
)
// DirectCSIVolumeInfo direct c s i volume info
//
// swagger:model directCSIVolumeInfo
type DirectCSIVolumeInfo struct {
// capacity
Capacity int64 `json:"capacity,omitempty"`
// drive
Drive string `json:"drive,omitempty"`
// node
Node string `json:"node,omitempty"`
// volume
Volume string `json:"volume,omitempty"`
}
// Validate validates this direct c s i volume info
func (m *DirectCSIVolumeInfo) Validate(formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *DirectCSIVolumeInfo) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *DirectCSIVolumeInfo) UnmarshalBinary(b []byte) error {
var res DirectCSIVolumeInfo
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -40,6 +40,9 @@ type EncryptionConfiguration struct {
// client
Client *KeyPairConfiguration `json:"client,omitempty"`
// gcp
Gcp *GcpConfiguration `json:"gcp,omitempty"`
// gemalto
Gemalto *GemaltoConfiguration `json:"gemalto,omitempty"`
@@ -68,6 +71,8 @@ func (m *EncryptionConfiguration) UnmarshalJSON(raw []byte) error {
Client *KeyPairConfiguration `json:"client,omitempty"`
Gcp *GcpConfiguration `json:"gcp,omitempty"`
Gemalto *GemaltoConfiguration `json:"gemalto,omitempty"`
Image string `json:"image,omitempty"`
@@ -84,6 +89,8 @@ func (m *EncryptionConfiguration) UnmarshalJSON(raw []byte) error {
m.Client = dataAO1.Client
m.Gcp = dataAO1.Gcp
m.Gemalto = dataAO1.Gemalto
m.Image = dataAO1.Image
@@ -109,6 +116,8 @@ func (m EncryptionConfiguration) MarshalJSON() ([]byte, error) {
Client *KeyPairConfiguration `json:"client,omitempty"`
Gcp *GcpConfiguration `json:"gcp,omitempty"`
Gemalto *GemaltoConfiguration `json:"gemalto,omitempty"`
Image string `json:"image,omitempty"`
@@ -122,6 +131,8 @@ func (m EncryptionConfiguration) MarshalJSON() ([]byte, error) {
dataAO1.Client = m.Client
dataAO1.Gcp = m.Gcp
dataAO1.Gemalto = m.Gemalto
dataAO1.Image = m.Image
@@ -155,6 +166,10 @@ func (m *EncryptionConfiguration) Validate(formats strfmt.Registry) error {
res = append(res, err)
}
if err := m.validateGcp(formats); err != nil {
res = append(res, err)
}
if err := m.validateGemalto(formats); err != nil {
res = append(res, err)
}
@@ -209,6 +224,24 @@ func (m *EncryptionConfiguration) validateClient(formats strfmt.Registry) error
return nil
}
func (m *EncryptionConfiguration) validateGcp(formats strfmt.Registry) error {
if swag.IsZero(m.Gcp) { // not required
return nil
}
if m.Gcp != nil {
if err := m.Gcp.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("gcp")
}
return err
}
}
return nil
}
func (m *EncryptionConfiguration) validateGemalto(formats strfmt.Registry) error {
if swag.IsZero(m.Gemalto) { // not required

210
models/gcp_configuration.go Normal file
View File

@@ -0,0 +1,210 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package 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"
)
// GcpConfiguration gcp configuration
//
// swagger:model gcpConfiguration
type GcpConfiguration struct {
// secretmanager
// Required: true
Secretmanager *GcpConfigurationSecretmanager `json:"secretmanager"`
}
// Validate validates this gcp configuration
func (m *GcpConfiguration) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateSecretmanager(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *GcpConfiguration) validateSecretmanager(formats strfmt.Registry) error {
if err := validate.Required("secretmanager", "body", m.Secretmanager); err != nil {
return err
}
if m.Secretmanager != nil {
if err := m.Secretmanager.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("secretmanager")
}
return err
}
}
return nil
}
// MarshalBinary interface implementation
func (m *GcpConfiguration) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *GcpConfiguration) UnmarshalBinary(b []byte) error {
var res GcpConfiguration
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}
// GcpConfigurationSecretmanager gcp configuration secretmanager
//
// swagger:model GcpConfigurationSecretmanager
type GcpConfigurationSecretmanager struct {
// credentials
Credentials *GcpConfigurationSecretmanagerCredentials `json:"credentials,omitempty"`
// endpoint
Endpoint string `json:"endpoint,omitempty"`
// project id
// Required: true
ProjectID *string `json:"project_id"`
}
// Validate validates this gcp configuration secretmanager
func (m *GcpConfigurationSecretmanager) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateCredentials(formats); err != nil {
res = append(res, err)
}
if err := m.validateProjectID(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *GcpConfigurationSecretmanager) validateCredentials(formats strfmt.Registry) error {
if swag.IsZero(m.Credentials) { // not required
return nil
}
if m.Credentials != nil {
if err := m.Credentials.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("secretmanager" + "." + "credentials")
}
return err
}
}
return nil
}
func (m *GcpConfigurationSecretmanager) validateProjectID(formats strfmt.Registry) error {
if err := validate.Required("secretmanager"+"."+"project_id", "body", m.ProjectID); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *GcpConfigurationSecretmanager) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *GcpConfigurationSecretmanager) UnmarshalBinary(b []byte) error {
var res GcpConfigurationSecretmanager
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}
// GcpConfigurationSecretmanagerCredentials gcp configuration secretmanager credentials
//
// swagger:model GcpConfigurationSecretmanagerCredentials
type GcpConfigurationSecretmanagerCredentials struct {
// client email
ClientEmail string `json:"client_email,omitempty"`
// client id
ClientID string `json:"client_id,omitempty"`
// private key
PrivateKey string `json:"private_key,omitempty"`
// private key id
PrivateKeyID string `json:"private_key_id,omitempty"`
}
// Validate validates this gcp configuration secretmanager credentials
func (m *GcpConfigurationSecretmanagerCredentials) Validate(formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *GcpConfigurationSecretmanagerCredentials) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *GcpConfigurationSecretmanagerCredentials) UnmarshalBinary(b []byte) error {
var res GcpConfigurationSecretmanagerCredentials
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -0,0 +1,97 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package 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"
)
// GetDirectCSIDriveListResponse get direct c s i drive list response
//
// swagger:model getDirectCSIDriveListResponse
type GetDirectCSIDriveListResponse struct {
// drives
Drives []*DirectCSIDriveInfo `json:"drives"`
}
// Validate validates this get direct c s i drive list response
func (m *GetDirectCSIDriveListResponse) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateDrives(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *GetDirectCSIDriveListResponse) validateDrives(formats strfmt.Registry) error {
if swag.IsZero(m.Drives) { // not required
return nil
}
for i := 0; i < len(m.Drives); i++ {
if swag.IsZero(m.Drives[i]) { // not required
continue
}
if m.Drives[i] != nil {
if err := m.Drives[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("drives" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
// MarshalBinary interface implementation
func (m *GetDirectCSIDriveListResponse) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *GetDirectCSIDriveListResponse) UnmarshalBinary(b []byte) error {
var res GetDirectCSIDriveListResponse
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -0,0 +1,97 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package 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"
)
// GetDirectCSIVolumeListResponse get direct c s i volume list response
//
// swagger:model getDirectCSIVolumeListResponse
type GetDirectCSIVolumeListResponse struct {
// volumes
Volumes []*DirectCSIVolumeInfo `json:"volumes"`
}
// Validate validates this get direct c s i volume list response
func (m *GetDirectCSIVolumeListResponse) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateVolumes(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *GetDirectCSIVolumeListResponse) validateVolumes(formats strfmt.Registry) error {
if swag.IsZero(m.Volumes) { // not required
return nil
}
for i := 0; i < len(m.Volumes); i++ {
if swag.IsZero(m.Volumes[i]) { // not required
continue
}
if m.Volumes[i] != nil {
if err := m.Volumes[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("volumes" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
// MarshalBinary interface implementation
func (m *GetDirectCSIVolumeListResponse) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *GetDirectCSIVolumeListResponse) UnmarshalBinary(b []byte) error {
var res GetDirectCSIVolumeListResponse
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -0,0 +1,97 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package 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"
)
// HasPermissionRequest has permission request
//
// swagger:model hasPermissionRequest
type HasPermissionRequest struct {
// actions
Actions []*PolicyArgs `json:"actions"`
}
// Validate validates this has permission request
func (m *HasPermissionRequest) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateActions(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *HasPermissionRequest) validateActions(formats strfmt.Registry) error {
if swag.IsZero(m.Actions) { // not required
return nil
}
for i := 0; i < len(m.Actions); i++ {
if swag.IsZero(m.Actions[i]) { // not required
continue
}
if m.Actions[i] != nil {
if err := m.Actions[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("actions" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
// MarshalBinary interface implementation
func (m *HasPermissionRequest) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *HasPermissionRequest) UnmarshalBinary(b []byte) error {
var res HasPermissionRequest
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -0,0 +1,97 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package 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"
)
// HasPermissionResponse has permission response
//
// swagger:model hasPermissionResponse
type HasPermissionResponse struct {
// permissions
Permissions []*PermissionAction `json:"permissions"`
}
// Validate validates this has permission response
func (m *HasPermissionResponse) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validatePermissions(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *HasPermissionResponse) validatePermissions(formats strfmt.Registry) error {
if swag.IsZero(m.Permissions) { // not required
return nil
}
for i := 0; i < len(m.Permissions); i++ {
if swag.IsZero(m.Permissions[i]) { // not required
continue
}
if m.Permissions[i] != nil {
if err := m.Permissions[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("permissions" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
// MarshalBinary interface implementation
func (m *HasPermissionResponse) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *HasPermissionResponse) UnmarshalBinary(b []byte) error {
var res HasPermissionResponse
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -34,6 +34,9 @@ import (
// swagger:model makeBucketRequest
type MakeBucketRequest struct {
// locking
Locking bool `json:"locking,omitempty"`
// name
// Required: true
Name *string `json:"name"`

View File

@@ -0,0 +1,63 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package 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"
)
// PermissionAction permission action
//
// swagger:model permissionAction
type PermissionAction struct {
// can
Can bool `json:"can,omitempty"`
// id
ID string `json:"id,omitempty"`
}
// Validate validates this permission action
func (m *PermissionAction) Validate(formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *PermissionAction) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *PermissionAction) UnmarshalBinary(b []byte) error {
var res PermissionAction
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

66
models/policy_args.go Normal file
View File

@@ -0,0 +1,66 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package 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"
)
// PolicyArgs policy args
//
// swagger:model policyArgs
type PolicyArgs struct {
// action
Action string `json:"action,omitempty"`
// bucket name
BucketName string `json:"bucket_name,omitempty"`
// id
ID string `json:"id,omitempty"`
}
// Validate validates this policy args
func (m *PolicyArgs) Validate(formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *PolicyArgs) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *PolicyArgs) UnmarshalBinary(b []byte) error {
var res PolicyArgs
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -44,9 +44,6 @@ type Principal struct {
// account access key
AccountAccessKey string `json:"accountAccessKey,omitempty"`
// account secret key
AccountSecretKey string `json:"accountSecretKey,omitempty"`
// actions
Actions []string `json:"actions"`
}

View File

@@ -35,6 +35,9 @@ import (
// swagger:model tlsConfiguration
type TLSConfiguration struct {
// ca certificates
CaCertificates []string `json:"ca_certificates"`
// console
Console *KeyPairConfiguration `json:"console,omitempty"`

View File

@@ -26,3 +26,7 @@ import (
func GetOperatorMode() bool {
return strings.ToLower(env.Get(consoleOperatorMode, "off")) == "on"
}
func GetLDAPEnabled() bool {
return strings.ToLower(env.Get(ConsoleLDAPEnabled, "off")) == "on"
}

View File

@@ -18,4 +18,6 @@ package acl
const (
consoleOperatorMode = "CONSOLE_OPERATOR_MODE"
// const for ldap configuration
ConsoleLDAPEnabled = "CONSOLE_LDAP_ENABLED"
)

View File

@@ -31,6 +31,7 @@ var (
buckets = "/buckets"
bucketsDetail = "/buckets/:bucketName"
serviceAccounts = "/account"
changePassword = "/account/change-password"
tenants = "/tenants"
tenantsDetail = "/namespaces/:tenantNamespace/tenants/:tenantName"
remoteBuckets = "/remote-buckets"
@@ -156,6 +157,16 @@ var serviceAccountsActionSet = ConfigurationActionSet{
actions: iampolicy.NewActionSet(),
}
// changePasswordActionSet requires admin:CreateUser policy permission
var changePasswordActionSet = ConfigurationActionSet{
actionTypes: iampolicy.NewActionSet(
iampolicy.AllAdminActions,
),
actions: iampolicy.NewActionSet(
iampolicy.CreateUserAdminAction,
),
}
// tenantsActionSet temporally no actions needed for tenants sections to work
var tenantsActionSet = ConfigurationActionSet{
actionTypes: iampolicy.NewActionSet(),
@@ -242,6 +253,17 @@ var healthInfoActionSet = ConfigurationActionSet{
),
}
var displayRules = map[string]func() bool{
// disable users page if LDAP is enabled
users: func() bool {
return !GetLDAPEnabled()
},
// disable groups page if LDAP is enabled
groups: func() bool {
return !GetLDAPEnabled()
},
}
// endpointRules contains the mapping between endpoints and ActionSets, additional rules can be added here
var endpointRules = map[string]ConfigurationActionSet{
configuration: configurationActionSet,
@@ -253,6 +275,7 @@ var endpointRules = map[string]ConfigurationActionSet{
buckets: bucketsActionSet,
bucketsDetail: bucketsActionSet,
serviceAccounts: serviceAccountsActionSet,
changePassword: changePasswordActionSet,
remoteBuckets: remoteBucketsActionSet,
replication: replicationActionSet,
objectBrowser: objectBrowserActionSet,
@@ -335,6 +358,15 @@ func GetAuthorizedEndpoints(actions []string) []string {
userAllowedAction := actionsStringToActionSet(actions)
var allowedEndpoints []string
for endpoint, rules := range rangeTake {
// check if display rule exists for this endpoint, this will control
// what user sees on the console UI
if rule, ok := displayRules[endpoint]; ok {
if rule != nil && !rule() {
continue
}
}
// check if user policy matches s3:* or admin:* typesIntersection
endpointActionTypes := rules.actionTypes
typesIntersection := endpointActionTypes.Intersection(userAllowedAction)

View File

@@ -72,7 +72,7 @@ func TestGetAuthorizedEndpoints(t *testing.T) {
"admin:*",
},
},
want: 18,
want: 19,
},
{
name: "all s3 endpoints",
@@ -91,7 +91,7 @@ func TestGetAuthorizedEndpoints(t *testing.T) {
"s3:*",
},
},
want: 20,
want: 21,
},
{
name: "Console User - default endpoints",

View File

@@ -91,9 +91,10 @@ type Provider struct {
// 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
ClientID string
oauth2Config Configuration
oidcProvider *oidc.Provider
provHTTPClient *http.Client
}
// derivedKey is the key used to compute the HMAC for signing the oauth state parameter
@@ -103,8 +104,9 @@ var derivedKey = pbkdf2.Key([]byte(getPassphraseForIdpHmac()), []byte(getSaltFor
// 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())
func NewOauth2ProviderClient(ctx context.Context, scopes []string, httpClient *http.Client) (*Provider, error) {
customCtx := oidc.ClientContext(ctx, httpClient)
provider, err := oidc.NewProvider(customCtx, GetIdpURL())
if err != nil {
return nil, err
}
@@ -122,6 +124,7 @@ func NewOauth2ProviderClient(ctx context.Context, scopes []string) (*Provider, e
}
client.oidcProvider = provider
client.ClientID = GetIdpClientID()
client.provHTTPClient = httpClient
return client, nil
}
@@ -172,10 +175,11 @@ func (client *Provider) VerifyIdentity(ctx context.Context, code, state string)
}, nil
}
stsEndpoint := GetSTSEndpoint()
sts, err := credentials.NewSTSWebIdentity(stsEndpoint, getWebTokenExpiry)
if err != nil {
return nil, err
}
sts := credentials.New(&credentials.STSWebIdentity{
Client: client.provHTTPClient,
STSEndpoint: stsEndpoint,
GetWebIDTokenExpiry: getWebTokenExpiry,
})
return sts, nil
}

View File

@@ -65,7 +65,6 @@ type TokenClaims struct {
STSSecretAccessKey string `json:"stsSecretAccessKey,omitempty"`
STSSessionToken string `json:"stsSessionToken,omitempty"`
AccountAccessKey string `json:"accountAccessKey,omitempty"`
AccountSecretKey string `json:"accountSecretKey,omitempty"`
Actions []string `json:"actions,omitempty"`
}
@@ -79,7 +78,6 @@ type TokenClaims struct {
// STSSecretAccessKey
// STSSessionToken
// AccountAccessKey
// AccountSecretKey
// Actions
// }
func SessionTokenAuthenticate(token string) (*TokenClaims, error) {
@@ -100,14 +98,13 @@ func SessionTokenAuthenticate(token string) (*TokenClaims, error) {
// NewEncryptedTokenForClient generates a new session token with claims based on the provided STS credentials, first
// encrypts the claims and the sign them
func NewEncryptedTokenForClient(credentials *credentials.Value, accountAccessKey, accountSecretKey string, actions []string) (string, error) {
func NewEncryptedTokenForClient(credentials *credentials.Value, accountAccessKey string, actions []string) (string, error) {
if credentials != nil {
encryptedClaims, err := encryptClaims(&TokenClaims{
STSAccessKeyID: credentials.AccessKeyID,
STSSecretAccessKey: credentials.SecretAccessKey,
STSSessionToken: credentials.SessionToken,
AccountAccessKey: accountAccessKey,
AccountSecretKey: accountSecretKey,
Actions: actions,
})
if err != nil {
@@ -330,6 +327,5 @@ func GetClaimsFromTokenInRequest(req *http.Request) (*models.Principal, error) {
STSSecretAccessKey: claims.STSSecretAccessKey,
STSSessionToken: claims.STSSessionToken,
AccountAccessKey: claims.AccountAccessKey,
AccountSecretKey: claims.AccountSecretKey,
}, nil
}

View File

@@ -36,14 +36,14 @@ func TestNewJWTWithClaimsForClient(t *testing.T) {
funcAssert := assert.New(t)
// Test-1 : NewEncryptedTokenForClient() is generated correctly without errors
function := "NewEncryptedTokenForClient()"
token, err := NewEncryptedTokenForClient(creds, "", "", []string{""})
token, err := NewEncryptedTokenForClient(creds, "", []string{""})
if err != nil || token == "" {
t.Errorf("Failed on %s:, error occurred: %s", function, err)
}
// saving token for future tests
goodToken = token
// Test-2 : NewEncryptedTokenForClient() throws error because of empty credentials
if _, err = NewEncryptedTokenForClient(nil, "", "", []string{""}); err != nil {
if _, err = NewEncryptedTokenForClient(nil, "", []string{""}); err != nil {
funcAssert.Equal("provided credentials are empty", err.Error())
}
}

View File

@@ -113,11 +113,29 @@ type Gemalto struct {
KeySecure *GemaltoKeySecure `yaml:"keysecure,omitempty"`
}
type GcpCredentials struct {
ClientEmail string `yaml:"client_email"`
ClientID string `yaml:"client_id"`
PrivateKeyID string `yaml:"private_key_id"`
PrivateKey string `yaml:"private_key"`
}
type GcpSecretManager struct {
ProjectID string `yaml:"project_id"`
Endpoint string `yaml:"endpoint,omitempty"`
Credentials *GcpCredentials `yaml:"credentials,omitempty"`
}
type Gcp struct {
SecretManager *GcpSecretManager `yaml:"secretmanager,omitempty"`
}
type Keys struct {
Fs *Fs `yaml:"fs,omitempty"`
Vault *Vault `yaml:"vault,omitempty"`
Aws *Aws `yaml:"aws,omitempty"`
Gemalto *Gemalto `yaml:"gemalto,omitempty"`
Gcp *Gcp `yaml:"gcp,omitempty"`
}
type ServerConfig struct {

View File

@@ -23,13 +23,17 @@ import (
"github.com/minio/minio/pkg/licverifier"
)
func TestGetLicenseInfoFromJWT(t *testing.T) {
license := "eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJsZW5pbitjMUBtaW5pby5pbyIsInRlYW1OYW1lIjoiY29uc29sZS1jdXN0b21lciIsImV4cCI6MS42Mzk5NTI2MTE2MDkxNDQ3MzJlOSwiaXNzIjoic3VibmV0QG1pbmlvLmlvIiwiY2FwYWNpdHkiOjI1LCJpYXQiOjEuNjA4NDE2NjExNjA5MTQ0NzMyZTksImFjY291bnRJZCI6MTc2LCJzZXJ2aWNlVHlwZSI6IlNUQU5EQVJEIn0.ndtf8V_FJTvhXeemVLlORyDev6RJaSPhZ2djkMVK9SvXD0srR_qlYJATPjC4NljkS71nXMGVDov5uCTuUL97x6FGQEKDruA-z24x_2Zr8kof4LfBb3HUHudCR8QvE--I"
publicKeys := []string{`-----BEGIN PUBLIC KEY-----
var (
license = "eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJrYW5hZ2FyYWorYzFAbWluaW8uaW8iLCJjYXAiOjUwLCJvcmciOiJHcmluZ290dHMgSW5jLiIsImV4cCI6MS42NDE0NDYxNjkwMDExOTg4OTRlOSwicGxhbiI6IlNUQU5EQVJEIiwiaXNzIjoic3VibmV0QG1pbi5pbyIsImFpZCI6MSwiaWF0IjoxLjYwOTkxMDE2OTAwMTE5ODg5NGU5fQ.EhTL2xwMHnUoLQF4UR-5bjUCja3whseLU5mb9XEj7PvAae6HEIDCOMEF8Hhh20DN_v_LRE283j2ZlA5zulcXSZXS0CLcrKqbVy6QLvZfvvLuerOjJI-NBa9dSJWJ0WoN"
publicKeys = []string{`-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEbo+e1wpBY4tBq9AONKww3Kq7m6QP/TBQ
mr/cKCUyBL7rcAvg0zNq1vcSrUSGlAmY3SEDCu3GOKnjG/U4E7+p957ocWSV+mQU
9NKlTdQFGF3+aO6jbQ4hX/S5qPyF+a3z
-----END PUBLIC KEY-----`}
)
func TestGetLicenseInfoFromJWT(t *testing.T) {
mockLicense, _ := GetLicenseInfoFromJWT(license, publicKeys)
@@ -54,7 +58,7 @@ mr/cKCUyBL7rcAvg0zNq1vcSrUSGlAmY3SEDCu3GOKnjG/U4E7+p957ocWSV+mQU
{
name: "error because invalid license",
args: args{
license: "eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJsZW5pbitjMUBtaW5pby5pbyIsInRlYW1OYW1lIjoiY29uc29sZS1jdXN0b21lciIsImV4cCI6MS42Mzk5NTI2MTE2MDkxNDQ3MzJlOSwiaXNzIjoic3VibmV0QG1pbmlvLmlvIiwiY2FwYWNpdHkiOjI1LCJpYXQiOjEuNjA4NDE2NjExNjA5MTQ0NzMyZTksImFjY291bnRJZCI6MTc2LCJzZXJ2aWNlVHlwZSI6IlNUQU5EQVJEIn0.ndtf8V_FJTvhXeemVLlORyDev6RJaSPhZ2djkMVK9SvXD0srR_qlYJATPjC4NljkS71nXMGVDov5uCTuUL97x6FGQEKDruA-z24x_2Zr8kof4LfBb3HUHudCR8QvE--I",
license: license,
publicKeys: []string{"eaeaeae"},
},
wantErr: true,
@@ -62,12 +66,8 @@ mr/cKCUyBL7rcAvg0zNq1vcSrUSGlAmY3SEDCu3GOKnjG/U4E7+p957ocWSV+mQU
{
name: "license successfully verified",
args: args{
license: "eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJsZW5pbitjMUBtaW5pby5pbyIsInRlYW1OYW1lIjoiY29uc29sZS1jdXN0b21lciIsImV4cCI6MS42Mzk5NTI2MTE2MDkxNDQ3MzJlOSwiaXNzIjoic3VibmV0QG1pbmlvLmlvIiwiY2FwYWNpdHkiOjI1LCJpYXQiOjEuNjA4NDE2NjExNjA5MTQ0NzMyZTksImFjY291bnRJZCI6MTc2LCJzZXJ2aWNlVHlwZSI6IlNUQU5EQVJEIn0.ndtf8V_FJTvhXeemVLlORyDev6RJaSPhZ2djkMVK9SvXD0srR_qlYJATPjC4NljkS71nXMGVDov5uCTuUL97x6FGQEKDruA-z24x_2Zr8kof4LfBb3HUHudCR8QvE--I",
publicKeys: []string{`-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEbo+e1wpBY4tBq9AONKww3Kq7m6QP/TBQ
mr/cKCUyBL7rcAvg0zNq1vcSrUSGlAmY3SEDCu3GOKnjG/U4E7+p957ocWSV+mQU
9NKlTdQFGF3+aO6jbQ4hX/S5qPyF+a3z
-----END PUBLIC KEY-----`},
license: license,
publicKeys: publicKeys,
},
wantErr: false,
want: mockLicense,

View File

@@ -30,7 +30,8 @@ const (
// Constants for subnet configuration
ConsoleSubnetURL = "CONSOLE_SUBNET_URL"
// Subnet endpoints
publicKey = "/downloads/license-pubkey.pem"
loginEndpoint = "/api/auth/login"
licenseKeyEndpoint = "/api/auth/subscription/license-key"
publicKey = "/downloads/license-pubkey.pem"
loginEndpoint = "/api/auth/login"
refreshLicenseKeyEndpoint = "/api/auth/subscription/renew-license"
licenseKeyEndpoint = "/api/auth/subscription/license-key"
)

View File

@@ -67,6 +67,41 @@ type subnetLicenseResponse struct {
Metadata LicenseMetadata `json:"metadata"`
}
// subnetLoginRequest body request for subnet login
type subnetRefreshRequest struct {
License string `json:"license"`
}
// getNewLicenseFromExistingLicense will perform license refresh based on the provided license key
func getNewLicenseFromExistingLicense(client cluster.HTTPClientI, licenseKey string) (string, error) {
request := subnetRefreshRequest{
License: licenseKey,
}
// http body for login request
payloadBytes, err := json.Marshal(request)
if err != nil {
return "", err
}
subnetURL := GetSubnetURL()
url := fmt.Sprintf("%s%s", subnetURL, refreshLicenseKeyEndpoint)
resp, err := client.Post(url, "application/json", bytes.NewReader(payloadBytes))
if err != nil {
return "", err
}
defer resp.Body.Close()
bodyBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
subnetLicense := &subnetLicenseResponse{}
// Parse subnet login response
err = json.Unmarshal(bodyBytes, subnetLicense)
if err != nil {
return "", err
}
return subnetLicense.License, nil
}
// getLicenseFromCredentials will perform authentication against subnet using
// user provided credentials and return the current subnet license key
func getLicenseFromCredentials(client cluster.HTTPClientI, username, password string) (string, error) {
@@ -171,3 +206,18 @@ func ValidateLicense(client cluster.HTTPClientI, licenseKey, email, password str
}
return licInfo, license, nil
}
func RefreshLicense(client cluster.HTTPClientI, licenseKey string) (licInfo *licverifier.LicenseInfo, license string, err error) {
if licenseKey != "" {
license, err = getNewLicenseFromExistingLicense(client, licenseKey)
if err != nil {
return nil, "", err
}
licenseInfo, rawLicense, err := ValidateLicense(client, license, "", "")
if err != nil {
return nil, "", err
}
return licenseInfo, rawLicense, nil
}
return nil, "", errors.New("invalid license")
}

View File

@@ -21,6 +21,7 @@ import (
"io"
"io/ioutil"
"net/http"
"strings"
"testing"
"errors"
@@ -138,7 +139,7 @@ func Test_getLicenseFromCredentials(t *testing.T) {
username: "valid",
password: "valid",
},
want: "eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJsZW5pbitjMUBtaW5pby5pbyIsInRlYW1OYW1lIjoiY29uc29sZS1jdXN0b21lciIsImV4cCI6MS42Mzk5NTI2MTE2MDkxNDQ3MzJlOSwiaXNzIjoic3VibmV0QG1pbmlvLmlvIiwiY2FwYWNpdHkiOjI1LCJpYXQiOjEuNjA4NDE2NjExNjA5MTQ0NzMyZTksImFjY291bnRJZCI6MTc2LCJzZXJ2aWNlVHlwZSI6IlNUQU5EQVJEIn0.ndtf8V_FJTvhXeemVLlORyDev6RJaSPhZ2djkMVK9SvXD0srR_qlYJATPjC4NljkS71nXMGVDov5uCTuUL97x6FGQEKDruA-z24x_2Zr8kof4LfBb3HUHudCR8QvE--I",
want: license,
wantErr: false,
mockFunc: func() {
HTTPPostMock = func(url, contentType string, body io.Reader) (resp *http.Response, err error) {
@@ -147,7 +148,7 @@ func Test_getLicenseFromCredentials(t *testing.T) {
}
HTTPDoMock = func(req *http.Request) (*http.Response, error) {
// returning test jwt license
return &http.Response{Body: ioutil.NopCloser(bytes.NewReader([]byte("{\"license\":\"eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJsZW5pbitjMUBtaW5pby5pbyIsInRlYW1OYW1lIjoiY29uc29sZS1jdXN0b21lciIsImV4cCI6MS42Mzk5NTI2MTE2MDkxNDQ3MzJlOSwiaXNzIjoic3VibmV0QG1pbmlvLmlvIiwiY2FwYWNpdHkiOjI1LCJpYXQiOjEuNjA4NDE2NjExNjA5MTQ0NzMyZTksImFjY291bnRJZCI6MTc2LCJzZXJ2aWNlVHlwZSI6IlNUQU5EQVJEIn0.ndtf8V_FJTvhXeemVLlORyDev6RJaSPhZ2djkMVK9SvXD0srR_qlYJATPjC4NljkS71nXMGVDov5uCTuUL97x6FGQEKDruA-z24x_2Zr8kof4LfBb3HUHudCR8QvE--I\",\"metadata\":{\"email\":\"lenin+c1@minio.io\",\"issuer\":\"subnet@minio.io\",\"accountId\":176,\"teamName\":\"console-customer\",\"serviceType\":\"STANDARD\",\"capacity\":25,\"requestedAt\":\"2020-12-19T22:23:31.609144732Z\",\"expiresAt\":\"2021-12-19T22:23:31.609144732Z\"}}")))}, nil
return &http.Response{Body: ioutil.NopCloser(bytes.NewReader([]byte("{\"license\":\"" + license + "\",\"metadata\":{\"email\":\"lenin+c1@minio.io\",\"issuer\":\"subnet@minio.io\",\"accountId\":176,\"teamName\":\"console-customer\",\"serviceType\":\"STANDARD\",\"capacity\":25,\"requestedAt\":\"2020-12-19T22:23:31.609144732Z\",\"expiresAt\":\"2021-12-19T22:23:31.609144732Z\"}}")))}, nil
}
},
},
@@ -282,11 +283,7 @@ func TestValidateLicense(t *testing.T) {
wantErr: true,
mockFunc: func() {
HTTPGetMock = func(url string) (resp *http.Response, err error) {
return &http.Response{Body: ioutil.NopCloser(bytes.NewReader([]byte(`-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEbo+e1wpBY4tBq9AONKww3Kq7m6QP/TBQ
mr/cKCUyBL7rcAvg0zNq1vcSrUSGlAmY3SEDCu3GOKnjG/U4E7+p957ocWSV+mQU
9NKlTdQFGF3+aO6jbQ4hX/S5qPyF+a3z
-----END PUBLIC KEY-----`)))}, nil
return &http.Response{Body: ioutil.NopCloser(strings.NewReader(publicKeys[0]))}, nil
}
},
},
@@ -294,21 +291,17 @@ mr/cKCUyBL7rcAvg0zNq1vcSrUSGlAmY3SEDCu3GOKnjG/U4E7+p957ocWSV+mQU
name: "license validated successfully",
args: args{
client: clientMock,
licenseKey: "eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJsZW5pbitjMUBtaW5pby5pbyIsInRlYW1OYW1lIjoiY29uc29sZS1jdXN0b21lciIsImV4cCI6MS42Mzk5NTI2MTE2MDkxNDQ3MzJlOSwiaXNzIjoic3VibmV0QG1pbmlvLmlvIiwiY2FwYWNpdHkiOjI1LCJpYXQiOjEuNjA4NDE2NjExNjA5MTQ0NzMyZTksImFjY291bnRJZCI6MTc2LCJzZXJ2aWNlVHlwZSI6IlNUQU5EQVJEIn0.ndtf8V_FJTvhXeemVLlORyDev6RJaSPhZ2djkMVK9SvXD0srR_qlYJATPjC4NljkS71nXMGVDov5uCTuUL97x6FGQEKDruA-z24x_2Zr8kof4LfBb3HUHudCR8QvE--I",
licenseKey: license,
email: "",
password: "",
},
wantErr: false,
mockFunc: func() {
HTTPGetMock = func(url string) (resp *http.Response, err error) {
return &http.Response{Body: ioutil.NopCloser(bytes.NewReader([]byte(`-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEbo+e1wpBY4tBq9AONKww3Kq7m6QP/TBQ
mr/cKCUyBL7rcAvg0zNq1vcSrUSGlAmY3SEDCu3GOKnjG/U4E7+p957ocWSV+mQU
9NKlTdQFGF3+aO6jbQ4hX/S5qPyF+a3z
-----END PUBLIC KEY-----`)))}, nil
return &http.Response{Body: ioutil.NopCloser(strings.NewReader(publicKeys[0]))}, nil
}
},
wantLicense: "eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJsZW5pbitjMUBtaW5pby5pbyIsInRlYW1OYW1lIjoiY29uc29sZS1jdXN0b21lciIsImV4cCI6MS42Mzk5NTI2MTE2MDkxNDQ3MzJlOSwiaXNzIjoic3VibmV0QG1pbmlvLmlvIiwiY2FwYWNpdHkiOjI1LCJpYXQiOjEuNjA4NDE2NjExNjA5MTQ0NzMyZTksImFjY291bnRJZCI6MTc2LCJzZXJ2aWNlVHlwZSI6IlNUQU5EQVJEIn0.ndtf8V_FJTvhXeemVLlORyDev6RJaSPhZ2djkMVK9SvXD0srR_qlYJATPjC4NljkS71nXMGVDov5uCTuUL97x6FGQEKDruA-z24x_2Zr8kof4LfBb3HUHudCR8QvE--I",
wantLicense: license,
},
}

View File

@@ -1,7 +1,6 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/build
node_modules/
/.pnp
.pnp.js
@@ -9,8 +8,6 @@ node_modules/
# testing
/coverage
# production
/build
# misc
.DS_Store

View File

@@ -3,5 +3,4 @@ default: build-static
build-static:
@echo "Building frontend static assets to 'build'"
yarn build
go-bindata-assetfs -pkg portal build/...

10
portal-ui/assets.go Normal file
View File

@@ -0,0 +1,10 @@
package portalui
import "embed"
//go:embed build/*
var fs embed.FS
func GetStaticAssets() embed.FS {
return fs
}

File diff suppressed because one or more lines are too long

1
portal-ui/build/agpl.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.2 KiB

BIN
portal-ui/build/amqp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -0,0 +1,25 @@
{
"files": {
"main.css": "/static/css/main.a19f3d53.chunk.css",
"main.js": "/static/js/main.fa0873e1.chunk.js",
"main.js.map": "/static/js/main.fa0873e1.chunk.js.map",
"runtime-main.js": "/static/js/runtime-main.f48e99e5.js",
"runtime-main.js.map": "/static/js/runtime-main.f48e99e5.js.map",
"static/css/2.f324abd6.chunk.css": "/static/css/2.f324abd6.chunk.css",
"static/js/2.44b7c49b.chunk.js": "/static/js/2.44b7c49b.chunk.js",
"static/js/2.44b7c49b.chunk.js.map": "/static/js/2.44b7c49b.chunk.js.map",
"index.html": "/index.html",
"static/css/2.f324abd6.chunk.css.map": "/static/css/2.f324abd6.chunk.css.map",
"static/css/main.a19f3d53.chunk.css.map": "/static/css/main.a19f3d53.chunk.css.map",
"static/js/2.44b7c49b.chunk.js.LICENSE.txt": "/static/js/2.44b7c49b.chunk.js.LICENSE.txt",
"static/media/minio_console_logo.0837460e.svg": "/static/media/minio_console_logo.0837460e.svg",
"static/media/minio_operator_logo.1312b7c9.svg": "/static/media/minio_operator_logo.1312b7c9.svg"
},
"entrypoints": [
"static/js/runtime-main.f48e99e5.js",
"static/css/2.f324abd6.chunk.css",
"static/js/2.44b7c49b.chunk.js",
"static/css/main.a19f3d53.chunk.css",
"static/js/main.fa0873e1.chunk.js"
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
portal-ui/build/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 368.999 192.934"><defs><style>.cls-1{opacity:0.35;}.cls-12,.cls-15,.cls-16,.cls-17,.cls-2,.cls-5,.cls-6,.cls-7,.cls-8{opacity:0.5;}.cls-10,.cls-11,.cls-12,.cls-13,.cls-14,.cls-15,.cls-16,.cls-17,.cls-3,.cls-4,.cls-5,.cls-6,.cls-7,.cls-9{fill:none;stroke:#fff;stroke-miterlimit:10;}.cls-4{stroke-width:0.5px;}.cls-10,.cls-11,.cls-5,.cls-9{stroke-width:0.873px;}.cls-5{stroke-dasharray:2.619 2.182;}.cls-12,.cls-15,.cls-16,.cls-17,.cls-5,.cls-6,.cls-7,.cls-8{isolation:isolate;}.cls-6{stroke-width:0.715px;stroke-dasharray:2.144 1.786;}.cls-7{stroke-width:0.743px;stroke-dasharray:2.23 1.858;}.cls-10{stroke-dasharray:2.646 2.204;}.cls-11{stroke-dasharray:2.585 2.154;}.cls-12{stroke-width:0.828px;stroke-dasharray:2.484 2.07;}.cls-13{stroke-dasharray:2.984 2.487;}.cls-14{stroke-dasharray:2.773 2.311;}.cls-16{stroke-width:0.899px;}.cls-17{stroke-width:0.859px;}</style></defs><title>BG_Illustration</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><g id="BG_Illustration" data-name="BG Illustration" class="cls-1"><g id="Group_118" data-name="Group 118" class="cls-2"><path id="Path_56" data-name="Path 56" class="cls-3" d="M211.5,140.678l-52.726,29.078L79.687,126.139V29.652L132.411.571,211.5,44.188Z"/><path id="Path_58" data-name="Path 58" class="cls-3" d="M158.776,169.756V73.271L211.5,44.193,158.776,73.271,79.688,29.654"/><path id="Path_59" data-name="Path 59" class="cls-4" d="M84.681,41l69.1,38.11v79.3l-69.1-38.11Z"/><line id="Line_37" data-name="Line 37" class="cls-4" x1="106.25" y1="52.782" x2="106.25" y2="132.086"/><line id="Line_38" data-name="Line 38" class="cls-4" x1="153.783" y1="92.327" x2="106.25" y2="65.999"/><line id="Line_39" data-name="Line 39" class="cls-4" x1="153.783" y1="105.545" x2="106.25" y2="79.217"/><line id="Line_40" data-name="Line 40" class="cls-4" x1="153.783" y1="118.762" x2="106.25" y2="92.434"/><line id="Line_41" data-name="Line 41" class="cls-4" x1="153.783" y1="131.979" x2="106.25" y2="105.651"/><line id="Line_42" data-name="Line 42" class="cls-4" x1="153.783" y1="145.197" x2="106.25" y2="118.869"/><path id="Path_60" data-name="Path 60" class="cls-4" d="M166.723,151.031l38.8-22.487V62.916L166.723,85.4Z"/></g><path id="Path_62" data-name="Path 62" class="cls-5" d="M117.106,148.062l-76.18,43.33"/><path id="Path_63" data-name="Path 63" class="cls-6" d="M271.394,167.271l-44.483,25.3"/><path id="Path_64" data-name="Path 64" class="cls-7" d="M190.722,155.708l61.951,36.031"/><path id="Path_65" data-name="Path 65" class="cls-5" d="M237.7,36.385l28.182,17.229"/><g id="Path_66" data-name="Path 66" class="cls-8"><line class="cls-9" x1="362.563" y1="69.327" x2="361.42" y2="68.688"/><line class="cls-10" x1="359.496" y1="67.613" x2="305.418" y2="37.39"/><polyline class="cls-9" points="304.456 36.852 303.313 36.213 302.158 36.83"/><line class="cls-11" x1="300.258" y1="37.844" x2="213.418" y2="84.213"/><line class="cls-9" x1="212.468" y1="84.72" x2="211.313" y2="85.337"/></g><path id="Path_67" data-name="Path 67" class="cls-12" d="M79.648,192.571,31.786,166.344h-.868l-23.579,14.2"/><g id="Path_68" data-name="Path 68" class="cls-8"><line class="cls-3" x1="22.871" y1="84.641" x2="24.156" y2="83.867"/><line class="cls-13" x1="26.286" y1="82.584" x2="48.654" y2="69.113"/><polyline class="cls-3" points="49.719 68.471 51.004 67.698 52.307 68.441"/><line class="cls-14" x1="54.315" y1="69.585" x2="75.395" y2="81.606"/><line class="cls-3" x1="76.399" y1="82.178" x2="77.702" y2="82.921"/></g><circle id="Ellipse_11" data-name="Ellipse 11" class="cls-15" cx="4.092" cy="183.59" r="3.592"/><circle id="Ellipse_12" data-name="Ellipse 12" class="cls-15" cx="274.986" cy="165.477" r="3.592"/><ellipse id="Ellipse_13" data-name="Ellipse 13" class="cls-16" cx="364.957" cy="71.922" rx="3.592" ry="2.904"/><circle id="Ellipse_14" data-name="Ellipse 14" class="cls-15" cx="19.279" cy="87.681" r="3.592"/><ellipse id="Ellipse_15" data-name="Ellipse 15" class="cls-17" cx="234.106" cy="32.58" rx="3.592" ry="2.649"/></g></g></g></svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@@ -0,0 +1,67 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 368.999 192.934">
<defs>
<style>
.cls-1{opacity:0.35;}.cls-12,.cls-15,.cls-16,.cls-17,.cls-2,.cls-5,.cls-6,.cls-7,.cls-8{opacity:0.5;}.cls-10,.cls-11,.cls-12,.cls-13,.cls-14,.cls-15,.cls-16,.cls-17,.cls-3,.cls-4,.cls-5,.cls-6,.cls-7,.cls-9{fill:none;stroke:#707070;stroke-miterlimit:10;}.cls-4{stroke-width:1px;}.cls-10,.cls-11,.cls-5,.cls-9{stroke-width:1.2px;}.cls-5{stroke-dasharray:2.619
2.182;}.cls-12,.cls-15,.cls-16,.cls-17,.cls-5,.cls-6,.cls-7,.cls-8{isolation:isolate;}.cls-6{stroke-width:1.6px;stroke-dasharray:2.144
1.786;}.cls-7{stroke-width:1.6px;stroke-dasharray:2.23 1.858;}.cls-10{stroke-dasharray:2.646
2.204;}.cls-11{stroke-dasharray:2.585 2.154;}.cls-12{stroke-width:1.8px;stroke-dasharray:2.484
2.07;}.cls-13{stroke-dasharray:2.984 2.487;}.cls-14{stroke-dasharray:2.773
2.311;}.cls-16{stroke-width:1.8px;}.cls-17{stroke-width:1.8px;}
</style>
</defs>
<title>BG_Illustration</title>
<g id="Layer_2" data-name="Layer 2">
<g id="Layer_1-2" data-name="Layer 1">
<g id="BG_Illustration" data-name="BG Illustration" class="cls-1">
<g id="Group_118" data-name="Group 118" class="cls-2">
<path id="Path_56" data-name="Path 56" class="cls-3"
d="M211.5,140.678l-52.726,29.078L79.687,126.139V29.652L132.411.571,211.5,44.188Z"/>
<path id="Path_58" data-name="Path 58" class="cls-3"
d="M158.776,169.756V73.271L211.5,44.193,158.776,73.271,79.688,29.654"/>
<path id="Path_59" data-name="Path 59" class="cls-4" d="M84.681,41l69.1,38.11v79.3l-69.1-38.11Z"/>
<line id="Line_37" data-name="Line 37" class="cls-4" x1="106.25" y1="52.782" x2="106.25"
y2="132.086"/>
<line id="Line_38" data-name="Line 38" class="cls-4" x1="153.783" y1="92.327" x2="106.25"
y2="65.999"/>
<line id="Line_39" data-name="Line 39" class="cls-4" x1="153.783" y1="105.545" x2="106.25"
y2="79.217"/>
<line id="Line_40" data-name="Line 40" class="cls-4" x1="153.783" y1="118.762" x2="106.25"
y2="92.434"/>
<line id="Line_41" data-name="Line 41" class="cls-4" x1="153.783" y1="131.979" x2="106.25"
y2="105.651"/>
<line id="Line_42" data-name="Line 42" class="cls-4" x1="153.783" y1="145.197" x2="106.25"
y2="118.869"/>
<path id="Path_60" data-name="Path 60" class="cls-4"
d="M166.723,151.031l38.8-22.487V62.916L166.723,85.4Z"/>
</g>
<path id="Path_62" data-name="Path 62" class="cls-5" d="M117.106,148.062l-76.18,43.33"/>
<path id="Path_63" data-name="Path 63" class="cls-6" d="M271.394,167.271l-44.483,25.3"/>
<path id="Path_64" data-name="Path 64" class="cls-7" d="M190.722,155.708l61.951,36.031"/>
<path id="Path_65" data-name="Path 65" class="cls-5" d="M237.7,36.385l28.182,17.229"/>
<g id="Path_66" data-name="Path 66" class="cls-8">
<line class="cls-9" x1="362.563" y1="69.327" x2="361.42" y2="68.688"/>
<line class="cls-10" x1="359.496" y1="67.613" x2="305.418" y2="37.39"/>
<polyline class="cls-9" points="304.456 36.852 303.313 36.213 302.158 36.83"/>
<line class="cls-11" x1="300.258" y1="37.844" x2="213.418" y2="84.213"/>
<line class="cls-9" x1="212.468" y1="84.72" x2="211.313" y2="85.337"/>
</g>
<path id="Path_67" data-name="Path 67" class="cls-12"
d="M79.648,192.571,31.786,166.344h-.868l-23.579,14.2"/>
<g id="Path_68" data-name="Path 68" class="cls-8">
<line class="cls-3" x1="22.871" y1="84.641" x2="24.156" y2="83.867"/>
<line class="cls-13" x1="26.286" y1="82.584" x2="48.654" y2="69.113"/>
<polyline class="cls-3" points="49.719 68.471 51.004 67.698 52.307 68.441"/>
<line class="cls-14" x1="54.315" y1="69.585" x2="75.395" y2="81.606"/>
<line class="cls-3" x1="76.399" y1="82.178" x2="77.702" y2="82.921"/>
</g>
<circle id="Ellipse_11" data-name="Ellipse 11" class="cls-15" cx="4.092" cy="183.59" r="3.592"/>
<circle id="Ellipse_12" data-name="Ellipse 12" class="cls-15" cx="274.986" cy="165.477" r="3.592"/>
<ellipse id="Ellipse_13" data-name="Ellipse 13" class="cls-16" cx="364.957" cy="71.922" rx="3.592"
ry="2.904"/>
<circle id="Ellipse_14" data-name="Ellipse 14" class="cls-15" cx="19.279" cy="87.681" r="3.592"/>
<ellipse id="Ellipse_15" data-name="Ellipse 15" class="cls-17" cx="234.106" cy="32.58" rx="3.592"
ry="2.649"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="11.174" height="11" viewBox="0 0 11.174 11">
<defs>
<style>.a{fill:none;stroke:#081c42;stroke-linecap:round;}</style>
</defs>
<path class="a" d="M8.392,10H1.608L0,0H10Z" transform="translate(0.587 0.5)"/>
</svg>

After

Width:  |  Height:  |  Size: 279 B

View File

@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="11.174" height="11" viewBox="0 0 11.174 11">
<defs>
<style>.a{fill:#081c42;stroke:#081c42;stroke-linecap:round;}</style>
</defs>
<path class="a" d="M8.392,10H1.608L0,0H10Z" transform="translate(0.587 0.5)"/>
</svg>

After

Width:  |  Height:  |  Size: 282 B

View File

@@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" width="11.442" height="15.302" viewBox="0 0 11.442 15.302">
<defs>
<style>.a,.b{fill:none;stroke:#081c42;}.b{stroke-linejoin:round;}</style>
</defs>
<g transform="translate(0.5 0.5)">
<path class="a" d="M-12060-11667.842v14.261h10.442v-10.591l-3.671-3.67Z"
transform="translate(12059.999 11667.883)"/>
<path class="b" d="M-12051.353-11664.255v-3.639l3.528,3.639Z" transform="translate(12058.188 11667.894)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 515 B

View File

@@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" width="11.442" height="15.302" viewBox="0 0 11.442 15.302">
<defs>
<style>.a,.b{fill:#081c42;stroke:#081c42;}.b{stroke-linejoin:round;fill:#fff}</style>
</defs>
<g transform="translate(0.5 0.5)">
<path class="a" d="M-12060-11667.842v14.261h10.442v-10.591l-3.671-3.67Z"
transform="translate(12059.999 11667.883)"/>
<path class="b" d="M-12051.353-11664.255v-3.639l3.528,3.639Z" transform="translate(12058.188 11667.894)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 527 B

View File

@@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" width="15.999" height="13.999" viewBox="0 0 15.999 13.999">
<defs>
<style>.a{fill:none;stroke-linecap:square;}.b,.c{stroke:none;}.c{fill:#081c42;}</style>
</defs>
<g class="a" transform="translate(-0.001 0.001)">
<path class="b" d="M0,14V0H8.572V2.411H16V14Z"/>
<path class="c"
d="M 15.00020027160645 12.99860000610352 L 15.00020027160645 3.411099910736084 L 8.571599960327148 3.411099910736084 L 7.571600437164307 3.411099910736084 L 7.571600437164307 2.411099910736084 L 7.571600437164307 0.9990998506546021 L 1.000900268554688 0.9990998506546021 L 1.000900268554688 2.411099910736084 L 1.000900268554688 12.99860000610352 L 15.00020027160645 12.99860000610352 M 16.00020027160645 13.99860000610352 L 0.0009002700680866838 13.99860000610352 L 0.0009002700680866838 2.411099910736084 L 0.0009002700680866838 -0.0009001312428154051 L 8.571599960327148 -0.0009001312428154051 L 8.571599960327148 2.411099910736084 L 16.00020027160645 2.411099910736084 L 16.00020027160645 13.99860000610352 Z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" width="15.999" height="13.999" viewBox="0 0 15.999 13.999">
<defs>
<style>.a{fill:none;stroke-linecap:square;}.b,.c{stroke:none;fill:#081c42}.c{fill:#081c42;}</style>
</defs>
<g class="a" transform="translate(-0.001 0.001)">
<path class="b" d="M0,14V0H8.572V2.411H16V14Z"/>
<path class="c"
d="M 15.00020027160645 12.99860000610352 L 15.00020027160645 3.411099910736084 L 8.571599960327148 3.411099910736084 L 7.571600437164307 3.411099910736084 L 7.571600437164307 2.411099910736084 L 7.571600437164307 0.9990998506546021 L 1.000900268554688 0.9990998506546021 L 1.000900268554688 2.411099910736084 L 1.000900268554688 12.99860000610352 L 15.00020027160645 12.99860000610352 M 16.00020027160645 13.99860000610352 L 0.0009002700680866838 13.99860000610352 L 0.0009002700680866838 2.411099910736084 L 0.0009002700680866838 -0.0009001312428154051 L 8.571599960327148 -0.0009001312428154051 L 8.571599960327148 2.411099910736084 L 16.00020027160645 2.411099910736084 L 16.00020027160645 13.99860000610352 Z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="MinIO Console"/><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="/apple-icon-180x180.png"/><link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"/><link rel="icon" type="image/png" sizes="96x96" href="/favicon-96x96.png"/><link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"/><link rel="manifest" href="/manifest.json"/><link rel="mask-icon" href="/safari-pinned-tab.svg" color="#3a4e54"/><title>MinIO Console</title><link href="/static/css/2.f324abd6.chunk.css" rel="stylesheet"><link href="/static/css/main.a19f3d53.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function r(r){for(var n,l,i=r[0],a=r[1],p=r[2],c=0,s=[];c<i.length;c++)l=i[c],Object.prototype.hasOwnProperty.call(o,l)&&o[l]&&s.push(o[l][0]),o[l]=0;for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(e[n]=a[n]);for(f&&f(r);s.length;)s.shift()();return u.push.apply(u,p||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,i=1;i<t.length;i++){var a=t[i];0!==o[a]&&(n=!1)}n&&(u.splice(r--,1),e=l(l.s=t[0]))}return e}var n={},o={1:0},u=[];function l(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,l),t.l=!0,t.exports}l.m=e,l.c=n,l.d=function(e,r,t){l.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},l.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},l.t=function(e,r){if(1&r&&(e=l(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(l.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)l.d(t,n,function(r){return e[r]}.bind(null,n));return t},l.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return l.d(r,"a",r),r},l.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},l.p="/";var i=this["webpackJsonpportal-ui"]=this["webpackJsonpportal-ui"]||[],a=i.push.bind(i);i.push=r,i=i.slice();for(var p=0;p<i.length;p++)r(i[p]);var f=a;t()}([])</script><script src="/static/js/2.44b7c49b.chunk.js"></script><script src="/static/js/main.fa0873e1.chunk.js"></script></body></html>

BIN
portal-ui/build/kafka.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
portal-ui/build/logo192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

BIN
portal-ui/build/logo512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -0,0 +1,41 @@
{
"name": "MinIO Console",
"icons": [
{
"src": "android-icon-36x36.png",
"sizes": "36x36",
"type": "image/png",
"density": "0.75"
},
{
"src": "android-icon-48x48.png",
"sizes": "48x48",
"type": "image/png",
"density": "1.0"
},
{
"src": "android-icon-72x72.png",
"sizes": "72x72",
"type": "image/png",
"density": "1.5"
},
{
"src": "android-icon-96x96.png",
"sizes": "96x96",
"type": "image/png",
"density": "2.0"
},
{
"src": "android-icon-144x144.png",
"sizes": "144x144",
"type": "image/png",
"density": "3.0"
},
{
"src": "android-icon-192x192.png",
"sizes": "192x192",
"type": "image/png",
"density": "4.0"
}
]
}

BIN
portal-ui/build/mqtt.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
portal-ui/build/mysql.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
portal-ui/build/nats.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
portal-ui/build/redis.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

View File

@@ -0,0 +1,2 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *

View File

@@ -0,0 +1,148 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="1344.000000pt" height="1344.000000pt" viewBox="0 0 1344.000000 1344.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.11, written by Peter Selinger 2001-2013
</metadata>
<g transform="translate(0.000000,1344.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M7171 13408 c-35 -4 -87 -12 -117 -18 -30 -6 -56 -11 -59 -10 -3 0
-19 -7 -35 -15 -17 -9 -30 -13 -30 -11 0 12 -265 -115 -280 -133 -3 -3 -24
-19 -48 -34 -71 -46 -214 -196 -274 -287 -93 -144 -150 -293 -176 -460 -17
-119 -2 -363 29 -450 1 -3 3 -9 5 -15 42 -141 95 -243 187 -365 23 -30 45 -59
49 -65 34 -48 152 -181 244 -275 61 -63 129 -133 150 -156 54 -57 367 -384
494 -515 93 -96 218 -226 500 -519 47 -48 137 -143 200 -211 63 -67 143 -152
178 -188 104 -108 196 -221 255 -311 75 -116 173 -328 177 -382 1 -4 7 -22 15
-41 14 -34 42 -167 53 -252 9 -70 8 -328 -2 -400 -14 -110 -77 -347 -97 -370
-5 -5 -9 -15 -9 -22 0 -21 -72 -163 -126 -249 -36 -58 -77 -119 -83 -124 -3
-3 -25 -28 -49 -57 -43 -53 -159 -169 -200 -200 -13 -10 -36 -27 -50 -39 -108
-85 -380 -234 -392 -214 -3 4 -5 580 -4 1279 l0 1270 -105 -55 c-57 -30 -109
-58 -115 -63 -6 -4 -36 -22 -66 -38 -141 -77 -319 -186 -498 -306 -75 -51
-141 -94 -147 -96 -5 -2 -15 -9 -22 -15 -29 -26 -43 -36 -70 -53 -51 -32 -292
-215 -329 -250 -7 -7 -17 -13 -22 -13 -6 0 -12 -3 -14 -7 -1 -5 -28 -28 -58
-53 -30 -25 -60 -49 -66 -55 -6 -5 -36 -30 -65 -55 -46 -38 -80 -68 -155 -135
-169 -151 -434 -411 -434 -426 0 -5 -7 -9 -15 -9 -8 0 -15 -3 -15 -7 0 -5 -25
-35 -56 -68 -102 -109 -180 -198 -291 -330 -95 -113 -100 -120 -143 -175 -19
-25 -37 -47 -40 -50 -29 -26 -440 -610 -440 -626 0 -3 -43 -70 -57 -89 -5 -5
-15 -23 -23 -40 -8 -16 -18 -32 -21 -35 -10 -9 -194 -335 -190 -339 1 -2 -1
-7 -6 -10 -5 -3 -24 -37 -43 -76 -19 -38 -38 -73 -43 -76 -5 -3 -9 -10 -9 -15
0 -5 -29 -67 -63 -139 -72 -150 -100 -211 -144 -315 -18 -41 -36 -84 -41 -95
-43 -93 -212 -555 -204 -555 2 0 -2 -13 -11 -30 -8 -16 -15 -38 -15 -50 0 -11
-4 -20 -8 -20 -5 0 -9 -6 -9 -13 0 -7 -16 -67 -37 -135 -20 -67 -39 -130 -41
-140 -2 -9 -20 -80 -40 -156 -20 -77 -39 -151 -41 -165 -3 -14 -10 -44 -16
-66 -6 -22 -11 -43 -10 -46 0 -3 -3 -22 -8 -42 -4 -20 -5 -36 -1 -34 51 24 87
44 93 52 4 6 8 7 8 3 0 -6 284 135 305 152 6 5 14 8 18 8 8 1 339 164 347 172
10 10 459 230 468 230 6 0 12 3 14 8 2 4 158 85 348 180 190 96 352 177 360
182 8 4 29 14 45 21 17 8 33 18 37 24 4 5 8 6 8 1 0 -5 6 -4 13 2 17 14 335
173 343 171 4 0 10 3 13 8 3 5 110 62 236 125 127 64 336 171 465 237 232 119
318 161 327 161 3 0 3 -9 0 -20 -3 -11 -1 -22 4 -25 4 -3 5 -16 0 -28 -5 -12
-5 -31 -1 -42 4 -11 5 -26 2 -34 -7 -19 -7 -80 1 -87 3 -3 1 -18 -4 -33 -6
-14 -10 -27 -9 -28 9 -15 17 -63 10 -63 -4 0 -4 -16 0 -35 4 -19 5 -35 1 -35
-8 0 -6 -68 2 -76 3 -3 2 -17 -3 -30 -5 -13 -6 -25 -2 -28 5 -3 5 -30 2 -61
-3 -31 -3 -58 2 -61 4 -3 3 -15 -2 -28 -5 -13 -6 -27 -3 -30 8 -7 10 -76 3
-76 -7 0 -3 -77 4 -88 2 -4 1 -14 -4 -21 -4 -8 -4 -27 0 -42 5 -16 6 -29 2
-29 -4 0 -7 -16 -7 -35 0 -19 2 -35 5 -35 3 0 5 -16 5 -35 0 -19 -2 -35 -5
-35 -3 0 -4 -19 -2 -43 3 -48 5 -100 2 -107 -5 -17 -4 -280 2 -280 4 0 3 -13
-2 -30 -5 -18 -5 -30 0 -30 6 0 6 -10 0 -25 -6 -15 -6 -26 1 -30 5 -4 7 -10 4
-15 -7 -12 -10 -124 -3 -135 3 -6 2 -19 -2 -30 -4 -11 -4 -30 1 -41 4 -12 5
-24 2 -28 -8 -8 -9 -276 -1 -276 4 0 3 -13 -2 -30 -5 -18 -5 -30 0 -30 6 0 6
-10 0 -25 -6 -15 -6 -26 1 -30 5 -4 7 -10 4 -15 -5 -8 -9 -116 -5 -135 1 -5 1
-14 0 -20 -5 -24 -3 -105 3 -111 3 -3 2 -16 -3 -29 -5 -13 -6 -26 -3 -29 8 -7
10 -76 3 -76 -7 0 -3 -77 4 -88 2 -4 1 -14 -4 -21 -4 -8 -4 -27 0 -42 5 -16 6
-29 2 -29 -4 0 -7 -16 -7 -35 0 -19 2 -35 5 -35 3 0 5 -16 5 -35 0 -19 -2 -35
-5 -35 -7 0 -3 -77 4 -88 2 -4 1 -14 -4 -21 -4 -8 -4 -27 0 -42 5 -16 5 -29 0
-29 -4 0 -4 -16 0 -35 4 -19 5 -35 1 -35 -8 0 -6 -68 2 -76 3 -3 2 -16 -3 -29
-5 -13 -6 -26 -3 -29 5 -5 8 -80 3 -88 -5 -10 -4 -278 2 -278 4 0 3 -13 -2
-30 -5 -18 -5 -30 0 -30 6 0 6 -10 0 -25 -6 -15 -6 -26 1 -30 5 -4 7 -10 4
-15 -8 -13 -10 -128 -3 -136 4 -3 2 -18 -3 -33 -6 -14 -10 -27 -9 -28 9 -15
17 -63 10 -63 -4 0 -4 -16 0 -35 4 -19 5 -35 1 -35 -8 0 -6 -68 2 -76 3 -3 2
-17 -3 -30 -5 -13 -6 -25 -2 -28 5 -3 5 -30 2 -61 -3 -31 -3 -58 2 -61 4 -3 3
-15 -2 -28 -5 -13 -6 -27 -3 -30 7 -7 10 -76 3 -76 -3 0 -4 -17 -2 -37 4 -55
2 -124 -3 -133 -3 -5 -1 -11 5 -15 6 -4 7 -13 1 -23 -6 -11 -5 -24 1 -36 13
-23 785 -796 796 -796 4 0 6 19 4 42 -1 24 -3 49 -2 56 0 6 0 19 0 27 0 8 0
22 0 30 0 8 0 22 0 30 0 8 0 22 0 30 0 8 0 22 0 30 0 8 0 22 0 30 0 8 0 22 0
30 0 8 0 22 0 30 0 8 0 22 0 30 0 8 0 22 0 30 0 8 0 22 0 30 0 8 0 22 0 30 0
8 0 22 0 30 0 8 0 22 0 30 0 8 0 22 0 30 0 8 0 22 0 30 0 8 0 22 0 30 0 8 0
21 0 28 -1 6 1 31 2 55 2 23 0 42 -4 42 -4 0 -3 14 2 30 5 17 5 30 0 30 -5 0
-5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5
17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30
-5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0
30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30
0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5
13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17
5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5
0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30
5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0
30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13
0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5
30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0
-5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5
17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30
-5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 6 30 2 30 -8 0 -7 68 1
76 3 3 2 17 -3 30 -6 14 -6 26 0 29 6 3 6 15 0 29 -5 13 -6 26 -4 29 8 8 10
167 2 167 -4 0 -3 14 2 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5
0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30
5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0
30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13
0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5
30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0
-5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5
17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30
-5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0
30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30
0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5
13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17
5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5
0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30
5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0 30 -5 0 -5 13 0 30 5 17 5 30 0
30 -4 0 -5 15 -1 33 4 17 4 47 0 65 -3 17 -3 32 2 32 4 0 4 13 -1 29 -4 15 -4
34 0 42 5 7 5 20 0 29 -5 9 -5 22 0 30 5 8 5 21 0 30 -5 9 -5 22 0 30 5 8 5
21 0 30 -5 9 -5 22 0 30 5 8 5 21 0 30 -5 9 -5 22 0 30 5 8 5 21 0 30 -4 8 -4
22 0 31 5 8 5 21 0 29 -4 7 -4 24 0 36 5 13 6 26 1 28 -5 3 -6 17 -4 30 4 21
33 39 172 109 266 135 574 311 627 358 11 11 23 19 27 19 8 0 26 15 141 115
144 125 302 298 374 409 15 22 30 43 33 46 14 11 130 212 160 276 18 38 37 72
43 76 6 4 8 8 4 8 -7 0 9 42 57 155 12 27 54 164 59 190 1 6 5 19 9 30 6 21 7
25 31 140 60 297 53 661 -19 975 -8 36 -17 76 -20 89 -3 13 -10 31 -14 40 -5
9 -9 18 -9 21 0 13 -24 93 -39 127 -9 21 -17 40 -18 43 -5 35 -111 254 -174
359 -29 49 -104 162 -123 186 -4 6 -24 30 -43 55 -84 106 -109 133 -635 679
-93 97 -406 423 -465 485 -69 72 -376 393 -455 476 -36 37 -137 143 -225 235
-88 93 -170 177 -182 188 -13 12 -23 25 -23 31 0 5 -6 17 -13 25 -41 48 -65
187 -46 269 11 52 41 122 51 122 5 0 8 6 8 13 0 24 116 119 176 145 117 50
275 35 374 -37 37 -27 46 -36 295 -296 172 -179 189 -196 405 -425 74 -78 155
-164 180 -190 25 -26 106 -111 180 -190 74 -78 158 -166 185 -195 28 -29 113
-119 190 -200 77 -81 170 -178 206 -216 36 -37 123 -130 195 -205 71 -75 149
-158 174 -183 25 -26 99 -105 165 -175 245 -260 297 -309 320 -300 8 3 15 11
15 16 0 23 -24 94 -37 109 -7 8 -13 21 -13 27 0 6 -10 23 -23 39 -12 15 -33
48 -46 73 -13 25 -29 52 -36 60 -7 8 -25 39 -41 67 -16 29 -32 53 -36 53 -5 0
-8 9 -8 20 0 11 -3 20 -7 20 -8 0 -34 39 -60 90 -7 14 -21 39 -32 55 -87 140
-121 198 -121 205 0 5 -3 10 -7 12 -5 2 -53 77 -107 168 -54 91 -127 211 -162
267 -35 56 -64 106 -64 112 0 5 -3 11 -7 13 -11 4 -83 124 -83 136 0 6 -4 12
-8 14 -7 3 -126 194 -201 322 -13 23 -32 53 -42 68 -11 14 -19 31 -19 37 0 6
-4 11 -9 11 -5 0 -18 19 -30 43 -12 23 -35 62 -51 87 -30 46 -68 108 -85 141
-5 11 -13 19 -17 19 -5 0 -8 4 -8 9 0 6 -27 52 -60 103 -34 51 -66 105 -73
121 -6 15 -15 27 -19 27 -4 0 -8 7 -8 15 0 8 -4 15 -10 15 -5 0 -10 5 -10 11
0 9 -155 245 -170 259 -3 3 -18 22 -34 43 -102 137 -309 304 -476 384 -79 38
-114 53 -132 58 -5 2 -9 3 -10 5 -2 1 -10 3 -18 6 -8 2 -38 10 -67 18 -128 36
-284 49 -412 34z m-292 -5345 c-4 -18 -3 -33 1 -33 4 0 4 -18 0 -40 -4 -22 -4
-40 1 -40 5 0 4 -11 -1 -24 -5 -13 -6 -27 -2 -30 7 -8 5 -123 -3 -136 -3 -5
-1 -11 4 -15 6 -3 7 -15 2 -28 -5 -12 -5 -32 0 -44 4 -12 4 -25 0 -27 -5 -3
-6 -20 -2 -38 4 -18 4 -51 1 -73 -3 -22 -3 -53 0 -70 3 -16 3 -45 -1 -62 -4
-18 -3 -33 1 -33 5 0 5 -13 0 -30 -5 -18 -5 -30 0 -30 6 0 6 -10 0 -24 -5 -13
-6 -27 -2 -30 7 -8 5 -123 -3 -136 -3 -5 -1 -11 5 -15 6 -4 8 -11 4 -16 -8
-13 -9 -107 -1 -115 3 -3 2 -16 -3 -29 -5 -13 -6 -26 -3 -29 8 -7 10 -76 3
-76 -3 0 -4 -19 -2 -42 4 -51 4 -50 1 -111 -3 -72 -29 -103 -139 -160 -52 -27
-129 -66 -170 -88 -41 -21 -80 -39 -87 -39 -6 0 -13 -3 -15 -7 -1 -5 -45 -29
-96 -55 -51 -26 -141 -73 -200 -104 -225 -119 -303 -160 -507 -264 -115 -60
-223 -115 -240 -124 -16 -9 -35 -16 -42 -16 -6 0 -13 -3 -15 -8 -1 -4 -77 -45
-168 -91 -91 -46 -238 -121 -327 -167 -90 -46 -163 -79 -163 -73 0 13 117 245
142 282 11 15 16 27 11 27 -4 0 -3 4 2 8 6 4 21 29 35 55 14 27 30 56 35 65 6
10 34 58 63 107 84 143 90 151 201 320 92 140 236 347 266 382 5 6 21 26 35
44 38 50 223 282 235 295 5 6 35 40 65 75 122 141 308 337 424 448 32 31 84
81 116 111 65 62 174 159 215 192 15 12 37 31 49 42 11 12 55 48 96 81 41 33
84 68 95 78 11 10 32 26 48 35 15 9 28 21 28 27 1 5 5 -8 8 -30 4 -22 3 -55 0
-72z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -0,0 +1,2 @@
.ReactVirtualized__Table__headerRow{font-weight:700;text-transform:uppercase}.ReactVirtualized__Table__headerRow,.ReactVirtualized__Table__row{display:flex;flex-direction:row;align-items:center}.ReactVirtualized__Table__headerTruncatedText{display:inline-block;max-width:100%;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.ReactVirtualized__Table__headerColumn,.ReactVirtualized__Table__rowColumn{margin-right:10px;min-width:0}.ReactVirtualized__Table__rowColumn{text-overflow:ellipsis;white-space:nowrap}.ReactVirtualized__Table__headerColumn:first-of-type,.ReactVirtualized__Table__rowColumn:first-of-type{margin-left:10px}.ReactVirtualized__Table__sortableHeaderColumn{cursor:pointer}.ReactVirtualized__Table__sortableHeaderIconContainer{display:flex;align-items:center}.ReactVirtualized__Table__sortableHeaderIcon{flex:0 0 24px;height:1em;width:1em;fill:currentColor}.react-grid-layout{position:relative;transition:height .2s ease}.react-grid-item{transition:all .2s ease;transition-property:left,top}.react-grid-item img{pointer-events:none;-webkit-user-select:none;-ms-user-select:none;user-select:none}.react-grid-item.cssTransforms{transition-property:transform}.react-grid-item.resizing{z-index:1;will-change:width,height}.react-grid-item.react-draggable-dragging{transition:none;z-index:3;will-change:transform}.react-grid-item.dropping{visibility:hidden}.react-grid-item.react-grid-placeholder{background:red;opacity:.2;transition-duration:.1s;z-index:2;-webkit-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.react-grid-item>.react-resizable-handle{position:absolute;width:20px;height:20px}.react-grid-item>.react-resizable-handle:after{content:"";position:absolute;right:3px;bottom:3px;width:5px;height:5px;border-right:2px solid rgba(0,0,0,.4);border-bottom:2px solid rgba(0,0,0,.4)}.react-resizable-hide>.react-resizable-handle{display:none}.react-grid-item>.react-resizable-handle.react-resizable-handle-sw{bottom:0;left:0;cursor:sw-resize;transform:rotate(90deg)}.react-grid-item>.react-resizable-handle.react-resizable-handle-se{bottom:0;right:0;cursor:se-resize}.react-grid-item>.react-resizable-handle.react-resizable-handle-nw{top:0;left:0;cursor:nw-resize;transform:rotate(180deg)}.react-grid-item>.react-resizable-handle.react-resizable-handle-ne{top:0;right:0;cursor:ne-resize;transform:rotate(270deg)}.react-grid-item>.react-resizable-handle.react-resizable-handle-e,.react-grid-item>.react-resizable-handle.react-resizable-handle-w{top:50%;margin-top:-10px;cursor:ew-resize}.react-grid-item>.react-resizable-handle.react-resizable-handle-w{left:0;transform:rotate(135deg)}.react-grid-item>.react-resizable-handle.react-resizable-handle-e{right:0;transform:rotate(315deg)}.react-grid-item>.react-resizable-handle.react-resizable-handle-n,.react-grid-item>.react-resizable-handle.react-resizable-handle-s{left:50%;margin-left:-10px;cursor:ns-resize}.react-grid-item>.react-resizable-handle.react-resizable-handle-n{top:0;transform:rotate(225deg)}.react-grid-item>.react-resizable-handle.react-resizable-handle-s{bottom:0;transform:rotate(45deg)}.react-resizable{position:relative}.react-resizable-handle{position:absolute;width:20px;height:20px;background-repeat:no-repeat;background-origin:content-box;box-sizing:border-box;background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNmZmZmZmYwMCIgd2lkdGg9IjYiIGhlaWdodD0iNiI+PHBhdGggZD0iTTYgNkgwVjQuMmg0LjJWMEg2djZ6IiBvcGFjaXR5PSIuMzAyIi8+PC9zdmc+");background-position:100% 100%;padding:0 3px 3px 0}.react-resizable-handle-sw{bottom:0;left:0;cursor:sw-resize;transform:rotate(90deg)}.react-resizable-handle-se{bottom:0;right:0;cursor:se-resize}.react-resizable-handle-nw{top:0;left:0;cursor:nw-resize;transform:rotate(180deg)}.react-resizable-handle-ne{top:0;right:0;cursor:ne-resize;transform:rotate(270deg)}.react-resizable-handle-e,.react-resizable-handle-w{top:50%;margin-top:-10px;cursor:ew-resize}.react-resizable-handle-w{left:0;transform:rotate(135deg)}.react-resizable-handle-e{right:0;transform:rotate(315deg)}.react-resizable-handle-n,.react-resizable-handle-s{left:50%;margin-left:-10px;cursor:ns-resize}.react-resizable-handle-n{top:0;transform:rotate(225deg)}.react-resizable-handle-s{bottom:0;transform:rotate(45deg)}
/*# sourceMappingURL=2.f324abd6.chunk.css.map */

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,271 @@
/*
object-assign
(c) Sindre Sorhus
@license MIT
*/
/*!
Copyright (c) 2017 Jed Watson.
Licensed under the MIT License (MIT), see
http://jedwatson.github.io/classnames
*/
/*!
* Chart.js v2.9.4
* https://www.chartjs.org
* (c) 2020 Chart.js Contributors
* Released under the MIT License
*/
/*!
* cookie
* Copyright(c) 2012-2014 Roman Shtylman
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*! Conditions:: INITIAL */
/*! Moment Duration Format v2.2.2
* https://github.com/jsmreese/moment-duration-format
* Date: 2018-02-16
*
* Duration format plugin function for the Moment.js library
* http://momentjs.com/
*
* Copyright 2018 John Madhavan-Reese
* Released under the MIT license
*/
/*! Production:: $accept : expression $end */
/*! Production:: css_value : ANGLE */
/*! Production:: css_value : CHS */
/*! Production:: css_value : EMS */
/*! Production:: css_value : EXS */
/*! Production:: css_value : FREQ */
/*! Production:: css_value : LENGTH */
/*! Production:: css_value : PERCENTAGE */
/*! Production:: css_value : REMS */
/*! Production:: css_value : RES */
/*! Production:: css_value : SUB css_value */
/*! Production:: css_value : TIME */
/*! Production:: css_value : VHS */
/*! Production:: css_value : VMAXS */
/*! Production:: css_value : VMINS */
/*! Production:: css_value : VWS */
/*! Production:: css_variable : CSS_VAR LPAREN CSS_CPROP COMMA math_expression RPAREN */
/*! Production:: css_variable : CSS_VAR LPAREN CSS_CPROP RPAREN */
/*! Production:: expression : math_expression EOF */
/*! Production:: math_expression : LPAREN math_expression RPAREN */
/*! Production:: math_expression : NESTED_CALC LPAREN math_expression RPAREN */
/*! Production:: math_expression : SUB PREFIX SUB NESTED_CALC LPAREN math_expression RPAREN */
/*! Production:: math_expression : css_value */
/*! Production:: math_expression : css_variable */
/*! Production:: math_expression : math_expression ADD math_expression */
/*! Production:: math_expression : math_expression DIV math_expression */
/*! Production:: math_expression : math_expression MUL math_expression */
/*! Production:: math_expression : math_expression SUB math_expression */
/*! Production:: math_expression : value */
/*! Production:: value : NUMBER */
/*! Production:: value : SUB NUMBER */
/*! Rule:: $ */
/*! Rule:: (--[0-9a-z-A-Z-]*) */
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)% */
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)Hz\b */
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)\b */
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)ch\b */
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)cm\b */
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)deg\b */
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)dpcm\b */
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)dpi\b */
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)dppx\b */
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)em\b */
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)ex\b */
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)grad\b */
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)in\b */
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)kHz\b */
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)mm\b */
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)ms\b */
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)pc\b */
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)pt\b */
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)px\b */
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)rad\b */
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)rem\b */
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)s\b */
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)turn\b */
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)vh\b */
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)vmax\b */
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)vmin\b */
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)vw\b */
/*! Rule:: ([a-z]+) */
/*! Rule:: (calc) */
/*! Rule:: (var) */
/*! Rule:: , */
/*! Rule:: - */
/*! Rule:: \( */
/*! Rule:: \) */
/*! Rule:: \* */
/*! Rule:: \+ */
/*! Rule:: \/ */
/*! Rule:: \s+ */
/*! decimal.js-light v2.5.1 https://github.com/MikeMcl/decimal.js-light/LICENCE */
/**
* A better abstraction over CSS.
*
* @copyright Oleg Isonen (Slobodskoi) / Isonen 2014-present
* @website https://github.com/cssinjs/jss
* @license MIT
*/
/** @license React v0.20.1
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v16.13.1
* react-is.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v17.0.1
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v17.0.1
* react-is.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v17.0.1
* react-jsx-runtime.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v17.0.1
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**!
* @fileOverview Kickass library to create and place poppers near their reference elements.
* @version 1.16.1-lts
* @license
* Copyright (c) 2016 Federico Zivolo and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
//! moment.js

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More