From 833d08bb4095bcf40a8196d1ef9cc60e30f6a475 Mon Sep 17 00:00:00 2001 From: RamiBerm <54766858+RamiBerm@users.noreply.github.com> Date: Wed, 5 Jan 2022 17:50:27 +0200 Subject: [PATCH] TRA-4075 integrate kratos user management (#583) * WIP * WIP * WIP * WIP * Update App.tsx and Header.tsx * Update createResources.go, provider.go, and 2 more files... * WIP * fix eof newlines * Fix ts imports, add readiness probe to kratos to prevent mizu being used while kratos isnt ready * cleaned code * fix install create namespace * Update package-lock.json * Update provider.go * Update provider.go * Update provider.go * Update install_controller.go * Update kratos.yml * Update start.sh * Update provider.go * Update provider.go * Update main.go, socket_routes.go, and 8 more files... * Update App.tsx * Update installRunner.go * Update App.tsx --- acceptanceTests/go.sum | 7 +- agent/go.mod | 1 + agent/go.sum | 86 +++++++++- agent/kratos/Dockerfile | 14 ++ agent/kratos/build-push-featurebranch.sh | 28 +++ agent/kratos/identity.schema.json | 43 +++++ agent/kratos/kratos.yml | 84 +++++++++ agent/kratos/start.sh | 4 + agent/main.go | 21 +-- agent/pkg/api/socket_routes.go | 6 +- agent/pkg/controllers/install_controller.go | 18 ++ agent/pkg/controllers/user_controller.go | 39 +++++ agent/pkg/middlewares/cors.go | 19 ++ agent/pkg/middlewares/requiresAuth.go | 49 ++++++ agent/pkg/models/models.go | 4 + agent/pkg/providers/install_provider.go | 18 ++ agent/pkg/providers/user_provider.go | 162 ++++++++++++++++++ agent/pkg/routes/entries_routes.go | 2 + agent/pkg/routes/install_routes.go | 13 ++ agent/pkg/routes/metadata_routes.go | 3 +- agent/pkg/routes/query_routes.go | 2 + agent/pkg/routes/status_routes.go | 5 +- agent/pkg/routes/user_routes.go | 15 ++ cli/cmd/installRunner.go | 7 +- cli/cmd/tapRunner.go | 6 +- cli/resources/createResources.go | 11 +- shared/kubernetes/provider.go | 97 +++++++---- shared/kubernetes/proxy.go | 1 - ui/package-lock.json | 2 +- ui/src/App.sass | 14 +- ui/src/App.tsx | 108 ++++++++++-- .../AuthPresentation/AuthPresentation.tsx | 2 +- ui/src/components/EntriesList.tsx | 2 +- ui/src/components/Header/Header.tsx | 2 - ui/src/components/InstallPage.tsx | 60 +++++++ ui/src/components/LoadingOverlay.tsx | 25 +++ ui/src/components/LoginPage.tsx | 49 ++++++ ui/src/components/TLSWarning/TLSWarning.tsx | 2 +- ui/src/components/TrafficPage.tsx | 15 +- ui/src/components/style/LoadingOverlay.sass | 54 ++++++ ui/src/consts.ts | 1 + ui/src/helpers/api.js | 103 +++++++++-- 42 files changed, 1098 insertions(+), 106 deletions(-) create mode 100644 agent/kratos/Dockerfile create mode 100755 agent/kratos/build-push-featurebranch.sh create mode 100644 agent/kratos/identity.schema.json create mode 100755 agent/kratos/kratos.yml create mode 100755 agent/kratos/start.sh create mode 100644 agent/pkg/controllers/install_controller.go create mode 100644 agent/pkg/controllers/user_controller.go create mode 100644 agent/pkg/middlewares/cors.go create mode 100644 agent/pkg/middlewares/requiresAuth.go create mode 100644 agent/pkg/providers/install_provider.go create mode 100644 agent/pkg/providers/user_provider.go create mode 100644 agent/pkg/routes/install_routes.go create mode 100644 agent/pkg/routes/user_routes.go create mode 100644 ui/src/components/InstallPage.tsx create mode 100644 ui/src/components/LoadingOverlay.tsx create mode 100644 ui/src/components/LoginPage.tsx create mode 100644 ui/src/components/style/LoadingOverlay.sass create mode 100644 ui/src/consts.ts diff --git a/acceptanceTests/go.sum b/acceptanceTests/go.sum index 02e707750..825dbcd0f 100644 --- a/acceptanceTests/go.sum +++ b/acceptanceTests/go.sum @@ -75,6 +75,7 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsr github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= @@ -198,7 +199,6 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -321,6 +321,7 @@ github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -364,6 +365,7 @@ github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJ github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= @@ -373,6 +375,7 @@ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoH github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= @@ -579,6 +582,7 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -693,4 +697,5 @@ sigs.k8s.io/kustomize/kyaml v0.10.17/go.mod h1:mlQFagmkm1P+W4lZJbJ/yaxMd8PqMRSC4 sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.1.0 h1:C4r9BgJ98vrKnnVCjwCSXcWjWe0NKcUQkmzDXZXGwH8= sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/agent/go.mod b/agent/go.mod index a4ccbb693..2d58364fb 100644 --- a/agent/go.mod +++ b/agent/go.mod @@ -15,6 +15,7 @@ require ( github.com/gorilla/websocket v1.4.2 github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 github.com/orcaman/concurrent-map v0.0.0-20210106121528-16402b402231 + github.com/ory/kratos-client-go v0.8.2-alpha.1 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/up9inc/basenine/client/go v0.0.0-20211215185650-10083bb9a1b3 github.com/up9inc/mizu/shared v0.0.0 diff --git a/agent/go.sum b/agent/go.sum index ed288cfc1..d73bf64fa 100644 --- a/agent/go.sum +++ b/agent/go.sum @@ -8,20 +8,30 @@ cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0 h1:3ithwDMr7/3vpAMXiH+ZQnYbuIsh+OPhUPMFC9enmn0= cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0 h1:Dg9iHVQfrhq82rUNu9ZxUDrJLaxFUe/HlCVaLyRruq8= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= @@ -76,6 +86,7 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -101,7 +112,9 @@ github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3 github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses= @@ -123,14 +136,11 @@ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm github.com/gin-contrib/static v0.0.1 h1:JVxuvHPuUfkoul12N7dtQw7KRn/pSMq7Ue1Va9Swm1U= github.com/gin-contrib/static v0.0.1/go.mod h1:CSxeF+wep05e0kCOsqWdAWbSszmc31zTIbD8TvWl7Hs= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= -github.com/gin-gonic/gin v1.7.2 h1:Tg03T9yM2xa8j6I3Z3oqLaQRSmKvxPd6g/2HJ6zICFA= -github.com/gin-gonic/gin v1.7.2/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs= github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-errors/errors v1.4.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -215,11 +225,14 @@ github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= @@ -236,7 +249,9 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -247,11 +262,14 @@ github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -376,6 +394,8 @@ github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWEr github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/orcaman/concurrent-map v0.0.0-20210106121528-16402b402231 h1:fa50YL1pzKW+1SsBnJDOHppJN9stOEwS+CRWyUtyYGU= github.com/orcaman/concurrent-map v0.0.0-20210106121528-16402b402231/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CFcDWnWD9XkenwhI= +github.com/ory/kratos-client-go v0.8.2-alpha.1 h1:YlKhGOSZjounlB9iY4xSWlqHbyLYkeLzlLk8ZL7/nEM= +github.com/ory/kratos-client-go v0.8.2-alpha.1/go.mod h1:dOQIsar76K07wMPJD/6aMhrWyY+sFGEagLDLso1CpsA= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= @@ -462,7 +482,9 @@ github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6Ut github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY= github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= @@ -472,6 +494,7 @@ go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= @@ -539,6 +562,7 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -548,6 +572,13 @@ golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210224082022-3d97a244fca7 h1:OgUuv8lsRpBibGNbSizVwKWlysjaNzmC9gYMhPVfqFM= @@ -556,14 +587,17 @@ golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAG golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558 h1:D7nTwh4J0i+5mW4Zjzn5omvlr6YBcWywE6KOcatyNxY= +golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -599,7 +633,13 @@ golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -659,9 +699,19 @@ golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -678,13 +728,20 @@ google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsb google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -702,16 +759,31 @@ google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -720,6 +792,7 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= @@ -756,6 +829,7 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.21.2 h1:vz7DqmRsXTCSa6pNxXwQ1IYeAZgdIsua+DZU+o+SX3Y= k8s.io/api v0.21.2/go.mod h1:Lv6UGJZ1rlMI1qusN8ruAp9PUBFyBwpEHAdG24vIsiU= k8s.io/apimachinery v0.21.2 h1:vezUc/BHqWlQDnZ+XkrpXSmnANSLbpnlpwo0Lhk0gpc= diff --git a/agent/kratos/Dockerfile b/agent/kratos/Dockerfile new file mode 100644 index 000000000..086a1a992 --- /dev/null +++ b/agent/kratos/Dockerfile @@ -0,0 +1,14 @@ +FROM oryd/kratos:v0.8.0-sqlite + +USER root + +RUN apk add sqlite + +RUN mkdir -p /etc/config/kratos + +COPY ./kratos.yml /etc/config/kratos/kratos.yml +COPY ./identity.schema.json /etc/config/kratos/identity.schema.json +COPY ./start.sh /opt/start.sh +RUN chmod +x /opt/start.sh + +ENTRYPOINT ["/opt/start.sh"] diff --git a/agent/kratos/build-push-featurebranch.sh b/agent/kratos/build-push-featurebranch.sh new file mode 100755 index 000000000..069114c23 --- /dev/null +++ b/agent/kratos/build-push-featurebranch.sh @@ -0,0 +1,28 @@ +#!/bin/bash +set -e + +GCP_PROJECT=up9-docker-hub +REPOSITORY=gcr.io/$GCP_PROJECT +SERVER_NAME=mizu-kratos +GIT_BRANCH=$(git branch | grep \* | cut -d ' ' -f2 | tr '[:upper:]' '[:lower:]') + +DOCKER_REPO=$REPOSITORY/$SERVER_NAME/$GIT_BRANCH +SEM_VER=${SEM_VER=0.0.0} + +DOCKER_TAGGED_BUILDS=("$DOCKER_REPO:latest" "$DOCKER_REPO:$SEM_VER") + +if [ "$GIT_BRANCH" = 'develop' -o "$GIT_BRANCH" = 'master' -o "$GIT_BRANCH" = 'main' ] +then + echo "Pushing to $GIT_BRANCH is allowed only via CI" + exit 1 +fi + +echo "building ${DOCKER_TAGGED_BUILDS[@]}" +DOCKER_TAGS_ARGS=$(echo ${DOCKER_TAGGED_BUILDS[@]/#/-t }) # "-t FIRST_TAG -t SECOND_TAG ..." +docker build $DOCKER_TAGS_ARGS --build-arg SEM_VER=${SEM_VER} --build-arg BUILD_TIMESTAMP=${BUILD_TIMESTAMP} --build-arg GIT_BRANCH=${GIT_BRANCH} --build-arg COMMIT_HASH=${COMMIT_HASH} . + +for DOCKER_TAG in "${DOCKER_TAGGED_BUILDS[@]}" +do + echo pushing "$DOCKER_TAG" + docker push "$DOCKER_TAG" +done diff --git a/agent/kratos/identity.schema.json b/agent/kratos/identity.schema.json new file mode 100644 index 000000000..318322299 --- /dev/null +++ b/agent/kratos/identity.schema.json @@ -0,0 +1,43 @@ +{ + "$id": "https://schemas.ory.sh/presets/kratos/quickstart/email-password/identity.schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Person", + "type": "object", + "properties": { + "traits": { + "type": "object", + "properties": { + "username": { + "type": "string", + "format": "username", + "title": "Username", + "minLength": 3, + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + } + } + } + }, + "name": { + "type": "object", + "properties": { + "first": { + "title": "First Name", + "type": "string" + }, + "last": { + "title": "Last Name", + "type": "string" + } + } + } + }, + "required": [ + "username" + ], + "additionalProperties": false + } + } +} diff --git a/agent/kratos/kratos.yml b/agent/kratos/kratos.yml new file mode 100755 index 000000000..a2362c24a --- /dev/null +++ b/agent/kratos/kratos.yml @@ -0,0 +1,84 @@ +version: v0.8.2-alpha.1 + +dsn: sqlite:///app/data/kratos.sqlite?_fk=true + +serve: + public: + base_url: http://127.0.0.1:4433/ + cors: + enabled: true + admin: + base_url: http://kratos:4434/ + +selfservice: + default_browser_return_url: http://127.0.0.1:4455/ + whitelisted_return_urls: + - http://127.0.0.1:4455 + + methods: + password: + enabled: true + + flows: + error: + ui_url: http://127.0.0.1:4455/error + + settings: + ui_url: http://127.0.0.1:4455/settings + privileged_session_max_age: 15m + + recovery: + enabled: true + ui_url: http://127.0.0.1:4455/recovery + + verification: + enabled: false + ui_url: http://127.0.0.1:4455/verification + after: + default_browser_return_url: http://127.0.0.1:4455/ + + logout: + after: + default_browser_return_url: http://127.0.0.1:4455/login + + login: + ui_url: http://127.0.0.1:4455/login + lifespan: 10m + + registration: + lifespan: 10m + ui_url: http://127.0.0.1:4455/registration + after: + password: + hooks: + - + hook: session + +log: + level: info + format: text + leak_sensitive_values: true + +secrets: + cookie: + - PLEASE-CHANGE-ME-I-AM-VERY-INSECURE + cipher: + - 32-LONG-SECRET-NOT-SECURE-AT-ALL + +ciphers: + algorithm: xchacha20-poly1305 + +hashers: + argon2: + parallelism: 1 + memory: 128MB + iterations: 2 + salt_length: 16 + key_length: 16 + +identity: + default_schema_url: file:///etc/config/kratos/identity.schema.json + +courier: + smtp: + connection_uri: smtps://test:test@mailslurper:1025/?skip_ssl_verify=true diff --git a/agent/kratos/start.sh b/agent/kratos/start.sh new file mode 100755 index 000000000..d81af188e --- /dev/null +++ b/agent/kratos/start.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +kratos migrate sql sqlite:///app/data/kratos.sqlite?_fk=true --yes # this initializes the db +kratos serve -c /etc/config/kratos/kratos.yml --watch-courier # start kratos diff --git a/agent/main.go b/agent/main.go index c6be71870..e8d815ff3 100644 --- a/agent/main.go +++ b/agent/main.go @@ -9,6 +9,7 @@ import ( "mizuserver/pkg/api" "mizuserver/pkg/config" "mizuserver/pkg/controllers" + "mizuserver/pkg/middlewares" "mizuserver/pkg/models" "mizuserver/pkg/routes" "mizuserver/pkg/up9" @@ -256,12 +257,14 @@ func hostApi(socketHarOutputChannel chan<- *tapApi.OutputChannelItem) { } app.Use(static.ServeRoot("/", "./site")) - app.Use(CORSMiddleware()) // This has to be called after the static middleware, does not work if its called before + app.Use(middlewares.CORSMiddleware()) // This has to be called after the static middleware, does not work if its called before api.WebSocketRoutes(app, &eventHandlers, startTime) if config.Config.StandaloneMode { routes.ConfigRoutes(app) + routes.UserRoutes(app) + routes.InstallRoutes(app) } routes.QueryRoutes(app) @@ -284,22 +287,6 @@ func DisableRootStaticCache() gin.HandlerFunc { } } -func CORSMiddleware() gin.HandlerFunc { - return func(c *gin.Context) { - c.Writer.Header().Set("Access-Control-Allow-Origin", "*") - c.Writer.Header().Set("Access-Control-Allow-Credentials", "true") - c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With") - c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT") - - if c.Request.Method == "OPTIONS" { - c.AbortWithStatus(204) - return - } - - c.Next() - } -} - func setUIMode() error { read, err := ioutil.ReadFile(uiIndexPath) if err != nil { diff --git a/agent/pkg/api/socket_routes.go b/agent/pkg/api/socket_routes.go index 89e8f45f0..41a1064e6 100644 --- a/agent/pkg/api/socket_routes.go +++ b/agent/pkg/api/socket_routes.go @@ -4,6 +4,7 @@ import ( "encoding/json" "errors" "fmt" + "mizuserver/pkg/middlewares" "mizuserver/pkg/models" "net/http" "sync" @@ -47,8 +48,9 @@ func init() { func WebSocketRoutes(app *gin.Engine, eventHandlers EventHandlers, startTime int64) { app.GET("/ws", func(c *gin.Context) { websocketHandler(c.Writer, c.Request, eventHandlers, false, startTime) - }) - app.GET("/wsTapper", func(c *gin.Context) { + }, middlewares.RequiresAuth()) + + app.GET("/wsTapper", func(c *gin.Context) { // TODO: add m2m authentication to this route websocketHandler(c.Writer, c.Request, eventHandlers, true, startTime) }) } diff --git a/agent/pkg/controllers/install_controller.go b/agent/pkg/controllers/install_controller.go new file mode 100644 index 000000000..843546bd4 --- /dev/null +++ b/agent/pkg/controllers/install_controller.go @@ -0,0 +1,18 @@ +package controllers + +import ( + "mizuserver/pkg/providers" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/up9inc/mizu/shared/logger" +) + +func IsSetupNecessary(c *gin.Context) { + if IsInstallNeeded, err := providers.IsInstallNeeded(); err != nil { + logger.Log.Errorf("unknown internal while checking if install is needed %s", err) + c.AbortWithStatusJSON(500, gin.H{"error": "internal error occured while checking if install is needed"}) + } else { + c.JSON(http.StatusOK, IsInstallNeeded) + } +} diff --git a/agent/pkg/controllers/user_controller.go b/agent/pkg/controllers/user_controller.go new file mode 100644 index 000000000..6232dfa1e --- /dev/null +++ b/agent/pkg/controllers/user_controller.go @@ -0,0 +1,39 @@ +package controllers + +import ( + "mizuserver/pkg/providers" + + "github.com/gin-gonic/gin" + "github.com/up9inc/mizu/shared/logger" +) + +func Login(c *gin.Context) { + if token, err := providers.PerformLogin(c.PostForm("username"), c.PostForm("password"), c.Request.Context()); err != nil { + c.AbortWithStatusJSON(401, gin.H{"error": "bad login"}) + } else { + c.JSON(200, gin.H{"token": token}) + } +} + +func Logout(c *gin.Context) { + token := c.GetHeader("x-session-token") + if err := providers.Logout(token, c.Request.Context()); err != nil { + c.AbortWithStatusJSON(401, gin.H{"error": "error occured while logging out, the session might still be valid"}) + } else { + c.JSON(200, "") + } +} + +func Register(c *gin.Context) { + if token, _, err, formErrorMessages := providers.RegisterUser(c.PostForm("username"), c.PostForm("password"), c.Request.Context()); err != nil { + if formErrorMessages != nil { + logger.Log.Infof("user attempted to register but had form errors %v %v", formErrorMessages, err) + c.AbortWithStatusJSON(400, formErrorMessages) + } else { + logger.Log.Errorf("unknown internal error registering user %s", err) + c.AbortWithStatusJSON(500, gin.H{"error": "internal error occured while registering"}) + } + } else { + c.JSON(200, gin.H{"token": token}) + } +} diff --git a/agent/pkg/middlewares/cors.go b/agent/pkg/middlewares/cors.go new file mode 100644 index 000000000..0e6d7d36e --- /dev/null +++ b/agent/pkg/middlewares/cors.go @@ -0,0 +1,19 @@ +package middlewares + +import "github.com/gin-gonic/gin" + +func CORSMiddleware() gin.HandlerFunc { + return func(c *gin.Context) { + c.Writer.Header().Set("Access-Control-Allow-Origin", "*") + c.Writer.Header().Set("Access-Control-Allow-Credentials", "true") + c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With") + c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT") + + if c.Request.Method == "OPTIONS" { + c.AbortWithStatus(204) + return + } + + c.Next() + } +} diff --git a/agent/pkg/middlewares/requiresAuth.go b/agent/pkg/middlewares/requiresAuth.go new file mode 100644 index 000000000..08c5079b4 --- /dev/null +++ b/agent/pkg/middlewares/requiresAuth.go @@ -0,0 +1,49 @@ +package middlewares + +import ( + "mizuserver/pkg/config" + "mizuserver/pkg/providers" + "time" + + "github.com/gin-gonic/gin" + "github.com/patrickmn/go-cache" + "github.com/up9inc/mizu/shared/logger" +) + +const cachedValidTokensRetainmentTime = time.Minute * 1 + +var cachedValidTokens = cache.New(cachedValidTokensRetainmentTime, cachedValidTokensRetainmentTime) + +func RequiresAuth() gin.HandlerFunc { + return func(c *gin.Context) { + // auth is irrelevant for ephermeral mizu + if !config.Config.StandaloneMode { + c.Next() + return + } + + token := c.GetHeader("x-session-token") + if token == "" { + c.AbortWithStatusJSON(401, gin.H{"error": "token header is empty"}) + return + } + + if _, isTokenCached := cachedValidTokens.Get(token); isTokenCached { + c.Next() + return + } + + if isTokenValid, err := providers.VerifyToken(token, c.Request.Context()); err != nil { + logger.Log.Errorf("error verifying token %s", err) + c.AbortWithStatusJSON(401, gin.H{"error": "unknown auth error occured"}) + return + } else if !isTokenValid { + c.AbortWithStatusJSON(401, gin.H{"error": "invalid token"}) + return + } + + cachedValidTokens.Set(token, true, cachedValidTokensRetainmentTime) + + c.Next() + } +} diff --git a/agent/pkg/models/models.go b/agent/pkg/models/models.go index cf714519e..3ed193db2 100644 --- a/agent/pkg/models/models.go +++ b/agent/pkg/models/models.go @@ -159,3 +159,7 @@ func RunValidationRulesState(harEntry har.Entry, service string) (tapApi.Applica statusPolicyToSend, latency, numberOfRules := rules.PassedValidationRules(resultPolicyToSend) return tapApi.ApplicableRules{Status: statusPolicyToSend, Latency: latency, NumberOfRules: numberOfRules}, resultPolicyToSend, isEnabled } + +type InstallState struct { + Completed bool `json:"completed"` +} diff --git a/agent/pkg/providers/install_provider.go b/agent/pkg/providers/install_provider.go new file mode 100644 index 000000000..5e2590a9d --- /dev/null +++ b/agent/pkg/providers/install_provider.go @@ -0,0 +1,18 @@ +package providers + +import ( + "context" + "mizuserver/pkg/config" +) + +func IsInstallNeeded() (bool, error) { + if !config.Config.StandaloneMode { // install not needed in ephermeral mizu + return false, nil + } + + if anyUserExists, err := AnyUserExists(context.Background()); err != nil { + return false, err + } else { + return !anyUserExists, nil + } +} diff --git a/agent/pkg/providers/user_provider.go b/agent/pkg/providers/user_provider.go new file mode 100644 index 000000000..71b994c19 --- /dev/null +++ b/agent/pkg/providers/user_provider.go @@ -0,0 +1,162 @@ +package providers + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "net/http" + "net/http/cookiejar" + + ory "github.com/ory/kratos-client-go" + "github.com/up9inc/mizu/shared/logger" +) + +var client = getKratosClient("http://127.0.0.1:4433", "http://127.0.0.1:4434") + +// returns session token if successful +func RegisterUser(username string, password string, ctx context.Context) (token *string, identityId string, err error, formErrorMessages map[string][]ory.UiText) { + flow, _, err := client.V0alpha2Api.InitializeSelfServiceRegistrationFlowWithoutBrowser(ctx).Execute() + if err != nil { + return nil, "", err, nil + } + + result, _, err := client.V0alpha2Api.SubmitSelfServiceRegistrationFlow(ctx).Flow(flow.Id).SubmitSelfServiceRegistrationFlowBody( + ory.SubmitSelfServiceRegistrationFlowWithPasswordMethodBodyAsSubmitSelfServiceRegistrationFlowBody(&ory.SubmitSelfServiceRegistrationFlowWithPasswordMethodBody{ + Method: "password", + Password: password, + Traits: map[string]interface{}{"username": username}, + }), + ).Execute() + + if err != nil { + parsedKratosError, parsingErr := parseKratosRegistrationFormError(err) + if parsingErr != nil { + logger.Log.Debugf("error parsing kratos error: %v", parsingErr) + return nil, "", err, nil + } else { + return nil, "", err, parsedKratosError + } + } + + return result.SessionToken, result.Identity.Id, nil, nil +} + +func PerformLogin(username string, password string, ctx context.Context) (*string, error) { + flow, _, err := client.V0alpha2Api.InitializeSelfServiceLoginFlowWithoutBrowser(ctx).Execute() + if err != nil { + return nil, err + } + + result, _, err := client.V0alpha2Api.SubmitSelfServiceLoginFlow(ctx).Flow(flow.Id).SubmitSelfServiceLoginFlowBody( + ory.SubmitSelfServiceLoginFlowWithPasswordMethodBodyAsSubmitSelfServiceLoginFlowBody(&ory.SubmitSelfServiceLoginFlowWithPasswordMethodBody{ + Method: "password", + Password: password, + PasswordIdentifier: username, + }), + ).Execute() + + if err != nil { + return nil, err + } + if result == nil { + return nil, errors.New("unknown error occured during login") + } + + return result.SessionToken, nil +} + +func VerifyToken(token string, ctx context.Context) (bool, error) { + flow, _, err := client.V0alpha2Api.ToSession(ctx).XSessionToken(token).Execute() + if err != nil { + return false, err + } + + if flow == nil { + return false, nil + } + + return true, nil +} + +func DeleteUser(identityId string, ctx context.Context) error { + result, err := client.V0alpha2Api.AdminDeleteIdentity(ctx, identityId).Execute() + if err != nil { + return err + } + if result == nil { + return errors.New("unknown error occured during user deletion") + } + + if result.StatusCode < 200 || result.StatusCode > 299 { + return errors.New(fmt.Sprintf("user deletion returned bad status %d", result.StatusCode)) + } else { + return nil + } +} + +func AnyUserExists(ctx context.Context) (bool, error) { + request := client.V0alpha2Api.AdminListIdentities(ctx) + request.PerPage(1) + + if result, _, err := request.Execute(); err != nil { + return false, err + } else { + return len(result) > 0, nil + } +} + +func Logout(token string, ctx context.Context) error { + logoutRequest := client.V0alpha2Api.SubmitSelfServiceLogoutFlowWithoutBrowser(ctx) + logoutRequest.SubmitSelfServiceLogoutFlowWithoutBrowserBody(ory.SubmitSelfServiceLogoutFlowWithoutBrowserBody{ + SessionToken: token, + }) + if response, err := logoutRequest.Execute(); err != nil { + return err + } else if response == nil || response.StatusCode < 200 || response.StatusCode > 299 { + return errors.New("unknown error occured during logout") + } + + return nil +} + +func getKratosClient(url string, adminUrl string) *ory.APIClient { + conf := ory.NewConfiguration() + conf.Servers = ory.ServerConfigurations{{URL: url}} + + // this ensures kratos client uses the admin url for admin actions (any new admin action we use will have to be added here) + conf.OperationServers = map[string]ory.ServerConfigurations{ + "V0alpha2ApiService.AdminDeleteIdentity": {{URL: adminUrl}}, + "V0alpha2ApiService.AdminListIdentities": {{URL: adminUrl}}, + } + + cj, _ := cookiejar.New(nil) + conf.HTTPClient = &http.Client{Jar: cj} + return ory.NewAPIClient(conf) +} + +// returns map of form value key to error message +func parseKratosRegistrationFormError(err error) (map[string][]ory.UiText, error) { + var openApiError *ory.GenericOpenAPIError + if errors.As(err, &openApiError) { + var registrationFlowModel *ory.SelfServiceRegistrationFlow + if jsonErr := json.Unmarshal(openApiError.Body(), ®istrationFlowModel); jsonErr != nil { + return nil, jsonErr + } else { + formMessages := registrationFlowModel.Ui.Nodes + parsedMessages := make(map[string][]ory.UiText) + + for _, message := range formMessages { + if len(message.Messages) > 0 { + if _, ok := parsedMessages[message.Group]; !ok { + parsedMessages[message.Group] = make([]ory.UiText, 0) + } + parsedMessages[message.Group] = append(parsedMessages[message.Group], message.Messages...) + } + } + return parsedMessages, nil + } + } else { + return nil, errors.New("error is not a generic openapi error") + } +} diff --git a/agent/pkg/routes/entries_routes.go b/agent/pkg/routes/entries_routes.go index d931196a9..75956d6f1 100644 --- a/agent/pkg/routes/entries_routes.go +++ b/agent/pkg/routes/entries_routes.go @@ -2,6 +2,7 @@ package routes import ( "mizuserver/pkg/controllers" + "mizuserver/pkg/middlewares" "github.com/gin-gonic/gin" ) @@ -9,6 +10,7 @@ import ( // EntriesRoutes defines the group of har entries routes. func EntriesRoutes(ginApp *gin.Engine) { routeGroup := ginApp.Group("/entries") + routeGroup.Use(middlewares.RequiresAuth()) routeGroup.GET("/", controllers.GetEntries) // get entries (base/thin entries) and metadata routeGroup.GET("/:id", controllers.GetEntry) // get single (full) entry diff --git a/agent/pkg/routes/install_routes.go b/agent/pkg/routes/install_routes.go new file mode 100644 index 000000000..83b28cdd8 --- /dev/null +++ b/agent/pkg/routes/install_routes.go @@ -0,0 +1,13 @@ +package routes + +import ( + "mizuserver/pkg/controllers" + + "github.com/gin-gonic/gin" +) + +func InstallRoutes(ginApp *gin.Engine) { + routeGroup := ginApp.Group("/install") + + routeGroup.GET("/isNeeded", controllers.IsSetupNecessary) +} diff --git a/agent/pkg/routes/metadata_routes.go b/agent/pkg/routes/metadata_routes.go index 4f32ff771..9a3c21b91 100644 --- a/agent/pkg/routes/metadata_routes.go +++ b/agent/pkg/routes/metadata_routes.go @@ -1,8 +1,9 @@ package routes import ( - "github.com/gin-gonic/gin" "mizuserver/pkg/controllers" + + "github.com/gin-gonic/gin" ) // MetadataRoutes defines the group of metadata routes. diff --git a/agent/pkg/routes/query_routes.go b/agent/pkg/routes/query_routes.go index 2807bd0b6..7ad8d0490 100644 --- a/agent/pkg/routes/query_routes.go +++ b/agent/pkg/routes/query_routes.go @@ -2,12 +2,14 @@ package routes import ( "mizuserver/pkg/controllers" + "mizuserver/pkg/middlewares" "github.com/gin-gonic/gin" ) func QueryRoutes(ginApp *gin.Engine) { routeGroup := ginApp.Group("/query") + routeGroup.Use(middlewares.RequiresAuth()) routeGroup.POST("/validate", controllers.PostValidate) } diff --git a/agent/pkg/routes/status_routes.go b/agent/pkg/routes/status_routes.go index dd601213d..4d2a6a90f 100644 --- a/agent/pkg/routes/status_routes.go +++ b/agent/pkg/routes/status_routes.go @@ -1,12 +1,15 @@ package routes import ( - "github.com/gin-gonic/gin" "mizuserver/pkg/controllers" + "mizuserver/pkg/middlewares" + + "github.com/gin-gonic/gin" ) func StatusRoutes(ginApp *gin.Engine) { routeGroup := ginApp.Group("/status") + routeGroup.Use(middlewares.RequiresAuth()) routeGroup.GET("/health", controllers.HealthCheck) diff --git a/agent/pkg/routes/user_routes.go b/agent/pkg/routes/user_routes.go new file mode 100644 index 000000000..6b2090dd3 --- /dev/null +++ b/agent/pkg/routes/user_routes.go @@ -0,0 +1,15 @@ +package routes + +import ( + "mizuserver/pkg/controllers" + + "github.com/gin-gonic/gin" +) + +func UserRoutes(ginApp *gin.Engine) { + routeGroup := ginApp.Group("/user") + + routeGroup.POST("/login", controllers.Login) + routeGroup.POST("/logout", controllers.Logout) + routeGroup.POST("/register", controllers.Register) +} diff --git a/cli/cmd/installRunner.go b/cli/cmd/installRunner.go index 5062fd557..9c5108bd3 100644 --- a/cli/cmd/installRunner.go +++ b/cli/cmd/installRunner.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "github.com/creasty/defaults" "github.com/up9inc/mizu/cli/config" "github.com/up9inc/mizu/cli/errormessage" @@ -21,6 +22,10 @@ func runMizuInstall() { return } + if config.Config.IsNsRestrictedMode() { + logger.Log.Error("install is not supported in restricted namespace mode") + } + ctx, cancel := context.WithCancel(context.Background()) defer cancel() // cancel will be called when this function exits @@ -47,7 +52,7 @@ func runMizuInstall() { var statusError *k8serrors.StatusError if errors.As(err, &statusError) { if statusError.ErrStatus.Reason == metav1.StatusReasonAlreadyExists { - logger.Log.Info("Mizu is already running in this namespace, change the `mizu-resources-namespace` configuration or run `mizu clean` to remove the currently running Mizu instance") + logger.Log.Info("Mizu is already running in this namespace, run `mizu clean` to remove the currently running Mizu instance") } } else { defer resources.CleanUpMizuResources(ctx, cancel, kubernetesProvider, config.Config.IsNsRestrictedMode(), config.Config.MizuResourcesNamespace) diff --git a/cli/cmd/tapRunner.go b/cli/cmd/tapRunner.go index 44ac2532f..5cc51556c 100644 --- a/cli/cmd/tapRunner.go +++ b/cli/cmd/tapRunner.go @@ -4,13 +4,14 @@ import ( "context" "errors" "fmt" - "github.com/up9inc/mizu/cli/resources" - "github.com/up9inc/mizu/cli/utils" "io/ioutil" "regexp" "strings" "time" + "github.com/up9inc/mizu/cli/resources" + "github.com/up9inc/mizu/cli/utils" + "github.com/getkin/kin-openapi/openapi3" "gopkg.in/yaml.v3" core "k8s.io/api/core/v1" @@ -124,6 +125,7 @@ func RunMizuTap() { logger.Log.Infof("Waiting for Mizu Agent to start...") if state.mizuServiceAccountExists, err = resources.CreateTapMizuResources(ctx, kubernetesProvider, serializedValidationRules, serializedContract, serializedMizuConfig, config.Config.IsNsRestrictedMode(), config.Config.MizuResourcesNamespace, config.Config.AgentImage, getSyncEntriesConfig(), config.Config.Tap.MaxEntriesDBSizeBytes(), config.Config.Tap.ApiServerResources, config.Config.ImagePullPolicy(), config.Config.LogLevel()); err != nil { + logger.Log.Errorf("error %v", err) var statusError *k8serrors.StatusError if errors.As(err, &statusError) { if statusError.ErrStatus.Reason == metav1.StatusReasonAlreadyExists { diff --git a/cli/resources/createResources.go b/cli/resources/createResources.go index 852b08f6c..ce238a9ea 100644 --- a/cli/resources/createResources.go +++ b/cli/resources/createResources.go @@ -3,6 +3,7 @@ package resources import ( "context" "fmt" + "github.com/op/go-logging" "github.com/up9inc/mizu/cli/errormessage" "github.com/up9inc/mizu/cli/mizu" @@ -65,6 +66,12 @@ func CreateTapMizuResources(ctx context.Context, kubernetesProvider *kubernetes. } func CreateInstallMizuResources(ctx context.Context, kubernetesProvider *kubernetes.Provider, serializedValidationRules string, serializedContract string, serializedMizuConfig string, isNsRestrictedMode bool, mizuResourcesNamespace string, agentImage string, syncEntriesConfig *shared.SyncEntriesConfig, maxEntriesDBSizeBytes int64, apiServerResources shared.Resources, imagePullPolicy core.PullPolicy, logLevel logging.Level, noPersistentVolumeClaim bool) error { + if !isNsRestrictedMode { + if err := createMizuNamespace(ctx, kubernetesProvider, mizuResourcesNamespace); err != nil { + return err + } + } + if err := createMizuConfigmap(ctx, kubernetesProvider, serializedValidationRules, serializedContract, serializedMizuConfig, mizuResourcesNamespace); err != nil { return err } @@ -137,7 +144,7 @@ func createMizuApiServerDeployment(ctx context.Context, kubernetesProvider *kube volumeClaimCreated = tryToCreatePersistentVolumeClaim(ctx, kubernetesProvider, opts) } - pod, err := kubernetesProvider.GetMizuApiServerPodObject(opts, volumeClaimCreated, kubernetes.PersistentVolumeClaimName) + pod, err := kubernetesProvider.GetMizuApiServerPodObject(opts, volumeClaimCreated, kubernetes.PersistentVolumeClaimName, true) if err != nil { return err } @@ -179,7 +186,7 @@ func tryToCreatePersistentVolumeClaim(ctx context.Context, kubernetesProvider *k } func createMizuApiServerPod(ctx context.Context, kubernetesProvider *kubernetes.Provider, opts *kubernetes.ApiServerOptions) error { - pod, err := kubernetesProvider.GetMizuApiServerPodObject(opts, false, "") + pod, err := kubernetesProvider.GetMizuApiServerPodObject(opts, false, "", false) if err != nil { return err } diff --git a/shared/kubernetes/provider.go b/shared/kubernetes/provider.go index 44827da78..072ea00f3 100644 --- a/shared/kubernetes/provider.go +++ b/shared/kubernetes/provider.go @@ -186,7 +186,7 @@ type ApiServerOptions struct { LogLevel logging.Level } -func (provider *Provider) GetMizuApiServerPodObject(opts *ApiServerOptions, mountVolumeClaim bool, volumeClaimName string) (*core.Pod, error) { +func (provider *Provider) GetMizuApiServerPodObject(opts *ApiServerOptions, mountVolumeClaim bool, volumeClaimName string, createAuthContainer bool) (*core.Pod, error) { var marshaledSyncEntriesConfig []byte if opts.SyncEntriesConfig != nil { var err error @@ -250,6 +250,69 @@ func (provider *Provider) GetMizuApiServerPodObject(opts *ApiServerOptions, moun }) } + containers := []core.Container{ + { + Name: opts.PodName, + Image: opts.PodImage, + ImagePullPolicy: opts.ImagePullPolicy, + VolumeMounts: volumeMounts, + Command: command, + Env: []core.EnvVar{ + { + Name: shared.SyncEntriesConfigEnvVar, + Value: string(marshaledSyncEntriesConfig), + }, + { + Name: shared.LogLevelEnvVar, + Value: opts.LogLevel.String(), + }, + }, + Resources: core.ResourceRequirements{ + Limits: core.ResourceList{ + "cpu": cpuLimit, + "memory": memLimit, + }, + Requests: core.ResourceList{ + "cpu": cpuRequests, + "memory": memRequests, + }, + }, + }, + } + + if createAuthContainer { + containers = append(containers, core.Container{ + Name: "kratos", + Image: "gcr.io/up9-docker-hub/mizu-kratos/stable:0.0.0", + ImagePullPolicy: opts.ImagePullPolicy, + VolumeMounts: volumeMounts, + ReadinessProbe: &core.Probe{ + FailureThreshold: 3, + Handler: core.Handler{ + HTTPGet: &core.HTTPGetAction{ + Path: "/health/ready", + Port: intstr.FromInt(4433), + Scheme: core.URISchemeHTTP, + }, + }, + PeriodSeconds: 1, + SuccessThreshold: 1, + TimeoutSeconds: 1, + }, + Resources: core.ResourceRequirements{ + Limits: core.ResourceList{ + "cpu": cpuLimit, + "memory": memLimit, + }, + Requests: core.ResourceList{ + "cpu": cpuRequests, + "memory": memRequests, + }, + }, + }) + + } + pod := &core.Pod{ ObjectMeta: metav1.ObjectMeta{ Name: opts.PodName, @@ -260,35 +323,7 @@ func (provider *Provider) GetMizuApiServerPodObject(opts *ApiServerOptions, moun }, }, Spec: core.PodSpec{ - Containers: []core.Container{ - { - Name: opts.PodName, - Image: opts.PodImage, - ImagePullPolicy: opts.ImagePullPolicy, - VolumeMounts: volumeMounts, - Command: command, - Env: []core.EnvVar{ - { - Name: shared.SyncEntriesConfigEnvVar, - Value: string(marshaledSyncEntriesConfig), - }, - { - Name: shared.LogLevelEnvVar, - Value: opts.LogLevel.String(), - }, - }, - Resources: core.ResourceRequirements{ - Limits: core.ResourceList{ - "cpu": cpuLimit, - "memory": memLimit, - }, - Requests: core.ResourceList{ - "cpu": cpuRequests, - "memory": memRequests, - }, - }, - }, - }, + Containers: containers, Volumes: volumes, DNSPolicy: core.DNSClusterFirstWithHostNet, TerminationGracePeriodSeconds: new(int64), @@ -343,7 +378,7 @@ func (provider *Provider) CreateService(ctx context.Context, namespace string, s }, }, Spec: core.ServiceSpec{ - Ports: []core.ServicePort{{TargetPort: intstr.FromInt(shared.DefaultApiServerPort), Port: 80}}, + Ports: []core.ServicePort{{TargetPort: intstr.FromInt(shared.DefaultApiServerPort), Port: 80, Name: "api"}}, Type: core.ServiceTypeClusterIP, Selector: map[string]string{"app": appLabelValue}, }, diff --git a/shared/kubernetes/proxy.go b/shared/kubernetes/proxy.go index 138bce331..4cb425e96 100644 --- a/shared/kubernetes/proxy.go +++ b/shared/kubernetes/proxy.go @@ -31,7 +31,6 @@ func StartProxy(kubernetesProvider *Provider, proxyHost string, mizuPort uint16, mux.Handle(k8sProxyApiPrefix, getRerouteHttpHandlerMizuAPI(proxyHandler, mizuNamespace, mizuServiceName)) mux.Handle("/static/", getRerouteHttpHandlerMizuStatic(proxyHandler, mizuNamespace, mizuServiceName)) - l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", proxyHost, int(mizuPort))) if err != nil { return err diff --git a/ui/package-lock.json b/ui/package-lock.json index 97b475cc3..085ebaf6a 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -18279,4 +18279,4 @@ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" } } -} +} \ No newline at end of file diff --git a/ui/src/App.sass b/ui/src/App.sass index c9c6ae28a..47ecb56ef 100644 --- a/ui/src/App.sass +++ b/ui/src/App.sass @@ -1,7 +1,9 @@ @import './variables.module' -.mizuApp +body background-color: $main-background-color + +.mizuApp color: $font-color width: 100% @@ -23,3 +25,13 @@ font-size: 11px font-weight: bold color: $light-blue-color + + .centeredForm + max-width: 500px + text-align: center + display: flex + flex-direction: column + margin: 0 auto + + .form-input, .form-button + margin-top: 20px diff --git a/ui/src/App.tsx b/ui/src/App.tsx index 8e6ab26e1..7371e18b9 100644 --- a/ui/src/App.tsx +++ b/ui/src/App.tsx @@ -1,16 +1,71 @@ -import React, {useState} from 'react'; +import React, {useEffect, useState} from 'react'; import './App.sass'; import {TrafficPage} from "./components/TrafficPage"; import {TLSWarning} from "./components/TLSWarning/TLSWarning"; import {Header} from "./components/Header/Header"; +import { ToastContainer, toast } from 'react-toastify'; +import 'react-toastify/dist/ReactToastify.css'; +import Api from "./helpers/api"; +import LoadingOverlay from './components/LoadingOverlay'; +import LoginPage from './components/LoginPage'; +import InstallPage from './components/InstallPage'; + +const api = Api.getInstance(); + + // TODO: move to state management +export enum Page { + Traffic, + Setup, + Login +} + +// TODO: move to state management +export interface MizuContextModel { + page: Page; + setPage: (page: Page) => void; +} + +// TODO: move to state management +export const MizuContext = React.createContext(null); const App = () => { - + const [isLoading, setIsLoading] = useState(true); const [analyzeStatus, setAnalyzeStatus] = useState(null); const [showTLSWarning, setShowTLSWarning] = useState(false); const [userDismissedTLSWarning, setUserDismissedTLSWarning] = useState(false); const [addressesWithTLS, setAddressesWithTLS] = useState(new Set()); + const [page, setPage] = useState(Page.Traffic); // TODO: move to state management + + const determinePage = async () => { // TODO: move to state management + if (window['isEnt'] !== true) { + setPage(Page.Traffic); + setIsLoading(false); + return; + } + + try { + const isInstallNeeded = await api.isInstallNeeded(); + if (isInstallNeeded) { + setPage(Page.Setup); + } else { + const isAuthNeeded = await api.isAuthenticationNeeded(); + if(isAuthNeeded) { + setPage(Page.Login); + } + } + } catch (e) { + toast.error("Error occured while checking Mizu API status, see console for mode details"); + console.error(e); + } finally { + setIsLoading(false); + } + } + + useEffect(() => { + determinePage(); + }, []); + const onTLSDetected = (destAddress: string) => { addressesWithTLS.add(destAddress); setAddressesWithTLS(new Set(addressesWithTLS)); @@ -20,16 +75,49 @@ const App = () => { } }; + let pageComponent: any; + + switch (page) { // TODO: move to state management / proper routing + case Page.Traffic: + pageComponent = ; + break; + case Page.Setup: + pageComponent = ; + break; + case Page.Login: + pageComponent = ; + break; + default: + pageComponent =
Unknown Error
; + } + + if (isLoading) { + return ; + } + return (
-
- - + +
+ {pageComponent} + + +
); } diff --git a/ui/src/components/AuthPresentation/AuthPresentation.tsx b/ui/src/components/AuthPresentation/AuthPresentation.tsx index 8efa739ea..d069f2912 100644 --- a/ui/src/components/AuthPresentation/AuthPresentation.tsx +++ b/ui/src/components/AuthPresentation/AuthPresentation.tsx @@ -2,7 +2,7 @@ import React, {useEffect, useState} from "react"; import Api from "../../helpers/api"; import './AuthPresentation.sass'; -const api = new Api(); +const api = Api.getInstance(); export const AuthPresentation = () => { diff --git a/ui/src/components/EntriesList.tsx b/ui/src/components/EntriesList.tsx index 6b3a6917b..9562c6fef 100644 --- a/ui/src/components/EntriesList.tsx +++ b/ui/src/components/EntriesList.tsx @@ -35,7 +35,7 @@ interface EntriesListProps { setTruncatedTimestamp: any; } -const api = new Api(); +const api = Api.getInstance(); export const EntriesList: React.FC = ({entries, setEntries, query, listEntryREF, onSnapBrokenEvent, isSnappedToBottom, setIsSnappedToBottom, queriedCurrent, setQueriedCurrent, queriedTotal, setQueriedTotal, startTime, noMoreDataTop, setNoMoreDataTop, focusedEntryId, setFocusedEntryId, updateQuery, leftOffTop, setLeftOffTop, isWebSocketConnectionClosed, ws, openWebSocket, leftOffBottom, truncatedTimestamp, setTruncatedTimestamp}) => { const [loadMoreTop, setLoadMoreTop] = useState(false); diff --git a/ui/src/components/Header/Header.tsx b/ui/src/components/Header/Header.tsx index 7fa7d4a9d..84a119d28 100644 --- a/ui/src/components/Header/Header.tsx +++ b/ui/src/components/Header/Header.tsx @@ -6,9 +6,7 @@ import logo from '../assets/Mizu-logo.svg'; interface HeaderProps { analyzeStatus: any } - export const Header: React.FC = ({analyzeStatus}) => { - return
logo
diff --git a/ui/src/components/InstallPage.tsx b/ui/src/components/InstallPage.tsx new file mode 100644 index 000000000..a950d0f27 --- /dev/null +++ b/ui/src/components/InstallPage.tsx @@ -0,0 +1,60 @@ +import { Button, TextField } from "@material-ui/core"; +import React, { useContext, useState } from "react"; +import { MizuContext, Page } from "../App"; +import { adminUsername } from "../consts"; +import Api, { FormValidationErrorType } from "../helpers/api"; +import { toast } from 'react-toastify'; +import LoadingOverlay from "./LoadingOverlay"; + +const api = Api.getInstance(); + +export const InstallPage: React.FC = () => { + + const [isLoading, setIsLoading] = useState(false); + const [password, setPassword] = useState(""); + const [passwordConfirm, setPasswordConfirm] = useState(""); + + const {setPage} = useContext(MizuContext); + + const onFormSubmit = async () => { + if (password.length < 8) { + toast.error("Password must be at least 8 characters long"); + return; + } else if (password !== passwordConfirm) { + toast.error("Passwords do not match"); + return; + } + + try { + setIsLoading(true); + await api.register(adminUsername, password); + if (!await api.isAuthenticationNeeded()) { + toast.success("admin user created successfully"); + setPage(Page.Traffic); + } + } catch (e) { + if (e.type === FormValidationErrorType) { + for (const messages of Object.values(e.messages) as any[]) { + for (const message of messages) { + toast.error(message.text); + } + } + } + console.error(e); + } finally { + setIsLoading(false); + } + + } + + return
+ {isLoading && } +

Welcome to Mizu, please set up the admin user to continue

+ + setPassword(e.target.value)}/> + setPasswordConfirm(e.target.value)}/> + +
; +}; + +export default InstallPage; diff --git a/ui/src/components/LoadingOverlay.tsx b/ui/src/components/LoadingOverlay.tsx new file mode 100644 index 000000000..b0802ebaf --- /dev/null +++ b/ui/src/components/LoadingOverlay.tsx @@ -0,0 +1,25 @@ +import React, {useEffect, useState} from "react"; +import './style/LoadingOverlay.sass'; + +const SpinnerShowDelayMs = 350; + +interface LoadingOverlayProps { + delay?: number +} + +const LoadingOverlay: React.FC = ({delay}) => { + + const [isVisible, setIsVisible] = useState(false); + + useEffect(() => { + setTimeout(() => { + setIsVisible(true); + }, delay ?? SpinnerShowDelayMs); + }, []); + + return
} {tappingStatus && } -
) }; diff --git a/ui/src/components/style/LoadingOverlay.sass b/ui/src/components/style/LoadingOverlay.sass new file mode 100644 index 000000000..26af44cab --- /dev/null +++ b/ui/src/components/style/LoadingOverlay.sass @@ -0,0 +1,54 @@ +.loading-overlay-container + position: absolute + display: flex + width: 100% + height: 100% + top: 0 + left: 0 + align-items: center + justify-content: center + background-color: rgba(25, 25, 25, 0.5) + +.loading-overlay-spinner + width: 60px + height: 60px + top: 50% + left: 50% + z-index: 1000 + -webkit-animation: rotation .6s infinite linear + -moz-animation: rotation .6s infinite linear + -o-animation: rotation .6s infinite linear + animation: rotation .6s infinite linear + border-left: 6px solid rgba(0, 174, 239, 0.15) + border-right: 6px solid rgba(0, 174, 239, 0.15) + border-bottom: 6px solid rgba(0, 174, 239, 0.15) + border-top: 6px solid rgba(0, 174, 239, 0.8) + border-radius: 100% + +@-webkit-keyframes rotation + from + -webkit-transform: rotate(0deg) + + to + -webkit-transform: rotate(359deg) + +@-moz-keyframes rotation + from + -moz-transform: rotate(0deg) + + to + -moz-transform: rotate(359deg) + +@-o-keyframes rotation + from + -o-transform: rotate(0deg) + + to + -o-transform: rotate(359deg) + +@keyframes rotation + from + transform: rotate(0deg) + + to + transform: rotate(359deg) diff --git a/ui/src/consts.ts b/ui/src/consts.ts new file mode 100644 index 000000000..1e62b4dc5 --- /dev/null +++ b/ui/src/consts.ts @@ -0,0 +1 @@ +export const adminUsername = "admin"; diff --git a/ui/src/helpers/api.js b/ui/src/helpers/api.js index 524b58334..3d6ee3d98 100644 --- a/ui/src/helpers/api.js +++ b/ui/src/helpers/api.js @@ -4,23 +4,27 @@ import * as axios from "axios"; export const MizuWebsocketURL = process.env.REACT_APP_OVERRIDE_WS_URL ? process.env.REACT_APP_OVERRIDE_WS_URL : window.location.protocol === 'https:' ? `wss://${window.location.host}/ws` : `ws://${window.location.host}/ws`; +export const FormValidationErrorType = "formError"; + const CancelToken = axios.CancelToken; +// When working locally cp `cp .env.example .env` +const apiURL = process.env.REACT_APP_OVERRIDE_API_URL ? process.env.REACT_APP_OVERRIDE_API_URL : `${window.location.origin}/`; + export default class Api { + static instance; + + static getInstance() { + if (!Api.instance) { + Api.instance = new Api(); + } + return Api.instance; + } constructor() { + this.token = localStorage.getItem("token"); - // When working locally cp `cp .env.example .env` - const apiURL = process.env.REACT_APP_OVERRIDE_API_URL ? process.env.REACT_APP_OVERRIDE_API_URL : `${window.location.origin}/`; - - this.client = axios.create({ - baseURL: apiURL, - timeout: 31000, - headers: { - Accept: "application/json", - } - }); - + this.client = this.getAxiosClient(); this.source = null; } @@ -79,4 +83,81 @@ export default class Api { return response.data; } + + isInstallNeeded = async () => { + const response = await this.client.get("/install/isNeeded"); + return response.data; + } + + isAuthenticationNeeded = async () => { + try { + await this.client.get("/status/tap"); + return false; + } catch (e) { + if (e.response.status == 401) { + return true; + } + throw e; + } + } + + register = async (username, password) => { + const form = new FormData(); + form.append('username', username); + form.append('password', password); + + try { + const response = await this.client.post(`/user/register`, form); + this.persistToken(response.data.token); + return response; + } catch (e) { + if (e.response.status === 400) { + throw { + 'type': FormValidationErrorType, + 'messages': e.response.data + }; + } else { + throw e; + } + } + } + + login = async (username, password) => { + const form = new FormData(); + form.append('username', username); + form.append('password', password); + + const response = await this.client.post(`/user/login`, form); + if (response.status >= 200 && response.status < 300) { + this.persistToken(response.data.token); + } + + return response; + } + + persistToken = (token) => { + this.token = token; + this.client = this.getAxiosClient(); + localStorage.setItem('token', token); + } + + logout = async () => { + await this.client.post(`/user/logout`); + this.persistToken(null); + } + + getAxiosClient = () => { + const headers = { + Accept: "application/json" + } + + if (this.token) { + headers['x-session-token'] = `${this.token}`; // we use `x-session-token` instead of `Authorization` because the latter is reserved by kubectl proxy, making mizu view not work + } + return axios.create({ + baseURL: apiURL, + timeout: 31000, + headers + }); + } }