diff --git a/go.mod b/go.mod index 324139db22..09ac464f90 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ go 1.14 require ( github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 // indirect - github.com/avast/retry-go v3.0.0+incompatible github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 github.com/blang/semver v3.5.1+incompatible github.com/cheggaaa/pb/v3 v3.0.5 @@ -13,6 +12,7 @@ require ( github.com/creack/pty v1.1.11 // indirect github.com/davecgh/go-spew v1.1.1 github.com/dgraph-io/badger/v2 v2.2007.2 + github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/dgrijalva/lfu-go v0.0.0-20141010002404-f174e76c5138 github.com/fatih/color v1.10.0 github.com/felixge/fgprof v0.9.1 @@ -47,6 +47,7 @@ require ( github.com/tklauser/go-sysconf v0.3.6 // indirect github.com/twmb/murmur3 v1.1.5 github.com/wacul/ptr v1.0.0 // indirect + golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 golang.org/x/sync v0.0.0-20201207232520-09787c993a3a golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 golang.org/x/tools v0.1.0 diff --git a/go.sum b/go.sum index 1bdc757c17..54b8c8333c 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,5 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -31,8 +32,6 @@ github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5 github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= -github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0= -github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= @@ -90,6 +89,7 @@ github.com/dgraph-io/badger/v2 v2.2007.2 h1:EjjK0KqwaFMlPin1ajhP943VPENHJdEz1KLI github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de h1:t0UHb5vdojIDUqktM6+xJAfScFBsVpXZmqC9dsgJmeA= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= @@ -501,6 +501,7 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 h1:Wo7BWFiOk0QRFMLYMqJGFMd9CgUAcGx7V+qEg/h5IBI= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 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= @@ -589,6 +590,7 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 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= diff --git a/package-lock.json b/package-lock.json index b7b5144cff..0d6b280608 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "pyroscope", - "version": "0.0.32", + "version": "0.0.35", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1481,6 +1481,8 @@ }, "@babel/preset-env": { "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.10.4.tgz", + "integrity": "sha512-tcmuQ6vupfMZPrLrc38d0sF2OjLT3/bZ0dry5HchNCQbrokoQi4reXqclvkkAT5b+gWc23meVWpve5P/7+w/zw==", "requires": { "@babel/compat-data": "^7.10.4", "@babel/helper-compilation-targets": "^7.10.4", @@ -1562,6 +1564,8 @@ }, "@babel/preset-react": { "version": "7.12.10", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.12.10.tgz", + "integrity": "sha512-vtQNjaHRl4DUpp+t+g4wvTHsLQuye+n0H/wsXIZRn69oz/fvNC7gQ4IK73zGJBaxvHoxElDvnYCthMcT7uzFoQ==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4", @@ -1573,6 +1577,8 @@ }, "@babel/preset-typescript": { "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.8.3.tgz", + "integrity": "sha512-qee5LgPGui9zQ0jR1TeU5/fP9L+ovoArklEqY12ek8P/wV5ZeM/VYSQYwICeoT6FfpJTekG9Ilay5PhwsOpMHA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.8.3", @@ -1676,16 +1682,22 @@ "integrity": "sha512-TsRwpTuKwFNiPhk1UfKgw7zNPeV5RhNp2Uw3pws+9gDAkPGKrtjR1y2lI3SYn7+YzyfuNknflpBA1LRKjt7hMg==" }, "@fortawesome/fontawesome-free": { - "version": "5.14.0" + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.14.0.tgz", + "integrity": "sha512-OfdMsF+ZQgdKHP9jUbmDcRrP0eX90XXrsXIdyjLbkmSBzmMXPABB8eobUJtivaupucYaByz6WNe1PI1JuYm3qA==" }, "@fortawesome/fontawesome-svg-core": { "version": "1.2.30", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.30.tgz", + "integrity": "sha512-E3sAXATKCSVnT17HYmZjjbcmwihrNOCkoU7dVMlasrcwiJAHxSKeZ+4WN5O+ElgO/FaYgJmASl8p9N7/B/RttA==", "requires": { "@fortawesome/fontawesome-common-types": "^0.2.30" } }, "@fortawesome/free-brands-svg-icons": { "version": "5.15.1", + "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-5.15.1.tgz", + "integrity": "sha512-pkTZIWn7iuliCCgV+huDfZmZb2UjslalXGDA2PcqOVUYJmYL11y6ooFiMJkJvUZu+xgAc1gZgQe+Px12mZF0CA==", "requires": { "@fortawesome/fontawesome-common-types": "^0.2.32" }, @@ -1699,6 +1711,8 @@ }, "@fortawesome/free-regular-svg-icons": { "version": "5.15.2", + "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-5.15.2.tgz", + "integrity": "sha512-Uv5NQCYjyisNVTu/1Xjs+z8vwQjbfT6hiqYvQNfF0n8qdgfWLM581bAfVMQ3BCs1SPy+eEUKNcGkK4n0FihFHg==", "requires": { "@fortawesome/fontawesome-common-types": "^0.2.34" }, @@ -1712,12 +1726,16 @@ }, "@fortawesome/free-solid-svg-icons": { "version": "5.14.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.14.0.tgz", + "integrity": "sha512-M933RDM8cecaKMWDSk3FRYdnzWGW7kBBlGNGfvqLVwcwhUPNj9gcw+xZMrqBdRqxnSXdl3zWzTCNNGEtFUq67Q==", "requires": { "@fortawesome/fontawesome-common-types": "^0.2.30" } }, "@fortawesome/react-fontawesome": { "version": "0.1.11", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.11.tgz", + "integrity": "sha512-sClfojasRifQKI0OPqTy8Ln8iIhnxR/Pv/hukBhWnBz9kQRmqi6JSH3nghlhAY7SUeIIM7B5/D2G8WjX0iepVg==", "requires": { "prop-types": "^15.7.2" } @@ -2367,7 +2385,8 @@ "@types/node": { "version": "14.0.27", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.27.tgz", - "integrity": "sha512-kVrqXhbclHNHGu9ztnAwSncIgJv/FaxmzXJvGXNdcCpV1b8u1/Mi6z6m0vwy0LzKeXFTPLH0NzwmoJ3fNCIq0g==" + "integrity": "sha512-kVrqXhbclHNHGu9ztnAwSncIgJv/FaxmzXJvGXNdcCpV1b8u1/Mi6z6m0vwy0LzKeXFTPLH0NzwmoJ3fNCIq0g==", + "dev": true }, "@types/normalize-package-data": { "version": "2.4.0", @@ -2394,6 +2413,8 @@ }, "@types/react": { "version": "17.0.0", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.0.tgz", + "integrity": "sha512-aj/L7RIMsRlWML3YB6KZiXB3fV2t41+5RBGYF8z+tAKU43Px8C3cYUZsDvf1/+Bm4FK21QWBrDutu8ZJ/70qOw==", "requires": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -2494,15 +2515,6 @@ "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==", "dev": true }, - "@types/yauzl": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.1.tgz", - "integrity": "sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA==", - "optional": true, - "requires": { - "@types/node": "*" - } - }, "@ungap/url-search-params": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/@ungap/url-search-params/-/url-search-params-0.1.4.tgz", @@ -2757,6 +2769,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, "requires": { "debug": "4" }, @@ -2765,6 +2778,7 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, "requires": { "ms": "2.1.2" } @@ -3097,6 +3111,8 @@ }, "autoprefixer": { "version": "9.8.5", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.5.tgz", + "integrity": "sha512-C2p5KkumJlsTHoNv9w31NrBRgXhf6eCMteJuHZi2xhkgC+5Vm40MEtCKPhc0qdgAOhox0YPy1SQHTAky05UoKg==", "dev": true, "requires": { "browserslist": "^4.12.0", @@ -3175,6 +3191,8 @@ }, "babel-eslint": { "version": "10.1.0", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", + "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -3412,6 +3430,8 @@ }, "babel-loader": { "version": "8.1.0", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.1.0.tgz", + "integrity": "sha512-7q7nC1tYOrqvUrN3LQK4GwSk/TQorZSOlO9C+RZDZpODgyN4ZlCqE5q9cDsyWOliN+aU9B4JX01xK9eJXowJLw==", "requires": { "find-cache-dir": "^2.1.0", "loader-utils": "^1.4.0", @@ -3494,6 +3514,8 @@ }, "babel-plugin-transform-class-properties": { "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz", + "integrity": "sha1-anl2PqYdM9NvN7YRqp3vgagbRqw=", "dev": true, "requires": { "babel-helper-function-name": "^6.24.1", @@ -3677,11 +3699,6 @@ "integrity": "sha512-7emyCsu1/xiBXgQZrscw/8KPRT44I4Yq9Pe6EGs3aPRTsWuggML1/1DTuZUuIaJPIm1FTDUVXl4x/yW8s0kQDQ==", "optional": true }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, "big.js": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", @@ -3693,16 +3710,6 @@ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true }, - "bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, "boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", @@ -3766,20 +3773,6 @@ "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz", "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==" }, - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" - }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -4046,11 +4039,6 @@ } } }, - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" - }, "chrome-trace-event": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", @@ -4163,6 +4151,8 @@ }, "clean-webpack-plugin": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/clean-webpack-plugin/-/clean-webpack-plugin-3.0.0.tgz", + "integrity": "sha512-MciirUH5r+cYLGCOL5JX/ZLzOZbVr1ot3Fw+KcvbhUb6PM+yycqd9ZhIlcigQ5gl+XhppNmw3bEFuaaMNyLj3A==", "dev": true, "requires": { "@types/webpack": "^4.4.31", @@ -4249,7 +4239,9 @@ } }, "clsx": { - "version": "1.1.1" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz", + "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==" }, "co": { "version": "4.6.0", @@ -4281,6 +4273,8 @@ }, "color": { "version": "3.1.3", + "resolved": "https://registry.npmjs.org/color/-/color-3.1.3.tgz", + "integrity": "sha512-xgXAcTHa2HeFCGLE9Xs/R82hujGtu9Jd9x4NW3T34+OMs7VoPsjwzRczKHvTAHeJwWFwX5j15+MgAppE8ztObQ==", "requires": { "color-convert": "^1.9.1", "color-string": "^1.5.4" @@ -4381,6 +4375,8 @@ }, "contributor-faces": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/contributor-faces/-/contributor-faces-1.1.0.tgz", + "integrity": "sha512-MGVY/0WnoQi3FcLEEe1cvT0UadI2m7AqRfTkAiYo0FqfWSKxhRsFHnCDm5g7iMr1cpvcZ9nPPjZ6XZm2zg20LA==", "dev": true, "requires": { "gh-got": "^9.0.0", @@ -4836,6 +4832,8 @@ }, "conventional-changelog-cli": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/conventional-changelog-cli/-/conventional-changelog-cli-2.1.1.tgz", + "integrity": "sha512-xMGQdKJ+4XFDDgfX5aK7UNFduvJMbvF5BB+g0OdVhA3rYdYyhctrIE2Al+WYdZeKTdg9YzMWF2iFPT8MupIwng==", "dev": true, "requires": { "add-stream": "^1.0.0", @@ -5147,6 +5145,8 @@ }, "copy-webpack-plugin": { "version": "7.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-7.0.0.tgz", + "integrity": "sha512-SLjQNa5iE3BoCP76ESU9qYo9ZkEWtXoZxDurHoqPchAFRblJ9g96xTeC560UXBMre1Nx6ixIIUfiY3VcjpJw3g==", "dev": true, "requires": { "fast-glob": "^3.2.4", @@ -5278,6 +5278,8 @@ }, "css-loader": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-4.0.0.tgz", + "integrity": "sha512-/7d5slKnmY2S39FNifJ7JQ8MhcMM/rDIjAZ2Sc/Z8lnOWOmc10hijg28ovBtljY364pQaF01O2nj5AIBDnJ9vQ==", "dev": true, "requires": { "camelcase": "^6.0.0", @@ -5659,11 +5661,6 @@ "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true }, - "devtools-protocol": { - "version": "0.0.869402", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.869402.tgz", - "integrity": "sha512-VvlVYY+VDJe639yHs5PHISzdWTLL3Aw8rO4cvUtwvoxFd6FHbE4OpHHcde52M6096uYYazAmd4l0o5VuFRO2WA==" - }, "diff-sequences": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", @@ -5845,6 +5842,7 @@ "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, "requires": { "once": "^1.4.0" } @@ -5868,6 +5866,8 @@ }, "enzyme": { "version": "3.11.0", + "resolved": "https://registry.npmjs.org/enzyme/-/enzyme-3.11.0.tgz", + "integrity": "sha512-Dw8/Gs4vRjxY6/6i9wU0V+utmQO9kvh9XLnz3LIudviOnVYDEe2ec+0k+NQoMamn1VrjKgCUOWj5jG/5M5M0Qw==", "dev": true, "requires": { "array.prototype.flat": "^1.2.3", @@ -5926,6 +5926,8 @@ }, "enzyme-adapter-react-16": { "version": "1.15.5", + "resolved": "https://registry.npmjs.org/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.15.5.tgz", + "integrity": "sha512-33yUJGT1nHFQlbVI5qdo5Pfqvu/h4qPwi1o0a6ZZsjpiqq92a3HjynDhwd1IeED+Su60HDWV8mxJqkTnLYdGkw==", "dev": true, "requires": { "enzyme-adapter-utils": "^1.13.1", @@ -6184,6 +6186,8 @@ }, "eslint": { "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.2.0.tgz", + "integrity": "sha512-B3BtEyaDKC5MlfDa2Ha8/D6DsS4fju95zs0hjS3HdGazw+LNayai38A25qMppK37wWGWNYSPOR6oYzlz5MHsRQ==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -6335,6 +6339,8 @@ }, "eslint-config-airbnb": { "version": "18.2.1", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-18.2.1.tgz", + "integrity": "sha512-glZNDEZ36VdlZWoxn/bUR1r/sdFKPd1mHPbqUtkctgNG4yT2DLLtJ3D+yCV+jzZCc2V1nBVkmdknOJBZ5Hc0fg==", "dev": true, "requires": { "eslint-config-airbnb-base": "^14.2.1", @@ -6369,6 +6375,8 @@ }, "eslint-config-prettier": { "version": "7.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-7.1.0.tgz", + "integrity": "sha512-9sm5/PxaFG7qNJvJzTROMM1Bk1ozXVTKI0buKOyb0Bsr1hrwi0H/TzxF/COtf1uxikIK8SwhX7K6zg78jAzbeA==", "dev": true }, "eslint-import-resolver-node": { @@ -6447,6 +6455,8 @@ }, "eslint-plugin-import": { "version": "2.22.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz", + "integrity": "sha512-8K7JjINHOpH64ozkAhpT3sd+FswIZTfMZTjdx052pnWrgRCVfp8op9tbjpAk3DdUeI/Ba4C8OjdC0r90erHEOw==", "dev": true, "requires": { "array-includes": "^3.1.1", @@ -6466,6 +6476,8 @@ }, "eslint-plugin-jsx-a11y": { "version": "6.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.4.1.tgz", + "integrity": "sha512-0rGPJBbwHoGNPU73/QCLP/vveMlM1b1Z9PponxO87jfr6tuH5ligXbDT6nHSSzBC8ovX2Z+BQu7Bk5D/Xgq9zg==", "dev": true, "requires": { "@babel/runtime": "^7.11.2", @@ -6491,6 +6503,8 @@ }, "eslint-plugin-prettier": { "version": "3.3.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.1.tgz", + "integrity": "sha512-Rq3jkcFY8RYeQLgk2cCwuc0P7SEFwDravPhsJZOQ5N4YI4DSg50NyqJ/9gdZHzQlHf8MvafSesbNJCcP/FF6pQ==", "dev": true, "requires": { "prettier-linter-helpers": "^1.0.0" @@ -6498,6 +6512,8 @@ }, "eslint-plugin-react": { "version": "7.22.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.22.0.tgz", + "integrity": "sha512-p30tuX3VS+NWv9nQot9xIGAHBXR0+xJVaZriEsHoJrASGCJZDJ8JLNM0YqKqI0AKm6Uxaa1VUHoNEibxRCMQHA==", "dev": true, "requires": { "array-includes": "^3.1.1", @@ -6526,6 +6542,8 @@ }, "eslint-plugin-react-hooks": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.0.0.tgz", + "integrity": "sha512-YKBY+kilK5wrwIdQnCF395Ya6nDro3EAMoe+2xFkmyklyhF16fH83TrQOo9zbZIDxBsXFgBbywta/0JKRNFDkw==", "dev": true }, "eslint-scope": { @@ -6555,6 +6573,8 @@ }, "eslint-webpack-plugin": { "version": "2.4.1", + "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-2.4.1.tgz", + "integrity": "sha512-cj8iPWZKuAiVD8MMgTSunyMCAvxQxp5mxoPHZl1UMGkApFXaXJHdCFcCR+oZEJbBNhReNa5SjESIn34uqUbBtg==", "dev": true, "requires": { "@types/eslint": "^7.2.4", @@ -6858,27 +6878,6 @@ } } }, - "extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "requires": { - "@types/yauzl": "^2.9.1", - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - }, - "dependencies": { - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "requires": { - "ms": "2.1.2" - } - } - } - }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -6933,14 +6932,6 @@ "bser": "2.1.1" } }, - "fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", - "requires": { - "pend": "~1.2.0" - } - }, "fflate": { "version": "0.4.8", "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz", @@ -6966,6 +6957,8 @@ }, "file-loader": { "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", "requires": { "loader-utils": "^2.0.0", "schema-utils": "^3.0.0" @@ -7006,6 +6999,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, "requires": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -7014,7 +7008,8 @@ "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true } } }, @@ -7208,11 +7203,6 @@ "map-cache": "^0.2.2" } }, - "fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" - }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -7544,6 +7534,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, "requires": { "pump": "^3.0.0" } @@ -7622,9 +7613,9 @@ } }, "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -7981,6 +7972,8 @@ }, "html-webpack-plugin": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.3.0.tgz", + "integrity": "sha512-C0fzKN8yQoVLTelcJxZfJCE+aAvQiY2VUf3UuKrR4a9k5UMWYOtpDLsaXwATbcVCnI05hUS7L9ULQHWLZhyi3w==", "dev": true, "requires": { "@types/html-minifier-terser": "^5.0.0", @@ -8075,6 +8068,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dev": true, "requires": { "agent-base": "6", "debug": "4" @@ -8084,6 +8078,7 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, "requires": { "ms": "2.1.2" } @@ -8097,7 +8092,9 @@ "dev": true }, "humanize-duration": { - "version": "3.25.1" + "version": "3.25.1", + "resolved": "https://registry.npmjs.org/humanize-duration/-/humanize-duration-3.25.1.tgz", + "integrity": "sha512-P+dRo48gpLgc2R9tMRgiDRNULPKCmqFYgguwqOO2C0fjO35TgdURDQDANSR1Nt92iHlbHGMxOTnsB8H8xnMa2Q==" }, "iconv-lite": { "version": "0.4.24", @@ -8117,11 +8114,6 @@ "postcss": "^7.0.14" } }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", @@ -8901,6 +8893,8 @@ }, "jest": { "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest/-/jest-26.6.3.tgz", + "integrity": "sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q==", "dev": true, "requires": { "@jest/core": "^26.6.3", @@ -9752,6 +9746,8 @@ }, "jspdf": { "version": "2.3.1", + "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.3.1.tgz", + "integrity": "sha512-1vp0USP1mQi1h7NKpwxjFgQkJ5ncZvtH858aLpycUc/M+r/RpWJT8PixAU7Cw/3fPd4fpC8eB/Bj42LnsR21YQ==", "requires": { "atob": "^2.1.2", "btoa": "^1.2.1", @@ -9763,7 +9759,9 @@ } }, "jspdf-autotable": { - "version": "3.5.14" + "version": "3.5.14", + "resolved": "https://registry.npmjs.org/jspdf-autotable/-/jspdf-autotable-3.5.14.tgz", + "integrity": "sha512-Qm11yQ2hTvM2iZ7MpWLpeDGR+uQlI8bcOsMjWYXon9mTo+UehMqp5xdQk6JpVSNUN6+rnJnpS5mkqelv4ncd5g==" }, "jsx-ast-utils": { "version": "3.2.0", @@ -9926,6 +9924,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, "requires": { "p-locate": "^4.1.0" } @@ -10373,6 +10372,8 @@ }, "mini-css-extract-plugin": { "version": "0.9.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.9.0.tgz", + "integrity": "sha512-lp3GeY7ygcgAmVIcRPBVhIkf8Us7FZjA+ILpal44qLdSu11wmjKQ3d9k15lfD7pO4esu9eUIAW7qiYIBppv40A==", "dev": true, "requires": { "loader-utils": "^1.1.0", @@ -10463,11 +10464,6 @@ "minimist": "^1.2.5" } }, - "mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" - }, "modify-values": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", @@ -10475,10 +10471,14 @@ "dev": true }, "moment": { - "version": "2.27.0" + "version": "2.27.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.27.0.tgz", + "integrity": "sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ==" }, "monaco-editor-webpack-plugin": { "version": "1.9.0", + "resolved": "https://registry.npmjs.org/monaco-editor-webpack-plugin/-/monaco-editor-webpack-plugin-1.9.0.tgz", + "integrity": "sha512-tOiiToc94E1sb50BgZ8q8WK/bxus77SRrwCqIpAB5er3cpX78SULbEBY4YPOB8kDolOzKRt30WIHG/D6gz69Ww==", "dev": true, "requires": { "loader-utils": "^1.2.3" @@ -10568,11 +10568,6 @@ } } }, - "node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" - }, "node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -10671,7 +10666,9 @@ } }, "normalize.css": { - "version": "8.0.1" + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-8.0.1.tgz", + "integrity": "sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg==" }, "npm-run-path": { "version": "2.0.2", @@ -11234,6 +11231,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, "requires": { "p-limit": "^2.2.0" }, @@ -11242,6 +11240,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, "requires": { "p-try": "^2.0.0" } @@ -11409,11 +11408,6 @@ "pinkie-promise": "^2.0.0" } }, - "pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" - }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -11564,6 +11558,8 @@ }, "postcss-browser-reporter": { "version": "0.6.0", + "resolved": "https://registry.npmjs.org/postcss-browser-reporter/-/postcss-browser-reporter-0.6.0.tgz", + "integrity": "sha512-61gzk4wgthOIen4TRURzYYVVIszyvcorkYmD40CopdM8cdwJaCTDMYo/y8HQqjTPqyelw7r2ptncmR9xrWpVnw==", "dev": true, "requires": { "postcss": "^7.0.14" @@ -11581,6 +11577,8 @@ }, "postcss-loader": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-3.0.0.tgz", + "integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==", "dev": true, "requires": { "loader-utils": "^1.1.0", @@ -11653,6 +11651,8 @@ }, "postcss-reporter": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-6.0.1.tgz", + "integrity": "sha512-LpmQjfRWyabc+fRygxZjpRxfhRf9u/fdlKf4VHG4TSPbV2XNsuISzYW1KL+1aQzx53CAppa1bKG4APIB/DOXXw==", "dev": true, "requires": { "chalk": "^2.4.1", @@ -11728,6 +11728,8 @@ }, "prettier": { "version": "2.2.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", + "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", "dev": true }, "prettier-linter-helpers": { @@ -11784,7 +11786,8 @@ "progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true }, "prompts": { "version": "2.4.1", @@ -11816,11 +11819,6 @@ "reflect.ownkeys": "^0.2.0" } }, - "proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" - }, "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -11843,6 +11841,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -11853,51 +11852,6 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, - "puppeteer": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-9.1.1.tgz", - "integrity": "sha512-W+nOulP2tYd/ZG99WuZC/I5ljjQQ7EUw/jQGcIb9eu8mDlZxNY2SgcJXTLG9h5gRvqA3uJOe4hZXYsd3EqioMw==", - "requires": { - "debug": "^4.1.0", - "devtools-protocol": "0.0.869402", - "extract-zip": "^2.0.0", - "https-proxy-agent": "^5.0.0", - "node-fetch": "^2.6.1", - "pkg-dir": "^4.2.0", - "progress": "^2.0.1", - "proxy-from-env": "^1.1.0", - "rimraf": "^3.0.2", - "tar-fs": "^2.0.0", - "unbzip2-stream": "^1.3.3", - "ws": "^7.2.3" - }, - "dependencies": { - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "requires": { - "ms": "2.1.2" - } - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "requires": { - "find-up": "^4.0.0" - } - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "requires": { - "glob": "^7.1.3" - } - } - } - }, "q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", @@ -11980,6 +11934,8 @@ }, "react": { "version": "16.12.0", + "resolved": "https://registry.npmjs.org/react/-/react-16.12.0.tgz", + "integrity": "sha512-fglqy3k5E+81pA8s+7K0/T3DBCF0ZDOher1elBFzF7O6arXJgzyu/FW+COxFvAWXJoJN9KIZbT2LXlukwphYTA==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", @@ -11988,6 +11944,8 @@ }, "react-datepicker": { "version": "3.4.1", + "resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-3.4.1.tgz", + "integrity": "sha512-ASyVb7UmVx1vzeITidD7Cr/EXRXhKyjjbSkBndPc1MipYq4rqQ3eMFgvRQzpsXc3JmIMFgICm7nmN6Otc1GE/Q==", "requires": { "classnames": "^2.2.6", "date-fns": "^2.0.1", @@ -12005,6 +11963,8 @@ }, "react-dom": { "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.13.1.tgz", + "integrity": "sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", @@ -12014,6 +11974,8 @@ }, "react-flot": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/react-flot/-/react-flot-1.3.0.tgz", + "integrity": "sha1-Q9LeNvY5RZnS/vt+jWsD1MViDno=", "requires": { "@types/react": "^15.0.38", "deep-equal": "^1.0.1", @@ -12033,7 +11995,9 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "react-keybind": { - "version": "0.8.1" + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/react-keybind/-/react-keybind-0.8.1.tgz", + "integrity": "sha512-/1T5xciPjGf+QRGLb7NKKTP8QLcYEeyCqCglFxUuKDcXDmVSyUtk53liM5fl4tFif6Y8NUlFvfOuyq5yt44aLw==" }, "react-lifecycles-compat": { "version": "3.0.4", @@ -12042,6 +12006,8 @@ }, "react-modal": { "version": "3.12.1", + "resolved": "https://registry.npmjs.org/react-modal/-/react-modal-3.12.1.tgz", + "integrity": "sha512-WGuXn7Fq31PbFJwtWmOk+jFtGC7E9tJVbFX0lts8ZoS5EPi9+WWylUJWLKKVm3H4GlQ7ZxY7R6tLlbSIBQ5oZA==", "requires": { "exenv": "^1.2.0", "prop-types": "^15.5.10", @@ -12056,6 +12022,8 @@ }, "react-outside-click-handler": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/react-outside-click-handler/-/react-outside-click-handler-1.3.0.tgz", + "integrity": "sha512-Te/7zFU0oHpAnctl//pP3hEAeobfeHMyygHB8MnjP6sX5OR8KHT1G3jmLsV3U9RnIYo+Yn+peJYWu+D5tUS8qQ==", "requires": { "airbnb-prop-types": "^2.15.0", "consolidated-events": "^1.1.1 || ^2.0.0", @@ -12179,6 +12147,8 @@ }, "react-redux": { "version": "7.2.1", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.1.tgz", + "integrity": "sha512-T+VfD/bvgGTUA74iW9d2i5THrDQWbweXP0AVNI8tNd1Rk5ch1rnMiJkDD67ejw7YBKM4+REvcvqRuWJb7BLuEg==", "requires": { "@babel/runtime": "^7.5.5", "hoist-non-react-statics": "^3.3.0", @@ -12216,6 +12186,8 @@ }, "react-router-dom": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.2.0.tgz", + "integrity": "sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA==", "requires": { "@babel/runtime": "^7.1.2", "history": "^4.9.0", @@ -12228,6 +12200,8 @@ }, "react-svg-spinner": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/react-svg-spinner/-/react-svg-spinner-1.0.4.tgz", + "integrity": "sha512-lpOdpptU5sutxdToI5vffuWAqQDatfz1cbWa1ThEmX5fonmdH8UgoM/iAb6ToKf6iv0z+X4jZxSqDar5EtcEjQ==", "requires": { "prop-types": "^15.7.2", "react": "^16.0.0" @@ -12398,6 +12372,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -12440,19 +12415,27 @@ }, "redux": { "version": "4.0.5", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.5.tgz", + "integrity": "sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==", "requires": { "loose-envify": "^1.4.0", "symbol-observable": "^1.2.0" } }, "redux-devtools-extension": { - "version": "2.13.8" + "version": "2.13.8", + "resolved": "https://registry.npmjs.org/redux-devtools-extension/-/redux-devtools-extension-2.13.8.tgz", + "integrity": "sha512-8qlpooP2QqPtZHQZRhx3x3OP5skEV1py/zUdMY28WNAocbafxdG2tRD1MWE7sp8obGMNYuLWanhhQ7EQvT1FBg==" }, "redux-localstorage": { - "version": "0.4.1" + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/redux-localstorage/-/redux-localstorage-0.4.1.tgz", + "integrity": "sha1-+vbXGcWBOXKU2BFHP/zt7gZckzw=" }, "redux-mock-store": { "version": "1.5.4", + "resolved": "https://registry.npmjs.org/redux-mock-store/-/redux-mock-store-1.5.4.tgz", + "integrity": "sha512-xmcA0O/tjCLXhh9Fuiq6pMrJCwFRaouA8436zcikdIpYWWCjU76CRk+i2bHx8EeiSiMGnB85/lZdU3wIJVXHTA==", "dev": true, "requires": { "lodash.isplainobject": "^4.0.6" @@ -12460,6 +12443,8 @@ }, "redux-promise": { "version": "0.6.0", + "resolved": "https://registry.npmjs.org/redux-promise/-/redux-promise-0.6.0.tgz", + "integrity": "sha512-R2mGxJbPFgXyCNbFDE6LjTZhCEuACF54g1bxld3nqBhnRMX0OsUyWk77moF7UMGkUdl5WOAwc4BC5jOd1dunqQ==", "requires": { "flux-standard-action": "^2.0.3", "is-promise": "^2.1.0" @@ -12467,13 +12452,17 @@ }, "redux-query-sync": { "version": "0.1.10", + "resolved": "https://registry.npmjs.org/redux-query-sync/-/redux-query-sync-0.1.10.tgz", + "integrity": "sha512-F33z0pH7p17pNsKRAJzxOihdg5C/0CcUM8POU57a83vDPJXUXviBuuATNUI6xdhfUE3Y3gjV222EyaP7zwOktw==", "requires": { "@ungap/url-search-params": "^0.1.2", "history": "^4.8.0" } }, "redux-thunk": { - "version": "2.3.0" + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.3.0.tgz", + "integrity": "sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw==" }, "reflect.ownkeys": { "version": "0.2.0", @@ -13144,7 +13133,8 @@ "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true }, "safe-regex": { "version": "1.1.0", @@ -13283,10 +13273,14 @@ } }, "sanitize.css": { - "version": "11.0.1" + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-11.0.1.tgz", + "integrity": "sha512-Q762QXJGHIyFLayll6zUueGKslmGxNpbEDpSB/sdaZ9Xgz+v6AYlVc5P49sorc9cPR9y47npHBfXswGo1I32tg==" }, "sass": { "version": "1.26.10", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.26.10.tgz", + "integrity": "sha512-bzN0uvmzfsTvjz0qwccN1sPm2HxxpNI/Xa+7PlUEMS+nQvbyuEK7Y0qFqxlPHhiNHb1Ze8WQJtU31olMObkAMw==", "dev": true, "requires": { "chokidar": ">=2.0.0 <4.0.0" @@ -13294,6 +13288,8 @@ }, "sass-loader": { "version": "9.0.2", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-9.0.2.tgz", + "integrity": "sha512-nphcum3jNI442njnrZ5wJgSNX5lfEOHOKHCLf+PrTIaleploKqAMUuT9CVKjf+lyi6c2MCGPHh1vb9nGsjnZJA==", "dev": true, "requires": { "klona": "^1.1.1", @@ -14150,6 +14146,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, "requires": { "safe-buffer": "~5.2.0" } @@ -14282,29 +14279,6 @@ "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", "dev": true }, - "tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "requires": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "requires": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - } - }, "temp-dir": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", @@ -14409,7 +14383,8 @@ "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true }, "through2": { "version": "4.0.2", @@ -14609,6 +14584,8 @@ }, "typescript": { "version": "3.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.3.tgz", + "integrity": "sha512-D/wqnB2xzNFIcoBG9FG8cXRDjiqSTbG2wd8DMZeQyJlP1vfTkIxH4GKveWaEBYySKIg+USu+E+EDIR47SqnaMQ==", "dev": true }, "uglify-js": { @@ -14629,15 +14606,6 @@ "which-boxed-primitive": "^1.0.2" } }, - "unbzip2-stream": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", - "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", - "requires": { - "buffer": "^5.2.1", - "through": "^2.3.8" - } - }, "unicode-canonical-property-names-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", @@ -14743,7 +14711,8 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true }, "util.promisify": { "version": "1.0.0", @@ -14860,6 +14829,8 @@ }, "webpack": { "version": "5.11.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.11.0.tgz", + "integrity": "sha512-ubWv7iP54RqAC/VjixgpnLLogCFbAfSOREcSWnnOlZEU8GICC5eKmJSu6YEnph2N2amKqY9rvxSwgyHxVqpaRw==", "dev": true, "requires": { "@types/eslint-scope": "^3.7.0", @@ -15001,6 +14972,8 @@ }, "webpack-bundle-analyzer": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.3.0.tgz", + "integrity": "sha512-J3TPm54bPARx6QG8z4cKBszahnUglcv70+N+8gUqv2I5KOFHJbzBiLx+pAp606so0X004fxM7hqRu10MLjJifA==", "dev": true, "requires": { "acorn": "^8.0.4", @@ -15036,6 +15009,8 @@ }, "webpack-cli": { "version": "3.3.12", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.12.tgz", + "integrity": "sha512-NVWBaz9k839ZH/sinurM+HcDvJOTXwSjYp1ku+5XKeOC03z8v5QitnK/x+lAxGXFyhdayoIf/GOpv85z3/xPag==", "dev": true, "requires": { "chalk": "^2.4.2", @@ -15230,6 +15205,8 @@ }, "webpack-merge": { "version": "5.0.9", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.0.9.tgz", + "integrity": "sha512-P4teh6O26xIDPugOGX61wPxaeP918QOMjmzhu54zTVcLtOS28ffPWtnv+ilt3wscwBUCL2WNMnh97XkrKqt9Fw==", "dev": true, "requires": { "clone-deep": "^4.0.1", @@ -15238,6 +15215,8 @@ }, "webpack-plugin-hash-output": { "version": "3.2.1", + "resolved": "https://registry.npmjs.org/webpack-plugin-hash-output/-/webpack-plugin-hash-output-3.2.1.tgz", + "integrity": "sha512-Iu4Sox3/bdiqd6TdYwZAExuH+XNbnJStPrwh6yhzOflwc/hZUP9MdiZDbFwTXrmm9ZwoXNUmvn7C0Qj4qRez2A==", "dev": true, "requires": { "outdent": "^0.7.0" @@ -15397,7 +15376,8 @@ "ws": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.1.tgz", - "integrity": "sha512-pTsP8UAfhy3sk1lSk/O/s4tjD0CRwvMnzvwr4OKGX7ZvqZtUyx4KIJB5JWbkykPoc55tixMGgTNoh3k4FkNGFQ==" + "integrity": "sha512-pTsP8UAfhy3sk1lSk/O/s4tjD0CRwvMnzvwr4OKGX7ZvqZtUyx4KIJB5JWbkykPoc55tixMGgTNoh3k4FkNGFQ==", + "dev": true }, "xml-name-validator": { "version": "3.0.0", @@ -15483,15 +15463,6 @@ "decamelize": "^1.2.0" } }, - "yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", - "requires": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, "yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 72972034ec..f670eab289 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,7 @@ "clsx": "^1.1.1", "color": "^3.1.3", "file-loader": "^6.2.0", + "glob": "^7.1.7", "humanize-duration": "^3.25.1", "jspdf": "^2.3.1", "jspdf-autotable": "^3.5.14", diff --git a/pkg/analytics/analytics_test.go b/pkg/analytics/analytics_test.go index 4fc870d69c..aa3ace2ca9 100644 --- a/pkg/analytics/analytics_test.go +++ b/pkg/analytics/analytics_test.go @@ -16,6 +16,7 @@ import ( "github.com/pyroscope-io/pyroscope/pkg/server" "github.com/pyroscope-io/pyroscope/pkg/storage" "github.com/pyroscope-io/pyroscope/pkg/testing" + "github.com/sirupsen/logrus" ) const durThreshold = 30 * time.Millisecond @@ -54,7 +55,7 @@ var _ = Describe("analytics", func() { s, err := storage.New(&(*cfg).Server) Expect(err).ToNot(HaveOccurred()) - c, _ := server.New(&(*cfg).Server, s) + c, _ := server.New(&(*cfg).Server, s, logrus.New()) analytics := NewService(&(*cfg).Server, s, c) startTime := time.Now() diff --git a/pkg/cli/server.go b/pkg/cli/server.go index d8ae075549..14253036ac 100644 --- a/pkg/cli/server.go +++ b/pkg/cli/server.go @@ -46,7 +46,7 @@ func newServerService(logger *logrus.Logger, c *config.Server) (*serverService, if err != nil { return nil, fmt.Errorf("new storage: %v", err) } - svc.controller, err = server.New(svc.config, svc.storage) + svc.controller, err = server.New(svc.config, svc.storage, svc.logger) if err != nil { return nil, fmt.Errorf("new server: %v", err) } diff --git a/pkg/config/config.go b/pkg/config/config.go index aa796f39c8..0e048370f2 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -80,6 +80,34 @@ type Server struct { CacheDictionarySize int `deprecated:"true"` CacheSegmentSize int `deprecated:"true"` CacheTreeSize int `deprecated:"true"` + + // TODO: remove skip: true when we enable these back + GoogleEnabled bool `deprecated:"true" def:"false" desc:"enables Google Oauth"` + GoogleClientID string `deprecated:"true" def:"" desc:"client ID generated for Google API"` + GoogleClientSecret string `deprecated:"true" def:"" desc:"client secret generated for Google API"` + GoogleRedirectURL string `deprecated:"true" def:"" desc:"url that google will redirect to after logging in. Has to be in form "` + GoogleAuthURL string `deprecated:"true" def:"https://accounts.google.com/o/oauth2/auth" desc:"auth url for Google API (usually present in credentials.json file)"` + GoogleTokenURL string `deprecated:"true" def:"https://accounts.google.com/o/oauth2/token" desc:"token url for Google API (usually present in credentials.json file)"` + + GitlabEnabled bool `deprecated:"true" def:"false" desc:"enables Gitlab Oauth"` + // TODO: why is this one ApplicationID and not ClientID ? + GitlabApplicationID string `deprecated:"true" def:"" desc:"application ID generated for GitLab API"` + GitlabClientSecret string `deprecated:"true" def:"" desc:"client secret generated for GitLab API"` + GitlabRedirectURL string `deprecated:"true" def:"" desc:"url that gitlab will redirect to after logging in. Has to be in form "` + GitlabAuthURL string `deprecated:"true" def:"https://gitlab.com/oauth/authorize" desc:"auth url for GitLab API (keep default for cloud, usually https://gitlab.mycompany.com/oauth/authorize for on-premise)"` + GitlabTokenURL string `deprecated:"true" def:"https://gitlab.com/oauth/token" desc:"token url for GitLab API (keep default for cloud, usually https://gitlab.mycompany.com/oauth/token for on-premise)"` + GitlabAPIURL string `deprecated:"true" def:"https://gitlab.com/api/v4/user" desc:"URL to gitlab API (keep default for cloud, usually https://gitlab.mycompany.com/api/v4/user for on-premise)"` + + GithubEnabled bool `deprecated:"true" def:"false" desc:"enables Github Oauth"` + GithubClientID string `deprecated:"true" def:"" desc:"client ID generated for Github API"` + GithubClientSecret string `deprecated:"true" def:"" desc:"client secret generated for Github API"` + GithubRedirectURL string `deprecated:"true" def:"" desc:"url that Github will redirect to after logging in. Has to be in form "` + GithubAuthURL string `deprecated:"true" def:"https://github.com/login/oauth/authorize" desc:"auth url for Github API"` + GithubTokenURL string `deprecated:"true" def:"https://github.com/login/oauth/access_token" desc:"token url for Github API"` + + // TODO: can we generate these automatically if it's empty? + JWTSecret string `deprecated:"true" def:"" desc:"secret used to secure your JWT tokens"` + LoginMaximumLifetimeDays int `deprecated:"true" def:"0" desc:"amount of days after which user will be logged out. 0 means non-expiring."` } type Convert struct { diff --git a/pkg/server/build_test.go b/pkg/server/build_test.go index ee02e69ef5..15a33bbda8 100644 --- a/pkg/server/build_test.go +++ b/pkg/server/build_test.go @@ -9,6 +9,7 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "github.com/sirupsen/logrus" "github.com/pyroscope-io/pyroscope/pkg/config" "github.com/pyroscope-io/pyroscope/pkg/storage" @@ -26,7 +27,7 @@ var _ = Describe("server", func() { (*cfg).Server.APIBindAddr = ":10044" s, err := storage.New(&(*cfg).Server) Expect(err).ToNot(HaveOccurred()) - c, _ := New(&(*cfg).Server, s) + c, _ := New(&(*cfg).Server, s, logrus.New()) httpServer := httptest.NewServer(c.mux()) defer httpServer.Close() diff --git a/pkg/server/config_test.go b/pkg/server/config_test.go index 9ab470d01b..aae60dda1e 100644 --- a/pkg/server/config_test.go +++ b/pkg/server/config_test.go @@ -8,6 +8,7 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "github.com/sirupsen/logrus" "github.com/pyroscope-io/pyroscope/pkg/config" "github.com/pyroscope-io/pyroscope/pkg/storage" @@ -25,7 +26,7 @@ var _ = Describe("server", func() { (*cfg).Server.APIBindAddr = ":10045" s, err := storage.New(&(*cfg).Server) Expect(err).ToNot(HaveOccurred()) - c, _ := New(&(*cfg).Server, s) + c, _ := New(&(*cfg).Server, s, logrus.New()) httpServer := httptest.NewServer(c.mux()) defer httpServer.Close() diff --git a/pkg/server/controller.go b/pkg/server/controller.go index 820c7bfef9..ad4f2262fd 100644 --- a/pkg/server/controller.go +++ b/pkg/server/controller.go @@ -2,21 +2,20 @@ package server import ( "context" - "encoding/json" "fmt" - "io/ioutil" golog "log" "net/http" "net/http/pprof" - "os" + "net/url" "sync" "sync/atomic" - "text/template" "time" + "github.com/dgrijalva/jwt-go" "github.com/markbates/pkger" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/sirupsen/logrus" + "golang.org/x/oauth2" "github.com/pyroscope-io/pyroscope/pkg/build" "github.com/pyroscope-io/pyroscope/pkg/config" @@ -24,20 +23,33 @@ import ( "github.com/pyroscope-io/pyroscope/pkg/util/hyperloglog" ) +const ( + jwtCookieName = "pyroscopeJWT" + stateCookieName = "pyroscopeState" + oauthGoogle = iota + oauthGithub + oauthGitlab +) + +type decodeResponseFunc func(*http.Response) (string, error) + type Controller struct { drained uint32 config *config.Server storage *storage.Storage + log *logrus.Logger httpServer *http.Server + dir http.FileSystem + statsMutex sync.Mutex stats map[string]int appStats *hyperloglog.HyperLogLogPlus } -func New(c *config.Server, s *storage.Storage) (*Controller, error) { +func New(c *config.Server, s *storage.Storage, l *logrus.Logger) (*Controller, error) { appStats, err := hyperloglog.NewPlus(uint8(18)) if err != nil { return nil, err @@ -45,14 +57,27 @@ func New(c *config.Server, s *storage.Storage) (*Controller, error) { ctrl := Controller{ config: c, + log: l, storage: s, stats: make(map[string]int), appStats: appStats, } + if build.UseEmbeddedAssets { + // for this to work you need to run `pkger` first. See Makefile for more information + ctrl.dir = pkger.Dir("/webapp/public") + } else { + ctrl.dir = http.Dir("./webapp/public") + } + return &ctrl, nil } +func (ctrl *Controller) assetsFilesHandler(w http.ResponseWriter, r *http.Request) { + fs := http.FileServer(ctrl.dir) + fs.ServeHTTP(w, r) +} + func (ctrl *Controller) mux() http.Handler { mux := http.NewServeMux() addRoutes(mux, []route{ @@ -62,16 +87,18 @@ func (ctrl *Controller) mux() http.Handler { {"/build", ctrl.buildHandler}, }) + // auth routes + addRoutes(mux, ctrl.getAuthRoutes(), ctrl.drainMiddleware) + // drainable routes: routes := []route{ {"/", ctrl.indexHandler()}, - {"/ingest", ctrl.ingestHandler}, {"/render", ctrl.renderHandler}, {"/labels", ctrl.labelsHandler}, {"/label-values", ctrl.labelValuesHandler}, } - addRoutes(mux, routes, ctrl.drainMiddleware) + addRoutes(mux, routes, ctrl.drainMiddleware, ctrl.authMiddleware) if !ctrl.config.DisablePprofEndpoint { addRoutes(mux, []route{ @@ -82,9 +109,140 @@ func (ctrl *Controller) mux() http.Handler { {"/debug/pprof/trace", pprof.Trace}, }) } + + nonAuthRoutes := []route{ + {"/ingest", ctrl.ingestHandler}, + {"/forbidden", ctrl.forbiddenHandler()}, + {"/assets/", ctrl.assetsFilesHandler}, + } + + addRoutes(mux, nonAuthRoutes, ctrl.drainMiddleware) return mux } +type oauthInfo struct { + Config *oauth2.Config + AuthURL *url.URL + Type int +} + +func (ctrl *Controller) generateOauthInfo(oauthType int) *oauthInfo { + switch oauthType { + case oauthGoogle: + googleOauthInfo := &oauthInfo{ + Config: &oauth2.Config{ + ClientID: ctrl.config.GoogleClientID, + ClientSecret: ctrl.config.GoogleClientSecret, + Scopes: []string{"https://www.googleapis.com/auth/userinfo.email"}, + Endpoint: oauth2.Endpoint{AuthURL: ctrl.config.GoogleAuthURL, TokenURL: ctrl.config.GoogleTokenURL}, + }, + Type: oauthGoogle, + } + if ctrl.config.GoogleRedirectURL != "" { + googleOauthInfo.Config.RedirectURL = ctrl.config.GoogleRedirectURL + } + + return googleOauthInfo + case oauthGithub: + githubOauthInfo := &oauthInfo{ + Config: &oauth2.Config{ + ClientID: ctrl.config.GithubClientID, + ClientSecret: ctrl.config.GithubClientSecret, + Scopes: []string{"read:user", "user:email"}, + Endpoint: oauth2.Endpoint{AuthURL: ctrl.config.GithubAuthURL, TokenURL: ctrl.config.GithubTokenURL}, + }, + Type: oauthGithub, + } + + if ctrl.config.GithubRedirectURL != "" { + githubOauthInfo.Config.RedirectURL = ctrl.config.GithubRedirectURL + } + + return githubOauthInfo + case oauthGitlab: + gitlabOauthInfo := &oauthInfo{ + Config: &oauth2.Config{ + ClientID: ctrl.config.GitlabApplicationID, + ClientSecret: ctrl.config.GitlabClientSecret, + Scopes: []string{"read_user"}, + Endpoint: oauth2.Endpoint{AuthURL: ctrl.config.GitlabAuthURL, TokenURL: ctrl.config.GitlabTokenURL}, + }, + Type: oauthGitlab, + } + + if ctrl.config.GitlabRedirectURL != "" { + gitlabOauthInfo.Config.RedirectURL = ctrl.config.GitlabRedirectURL + } + + return gitlabOauthInfo + } + + return nil +} + +func (ctrl *Controller) getAuthRoutes() []route { + authRoutes := []route{ + {"/login", ctrl.loginHandler()}, + {"/logout", ctrl.logoutHandler()}, + } + + if ctrl.config.GoogleEnabled { + authURL, err := url.Parse(ctrl.config.GoogleAuthURL) + if err != nil { + ctrl.log.WithError(err).Error("Problem parsing google auth url") + } + + googleOauthInfo := ctrl.generateOauthInfo(oauthGoogle) + if err == nil && googleOauthInfo != nil { + googleOauthInfo.AuthURL = authURL + authRoutes = append(authRoutes, []route{ + {"/auth/google/login", ctrl.oauthLoginHandler(googleOauthInfo)}, + {"/auth/google/callback", ctrl.callbackHandler("/auth/google/redirect")}, + {"/auth/google/redirect", ctrl.callbackRedirectHandler( + "https://www.googleapis.com/oauth2/v2/userinfo", googleOauthInfo, ctrl.decodeGoogleCallbackResponse)}, + }...) + } + } + + if ctrl.config.GithubEnabled { + authURL, err := url.Parse(ctrl.config.GithubAuthURL) + if err != nil { + ctrl.log.WithError(err).Error("Problem parsing github auth url") + return nil + } + + githubOauthInfo := ctrl.generateOauthInfo(oauthGithub) + if err == nil && githubOauthInfo != nil { + githubOauthInfo.AuthURL = authURL + authRoutes = append(authRoutes, []route{ + {"/auth/github/login", ctrl.oauthLoginHandler(githubOauthInfo)}, + {"/auth/github/callback", ctrl.callbackHandler("/auth/github/redirect")}, + {"/auth/github/redirect", ctrl.callbackRedirectHandler("https://api.github.com/user", githubOauthInfo, ctrl.decodeGithubCallbackResponse)}, + }...) + } + } + + if ctrl.config.GitlabEnabled { + authURL, err := url.Parse(ctrl.config.GitlabAuthURL) + if err != nil { + ctrl.log.WithError(err).Error("Problem parsing gitlab auth url") + return nil + } + + gitlabOauthInfo := ctrl.generateOauthInfo(oauthGitlab) + if err == nil && gitlabOauthInfo != nil { + gitlabOauthInfo.AuthURL = authURL + authRoutes = append(authRoutes, []route{ + {"/auth/gitlab/login", ctrl.oauthLoginHandler(gitlabOauthInfo)}, + {"/auth/gitlab/callback", ctrl.callbackHandler("/auth/gitlab/redirect")}, + {"/auth/gitlab/redirect", ctrl.callbackRedirectHandler(ctrl.config.GitlabAPIURL, gitlabOauthInfo, ctrl.decodeGitLabCallbackResponse)}, + }...) + } + } + + return authRoutes +} + func (ctrl *Controller) Start() error { logger := logrus.New() w := logger.Writer() @@ -129,94 +287,40 @@ func (ctrl *Controller) drainMiddleware(next http.HandlerFunc) http.HandlerFunc } } -func renderServerError(rw http.ResponseWriter, text string) { - rw.WriteHeader(500) - rw.Write([]byte(text)) - rw.Write([]byte("\n")) -} - -type indexPageJSON struct { - AppNames []string `json:"appNames"` -} -type indexPage struct { - InitialState string - BuildInfo string - ExtraMetadata string - BaseURL string +func (ctrl *Controller) isAuthRequired() bool { + return ctrl.config.GoogleEnabled || ctrl.config.GithubEnabled || ctrl.config.GitlabEnabled } -func (ctrl *Controller) indexHandler() http.HandlerFunc { - var dir http.FileSystem - if build.UseEmbeddedAssets { - // for this to work you need to run `pkger` first. See Makefile for more information - dir = pkger.Dir("/webapp/public") - } else { - dir = http.Dir("./webapp/public") - } - fs := http.FileServer(dir) - return func(rw http.ResponseWriter, r *http.Request) { - if r.URL.Path == "/" { - ctrl.statsInc("index") - ctrl.renderIndexPage(dir, rw, r) - } else if r.URL.Path == "/comparison" { - ctrl.statsInc("index") - ctrl.renderIndexPage(dir, rw, r) - } else { - fs.ServeHTTP(rw, r) +func (ctrl *Controller) authMiddleware(next http.HandlerFunc) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + if !ctrl.isAuthRequired() { + next.ServeHTTP(w, r) + return } - } -} - -func (ctrl *Controller) renderIndexPage(dir http.FileSystem, rw http.ResponseWriter, _ *http.Request) { - f, err := dir.Open("/index.html") - if err != nil { - renderServerError(rw, fmt.Sprintf("could not find file index.html: %q", err)) - return - } - b, err := ioutil.ReadAll(f) - if err != nil { - renderServerError(rw, fmt.Sprintf("could not read file index.html: %q", err)) - return - } - - tmpl, err := template.New("index.html").Parse(string(b)) - if err != nil { - renderServerError(rw, fmt.Sprintf("could not parse index.html template: %q", err)) - return - } + jwtCookie, err := r.Cookie(jwtCookieName) + if err != nil { + ctrl.log.WithFields(logrus.Fields{ + "url": r.URL.String(), + "host": r.Header.Get("Host"), + }).Debug("missing jwt cookie") + http.Redirect(w, r, "/login", http.StatusTemporaryRedirect) + return + } - initialStateObj := indexPageJSON{} - ctrl.storage.GetValues("__name__", func(v string) bool { - initialStateObj.AppNames = append(initialStateObj.AppNames, v) - return true - }) - b, err = json.Marshal(initialStateObj) - if err != nil { - renderServerError(rw, fmt.Sprintf("could not marshal initialStateObj json: %q", err)) - return - } - initialStateStr := string(b) + _, err = jwt.Parse(jwtCookie.Value, func(token *jwt.Token) (interface{}, error) { + if token.Method.Alg() != jwt.SigningMethodHS256.Alg() { + return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) + } + return []byte(ctrl.config.JWTSecret), nil + }) - var extraMetadataStr string - extraMetadataPath := os.Getenv("PYROSCOPE_EXTRA_METADATA") - if extraMetadataPath != "" { - b, err = ioutil.ReadFile(extraMetadataPath) if err != nil { - logrus.Errorf("failed to read file at %s", extraMetadataPath) + ctrl.log.WithError(err).Error("parsing jwt token") + http.Redirect(w, r, "/login", http.StatusTemporaryRedirect) + return } - extraMetadataStr = string(b) - } - rw.Header().Add("Content-Type", "text/html") - err = tmpl.Execute(rw, indexPage{ - InitialState: initialStateStr, - BuildInfo: build.JSON(), - ExtraMetadata: extraMetadataStr, - BaseURL: ctrl.config.BaseURL, - }) - if err != nil { - renderServerError(rw, fmt.Sprintf("could not marshal json: %q", err)) - return + next.ServeHTTP(w, r) } } diff --git a/pkg/server/handler.go b/pkg/server/handler.go new file mode 100644 index 0000000000..2ff6dc37b9 --- /dev/null +++ b/pkg/server/handler.go @@ -0,0 +1,427 @@ +package server + +import ( + "crypto/rand" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "os" + "strings" + "text/template" + "time" + + "github.com/dgrijalva/jwt-go" + "github.com/pyroscope-io/pyroscope/pkg/build" + "github.com/sirupsen/logrus" +) + +func (ctrl *Controller) loginHandler() http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + tmplt, err := ctrl.getTemplate("/login.html") + if err != nil { + renderServerError(w, err.Error()) + return + } + params := map[string]interface{}{ + "GoogleEnabled": ctrl.config.GoogleEnabled, + "GithubEnabled": ctrl.config.GithubEnabled, + "GitlabEnabled": ctrl.config.GitlabEnabled, + "BaseURL": ctrl.config.BaseURL, + } + + tmplt.Execute(w, params) + } +} + +func createCookie(w http.ResponseWriter, name, value string) { + cookie := &http.Cookie{ + Name: name, + Path: "/", + Value: value, + HttpOnly: true, + MaxAge: 0, + SameSite: http.SameSiteStrictMode, + } + http.SetCookie(w, cookie) +} + +func invalidateCookie(w http.ResponseWriter, name string) { + cookie := &http.Cookie{ + Name: name, + Path: "/", + Value: "", + HttpOnly: true, + // MaxAge -1 request cookie be deleted immediately + MaxAge: -1, + SameSite: http.SameSiteStrictMode, + } + + http.SetCookie(w, cookie) +} + +func (ctrl *Controller) logoutHandler() http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + if r.Method != "POST" && r.Method != "DELETE" { + renderServerError(w, "you can only logout via a POST or DELETE") + return + } + invalidateCookie(w, jwtCookieName) + http.Redirect(w, r, "/login", http.StatusTemporaryRedirect) + } +} + +// can be replaced with a faster solution if cryptographic randomness isn't a priority +func generateStateToken(length int) (string, error) { + b := make([]byte, length) + if _, err := rand.Read(b); err != nil { + return "", err + } + return hex.EncodeToString(b), nil +} + +func getCallbackURL(host, configCallbackURL string, oauthType int, hasTLS bool) (string, error) { + if configCallbackURL != "" { + return configCallbackURL, nil + } + + if host == "" { + return "", errors.New("host is empty") + } + + schema := "http" + if hasTLS { + schema = "https" + } + + switch oauthType { + case oauthGoogle: + return fmt.Sprintf("%v://%v/auth/google/callback", schema, host), nil + case oauthGithub: + return fmt.Sprintf("%v://%v/auth/github/callback", schema, host), nil + case oauthGitlab: + return fmt.Sprintf("%v://%v/auth/gitlab/callback", schema, host), nil + } + + return "", errors.New("invalid oauth type provided") +} + +func (ctrl *Controller) oauthLoginHandler(info *oauthInfo) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + callbackURL, err := getCallbackURL(r.Host, info.Config.RedirectURL, info.Type, r.URL.Query().Get("tls") == "true") + if err != nil { + ctrl.log.WithError(err).Error("callbackURL parsing failed") + return + } + + authURL := *info.AuthURL + parameters := url.Values{} + parameters.Add("client_id", info.Config.ClientID) + parameters.Add("scope", strings.Join(info.Config.Scopes, " ")) + parameters.Add("redirect_uri", callbackURL) + parameters.Add("response_type", "code") + + // generate state token for CSRF protection + state, err := generateStateToken(16) + if err != nil { + ctrl.log.WithError(err).Error("problem generating state token") + w.WriteHeader(http.StatusInternalServerError) + return + } + + createCookie(w, stateCookieName, state) + parameters.Add("state", state) + authURL.RawQuery = parameters.Encode() + + http.Redirect(w, r, authURL.String(), http.StatusTemporaryRedirect) + } +} + +// Instead of this handler that just redirects, Javascript code can be added to load the state and send it to backend +// this is done so that the state cookie would be send back from browser +func (ctrl *Controller) callbackHandler(redirectURL string) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + tmplt, err := ctrl.getTemplate("/redirect.html") + if err != nil { + renderServerError(w, err.Error()) + return + } + + params := map[string]interface{}{ + "RedirectURL": redirectURL + "?" + r.URL.RawQuery, + "BaseURL": ctrl.config.BaseURL, + } + + tmplt.Execute(w, params) + } +} + +func (ctrl *Controller) forbiddenHandler() http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + tmplt, err := ctrl.getTemplate("/forbidden.html") + if err != nil { + renderServerError(w, err.Error()) + return + } + + tmplt.Execute(w, map[string]interface{}{ + "BaseURL": ctrl.config.BaseURL, + }) + } +} + +func (ctrl *Controller) decodeGoogleCallbackResponse(resp *http.Response) (string, error) { + type callbackResponse struct { + ID string + Email string + VerifiedEmail bool + Picture string + } + + var userProfile callbackResponse + err := json.NewDecoder(resp.Body).Decode(&userProfile) + if err != nil { + return "", err + } + + return userProfile.Email, nil +} + +func (ctrl *Controller) decodeGithubCallbackResponse(resp *http.Response) (string, error) { + type callbackResponse struct { + ID int64 + Email string + Login string + AvatarURL string + } + + var userProfile callbackResponse + err := json.NewDecoder(resp.Body).Decode(&userProfile) + if err != nil { + return "", err + } + + return userProfile.Login, nil +} + +func (ctrl *Controller) decodeGitLabCallbackResponse(resp *http.Response) (string, error) { + type callbackResponse struct { + ID int64 + Email string + Username string + AvatarURL string + } + + var userProfile callbackResponse + err := json.NewDecoder(resp.Body).Decode(&userProfile) + if err != nil { + return "", nil + } + + return userProfile.Username, nil +} + +func (ctrl *Controller) newJWTToken(name string) (string, error) { + claims := jwt.MapClaims{ + "iat": time.Now().Unix(), + "name": name, + } + + if ctrl.config.LoginMaximumLifetimeDays > 0 { + claims["exp"] = time.Now().Add(time.Hour * 24 * time.Duration(ctrl.config.LoginMaximumLifetimeDays)).Unix() + } + + jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + tk, err := jwtToken.SignedString([]byte(ctrl.config.JWTSecret)) + if err != nil { + return "", err + } + + return tk, nil +} + +func (ctrl *Controller) logErrorAndRedirect(w http.ResponseWriter, r *http.Request, logString string, err error) { + if err != nil { + ctrl.log.WithError(err).Error(logString) + } else { + ctrl.log.Error(logString) + } + + invalidateCookie(w, stateCookieName) + + http.Redirect(w, r, "/forbidden", http.StatusTemporaryRedirect) + return +} + +func (ctrl *Controller) callbackRedirectHandler(getAccountInfoURL string, info *oauthInfo, decodeResponse decodeResponseFunc) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + callbackURL, err := getCallbackURL(r.Host, info.Config.RedirectURL, info.Type, r.URL.Query().Get("tls") == "true") + if err != nil { + ctrl.logErrorAndRedirect(w, r, "callbackURL parsing failed", nil) + ctrl.log.WithError(err).Error("") + return + } + + oauthConf := *info.Config + oauthConf.RedirectURL = callbackURL + + cookie, err := r.Cookie(stateCookieName) + if err != nil { + ctrl.logErrorAndRedirect(w, r, "missing state cookie", err) + return + } + + cookieState := cookie.Value + requestState := r.FormValue("state") + + if requestState != cookieState { + ctrl.logErrorAndRedirect(w, r, "invalid oauth state", nil) + return + } + + code := r.FormValue("code") + if code == "" { + ctrl.logErrorAndRedirect(w, r, "code not found", nil) + return + } + + token, err := oauthConf.Exchange(r.Context(), code) + if err != nil { + ctrl.logErrorAndRedirect(w, r, "exchanging auth code for token failed", err) + return + } + + client := oauthConf.Client(r.Context(), token) + resp, err := client.Get(getAccountInfoURL) + if err != nil { + ctrl.logErrorAndRedirect(w, r, "failed to get oauth user info", err) + return + } + defer resp.Body.Close() + + name, err := decodeResponse(resp) + if err != nil { + ctrl.logErrorAndRedirect(w, r, "decoding response body failed", err) + return + } + + tk, err := ctrl.newJWTToken(name) + if err != nil { + ctrl.logErrorAndRedirect(w, r, "signing jwt failed", err) + return + } + + // delete state cookie and add jwt cookie + invalidateCookie(w, stateCookieName) + createCookie(w, jwtCookieName, tk) + + tmplt, err := ctrl.getTemplate("/welcome.html") + if err != nil { + renderServerError(w, err.Error()) + return + } + + params := map[string]interface{}{ + "Name": name, + "BaseURL": ctrl.config.BaseURL, + } + + tmplt.Execute(w, params) + return + } +} + +func (ctrl *Controller) indexHandler() http.HandlerFunc { + fs := http.FileServer(ctrl.dir) + return func(rw http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/" { + ctrl.statsInc("index") + ctrl.renderIndexPage(rw, r) + } else if r.URL.Path == "/comparison" { + ctrl.statsInc("index") + ctrl.renderIndexPage(rw, r) + } else { + fs.ServeHTTP(rw, r) + } + } +} + +func renderServerError(rw http.ResponseWriter, text string) { + rw.WriteHeader(500) + rw.Write([]byte(text)) + rw.Write([]byte("\n")) +} + +type indexPageJSON struct { + AppNames []string `json:"appNames"` +} +type indexPage struct { + InitialState string + BuildInfo string + ExtraMetadata string + BaseURL string +} + +func (ctrl *Controller) getTemplate(path string) (*template.Template, error) { + f, err := ctrl.dir.Open(path) + if err != nil { + return nil, fmt.Errorf("could not find file %s: %q", path, err) + } + + b, err := ioutil.ReadAll(f) + if err != nil { + return nil, fmt.Errorf("could not read file %s: %q", path, err) + } + + tmpl, err := template.New(path).Parse(string(b)) + if err != nil { + return nil, fmt.Errorf("could not parse %s template: %q", path, err) + } + return tmpl, nil +} + +func (ctrl *Controller) renderIndexPage(rw http.ResponseWriter, _ *http.Request) { + var b []byte + tmpl, err := ctrl.getTemplate("/index.html") + if err != nil { + renderServerError(rw, err.Error()) + return + } + + initialStateObj := indexPageJSON{} + ctrl.storage.GetValues("__name__", func(v string) bool { + initialStateObj.AppNames = append(initialStateObj.AppNames, v) + return true + }) + b, err = json.Marshal(initialStateObj) + if err != nil { + renderServerError(rw, fmt.Sprintf("could not marshal initialStateObj json: %q", err)) + return + } + initialStateStr := string(b) + + var extraMetadataStr string + extraMetadataPath := os.Getenv("PYROSCOPE_EXTRA_METADATA") + if extraMetadataPath != "" { + b, err = ioutil.ReadFile(extraMetadataPath) + if err != nil { + logrus.Errorf("failed to read file at %s", extraMetadataPath) + } + extraMetadataStr = string(b) + } + + rw.Header().Add("Content-Type", "text/html") + err = tmpl.Execute(rw, indexPage{ + InitialState: initialStateStr, + BuildInfo: build.JSON(), + ExtraMetadata: extraMetadataStr, + BaseURL: ctrl.config.BaseURL, + }) + if err != nil { + renderServerError(rw, fmt.Sprintf("could not marshal json: %q", err)) + return + } +} diff --git a/pkg/server/ingest_test.go b/pkg/server/ingest_test.go index afa3734d5e..7ef2d3909e 100644 --- a/pkg/server/ingest_test.go +++ b/pkg/server/ingest_test.go @@ -10,6 +10,7 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "github.com/sirupsen/logrus" "github.com/pyroscope-io/pyroscope/pkg/config" "github.com/pyroscope-io/pyroscope/pkg/storage" @@ -37,7 +38,7 @@ var _ = Describe("server", func() { s, err := storage.New(&(*cfg).Server) Expect(err).ToNot(HaveOccurred()) - c, _ := New(&(*cfg).Server, s) + c, _ := New(&(*cfg).Server, s, logrus.New()) httpServer := httptest.NewServer(c.mux()) defer s.Close() diff --git a/scripts/webpack/webpack.common.js b/scripts/webpack/webpack.common.js index f82d4a3ab2..6a3ba34f70 100644 --- a/scripts/webpack/webpack.common.js +++ b/scripts/webpack/webpack.common.js @@ -1,5 +1,6 @@ const webpack = require("webpack"); const path = require("path"); +const glob = require("glob"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const CopyPlugin = require("copy-webpack-plugin"); @@ -7,6 +8,29 @@ const ESLintPlugin = require("eslint-webpack-plugin"); const fs = require("fs"); +let pages = glob.sync("./webapp/templates/*.html").map((x) => path.basename(x)); +let pagePlugins = pages.map((name) => { + return new HtmlWebpackPlugin({ + filename: path.resolve(__dirname, "../../webapp/public/" + name), + template: path.resolve(__dirname, "../../webapp/templates/" + name), + inject: false, + chunksSortMode: "none", + templateParameters: (compilation, assets, options) => ({ + extra_metadata: process.env.EXTRA_METADATA + ? fs.readFileSync(process.env.EXTRA_METADATA) + : "", + mode: process.env.NODE_ENV, + webpack: compilation.getStats().toJson(), + compilation, + webpackConfig: compilation.options, + htmlWebpackPlugin: { + files: assets, + options, + }, + }), + }); +}); + module.exports = { target: "web", @@ -17,7 +41,7 @@ module.exports = { output: { publicPath: "", - path: path.resolve(__dirname, "../../webapp/public/build"), + path: path.resolve(__dirname, "../../webapp/public/assets"), filename: "[name].[hash].js", }, @@ -93,21 +117,6 @@ module.exports = { }, ], }, - { - test: /\.html$/, - exclude: /(index|error)\.html/, - use: [ - { - loader: "html-loader", - options: { - attrs: [], - minimize: true, - removeComments: false, - collapseWhitespace: false, - }, - }, - ], - }, { test: /\.css$/, // include: MONACO_DIR, // https://github.com/react-monaco-editor/react-monaco-editor @@ -154,25 +163,7 @@ module.exports = { $: "jquery", jQuery: "jquery", }), - new HtmlWebpackPlugin({ - filename: path.resolve(__dirname, "../../webapp/public/index.html"), - template: path.resolve(__dirname, "../../webapp/templates/index.html"), - inject: false, - chunksSortMode: "none", - templateParameters: (compilation, assets, options) => ({ - extra_metadata: process.env.EXTRA_METADATA - ? fs.readFileSync(process.env.EXTRA_METADATA) - : "", - mode: process.env.NODE_ENV, - webpack: compilation.getStats().toJson(), - compilation, - webpackConfig: compilation.options, - htmlWebpackPlugin: { - files: assets, - options, - }, - }), - }), + ...pagePlugins, new MiniCssExtractPlugin({ filename: "[name].[hash].css", }), @@ -184,6 +175,6 @@ module.exports = { to: "images", }, ], - }), + }) ], }; diff --git a/webapp/__tests__/ShortcutsModal.spec.js b/webapp/__tests__/ShortcutsModal.spec.js index a5e6f73fb8..b4d02bcf95 100644 --- a/webapp/__tests__/ShortcutsModal.spec.js +++ b/webapp/__tests__/ShortcutsModal.spec.js @@ -22,8 +22,8 @@ describe("ShortcutsModal", () => { ); - - wrapper.find("button").last().simulate("click"); + + wrapper.find("#tests-shortcuts-btn").last().simulate("click"); expect(wrapper.find(ShortcutsModal).length).toBe(1); }); diff --git a/webapp/images/logo-v3-small.svg b/webapp/images/logo-v3-small.svg new file mode 100644 index 0000000000..ef2575bdcc --- /dev/null +++ b/webapp/images/logo-v3-small.svg @@ -0,0 +1,32 @@ + + + Artboard@2x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/webapp/javascript/components/Sidebar.jsx b/webapp/javascript/components/Sidebar.jsx index de6b6a2a73..4882a9f171 100644 --- a/webapp/javascript/components/Sidebar.jsx +++ b/webapp/javascript/components/Sidebar.jsx @@ -12,6 +12,7 @@ import { faKeyboard, faColumns, faBell, + faSignOutAlt, } from "@fortawesome/free-solid-svg-icons"; import { faWindowMaximize } from "@fortawesome/free-regular-svg-icons"; import { faGithub } from "@fortawesome/free-brands-svg-icons"; @@ -43,6 +44,17 @@ function SidebarItem(props) { ); } +function signOut(){ + var form = document.createElement("form"); + + form.method = "POST"; + form.action = "/logout"; + + document.body.appendChild(form); + + form.submit(); +} + const initialState = { shortcutsModalOpen: false, currentRoute: "/", @@ -131,10 +143,18 @@ function Sidebar(props) { - + + +