Compare commits
25 commits
develop
...
acceptance
Author | SHA1 | Date | |
---|---|---|---|
![]() |
18c8254cea | ||
![]() |
d6e81cc0b3 | ||
![]() |
23f12e38ca | ||
![]() |
8d8f0df58f | ||
![]() |
e3099e0cb6 | ||
![]() |
8b00cd068c | ||
![]() |
f278fb69c1 | ||
![]() |
a7400d6477 | ||
![]() |
5bac7ba11d | ||
![]() |
24f6041a76 | ||
![]() |
1ae85a0e04 | ||
![]() |
b5ddd0d3bb | ||
![]() |
d51f24bde9 | ||
![]() |
da7035c106 | ||
![]() |
9bdc38be9a | ||
![]() |
dea527591e | ||
![]() |
0cc9dcb2b9 | ||
![]() |
d6fd6cf297 | ||
![]() |
457085d7bd | ||
![]() |
d7aa739d26 | ||
![]() |
5d26325b7d | ||
![]() |
7e754e8cfa | ||
![]() |
e7db639c54 | ||
![]() |
6634e8a56b | ||
![]() |
aa8ebc2076 |
42 changed files with 2069 additions and 263 deletions
6
Makefile
6
Makefile
|
@ -41,6 +41,7 @@ upgrade: dep-upgrade-js dep-upgrade
|
|||
clean-local: clean-local-config clean-local-cache
|
||||
clean-install: clean-local dep build-js install-bin install-assets
|
||||
dev: dev-npm dev-go-amd64
|
||||
debug-go: build-go-remote start-debug
|
||||
dev-npm:
|
||||
$(info Upgrading NPM in local dev environment...)
|
||||
sudo npm update -g npm
|
||||
|
@ -123,6 +124,8 @@ build-js:
|
|||
build-go:
|
||||
rm -f $(BINARY_NAME)
|
||||
scripts/build.sh debug $(BINARY_NAME)
|
||||
build-go-remote:
|
||||
docker-compose exec -u root photoprism make build-go
|
||||
build-race:
|
||||
rm -f $(BINARY_NAME)
|
||||
scripts/build.sh race $(BINARY_NAME)
|
||||
|
@ -135,6 +138,9 @@ build-tensorflow:
|
|||
build-tensorflow-arm64:
|
||||
docker build -t photoprism/tensorflow:arm64 docker/tensorflow/arm64
|
||||
docker run -ti photoprism/tensorflow:arm64 bash
|
||||
start-debug:
|
||||
docker-compose exec -u root photoprism go install github.com/go-delve/delve/cmd/dlv@latest
|
||||
docker-compose exec -u root photoprism dlv --listen=:40000 --headless=true --api-version=2 --accept-multiclient exec ./photoprism start
|
||||
watch-js:
|
||||
(cd frontend && env NODE_ENV=development npm run watch)
|
||||
test-js:
|
||||
|
|
57
assets/templates/callback.tmpl
Normal file
57
assets/templates/callback.tmpl
Normal file
|
@ -0,0 +1,57 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0{{if not .config.Settings.UI.Zoom }}, maximum-scale=1.0, user-scalable=no{{end}}">
|
||||
<title>{{ .config.SiteTitle }}</title>
|
||||
|
||||
<meta property="og:url" content="{{ .config.SiteUrl }}">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:title" content="{{ .config.SiteTitle }}{{if .config.SiteCaption}}: {{ .config.SiteCaption }}{{end}}">
|
||||
<meta property="og:image" content="{{ .config.SitePreview }}">
|
||||
<meta property="og:description" content="{{ .config.SiteDescription }}">
|
||||
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="{{ .config.SiteTitle }}{{if .config.SiteCaption}}: {{ .config.SiteCaption }}{{end}}">
|
||||
<meta name="twitter:image" content="{{ .config.SitePreview }}">
|
||||
<meta name="twitter:description" content="{{ .config.SiteDescription }}">
|
||||
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<meta name="apple-mobile-web-app-title" content="{{ .config.SiteTitle }}">
|
||||
|
||||
{{if .config.SiteAuthor}}<meta name="author" content="{{ .config.SiteAuthor }}">{{end}}
|
||||
{{if .config.SiteDescription}}<meta name="description" content="{{ .config.SiteDescription }}"/>{{end}}
|
||||
|
||||
{{template "favicons.tmpl" .}}
|
||||
|
||||
<link rel="stylesheet" href="/static/build/app.css?{{ .config.CSSHash }}">
|
||||
<link rel="manifest" href="/static/manifest.json?{{ .config.ManifestHash }}">
|
||||
|
||||
<script>
|
||||
window.__CONFIG__ = {{ .config }};
|
||||
</script>
|
||||
</head>
|
||||
<body class="{{ .config.Flags }}">
|
||||
{{ if and .status (eq .status "ok") }}
|
||||
<p class="browserupgrade">Login successful. Window can be closed.</p>
|
||||
{{ else if and .status (eq .status "error") }}
|
||||
<p class="browserupgrade">Login Error: {{ .errors }}</p>
|
||||
{{ else }}
|
||||
<p class="browserupgrade">Undefined State or deprecated link user flow...</p>
|
||||
{{ end }}
|
||||
|
||||
<script>
|
||||
{{ if and .status (eq .status "ok") }}
|
||||
window.localStorage.setItem("session_id", {{ .id }})
|
||||
window.localStorage.setItem("data", JSON.stringify({{ .data }}));
|
||||
window.localStorage.setItem("config", JSON.stringify({{ .config }}));
|
||||
{{ else if and .status (eq .status "error") }}
|
||||
window.localStorage.setItem("auth_error", {{ .errors }});
|
||||
{{ else }}
|
||||
window.localStorage.setItem("link_user", JSON.stringify({{ .linkUser }}));
|
||||
{{ end }}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -13,6 +13,7 @@ services:
|
|||
ports:
|
||||
- "2342:2342" # Web Server (PhotoPrism)
|
||||
- "2343:2343" # Acceptance Tests
|
||||
- "40000:40000" # Go Debugging
|
||||
working_dir: "/go/src/github.com/photoprism/photoprism"
|
||||
volumes:
|
||||
- ".:/go/src/github.com/photoprism/photoprism"
|
||||
|
@ -27,7 +28,7 @@ services:
|
|||
PHOTOPRISM_SITE_AUTHOR: "@photoprism_app"
|
||||
PHOTOPRISM_DEBUG: "true"
|
||||
PHOTOPRISM_READONLY: "false"
|
||||
PHOTOPRISM_PUBLIC: "true"
|
||||
PHOTOPRISM_PUBLIC: "false"
|
||||
PHOTOPRISM_EXPERIMENTAL: "true"
|
||||
PHOTOPRISM_SERVER_MODE: "debug"
|
||||
PHOTOPRISM_HTTP_HOST: "0.0.0.0"
|
||||
|
@ -62,6 +63,13 @@ services:
|
|||
PHOTOPRISM_JPEG_SIZE: 7680 # Size limit for converted image files in pixels (720-30000)
|
||||
PHOTOPRISM_JPEG_QUALITY: 92 # Set to 95 for high-quality thumbnails (25-100)
|
||||
TF_CPP_MIN_LOG_LEVEL: 0 # Show TensorFlow log messages for development
|
||||
HOME: "/photoprism"
|
||||
PHOTOPRISM_OIDC_ISSUER: "https://keycloak.timovolkmann.de/auth/realms/master"
|
||||
PHOTOPRISM_OIDC_CLIENT_ID: "photoprism-dev"
|
||||
PHOTOPRISM_OIDC_CLIENT_SECRET: "9d8351a0-ca01-4556-9c37-85eb634869b9"
|
||||
# PHOTOPRISM_OIDC_ISSUER: "https://accounts.google.com"
|
||||
# PHOTOPRISM_OIDC_CLIENT_ID: "86720117204-mb09c300nas5r9rid1ad0omv67nlvhck.apps.googleusercontent.com"
|
||||
# PHOTOPRISM_OIDC_CLIENT_SECRET: "WQ2-LdfhYhHd-BdpfZCYGE12"
|
||||
|
||||
mariadb:
|
||||
image: mariadb:10.5
|
||||
|
@ -81,6 +89,12 @@ services:
|
|||
webdav-dummy:
|
||||
image: photoprism/webdav:20210602
|
||||
|
||||
oidc-test-op:
|
||||
build: docker/oidc/.
|
||||
image: test-op:latest
|
||||
ports:
|
||||
- "9998:9998"
|
||||
|
||||
volumes:
|
||||
go-mod:
|
||||
driver: local
|
||||
|
|
19
docker/oidc/Dockerfile
Normal file
19
docker/oidc/Dockerfile
Normal file
|
@ -0,0 +1,19 @@
|
|||
FROM golang:1.17-alpine
|
||||
|
||||
# Move to working directory /app
|
||||
WORKDIR /app
|
||||
|
||||
# Copy files and download dependency using go mod
|
||||
COPY . .
|
||||
RUN go mod download
|
||||
|
||||
# Build the application
|
||||
RUN go build -o test-op .
|
||||
|
||||
# Allow HTTP scheme
|
||||
ENV CAOS_OIDC_DEV=true
|
||||
|
||||
# Expose HTTP port
|
||||
EXPOSE 9998
|
||||
|
||||
CMD ["/app/test-op"]
|
26
docker/oidc/go.mod
Normal file
26
docker/oidc/go.mod
Normal file
|
@ -0,0 +1,26 @@
|
|||
module caos-test-op
|
||||
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/caos/oidc v0.15.10
|
||||
github.com/gorilla/mux v1.8.0
|
||||
gopkg.in/square/go-jose.v2 v2.6.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/caos/logging v0.0.2 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.1 // indirect
|
||||
github.com/golang/protobuf v1.4.2 // indirect
|
||||
github.com/gorilla/handlers v1.5.1 // indirect
|
||||
github.com/gorilla/schema v1.2.0 // indirect
|
||||
github.com/gorilla/securecookie v1.1.1 // indirect
|
||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||
golang.org/x/crypto v0.0.0-20201217014255-9d1352758620 // indirect
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 // indirect
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
google.golang.org/appengine v1.6.6 // indirect
|
||||
google.golang.org/protobuf v1.25.0 // indirect
|
||||
)
|
420
docker/oidc/go.sum
Normal file
420
docker/oidc/go.sum
Normal file
|
@ -0,0 +1,420 @@
|
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
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/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/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/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/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/caos/logging v0.0.2 h1:ebg5C/HN0ludYR+WkvnFjwSExF4wvyiWPyWGcKMYsoo=
|
||||
github.com/caos/logging v0.0.2/go.mod h1:9LKiDE2ChuGv6CHYif/kiugrfEXu9AwDiFWSreX7Wp0=
|
||||
github.com/caos/oidc v0.15.10 h1:dSzkIvsZR2PSZgvBFFkLJt8A/MujsyLac1yNvBShXuw=
|
||||
github.com/caos/oidc v0.15.10/go.mod h1:4l0PPwdc6BbrdCFhNrRTUddsG292uHGa7gE2DSEIqoU=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
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/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/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/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
|
||||
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
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=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
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/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
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=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
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 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-github/v31 v31.0.0/go.mod h1:NQPZol8/1sMoWYGN2yaALIBytu17gAWfhbweiEed3pM=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
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/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
|
||||
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc=
|
||||
github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU=
|
||||
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
|
||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
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/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
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.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
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=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201217014255-9d1352758620 h1:3wPMTskHO3+O6jqTEXyFcsnuxMQOqYSaHsDxcbUXpqA=
|
||||
golang.org/x/crypto v0.0.0-20201217014255-9d1352758620/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
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-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/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-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-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/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 h1:ld7aEMNHoBnnDAX15v1T6z31v8HwR2A9FYOuAhWqkwc=
|
||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/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-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191206220618-eeba5f6aabab/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
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-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
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-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-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.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
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=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
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/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=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
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.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=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
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/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
|
||||
gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
|
||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/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=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
382
docker/oidc/mock/storage.go
Normal file
382
docker/oidc/mock/storage.go
Normal file
|
@ -0,0 +1,382 @@
|
|||
package mock
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"gopkg.in/square/go-jose.v2"
|
||||
|
||||
"github.com/caos/oidc/pkg/oidc"
|
||||
"github.com/caos/oidc/pkg/op"
|
||||
)
|
||||
|
||||
type AuthStorage struct {
|
||||
key *rsa.PrivateKey
|
||||
kid string
|
||||
}
|
||||
|
||||
func NewAuthStorage() op.Storage {
|
||||
key, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
b := make([]byte, 16)
|
||||
rand.Read(b)
|
||||
|
||||
return &AuthStorage{
|
||||
key: key,
|
||||
kid: string(b),
|
||||
}
|
||||
}
|
||||
|
||||
type AuthRequest struct {
|
||||
ID string
|
||||
ResponseType oidc.ResponseType
|
||||
RedirectURI string
|
||||
Nonce string
|
||||
ClientID string
|
||||
CodeChallenge *oidc.CodeChallenge
|
||||
}
|
||||
|
||||
func (a *AuthRequest) GetACR() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (a *AuthRequest) GetAMR() []string {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
func (a *AuthRequest) GetAudience() []string {
|
||||
return []string{
|
||||
a.ClientID,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *AuthRequest) GetAuthTime() time.Time {
|
||||
return time.Now().UTC()
|
||||
}
|
||||
|
||||
func (a *AuthRequest) GetClientID() string {
|
||||
return a.ClientID
|
||||
}
|
||||
|
||||
//func (a *AuthRequest) GetCode() string {
|
||||
// return "GetCode"
|
||||
//}
|
||||
//
|
||||
func (a *AuthRequest) GetCodeChallenge() *oidc.CodeChallenge {
|
||||
fmt.Println("GetCodeChallenge: ", a.CodeChallenge.Challenge, a.CodeChallenge.Method)
|
||||
return a.CodeChallenge
|
||||
}
|
||||
|
||||
func (a *AuthRequest) GetID() string {
|
||||
return a.ID
|
||||
}
|
||||
|
||||
func (a *AuthRequest) GetNonce() string {
|
||||
return a.Nonce
|
||||
}
|
||||
|
||||
func (a *AuthRequest) GetRedirectURI() string {
|
||||
return a.RedirectURI
|
||||
// return "http://localhost:5556/auth/callback"
|
||||
}
|
||||
|
||||
func (a *AuthRequest) GetResponseType() oidc.ResponseType {
|
||||
return a.ResponseType
|
||||
}
|
||||
|
||||
func (a *AuthRequest) GetScopes() []string {
|
||||
return []string{
|
||||
"openid",
|
||||
"profile",
|
||||
"email",
|
||||
}
|
||||
}
|
||||
|
||||
func (a *AuthRequest) SetCurrentScopes(scopes []string) {}
|
||||
|
||||
func (a *AuthRequest) GetState() string {
|
||||
return state
|
||||
}
|
||||
|
||||
func (a *AuthRequest) GetSubject() string {
|
||||
return "sub00000001"
|
||||
}
|
||||
|
||||
func (a *AuthRequest) Done() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
var (
|
||||
a = &AuthRequest{}
|
||||
t bool
|
||||
c string
|
||||
state string
|
||||
)
|
||||
|
||||
func (s *AuthStorage) Health(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *AuthStorage) CreateAuthRequest(_ context.Context, authReq *oidc.AuthRequest, userId string) (op.AuthRequest, error) {
|
||||
fmt.Println("Userid: ", userId)
|
||||
fmt.Println("CreateAuthRequest ID: ", authReq.ID)
|
||||
fmt.Println("CreateAuthRequest CodeChallenge: ", authReq.CodeChallenge)
|
||||
fmt.Println("CreateAuthRequest CodeChallengeMethod: ", authReq.CodeChallengeMethod)
|
||||
fmt.Println("CreateAuthRequest State: ", authReq.State)
|
||||
fmt.Println("CreateAuthRequest ClientID: ", authReq.ClientID)
|
||||
fmt.Println("CreateAuthRequest ResponseType: ", authReq.ResponseType)
|
||||
fmt.Println("CreateAuthRequest Nonce: ", authReq.Nonce)
|
||||
fmt.Println("CreateAuthRequest Scopes: ", authReq.Scopes)
|
||||
fmt.Println("CreateAuthRequest Display: ", authReq.Display)
|
||||
fmt.Println("CreateAuthRequest LoginHint: ", authReq.LoginHint)
|
||||
fmt.Println("CreateAuthRequest IDTokenHint: ", authReq.IDTokenHint)
|
||||
a = &AuthRequest{ID: "authReqUserAgentId", ClientID: authReq.ClientID, ResponseType: authReq.ResponseType, Nonce: authReq.Nonce, RedirectURI: authReq.RedirectURI}
|
||||
if authReq.CodeChallenge != "" {
|
||||
a.CodeChallenge = &oidc.CodeChallenge{
|
||||
Challenge: authReq.CodeChallenge,
|
||||
Method: authReq.CodeChallengeMethod,
|
||||
}
|
||||
}
|
||||
state = authReq.State
|
||||
t = false
|
||||
return a, nil
|
||||
}
|
||||
func (s *AuthStorage) AuthRequestByCode(_ context.Context, code string) (op.AuthRequest, error) {
|
||||
if code != c {
|
||||
return nil, errors.New("invalid code")
|
||||
}
|
||||
return a, nil
|
||||
}
|
||||
func (s *AuthStorage) SaveAuthCode(_ context.Context, id, code string) error {
|
||||
if a.ID != id {
|
||||
return errors.New("SaveAuthCode: not found")
|
||||
}
|
||||
c = code
|
||||
return nil
|
||||
}
|
||||
func (s *AuthStorage) DeleteAuthRequest(context.Context, string) error {
|
||||
t = true
|
||||
return nil
|
||||
}
|
||||
func (s *AuthStorage) AuthRequestByID(_ context.Context, id string) (op.AuthRequest, error) {
|
||||
fmt.Println("AuthRequestByID: ", id)
|
||||
if id != "authReqUserAgentId:usertoken" || t {
|
||||
return nil, errors.New("AuthRequestByID: not found")
|
||||
}
|
||||
return a, nil
|
||||
}
|
||||
func (s *AuthStorage) CreateAccessToken(ctx context.Context, request op.TokenRequest) (string, time.Time, error) {
|
||||
return "loginId", time.Now().UTC().Add(5 * time.Minute), nil
|
||||
}
|
||||
func (s *AuthStorage) CreateAccessAndRefreshTokens(ctx context.Context, request op.TokenRequest, currentRefreshToken string) (accessTokenID string, newRefreshToken string, expiration time.Time, err error) {
|
||||
return "loginId", "refreshToken", time.Now().UTC().Add(5 * time.Minute), nil
|
||||
}
|
||||
func (s *AuthStorage) TokenRequestByRefreshToken(ctx context.Context, refreshToken string) (op.RefreshTokenRequest, error) {
|
||||
if refreshToken != c {
|
||||
return nil, errors.New("invalid token")
|
||||
}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
func (s *AuthStorage) TerminateSession(_ context.Context, userID, clientID string) error {
|
||||
return nil
|
||||
}
|
||||
func (s *AuthStorage) GetSigningKey(_ context.Context, keyCh chan<- jose.SigningKey) {
|
||||
//keyCh <- jose.SigningKey{Algorithm: jose.RS256, Key: s.key}
|
||||
keyCh <- jose.SigningKey{Algorithm: jose.RS256, Key: &jose.JSONWebKey{Key: s.key, KeyID: s.kid}}
|
||||
}
|
||||
func (s *AuthStorage) GetKey(_ context.Context) (*rsa.PrivateKey, error) {
|
||||
return s.key, nil
|
||||
}
|
||||
func (s *AuthStorage) GetKeySet(_ context.Context) (*jose.JSONWebKeySet, error) {
|
||||
pubkey := s.key.Public()
|
||||
|
||||
wrongkey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return &jose.JSONWebKeySet{
|
||||
Keys: []jose.JSONWebKey{
|
||||
{
|
||||
Key: wrongkey.Public(),
|
||||
Use: "sig",
|
||||
Algorithm: "RS256",
|
||||
KeyID: "wrongkey0002",
|
||||
}, {
|
||||
Key: pubkey,
|
||||
Use: "sig",
|
||||
Algorithm: "RS256",
|
||||
KeyID: s.kid,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
func (s *AuthStorage) GetKeyByIDAndUserID(_ context.Context, _, _ string) (*jose.JSONWebKey, error) {
|
||||
pubkey := s.key.Public()
|
||||
|
||||
return &jose.JSONWebKey{
|
||||
Key: pubkey,
|
||||
Use: "sig",
|
||||
Algorithm: "RS256",
|
||||
KeyID: s.kid,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *AuthStorage) GetClientByClientID(_ context.Context, id string) (op.Client, error) {
|
||||
if id == "none" {
|
||||
return nil, errors.New("GetClientByClientID: not found")
|
||||
}
|
||||
var appType op.ApplicationType
|
||||
var authMethod oidc.AuthMethod
|
||||
var accessTokenType op.AccessTokenType
|
||||
var responseTypes []oidc.ResponseType
|
||||
var grantTypes = []oidc.GrantType{
|
||||
oidc.GrantTypeCode,
|
||||
}
|
||||
if id == "web" {
|
||||
appType = op.ApplicationTypeWeb
|
||||
authMethod = oidc.AuthMethodBasic
|
||||
accessTokenType = op.AccessTokenTypeBearer
|
||||
responseTypes = []oidc.ResponseType{oidc.ResponseTypeCode}
|
||||
} else if id == "native" {
|
||||
appType = op.ApplicationTypeNative
|
||||
authMethod = oidc.AuthMethodBasic
|
||||
accessTokenType = op.AccessTokenTypeBearer
|
||||
responseTypes = []oidc.ResponseType{oidc.ResponseTypeCode, oidc.ResponseTypeIDToken, oidc.ResponseTypeIDTokenOnly}
|
||||
} else {
|
||||
appType = op.ApplicationTypeUserAgent
|
||||
authMethod = oidc.AuthMethodNone
|
||||
accessTokenType = op.AccessTokenTypeJWT
|
||||
responseTypes = []oidc.ResponseType{oidc.ResponseTypeIDToken, oidc.ResponseTypeIDTokenOnly}
|
||||
}
|
||||
return &ConfClient{ID: id, applicationType: appType, authMethod: authMethod, accessTokenType: accessTokenType, responseTypes: responseTypes, grantTypes: grantTypes, devMode: true}, nil
|
||||
}
|
||||
|
||||
func (s *AuthStorage) AuthorizeClientIDSecret(_ context.Context, id string, _ string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *AuthStorage) SetUserinfoFromToken(ctx context.Context, userinfo oidc.UserInfoSetter, _, _, _ string) error {
|
||||
return s.SetUserinfoFromScopes(ctx, userinfo, "", "", []string{})
|
||||
}
|
||||
func (s *AuthStorage) SetUserinfoFromScopes(ctx context.Context, userinfo oidc.UserInfoSetter, _, _ string, _ []string) error {
|
||||
userinfo.SetSubject(a.GetSubject())
|
||||
//userinfo.SetAddress(oidc.NewUserInfoAddress("Test 789\nPostfach 2", "", "", "", "", ""))
|
||||
userinfo.SetEmail("test@example.com", true)
|
||||
userinfo.SetPhone("0791234567", true)
|
||||
userinfo.SetName("Test")
|
||||
userinfo.AppendClaims("private_claim", "test")
|
||||
userinfo.SetNickname("testnick")
|
||||
userinfo.SetPreferredUsername("prefname")
|
||||
return nil
|
||||
}
|
||||
func (s *AuthStorage) GetPrivateClaimsFromScopes(_ context.Context, _, _ string, _ []string) (map[string]interface{}, error) {
|
||||
return map[string]interface{}{"private_claim": "test"}, nil
|
||||
}
|
||||
|
||||
func (s *AuthStorage) SetIntrospectionFromToken(ctx context.Context, introspect oidc.IntrospectionResponse, tokenID, subject, clientID string) error {
|
||||
if err := s.SetUserinfoFromScopes(ctx, introspect, "", "", []string{}); err != nil {
|
||||
return err
|
||||
}
|
||||
introspect.SetClientID(a.ClientID)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *AuthStorage) ValidateJWTProfileScopes(ctx context.Context, userID string, scope []string) ([]string, error) {
|
||||
return scope, nil
|
||||
}
|
||||
|
||||
type ConfClient struct {
|
||||
applicationType op.ApplicationType
|
||||
authMethod oidc.AuthMethod
|
||||
responseTypes []oidc.ResponseType
|
||||
grantTypes []oidc.GrantType
|
||||
ID string
|
||||
accessTokenType op.AccessTokenType
|
||||
devMode bool
|
||||
}
|
||||
|
||||
func (c *ConfClient) GetID() string {
|
||||
return c.ID
|
||||
}
|
||||
func (c *ConfClient) RedirectURIs() []string {
|
||||
return []string{
|
||||
"https://registered.com/callback",
|
||||
"http://localhost:9999/callback",
|
||||
"http://localhost:5556/auth/callback",
|
||||
"custom://callback",
|
||||
"https://localhost:8443/test/a/instructions-example/callback",
|
||||
"https://op.certification.openid.net:62064/authz_cb",
|
||||
"https://op.certification.openid.net:62064/authz_post",
|
||||
"http://localhost:2342/api/v1/auth/callback",
|
||||
}
|
||||
}
|
||||
func (c *ConfClient) PostLogoutRedirectURIs() []string {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
func (c *ConfClient) LoginURL(id string) string {
|
||||
//return "authorize/callback?id=" + id
|
||||
return "login?id=" + id
|
||||
}
|
||||
|
||||
func (c *ConfClient) ApplicationType() op.ApplicationType {
|
||||
return c.applicationType
|
||||
}
|
||||
|
||||
func (c *ConfClient) AuthMethod() oidc.AuthMethod {
|
||||
return c.authMethod
|
||||
}
|
||||
|
||||
func (c *ConfClient) IDTokenLifetime() time.Duration {
|
||||
return 60 * time.Minute
|
||||
}
|
||||
func (c *ConfClient) AccessTokenType() op.AccessTokenType {
|
||||
return c.accessTokenType
|
||||
}
|
||||
func (c *ConfClient) ResponseTypes() []oidc.ResponseType {
|
||||
return c.responseTypes
|
||||
}
|
||||
func (c *ConfClient) GrantTypes() []oidc.GrantType {
|
||||
return c.grantTypes
|
||||
}
|
||||
|
||||
func (c *ConfClient) DevMode() bool {
|
||||
return c.devMode
|
||||
}
|
||||
|
||||
func (c *ConfClient) AllowedScopes() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ConfClient) RestrictAdditionalIdTokenScopes() func(scopes []string) []string {
|
||||
return func(scopes []string) []string {
|
||||
return scopes
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ConfClient) RestrictAdditionalAccessTokenScopes() func(scopes []string) []string {
|
||||
return func(scopes []string) []string {
|
||||
return scopes
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ConfClient) IsScopeAllowed(scope string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *ConfClient) IDTokenUserinfoClaimsAssertion() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *ConfClient) ClockSkew() time.Duration {
|
||||
return 0
|
||||
}
|
54
docker/oidc/server.go
Normal file
54
docker/oidc/server.go
Normal file
|
@ -0,0 +1,54 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"caos-test-op/mock"
|
||||
"github.com/caos/oidc/pkg/op"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx := context.Background()
|
||||
|
||||
b := make([]byte, 32)
|
||||
rand.Read(b)
|
||||
|
||||
port := "9998"
|
||||
config := &op.Config{
|
||||
Issuer: "http://oidc-test-op:9998",
|
||||
CryptoKey: sha256.Sum256(b),
|
||||
CodeMethodS256: true,
|
||||
}
|
||||
storage := mock.NewAuthStorage()
|
||||
|
||||
handler, err := op.NewOpenIDProvider(ctx, config, storage)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
router := handler.HttpHandler().(*mux.Router)
|
||||
router.Methods("GET").Path("/login").HandlerFunc(HandleLogin)
|
||||
server := &http.Server{
|
||||
Addr: ":" + port,
|
||||
Handler: router,
|
||||
}
|
||||
err = server.ListenAndServe()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
<-ctx.Done()
|
||||
}
|
||||
|
||||
func HandleLogin(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
requestId := r.Form.Get("id")
|
||||
// simulate user login and retrieve a token that indicates a successfully logged-in user
|
||||
usertoken := requestId + ":usertoken"
|
||||
|
||||
http.Redirect(w, r, "/authorize/callback?id="+usertoken, http.StatusFound)
|
||||
}
|
|
@ -13,11 +13,11 @@
|
|||
"fmt": "eslint --cache --fix src/ *.js .eslintrc.js",
|
||||
"test": "karma start",
|
||||
"upgrade": "npm --depth 10 update && npm audit fix",
|
||||
"acceptance": "testcafe \"chromium:headless --disable-dev-shm-usage\" --skip-js-errors --quarantine-mode --selector-timeout 5000 -S -s tests/screenshots tests/acceptance",
|
||||
"acceptance-firefox": "testcafe firefox:headless --skip-js-errors --quarantine-mode --selector-timeout 5000 -S -s tests/screenshots tests/acceptance",
|
||||
"acceptance-private": "testcafe \"chromium:headless --disable-dev-shm-usage\" --skip-js-errors --quarantine-mode --selector-timeout 5000 -S -s tests/screenshots tests/acceptance-private",
|
||||
"acceptance-private-firefox": "testcafe firefox:headless --skip-js-errors --quarantine-mode --selector-timeout 5000 -S -s tests/screenshots tests/acceptance-private",
|
||||
"acceptance-local": "testcafe chrome --selector-timeout 5000 -S -s tests/screenshots tests/acceptance",
|
||||
"acceptance": "testcafe \"chromium:headless --disable-dev-shm-usage\" --skip-js-errors --quarantine-mode --selector-timeout 15000 -S -s tests/screenshots tests/acceptance",
|
||||
"acceptance-firefox": "testcafe firefox:headless --skip-js-errors --quarantine-mode --selector-timeout 15000 -S -s tests/screenshots tests/acceptance",
|
||||
"acceptance-private": "testcafe \"chromium:headless --disable-dev-shm-usage\" --skip-js-errors --quarantine-mode --selector-timeout 15000 -S -s tests/screenshots tests/acceptance-private",
|
||||
"acceptance-private-firefox": "testcafe firefox:headless --skip-js-errors --quarantine-mode --selector-timeout 15000 -S -s tests/screenshots tests/acceptance-private",
|
||||
"acceptance-local": "testcafe chrome --selector-timeout 15000 -S -s tests/screenshots tests/acceptance",
|
||||
"gettext-extract": "gettext-extract --output src/locales/translations.pot $(find src -type f \\( -iname \\*.vue -o -iname \\*.js \\) -not -path src/common/vm.js)",
|
||||
"gettext-compile": "gettext-compile --output src/locales/translations.json src/locales/*.po"
|
||||
},
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
browser-autocomplete="off"
|
||||
color="secondary-dark"
|
||||
class="input-name"
|
||||
placeholder="••••••••"
|
||||
placeholder="username"
|
||||
></v-text-field>
|
||||
</v-flex>
|
||||
<v-flex xs12 class="pa-2">
|
||||
|
@ -47,6 +47,15 @@
|
|||
<translate>Sign in</translate>
|
||||
<v-icon :right="!rtl" :left="rtl" dark>login</v-icon>
|
||||
</v-btn>
|
||||
<v-btn color="primary-button"
|
||||
class="white--text ml-0 action-confirm"
|
||||
depressed
|
||||
:disabled="loading"
|
||||
@click.stop="loginExternal"
|
||||
v-if="!!authProvider" >
|
||||
<translate>Sign in with {{ authProvider }}</translate>
|
||||
<v-icon :right="!rtl" :left="rtl" dark>login</v-icon>
|
||||
</v-btn>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-card-actions>
|
||||
|
@ -62,13 +71,16 @@ export default {
|
|||
name: 'Login',
|
||||
data() {
|
||||
const c = this.$config.values;
|
||||
|
||||
console.log(c)
|
||||
console.log(c.oidc)
|
||||
console.log(!!(c.oidc ? "OpenID Connect" : null))
|
||||
return {
|
||||
loading: false,
|
||||
showPassword: false,
|
||||
username: "admin",
|
||||
username: "",
|
||||
password: "",
|
||||
siteDescription: c.siteDescription ? c.siteDescription : c.siteCaption,
|
||||
authProvider: c.oidc ? "OpenID Connect" : null,
|
||||
nextUrl: this.$route.params.nextUrl ? this.$route.params.nextUrl : "/",
|
||||
rtl: this.$rtl,
|
||||
};
|
||||
|
@ -87,6 +99,57 @@ export default {
|
|||
}
|
||||
).catch(() => this.loading = false);
|
||||
},
|
||||
loginExternal() {
|
||||
this.loading = true;
|
||||
let popup = window.open('api/v1/auth/external', "test");
|
||||
const onstorage = window.onstorage;
|
||||
const cleanup = () => {
|
||||
popup.close();
|
||||
window.localStorage.removeItem('config');
|
||||
window.localStorage.removeItem('auth_error');
|
||||
window.onstorage = onstorage;
|
||||
this.loading = false;
|
||||
};
|
||||
|
||||
window.onstorage = () => {
|
||||
const sid = window.localStorage.getItem('session_id');
|
||||
const data = window.localStorage.getItem('data');
|
||||
const config = window.localStorage.getItem('config');
|
||||
const error = window.localStorage.getItem('auth_error');
|
||||
// const linkUser = window.localStorage.getItem('link_user');
|
||||
if (error === "authentication failed") {
|
||||
window.localStorage.removeItem('config');
|
||||
window.localStorage.removeItem('auth_error');
|
||||
window.onstorage = onstorage;
|
||||
return;
|
||||
}
|
||||
// if (linkUser !== null) {
|
||||
// if (this.$session.isUser()) {
|
||||
// this.localStorage.removeItem('link_user');
|
||||
// this.$router.push(this.nextUrl);
|
||||
// } else {
|
||||
// this.$router.push('/link_user');
|
||||
// }
|
||||
// cleanup();
|
||||
// return;
|
||||
// }
|
||||
if (error !== null) {
|
||||
// TODO: handle Error
|
||||
cleanup();
|
||||
return;
|
||||
}
|
||||
if (sid === null || data === null || config === null) {
|
||||
return;
|
||||
}
|
||||
console.log("sid = ", sid);
|
||||
this.$session.setId(sid);
|
||||
this.$session.setData(JSON.parse(data));
|
||||
this.$session.setConfig(JSON.parse(config));
|
||||
//this.$session.sendClientInfo();
|
||||
this.$router.push(this.nextUrl);
|
||||
cleanup();
|
||||
};
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -8,7 +8,7 @@ const page = new Page();
|
|||
test.meta("testID", "authentication-000")(
|
||||
"Time to start instance (will be marked as unstable)",
|
||||
async (t) => {
|
||||
await t.wait(5000);
|
||||
await t.wait(15000);
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -33,7 +33,7 @@ test.meta("testID", "authentication-001")("Login and Logout", async (t) => {
|
|||
.expect(Selector(".input-password input").hasAttribute("type", "password"))
|
||||
.ok()
|
||||
.click(Selector(".action-confirm"))
|
||||
.expect(Selector(".input-search input", { timeout: 7000 }).visible)
|
||||
.expect(Selector(".input-search input", { timeout: 17000 }).visible)
|
||||
.ok();
|
||||
await page.openNav();
|
||||
await t
|
||||
|
@ -105,7 +105,7 @@ test.meta("testID", "authentication-003")("Change password", async (t) => {
|
|||
await t.expect(Selector(".input-search input").visible).ok();
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-settings", { timeout: 7000 }))
|
||||
.click(Selector(".nav-settings", { timeout: 17000 }))
|
||||
.click(Selector("#tab-settings-account"))
|
||||
.typeText(Selector(".input-current-password input"), "photoprism123", { replace: true })
|
||||
.typeText(Selector(".input-new-password input"), "photoprism", { replace: true })
|
||||
|
|
|
@ -9,7 +9,7 @@ const page = new Page();
|
|||
test.meta("testID", "authentication-000")(
|
||||
"Time to start instance (will be marked as unstable)",
|
||||
async (t) => {
|
||||
await t.wait(5000);
|
||||
await t.wait(15000);
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
@ -118,9 +118,9 @@ test.meta("testID", "calendar-004")("Create/delete album during add to album", a
|
|||
await t
|
||||
.expect(PhotoCountInAlbum)
|
||||
.eql(PhotoCountInCalendar)
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 15000 })
|
||||
.ok()
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
await page.openNav();
|
||||
await t.click(Selector(".nav-albums"));
|
||||
|
@ -133,9 +133,9 @@ test.meta("testID", "calendar-004")("Create/delete album during add to album", a
|
|||
await t
|
||||
.click(Selector(".nav-calendar"))
|
||||
.click(Selector("a.is-album").withAttribute("data-uid", SecondCalendar))
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 15000 })
|
||||
.ok()
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
});
|
||||
|
||||
|
|
|
@ -179,7 +179,7 @@ const PhotoCountInAlbum = await Selector("div.is-photo").count;
|
|||
await t
|
||||
.expect(PhotoCountInAlbum)
|
||||
.eql(PhotoCountInFolder)
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
await page.openNav();
|
||||
await t.click(Selector(".nav-albums"));
|
||||
|
@ -192,7 +192,7 @@ await t.expect(countAlbumsAfterDelete).eql(countAlbums);
|
|||
await t
|
||||
.click(Selector(".nav-folders"))
|
||||
.click(Selector("a.is-album").withAttribute("data-uid", ThirdFolder))
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
});
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ test.meta("testID", "labels-001")("Remove/Activate Add/Delete Label from photo",
|
|||
.expect(PhotoKeywords)
|
||||
.contains("beacon")
|
||||
.click(Selector("#tab-labels"))
|
||||
.click(Selector("button.action-remove"), { timeout: 5000 })
|
||||
.click(Selector("button.action-remove"), { timeout: 15000 })
|
||||
.typeText(Selector(".input-label input"), "Test")
|
||||
.click(Selector("button.p-photo-label-add"))
|
||||
.click(Selector("#tab-details"));
|
||||
|
@ -48,7 +48,7 @@ test.meta("testID", "labels-001")("Remove/Activate Add/Delete Label from photo",
|
|||
.click(Selector("a.is-label").withAttribute("data-uid", LabelTest))
|
||||
.click(Selector(".action-title-edit").withAttribute("data-uid", PhotoBeacon))
|
||||
.click(Selector("#tab-labels"))
|
||||
.click(Selector(".action-delete"), { timeout: 5000 })
|
||||
.click(Selector(".action-delete"), { timeout: 15000 })
|
||||
.click(Selector(".action-on"))
|
||||
.click(Selector("#tab-details"));
|
||||
const PhotoKeywordsAfterUndo = await Selector(".input-keywords textarea").value;
|
||||
|
@ -72,16 +72,16 @@ test.meta("testID", "labels-002")("Rename Label", async (t) => {
|
|||
await page.search("zebra");
|
||||
const LabelZebra = await Selector("a.is-label").nth(0).getAttribute("data-uid");
|
||||
await t.click(Selector("a.is-label").nth(0));
|
||||
const FirstPhotoZebra = await Selector("div.is-photo", { timeout: 5000 })
|
||||
const FirstPhotoZebra = await Selector("div.is-photo", { timeout: 15000 })
|
||||
.nth(0)
|
||||
.getAttribute("data-uid");
|
||||
const SecondPhotoZebra = await Selector("div.is-photo", { timeout: 5000 })
|
||||
const SecondPhotoZebra = await Selector("div.is-photo", { timeout: 15000 })
|
||||
.nth(1)
|
||||
.getAttribute("data-uid");
|
||||
await page.setFilter("view", "Cards");
|
||||
await t.click(Selector(".action-title-edit").withAttribute("data-uid", FirstPhotoZebra));
|
||||
const FirstPhotoTitle = await Selector(".input-title input", { timeout: 5000 }).value;
|
||||
const FirstPhotoKeywords = await Selector(".input-keywords textarea", { timeout: 5000 }).value;
|
||||
const FirstPhotoTitle = await Selector(".input-title input", { timeout: 15000 }).value;
|
||||
const FirstPhotoKeywords = await Selector(".input-keywords textarea", { timeout: 15000 }).value;
|
||||
await t
|
||||
.expect(FirstPhotoTitle)
|
||||
.contains("Zebra")
|
||||
|
@ -92,8 +92,8 @@ test.meta("testID", "labels-002")("Rename Label", async (t) => {
|
|||
.typeText(Selector(".input-rename input"), "Horse", { replace: true })
|
||||
.pressKey("enter")
|
||||
.click(Selector("#tab-details"));
|
||||
const FirstPhotoTitleAfterEdit = await Selector(".input-title input", { timeout: 5000 }).value;
|
||||
const FirstPhotoKeywordsAfterEdit = await Selector(".input-keywords textarea", { timeout: 5000 })
|
||||
const FirstPhotoTitleAfterEdit = await Selector(".input-title input", { timeout: 15000 }).value;
|
||||
const FirstPhotoKeywordsAfterEdit = await Selector(".input-keywords textarea", { timeout: 15000 })
|
||||
.value;
|
||||
await t
|
||||
.expect(FirstPhotoTitleAfterEdit)
|
||||
|
@ -153,7 +153,7 @@ test.meta("testID", "labels-003")("Add label to album", async (t) => {
|
|||
await t
|
||||
.click(Selector(".nav-albums"))
|
||||
.click(Selector("a.is-album").withAttribute("data-uid", AlbumUid));
|
||||
const PhotoCountAfterAdd = await Selector("div.is-photo", { timeout: 5000 }).count;
|
||||
const PhotoCountAfterAdd = await Selector("div.is-photo", { timeout: 15000 }).count;
|
||||
await t.expect(PhotoCountAfterAdd).eql(PhotoCount + 6);
|
||||
await page.selectPhotoFromUID(FirstPhotoLandscape);
|
||||
await page.selectPhotoFromUID(SecondPhotoLandscape);
|
||||
|
@ -162,7 +162,7 @@ test.meta("testID", "labels-003")("Add label to album", async (t) => {
|
|||
await page.selectPhotoFromUID(FifthPhotoLandscape);
|
||||
await page.selectPhotoFromUID(SixthPhotoLandscape);
|
||||
await page.removeSelected();
|
||||
const PhotoCountAfterDelete = await Selector("div.is-photo", { timeout: 5000 }).count;
|
||||
const PhotoCountAfterDelete = await Selector("div.is-photo", { timeout: 15000 }).count;
|
||||
await t.expect(PhotoCountAfterDelete).eql(PhotoCountAfterAdd - 6);
|
||||
});
|
||||
|
||||
|
@ -170,15 +170,15 @@ test.meta("testID", "labels-004")("Delete label", async (t) => {
|
|||
await page.openNav();
|
||||
await t.click(Selector(".nav-labels"));
|
||||
await page.search("dome");
|
||||
const LabelDome = await Selector("a.is-label", { timeout: 5000 }).nth(0).getAttribute("data-uid");
|
||||
const LabelDome = await Selector("a.is-label", { timeout: 15000 }).nth(0).getAttribute("data-uid");
|
||||
await t.click(Selector("a.is-label").withAttribute("data-uid", LabelDome));
|
||||
const FirstPhotoDome = await Selector("div.is-photo", { timeout: 5000 })
|
||||
const FirstPhotoDome = await Selector("div.is-photo", { timeout: 15000 })
|
||||
.nth(0)
|
||||
.getAttribute("data-uid");
|
||||
await page.openNav();
|
||||
await t.click(".nav-labels");
|
||||
await page.selectFromUID(LabelDome);
|
||||
const clipboardCount = await Selector("span.count-clipboard", { timeout: 5000 });
|
||||
const clipboardCount = await Selector("span.count-clipboard", { timeout: 15000 });
|
||||
await t.expect(clipboardCount.textContent).eql("1");
|
||||
await page.deleteSelected();
|
||||
await page.search("dome");
|
||||
|
|
|
@ -180,9 +180,9 @@ test.meta("testID", "moments-004")("Create/delete album during add to album", as
|
|||
await t
|
||||
.expect(PhotoCountInAlbum)
|
||||
.eql(PhotoCountInMoment)
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 15000 })
|
||||
.ok()
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
await page.openNav();
|
||||
await t.click(Selector(".nav-albums"));
|
||||
|
@ -195,9 +195,9 @@ test.meta("testID", "moments-004")("Create/delete album during add to album", as
|
|||
await t
|
||||
.click(Selector(".nav-moments"))
|
||||
.click(Selector("a.is-album").withAttribute("data-uid", FirstMoment))
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 15000 })
|
||||
.ok()
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
});
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ test.meta("testID", "originals-001")("Add original files to album", async (t) =>
|
|||
.click(Selector("button").withText("BotanicalGarden"))
|
||||
.click(Selector('a[href="/library/files/Vacation"]'));
|
||||
await page.selectPhotoFromUID(KanadaUid);
|
||||
const clipboardCount = await Selector("span.count-clipboard", { timeout: 5000 });
|
||||
const clipboardCount = await Selector("span.count-clipboard", { timeout: 15000 });
|
||||
await t.expect(clipboardCount.textContent).eql("1");
|
||||
await page.addSelectedToAlbum("KanadaVacation", "album");
|
||||
await page.openNav();
|
||||
|
@ -45,7 +45,7 @@ test.meta("testID", "originals-001")("Add original files to album", async (t) =>
|
|||
await page.search("KanadaVacation");
|
||||
const AlbumUid = await Selector("a.is-album").nth(0).getAttribute("data-uid");
|
||||
await t.click(Selector("a.is-album").nth(0));
|
||||
const PhotoCountAfterAdd = await Selector("div.is-photo", { timeout: 5000 }).count;
|
||||
const PhotoCountAfterAdd = await Selector("div.is-photo", { timeout: 15000 }).count;
|
||||
await t.expect(PhotoCountAfterAdd).eql(2);
|
||||
await page.openNav();
|
||||
await t.click(Selector(".nav-albums"));
|
||||
|
@ -58,7 +58,7 @@ test.meta("testID", "originals-002")("Download original files", async (t) => {
|
|||
await t.click(Selector("div.nav-library + div")).click(Selector(".nav-originals"));
|
||||
const FirstFile = await Selector("div.is-file").nth(0).getAttribute("data-uid");
|
||||
await page.selectPhotoFromUID(FirstFile);
|
||||
const clipboardCount = await Selector("span.count-clipboard", { timeout: 5000 });
|
||||
const clipboardCount = await Selector("span.count-clipboard", { timeout: 15000 });
|
||||
await t
|
||||
.expect(clipboardCount.textContent)
|
||||
.eql("1")
|
||||
|
|
|
@ -86,12 +86,12 @@ export default class Page {
|
|||
.expect(Selector("#photo-viewer").visible)
|
||||
.ok()
|
||||
.click(Selector('button[title="Select"]'))
|
||||
.click(Selector(".action-close", { timeout: 4000 }));
|
||||
.click(Selector(".action-close", { timeout: 14000 }));
|
||||
}
|
||||
|
||||
async toggleSelectNthPhoto(nPhoto) {
|
||||
await t
|
||||
.hover(Selector(".is-photo.type-image", { timeout: 4000 }).nth(nPhoto))
|
||||
.hover(Selector(".is-photo.type-image", { timeout: 14000 }).nth(nPhoto))
|
||||
.click(Selector(".is-photo.type-image .input-select").nth(nPhoto));
|
||||
}
|
||||
|
||||
|
@ -101,34 +101,34 @@ export default class Page {
|
|||
|
||||
async archiveSelected() {
|
||||
if (!(await Selector("#t-clipboard button.action-archive").visible)) {
|
||||
await t.click(Selector("button.action-menu", { timeout: 5000 }));
|
||||
await t.click(Selector("button.action-menu", { timeout: 15000 }));
|
||||
}
|
||||
if (t.browser.platform === "mobile") {
|
||||
if (!(await Selector("#t-clipboard button.action-archive").visible)) {
|
||||
await t.click(Selector("button.action-menu", { timeout: 5000 }));
|
||||
await t.click(Selector("button.action-menu", { timeout: 15000 }));
|
||||
if (!(await Selector("#t-clipboard button.action-archive").visible)) {
|
||||
await t.click(Selector("button.action-menu", { timeout: 5000 }));
|
||||
await t.click(Selector("button.action-menu", { timeout: 15000 }));
|
||||
}
|
||||
if (!(await Selector("#t-clipboard button.action-archive").visible)) {
|
||||
await t.click(Selector("button.action-menu", { timeout: 5000 }));
|
||||
await t.click(Selector("button.action-menu", { timeout: 15000 }));
|
||||
}
|
||||
}
|
||||
}
|
||||
await t.click(Selector("#t-clipboard button.action-archive", { timeout: 5000 }));
|
||||
await t.click(Selector("#t-clipboard button.action-archive", { timeout: 15000 }));
|
||||
}
|
||||
|
||||
async privateSelected() {
|
||||
await t.click(Selector("button.action-menu", { timeout: 5000 }));
|
||||
await t.click(Selector("button.action-menu", { timeout: 15000 }));
|
||||
if (!(await Selector("button.action-private").visible)) {
|
||||
await t.click(Selector("button.action-menu", { timeout: 5000 }));
|
||||
await t.click(Selector("button.action-menu", { timeout: 15000 }));
|
||||
if (!(await Selector("button.action-private").visible)) {
|
||||
await t.click(Selector("button.action-menu", { timeout: 5000 }));
|
||||
await t.click(Selector("button.action-menu", { timeout: 15000 }));
|
||||
}
|
||||
if (!(await Selector("button.action-private").visible)) {
|
||||
await t.click(Selector("button.action-menu", { timeout: 5000 }));
|
||||
await t.click(Selector("button.action-menu", { timeout: 15000 }));
|
||||
}
|
||||
}
|
||||
await t.click(Selector("button.action-private", { timeout: 5000 }));
|
||||
await t.click(Selector("button.action-private", { timeout: 15000 }));
|
||||
}
|
||||
|
||||
async restoreSelected() {
|
||||
|
@ -166,7 +166,7 @@ export default class Page {
|
|||
await t
|
||||
.click("#tab-info")
|
||||
.expect(
|
||||
Selector(".input-" + type + " input", { timeout: 8000 }).hasAttribute(
|
||||
Selector(".input-" + type + " input", { timeout: 18000 }).hasAttribute(
|
||||
"aria-checked",
|
||||
"true"
|
||||
)
|
||||
|
@ -174,7 +174,7 @@ export default class Page {
|
|||
.ok()
|
||||
.click(Selector(".input-" + type + " input"))
|
||||
.expect(
|
||||
Selector(".input-" + type + " input", { timeout: 8000 }).hasAttribute(
|
||||
Selector(".input-" + type + " input", { timeout: 18000 }).hasAttribute(
|
||||
"aria-checked",
|
||||
"false"
|
||||
)
|
||||
|
@ -186,7 +186,7 @@ export default class Page {
|
|||
await t
|
||||
.click("#tab-info")
|
||||
.expect(
|
||||
Selector(".input-" + type + " input", { timeout: 8000 }).hasAttribute(
|
||||
Selector(".input-" + type + " input", { timeout: 18000 }).hasAttribute(
|
||||
"aria-checked",
|
||||
"false"
|
||||
)
|
||||
|
@ -194,7 +194,7 @@ export default class Page {
|
|||
.ok()
|
||||
.click(Selector(".input-" + type + " input"))
|
||||
.expect(
|
||||
Selector(".input-" + type + " input", { timeout: 8000 }).hasAttribute(
|
||||
Selector(".input-" + type + " input", { timeout: 18000 }).hasAttribute(
|
||||
"aria-checked",
|
||||
"true"
|
||||
)
|
||||
|
@ -212,7 +212,7 @@ export default class Page {
|
|||
|
||||
async login(username, password) {
|
||||
await t
|
||||
.typeText(Selector(".input-name input"), username, { replace: true, timeout: 5000 })
|
||||
.typeText(Selector(".input-name input"), username, { replace: true, timeout: 15000 })
|
||||
.typeText(Selector(".input-password input"), password, { replace: true })
|
||||
.click(Selector(".action-confirm"));
|
||||
}
|
||||
|
@ -314,10 +314,10 @@ export default class Page {
|
|||
await t.click(Selector(".nav-browse + div")).click(Selector(".nav-archive"));
|
||||
await this.selectPhotoFromUID(uid);
|
||||
await t
|
||||
.click(Selector("button.action-menu", { timeout: 5000 }))
|
||||
.click(Selector("button.action-menu", { timeout: 15000 }))
|
||||
.click(Selector(".remove"))
|
||||
.click(Selector(".action-confirm"))
|
||||
.expect(Selector("div").withAttribute("data-uid", uid).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", uid).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
}
|
||||
|
||||
|
@ -491,11 +491,11 @@ export default class Page {
|
|||
.typeText(Selector(".input-keywords textarea"), keywords)
|
||||
.typeText(Selector(".input-notes textarea"), notes, { replace: true })
|
||||
.click(Selector("button.action-approve"));
|
||||
await t.expect(Selector(".input-latitude input").visible, { timeout: 5000 }).ok();
|
||||
await t.expect(Selector(".input-latitude input").visible, { timeout: 15000 }).ok();
|
||||
if (t.browser.platform === "mobile") {
|
||||
await t.click(Selector("button.action-apply")).click(Selector("button.action-close"));
|
||||
} else {
|
||||
await t.click(Selector("button.action-done", { timeout: 5000 }));
|
||||
await t.click(Selector("button.action-done", { timeout: 15000 }));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -657,7 +657,7 @@ export default class Page {
|
|||
if (t.browser.platform === "mobile") {
|
||||
await t.click(Selector("button.action-apply")).click(Selector("button.action-close"));
|
||||
} else {
|
||||
await t.click(Selector("button.action-done", { timeout: 5000 }));
|
||||
await t.click(Selector("button.action-done", { timeout: 15000 }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,26 +24,26 @@ test.meta("testID", "photos-005")(
|
|||
await page.openNav();
|
||||
await t.click(Selector(".nav-private"));
|
||||
await t
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.expect(Selector("div").withAttribute("data-uid", ThirdPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", ThirdPhoto).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondVideo).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondVideo).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.expect(Selector("div").withAttribute("data-uid", ThirdVideo).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", ThirdVideo).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await page.openNav();
|
||||
await t.click(Selector(".nav-browse"));
|
||||
await page.selectPhotoFromUID(FirstPhoto);
|
||||
await page.selectFromUIDInFullscreen(SecondPhoto);
|
||||
const clipboardCount = await Selector("span.count-clipboard", { timeout: 5000 });
|
||||
const clipboardCount = await Selector("span.count-clipboard", { timeout: 15000 });
|
||||
await t.expect(clipboardCount.textContent).eql("2");
|
||||
await page.privateSelected();
|
||||
await t.expect(Selector("button.action-menu").exists, { timeout: 5000 }).notOk();
|
||||
await t.expect(Selector("button.action-menu").exists, { timeout: 15000 }).notOk();
|
||||
await page.setFilter("view", "List");
|
||||
await t.click(Selector("button.input-private").withAttribute("data-uid", ThirdPhoto));
|
||||
if (t.browser.platform === "mobile") {
|
||||
|
@ -52,11 +52,11 @@ test.meta("testID", "photos-005")(
|
|||
await t.click(Selector("button.action-reload"));
|
||||
}
|
||||
await t
|
||||
.expect(Selector("td").withAttribute("data-uid", FirstPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("td").withAttribute("data-uid", FirstPhoto).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.expect(Selector("td").withAttribute("data-uid", SecondPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("td").withAttribute("data-uid", SecondPhoto).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.expect(Selector("td").withAttribute("data-uid", ThirdPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("td").withAttribute("data-uid", ThirdPhoto).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await page.openNav();
|
||||
await t.click(Selector(".nav-video"));
|
||||
|
@ -65,13 +65,13 @@ test.meta("testID", "photos-005")(
|
|||
await page.setFilter("view", "Card");
|
||||
|
||||
await page.selectPhotoFromUID(FirstVideo);
|
||||
const clipboardCountVideo = await Selector("span.count-clipboard", { timeout: 5000 });
|
||||
const clipboardCountVideo = await Selector("span.count-clipboard", { timeout: 15000 });
|
||||
await t
|
||||
.expect(clipboardCountVideo.textContent)
|
||||
.eql("1")
|
||||
.click(Selector("button.action-menu"))
|
||||
.click(Selector("button.action-private"))
|
||||
.expect(Selector("button.action-menu").exists, { timeout: 5000 })
|
||||
.expect(Selector("button.action-menu").exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await page.selectPhotoFromUID(ThirdVideo);
|
||||
await page.editSelected();
|
||||
|
@ -84,25 +84,25 @@ test.meta("testID", "photos-005")(
|
|||
await t.click(Selector("button.action-reload"));
|
||||
}
|
||||
await t
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondVideo).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondVideo).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.expect(Selector("div").withAttribute("data-uid", ThirdVideo).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", ThirdVideo).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await page.openNav();
|
||||
await t.click(Selector(".nav-private"));
|
||||
|
||||
await t
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 15000 })
|
||||
.ok()
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 15000 })
|
||||
.ok()
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 15000 })
|
||||
.ok()
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondVideo).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondVideo).exists, { timeout: 15000 })
|
||||
.ok()
|
||||
.expect(Selector("div").withAttribute("data-uid", ThirdVideo).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", ThirdVideo).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
await page.selectPhotoFromUID(FirstPhoto);
|
||||
await page.selectPhotoFromUID(SecondPhoto);
|
||||
|
@ -124,43 +124,43 @@ test.meta("testID", "photos-005")(
|
|||
await t.click(Selector("button.action-reload"));
|
||||
}
|
||||
await t
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.expect(Selector("div").withAttribute("data-uid", ThirdPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", ThirdPhoto).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondVideo).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondVideo).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.expect(Selector("div").withAttribute("data-uid", ThirdVideo).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", ThirdVideo).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await page.openNav();
|
||||
await t.click(Selector(".nav-browse"));
|
||||
|
||||
await t
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 15000 })
|
||||
.ok()
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 15000 })
|
||||
.ok()
|
||||
.expect(Selector("div").withAttribute("data-uid", ThirdPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", ThirdPhoto).exists, { timeout: 15000 })
|
||||
.ok()
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 15000 })
|
||||
.ok()
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondVideo).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondVideo).exists, { timeout: 15000 })
|
||||
.ok()
|
||||
.expect(Selector("div").withAttribute("data-uid", ThirdVideo).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", ThirdVideo).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
await page.openNav();
|
||||
await t.click(Selector(".nav-video"));
|
||||
|
||||
await t
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 15000 })
|
||||
.ok()
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondVideo).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondVideo).exists, { timeout: 15000 })
|
||||
.ok()
|
||||
.expect(Selector("div").withAttribute("data-uid", ThirdVideo).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", ThirdVideo).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
}
|
||||
);
|
||||
|
@ -186,56 +186,56 @@ test.meta("testID", "photos-006")(
|
|||
await page.openNav();
|
||||
await t.click(Selector(".nav-archive"));
|
||||
await t
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPrivatePhoto).exists, {
|
||||
timeout: 5000,
|
||||
})
|
||||
.notOk()
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstReviewPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstReviewPhoto).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await page.openNav();
|
||||
await t.click(Selector(".nav-video"));
|
||||
await page.setFilter("view", "Card");
|
||||
await page.selectPhotoFromUID(FirstVideo);
|
||||
const clipboardCountVideo = await Selector("span.count-clipboard", { timeout: 5000 });
|
||||
const clipboardCountVideo = await Selector("span.count-clipboard", { timeout: 15000 });
|
||||
await t.expect(clipboardCountVideo.textContent).eql("1");
|
||||
await page.archiveSelected();
|
||||
await t.expect(Selector("button.action-menu").exists, { timeout: 5000 }).notOk();
|
||||
await t.expect(Selector("button.action-menu").exists, { timeout: 15000 }).notOk();
|
||||
if (t.browser.platform === "mobile") {
|
||||
await t.eval(() => location.reload());
|
||||
} else {
|
||||
await t.click(Selector("button.action-reload"));
|
||||
}
|
||||
await t
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await page.openNav();
|
||||
await t.click(Selector(".nav-browse"));
|
||||
await page.selectPhotoFromUID(FirstPhoto);
|
||||
await page.selectPhotoFromUID(SecondPhoto);
|
||||
const clipboardCountPhotos = await Selector("span.count-clipboard", { timeout: 5000 });
|
||||
const clipboardCountPhotos = await Selector("span.count-clipboard", { timeout: 15000 });
|
||||
await t.expect(clipboardCountPhotos.textContent).eql("2");
|
||||
await page.archiveSelected();
|
||||
await t.expect(Selector("button.action-menu").exists, { timeout: 5000 }).notOk();
|
||||
await t.expect(Selector("button.action-menu").exists, { timeout: 15000 }).notOk();
|
||||
if (t.browser.platform === "mobile") {
|
||||
await t.eval(() => location.reload());
|
||||
} else {
|
||||
await t.click(Selector("button.action-reload"));
|
||||
}
|
||||
await t
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await page.openNav();
|
||||
await t.click(Selector(".nav-private"));
|
||||
await page.selectPhotoFromUID(FirstPrivatePhoto);
|
||||
const clipboardCountPrivate = await Selector("span.count-clipboard", { timeout: 5000 });
|
||||
const clipboardCountPrivate = await Selector("span.count-clipboard", { timeout: 15000 });
|
||||
await t.expect(clipboardCountPrivate.textContent).eql("1");
|
||||
await page.openNav();
|
||||
if (t.browser.platform === "mobile") {
|
||||
|
@ -244,17 +244,17 @@ test.meta("testID", "photos-006")(
|
|||
await t.click(Selector(".nav-review"));
|
||||
}
|
||||
await page.selectPhotoFromUID(FirstReviewPhoto);
|
||||
const clipboardCountReview = await Selector("span.count-clipboard", { timeout: 5000 });
|
||||
const clipboardCountReview = await Selector("span.count-clipboard", { timeout: 15000 });
|
||||
await t.expect(clipboardCountReview.textContent).eql("2");
|
||||
await page.archiveSelected();
|
||||
await t.expect(Selector("button.action-menu").exists, { timeout: 5000 }).notOk();
|
||||
await t.expect(Selector("button.action-menu").exists, { timeout: 15000 }).notOk();
|
||||
if (t.browser.platform === "mobile") {
|
||||
await t.eval(() => location.reload());
|
||||
} else {
|
||||
await t.click(Selector("button.action-reload"));
|
||||
}
|
||||
await t
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstReviewPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstReviewPhoto).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await page.openNav();
|
||||
if (t.browser.platform === "mobile") {
|
||||
|
@ -263,62 +263,62 @@ test.meta("testID", "photos-006")(
|
|||
await t.click(Selector(".nav-archive"));
|
||||
}
|
||||
await t
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 15000 })
|
||||
.ok()
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 15000 })
|
||||
.ok()
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 15000 })
|
||||
.ok()
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPrivatePhoto).exists, {
|
||||
timeout: 5000,
|
||||
})
|
||||
.ok()
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstReviewPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstReviewPhoto).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
await page.selectPhotoFromUID(FirstPhoto);
|
||||
await page.selectPhotoFromUID(SecondPhoto);
|
||||
await page.selectPhotoFromUID(FirstVideo);
|
||||
await page.selectPhotoFromUID(FirstPrivatePhoto);
|
||||
await page.selectPhotoFromUID(FirstReviewPhoto);
|
||||
const clipboardCountArchive = await Selector("span.count-clipboard", { timeout: 5000 });
|
||||
const clipboardCountArchive = await Selector("span.count-clipboard", { timeout: 15000 });
|
||||
await t.expect(clipboardCountArchive.textContent).eql("5");
|
||||
await page.restoreSelected();
|
||||
await t.expect(Selector("button.action-menu").exists, { timeout: 5000 }).notOk();
|
||||
await t.expect(Selector("button.action-menu").exists, { timeout: 15000 }).notOk();
|
||||
if (t.browser.platform === "mobile") {
|
||||
await t.eval(() => location.reload());
|
||||
} else {
|
||||
await t.click(Selector("button.action-reload"));
|
||||
}
|
||||
await t
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPrivatePhoto).exists, {
|
||||
timeout: 5000,
|
||||
})
|
||||
.notOk()
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstReviewPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstReviewPhoto).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await page.openNav();
|
||||
await t.click(Selector(".nav-video"));
|
||||
await t
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
await page.openNav();
|
||||
await t.click(Selector(".nav-browse"));
|
||||
await t
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 15000 })
|
||||
.ok()
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
await page.openNav();
|
||||
await t.click(Selector(".nav-private"));
|
||||
await t
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPrivatePhoto).exists, {
|
||||
timeout: 5000,
|
||||
timeout: 15000,
|
||||
})
|
||||
.ok();
|
||||
await page.openNav();
|
||||
|
@ -328,7 +328,7 @@ test.meta("testID", "photos-006")(
|
|||
await t.click(Selector(".nav-review"));
|
||||
}
|
||||
await t
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstReviewPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstReviewPhoto).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
}
|
||||
);
|
||||
|
@ -405,67 +405,67 @@ test.meta("testID", "photos-013")(
|
|||
await t.click(Selector(".nav-browse + div")).click(Selector(".nav-archive"));
|
||||
const PhotoCountInArchiveAfterArchive = await Selector("div.is-photo").count;
|
||||
await t.expect(PhotoCountInArchiveAfterArchive).eql(InitialPhotoCountInArchive + 13);
|
||||
await t.expect(Selector("button.action-menu").exists, { timeout: 5000 }).notOk();
|
||||
await t.expect(Selector("button.action-menu").exists, { timeout: 15000 }).notOk();
|
||||
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-monochrome"))
|
||||
.expect(Selector("div").withAttribute("data-uid", MonochromePhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", MonochromePhoto).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-panoramas"))
|
||||
.expect(Selector("div").withAttribute("data-uid", PanoramaPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", PanoramaPhoto).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-stacks"))
|
||||
.expect(Selector("div").withAttribute("data-uid", StackedPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", StackedPhoto).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-scans"))
|
||||
.expect(Selector("div").withAttribute("data-uid", ScannedPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", ScannedPhoto).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-review"))
|
||||
.expect(Selector("div").withAttribute("data-uid", ReviewPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", ReviewPhoto).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-favorites"))
|
||||
.expect(Selector("div").withAttribute("data-uid", FavoritesPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FavoritesPhoto).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-private"))
|
||||
.expect(Selector("div").withAttribute("data-uid", PrivatePhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", PrivatePhoto).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-video"))
|
||||
.expect(Selector("div").withAttribute("data-uid", Video).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", Video).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await t
|
||||
.navigateTo("/calendar/aqmxlr71p6zo22dk/january-2017")
|
||||
.expect(Selector("div").withAttribute("data-uid", CalendarPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", CalendarPhoto).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-moments"))
|
||||
.click(Selector("a.is-album").nth(0))
|
||||
.expect(Selector("div").withAttribute("data-uid", MomentPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", MomentPhoto).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await t
|
||||
.navigateTo("/states/aqmxlr71tebcohrw/western-cape-south-africa")
|
||||
.expect(Selector("div").withAttribute("data-uid", StatesPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", StatesPhoto).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.navigateTo("/all?q=label%3Aseashore")
|
||||
.expect(Selector("div").withAttribute("data-uid", LabelPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", LabelPhoto).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.navigateTo("/folders/aqnah1321mgkt1w2/archive")
|
||||
.expect(Selector("div").withAttribute("data-uid", FolderPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FolderPhoto).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
|
||||
await page.openNav();
|
||||
|
@ -487,67 +487,67 @@ test.meta("testID", "photos-013")(
|
|||
await page.restoreSelected();
|
||||
const PhotoCountInArchiveAfterRestore = await Selector("div.is-photo").count;
|
||||
await t.expect(PhotoCountInArchiveAfterRestore).eql(InitialPhotoCountInArchive);
|
||||
await t.expect(Selector("button.action-menu").exists, { timeout: 5000 }).notOk();
|
||||
await t.expect(Selector("button.action-menu").exists, { timeout: 15000 }).notOk();
|
||||
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-monochrome"))
|
||||
.expect(Selector("div").withAttribute("data-uid", MonochromePhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", MonochromePhoto).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-panoramas"))
|
||||
.expect(Selector("div").withAttribute("data-uid", PanoramaPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", PanoramaPhoto).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-stacks"))
|
||||
.expect(Selector("div").withAttribute("data-uid", StackedPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", StackedPhoto).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-scans"))
|
||||
.expect(Selector("div").withAttribute("data-uid", ScannedPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", ScannedPhoto).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-review"))
|
||||
.expect(Selector("div").withAttribute("data-uid", ReviewPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", ReviewPhoto).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-favorites"))
|
||||
.expect(Selector("div").withAttribute("data-uid", FavoritesPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FavoritesPhoto).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-private"))
|
||||
.expect(Selector("div").withAttribute("data-uid", PrivatePhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", PrivatePhoto).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-video"))
|
||||
.expect(Selector("div").withAttribute("data-uid", Video).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", Video).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
await t
|
||||
.navigateTo("/calendar/aqmxlr71p6zo22dk/january-2017")
|
||||
.expect(Selector("div").withAttribute("data-uid", CalendarPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", CalendarPhoto).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-moments"))
|
||||
.click(Selector("a.is-album").nth(0))
|
||||
.expect(Selector("div").withAttribute("data-uid", MomentPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", MomentPhoto).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
await t
|
||||
.navigateTo("/states/aqmxlr71tebcohrw/western-cape-south-africa")
|
||||
.expect(Selector("div").withAttribute("data-uid", StatesPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", StatesPhoto).exists, { timeout: 15000 })
|
||||
.ok()
|
||||
.navigateTo("/all?q=label%3Aseashore")
|
||||
.expect(Selector("div").withAttribute("data-uid", LabelPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", LabelPhoto).exists, { timeout: 15000 })
|
||||
.ok()
|
||||
.navigateTo("/folders/aqnah1321mgkt1w2/archive")
|
||||
.expect(Selector("div").withAttribute("data-uid", FolderPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FolderPhoto).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
}
|
||||
);
|
||||
|
@ -627,67 +627,67 @@ test.meta("testID", "photos-014")(
|
|||
await t.click(Selector(".nav-private"));
|
||||
const PhotoCountInPrivateAfterPrivate = await Selector("div.is-photo").count;
|
||||
await t.expect(PhotoCountInPrivateAfterPrivate).eql(InitialPhotoCountInPrivate + 13);
|
||||
await t.expect(Selector("button.action-menu").exists, { timeout: 5000 }).notOk();
|
||||
await t.expect(Selector("button.action-menu").exists, { timeout: 15000 }).notOk();
|
||||
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-browse + div"))
|
||||
.click(Selector(".nav-monochrome"))
|
||||
.expect(Selector("div").withAttribute("data-uid", MonochromePhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", MonochromePhoto).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-panoramas"))
|
||||
.expect(Selector("div").withAttribute("data-uid", PanoramaPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", PanoramaPhoto).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-stacks"))
|
||||
.expect(Selector("div").withAttribute("data-uid", StackedPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", StackedPhoto).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-scans"))
|
||||
.expect(Selector("div").withAttribute("data-uid", ScannedPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", ScannedPhoto).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-review"))
|
||||
.expect(Selector("div").withAttribute("data-uid", ReviewPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", ReviewPhoto).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.navigateTo("/albums?q=Holiday")
|
||||
.click(Selector("a.is-album").nth(0))
|
||||
.expect(Selector("div").withAttribute("data-uid", AlbumPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", AlbumPhoto).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-favorites"))
|
||||
.expect(Selector("div").withAttribute("data-uid", FavoritesPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FavoritesPhoto).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-video"))
|
||||
.expect(Selector("div").withAttribute("data-uid", Video).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", Video).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await t
|
||||
.navigateTo("/calendar/aqmxlr71p6zo22dk/january-2017")
|
||||
.expect(Selector("div").withAttribute("data-uid", CalendarPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", CalendarPhoto).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-moments"))
|
||||
.click(Selector("a.is-album").nth(0))
|
||||
.expect(Selector("div").withAttribute("data-uid", MomentPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", MomentPhoto).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await t
|
||||
.navigateTo("/states/aqmxlr71tebcohrw/western-cape-south-africa")
|
||||
.expect(Selector("div").withAttribute("data-uid", StatesPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", StatesPhoto).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.navigateTo("/all?q=label%3Aseashore")
|
||||
.expect(Selector("div").withAttribute("data-uid", LabelPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", LabelPhoto).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.navigateTo("/folders/aqnah1321mgkt1w2/archive")
|
||||
.expect(Selector("div").withAttribute("data-uid", FolderPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FolderPhoto).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
|
||||
await page.openNav();
|
||||
|
@ -713,67 +713,67 @@ test.meta("testID", "photos-014")(
|
|||
await t.click(Selector(".nav-private"));
|
||||
const PhotoCountInPrivateAfterUnprivate = await Selector("div.is-photo").count;
|
||||
await t.expect(PhotoCountInPrivateAfterUnprivate).eql(InitialPhotoCountInPrivate);
|
||||
await t.expect(Selector("button.action-menu").exists, { timeout: 5000 }).notOk();
|
||||
await t.expect(Selector("button.action-menu").exists, { timeout: 15000 }).notOk();
|
||||
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-browse + div"))
|
||||
.click(Selector(".nav-monochrome"))
|
||||
.expect(Selector("div").withAttribute("data-uid", MonochromePhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", MonochromePhoto).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-panoramas"))
|
||||
.expect(Selector("div").withAttribute("data-uid", PanoramaPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", PanoramaPhoto).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-stacks"))
|
||||
.expect(Selector("div").withAttribute("data-uid", StackedPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", StackedPhoto).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-scans"))
|
||||
.expect(Selector("div").withAttribute("data-uid", ScannedPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", ScannedPhoto).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-review"))
|
||||
.expect(Selector("div").withAttribute("data-uid", ReviewPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", ReviewPhoto).exists, { timeout: 15000 })
|
||||
.ok()
|
||||
.navigateTo("/albums?q=Holiday")
|
||||
.click(Selector("a.is-album").nth(0))
|
||||
.expect(Selector("div").withAttribute("data-uid", AlbumPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", AlbumPhoto).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-favorites"))
|
||||
.expect(Selector("div").withAttribute("data-uid", FavoritesPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FavoritesPhoto).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-video"))
|
||||
.expect(Selector("div").withAttribute("data-uid", Video).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", Video).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
await t
|
||||
.navigateTo("/calendar/aqmxlr71p6zo22dk/january-2017")
|
||||
.expect(Selector("div").withAttribute("data-uid", CalendarPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", CalendarPhoto).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
await page.openNav();
|
||||
await t
|
||||
.click(Selector(".nav-moments"))
|
||||
.click(Selector("a.is-album").nth(0))
|
||||
.expect(Selector("div").withAttribute("data-uid", MomentPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", MomentPhoto).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
await t
|
||||
.navigateTo("/states/aqmxlr71tebcohrw/western-cape-south-africa")
|
||||
.expect(Selector("div").withAttribute("data-uid", StatesPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", StatesPhoto).exists, { timeout: 15000 })
|
||||
.ok()
|
||||
.navigateTo("/all?q=label%3Aseashore")
|
||||
.expect(Selector("div").withAttribute("data-uid", LabelPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", LabelPhoto).exists, { timeout: 15000 })
|
||||
.ok()
|
||||
.navigateTo("/folders/aqnah1321mgkt1w2/archive")
|
||||
.expect(Selector("div").withAttribute("data-uid", FolderPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FolderPhoto).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
}
|
||||
);
|
||||
|
|
|
@ -50,7 +50,7 @@ test.meta("testID", "photos-upload-delete-001")("Upload + Delete jpg/json", asyn
|
|||
await t.click(Selector(".nav-browse"));
|
||||
await page.search("digikam");
|
||||
await t
|
||||
.expect(Selector("div").withAttribute("data-uid", UploadedPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", UploadedPhoto).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.navigateTo("/library/files/2020/10");
|
||||
const FileCountAfterDelete = await Selector("div.is-file").count;
|
||||
|
@ -103,7 +103,7 @@ test.meta("testID", "photos-upload-delete-002")("Upload + Delete video", async (
|
|||
await t.click(Selector(".nav-browse"));
|
||||
await page.search("korn");
|
||||
await t
|
||||
.expect(Selector("div").withAttribute("data-uid", UploadedPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", UploadedPhoto).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.navigateTo("/library/files/2020/06");
|
||||
const FileCountAfterDelete = await Selector("div.is-file").count;
|
||||
|
@ -139,13 +139,13 @@ test.meta("testID", "photos-upload-delete-003")("Upload to existing Album + Dele
|
|||
await t.click(Selector(".nav-browse"));
|
||||
await page.search("ladybug");
|
||||
await t
|
||||
.expect(Selector("div").withAttribute("data-uid", UploadedPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", UploadedPhoto).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await page.openNav();
|
||||
await t.click(Selector(".nav-albums"));
|
||||
await t
|
||||
.click(Selector("a.is-album").withAttribute("data-uid", AlbumUid))
|
||||
.expect(Selector("div").withAttribute("data-uid", UploadedPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", UploadedPhoto).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
const PhotoCountAfterDelete = await Selector("div.is-photo").count;
|
||||
await t.expect(PhotoCountAfterDelete).eql(PhotoCount);
|
||||
|
@ -156,7 +156,7 @@ test.meta("testID", "photos-upload-delete-004")("Upload jpg to new Album + Delet
|
|||
await t.click(Selector(".nav-albums"));
|
||||
const AlbumCount = await Selector("a.is-album").count;
|
||||
await t
|
||||
.click(Selector(".action-upload", { timeout: 5000 }))
|
||||
.click(Selector(".action-upload", { timeout: 15000 }))
|
||||
.click(Selector(".input-albums"))
|
||||
.typeText(Selector(".input-albums input"), "NewCreatedAlbum")
|
||||
.pressKey("enter")
|
||||
|
@ -182,14 +182,14 @@ test.meta("testID", "photos-upload-delete-004")("Upload jpg to new Album + Delet
|
|||
await t.click(Selector(".nav-browse"));
|
||||
await page.search("digikam");
|
||||
await t
|
||||
.expect(Selector("div").withAttribute("data-uid", UploadedPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", UploadedPhoto).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await page.openNav();
|
||||
await t.click(Selector(".nav-albums"));
|
||||
await page.search("NewCreatedAlbum");
|
||||
await t
|
||||
.click(Selector("a.is-album").nth(0))
|
||||
.expect(Selector("div").withAttribute("data-uid", UploadedPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", UploadedPhoto).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
const PhotoCountAfterDelete = await Selector("div.is-photo").count;
|
||||
await t.expect(PhotoCountAfterDelete).eql(0);
|
||||
|
|
|
@ -45,7 +45,7 @@ test.meta("testID", "photos-002")(
|
|||
await t.click(Selector(".nav-video"));
|
||||
const FirstVideo = await Selector("div.is-photo").nth(0).getAttribute("data-uid");
|
||||
await page.selectPhotoFromUID(FirstVideo);
|
||||
const clipboardCount = await Selector("span.count-clipboard", { timeout: 5000 });
|
||||
const clipboardCount = await Selector("span.count-clipboard", { timeout: 15000 });
|
||||
await t
|
||||
.expect(clipboardCount.textContent)
|
||||
.eql("2")
|
||||
|
@ -68,9 +68,9 @@ test.meta("testID", "photos-003")(
|
|||
|
||||
await t.click(Selector(".nav-browse"));
|
||||
await t
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await page.openNav();
|
||||
await t.click(Selector(".nav-review"));
|
||||
|
@ -84,14 +84,14 @@ test.meta("testID", "photos-003")(
|
|||
await t.click(Selector("button.action-reload"));
|
||||
}
|
||||
await t
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).visible, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).visible, { timeout: 15000 })
|
||||
.ok();
|
||||
await page.editSelected();
|
||||
await t.click(Selector("button.action-approve"));
|
||||
if (t.browser.platform === "mobile") {
|
||||
await t.click(Selector("button.action-apply")).click(Selector("button.action-close"));
|
||||
} else {
|
||||
await t.click(Selector("button.action-done", { timeout: 5000 }));
|
||||
await t.click(Selector("button.action-done", { timeout: 15000 }));
|
||||
}
|
||||
await page.selectPhotoFromUID(SecondPhoto);
|
||||
await page.editSelected();
|
||||
|
@ -101,7 +101,7 @@ test.meta("testID", "photos-003")(
|
|||
if (t.browser.platform === "mobile") {
|
||||
await t.click(Selector("button.action-apply")).click(Selector("button.action-close"));
|
||||
} else {
|
||||
await t.click(Selector("button.action-done", { timeout: 5000 }));
|
||||
await t.click(Selector("button.action-done", { timeout: 15000 }));
|
||||
}
|
||||
await page.setFilter("view", "Cards");
|
||||
const ButtonThirdPhoto = 'div.is-photo[data-uid="' + ThirdPhoto + '"] button.action-approve';
|
||||
|
@ -112,9 +112,9 @@ test.meta("testID", "photos-003")(
|
|||
await t.click(Selector("button.action-reload"));
|
||||
}
|
||||
await t
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.expect(Selector("div").withAttribute("data-uid", ThirdPhoto).exists, { timeout: 5000 })
|
||||
.notOk();
|
||||
|
@ -141,11 +141,11 @@ test.meta("testID", "photos-004")("Like/dislike photo/video", async (t) => {
|
|||
await page.openNav();
|
||||
await t.click(Selector(".nav-favorites"));
|
||||
await t
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await page.openNav();
|
||||
await t.click(Selector(".nav-browse"));
|
||||
|
@ -157,11 +157,11 @@ test.meta("testID", "photos-004")("Like/dislike photo/video", async (t) => {
|
|||
.click(Selector(".action-close"));
|
||||
await t
|
||||
.expect(Selector("div.is-photo").withAttribute("data-uid", FirstPhoto).exists, {
|
||||
timeout: 5000,
|
||||
timeout: 15000,
|
||||
})
|
||||
.ok()
|
||||
.expect(Selector("div.is-photo").withAttribute("data-uid", SecondPhoto).exists, {
|
||||
timeout: 5000,
|
||||
timeout: 15000,
|
||||
})
|
||||
.ok();
|
||||
await page.openNav();
|
||||
|
@ -174,17 +174,17 @@ test.meta("testID", "photos-004")("Like/dislike photo/video", async (t) => {
|
|||
}
|
||||
await t
|
||||
.expect(Selector("div.is-photo").withAttribute("data-uid", FirstVideo).exists, {
|
||||
timeout: 5000,
|
||||
timeout: 15000,
|
||||
})
|
||||
.ok();
|
||||
await page.openNav();
|
||||
await t.click(Selector(".nav-favorites"));
|
||||
await t
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 15000 })
|
||||
.ok()
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 15000 })
|
||||
.ok()
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
await page.toggleLike(FirstVideo);
|
||||
await page.toggleLike(FirstPhoto);
|
||||
|
@ -199,11 +199,11 @@ test.meta("testID", "photos-004")("Like/dislike photo/video", async (t) => {
|
|||
await t.click(Selector("button.action-reload"));
|
||||
}
|
||||
await t
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
});
|
||||
|
||||
|
@ -322,12 +322,12 @@ test.meta("testID", "photos-007")("Edit photo/video", async (t) => {
|
|||
FirstPhotoKeywords,
|
||||
FirstPhotoNotes
|
||||
)
|
||||
const clipboardCount = await Selector("span.count-clipboard", { timeout: 5000 });
|
||||
const clipboardCount = await Selector("span.count-clipboard", { timeout: 15000 });
|
||||
await t
|
||||
.expect(clipboardCount.textContent)
|
||||
.eql("1")
|
||||
.click(Selector(".action-clear"))
|
||||
.expect(Selector("button.action-menu").exists, { timeout: 5000 })
|
||||
.expect(Selector("button.action-menu").exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
});
|
||||
|
||||
|
@ -342,7 +342,7 @@ test.meta("testID", "photos-008")("Change primary file", async (t) => {
|
|||
console.log(t.browser.platform);
|
||||
await t
|
||||
.click(Selector(".input-open"))
|
||||
.click(Selector(".action-next", { timeout: 5000 }))
|
||||
.click(Selector(".action-next", { timeout: 15000 }))
|
||||
.click(Selector(".action-previous"))
|
||||
.click(Selector(".action-close"));
|
||||
}
|
||||
|
@ -383,7 +383,7 @@ test.meta("testID", "photos-010")("Ungroup files", async (t) => {
|
|||
await t.click(Selector(".nav-browse")).click(Selector(".p-expand-search"));
|
||||
await page.search("group");
|
||||
await page.setFilter("view", "Cards");
|
||||
const PhotoCount = await Selector("button.action-title-edit", { timeout: 5000 }).count;
|
||||
const PhotoCount = await Selector("button.action-title-edit", { timeout: 15000 }).count;
|
||||
const SequentialPhoto = await Selector("div.is-photo").nth(0).getAttribute("data-uid");
|
||||
await t.expect(PhotoCount).eql(1);
|
||||
await page.openNav();
|
||||
|
@ -407,7 +407,7 @@ test.meta("testID", "photos-010")("Ungroup files", async (t) => {
|
|||
} else {
|
||||
await t.click(Selector("button.action-reload"));
|
||||
}
|
||||
const PhotoCountAfterUngroup = await Selector("button.action-title-edit", { timeout: 5000 })
|
||||
const PhotoCountAfterUngroup = await Selector("button.action-title-edit", { timeout: 15000 })
|
||||
.count;
|
||||
await t.expect(PhotoCountAfterUngroup).eql(2);
|
||||
});
|
||||
|
@ -417,7 +417,7 @@ test.skip.meta("testID", "photos-011")("Delete non primary file", async (t) => {
|
|||
await t
|
||||
.click(Selector(".nav-library"))
|
||||
.click(Selector("#tab-library-import"))
|
||||
.click(Selector(".input-import-folder input"), { timeout: 5000 })
|
||||
.click(Selector(".input-import-folder input"), { timeout: 15000 })
|
||||
.click(Selector("div.v-list__tile__title").withText("/pizza"))
|
||||
.click(Selector(".action-import"))
|
||||
.wait(10000);
|
||||
|
@ -425,7 +425,7 @@ test.skip.meta("testID", "photos-011")("Delete non primary file", async (t) => {
|
|||
await t.click(Selector(".nav-browse")).click(Selector(".p-expand-search"));
|
||||
await page.search("mogale");
|
||||
await page.setFilter("view", "Cards");
|
||||
const PhotoCount = await Selector("button.action-title-edit", { timeout: 5000 }).count;
|
||||
const PhotoCount = await Selector("button.action-title-edit", { timeout: 15000 }).count;
|
||||
|
||||
const Photo = await Selector("div.is-photo").nth(0).getAttribute("data-uid");
|
||||
await t
|
||||
|
@ -433,7 +433,7 @@ test.skip.meta("testID", "photos-011")("Delete non primary file", async (t) => {
|
|||
.eql(1)
|
||||
.click(Selector("button.action-title-edit").withAttribute("data-uid", Photo))
|
||||
.click(Selector("#tab-files"));
|
||||
const FileCount = await Selector("li.v-expansion-panel__container", { timeout: 5000 }).count;
|
||||
const FileCount = await Selector("li.v-expansion-panel__container", { timeout: 15000 }).count;
|
||||
await t
|
||||
.expect(FileCount)
|
||||
.eql(2)
|
||||
|
@ -442,7 +442,7 @@ test.skip.meta("testID", "photos-011")("Delete non primary file", async (t) => {
|
|||
.click(Selector(".action-confirm"))
|
||||
.wait(10000);
|
||||
const FileCountAfterDeletion = await Selector("li.v-expansion-panel__container", {
|
||||
timeout: 5000,
|
||||
timeout: 15000,
|
||||
}).count;
|
||||
await t.expect(FileCountAfterDeletion).eql(1);
|
||||
});
|
||||
|
@ -456,18 +456,18 @@ test.meta("testID", "photos-012")("Mark photos/videos as panorama/scan", async (
|
|||
await page.openNav();
|
||||
await t.click(Selector(".nav-browse + div"))
|
||||
.click(Selector(".nav-scans"))
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
if (t.browser.platform === "mobile") {
|
||||
await page.openNav();
|
||||
}
|
||||
await t
|
||||
.click(Selector(".nav-panoramas"))
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
await page.openNav();
|
||||
await t.click(Selector(".nav-browse"));
|
||||
|
@ -482,16 +482,16 @@ test.meta("testID", "photos-012")("Mark photos/videos as panorama/scan", async (
|
|||
await page.turnSwitchOn("panorama");
|
||||
await t.click(Selector(".action-close"));
|
||||
await page.clearSelection();
|
||||
await t.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 5000 })
|
||||
await t.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 15000 })
|
||||
.ok()
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
if (t.browser.platform === "mobile") {
|
||||
await page.openNav();
|
||||
}
|
||||
await t
|
||||
.click(Selector(".nav-scans"))
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
if (t.browser.platform === "mobile") {
|
||||
await page.openNav();
|
||||
|
@ -514,9 +514,9 @@ test.meta("testID", "photos-012")("Mark photos/videos as panorama/scan", async (
|
|||
} else {
|
||||
await t.click(Selector("button.action-reload"));
|
||||
}
|
||||
await t.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 5000 })
|
||||
await t.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
if (t.browser.platform === "mobile") {
|
||||
await page.openNav();
|
||||
|
@ -524,9 +524,9 @@ test.meta("testID", "photos-012")("Mark photos/videos as panorama/scan", async (
|
|||
}
|
||||
await t
|
||||
.click(Selector(".nav-scans"))
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 15000 })
|
||||
.notOk()
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstVideo).exists, { timeout: 15000 })
|
||||
.notOk();
|
||||
});
|
||||
|
||||
|
|
|
@ -189,9 +189,9 @@ test.meta("testID", "states-004")("Create/delete album during add to album", asy
|
|||
await t
|
||||
.expect(PhotoCountInAlbum)
|
||||
.eql(PhotoCountInMoment)
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 15000 })
|
||||
.ok()
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
await page.openNav();
|
||||
await t.click(Selector(".nav-albums"));
|
||||
|
@ -204,9 +204,9 @@ test.meta("testID", "states-004")("Create/delete album during add to album", asy
|
|||
await t
|
||||
.click(Selector(".nav-states"))
|
||||
.click(Selector("a.is-album").withAttribute("data-uid", FirstMoment))
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", FirstPhoto).exists, { timeout: 15000 })
|
||||
.ok()
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 5000 })
|
||||
.expect(Selector("div").withAttribute("data-uid", SecondPhoto).exists, { timeout: 15000 })
|
||||
.ok();
|
||||
});
|
||||
|
||||
|
|
3
go.mod
3
go.mod
|
@ -2,6 +2,7 @@ module github.com/photoprism/photoprism
|
|||
|
||||
require (
|
||||
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de
|
||||
github.com/caos/oidc v0.15.10
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
|
||||
github.com/disintegration/imaging v1.6.2
|
||||
github.com/djherbis/times v1.5.0
|
||||
|
@ -50,7 +51,6 @@ require (
|
|||
github.com/sevlyar/go-daemon v0.1.5
|
||||
github.com/shopspring/decimal v1.2.0 // indirect
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/stretchr/objx v0.3.0 // indirect
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/studio-b12/gowebdav v0.0.0-20210917133250-a3a86976a1df
|
||||
github.com/tensorflow/tensorflow v1.15.2
|
||||
|
@ -63,7 +63,6 @@ require (
|
|||
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d // indirect
|
||||
golang.org/x/net v0.0.0-20210917221730-978cfadd31cf
|
||||
golang.org/x/sys v0.0.0-20210917161153-d61c044b1678 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
gonum.org/v1/gonum v0.9.3
|
||||
google.golang.org/protobuf v1.27.1 // indirect
|
||||
gopkg.in/photoprism/go-tz.v2 v2.1.1
|
||||
|
|
171
go.sum
171
go.sum
|
@ -6,14 +6,30 @@ cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxK
|
|||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
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/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/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/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=
|
||||
gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
|
@ -24,6 +40,9 @@ github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9Pq
|
|||
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhPwqqXc4/vE0f7GvRjuAsbW+HOIe8KnA=
|
||||
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw=
|
||||
github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||
github.com/caos/logging v0.0.2/go.mod h1:9LKiDE2ChuGv6CHYif/kiugrfEXu9AwDiFWSreX7Wp0=
|
||||
github.com/caos/oidc v0.15.10 h1:dSzkIvsZR2PSZgvBFFkLJt8A/MujsyLac1yNvBShXuw=
|
||||
github.com/caos/oidc v0.15.10/go.mod h1:4l0PPwdc6BbrdCFhNrRTUddsG292uHGa7gE2DSEIqoU=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
|
@ -32,6 +51,7 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P
|
|||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
|
||||
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/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
|
@ -76,12 +96,15 @@ github.com/dsoprea/go-utility/v2 v2.0.0-20200717064901-2fccff4aa15e h1:IxIbA7VbC
|
|||
github.com/dsoprea/go-utility/v2 v2.0.0-20200717064901-2fccff4aa15e/go.mod h1:uAzdkPTub5Y9yQwXe8W4m2XuP0tK4a9Q/dantD0+uaU=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
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/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
|
||||
github.com/esimov/pigo v1.4.4 h1:Ab9uYXw0F0Y7OyZQQGwJjktl5LlHdL3ovdXe/T0juK8=
|
||||
github.com/esimov/pigo v1.4.4/go.mod h1:SGkOUpm4wlEmQQJKlaymAkThY8/8iP+XE0gFo7g8G6w=
|
||||
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||
github.com/gin-contrib/gzip v0.0.3 h1:etUaeesHhEORpZMp18zoOhepboiWnFtXrBZxszWUn4k=
|
||||
|
@ -102,6 +125,7 @@ github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2H
|
|||
github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY=
|
||||
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=
|
||||
github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U=
|
||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
|
@ -134,10 +158,23 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
|
|||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
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/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
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=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
|
@ -147,18 +184,37 @@ 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.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-github/v31 v31.0.0/go.mod h1:NQPZol8/1sMoWYGN2yaALIBytu17gAWfhbweiEed3pM=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/open-location-code/go v0.0.0-20210504205230-1796878d947c h1:kiK/0Vz+XhUoQU+PAVuP30aVHObEz0HMawJQXKiSzV4=
|
||||
github.com/google/open-location-code/go v0.0.0-20210504205230-1796878d947c/go.mod h1:eJfRN6aj+kR/rnua/rw9jAgYhqoMHldQkdTi+sePRKk=
|
||||
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/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc=
|
||||
github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU=
|
||||
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
|
||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gosimple/slug v1.10.0 h1:3XbiQua1IpCdrvuntWvGBxVm+K99wCSxJjlxkP49GGQ=
|
||||
|
@ -194,6 +250,8 @@ github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1q
|
|||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
|
@ -242,6 +300,7 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
|
|||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/montanaflynn/stats v0.6.6 h1:Duep6KMIDpY4Yo11iFsvyqJDyfzLF9+sndUKT+v64GQ=
|
||||
github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
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=
|
||||
github.com/paulmach/go.geojson v1.4.0 h1:5x5moCkCtDo5x8af62P9IOAYGQcYHtxz2QJ3x1DoCgY=
|
||||
|
@ -275,11 +334,11 @@ github.com/sevlyar/go-daemon v0.1.5/go.mod h1:6dJpPatBT9eUwM5VCw9Bt6CdX9Tk6UWvhW
|
|||
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
|
||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.3.0 h1:NGXK3lHquSN08v5vWalVI/L8XU9hdzE/G6xsrze47As=
|
||||
github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
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=
|
||||
|
@ -306,10 +365,15 @@ github.com/ulule/deepcopier v0.0.0-20200430083143-45decc6639b6 h1:TtyC78WMafNW8Q
|
|||
github.com/ulule/deepcopier v0.0.0-20200430083143-45decc6639b6/go.mod h1:h8272+G2omSmi30fBXiZDMkmHuOgonplfKIKjQWzlfs=
|
||||
github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU=
|
||||
github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
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.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
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=
|
||||
go4.org v0.0.0-20200411211856-f5505b9728dd/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg=
|
||||
go4.org v0.0.0-20201209231011-d4a079459e60 h1:iqAGo78tVOJXELHQFRjR6TMwItrvXH4hrGJ32I/NFF8=
|
||||
go4.org v0.0.0-20201209231011-d4a079459e60/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg=
|
||||
|
@ -334,8 +398,10 @@ golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgn
|
|||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd h1:zkO/Lhoka23X63N9OSzpSeROEUQ5ODw47tM3YWjygbs=
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
|
@ -358,12 +424,16 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl
|
|||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
@ -375,17 +445,25 @@ golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn
|
|||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
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-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200320220750-118fecf932d8/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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210917221730-978cfadd31cf h1:R150MpwJIv1MpS0N/pc+NhTM8ajzvlmxlY5OYsrevXQ=
|
||||
golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
|
@ -393,33 +471,53 @@ golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4Iltr
|
|||
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/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 h1:ld7aEMNHoBnnDAX15v1T6z31v8HwR2A9FYOuAhWqkwc=
|
||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/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-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191206220618-eeba5f6aabab/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
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-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201107080550-4d91cf3a1aaf/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
@ -438,6 +536,7 @@ golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
|||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
@ -460,16 +559,34 @@ golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtn
|
|||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
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-20200221224223-e1da425f72fd/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-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-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.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
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=
|
||||
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
|
||||
gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=
|
||||
gonum.org/v1/gonum v0.9.3 h1:DnoIG+QAMaF5NvxnGe/oKsgKcAc6PcUyl8q0VetfQ8s=
|
||||
|
@ -485,11 +602,21 @@ google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsb
|
|||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
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/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=
|
||||
|
@ -502,25 +629,59 @@ google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvx
|
|||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
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.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=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
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/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/photoprism/go-tz.v2 v2.1.1 h1:XdNAQRneJmJdXDFovXJbf5eewp3zsir+jJ1BxdmbnPk=
|
||||
gopkg.in/photoprism/go-tz.v2 v2.1.1/go.mod h1:E1aQvLJs3YA4wbrPMOdX4YEx1TgRO2PLSxnO+J1Kqiw=
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
|
||||
gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
@ -535,6 +696,8 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh
|
|||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/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=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
|
|
|
@ -18,8 +18,10 @@ import (
|
|||
|
||||
// NewApiTest returns new API test helper.
|
||||
func NewApiTest() (app *gin.Engine, router *gin.RouterGroup, conf *config.Config) {
|
||||
conf = service.Config()
|
||||
gin.SetMode(gin.TestMode)
|
||||
app = gin.New()
|
||||
app.LoadHTMLGlob(conf.TemplatesPath() + "/*")
|
||||
router = app.Group("/api/v1")
|
||||
return app, router, service.Config()
|
||||
}
|
||||
|
@ -56,6 +58,15 @@ func PerformRequest(r http.Handler, method, path string) *httptest.ResponseRecor
|
|||
return w
|
||||
}
|
||||
|
||||
// Performs API request with empty request body and Cookie.
|
||||
func PerformRequestWithCookie(r http.Handler, method, path string, cookie string) *httptest.ResponseRecorder {
|
||||
req := httptest.NewRequest(method, path, nil)
|
||||
req.Header.Add("Cookie", cookie)
|
||||
w := httptest.NewRecorder()
|
||||
r.ServeHTTP(w, req)
|
||||
return w
|
||||
}
|
||||
|
||||
// Performs authenticated API request with empty request body.
|
||||
func AuthenticatedRequest(r http.Handler, method, path, sess string) *httptest.ResponseRecorder {
|
||||
req, _ := http.NewRequest(method, path, nil)
|
||||
|
|
96
internal/api/auth.go
Normal file
96
internal/api/auth.go
Normal file
|
@ -0,0 +1,96 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/photoprism/photoprism/internal/entity"
|
||||
"github.com/photoprism/photoprism/internal/oidc"
|
||||
"github.com/photoprism/photoprism/internal/service"
|
||||
"github.com/photoprism/photoprism/internal/session"
|
||||
)
|
||||
|
||||
// GET /api/v1/auth/
|
||||
func AuthEndpoints(router *gin.RouterGroup) {
|
||||
conf := service.Config()
|
||||
if conf.OidcIssuerUrl() == nil || conf.OidcClientId() == "" || conf.OidcClientSecret() == "" {
|
||||
log.Debugf("no oidc provider configured. skip mounting endpoints")
|
||||
return
|
||||
}
|
||||
|
||||
router.GET("/auth/external", func(c *gin.Context) {
|
||||
openIdConnect := service.Oidc()
|
||||
if openIdConnect == nil {
|
||||
AbortFeatureDisabled(c)
|
||||
return
|
||||
}
|
||||
|
||||
handle := openIdConnect.AuthUrlHandler()
|
||||
handle(c.Writer, c.Request)
|
||||
return
|
||||
})
|
||||
|
||||
router.GET(oidc.RedirectPath, func(c *gin.Context) {
|
||||
openIdConnect := service.Oidc()
|
||||
if openIdConnect == nil {
|
||||
AbortFeatureDisabled(c)
|
||||
return
|
||||
}
|
||||
|
||||
userInfo, err := openIdConnect.CodeExchangeUserInfo(c)
|
||||
if err != nil {
|
||||
log.Errorf("%s", err)
|
||||
return
|
||||
}
|
||||
var uname string
|
||||
if len(userInfo.GetPreferredUsername()) >= 4 {
|
||||
uname = userInfo.GetPreferredUsername()
|
||||
} else if len(userInfo.GetNickname()) >= 4 {
|
||||
uname = userInfo.GetNickname()
|
||||
} else if len(userInfo.GetName()) >= 4 {
|
||||
uname = strings.ReplaceAll(strings.ToLower(userInfo.GetName()), " ", "-")
|
||||
} else if len(userInfo.GetEmail()) >= 4 {
|
||||
uname = userInfo.GetEmail()
|
||||
} else {
|
||||
log.Error("auth: no username found")
|
||||
}
|
||||
|
||||
u := &entity.User{
|
||||
FullName: userInfo.GetName(),
|
||||
UserName: uname,
|
||||
PrimaryEmail: userInfo.GetEmail(),
|
||||
ExternalID: userInfo.GetSubject(),
|
||||
RoleAdmin: true,
|
||||
}
|
||||
|
||||
log.Debugf("USER: %s %s %s %s\n", u.FullName, u.UserName, u.PrimaryEmail, u.ExternalID)
|
||||
|
||||
user, e := entity.CreateOrUpdateExternalUser(u)
|
||||
if e != nil {
|
||||
c.Error(e)
|
||||
callbackError(c, e.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
log.Infof("user '%s' logged in", user.UserName)
|
||||
var data = session.Data{
|
||||
User: *user,
|
||||
}
|
||||
id := service.Session().Create(data)
|
||||
c.HTML(http.StatusOK, "callback.tmpl", gin.H{
|
||||
"status": "ok",
|
||||
"id": id,
|
||||
"data": data,
|
||||
"config": conf.UserConfig(),
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func callbackError(c *gin.Context, err string, status int) {
|
||||
c.Abort()
|
||||
c.HTML(status, "callback.tmpl", gin.H{
|
||||
"status": "error",
|
||||
"errors": err,
|
||||
})
|
||||
}
|
97
internal/api/auth_test.go
Normal file
97
internal/api/auth_test.go
Normal file
|
@ -0,0 +1,97 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/httpclient"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAuthEndpoints(t *testing.T) {
|
||||
t.Run("successful oidc authentication", func(t *testing.T) {
|
||||
app, router, _ := NewApiTest()
|
||||
AuthEndpoints(router)
|
||||
|
||||
// Step 1a: Request AuthURL
|
||||
log.Debug("Requesting OIDC AuthURL...")
|
||||
r := PerformRequest(app, http.MethodGet, "/api/v1/auth/external")
|
||||
assert.Equal(t, http.StatusFound, r.Code)
|
||||
|
||||
// Step 1b: Redirect user agent to OP and save state cookie
|
||||
l := r.Header().Get("Location")
|
||||
log.Debug("Requesting AuthCode from OP: ", l)
|
||||
cookies := r.Header().Values("Set-Cookie")
|
||||
log.Debug("Cookies: ", cookies)
|
||||
assert.Contains(t, l, "authorize")
|
||||
|
||||
var l2 string
|
||||
cl := httpclient.Client(true)
|
||||
cl.CheckRedirect = func(req *http.Request, via []*http.Request) error {
|
||||
if strings.Contains(req.URL.String(), "localhost") {
|
||||
|
||||
l2 = req.URL.RequestURI()
|
||||
return http.ErrUseLastResponse
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err := cl.Get(l)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
log.Debug(l2)
|
||||
log.Debug("Successful")
|
||||
|
||||
// Step 2a: OP redirects user agent back to PhotoPrism
|
||||
// Step 2b: PhotoPrism redeems AuthCode and fetches tokens from OP
|
||||
log.Debug("Redeem AuthCode...")
|
||||
r3 := PerformRequestWithCookie(app, http.MethodGet, l2, strings.Join(cookies, "; "))
|
||||
|
||||
assert.Equal(t, http.StatusOK, r3.Code)
|
||||
log.Debug("Successful")
|
||||
})
|
||||
|
||||
t.Run("oidc authentication: missing cookie", func(t *testing.T) {
|
||||
app, router, _ := NewApiTest()
|
||||
AuthEndpoints(router)
|
||||
|
||||
// Step 1a: Request AuthURL
|
||||
log.Debug("Requesting OIDC AuthURL...")
|
||||
r := PerformRequest(app, http.MethodGet, "/api/v1/auth/external")
|
||||
assert.Equal(t, r.Code, http.StatusFound)
|
||||
|
||||
// Step 1b: Redirect user agent to OP and save state cookie
|
||||
l := r.Header().Get("Location")
|
||||
log.Debug("Requesting AuthCode from OP: ", l)
|
||||
cookie := ""
|
||||
assert.Contains(t, l, "authorize")
|
||||
var l2 string
|
||||
cl := &http.Client{
|
||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||
if strings.Contains(req.URL.String(), "localhost") {
|
||||
|
||||
l2 = req.URL.RequestURI()
|
||||
return http.ErrUseLastResponse
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
_, err := cl.Get(l)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
log.Debug(l2)
|
||||
log.Debug("Successful")
|
||||
|
||||
// Step 2a: OP redirects user agent back to PhotoPrism
|
||||
// Step 2b: PhotoPrism redeems AuthCode and fetches tokens from OP
|
||||
log.Debug("Redeem AuthCode...")
|
||||
r3 := PerformRequestWithCookie(app, http.MethodGet, l2, cookie)
|
||||
|
||||
assert.Equal(t, http.StatusUnauthorized, r3.Code)
|
||||
log.Debug("Successful")
|
||||
})
|
||||
}
|
|
@ -60,6 +60,7 @@ type ClientConfig struct {
|
|||
Categories CategoryLabels `json:"categories"`
|
||||
Clip int `json:"clip"`
|
||||
Server RuntimeInfo `json:"server"`
|
||||
Oidc bool `json:"oidc"`
|
||||
}
|
||||
|
||||
// Years represents a list of years.
|
||||
|
@ -214,6 +215,7 @@ func (c *Config) PublicConfig() ClientConfig {
|
|||
Clip: txt.ClipDefault,
|
||||
PreviewToken: "public",
|
||||
DownloadToken: "public",
|
||||
Oidc: c.OidcIssuerUrl() != nil,
|
||||
}
|
||||
|
||||
return result
|
||||
|
@ -278,6 +280,7 @@ func (c *Config) GuestConfig() ClientConfig {
|
|||
CSSHash: fs.Checksum(c.BuildPath() + "/share.css"),
|
||||
ManifestHash: fs.Checksum(c.TemplatesPath() + "/manifest.json"),
|
||||
Clip: txt.ClipDefault,
|
||||
Oidc: c.OidcIssuerUrl() != nil,
|
||||
}
|
||||
|
||||
return result
|
||||
|
@ -336,6 +339,7 @@ func (c *Config) UserConfig() ClientConfig {
|
|||
ManifestHash: fs.Checksum(c.TemplatesPath() + "/manifest.json"),
|
||||
Clip: txt.ClipDefault,
|
||||
Server: NewRuntimeInfo(),
|
||||
Oidc: c.OidcIssuerUrl() != nil,
|
||||
}
|
||||
|
||||
c.Db().
|
||||
|
|
|
@ -474,4 +474,22 @@ var GlobalFlags = []cli.Flag{
|
|||
Value: face.MatchDist,
|
||||
EnvVar: "PHOTOPRISM_FACE_MATCH_DIST",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "client-id",
|
||||
Usage: "OpenID Connect Client ID",
|
||||
Value: "",
|
||||
EnvVar: "PHOTOPRISM_OIDC_CLIENT_ID",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "client-secret",
|
||||
Usage: "OpenID Connect Client Secret",
|
||||
Value: "",
|
||||
EnvVar: "PHOTOPRISM_OIDC_CLIENT_SECRET",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "oidc-issuer",
|
||||
Usage: "OpenID Connect Provider/Issuer URL",
|
||||
Value: "",
|
||||
EnvVar: "PHOTOPRISM_OIDC_ISSUER",
|
||||
},
|
||||
}
|
||||
|
|
23
internal/config/oidc.go
Normal file
23
internal/config/oidc.go
Normal file
|
@ -0,0 +1,23 @@
|
|||
package config
|
||||
|
||||
import "net/url"
|
||||
|
||||
func (c *Config) OidcIssuerUrl() *url.URL {
|
||||
if c.Options().OidcIssuer == "" {
|
||||
return nil
|
||||
}
|
||||
res, err := url.Parse(c.Options().OidcIssuer)
|
||||
if err != nil {
|
||||
log.Debugf("error parsing oidc issuer url: %q", err)
|
||||
return nil
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (c *Config) OidcClientId() string {
|
||||
return c.Options().OidcClientID
|
||||
}
|
||||
|
||||
func (c *Config) OidcClientSecret() string {
|
||||
return c.Options().OidcClientSecret
|
||||
}
|
|
@ -120,6 +120,9 @@ type Options struct {
|
|||
FaceClusterCore int `yaml:"-" json:"-" flag:"face-cluster-core"`
|
||||
FaceClusterDist float64 `yaml:"-" json:"-" flag:"face-cluster-dist"`
|
||||
FaceMatchDist float64 `yaml:"-" json:"-" flag:"face-match-dist"`
|
||||
OidcClientID string `yaml:"OidcClientID" json:"-" flag:"client-id"`
|
||||
OidcClientSecret string `yaml:"OidcClientSecret" json:"-" flag:"client-secret"`
|
||||
OidcIssuer string `yaml:"OidcIssuer" json:"-" flag:"oidc-issuer"`
|
||||
}
|
||||
|
||||
// NewOptions creates a new configuration entity by using two methods:
|
||||
|
|
|
@ -52,28 +52,31 @@ func NewTestOptions() *Options {
|
|||
}
|
||||
|
||||
c := &Options{
|
||||
Name: "PhotoPrism",
|
||||
Version: "0.0.0",
|
||||
Copyright: "(c) 2018-2021 Michael Mayer",
|
||||
Debug: true,
|
||||
Public: true,
|
||||
Experimental: true,
|
||||
ReadOnly: false,
|
||||
DetectNSFW: true,
|
||||
UploadNSFW: false,
|
||||
AssetsPath: assetsPath,
|
||||
AutoIndex: -1,
|
||||
AutoImport: 7200,
|
||||
StoragePath: testDataPath,
|
||||
CachePath: testDataPath + "/cache",
|
||||
OriginalsPath: testDataPath + "/originals",
|
||||
ImportPath: testDataPath + "/import",
|
||||
TempPath: testDataPath + "/temp",
|
||||
ConfigPath: testDataPath + "/config",
|
||||
SidecarPath: testDataPath + "/sidecar",
|
||||
DatabaseDriver: dbDriver,
|
||||
DatabaseDsn: dbDsn,
|
||||
AdminPassword: "photoprism",
|
||||
Name: "PhotoPrism",
|
||||
Version: "0.0.0",
|
||||
Copyright: "(c) 2018-2021 Michael Mayer",
|
||||
Debug: true,
|
||||
Public: true,
|
||||
Experimental: true,
|
||||
ReadOnly: false,
|
||||
DetectNSFW: true,
|
||||
UploadNSFW: false,
|
||||
AssetsPath: assetsPath,
|
||||
AutoIndex: -1,
|
||||
AutoImport: 7200,
|
||||
StoragePath: testDataPath,
|
||||
CachePath: testDataPath + "/cache",
|
||||
OriginalsPath: testDataPath + "/originals",
|
||||
ImportPath: testDataPath + "/import",
|
||||
TempPath: testDataPath + "/temp",
|
||||
ConfigPath: testDataPath + "/config",
|
||||
SidecarPath: testDataPath + "/sidecar",
|
||||
DatabaseDriver: dbDriver,
|
||||
DatabaseDsn: dbDsn,
|
||||
AdminPassword: "photoprism",
|
||||
OidcIssuer: "http://oidc-test-op:9998",
|
||||
OidcClientID: "native",
|
||||
OidcClientSecret: "random",
|
||||
}
|
||||
|
||||
return c
|
||||
|
|
|
@ -69,6 +69,7 @@ type User struct {
|
|||
ResetToken string `gorm:"type:VARBINARY(64);" json:"-" yaml:"-"`
|
||||
ApiToken string `gorm:"column:api_token;type:VARBINARY(128);" json:"-" yaml:"-"`
|
||||
ApiSecret string `gorm:"column:api_secret;type:VARBINARY(128);" json:"-" yaml:"-"`
|
||||
ExternalID string `gorm:"size:255;column:external_id;" json:"-" yaml:"-"`
|
||||
LoginAttempts int `json:"-" yaml:"-"`
|
||||
LoginAt *time.Time `json:"-" yaml:"-"`
|
||||
CreatedAt time.Time `json:"CreatedAt" yaml:"-"`
|
||||
|
@ -163,6 +164,50 @@ func FirstOrCreateUser(m *User) *User {
|
|||
return m
|
||||
}
|
||||
|
||||
// CreateOrUpdateExternalUser Retrieves User by its ExternalID and updates relevant properties. If no User exists, a new one will be inserted into database.
|
||||
func CreateOrUpdateExternalUser(m *User) (*User, error) {
|
||||
result := User{}
|
||||
|
||||
if err := Db().Preload("Address").Where("external_id = ?", m.ExternalID).First(&result).Error; err == nil {
|
||||
mustUpdate := false
|
||||
if m.PrimaryEmail != result.PrimaryEmail {
|
||||
result.PrimaryEmail = m.PrimaryEmail
|
||||
mustUpdate = true
|
||||
}
|
||||
if m.FullName != result.FullName {
|
||||
result.FullName = m.FullName
|
||||
mustUpdate = true
|
||||
}
|
||||
if mustUpdate {
|
||||
err := result.Validate()
|
||||
if err != nil {
|
||||
log.Errorf("user: %s", err)
|
||||
return nil, err
|
||||
}
|
||||
err = result.Save()
|
||||
if err != nil {
|
||||
log.Errorf("user: %s", err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
log.Debugf("user: retrieved %q from db", result.UserName)
|
||||
return &result, nil
|
||||
} else {
|
||||
err := m.Validate()
|
||||
if err != nil {
|
||||
log.Errorf("user: %s", err)
|
||||
return nil, err
|
||||
}
|
||||
if err := m.Create(); err != nil {
|
||||
log.Debugf("user: %s", err)
|
||||
return nil, err
|
||||
}
|
||||
log.Debugf("user: created %q", result.UserName)
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// FindUserByName returns an existing user or nil if not found.
|
||||
func FindUserByName(userName string) *User {
|
||||
if userName == "" {
|
||||
|
|
|
@ -526,3 +526,56 @@ func TestUser_Deleted(t *testing.T) {
|
|||
assert.False(t, UserFixtures.Pointer("alice").Deleted())
|
||||
assert.True(t, UserFixtures.Pointer("deleted").Deleted())
|
||||
}
|
||||
|
||||
func TestCreateOrUpdateExternalUser(t *testing.T) {
|
||||
u := &User{
|
||||
AddressID: 1,
|
||||
UserName: "gopher",
|
||||
FullName: "Gopher Go",
|
||||
PrimaryEmail: "gopher@example.com",
|
||||
ExternalID: "testid-0123455678",
|
||||
}
|
||||
u2 := &User{
|
||||
AddressID: 1,
|
||||
UserName: "gop",
|
||||
FullName: "Gopher Go Invalid",
|
||||
PrimaryEmail: "gopher@example.com",
|
||||
ExternalID: "testid-0123455678-2",
|
||||
}
|
||||
var uid string
|
||||
t.Run("CreateOrUpdateExternalUser - new", func(t *testing.T) {
|
||||
user, err := CreateOrUpdateExternalUser(u)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.Equal(t, "gopher", user.UserName)
|
||||
assert.Equal(t, "testid-0123455678", user.ExternalID)
|
||||
uid = user.UserUID
|
||||
assert.NotEmpty(t, user.UserUID)
|
||||
|
||||
})
|
||||
t.Run("CreateOrUpdateExternalUser - new invalid", func(t *testing.T) {
|
||||
user, err := CreateOrUpdateExternalUser(u2)
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, user)
|
||||
})
|
||||
t.Run("CreateOrUpdateExternalUser - update", func(t *testing.T) {
|
||||
u.PrimaryEmail = "gopher-new@example.com"
|
||||
user, err := CreateOrUpdateExternalUser(u)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.Equal(t, "gopher", user.UserName)
|
||||
assert.Equal(t, "testid-0123455678", user.ExternalID)
|
||||
assert.Equal(t, "gopher-new@example.com", user.PrimaryEmail)
|
||||
assert.Equal(t, uid, user.UserUID)
|
||||
|
||||
})
|
||||
t.Run("CreateOrUpdateExternalUser - update invalid", func(t *testing.T) {
|
||||
u.PrimaryEmail = "noemail"
|
||||
user, err := CreateOrUpdateExternalUser(u)
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, user)
|
||||
})
|
||||
|
||||
}
|
||||
|
|
51
internal/httpclient/httpclient.go
Normal file
51
internal/httpclient/httpclient.go
Normal file
|
@ -0,0 +1,51 @@
|
|||
package httpclient
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/event"
|
||||
)
|
||||
|
||||
var log = event.Log
|
||||
|
||||
func Client(debug bool) *http.Client {
|
||||
if debug {
|
||||
return &http.Client{
|
||||
Transport: LoggingRoundTripper{http.DefaultTransport},
|
||||
}
|
||||
}
|
||||
return http.DefaultClient
|
||||
}
|
||||
|
||||
// This type implements the http.RoundTripper interface
|
||||
type LoggingRoundTripper struct {
|
||||
proxy http.RoundTripper
|
||||
}
|
||||
|
||||
func (lrt LoggingRoundTripper) RoundTrip(req *http.Request) (res *http.Response, e error) {
|
||||
// Do "before sending requests" actions here.
|
||||
log.Debugf("Sending request to %v\n", req.URL.String())
|
||||
|
||||
// Send the request, get the response (or the error)
|
||||
res, e = lrt.proxy.RoundTrip(req)
|
||||
|
||||
// Handle the result.
|
||||
if e != nil {
|
||||
log.Errorf("Error: %v", e)
|
||||
} else {
|
||||
log.Debugf("Received %v response\n", res.Status)
|
||||
|
||||
// Copy body into buffer for logging
|
||||
buf := new(bytes.Buffer)
|
||||
_, err := io.Copy(buf, res.Body)
|
||||
if err != nil {
|
||||
log.Errorf("Error: %v", err)
|
||||
}
|
||||
log.Debugf("Header: %s\n", res.Header)
|
||||
log.Debugf("Reponse Body: %s\n", buf.String())
|
||||
res.Body = io.NopCloser(buf)
|
||||
}
|
||||
return
|
||||
}
|
29
internal/httpclient/httpclient_test.go
Normal file
29
internal/httpclient/httpclient_test.go
Normal file
|
@ -0,0 +1,29 @@
|
|||
package httpclient
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestClient(t *testing.T) {
|
||||
t.Run("default client", func(t *testing.T) {
|
||||
client := Client(false)
|
||||
|
||||
assert.IsType(t, http.DefaultClient, client)
|
||||
assert.IsType(t, nil, client.Transport)
|
||||
})
|
||||
t.Run("logging proxy client", func(t *testing.T) {
|
||||
client := Client(true)
|
||||
|
||||
assert.IsType(t, LoggingRoundTripper{}, client.Transport)
|
||||
})
|
||||
t.Run("RoundTripper working", func(t *testing.T) {
|
||||
req, err := http.NewRequest("GET", "https://photoprism.app", nil)
|
||||
assert.Nil(t, err)
|
||||
rt := LoggingRoundTripper{http.DefaultTransport}
|
||||
_, err = rt.RoundTrip(req)
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
}
|
132
internal/oidc/client.go
Normal file
132
internal/oidc/client.go
Normal file
|
@ -0,0 +1,132 @@
|
|||
package oidc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/caos/oidc/pkg/client"
|
||||
"github.com/caos/oidc/pkg/client/rp"
|
||||
"github.com/caos/oidc/pkg/oidc"
|
||||
"github.com/caos/oidc/pkg/utils"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/photoprism/photoprism/internal/event"
|
||||
"github.com/photoprism/photoprism/internal/httpclient"
|
||||
"github.com/photoprism/photoprism/pkg/rnd"
|
||||
)
|
||||
|
||||
const RedirectPath = "/auth/callback"
|
||||
|
||||
var log = event.Log
|
||||
|
||||
type Client struct {
|
||||
rp.RelyingParty
|
||||
}
|
||||
|
||||
func NewClient(iss *url.URL, clientId, clientSecret, siteUrl string, debug bool) *Client {
|
||||
log.Debugf("Provider Params: %s %s %s %s", iss.String(), clientId, clientSecret, siteUrl)
|
||||
|
||||
u, err := url.Parse(siteUrl)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
u.Path = path.Join(u.Path, "/api/v1/", RedirectPath)
|
||||
log.Debugf(u.String())
|
||||
|
||||
hashKey, err := rnd.RandomBytes(16)
|
||||
encryptKey, err := rnd.RandomBytes(16)
|
||||
if err != nil {
|
||||
log.Errorf("oidc intialization: %q", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
cookieHandler := utils.NewCookieHandler(hashKey, encryptKey, utils.WithUnsecure())
|
||||
httpClient := httpclient.Client(debug)
|
||||
|
||||
options := []rp.Option{
|
||||
rp.WithHTTPClient(httpClient),
|
||||
rp.WithCookieHandler(cookieHandler),
|
||||
rp.WithVerifierOpts(
|
||||
rp.WithIssuedAtOffset(5 * time.Second),
|
||||
),
|
||||
}
|
||||
|
||||
discover, err := client.Discover(iss.String(), httpClient)
|
||||
if err != nil {
|
||||
log.Errorf("oidc intialization: %q", err)
|
||||
return nil
|
||||
}
|
||||
for _, v := range discover.CodeChallengeMethodsSupported {
|
||||
if v == oidc.CodeChallengeMethodS256 {
|
||||
options = append(options, rp.WithPKCE(cookieHandler))
|
||||
}
|
||||
}
|
||||
|
||||
scopes := strings.Split("openid profile email", " ")
|
||||
|
||||
provider, err := rp.NewRelyingPartyOIDC(iss.String(), clientId, clientSecret, u.String(), scopes, options...)
|
||||
if err != nil {
|
||||
log.Errorf("oidc intialization: %s", err)
|
||||
return nil
|
||||
}
|
||||
log.Debugf("PKCE enabled: %v", provider.IsPKCE())
|
||||
|
||||
return &Client{
|
||||
provider,
|
||||
}
|
||||
}
|
||||
|
||||
func state() string {
|
||||
return rnd.UUID()
|
||||
}
|
||||
|
||||
func (c *Client) AuthUrlHandler() http.HandlerFunc {
|
||||
return rp.AuthURLHandler(state, c)
|
||||
}
|
||||
|
||||
//var tempstate string
|
||||
//
|
||||
//func (c *Client) AuthUrl() string {
|
||||
// tempstate = state()
|
||||
// return rp.AuthURL(tempstate, c)
|
||||
//}
|
||||
|
||||
//func (c *Client) Available() bool {
|
||||
// return c.RelyingParty != nil
|
||||
//}
|
||||
|
||||
func (c *Client) CodeExchangeUserInfo(ctx *gin.Context) (oidc.UserInfo, error) {
|
||||
var userinfo oidc.UserInfo
|
||||
|
||||
userinfoClosure := func(w http.ResponseWriter, r *http.Request, tokens *oidc.Tokens, state string, rp rp.RelyingParty, info oidc.UserInfo) {
|
||||
log.Infof("UserInfo: %s %s %s %s %s", info.GetEmail(), info.GetSubject(), info.GetNickname(), info.GetName(), info.GetPreferredUsername())
|
||||
log.Debugf("IDToken: %s", tokens.IDToken)
|
||||
log.Debugf("AToken: %s", tokens.AccessToken)
|
||||
log.Debugf("RToken: %s", tokens.RefreshToken)
|
||||
|
||||
userinfo = info
|
||||
}
|
||||
|
||||
//you could also just take the access_token and id_token without calling the userinfo endpoint:
|
||||
//
|
||||
//tokeninfoClosure := func(w http.ResponseWriter, r *http.Request, tokens *oidc.Tokens, state string, rp rp.RelyingParty) {
|
||||
// log.Infof("IDTOKEN: %q\n\n" , tokens.IDToken)
|
||||
// log.Infof("ACCESSTOKEN: %q\n\n" , tokens.AccessToken)
|
||||
// log.Infof("REFRESHTOKEN: %q\n\n" , tokens.RefreshToken)
|
||||
//}
|
||||
|
||||
handle := rp.CodeExchangeHandler(rp.UserinfoCallback(userinfoClosure), c)
|
||||
//handle := rp.CodeExchangeHandler(tokeninfoClosure, c)
|
||||
handle(ctx.Writer, ctx.Request)
|
||||
|
||||
log.Debugf("current request state: %v", ctx.Writer.Status())
|
||||
//log.Debugf("RESPONSE BODY: %v", ctx.Wri)
|
||||
if sc := ctx.Writer.Status(); sc != 0 && sc != http.StatusOK {
|
||||
return nil, errors.New("oidc: couldn't exchange auth code and thus not retrieve external user info")
|
||||
}
|
||||
|
||||
return userinfo, nil
|
||||
}
|
|
@ -163,6 +163,8 @@ func registerRoutes(router *gin.Engine, conf *config.Config) {
|
|||
api.GetErrors(v1)
|
||||
api.SendFeedback(v1)
|
||||
api.Websocket(v1)
|
||||
|
||||
api.AuthEndpoints(v1)
|
||||
}
|
||||
|
||||
// Configure link sharing.
|
||||
|
|
22
internal/service/oidc.go
Normal file
22
internal/service/oidc.go
Normal file
|
@ -0,0 +1,22 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"github.com/photoprism/photoprism/internal/oidc"
|
||||
)
|
||||
|
||||
func initOidc() {
|
||||
services.Oidc = oidc.NewClient(
|
||||
Config().OidcIssuerUrl(),
|
||||
Config().OidcClientId(),
|
||||
Config().OidcClientSecret(),
|
||||
Config().SiteUrl(),
|
||||
Config().Debug(),
|
||||
)
|
||||
}
|
||||
|
||||
func Oidc() *oidc.Client {
|
||||
if services.Oidc == nil {
|
||||
initOidc()
|
||||
}
|
||||
return services.Oidc
|
||||
}
|
|
@ -5,6 +5,7 @@ import (
|
|||
"github.com/photoprism/photoprism/internal/config"
|
||||
"github.com/photoprism/photoprism/internal/face"
|
||||
"github.com/photoprism/photoprism/internal/nsfw"
|
||||
"github.com/photoprism/photoprism/internal/oidc"
|
||||
"github.com/photoprism/photoprism/internal/photoprism"
|
||||
"github.com/photoprism/photoprism/internal/query"
|
||||
"github.com/photoprism/photoprism/internal/session"
|
||||
|
@ -33,6 +34,7 @@ var services struct {
|
|||
Query *query.Query
|
||||
Resample *photoprism.Resample
|
||||
Session *session.Session
|
||||
Oidc *oidc.Client
|
||||
}
|
||||
|
||||
func SetConfig(c *config.Config) {
|
||||
|
|
12
pkg/rnd/bytes.go
Normal file
12
pkg/rnd/bytes.go
Normal file
|
@ -0,0 +1,12 @@
|
|||
package rnd
|
||||
|
||||
import "crypto/rand"
|
||||
|
||||
func RandomBytes(n int) ([]byte, error) {
|
||||
b := make([]byte, n)
|
||||
_, err := rand.Read(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b, nil
|
||||
}
|
|
@ -29,7 +29,7 @@ fi
|
|||
|
||||
if [[ $1 == "debug" ]]; then
|
||||
echo "Building development binary..."
|
||||
go build -ldflags "-X main.version=${PHOTOPRISM_DATE}-${PHOTOPRISM_VERSION}-${PHOTOPRISM_OS}-${PHOTOPRISM_ARCH}-DEBUG" -o $2 cmd/photoprism/photoprism.go
|
||||
go build -gcflags="all=-N -l" -ldflags "-X main.version=${PHOTOPRISM_DATE}-${PHOTOPRISM_VERSION}-${PHOTOPRISM_OS}-${PHOTOPRISM_ARCH}-DEBUG" -o $2 cmd/photoprism/photoprism.go
|
||||
du -h $2
|
||||
echo "Done."
|
||||
elif [[ $1 == "race" ]]; then
|
||||
|
|
Loading…
Add table
Reference in a new issue